[
  {
    "path": ".clang-format",
    "content": "BasedOnStyle: LLVM\nIndentWidth: 4\nUseTab: Never\nBreakBeforeBraces: Custom\nBraceWrapping: \n    AfterClass: true\n    AfterControlStatement: false\n    AfterEnum: true \n    AfterFunction: true \n    AfterNamespace: true\n    AfterObjCDeclaration: true \n    AfterStruct: true \n    AfterUnion: true \n    BeforeCatch: true \n    BeforeElse: false \n    IndentBraces: false\n\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAllowShortIfStatementsOnASingleLine: false\nIndentCaseLabels: true\nBinPackArguments: true\nBinPackParameters: false\nAlignTrailingComments: true\nAllowShortBlocksOnASingleLine: false\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortFunctionsOnASingleLine: InlineOnly\nAlwaysBreakTemplateDeclarations: false\nColumnLimit: 80\nMaxEmptyLinesToKeep: 2\nKeepEmptyLinesAtTheStartOfBlocks: false\nContinuationIndentWidth: 2\nPointerAlignment: Right\nReflowComments: false\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeParens: Always\nSpaceInEmptyParentheses: false\nSpacesInAngles: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nStandard: Cpp03\n\nSortIncludes: false\n\nFixNamespaceComments: false\nBreakBeforeBinaryOperators: NonAssignment\nSpaceAfterTemplateKeyword: true\nAlignAfterOpenBracket: Align\nAlignOperands: true\nBreakConstructorInitializers: AfterColon\nConstructorInitializerAllOnOneLineOrOnePerLine: true\nSpaceAfterCStyleCast: true\nBreakBeforeTernaryOperators: true\n"
  },
  {
    "path": ".clang-tidy",
    "content": "Checks:        \"*,\\\n# not currently a coding convention, but conceivable,\\\n-llvm-include-order,\\\n# currently the coding convention deliberately produces violations of these,\\\n# rules, but it may make sense to reconsider,\\\n-readability-implicit-bool-conversion,\\\n-readability-braces-around-statements,\\\n-readability-named-parameter,\\\n-fuchsia-default-arguments,\\\n-google-readability-todo,\\\n-google-runtime-int,\\\n-cppcoreguidelines-avoid-goto,\\\n-hicpp-avoid-goto, \\\n-cppcoreguidelines-pro-type-member-init,\\\n-cppcoreguidelines-pro-type-static-cast-downcast,\\\n-readability-identifier-naming,\\\n# not applicable,\\\n-fuchsia-default-arguments-calls,\\\n-fuchsia-overloaded-operator,\\\n-fuchsia-statically-constructed-objects,\\\n# not currently a coding convention, C++11-specific, but conceivable,\\\n-modernize-use-nullptr,\\\n-modernize-use-equals-default,\\\n-modernize-deprecated-headers,\\\n# not currently a coding convention, C++11-specific and hard to implement,\\\n-hicpp-no-malloc,\\\n-hicpp-avoid-c-arrays,\\\n-modernize-avoid-c-arrays,\\\n-modernize-pass-by-value,\\\n-modernize-loop-convert,\\\n-modernize-use-auto,\\\n-modernize-use-trailing-return-type,\\\n-modernize-use-using,\\\n-modernize-return-braced-init-list,\\\n-cppcoreguidelines-avoid-c-arrays,\\\n-cppcoreguidelines-no-malloc,\\\n-cppcoreguidelines-owning-memory,\\\n-cppcoreguidelines-pro-type-union-access,\\\n-cppcoreguidelines-pro-bounds-array-to-pointer-decay,\\\n-cppcoreguidelines-pro-bounds-constant-array-index,\\\n-cppcoreguidelines-pro-bounds-pointer-arithmetic,\\\n# not easily possible to implement (maybe replace by specific exclusions),\\\n-cppcoreguidelines-pro-type-vararg,\\\n-cppcoreguidelines-pro-type-reinterpret-cast,\\\n-hicpp-signed-bitwise,\\\n# duplicates,\\\n-google-readability-braces-around-statements,\\\n-cppcoreguidelines-pro-type-cstyle-cast,\\\n-cppcoreguidelines-avoid-magic-numbers,\\\n-readability-magic-numbers,\\\n-hicpp-braces-around-statements,\\\n-hicpp-use-equals-default,\\\n-hicpp-deprecated-headers,\\\n-hicpp-no-assembler,\\\n-hicpp-vararg,\\\n-hicpp-use-auto,\\\n-hicpp-use-nullptr,\\\n-hicpp-no-array-decay,\\\n-hicpp-member-init\"\nWarningsAsErrors: ''\nHeaderFilterRegex: ''\n# AnalyzeTemporaryDtors: false\nCheckOptions:\n  # - key:             cert-dcl59-cpp.HeaderFileExtensions\n    # value:           h,hh,hpp,hxx\n  # - key:             cert-err61-cpp.CheckThrowTemporaries\n    # value:           '1'\n  # - key:             cert-oop11-cpp.IncludeStyle\n    # value:           llvm\n  # - key:             cert-oop11-cpp.UseCERTSemantics\n    # value:           '1'\n  # - key:             cppcoreguidelines-pro-bounds-constant-array-index.GslHeader\n    # value:           ''\n  # - key:             cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle\n    # value:           '0'\n  # - key:             cppcoreguidelines-pro-type-member-init.IgnoreArrays\n    # value:           '0'\n  # - key:             google-build-namespaces.HeaderFileExtensions\n    # value:           h,hh,hpp,hxx\n  # - key:             google-global-names-in-headers.HeaderFileExtensions\n    # value:           h\n  # - key:             google-readability-braces-around-statements.ShortStatementLines\n    # value:           '1'\n  # - key:             google-readability-function-size.BranchThreshold\n    # value:           '4294967295'\n  # - key:             google-readability-function-size.LineThreshold\n    # value:           '4294967295'\n  # - key:             google-readability-function-size.StatementThreshold\n    # value:           '800'\n  # - key:             google-readability-namespace-comments.ShortNamespaceLines\n    # value:           '10'\n  # - key:             google-readability-namespace-comments.SpacesBeforeComments\n    # value:           '2'\n  # - key:             google-runtime-int.SignedTypePrefix\n    # value:           int\n  # - key:             google-runtime-int.TypeSuffix\n    # value:           ''\n  # - key:             google-runtime-int.UnsignedTypePrefix\n    # value:           uint\n  # - key:             llvm-namespace-comment.ShortNamespaceLines\n    # value:           '1'\n  # - key:             llvm-namespace-comment.SpacesBeforeComments\n    # value:           '1'\n  # - key:             misc-assert-side-effect.AssertMacros\n    # value:           assert\n  # - key:             misc-assert-side-effect.CheckFunctionCalls\n    # value:           '0'\n  # - key:             misc-dangling-handle.HandleClasses\n    # value:           'std::basic_string_view;std::experimental::basic_string_view'\n  # - key:             misc-definitions-in-headers.HeaderFileExtensions\n    # value:           ',h,hh,hpp,hxx'\n  # - key:             misc-definitions-in-headers.UseHeaderFileExtension\n    # value:           '1'\n  # - key:             misc-misplaced-widening-cast.CheckImplicitCasts\n    # value:           '1'\n  # - key:             misc-move-constructor-init.IncludeStyle\n    # value:           llvm\n  # - key:             misc-move-constructor-init.UseCERTSemantics\n    # value:           '0'\n  # - key:             misc-sizeof-expression.WarnOnSizeOfCompareToConstant\n    # value:           '1'\n  # - key:             misc-sizeof-expression.WarnOnSizeOfConstant\n    # value:           '1'\n  # - key:             misc-sizeof-expression.WarnOnSizeOfThis\n    # value:           '1'\n  # - key:             misc-string-constructor.LargeLengthThreshold\n    # value:           '8388608'\n  # - key:             misc-string-constructor.WarnOnLargeLength\n    # value:           '1'\n  # - key:             misc-suspicious-missing-comma.MaxConcatenatedTokens\n    # value:           '5'\n  # - key:             misc-suspicious-missing-comma.RatioThreshold\n    # value:           '0.200000'\n  # - key:             misc-suspicious-missing-comma.SizeThreshold\n    # value:           '5'\n  # - key:             misc-suspicious-string-compare.StringCompareLikeFunctions\n    # value:           ''\n  # - key:             misc-suspicious-string-compare.WarnOnImplicitComparison\n    # value:           '1'\n  # - key:             misc-suspicious-string-compare.WarnOnLogicalNotComparison\n    # value:           '0'\n  # - key:             misc-throw-by-value-catch-by-reference.CheckThrowTemporaries\n    # value:           '1'\n  # - key:             modernize-loop-convert.MaxCopySize\n    # value:           '16'\n  # - key:             modernize-loop-convert.MinConfidence\n    # value:           reasonable\n  # - key:             modernize-loop-convert.NamingStyle\n    # value:           CamelCase\n  # - key:             modernize-pass-by-value.IncludeStyle\n    # value:           llvm\n  # - key:             modernize-replace-auto-ptr.IncludeStyle\n    # value:           llvm\n  # - key:             modernize-use-nullptr.NullMacros\n    # value:           'NULL'\n  # - key:             performance-faster-string-find.StringLikeClasses\n    # value:           'std::basic_string'\n  # - key:             performance-for-range-copy.WarnOnAllAutoCopies\n    # value:           '0'\n  # - key:             readability-braces-around-statements.ShortStatementLines\n    # value:           '1'\n  # - key:             readability-function-size.BranchThreshold\n    # value:           '4294967295'\n  # - key:             readability-function-size.LineThreshold\n    # value:           '4294967295'\n  # - key:             readability-function-size.StatementThreshold\n    # value:           '800'\n  # - key:             readability-identifier-naming.AbstractClassCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.AbstractClassPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.AbstractClassSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ClassCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ClassConstantCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ClassConstantPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ClassConstantSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ClassMemberCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ClassMemberPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ClassMemberSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ClassMethodCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ClassMethodPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ClassMethodSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ClassPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ClassSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstantCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ConstantMemberCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ConstantMemberPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstantMemberSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstantParameterCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ConstantParameterPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstantParameterSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstantPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstantSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstexprFunctionCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ConstexprFunctionPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstexprFunctionSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstexprMethodCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ConstexprMethodPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstexprMethodSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstexprVariableCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ConstexprVariablePrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ConstexprVariableSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.EnumCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.EnumConstantCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.EnumConstantPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.EnumConstantSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.EnumPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.EnumSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.FunctionCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.FunctionPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.FunctionSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.GlobalConstantCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.GlobalConstantPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.GlobalConstantSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.GlobalFunctionCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.GlobalFunctionPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.GlobalFunctionSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.GlobalVariableCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.GlobalVariablePrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.GlobalVariableSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.IgnoreFailedSplit\n    # value:           '0'\n  # - key:             readability-identifier-naming.InlineNamespaceCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.InlineNamespacePrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.InlineNamespaceSuffix\n    # value:           ''\n   - key:             readability-identifier-naming.LocalConstantCase\n     value:           lower_case\n   - key:             readability-identifier-naming.LocalConstantPrefix\n     value:           ''\n   - key:             readability-identifier-naming.LocalConstantSuffix\n     value:           ''\n   - key:             readability-identifier-naming.LocalVariableCase\n     value:           lower_case\n   - key:             readability-identifier-naming.LocalVariablePrefix\n     value:           ''\n   - key:             readability-identifier-naming.LocalVariableSuffix\n     value:           ''\n  # - key:             readability-identifier-naming.MemberCase\n    # value:           lower_case\n  # - key:             readability-identifier-naming.MemberPrefix\n    # value:           '_'\n  # - key:             readability-identifier-naming.MemberSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.MethodCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.MethodPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.MethodSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.NamespaceCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.NamespacePrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.NamespaceSuffix\n    # value:           ''\n   - key:             readability-identifier-naming.ParameterCase\n     value:           lower_case\n  # - key:             readability-identifier-naming.ParameterPackCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ParameterPackPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ParameterPackSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ParameterPrefix\n    # value:           ''\n   - key:             readability-identifier-naming.ParameterSuffix\n     value:           '_'\n   - key:             readability-identifier-naming.PrivateMemberCase\n     value:           lower_case\n   - key:             readability-identifier-naming.PrivateMemberPrefix\n     value:           '_'\n   - key:             readability-identifier-naming.PrivateMemberSuffix\n     value:           ''\n  # - key:             readability-identifier-naming.PrivateMethodCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.PrivateMethodPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.PrivateMethodSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ProtectedMemberCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ProtectedMemberPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ProtectedMemberSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ProtectedMethodCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ProtectedMethodPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ProtectedMethodSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.PublicMemberCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.PublicMemberPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.PublicMemberSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.PublicMethodCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.PublicMethodPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.PublicMethodSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.StaticConstantCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.StaticConstantPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.StaticConstantSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.StaticVariableCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.StaticVariablePrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.StaticVariableSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.StructCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.StructPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.StructSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.TemplateParameterCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.TemplateParameterPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.TemplateParameterSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.TemplateTemplateParameterCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.TemplateTemplateParameterPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.TemplateTemplateParameterSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.TypeTemplateParameterCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.TypeTemplateParameterPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.TypeTemplateParameterSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.TypedefCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.TypedefPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.TypedefSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.UnionCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.UnionPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.UnionSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.ValueTemplateParameterCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.ValueTemplateParameterPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.ValueTemplateParameterSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.VariableCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.VariablePrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.VariableSuffix\n    # value:           ''\n  # - key:             readability-identifier-naming.VirtualMethodCase\n    # value:           aNy_CasE\n  # - key:             readability-identifier-naming.VirtualMethodPrefix\n    # value:           ''\n  # - key:             readability-identifier-naming.VirtualMethodSuffix\n    # value:           ''\n  # - key:             readability-simplify-boolean-expr.ChainedConditionalAssignment\n    # value:           '0'\n  # - key:             readability-simplify-boolean-expr.ChainedConditionalReturn\n    # value:           '0'\n   - key:             modernize-use-override.OverrideSpelling\n     value:           'ZMQ_OVERRIDE'\n   - key:             modernize-use-override.FinalSpelling\n     value:           'ZMQ_FINAL'\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "# tree-wide clang format\n41f459e1dc6f7cdedd1268298153c970e290b2ce\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Pull Request Notice\n\nBefore sending a pull request make sure each commit solves one clear, minimal,\nplausible problem. Further each commit should have the following format:\n\n```\nProblem: X is broken\n\nSolution: do Y and Z to fix X\n```\n\nPlease try to have the code changes conform to our coding style. For your\nconvenience, you can install clang-format (at least version 5.0) and then\nrun ```make clang-format-check```. Don't fix existing issues, if any - just\nmake sure your changes are compliant. ```make clang-format-diff``` will\nautomatically apply the required changes.\nTo set a specific clang-format binary with autotools, you can for example\nrun: ```./configure CLANG_FORMAT=clang-format-5.0```\n\nPlease avoid sending a pull request with recursive merge nodes, as they\nare impossible to fix once merged. Please rebase your branch on\nzeromq/libzmq master instead of merging it.\n\n```\ngit remote add upstream git@github.com:zeromq/libzmq.git\ngit fetch upstream\ngit rebase upstream/master\ngit push -f\n```\n\nIn case you already merged instead of rebasing you can drop the merge commit.\n\n```\ngit rebase -i HEAD~10\n```\n\nNow, find your merge commit and mark it as drop and save. Finally rebase!\n\nIf you are a new contributor please have a look at our contributing guidelines:\n[CONTRIBUTING](http://zeromq.org/docs:contributing)\n\n# FIRST TIME CONTRIBUTORS PLEASE NOTE\n\nPlease add an additional commit with a relicensing grant.\n\n[Example](https://github.com/zeromq/libzmq/commit/fecbd42dbe45455fff3b6456350ceca047b82050)\n\n[More information on RELICENSING effort](https://github.com/zeromq/libzmq/tree/master/RELICENSE/README.md)\n"
  },
  {
    "path": ".github/issue_template.md",
    "content": "*Please use this template for reporting suspected bugs or requests for help.*\n\n# Issue description\n\n\n\n# Environment\n\n* libzmq version (commit hash if unreleased): \n* OS: \n\n# Minimal test code / Steps to reproduce the issue\n\n1.  \n\n\n# What's the actual result? (include assertion message & call stack if applicable)\n\n\n\n# What's the expected result?\n\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 365\n# Number of days of inactivity before a stale issue is closed\ndaysUntilClose: 56\n# Issues with these labels will never be considered stale\nexemptLabels:\n  - \"Help Request\"\n  - \"Feature Request\"\n  - \"Problem reproduced\"\n  - Critical\n# Label to use when marking an issue as stale\nstaleLabel: stale\n# Comment to post when marking an issue as stale. Set to `false` to disable\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  activity for 365 days. It will be closed if no further activity occurs within\n  56 days. Thank you for your contributions.\n# Comment to post when closing a stale issue. Set to `false` to disable\ncloseComment: false\n"
  },
  {
    "path": ".github/workflows/CI.yaml",
    "content": "name: CI\non:\n  push:\n  pull_request:\n  schedule:\n    - cron: \"0 9 * * 5\"\n\njobs:\n  build:\n    if: github.event_name == 'pull_request' || github.event_name == 'push'\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - platform: x64\n            configuration: release\n            os: windows-2019\n            WITH_LIBSODIUM: ON\n            ENABLE_CURVE: ON\n            CMAKE_GENERATOR: Visual Studio 16 2019\n            MSVCVERSION: v142\n            MSVCYEAR: vs2019\n            ARTIFACT_NAME: v142-x64\n            ENABLE_DRAFTS: ON\n          - os: ubuntu-latest\n            BUILD_TYPE: default\n            PACKAGES: asciidoctor\n            DRAFT: disabled\n            POLLER: select\n          - os: ubuntu-latest\n            BUILD_TYPE: default\n            DRAFT: disabled\n            POLLER: poll\n          - os: ubuntu-latest\n            BUILD_TYPE: android\n            NDK_VERSION: android-ndk-r25\n            DRAFT: disabled\n          - os: ubuntu-latest\n            BUILD_TYPE: coverage\n            PACKAGES: libkrb5-dev libnorm-dev libpgm-dev libgnutls28-dev lcov\n            DRAFT: enabled\n            GSSAPI: enabled\n            PGM: enabled\n            NORM: enabled\n            TIPC: enabled\n            TLS: enabled\n            VMCI: enabled\n          - os: ubuntu-latest\n            BUILD_TYPE: valgrind\n            PACKAGES: valgrind libgnutls28-dev\n            DRAFT: enabled\n          - os: ubuntu-latest\n            BUILD_TYPE: cmake\n            CURVE: libsodium\n            DRAFT: enabled\n            PACKAGES: cmake libsodium-dev\n            TLS: enabled\n          - os: ubuntu-latest\n            BUILD_TYPE: cmake\n            CURVE: libsodium\n            DRAFT: enabled\n            GSSAPI: enabled\n            PACKAGES: cmake libsodium-dev libkrb5-dev\n            TLS: enabled\n          - os: ubuntu-latest\n            BUILD_TYPE: cmake\n            DRAFT: enabled\n            PACKAGES: cmake clang-format-18\n            DO_CLANG_FORMAT_CHECK: 1\n          - os: ubuntu-latest\n            BUILD_TYPE: default\n            PACKAGES: libkrb5-dev libnorm-dev libpgm-dev libgnutls28-dev libsodium-dev libnss3-dev libbsd-dev\n            CURVE: libsodium\n            ADDRESS_SANITIZER: enabled\n            DRAFT: enabled\n          - os: ubuntu-latest\n            BUILD_TYPE: default\n            PACKAGES: libkrb5-dev libnorm-dev libpgm-dev libgnutls28-dev libsodium-dev libnss3-dev libbsd-dev\n            CURVE: libsodium\n            GSSAPI: enabled\n            PGM: enabled\n            NORM: enabled\n            TIPC: enabled\n            IPv6: ON\n            TLS: enabled\n            USE_NSS: yes\n            VMCI: enabled\n            DRAFT: enabled\n          - os: ubuntu-latest\n            BUILD_TYPE: default\n            PACKAGES: libkrb5-dev libnorm-dev libpgm-dev libgnutls28-dev libsodium-dev libnss3-dev\n            CURVE: libsodium\n            GSSAPI: enabled\n            PGM: enabled\n            NORM: enabled\n            TIPC: enabled\n            IPv6: ON\n            TLS: enabled\n            USE_NSS: yes\n            VMCI: enabled\n            DRAFT: enabled\n            FORCE_98: enabled\n            CXX: clang++\n          - os: ubuntu-latest\n            BUILD_TYPE: abi-compliance-checker\n            PACKAGES: abi-dumper abi-compliance-checker\n            DRAFT: disabled\n          - os: ubuntu-latest\n            BUILD_TYPE: cmake\n            PACKAGES: clang-tidy clang-tools\n            DRAFT: enabled\n            CXX: clang++\n          - os: macos-latest\n            BUILD_TYPE: default\n            PACKAGES: automake autoconf libtool\n            DRAFT: enabled\n          - os: macos-latest\n            BUILD_TYPE: default\n            PACKAGES: automake autoconf libtool libsodium\n            CURVE: libsodium\n            DRAFT: disabled\n    env:\n      platform: ${{ matrix.platform }}\n      configuration: ${{ matrix.configuration }}\n      WITH_LIBSODIUM: ${{ matrix.WITH_LIBSODIUM }}\n      ENABLE_CURVE: ${{ matrix.ENABLE_CURVE }}\n      CMAKE_GENERATOR: ${{ matrix.CMAKE_GENERATOR }}\n      MSVCVERSION: ${{ matrix.MSVCVERSION }}\n      MSVCYEAR: ${{ matrix.MSVCYEAR }}\n      ARTIFACT_NAME: ${{ matrix.ARTIFACT_NAME }}\n      ENABLE_DRAFTS: ${{ matrix.ENABLE_DRAFTS }}\n      SODIUM_INCLUDE_DIR: ${{ github.workspace }}\\libsodium\\src\\libsodium\\include\"\n      SODIUM_LIBRARY_DIR: ${{ github.workspace }}\\libsodium\\bin\\${{ matrix.platform }}\\${{ matrix.configuration }}\\${{ matrix.MSVCVERSION }}\\dynamic\"\n      LIBZMQ_SRCDIR: ${{ github.workspace }}\\libzmq\n      BUILD_TYPE: ${{ matrix.BUILD_TYPE }}\n      CURVE: ${{ matrix.CURVE }}\n      DRAFT: ${{ matrix.DRAFT }}\n      ADDRESS_SANITIZER: ${{ matrix.ADDRESS_SANITIZER }}\n      DO_CLANG_FORMAT_CHECK: ${{ matrix.DO_CLANG_FORMAT_CHECK }}\n      FORCE_98: ${{ matrix.FORCE_98 }}\n      CXX: ${{ matrix.CXX }}\n      GSSAPI: ${{ matrix.GSSAPI }}\n      PGM: ${{ matrix.PGM }}\n      NORM: ${{ matrix.NORM }}\n      TIPC: ${{ matrix.TIPC }}\n      IPv6: ${{ matrix.IPv6 }}\n      TLS: ${{ matrix.TLS }}\n      USE_NSS: ${{ matrix.USE_NSS }}\n      VMCI: ${{ matrix.VMCI }}\n      POLLER: ${{ matrix.POLLER }}\n      NDK_VERSION: ${{ matrix.NDK_VERSION }}\n      ANDROID_NDK_ROOT: /tmp/${{ matrix.NDK_VERSION }}\n    steps:    \n    - name: Add msbuild to PATH\n      uses: microsoft/setup-msbuild@v1.0.2\n      if: matrix.os == 'windows-2019'\n    - uses: actions/checkout@v2\n      if: matrix.WITH_LIBSODIUM == 'ON'\n      with:\n        repository: jedisct1/libsodium\n        ref: stable\n        path: libsodium\n    - name: Compile libsodium\n      if: matrix.WITH_LIBSODIUM == 'ON' && matrix.os == 'windows-2019'\n      shell: cmd\n      working-directory: libsodium\n      run: msbuild /v:minimal /p:Configuration=%Configuration%DLL builds\\msvc\\%MSVCYEAR%\\libsodium\\libsodium.vcxproj\n    - name: Copy libsodium\n      if: matrix.WITH_LIBSODIUM == 'ON' && matrix.os == 'windows-2019'\n      shell: powershell\n      working-directory: libsodium\n      run: Copy-Item \"bin\\${env:Platform}\\${env:Configuration}\\${env:MSVCVERSION}\\dynamic\\libsodium.lib\" -Destination \"bin\\${env:Platform}\\${env:Configuration}\\${env:MSVCVERSION}\\dynamic\\sodium.lib\"\n    - uses: actions/checkout@v2    \n      with:    \n        path: libzmq\n    - run: md build_libzmq\n      shell: cmd\n      if: matrix.os == 'windows-2019'\n    - name: build-win\n      if: matrix.os == 'windows-2019'\n      shell: cmd\n      working-directory: build_libzmq\n      run: |        \n        cmake -D CMAKE_INCLUDE_PATH=\"%SODIUM_INCLUDE_DIR%\" -D CMAKE_LIBRARY_PATH=\"%SODIUM_LIBRARY_DIR%\" -D WITH_LIBSODIUM=\"%WITH_LIBSODIUM%\" -D ENABLE_DRAFTS=\"%ENABLE_DRAFTS%\" -D ENABLE_ANALYSIS=\"%ENABLE_ANALYSIS%\" -D ENABLE_CURVE=\"%ENABLE_CURVE%\" -D API_POLLER=\"%API_POLLER%\" -D POLLER=\"%POLLER%\" %EXTRA_FLAGS% -D WITH_LIBSODIUM=\"%WITH_LIBSODIUM%\" -D LIBZMQ_WERROR=\"%LIBZMQ_WERROR%\" -G \"%CMAKE_GENERATOR%\" \"%LIBZMQ_SRCDIR%\"\n        cmake --build . --config %configuration% --target install -- -verbosity:Minimal -maxcpucount           \n    - name: test\n      if: matrix.os == 'windows-2019'\n      shell: cmd\n      working-directory: build_libzmq\n      run: ctest -C \"%Configuration%\"\n    - name: Add debian packages\n      if: matrix.os == 'ubuntu-latest' && (matrix.BUILD_TYPE != 'coverage' || github.repository == 'zeromq/libzmq')\n      uses: myci-actions/add-deb-repo@10\n      with:\n        repo-name: obs\n        repo: deb http://download.opensuse.org/repositories/network:/messaging:/zeromq:/git-stable/xUbuntu_20.04/ ./\n        keys-asc: https://download.opensuse.org/repositories/network:/messaging:/zeromq:/git-stable/xUbuntu_20.04/Release.key\n        install: ${{ matrix.PACKAGES }}\n    - name: Add brew packages\n      if: matrix.os == 'macos-latest'\n      shell: bash\n      run: brew install ${{ matrix.PACKAGES }}\n    - name: build\n      if: (matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest') && (matrix.BUILD_TYPE != 'coverage' || github.repository == 'zeromq/libzmq')\n      shell: bash\n      working-directory: libzmq\n      run: ./ci_build.sh\n    - name: coveralls\n      if: matrix.BUILD_TYPE == 'coverage' && github.repository == 'zeromq/libzmq'\n      uses: coverallsapp/github-action@master\n      with:\n        github-token: ${{ secrets.GITHUB_TOKEN }}\n        path-to-lcov: /home/runner/work/libzmq/libzmq/libzmq/lcov.info\n  cron:\n    runs-on: ubuntu-latest\n    if: github.event_name == 'schedule'\n    strategy:\n      fail-fast: false\n    env:\n      BUILD_TYPE: cmake\n      CXX: clang++\n      CLANG_TIDY: clang-tidy\n    steps:\n    - name: Add debian packages\n      run: sudo apt-get install --yes clang-tidy clang-tools\n    - name: build\n      shell: bash\n      working-directory: libzmq\n      run: ./ci_build.sh\n"
  },
  {
    "path": ".github/workflows/Docs.yaml",
    "content": "# Simple workflow for deploying static content to GitHub Pages\nname: Deploy API docs content to Pages\n\non:\n  # Runs on pushes targeting the default branch\n  push:\n    branches: [\"master\"]\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\n# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.\n# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.\nconcurrency:\n  group: \"pages\"\n  cancel-in-progress: false\n\njobs:\n  # Single deploy job since we're just deploying\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n\n      ## libzmq-specific CI/CD ##\n      - name: Install AsciiDoctor\n        run: sudo apt install -y asciidoctor\n      - name: Convert AsciiDoc with AsciiDoctor into HTML\n        run: ./autogen.sh && ./configure && make --directory=doc\n\n      ## boilerplate steps to publish github Pages ##\n      - name: Setup Pages\n        uses: actions/configure-pages@v3\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v2\n        with:\n          path: 'doc/'\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v2\n"
  },
  {
    "path": ".github/workflows/Fuzzers.yaml",
    "content": "name: Fuzzers\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    paths:\n      - '.github/workflows/Fuzzers.yaml'\n      - 'src/*'\n      - 'tests/*fuzzer.cpp'\njobs:\n  Fuzzing:\n    runs-on: ubuntu-latest\n    if: github.repository == 'zeromq/libzmq'\n    strategy:\n      matrix:\n        san: [address, memory, undefined]\n    steps:\n    - name: Build Fuzzers (${{ matrix.san }})\n      id: build\n      uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master\n      with:\n        sanitizer: ${{ matrix.san }}\n        oss-fuzz-project-name: 'libzmq'\n        allowed-broken-targets-percentage: 0\n        dry-run: false\n    - name: Run Fuzzers (${{ matrix.san }})\n      id: run\n      uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master\n      with:\n        sanitizer: ${{ matrix.san }}\n        oss-fuzz-project-name: 'libzmq'\n        allowed-broken-targets-percentage: 0\n        dry-run: false\n        fuzz-seconds: 300\n"
  },
  {
    "path": ".gitignore",
    "content": "syntax: glob # for hg-git users\n\n# Generated build scripts and IDE generating files\n## autotools\n/Makefile\nbuilds/Makefile\nbuilds/deprecated-msvc/Makefile\ndoc/Makefile\ndoc/__pagelist\nlibtool\n### automake\nMakefile.in\n.deps/\n.dirstamp\n### autoconf\nautom4te.cache\naclocal.m4\nconfig\nconfig.status\nconfig.log\nconfigure\nstamp-h1\n## CMake\ncmake-build-debug/\nbuild/\n## Android\nbuilds/android/prefix\n## IntelliJ\n.idea/\n## Visual Code\n.vscode/\n## other results-like folders\nbin/\nlib/\nobj/\n## Doxygen\ndoxygen/\n## Packaging \npackaging/nuget/*.nupkg\n\n# Test related build files\nlibtestutil.a\nlibunity.a\n\n# Some build outputs and temporal files\n*.o\n*.gcno\n*.gcda\n*.gcov\n*.ncb\n*.lo\n*.loT\n*.la\n*.exe\n*.html\n*.pdf\n*.ps\n*~\n.*~\n.libs\n\n# /src\n## Ignore generated files in configuration process\nsrc/platform.hpp*\nsrc/libzmq.pc\n\n# /tools\n## Executable binaries are ignored\ntools/curve_keygen\n## Executable source files must be tracked\n!tools/*.[ch]\n!tools/*.[ch]pp\n\n# /tests\n## Test binaries and logs are ignored\ntests/test*\ntests/test*.log\ntests/test*.trs\n## Test source files must be tracked\n!tests/test*.[ch]\n!tests/test*.[ch]pp\n## Build script and documentations must be tracked\n!tests/CMakeLists.txt\n!tests/README.md\n\n# /unittests\n## Unit test binaries and logs are ignored\nunittests/unittest_*\nunittests/unittest*.log\nunittests/unittest*.trs\n## Unit test source files must be tracked\n!unittests/unittest*.[ch]\n!unittests/unittest*.[ch]pp\n## Build script and documentations must be tracked\n!unittests/CMakeLists.txt\n!unittests/README.md\n\n# check test log files\ntest-suite*.log\n\n# /perf\n## Benchmarking binaries and result files are ignored\nperf/*_lat\nperf/*_thr\nperf/benchmark_*\nperf/results\n## Benchmarking source files must be tracked\n!perf/*.[ch]\n!perf/*.[ch]pp\n## Benchmarking tool scripts must be tracked\n!perf/*.py\n!perf/*.sh\n\n# /doc\n## Generated document files \ndoc/*.[137]\ndoc/*.html\ndoc/*.xml\n\n# external libraries and release archive files\nforeign/openpgm/*\n!foreign/openpgm/*.tar.bz2\n!foreign/openpgm/*.tar.gz\n!foreign/openpgm/Makefile.am\nzeromq-*.tar.gz\nzeromq-*.zip\ncore\n\nmybuild\n"
  },
  {
    "path": ".hgeol",
    "content": "[patterns]\n** = native\n"
  },
  {
    "path": ".mailmap",
    "content": "Ahmet Kakici <ahmet.kakici@pro-line.com.tr> ahmet <ahmet.kakici@pro-line.com.tr>\nAndrey Sibiryov <me@kobology.ru> Kobolog <me@kobology.ru>\nBrian Knox <taotetek@gmail.com> taotetek <taotetek@users.noreply.github.com>\nChernyshev Vyacheslav <astellar@ro.ru> Astellar <astellar@ro.ru>\nChris Laws <clawsicus@gmail.com> Chris Laws <claws@localhost>\nChris Staite <chris@yourdreamnet.co.uk> Chris <chris@yourdreamnet.co.uk>\nChristoph Zach <czach@rst-automation.com> czach <czach@rst-automation.com>\nChuck Remes <git@chuckremes.com> Chuck Remes <cremes@mac.com>\nChuck Remes <git@chuckremes.com> Chuck Remes <cremes.devlist@mac.com>\nConstantin Rack <constantin.rack@gmail.com> Constantin Rack <constantin@rack.li>\nConstantin Rack <constantin.rack@gmail.com> Constantin Rack <c-rack@users.noreply.github.com>\nDaniel Krikun <krikun.daniel@gmail.com> danielkr <krikun.daniel@gmail.com>\nDaiyu Hurst <daiyu.hurst@gmail.com> DaiyuHurst <daiyu.hurst@gmail.com>\nDiego Rodriguez-Losada <diego.rlosada@gmail.com> Diego <diego.rlosada@gmail.com>\nDongmin Yu <miniway@gmail.com> Min(Dongmin Yu) <miniway@gmail.com>\nDoron Somech <somdoron@gmail.com> somdoron <somdoron@gmail.com>\nElliot Saba <staticfloat@gmail.com> staticfloat <staticfloat@gmail.com>\nEric Voskuil <eric@voskuil.org> evoskuil <eric@voskuil.org>\nEric Voskuil <eric@voskuil.org> anonymous <eric@voskuil.org>\nFelipe Farinon <felipe.farinon@powersyslab.com> psl-felipefarinon <felipe.farinon@powersyslab.com>\nFrank Hartmann <soundart@gmx.net> Frank <soundart@gmx.net>\nGian Lorenzo Meocci <glmeocci@gmail.com> meox <glmeocci@gmail.com>\nHardeep Singh <hshardeesi@gmail.com> Hardeep <hshardeesi@gmail.com>\nHenrik Feldt <henrik@haf.se> Henrik <henrik@haf.se>\nHuang Xin <chrox.huang@gmail.com> chrox <chrox.huang@gmail.com>\nIan Barber <ian.barber@gmail.com> Ian Barber <ianbarber@google.com>\nJens Auer <jens.auer@cgi.com> Jens Auer <jens-auer@users.noreply.github.com>\nJens Auer <jens.auer@cgi.com> Jens Auer <jens.auer@betaversion.net>\nJoe Eli McIlvain <joe.eli.mac@gmail.com> Joe McIlvain <joe.eli.mac@gmail.com>\nJos Decoster <jos.decoster@gmail.com> jdc8 <jos.decoster@gmail.com>\nJos Decoster <jos.decoster@gmail.com> Jos Decoster <jos.decoster@retarget.com>\nJoshua Gao <jmg116@gmail.com> Josh Gao <jgao@mobileiron.com>\nJörg Kreuzberger <joerg@kreuzberger.eu> kreuzberger <joerg@kreuzberger.eu>\nArnaud Kapp <kapp.arno@gmail.com> Kapp Arnaud <kapp.arno@gmail.com>\nArnaud Kapp <kapp.arno@gmail.com> KAPP Arnaud <kapp.arno@gmail.com>\nArnaud Kapp <kapp.arno@gmail.com> KAPP Arnaud <xaqq@users.noreply.github.com>\nKenneth Wilke <kenneth.wilke@rackspace.com> KennethWilke <kenneth.wilke@rackspace.com>\nKevin Sapper <mail@kevinsapper.de> sappo <mail@kevinsapper.de>\nKevin Sapper <mail@kevinsapper.de> Kevin Sapper <sappo@users.noreply.github.com>\nLeonard Michelet <leonard.michelet@openwide.fr> leonarf <leonard.michelet@openwide.fr>\nMartijn Jasperse <m.jasperse@gmail.com> mjasperse <m.jasperse@gmail.com>\nMartin Hurton <hurtonm@gmail.com> Martin Hurtoň <hurtonm@gmail.com>\nMartin Lucina <martin@lucina.net> Martin Lucina <mato@kotelna.sk>\nMartin Sustrik <sustrik@250bpm.com> Martin Sustrik <sustrik@fastmq.commkdir>\nMartin Sustrik <sustrik@250bpm.com> Martin Sustrik <sustrik@fastmq.com>\nMartin Sustrik <sustrik@250bpm.com> sustrik <sustrik@250bpm.com>\nMartin Sustrik <sustrik@250bpm.com> Martin Sustrik <sustrik@jozsi.(none)>\nMartin Sustrik <sustrik@250bpm.com> unknown <sustrik@.(none)>\nMartin Sustrik <sustrik@250bpm.com> Martin Sustrik <sustrik@turist.(none)>\nMaurice Barnum <msb@yahoo-inc.com> maurice barnum <msb@yahoo-inc.com>\nMaurizio Melato <maurizio.melato@nice-software.com> unknown <mauri@okinawa.(none)>\nMax Skaller <Max.Skaller@gmail.com> skaller <Max.Skaller@gmail.com>\nMichael Fox <415fox@gmail.com> m <415fox@gmail.com>\nMichael Hand <mipa@matrix.by> Mipa <mipa@matrix.by>\nMichel Zou <xantares10@hotmail.com> xantares <xantares09@hotmail.com>\nMikael Helbo Kjaer <mhk@designtech.dk> Mikael Helbo Kjær <mhk@designtech.dk>\nMike Gatny <mgatny@gmail.com> Mike Gatny <mgatny@connamara.com>\nMikko Koppanen <mikko.koppanen@gmail.com> Mikko Koppanen <mkoppanen@php.net>\nMikko Koppanen <mikko.koppanen@gmail.com> Mikko Koppanen <mikko@kuut.io>\nMikko Koppanen <mikko.koppanen@gmail.com> Mikko Koppanen <mkoppanen@gameboy.config>\nMin RK <benjaminrk@gmail.com> MinRK <benjaminrk@gmail.com>\nMin RK <benjaminrk@gmail.com> Min Ragan-Kelley <benjaminrk@gmail.com>\nMontoya Edu <montoya.edu@gmail.com> montoyaedu <montoya.edu@gmail.com>\nNikita Kozlov <nikita@elyzion.net> nikita kozlov <nikita@elyzion.net>\nPavol Malosek <malosek@fastmq.com> malosek <malosek@fastmq.com>\nPieter Hintjens <ph@imatix.com> Pieter Hintjens <ph@itmatix.com>\nReza Ebrahimi <reza.ebrahimi.dev@gmail.com> reza.ebrahimi <reza.ebrahimi.dev@gmail.com>\nRicardo Catalinas Jiménez <r@untroubled.be> Ricardo Catalinas Jiménez <jimenezrick@gmail.com>\nRohan Bedarkar <rohanb@cs.uchicago.edu> rohanbedarkar <rohanb@cs.uchicago.edu>\nRohan Bedarkar <rohanb@cs.uchicago.edu> Rohan <rbe@ws5-34-chi.rtsgroup.net>\nSergey KHripchenko <shripchenko@intermedia.net> root <root@ast-pbx-mt-3.intermedia.net>\nSergey KHripchenko <shripchenko@intermedia.net> shripchenko <shripchenko@intermedia.net>\nSergey M. <dstftw@gmail.com> Sergey M․ <dstftw@gmail.com>\nSteven McCoy <steven.mccoy@miru.hk> Steve-o <fnjordy@gmail.com>\nTamara Kustarova <kustarova@fastmq.com> tamara <tamara@jozsi.(none)>\nTimothee Besset <ttimo@ttimo.net> Timothee \"TTimo\" Besset <ttimo@ttimo.net>\nTimothy Mossbarger <tim@ent.net> Tim M <tim@ent.net>\nTrevor Bernard <trevor.bernard@gmail.com> Trevor Bernard <tbernard@liveops.com>\nTrevor Bernard <trevor.bernard@gmail.com> Trevor Bernard <trevor.bernard@userevents.com>\nVolodymyr Korniichuk <VolodymyrKorn@gmail.com> Volodymyr Korniichuk <9173519@gmail.com>\nlysyloren <lysy_loren@gmail.com> lysyloren <lysy.loren@gmail.com>\n"
  },
  {
    "path": ".obs/workflows.yml",
    "content": "workflow:\n  steps:\n    - branch_package:\n        source_project: network:messaging:zeromq:git-draft\n        source_package: libzmq\n        target_project: network:messaging:zeromq:ci\nrebuild:\n  steps:\n    - trigger_services:\n        project: network:messaging:zeromq:git-stable\n        package: libzmq\n    - trigger_services:\n        project: network:messaging:zeromq:git-draft\n        package: libzmq\n  filters:\n    event: push\nrelease:\n  steps:\n    - trigger_services:\n        project: network:messaging:zeromq:release-stable\n        package: libzmq\n    - trigger_services:\n        project: network:messaging:zeromq:release-draft\n        package: libzmq\n  filters:\n    event: tag_push\n"
  },
  {
    "path": ".readthedocs.yaml",
    "content": "#\n# libzmq readthedocs.io integration\n#\n# This configuration file is processed by readthedocs.io to rebuild the\n# libzmq documentation using Asciidoctor, see\n#   https://docs.readthedocs.io/en/stable/build-customization.html#asciidoc\n\nversion: \"2\"\n\nformats:\n  - htmlzip\n\nbuild:\n  os: \"ubuntu-22.04\"\n  tools:\n    nodejs: \"20\"\n  # NOTE: as of Nov 2023, build.apt_packages is NOT considered when using build.commands\n  #apt_packages:\n  #  - automake\n  #  - autoconf\n  #  - cmake\n  #  - libtool\n  commands:\n    # install required tools\n    - npm install -g asciidoctor\n\n    # HTML docs\n    # ---------\n    - doc/create_page_list.sh \"$(pwd)/doc/__pagelist\" \"$(pwd)/doc\"\n    - asciidoctor --backend html --destination-dir $READTHEDOCS_OUTPUT/html --attribute stylesheet=asciidoctor.css --attribute zmq_version='4.3.6' --attribute zmq_pagelist_dir=$(pwd)/doc doc/*.adoc\n\n    # HTMLZIP docs\n    # ------------\n    # Note that for usability we make sure zip will create a zipfile containing just a flat list of HTML files; \n    # to achieve that it's important to avoid storing absolute paths when invoking \"zip\", thus we use -j\n    # Also note that the archive name should match exactly the project slug, \"libzmq\" in this case.\n    - mkdir -p $READTHEDOCS_OUTPUT/htmlzip/\n    - cd $READTHEDOCS_OUTPUT/html && zip -j ../htmlzip/libzmq.zip *.html\n"
  },
  {
    "path": ".travis.yml",
    "content": "# Travis CI script\n\nlanguage: c\n\nos:\n- linux\n\ndist: bionic\n\ncache: ccache\n\nenv:\n  matrix:\n    - BUILD_TYPE=default\n  # tokens to deploy releases on OBS and create/delete temporary branch on Github.\n  # 1) Create a token on https://github.com/settings/tokens/new with \"public_repo\"\n  #    capability and encrypt it with travis encrypt --org -r zeromq/libzmq GH_TOKEN=\"<token>\"\n  # 2) Create 2 OBS tokens with osc token --create network:messaging:zeromq:release-<stable|draft> libzmq\n  #    encrypt them with travis encrypt --org -r zeromq/libzmq OBS_<STABLE|DRAFT>_TOKEN=\"<token>\"\n  global:\n    - secure: aaIs9Y44FYp9VFCqa6LLD4illBH4aUfbS0zzzbAQ5xJvD6NfBsMiKEIhf/kRNCHAtP+1VfQVOejTD6/i08ALsVr3cZD9oB/t7874tz2/jeZUIhRNo+1KwyaVqNg0yUSV6ASIoq4aOfuGnjBlezNQ8LQ2bjQB2m4Enl5wxoYcYdA=\n    - secure: YFrcedBIKe0NR1WC6qQi9phZgtnzOiBIXm40TirvCtstV4eVnSouKgtQfLLArZ4o2tjflq4grQQNo1rJatvyi5YPOXsMcndsni18S+4Ffu8qbECdtPrK52vBweuf7q9oV9Ydax0Fm4bEqEMOZ2/mRBy3nK+mgsE3upeMwyWR0Zw=\n    - secure: lbZSzmqN39QdJwewKOZgq/1ijPKuyx9MFrGzMqXj2+eOSlaZS/tNavHMdKJOev+qJGK9wxmwzxOxS10AiH+AvN7WBacXX4ZtudjScz2HKJRDWTKyzMbzyScq51afniItzrsm+Vo8NHkenNFkux0sSbh0aHlpkLwrGQu+WZWcDN4=\n    - secure: \"ZFL7hLJlGwYix8fF835OnQYakBt/o5iS7IfSW7el44ejEvGAOM9O5/ufxCcqSqn8Np7nOaM3RriAVTqWPZD6S7tMeflGTSGYHPYwWUc83z4rUPyG2FWVKXdB8ufpebAwu3hCgLiSmVeoQG47dl6xNk1oKCd+3UIjgz33u1Ecfps=\"\n\n# Build and check this project according to the BUILD_TYPE\nscript: ./ci_build.sh\n\n# Deploy tags\nbefore_deploy:\n- . ./ci_deploy.sh\ndeploy:\n  provider: releases\n  api_key:\n    secure: vGB5E+A8wxm2J1GJZzmIgT9PrjEzvd9gE8iui8FyxSbxAsW9vFZFGZC/21sTtpVcmRarwQCHH1UEbtg+nJwN2iD9YzMRnSVks8xqP+b709YW+VXaMuhZgTzWa74IorQku7NuvLibvQk72/OSgdwPGaNJ6f5AX9pnWVWbEoW1svE=\n  file_glob: true\n  file: ${LIBZMQ_DEPLOYMENT}\n  skip_cleanup: true\n  on:\n    repo: zeromq/libzmq\n    branch: master\n    tags: true\n    condition: \"$TRAVIS_OS_NAME =~ (linux) && $BUILD_TYPE =~ (default) && $CURVE =~ (libsodium) && -z $DRAFT\"\n"
  },
  {
    "path": "AUTHORS",
    "content": "Corporate Contributors\n======================\n\nCopyright (c) 2007-2014 iMatix Corporation\nCopyright (c) 2009-2011 250bpm s.r.o.\nCopyright (c) 2010-2011 Miru Limited\nCopyright (c) 2011 VMware, Inc.\nCopyright (c) 2012 Spotify AB\nCopyright (c) 2013 Ericsson AB\nCopyright (c) 2014 AppDynamics Inc.\nCopyright (c) 2015 Google, Inc.\nCopyright (c) 2015-2016 Brocade Communications Systems Inc.\n\nIndividual Contributors\n=======================\n\nAJ Lewis\nAlexej Lotz\nAndrew Thompson\nAndré Caron\nAsko Kauppi\nAttila Mark\nBarak Amar\nBen Gray\nBernd Melchers\nBernd Prager\nBob Beaty\nBrandon Carpenter\nBrett Cameron\nBrett Viren\nBrian Buchanan\nBurak Arslan\nCarl Clemens\nChia-liang Kao\nChris Busbey\nChris Rempel\nChris Wong\nChristian Gudrian\nChristian Kamm\nChuck Remes\nConrad D. Steenberg\nConstantin Rack\nDaniel J. Bernstein\nDhammika Pathirana\nDhruva Krishnamurthy\nDirk O. Kaar\nDoron Somech\nDouglas Creager\nDrew Crawford\nErich Heine\nErik Hugne\nErik Rigtorp\nFabien Ninoles\nFrank Denis\nGeorge Neill\nGerard Toonstra\nGhislain Putois\nGonzalo Diethelm\nGuido Goldstein\nHarald Achitz\nHardeep Singh\nHiten Pandya\nIan Barber\nIlja Golshtein\nIlya Kulakov\nIvo Danihelka\nJacob Rideout\nJoe Thornber\nJon Dyte\nKamil Shakirov\nKen Steele\nKouhei Sutou\nLeonardo J. Consoni\nLionel Flandrin\nLourens Naudé\nLuca Boccassi\nMarc Rossi\nMark Barbisan\nMartin Hurton\nMartin Lucina\nMartin Pales\nMartin Sustrik\nMatus Hamorsky\nMax Wolf\nMcClain Looney\nMichael Compton\nMika Fischer\nMikael Helbo Kjaer\nMike Gatny\nMikko Koppanen\nMin Ragan-Kelley\nNeale Ferguson\nNir Soffer\nOsiris Pedroso\nPaul Betts\nPaul Colomiets\nPavel Gushcha\nPavol Malosek\nPerry Kundert\nPeter Bourgon\nPhilip Kovacs\nPieter Hintjens\nPiotr Trojanek\nReza Ebrahimi\nRemi Jouannet\nRichard Newton\nRik van der Heijden\nRobert G. Jakabosky\nSebastian Otaegui\nStefan Radomski\nSteven McCoy\nStuart Webster\nTamara Kustarova\nTaras Shpot\nTero Marttila\nTerry Wilson\nThijs Terlouw\nThomas Rodgers\nTim Mossbarger\nToralf Wittner\nTore Halvorsen\nTrevor Bernard\nVitaly Mayatskikh\nYacheng Zhou\n\nCredits\n=======\n\nAamir Mohammad\nAdrian von Bidder\nAleksey Yeschenko\nAlessio Spadaro\nAlexander Majorov\nAnh Vu\nBernd Schumacher\nBrian Granger\nCarsten Dinkelmann\nDavid Bahi\nDirk Eddelbuettel\nEvgueny Khartchenko\nFrank Vanden Berghen\nIan Barber\nJohn Apps\nMarkus Fischer\nMatt Muggeridge\nMichael Santy\nOleg Sevostyanov\nPaulo Henrique Silva\nPeter Busser\nPeter Lemenkov\nRobert Zhang\nToralf Wittner\nZed Shaw\n\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# CMake build script for ZeroMQ\n\nif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Darwin)\n  cmake_minimum_required(VERSION 3.0.2...3.31)\nelse()\n  cmake_minimum_required(VERSION 2.8.12...3.31)\nendif()\n\nproject(ZeroMQ)\n\ninclude(CheckIncludeFiles)\ninclude(CheckCCompilerFlag)\ninclude(CheckCXXCompilerFlag)\ninclude(CheckLibraryExists)\ninclude(CheckCSourceCompiles)\ninclude(CheckCSourceRuns)\ninclude(CMakeDependentOption)\ninclude(CheckCXXSymbolExists)\ninclude(CheckStructHasMember)\ninclude(CheckTypeSize)\ninclude(FindThreads)\ninclude(GNUInstallDirs)\ninclude(CheckTypeSize)\ninclude(CMakePackageConfigHelpers)\n\nlist(INSERT CMAKE_MODULE_PATH 0 \"${CMAKE_CURRENT_SOURCE_DIR}\")\nset(ZMQ_CMAKE_MODULES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/builds/cmake/Modules)\nlist(APPEND CMAKE_MODULE_PATH ${ZMQ_CMAKE_MODULES_DIR})\n\ninclude(TestZMQVersion)\ninclude(ZMQSourceRunChecks)\ninclude(ZMQSupportMacros)\n\nfind_package(PkgConfig)\n\n# Set lists to empty beforehand as to not accidentally take values from parent\nset(sources)\nset(cxx-sources)\nset(html-docs)\nset(target_outputs)\n\noption(ENABLE_ASAN \"Build with address sanitizer\" OFF)\nif(ENABLE_ASAN)\n  message(STATUS \"Instrumenting with Address Sanitizer\")\n  set(CMAKE_BUILD_TYPE \"RelWithDebInfo\")\n  set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer\")\n  set(CMAKE_CXX_FLAGS\n      \"${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer\")\n  set(CMAKE_SHARED_LINKER_FLAGS \"${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope\")\n  set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope\")\nendif()\n\n# NOTE: Running libzmq under TSAN doesn't make much sense -- synchronization in libzmq is to some extent\n# handled by the code \"knowing\" what threads are allowed to do, rather than by enforcing those\n# restrictions, so TSAN generates a lot of (presumably) false positives from libzmq.\n# The settings below are intended to enable libzmq to be built with minimal support for TSAN\n# such that it can be used along with other code that is also built with TSAN.\noption(ENABLE_TSAN \"Build with thread sanitizer\" OFF)\nif(ENABLE_TSAN)\n  message(STATUS \"Instrumenting with Thread Sanitizer\")\n  set(CMAKE_BUILD_TYPE \"RelWithDebInfo\")\n  set(TSAN_FLAGS \"-fno-omit-frame-pointer -fsanitize=thread\")\n  set(TSAN_CCFLAGS \"${TSAN_CCFLAGS} -mllvm -tsan-instrument-memory-accesses=0\")\n  set(TSAN_CCFLAGS \"${TSAN_CCFLAGS} -mllvm -tsan-instrument-atomics=0\")\n  set(TSAN_CCFLAGS \"${TSAN_CCFLAGS} -mllvm -tsan-instrument-func-entry-exit=1\")\n  set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${TSAN_FLAGS} ${TSAN_CCFLAGS} -fPIE\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} ${TSAN_FLAGS} ${TSAN_CCFLAGS} -fPIE\")\n  set(CMAKE_SHARED_LINKER_FLAGS \"${CMAKE_SHARED_LINKER_FLAGS} ${TSAN_FLAGS} -pie -Qunused-arguments\")\n  set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} ${TSAN_FLAGS} -pie -Qunused-arguments\")\nendif()\n\noption(ENABLE_UBSAN \"Build with undefined behavior sanitizer\" OFF)\nif(ENABLE_UBSAN)\n  message(STATUS \"Instrumenting with Undefined Behavior Sanitizer\")\n  set(CMAKE_BUILD_TYPE \"Debug\")\n  set(UBSAN_FLAGS \"${UBSAN_FLAGS} -fno-omit-frame-pointer\")\n  set(UBSAN_FLAGS \"${UBSAN_FLAGS} -fsanitize=undefined\")\n  set(UBSAN_FLAGS \"${UBSAN_FLAGS} -fsanitize=implicit-conversion\")\n  set(UBSAN_FLAGS \"${UBSAN_FLAGS} -fsanitize=implicit-integer-truncation\")\n  set(UBSAN_FLAGS \"${UBSAN_FLAGS} -fsanitize=integer\")\n  set(UBSAN_FLAGS \"${UBSAN_FLAGS} -fsanitize=nullability\")\n  set(UBSAN_FLAGS \"${UBSAN_FLAGS} -fsanitize=vptr\")\n  set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${UBSAN_FLAGS}\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} ${UBSAN_FLAGS}\")\n  set(CMAKE_SHARED_LINKER_FLAGS \"${CMAKE_SHARED_LINKER_FLAGS} ${UBSAN_FLAGS}\")\n  set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} ${UBSAN_FLAGS}\")\nendif()\n\noption(ENABLE_INTRINSICS \"Build using compiler intrinsics for atomic ops\" OFF)\nif(ENABLE_INTRINSICS)\n  message(STATUS \"Using compiler intrinsics for atomic ops\")\n  add_definitions(-DZMQ_HAVE_ATOMIC_INTRINSICS)\nendif()\n\nset(ZMQ_OUTPUT_BASENAME\n    \"zmq\"\n    CACHE STRING \"Output zmq library base name\")\n\nif(${CMAKE_SYSTEM_NAME} STREQUAL Darwin)\n  # Find more information: https://cmake.org/Wiki/CMake_RPATH_handling\n\n  # Apply CMP0042: MACOSX_RPATH is enabled by default\n  cmake_policy(SET CMP0042 NEW)\n\n  # Add an install rpath if it is not a system directory\n  list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES \"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}\" isSystemDir)\n  if(\"${isSystemDir}\" STREQUAL \"-1\")\n    set(CMAKE_INSTALL_RPATH \"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}\")\n  endif()\n\n  # Add linker search paths pointing to external dependencies\n  set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)\nendif()\n\nif (NOT MSVC)\n  if(NOT CMAKE_CXX_FLAGS MATCHES \"-std=\" AND NOT CXX_STANDARD AND NOT CMAKE_CXX_STANDARD)\n    # use C++11 by default if supported\n    check_cxx_compiler_flag(\"-std=c++11\" COMPILER_SUPPORTS_CXX11)\n    if(COMPILER_SUPPORTS_CXX11)\n      set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++11\")\n    endif()\n  endif()\n  if(NOT CMAKE_C_FLAGS MATCHES \"-std=\" AND NOT C_STANDARD AND NOT CMAKE_C_STANDARD)\n    check_c_compiler_flag(\"-std=c11\" COMPILER_SUPPORTS_C11)\n    if(COMPILER_SUPPORTS_C11)\n      set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -D_DEFAULT_SOURCE -std=c11\")\n    else()\n      set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -std=gnu99\")\n    endif()\n  endif()\n\n  # clang 6 has a warning that does not make sense on multi-platform code\n  check_cxx_compiler_flag(\"-Wno-tautological-constant-compare\" CXX_HAS_TAUT_WARNING)\n  if(CXX_HAS_TAUT_WARNING)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wno-tautological-constant-compare\")\n  endif()\n  check_c_compiler_flag(\"-Wno-tautological-constant-compare\" CC_HAS_TAUT_WARNING)\n  if(CC_HAS_TAUT_WARNING)\n    set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wno-tautological-constant-compare\")\n  endif()\nendif()\n\n# Will be used to add flags to pkg-config useful when apps want to statically link\nset(pkg_config_libs_private \"\")\nset(pkg_config_names_private \"\")\nset(pkg_config_defines \"\")\n\noption(WITH_OPENPGM \"Build with support for OpenPGM\" OFF)\noption(WITH_NORM \"Build with support for NORM\" OFF)\noption(WITH_VMCI \"Build with support for VMware VMCI socket\" OFF)\n\nif(APPLE)\n  option(ZMQ_BUILD_FRAMEWORK \"Build as OS X framework\" OFF)\nendif()\n\nif(EXISTS \"${CMAKE_SOURCE_DIR}/.git\")\n  option(ENABLE_DRAFTS \"Build and install draft classes and methods\" ON)\nelse()\n  option(ENABLE_DRAFTS \"Build and install draft classes and methods\" OFF)\nendif()\n\n# Enable WebSocket transport and RadixTree\nif(ENABLE_DRAFTS)\n  message(STATUS \"Building draft classes and methods\")\n  option(ENABLE_WS \"Enable WebSocket transport\" ON)\n  option(ENABLE_RADIX_TREE \"Use radix tree implementation to manage subscriptions\" ON)\n  set(pkg_config_defines \"-DZMQ_BUILD_DRAFT_API=1\")\nelse()\n  message(STATUS \"Not building draft classes and methods\")\n  option(ENABLE_WS \"Enable WebSocket transport\" OFF)\n  option(ENABLE_RADIX_TREE \"Use radix tree implementation to manage subscriptions\" OFF)\nendif()\n\nif(ENABLE_RADIX_TREE)\n  message(STATUS \"Using radix tree implementation to manage subscriptions\")\n  set(ZMQ_USE_RADIX_TREE 1)\nendif()\n\nif(ENABLE_WS)\n  list(\n    APPEND\n    sources\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_address.cpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_connecter.cpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_decoder.cpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_encoder.cpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_engine.cpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_listener.cpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_address.hpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_connecter.hpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_decoder.hpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_encoder.hpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_engine.hpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_listener.hpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/ws_protocol.hpp)\n  set(ZMQ_HAVE_WS 1)\n\n  message(STATUS \"Enable WebSocket transport\")\n\n  option(WITH_TLS \"Use TLS for WSS support\" ON)\n  option(WITH_NSS \"Use NSS instead of builtin sha1\" OFF)\n\n  if(WITH_TLS)\n    find_package(\"GnuTLS\" 3.6.7)\n    if(GNUTLS_FOUND)\n      set(pkg_config_names_private \"${pkg_config_names_private} gnutls\")\n      list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/src/wss_address.hpp\n           ${CMAKE_CURRENT_SOURCE_DIR}/src/wss_address.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/wss_engine.hpp\n           ${CMAKE_CURRENT_SOURCE_DIR}/src/wss_engine.cpp)\n\n      message(STATUS \"Enable WSS transport\")\n      set(ZMQ_USE_GNUTLS 1)\n      set(ZMQ_HAVE_WSS 1)\n    else()\n      message(WARNING \"No WSS support, you may want to install GnuTLS and run cmake again\")\n    endif()\n  endif()\nendif()\n\nif(NOT ZMQ_USE_GNUTLS)\n  if(WITH_NSS)\n    pkg_check_modules(NSS3 \"nss\")\n    if(NSS3_FOUND)\n      set(pkg_config_names_private \"${pkg_config_names_private} nss\")\n      message(STATUS \"Using NSS\")\n      set(ZMQ_USE_NSS 1)\n    else()\n      find_package(\"NSS3\")\n      if(NSS3_FOUND)\n        set(pkg_config_libs_private \"${pkg_config_libs_private} -lnss3\")\n        message(STATUS \"Using NSS\")\n        set(ZMQ_USE_NSS 1)\n      else()\n        message(WARNING \"No nss installed, if you don't want builtin SHA1, install NSS or GnuTLS\")\n      endif()\n    endif()\n  endif()\n  if(ENABLE_WS AND NOT ZMQ_USE_NSS)\n    list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/external/sha1/sha1.c\n         ${CMAKE_CURRENT_SOURCE_DIR}/external/sha1/sha1.h)\n    message(STATUS \"Using builtin sha1\")\n    set(ZMQ_USE_BUILTIN_SHA1 1)\n  endif()\nendif()\n\nif(NOT MSVC)\n  option(WITH_LIBBSD \"Use libbsd instead of builtin strlcpy\" ON)\n  if(WITH_LIBBSD)\n    pkg_check_modules(LIBBSD \"libbsd\")\n    if(LIBBSD_FOUND)\n      message(STATUS \"Using libbsd\")\n      set(pkg_config_names_private \"${pkg_config_names_private} libbsd\")\n      set(ZMQ_HAVE_LIBBSD 1)\n    endif()\n  endif()\n  check_cxx_symbol_exists(strlcpy string.h ZMQ_HAVE_STRLCPY)\nendif()\n\n# Select curve encryption library, defaults to disabled To use libsodium instead, use --with-libsodium(must be\n# installed) To disable curve, use --disable-curve\n\noption(WITH_LIBSODIUM \"Use libsodium (required with ENABLE_CURVE)\" OFF)\noption(WITH_LIBSODIUM_STATIC \"Use static libsodium library\" OFF)\noption(ENABLE_LIBSODIUM_RANDOMBYTES_CLOSE \"Automatically close libsodium randombytes. Not threadsafe without getrandom()\" ON)\noption(ENABLE_CURVE \"Enable CURVE security\" OFF)\n\nif(ENABLE_CURVE)\n  # libsodium is currently the only CURVE provider\n  if(WITH_LIBSODIUM)\n    find_package(\"sodium\")\n    if(SODIUM_FOUND)\n      message(STATUS \"Using libsodium for CURVE security\")\n      include_directories(${SODIUM_INCLUDE_DIRS})\n      link_directories(${SODIUM_LIBRARY_DIRS})\n      if(WITH_LIBSODIUM_STATIC)\n        add_compile_definitions(SODIUM_STATIC)\n      endif()\n      set(ZMQ_USE_LIBSODIUM 1)\n      set(ZMQ_HAVE_CURVE 1)\n      if (ENABLE_LIBSODIUM_RANDOMBYTES_CLOSE)\n        set(ZMQ_LIBSODIUM_RANDOMBYTES_CLOSE 1)\n      endif()\n    else()\n      message(\n        FATAL_ERROR\n          \"libsodium requested but not found, you may want to install libsodium and run cmake again\"\n      )\n    endif()\n  else() # WITH_LIBSODIUM\n    message(\n      FATAL_ERROR\n      \"ENABLE_CURVE set, but not WITH_LIBSODIUM. No CURVE provider found.\"\n      )\n  endif()\nelse() # ENABLE_CURVE\n  message(STATUS \"CURVE security is disabled\")\nendif()\n\noption(WITH_GSSAPI_KRB5 \"Use libgssapi_krb5\" OFF)\nif(WITH_GSSAPI_KRB5)\n  find_package(\"gssapi_krb5\" REQUIRED)\n  message(STATUS \"Using GSSAPI_KRB5\")\n  include_directories(${GSSAPI_KRB5_INCLUDE_DIRS})\n  link_directories(${GSSAPI_KRB5_LIBRARY_DIRS})\n  set(HAVE_LIBGSSAPI_KRB5 1)\nendif()\n\n\nset(SOURCE_DIR \"${CMAKE_CURRENT_SOURCE_DIR}\")\n\noption(WITH_MILITANT \"Enable militant assertions\" OFF)\nif(WITH_MILITANT)\n  add_definitions(-DZMQ_ACT_MILITANT)\nendif()\n\nset(API_POLLER\n    \"\"\n    CACHE STRING \"Choose polling system for zmq_poll(er)_*. valid values are\n  poll or select [default=poll unless POLLER=select]\")\n\nset(POLLER\n    \"\"\n    CACHE STRING \"Choose polling system for I/O threads. valid values are\n  kqueue, epoll, devpoll, pollset, poll or select [default=autodetect]\")\n\nif(WIN32)\n  if(CMAKE_SYSTEM_NAME STREQUAL \"WindowsStore\" AND CMAKE_SYSTEM_VERSION MATCHES \"^10.0\")\n    set(ZMQ_HAVE_WINDOWS_UWP ON)\n    set(ZMQ_HAVE_IPC OFF)\n    # to remove compile warninging \"D9002 ignoring unknown option\"\n    string(REPLACE \"/Zi\" \"\" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})\n    set(CMAKE_CXX_FLAGS_DEBUG\n        ${CMAKE_CXX_FLAGS_DEBUG}\n        CACHE STRING \"\" FORCE)\n    string(REPLACE \"/Zi\" \"\" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO})\n    set(CMAKE_CXX_FLAGS_RELWITHDEBINFO\n        ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}\n        CACHE STRING \"\" FORCE)\n    string(REPLACE \"/Zi\" \"\" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})\n  endif()\n  # from https://stackoverflow.com/a/40217291/2019765\n  macro(get_WIN32_WINNT version)\n    if(CMAKE_SYSTEM_VERSION)\n      set(ver ${CMAKE_SYSTEM_VERSION})\n      string(REGEX MATCH \"^([0-9]+).([0-9])\" ver ${ver})\n      string(REGEX MATCH \"^([0-9]+)\" verMajor ${ver})\n      # Check for Windows 10, b/c we'll need to convert to hex 'A'.\n      if(\"${verMajor}\" MATCHES \"10\")\n        set(verMajor \"A\")\n        string(REGEX REPLACE \"^([0-9]+)\" ${verMajor} ver ${ver})\n      endif(\"${verMajor}\" MATCHES \"10\")\n      # Remove all remaining '.' characters.\n      string(REPLACE \".\" \"\" ver ${ver})\n      # Prepend each digit with a zero.\n      string(REGEX REPLACE \"([0-9A-Z])\" \"0\\\\1\" ver ${ver})\n      set(${version} \"0x${ver}\")\n    endif(CMAKE_SYSTEM_VERSION)\n  endmacro(get_WIN32_WINNT)\n\n  get_win32_winnt(ZMQ_WIN32_WINNT_DEFAULT)\n  message(STATUS \"Detected _WIN32_WINNT from CMAKE_SYSTEM_VERSION: ${ZMQ_WIN32_WINNT_DEFAULT}\")\n\n  # TODO limit _WIN32_WINNT to the actual Windows SDK version, which might be different from the default version\n  # installed with Visual Studio\n  if(MSVC_VERSION STREQUAL \"1500\" AND CMAKE_SYSTEM_VERSION VERSION_GREATER \"6.0\")\n    set(ZMQ_WIN32_WINNT_LIMIT \"0x0600\")\n  elseif(MSVC_VERSION STREQUAL \"1600\" AND CMAKE_SYSTEM_VERSION VERSION_GREATER \"6.1\")\n    set(ZMQ_WIN32_WINNT_LIMIT \"0x0601\")\n  elseif(MSVC_VERSION STREQUAL \"1700\" AND CMAKE_SYSTEM_VERSION VERSION_GREATER \"6.1\")\n    set(ZMQ_WIN32_WINNT_LIMIT \"0x0601\")\n  elseif(MSVC_VERSION STREQUAL \"1800\" AND CMAKE_SYSTEM_VERSION VERSION_GREATER \"6.2\")\n    set(ZMQ_WIN32_WINNT_LIMIT \"0x0602\")\n  endif()\n  if(ZMQ_WIN32_WINNT_LIMIT)\n    message(\n      STATUS\n        \"Mismatch of Visual Studio Version (${MSVC_VERSION}) and CMAKE_SYSTEM_VERSION (${CMAKE_SYSTEM_VERSION}), limiting _WIN32_WINNT to ${ZMQ_WIN32_WINNT_LIMIT}, you may override this by setting ZMQ_WIN32_WINNT\"\n    )\n    set(ZMQ_WIN32_WINNT_DEFAULT \"${ZMQ_WIN32_WINNT_LIMIT}\")\n  endif()\n\n  set(ZMQ_WIN32_WINNT\n      \"${ZMQ_WIN32_WINNT_DEFAULT}\"\n      CACHE STRING \"Value to set _WIN32_WINNT to for building [default=autodetect from build environment]\")\n\n  # On Windows Vista or greater, with MSVC 2013 or greater, default to epoll (which is required on Win 10 for ipc\n  # support)\n  if(ZMQ_WIN32_WINNT GREATER \"0x05FF\"\n     AND MSVC_VERSION GREATER 1799\n     AND POLLER STREQUAL \"\"\n     AND NOT ZMQ_HAVE_WINDOWS_UWP)\n    set(POLLER \"epoll\")\n  endif()\n\n  add_definitions(-D_WIN32_WINNT=${ZMQ_WIN32_WINNT})\nendif(WIN32)\n\nif(NOT MSVC)\n  if(POLLER STREQUAL \"\")\n    check_cxx_symbol_exists(kqueue \"sys/types.h;sys/event.h;sys/time.h\" HAVE_KQUEUE)\n    if(HAVE_KQUEUE)\n      set(POLLER \"kqueue\")\n    endif()\n  endif()\n\n  if(POLLER STREQUAL \"\")\n    check_cxx_symbol_exists(epoll_create sys/epoll.h HAVE_EPOLL)\n    if(HAVE_EPOLL)\n      set(POLLER \"epoll\")\n      check_cxx_symbol_exists(epoll_create1 sys/epoll.h HAVE_EPOLL_CLOEXEC)\n      if(HAVE_EPOLL_CLOEXEC)\n        set(ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC 1)\n      endif()\n    endif()\n  endif()\n\n  if(POLLER STREQUAL \"\")\n    check_include_files(\"sys/devpoll.h\" HAVE_DEVPOLL)\n    if(HAVE_DEVPOLL)\n      set(POLLER \"devpoll\")\n    endif()\n  endif()\n\n  if(POLLER STREQUAL \"\")\n    check_cxx_symbol_exists(pollset_create sys/pollset.h HAVE_POLLSET)\n    if(HAVE_POLLSET)\n      set(POLLER \"pollset\")\n    endif()\n  endif()\n\n  if(POLLER STREQUAL \"\")\n    check_cxx_symbol_exists(poll poll.h HAVE_POLL)\n    if(HAVE_POLL)\n      set(POLLER \"poll\")\n    endif()\n  endif()\nendif()\n\nif(POLLER STREQUAL \"\")\n  if(WIN32)\n    set(HAVE_SELECT 1)\n  else()\n    check_cxx_symbol_exists(select sys/select.h HAVE_SELECT)\n  endif()\n  if(HAVE_SELECT)\n    set(POLLER \"select\")\n  else()\n    message(FATAL_ERROR \"Could not autodetect polling method\")\n  endif()\nendif()\n\nif(POLLER STREQUAL \"kqueue\"\n   OR POLLER STREQUAL \"epoll\"\n   OR POLLER STREQUAL \"devpoll\"\n   OR POLLER STREQUAL \"pollset\"\n   OR POLLER STREQUAL \"poll\"\n   OR POLLER STREQUAL \"select\")\n  message(STATUS \"Using polling method in I/O threads: ${POLLER}\")\n  string(TOUPPER ${POLLER} UPPER_POLLER)\n  set(ZMQ_IOTHREAD_POLLER_USE_${UPPER_POLLER} 1)\nelse()\n  message(FATAL_ERROR \"Invalid polling method\")\nendif()\n\nif(POLLER STREQUAL \"epoll\" AND WIN32)\n  message(STATUS \"Including wepoll\")\n  list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/external/wepoll/wepoll.c\n       ${CMAKE_CURRENT_SOURCE_DIR}/external/wepoll/wepoll.h)\nendif()\n\nif(API_POLLER STREQUAL \"\")\n  if(POLLER STREQUAL \"select\")\n    set(API_POLLER \"select\")\n  else()\n    set(API_POLLER \"poll\")\n  endif()\nendif()\n\nmessage(STATUS \"Using polling method in zmq_poll(er)_* API: ${API_POLLER}\")\nstring(TOUPPER ${API_POLLER} UPPER_API_POLLER)\nset(ZMQ_POLL_BASED_ON_${UPPER_API_POLLER} 1)\n\ncheck_cxx_symbol_exists(pselect sys/select.h HAVE_PSELECT)\nif (NOT WIN32 AND HAVE_PSELECT)\n  set(ZMQ_HAVE_PPOLL 1)\nendif()\n\n# special alignment settings\nexecute_process(\n  COMMAND getconf LEVEL1_DCACHE_LINESIZE\n  OUTPUT_VARIABLE CACHELINE_SIZE\n  ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)\nif(CACHELINE_SIZE STREQUAL \"\"\n   OR CACHELINE_SIZE STREQUAL \"undefined\"\n   OR CACHELINE_SIZE EQUAL 0\n   OR CACHELINE_SIZE EQUAL -1)\n  set(ZMQ_CACHELINE_SIZE 64)\nelse()\n  set(ZMQ_CACHELINE_SIZE ${CACHELINE_SIZE})\nendif()\nmessage(STATUS \"Using ${ZMQ_CACHELINE_SIZE} bytes alignment for lock-free data structures\")\ncheck_cxx_symbol_exists(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN)\n\nif(NOT CYGWIN)\n  # TODO cannot we simply do 'if(WIN32) set(ZMQ_HAVE_WINDOWS ON)' or similar?\n  check_include_files(windows.h ZMQ_HAVE_WINDOWS)\nendif()\n\nif(NOT WIN32)\n  set(ZMQ_HAVE_IPC 1)\n  set(ZMQ_HAVE_STRUCT_SOCKADDR_UN 1)\nelse()\n  check_include_files(\"winsock2.h;afunix.h\" ZMQ_HAVE_IPC)\n  if(ZMQ_HAVE_IPC)\n    check_struct_has_member(\"struct sockaddr_un\" sun_path \"winsock2.h;afunix.h\" ZMQ_HAVE_STRUCT_SOCKADDR_UN)\n  endif()\nendif()\n\n# ##################### BEGIN condition_variable_t selection\nif(NOT ZMQ_CV_IMPL)\n  # prefer C++11 STL std::condition_variable implementation, if available\n  check_include_files(condition_variable ZMQ_HAVE_STL_CONDITION_VARIABLE LANGUAGE CXX)\n\n  if(ZMQ_HAVE_STL_CONDITION_VARIABLE)\n    set(ZMQ_CV_IMPL_DEFAULT \"stl11\")\n  else()\n    if(WIN32 AND NOT CMAKE_SYSTEM_VERSION VERSION_LESS \"6.0\")\n      # Win32API CONDITION_VARIABLE is supported from Windows Vista only\n      set(ZMQ_CV_IMPL_DEFAULT \"win32api\")\n    elseif(CMAKE_USE_PTHREADS_INIT)\n      set(ZMQ_CV_IMPL_DEFAULT \"pthreads\")\n    else()\n      set(ZMQ_CV_IMPL_DEFAULT \"none\")\n    endif()\n  endif()\n\n  # TODO a vxworks implementation also exists, but vxworks is not currently supported with cmake at all\n  set(ZMQ_CV_IMPL\n      \"${ZMQ_CV_IMPL_DEFAULT}\"\n      CACHE STRING \"Choose condition_variable_t implementation. Valid values are\n       stl11, win32api, pthreads, none [default=autodetect]\")\nendif()\n\nmessage(STATUS \"Using condition_variable_t implementation: ${ZMQ_CV_IMPL}\")\nif(ZMQ_CV_IMPL STREQUAL \"stl11\")\n  set(ZMQ_USE_CV_IMPL_STL11 1)\nelseif(ZMQ_CV_IMPL STREQUAL \"win32api\")\n  set(ZMQ_USE_CV_IMPL_WIN32API 1)\nelseif(ZMQ_CV_IMPL STREQUAL \"pthreads\")\n  set(ZMQ_USE_CV_IMPL_PTHREADS 1)\nelseif(ZMQ_CV_IMPL STREQUAL \"none\")\n  set(ZMQ_USE_CV_IMPL_NONE 1)\nelse()\n  message(ERROR \"Unknown value for ZMQ_CV_IMPL: ${ZMQ_CV_IMPL}\")\nendif()\n# ##################### END condition_variable_t selection\n\nif(NOT MSVC)\n  check_include_files(ifaddrs.h ZMQ_HAVE_IFADDRS)\n  check_include_files(sys/uio.h ZMQ_HAVE_UIO)\n  check_include_files(sys/eventfd.h ZMQ_HAVE_EVENTFD)\n  if(ZMQ_HAVE_EVENTFD AND NOT CMAKE_CROSSCOMPILING)\n    zmq_check_efd_cloexec()\n  endif()\nendif()\n\nif(ZMQ_HAVE_WINDOWS)\n  # Cannot use check_library_exists because the symbol is always declared as char(*)(void)\n  set(CMAKE_REQUIRED_LIBRARIES \"ws2_32.lib\")\n  check_cxx_symbol_exists(WSAStartup \"winsock2.h\" HAVE_WS2_32)\n  if(HAVE_WS2_32)\n    set(pkg_config_libs_private \"${pkg_config_libs_private} -lws2_32\")\n  endif()\n\n  set(CMAKE_REQUIRED_LIBRARIES \"rpcrt4.lib\")\n  check_cxx_symbol_exists(UuidCreateSequential \"rpc.h\" HAVE_RPCRT4)\n\n  set(CMAKE_REQUIRED_LIBRARIES \"iphlpapi.lib\")\n  check_cxx_symbol_exists(GetAdaptersAddresses \"winsock2.h;iphlpapi.h\" HAVE_IPHLAPI)\n  if(HAVE_IPHLAPI)\n    set(pkg_config_libs_private \"${pkg_config_libs_private} -liphlpapi\")\n  endif()\n  check_cxx_symbol_exists(if_nametoindex \"iphlpapi.h\" HAVE_IF_NAMETOINDEX)\n\n  set(CMAKE_REQUIRED_LIBRARIES \"\")\n  # TODO: This not the symbol we're looking for. What is the symbol?\n  check_library_exists(ws2 fopen \"\" HAVE_WS2)\nelse()\n  check_cxx_symbol_exists(if_nametoindex net/if.h HAVE_IF_NAMETOINDEX)\n  check_cxx_symbol_exists(SO_PEERCRED sys/socket.h ZMQ_HAVE_SO_PEERCRED)\n  check_cxx_symbol_exists(LOCAL_PEERCRED sys/socket.h ZMQ_HAVE_LOCAL_PEERCRED)\n  check_cxx_symbol_exists(SO_BUSY_POLL sys/socket.h ZMQ_HAVE_BUSY_POLL)\nendif()\n\nif(NOT MINGW)\n  find_library(RT_LIBRARY rt)\n  if(RT_LIBRARY)\n    set(pkg_config_libs_private \"${pkg_config_libs_private} -lrt\")\n\n    set(CMAKE_REQUIRED_LIBRARIES rt)\n    check_cxx_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME)\n    set(CMAKE_REQUIRED_LIBRARIES)\n  else()\n    check_cxx_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME)\n  endif()\nendif()\n\nfind_package(Threads)\n\nif(WIN32 AND NOT CYGWIN)\n  if(NOT HAVE_WS2_32 AND NOT HAVE_WS2)\n    message(FATAL_ERROR \"Cannot link to ws2_32 or ws2\")\n  endif()\n\n  if(NOT HAVE_RPCRT4)\n    message(FATAL_ERROR \"Cannot link to rpcrt4\")\n  endif()\n\n  if(NOT HAVE_IPHLAPI)\n    message(FATAL_ERROR \"Cannot link to iphlapi\")\n  endif()\nendif()\n\nif(NOT MSVC)\n  check_cxx_symbol_exists(fork unistd.h HAVE_FORK)\n  check_cxx_symbol_exists(gethrtime sys/time.h HAVE_GETHRTIME)\n  check_cxx_symbol_exists(mkdtemp \"stdlib.h;unistd.h\" HAVE_MKDTEMP)\n  check_cxx_symbol_exists(accept4 sys/socket.h HAVE_ACCEPT4)\n  check_cxx_symbol_exists(strnlen string.h HAVE_STRNLEN)\nelse()\n  set(HAVE_STRNLEN 1)\nendif()\n\nadd_definitions(-D_REENTRANT -D_THREAD_SAFE)\nadd_definitions(-DZMQ_CUSTOM_PLATFORM_HPP)\n\noption(ENABLE_EVENTFD \"Enable/disable eventfd\" ZMQ_HAVE_EVENTFD)\n\nmacro(zmq_check_cxx_flag_prepend flag)\n  check_cxx_compiler_flag(\"${flag}\" HAVE_FLAG_${flag})\n\n  if(HAVE_FLAG_${flag})\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} ${flag}\")\n  endif()\nendmacro()\n\noption(ENABLE_ANALYSIS \"Build with static analysis(make take very long)\" OFF)\n\nif(MSVC)\n  if(ENABLE_ANALYSIS)\n    zmq_check_cxx_flag_prepend(\"/W4\")\n\n    zmq_check_cxx_flag_prepend(\"/analyze\")\n\n    # C++11/14/17-specific, but maybe possible via conditional defines\n    zmq_check_cxx_flag_prepend(\"/wd26440\") # Function '...' can be declared 'noexcept'\n    zmq_check_cxx_flag_prepend(\"/wd26432\") # If you define or delete any default operation in the type '...', define or\n                                           # delete them all\n    zmq_check_cxx_flag_prepend(\"/wd26439\") # This kind of function may not throw. Declare it 'noexcept'\n    zmq_check_cxx_flag_prepend(\"/wd26447\") # The function is declared 'noexcept' but calls function '...' which may\n                                           # throw exceptions\n    zmq_check_cxx_flag_prepend(\"/wd26433\") # Function '...' should be marked with 'override'\n    zmq_check_cxx_flag_prepend(\"/wd26409\") # Avoid calling new and delete explicitly, use std::make_unique<T> instead\n    # Requires GSL\n    zmq_check_cxx_flag_prepend(\"/wd26429\") # Symbol '...' is never tested for nullness, it can be marked as not_null\n    zmq_check_cxx_flag_prepend(\"/wd26446\") # Prefer to use gsl::at()\n    zmq_check_cxx_flag_prepend(\"/wd26481\") # Don't use pointer arithmetic. Use span instead\n    zmq_check_cxx_flag_prepend(\"/wd26472\") # Don't use a static_cast for arithmetic conversions. Use brace\n                                           # initialization, gsl::narrow_cast or gsl::narow\n    zmq_check_cxx_flag_prepend(\"/wd26448\") # Consider using gsl::finally if final action is intended\n    zmq_check_cxx_flag_prepend(\"/wd26400\") # Do not assign the result of an allocation or a function call with an\n                                           # owner<T> return value to a raw pointer, use owner<T> instead\n    zmq_check_cxx_flag_prepend(\"/wd26485\") # Expression '...': No array to pointer decay(bounds.3)\n  else()\n    zmq_check_cxx_flag_prepend(\"/W3\")\n  endif()\n\n  if(MSVC_IDE)\n    set(MSVC_TOOLSET \"-${CMAKE_VS_PLATFORM_TOOLSET}\")\n  else()\n    set(MSVC_TOOLSET \"\")\n  endif()\nelse()\n  zmq_check_cxx_flag_prepend(\"-Wall\")\nendif()\n\nif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES \"Clang\")\n  zmq_check_cxx_flag_prepend(\"-Wextra\")\nendif()\n\noption(LIBZMQ_PEDANTIC \"\" ON)\noption(LIBZMQ_WERROR \"\" OFF)\n\n# TODO: why is -Wno-long-long defined differently than in configure.ac?\nif(NOT MSVC)\n  zmq_check_cxx_flag_prepend(\"-Wno-long-long\")\n  zmq_check_cxx_flag_prepend(\"-Wno-uninitialized\")\n\n  if(LIBZMQ_PEDANTIC)\n    zmq_check_cxx_flag_prepend(\"-pedantic\")\n\n    if(${CMAKE_CXX_COMPILER_ID} MATCHES \"Intel\")\n      zmq_check_cxx_flag_prepend(\"-strict-ansi\")\n    endif()\n\n    if(${CMAKE_CXX_COMPILER_ID} MATCHES \"SunPro\")\n      zmq_check_cxx_flag_prepend(\"-compat=5\")\n    endif()\n  endif()\nendif()\n\nif(LIBZMQ_WERROR)\n  if(MSVC)\n    zmq_check_cxx_flag_prepend(\"/WX\")\n  else()\n    zmq_check_cxx_flag_prepend(\"-Werror\")\n    if(${CMAKE_CXX_COMPILER_ID} MATCHES \"SunPro\")\n      zmq_check_cxx_flag_prepend(\"-errwarn=%all\")\n    endif()\n  endif()\nendif()\n\nif(CMAKE_SYSTEM_PROCESSOR MATCHES \"^sparc\")\n  zmq_check_cxx_flag_prepend(\"-mcpu=v9\")\nendif()\n\nif(${CMAKE_CXX_COMPILER_ID} MATCHES \"SunPro\")\n  zmq_check_cxx_flag_prepend(\"-features=zla\")\nendif()\n\nif(CMAKE_SYSTEM_NAME MATCHES \"SunOS\"\n   OR CMAKE_SYSTEM_NAME MATCHES \"NetBSD\"\n   OR CMAKE_SYSTEM_NAME MATCHES \"QNX\")\n  message(STATUS \"Checking whether atomic operations can be used\")\n  check_c_source_compiles(\n    \"\\\n  #include <atomic.h> \\\n  \\\n  int main() \\\n  { \\\n    uint32_t value; \\\n    atomic_cas_32(&value, 0, 0); \\\n    return 0; \\\n  } \\\n  \"\n    HAVE_ATOMIC_H)\n\n  if(NOT HAVE_ATOMIC_H)\n    set(ZMQ_FORCE_MUTEXES 1)\n  endif()\nendif()\n\nif(NOT ANDROID)\n  zmq_check_noexcept()\nendif()\n\n# -----------------------------------------------------------------------------\nif (NOT MSVC)\n  # Compilation checks\n  zmq_check_pthread_setname()\n  zmq_check_pthread_setaffinity()\n  # Execution checks\n  if(NOT CMAKE_CROSSCOMPILING)\n    zmq_check_sock_cloexec()\n    zmq_check_o_cloexec()\n    zmq_check_so_bindtodevice()\n    zmq_check_so_keepalive()\n    zmq_check_so_priority()\n    zmq_check_tcp_keepcnt()\n    zmq_check_tcp_keepidle()\n    zmq_check_tcp_keepintvl()\n    zmq_check_tcp_keepalive()\n    zmq_check_tcp_tipc()\n    zmq_check_getrandom()\n  endif()\nendif()\n\nif(CMAKE_SYSTEM_NAME MATCHES \"Linux\"\n   OR CMAKE_SYSTEM_NAME MATCHES \"GNU/kFreeBSD\"\n   OR CMAKE_SYSTEM_NAME MATCHES \"GNU/Hurd\"\n   OR CYGWIN)\n  add_definitions(-D_GNU_SOURCE)\nelseif(CMAKE_SYSTEM_NAME MATCHES \"FreeBSD\")\n  add_definitions(-D__BSD_VISIBLE)\nelseif(CMAKE_SYSTEM_NAME MATCHES \"NetBSD\")\n  add_definitions(-D_NETBSD_SOURCE)\nelseif(CMAKE_SYSTEM_NAME MATCHES \"OpenBSD\")\n  add_definitions(-D_OPENBSD_SOURCE)\nelseif(CMAKE_SYSTEM_NAME MATCHES \"SunOS\")\n  add_definitions(-D_PTHREADS)\nelseif(CMAKE_SYSTEM_NAME MATCHES \"HP-UX\")\n  add_definitions(-D_POSIX_C_SOURCE=200112L)\n  zmq_check_cxx_flag_prepend(-Ae)\nelseif(CMAKE_SYSTEM_NAME MATCHES \"Darwin\")\n  add_definitions(-D_DARWIN_C_SOURCE)\nendif()\n\nfind_package(AsciiDoctor)\n\ncmake_dependent_option(WITH_DOC \"Build Reference Guide documentation(requires DocBook)\" ON \"ASCIIDOC_FOUND;NOT WIN32\"\n                       OFF) # Do not build docs on Windows due to issues with symlinks\n\nif(MSVC)\n  if(WITH_OPENPGM)\n    # set(OPENPGM_ROOT \"\" CACHE PATH \"Location of OpenPGM\")\n    set(OPENPGM_VERSION_MAJOR 5)\n    set(OPENPGM_VERSION_MINOR 2)\n    set(OPENPGM_VERSION_MICRO 122)\n    if(CMAKE_CL_64)\n      find_path(\n        OPENPGM_ROOT include/pgm/pgm.h\n        PATHS\n          \"[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Miru\\\\OpenPGM ${OPENPGM_VERSION_MAJOR}.${OPENPGM_VERSION_MINOR}.${OPENPGM_VERSION_MICRO}]\"\n        NO_DEFAULT_PATH)\n      message(STATUS \"OpenPGM x64 detected - ${OPENPGM_ROOT}\")\n    else()\n      find_path(\n        OPENPGM_ROOT include/pgm/pgm.h\n        PATHS\n          \"[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Miru\\\\OpenPGM ${OPENPGM_VERSION_MAJOR}.${OPENPGM_VERSION_MINOR}.${OPENPGM_VERSION_MICRO}]\"\n          \"[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Miru\\\\OpenPGM ${OPENPGM_VERSION_MAJOR}.${OPENPGM_VERSION_MINOR}.${OPENPGM_VERSION_MICRO}]\"\n          NO_DEFAULT_PATH)\n      message(STATUS \"OpenPGM x86 detected - ${OPENPGM_ROOT}\")\n    endif()\n    set(OPENPGM_INCLUDE_DIRS ${OPENPGM_ROOT}/include)\n    set(OPENPGM_LIBRARY_DIRS ${OPENPGM_ROOT}/lib)\n    set(OPENPGM_LIBRARIES\n        optimized\n        libpgm${MSVC_TOOLSET}-mt-${OPENPGM_VERSION_MAJOR}_${OPENPGM_VERSION_MINOR}_${OPENPGM_VERSION_MICRO}.lib debug\n        libpgm${MSVC_TOOLSET}-mt-gd-${OPENPGM_VERSION_MAJOR}_${OPENPGM_VERSION_MINOR}_${OPENPGM_VERSION_MICRO}.lib)\n  endif()\nelse()\n  if(WITH_OPENPGM)\n    # message(FATAL_ERROR \"WITH_OPENPGM not implemented\")\n\n    if(NOT OPENPGM_PKGCONFIG_NAME)\n      set(OPENPGM_PKGCONFIG_NAME \"openpgm-5.2\")\n    endif()\n\n    set(OPENPGM_PKGCONFIG_NAME\n        ${OPENPGM_PKGCONFIG_NAME}\n        CACHE STRING \"Name pkg-config shall use to find openpgm libraries and include paths\" FORCE)\n\n    pkg_check_modules(OPENPGM ${OPENPGM_PKGCONFIG_NAME})\n\n    if(OPENPGM_FOUND)\n      message(STATUS ${OPENPGM_PKGCONFIG_NAME}\" found\")\n      set(pkg_config_names_private \"${pkg_config_names_private} ${OPENPGM_PKGCONFIG_NAME}\")\n    else()\n      message(\n        FATAL_ERROR\n          ${OPENPGM_PKGCONFIG_NAME}\"  not found. openpgm is searchd via `pkg-config ${OPENPGM_PKGCONFIG_NAME}`. Consider providing a valid OPENPGM_PKGCONFIG_NAME\"\n      )\n    endif()\n\n    # DSO symbol visibility for openpgm\n    if(HAVE_FLAG_VISIBILITY_HIDDEN)\n\n    elseif(HAVE_FLAG_LDSCOPE_HIDDEN)\n\n    endif()\n  endif()\nendif()\n\n# -----------------------------------------------------------------------------\n# force off-tree build\n\nif(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})\n  message(\n    FATAL_ERROR\n      \"CMake generation is not allowed within the source directory! \\\n    Remove the CMakeCache.txt file and try again from another folder, e.g.: \\\n    \\\n      rm CMakeCache.txt \\\n      mkdir cmake-make \\\n      cd cmake-make \\\n      cmake ..\")\nendif()\n\n# -----------------------------------------------------------------------------\n# default to Release build\n\nif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n  # CMAKE_BUILD_TYPE is not used for multi-configuration generators like Visual Studio/XCode which instead use\n  # CMAKE_CONFIGURATION_TYPES\n  set(CMAKE_BUILD_TYPE\n      Release\n      CACHE STRING \"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel.\" FORCE)\nendif()\n\n# -----------------------------------------------------------------------------\n# output directories\n\nzmq_set_with_default(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"${ZeroMQ_BINARY_DIR}/bin\")\nif(UNIX)\n  set(zmq_library_directory \"lib\")\nelse()\n  set(zmq_library_directory \"bin\")\nendif()\nzmq_set_with_default(CMAKE_LIBRARY_OUTPUT_DIRECTORY \"${ZeroMQ_BINARY_DIR}/${zmq_library_directory}\")\nzmq_set_with_default(CMAKE_ARCHIVE_OUTPUT_DIRECTORY \"${ZeroMQ_BINARY_DIR}/lib\")\n\n# -----------------------------------------------------------------------------\n# platform specifics\n\nif(WIN32)\n  # Socket limit is 16K(can be raised arbitrarily)\n  add_definitions(-DFD_SETSIZE=16384)\n  add_definitions(-D_CRT_SECURE_NO_WARNINGS)\n  add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS)\nendif()\n\nif(MSVC)\n  # Parallel make.\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /MP\")\n  set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} /MP\")\n\n  # Compile the static lib with debug information included note: we assume here that the default flags contain some /Z\n  # flag\n  string(REGEX REPLACE \"/Z.[^:]\" \"/Z7 \" CMAKE_CXX_FLAGS_DEBUG \"${CMAKE_CXX_FLAGS_DEBUG}\")\n  string(REGEX REPLACE \"/Z.[^:]\" \"/Z7 \" CMAKE_CXX_FLAGS_RELWITHDEBINFO \"${CMAKE_CXX_FLAGS_RELWITHDEBINFO}\")\n\nendif()\n\n# -----------------------------------------------------------------------------\n# source files\n\nset(cxx-sources\n    precompiled.cpp\n    address.cpp\n    channel.cpp\n    client.cpp\n    clock.cpp\n    ctx.cpp\n    curve_mechanism_base.cpp\n    curve_client.cpp\n    curve_server.cpp\n    dealer.cpp\n    devpoll.cpp\n    dgram.cpp\n    dist.cpp\n    endpoint.cpp\n    epoll.cpp\n    err.cpp\n    fq.cpp\n    io_object.cpp\n    io_thread.cpp\n    ip.cpp\n    ipc_address.cpp\n    ipc_connecter.cpp\n    ipc_listener.cpp\n    kqueue.cpp\n    lb.cpp\n    mailbox.cpp\n    mailbox_safe.cpp\n    mechanism.cpp\n    mechanism_base.cpp\n    metadata.cpp\n    msg.cpp\n    mtrie.cpp\n    norm_engine.cpp\n    object.cpp\n    options.cpp\n    own.cpp\n    null_mechanism.cpp\n    pair.cpp\n    peer.cpp\n    pgm_receiver.cpp\n    pgm_sender.cpp\n    pgm_socket.cpp\n    pipe.cpp\n    plain_client.cpp\n    plain_server.cpp\n    poll.cpp\n    poller_base.cpp\n    polling_util.cpp\n    pollset.cpp\n    proxy.cpp\n    pub.cpp\n    pull.cpp\n    push.cpp\n    random.cpp\n    raw_encoder.cpp\n    raw_decoder.cpp\n    raw_engine.cpp\n    reaper.cpp\n    rep.cpp\n    req.cpp\n    router.cpp\n    select.cpp\n    server.cpp\n    session_base.cpp\n    signaler.cpp\n    socket_base.cpp\n    socks.cpp\n    socks_connecter.cpp\n    stream.cpp\n    stream_engine_base.cpp\n    sub.cpp\n    tcp.cpp\n    tcp_address.cpp\n    tcp_connecter.cpp\n    tcp_listener.cpp\n    thread.cpp\n    trie.cpp\n    radix_tree.cpp\n    v1_decoder.cpp\n    v1_encoder.cpp\n    v2_decoder.cpp\n    v2_encoder.cpp\n    v3_1_encoder.cpp\n    xpub.cpp\n    xsub.cpp\n    zmq.cpp\n    zmq_utils.cpp\n    decoder_allocators.cpp\n    socket_poller.cpp\n    timers.cpp\n    config.hpp\n    radio.cpp\n    dish.cpp\n    udp_engine.cpp\n    udp_address.cpp\n    scatter.cpp\n    gather.cpp\n    ip_resolver.cpp\n    zap_client.cpp\n    zmtp_engine.cpp\n    # at least for VS, the header files must also be listed\n    address.hpp\n    array.hpp\n    atomic_counter.hpp\n    atomic_ptr.hpp\n    blob.hpp\n    channel.hpp\n    client.hpp\n    clock.hpp\n    command.hpp\n    compat.hpp\n    condition_variable.hpp\n    config.hpp\n    ctx.hpp\n    curve_client.hpp\n    curve_client_tools.hpp\n    curve_mechanism_base.hpp\n    curve_server.hpp\n    dbuffer.hpp\n    dealer.hpp\n    decoder.hpp\n    decoder_allocators.hpp\n    devpoll.hpp\n    dgram.hpp\n    dish.hpp\n    dist.hpp\n    encoder.hpp\n    endpoint.hpp\n    epoll.hpp\n    err.hpp\n    fd.hpp\n    fq.hpp\n    gather.hpp\n    generic_mtrie.hpp\n    generic_mtrie_impl.hpp\n    gssapi_client.hpp\n    gssapi_mechanism_base.hpp\n    gssapi_server.hpp\n    i_decoder.hpp\n    i_encoder.hpp\n    i_engine.hpp\n    i_mailbox.hpp\n    i_poll_events.hpp\n    io_object.hpp\n    io_thread.hpp\n    ip.hpp\n    ipc_address.hpp\n    ipc_connecter.hpp\n    ipc_listener.hpp\n    kqueue.hpp\n    lb.hpp\n    likely.hpp\n    macros.hpp\n    mailbox.hpp\n    mailbox_safe.hpp\n    mechanism.hpp\n    mechanism_base.hpp\n    metadata.hpp\n    msg.hpp\n    mtrie.hpp\n    mutex.hpp\n    norm_engine.hpp\n    null_mechanism.hpp\n    object.hpp\n    options.hpp\n    own.hpp\n    pair.hpp\n    peer.hpp\n    pgm_receiver.hpp\n    pgm_sender.hpp\n    pgm_socket.hpp\n    pipe.hpp\n    plain_client.hpp\n    plain_common.hpp\n    plain_server.hpp\n    poll.hpp\n    poller.hpp\n    poller_base.hpp\n    polling_util.hpp\n    pollset.hpp\n    precompiled.hpp\n    proxy.hpp\n    pub.hpp\n    pull.hpp\n    push.hpp\n    radio.hpp\n    random.hpp\n    raw_decoder.hpp\n    raw_encoder.hpp\n    raw_engine.hpp\n    reaper.hpp\n    rep.hpp\n    req.hpp\n    router.hpp\n    scatter.hpp\n    secure_allocator.hpp\n    select.hpp\n    server.hpp\n    session_base.hpp\n    signaler.hpp\n    socket_base.hpp\n    socket_poller.hpp\n    socks.hpp\n    socks_connecter.hpp\n    stdint.hpp\n    stream.hpp\n    stream_engine_base.hpp\n    stream_connecter_base.hpp\n    stream_connecter_base.cpp\n    stream_listener_base.hpp\n    stream_listener_base.cpp\n    sub.hpp\n    tcp.hpp\n    tcp_address.hpp\n    tcp_connecter.hpp\n    tcp_listener.hpp\n    thread.hpp\n    timers.hpp\n    tipc_address.hpp\n    tipc_connecter.hpp\n    tipc_listener.hpp\n    trie.hpp\n    udp_address.hpp\n    udp_engine.hpp\n    v1_decoder.hpp\n    v1_encoder.hpp\n    v2_decoder.hpp\n    v2_encoder.hpp\n    v3_1_encoder.hpp\n    v2_protocol.hpp\n    vmci.hpp\n    vmci_address.hpp\n    vmci_connecter.hpp\n    vmci_listener.hpp\n    vsock_address.hpp\n    vsock_connecter.hpp\n    vsock_listener.hpp\n    windows.hpp\n    wire.hpp\n    xpub.hpp\n    xsub.hpp\n    ypipe.hpp\n    ypipe_base.hpp\n    ypipe_conflate.hpp\n    yqueue.hpp\n    zap_client.hpp\n    zmtp_engine.hpp)\n\nif(MINGW)\n  # Generate the right type when using -m32 or -m64\n  macro(set_rc_arch rc_target)\n    set(CMAKE_RC_COMPILER_INIT windres)\n    enable_language(RC)\n    set(CMAKE_RC_COMPILE_OBJECT\n        \"<CMAKE_RC_COMPILER> <FLAGS> -O coff --target=${rc_target} <DEFINES> -i <SOURCE> -o <OBJECT>\")\n  endmacro()\n\n  if(NOT CMAKE_SYSTEM_PROCESSOR)\n    set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR})\n  endif()\n\n  # Also happens on x86_64 systems...what a worthless variable\n  if(CMAKE_SYSTEM_PROCESSOR MATCHES \"i386\"\n     OR CMAKE_SYSTEM_PROCESSOR MATCHES \"i486\"\n     OR CMAKE_SYSTEM_PROCESSOR MATCHES \"i586\"\n     OR CMAKE_SYSTEM_PROCESSOR MATCHES \"i686\"\n     OR CMAKE_SYSTEM_PROCESSOR MATCHES \"x86\"\n     OR CMAKE_SYSTEM_PROCESSOR MATCHES \"x86_64\"\n     OR CMAKE_SYSTEM_PROCESSOR MATCHES \"amd64\")\n\n    if(CMAKE_SIZEOF_VOID_P EQUAL 8)\n      set_rc_arch(\"pe-x86-64\")\n    else()\n      set_rc_arch(\"pe-i386\")\n    endif()\n  endif()\nendif()\n\nset(public_headers include/zmq.h include/zmq_utils.h)\n\nset(readme-docs AUTHORS LICENSE NEWS)\n\n# -----------------------------------------------------------------------------\n# optional modules\n\nif(WITH_OPENPGM)\n  message(STATUS \"Building with OpenPGM\")\n  set(ZMQ_HAVE_OPENPGM 1)\n  include_directories(${OPENPGM_INCLUDE_DIRS})\n  link_directories(${OPENPGM_LIBRARY_DIRS})\n  set(OPTIONAL_LIBRARIES ${OPENPGM_LIBRARIES})\nendif()\n\nif(WITH_NORM)\n  find_package(norm)\n    if(norm_FOUND)\n      message(STATUS \"Building with NORM\")\n      set(ZMQ_HAVE_NORM 1)\n    else()\n      message(FATAL_ERROR \"NORM not found\")\n    endif()\nendif()\n\nif(WITH_VMCI)\nmessage(STATUS \"Building with VMCI\")\n  set(ZMQ_HAVE_VMCI 1)\n  include_directories(${VMCI_INCLUDE_DIRS})\n  list(APPEND cxx-sources vmci_address.cpp vmci_connecter.cpp vmci_listener.cpp vmci.cpp)\nendif()\n\nif(ZMQ_HAVE_VSOCK)\n  list(APPEND cxx-sources vsock_address.cpp vsock_connecter.cpp vsock_listener.cpp)\nendif()\n\nif(ZMQ_HAVE_TIPC)\n  list(APPEND cxx-sources tipc_address.cpp tipc_connecter.cpp tipc_listener.cpp)\nendif()\n\nif(WITH_GSSAPI_KRB5)\n  list(APPEND cxx-sources gssapi_client.cpp gssapi_mechanism_base.cpp gssapi_server.cpp)\nendif()\n\n# -----------------------------------------------------------------------------\n# source generators\n\nforeach(source ${cxx-sources})\n  list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/src/${source})\nendforeach()\n\nconfigure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc)\n\n# Delete any src/platform.hpp left by configure\nfile(REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/src/platform.hpp)\n\nconfigure_file(${CMAKE_CURRENT_SOURCE_DIR}/builds/cmake/platform.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/platform.hpp)\nlist(APPEND sources ${CMAKE_CURRENT_BINARY_DIR}/platform.hpp)\n\nset(prefix ${CMAKE_INSTALL_PREFIX})\nset(exec_prefix \"\\${prefix}\")\nset(libdir \"\\${prefix}/${CMAKE_INSTALL_LIBDIR}\")\nset(includedir \"\\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}\")\nset(VERSION ${ZMQ_VERSION_MAJOR}.${ZMQ_VERSION_MINOR}.${ZMQ_VERSION_PATCH})\nconfigure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/libzmq.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libzmq.pc @ONLY)\nset(zmq-pkgconfig ${CMAKE_CURRENT_BINARY_DIR}/libzmq.pc)\n\nif(NOT ZMQ_BUILD_FRAMEWORK)\n  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libzmq.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)\nendif()\n\nif(MSVC)\n  if(CMAKE_CL_64)\n    set(nsis-template ${CMAKE_CURRENT_SOURCE_DIR}/builds/cmake/NSIS.template64.in)\n  else()\n    set(nsis-template ${CMAKE_CURRENT_SOURCE_DIR}/builds/cmake/NSIS.template32.in)\n  endif()\n\n  add_custom_command(\n    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/NSIS.template.in\n    COMMAND ${CMAKE_COMMAND} ARGS -E copy ${nsis-template} ${CMAKE_CURRENT_BINARY_DIR}/NSIS.template.in\n    DEPENDS ${nsis-template})\nendif()\n\noption(WITH_DOCS \"Build html docs\" ON)\nif(WITH_DOCS)\n  file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc)\n  file(\n    GLOB asciidoc_files\n    RELATIVE ${CMAKE_CURRENT_BINARY_DIR}/\n    \"${CMAKE_CURRENT_SOURCE_DIR}/doc/*.adoc\")\n  string(REPLACE \".txt\" \".html\" html_files ${asciidoc_files})\n  add_custom_command(\n    OUTPUT ${html_files}\n    COMMAND asciidoctor -b html -azmq_version=${ZMQ_VERSION} *.adoc\n    DEPENDS ${asciidoc_files}\n    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n    COMMENT \"Generating ${html}\")\nendif()\n\nif(ZMQ_BUILD_FRAMEWORK)\n  add_custom_command(\n    TARGET libzmq\n    POST_BUILD\n    COMMAND ${CMAKE_COMMAND} ARGS -E make_directory\n            \"${CMAKE_LIBRARY_OUTPUT_PATH}/ZeroMQ.framework/Versions/${ZMQ_VERSION}/MacOS\"\n    COMMENT \"Perf tools\")\nendif()\n\noption(ENABLE_PRECOMPILED \"Enable precompiled headers, if possible\" ON)\nif(MSVC AND ENABLE_PRECOMPILED)\n  # default for all sources is to use precompiled headers\n  foreach(source ${sources})\n    # C and C++ can not use the same precompiled header\n    if(${source} MATCHES \".cpp$\" AND NOT ${source} STREQUAL \"${CMAKE_CURRENT_SOURCE_DIR}/src/precompiled.cpp\")\n      set_source_files_properties(${source} PROPERTIES COMPILE_FLAGS \"/Yuprecompiled.hpp\" OBJECT_DEPENDS\n                                                                                          precompiled.hpp)\n    endif()\n  endforeach()\n  # create precompiled header\n  set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/precompiled.cpp\n                              PROPERTIES COMPILE_FLAGS \"/Ycprecompiled.hpp\" OBJECT_OUTPUTS precompiled.hpp)\nendif()\n\n# -----------------------------------------------------------------------------\n# output\noption(BUILD_SHARED \"Whether or not to build the shared object\" ON)\noption(BUILD_STATIC \"Whether or not to build the static archive\" ON)\n\nif(MSVC)\n  # Suppress linker warnings caused by #ifdef omission of file content.\n  set(CMAKE_STATIC_LINKER_FLAGS \"${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221\")\n  set(PDB_OUTPUT_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/bin\")\n  set(PDB_NAME\n      \"lib${ZMQ_OUTPUT_BASENAME}${MSVC_TOOLSET}-mt-gd-${ZMQ_VERSION_MAJOR}_${ZMQ_VERSION_MINOR}_${ZMQ_VERSION_PATCH}\")\n  function(enable_vs_guideline_checker target)\n    set_target_properties(\n      ${target} PROPERTIES VS_GLOBAL_EnableCppCoreCheck true VS_GLOBAL_CodeAnalysisRuleSet CppCoreCheckRules.ruleset\n                           VS_GLOBAL_RunCodeAnalysis true)\n  endfunction()\n  if(BUILD_SHARED)\n    # Whole Program Optimization flags. http://msdn.microsoft.com/en-us/magazine/cc301698.aspx\n    #\n    # \"Finally, there's the subject of libraries. It's possible to create .LIB \n    # files with code in its IL form. The linker will happily work with these \n    # .LIB files. Be aware that these libraries will be tied to a specific \n    # version of the compiler and linker. If you distribute these libraries, \n    # you'll need to update them if Microsoft changes the format of IL in a \n    # future release.\"\n    # \n    # /GL and /LTCG can cause problems when libraries built with different \n    # versions of compiler are later linked into an executable while /LTCG is active. \n    # https://social.msdn.microsoft.com/Forums/vstudio/en-US/5c102025-c254-4f02-9a51-c775c6cc9f4b/problem-with-ltcg-when-building-a-static-library-in-vs2005?forum=vcgeneral\n    #\n    # For this reason, enable only when building a \"Release\" (e.g. non-DEBUG) DLL.\n    if(NOT ${CMAKE_BUILD_TYPE} MATCHES \"Debug\")\n      set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /GL\")\n      set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} /LTCG\")\n      set(CMAKE_SHARED_LINKER_FLAGS \"${CMAKE_SHARED_LINKER_FLAGS} /LTCG\")\n      set(CMAKE_MODULE_LINKER_FLAGS \"${CMAKE_MODULE_LINKER_FLAGS} /LTCG\")\n    endif()\n\n    add_library(libzmq SHARED ${sources} ${public_headers} ${html-docs} ${readme-docs}\n                              ${CMAKE_CURRENT_BINARY_DIR}/NSIS.template.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc)\n    if(ENABLE_ANALYSIS)\n      enable_vs_guideline_checker(libzmq)\n    endif()\n    set_target_properties(\n      libzmq\n      PROPERTIES PUBLIC_HEADER \"${public_headers}\"\n                 RELEASE_POSTFIX \"${MSVC_TOOLSET}-mt-${ZMQ_VERSION_MAJOR}_${ZMQ_VERSION_MINOR}_${ZMQ_VERSION_PATCH}\"\n                 RELWITHDEBINFO_POSTFIX\n                 \"${MSVC_TOOLSET}-mt-${ZMQ_VERSION_MAJOR}_${ZMQ_VERSION_MINOR}_${ZMQ_VERSION_PATCH}\"\n                 MINSIZEREL_POSTFIX \"${MSVC_TOOLSET}-mt-${ZMQ_VERSION_MAJOR}_${ZMQ_VERSION_MINOR}_${ZMQ_VERSION_PATCH}\"\n                 DEBUG_POSTFIX \"${MSVC_TOOLSET}-mt-gd-${ZMQ_VERSION_MAJOR}_${ZMQ_VERSION_MINOR}_${ZMQ_VERSION_PATCH}\"\n                 RUNTIME_OUTPUT_DIRECTORY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\"\n                 COMPILE_DEFINITIONS \"DLL_EXPORT\"\n                 OUTPUT_NAME \"lib${ZMQ_OUTPUT_BASENAME}\")\n    if(ZMQ_HAVE_WINDOWS_UWP)\n      set_target_properties(libzmq PROPERTIES LINK_FLAGS_DEBUG \"/OPT:NOICF /OPT:NOREF\")\n    endif()\n  endif()\n\n  if(BUILD_STATIC)\n    add_library(libzmq-static STATIC ${sources} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)\n    set_target_properties(\n      libzmq-static\n      PROPERTIES PUBLIC_HEADER \"${public_headers}\"\n                 RELEASE_POSTFIX \"${MSVC_TOOLSET}-mt-s-${ZMQ_VERSION_MAJOR}_${ZMQ_VERSION_MINOR}_${ZMQ_VERSION_PATCH}\"\n                 RELWITHDEBINFO_POSTFIX\n                 \"${MSVC_TOOLSET}-mt-s-${ZMQ_VERSION_MAJOR}_${ZMQ_VERSION_MINOR}_${ZMQ_VERSION_PATCH}\"\n                 MINSIZEREL_POSTFIX\n                 \"${MSVC_TOOLSET}-mt-s-${ZMQ_VERSION_MAJOR}_${ZMQ_VERSION_MINOR}_${ZMQ_VERSION_PATCH}\"\n                 DEBUG_POSTFIX \"${MSVC_TOOLSET}-mt-sgd-${ZMQ_VERSION_MAJOR}_${ZMQ_VERSION_MINOR}_${ZMQ_VERSION_PATCH}\"\n                 COMPILE_FLAGS \"/DZMQ_STATIC\"\n                 OUTPUT_NAME \"lib${ZMQ_OUTPUT_BASENAME}\")\n  endif()\nelse()\n  # avoid building everything twice for shared + static only on *nix, as Windows needs different preprocessor defines in\n  # static builds\n  if(NOT MINGW)\n    add_library(objects OBJECT ${sources})\n    set_property(TARGET objects PROPERTY POSITION_INDEPENDENT_CODE ON)\n    if(GNUTLS_FOUND)\n      target_include_directories(objects PRIVATE \"${GNUTLS_INCLUDE_DIR}\")\n    endif()\n  endif()\n\n  if(BUILD_SHARED)\n    if(MINGW)\n      add_library(libzmq SHARED ${sources} ${public_headers} ${html-docs} ${readme-docs} ${zmq-pkgconfig}\n                                ${CMAKE_CURRENT_BINARY_DIR}/version.rc)\n    else()\n        if (CMAKE_GENERATOR STREQUAL \"Xcode\")\n           add_library(libzmq SHARED ${sources} ${public_headers} ${html-docs} ${readme-docs}\n                                     ${zmq-pkgconfig} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)\n        else()\n           add_library(libzmq SHARED $<TARGET_OBJECTS:objects> ${public_headers} ${html-docs} ${readme-docs}\n                                     ${zmq-pkgconfig} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)\n        endif()\n\n    endif()\n    # NOTE: the SOVERSION and VERSION MUST be the same as the one generated by libtool! It is NOT the same as the\n    # version of the package.\n    set_target_properties(\n      libzmq PROPERTIES COMPILE_DEFINITIONS \"DLL_EXPORT\" PUBLIC_HEADER \"${public_headers}\" VERSION \"5.2.6\"\n                        SOVERSION \"5\" OUTPUT_NAME \"${ZMQ_OUTPUT_BASENAME}\" PREFIX \"lib\")\n    if(ZMQ_BUILD_FRAMEWORK)\n      set_target_properties(\n        libzmq\n        PROPERTIES FRAMEWORK TRUE MACOSX_FRAMEWORK_IDENTIFIER \"org.zeromq.libzmq\" MACOSX_FRAMEWORK_SHORT_VERSION_STRING\n                                                                                  ${ZMQ_VERSION}\n                   MACOSX_FRAMEWORK_BUNDLE_VERSION ${ZMQ_VERSION})\n      set_source_files_properties(${html-docs} PROPERTIES MACOSX_PACKAGE_LOCATION doc)\n      set_source_files_properties(${readme-docs} PROPERTIES MACOSX_PACKAGE_LOCATION etc)\n      set_source_files_properties(${zmq-pkgconfig} PROPERTIES MACOSX_PACKAGE_LOCATION lib/pkgconfig)\n    endif()\n  endif()\n\n  if(BUILD_STATIC)\n    if(MINGW)\n      add_library(libzmq-static STATIC ${sources} ${public_headers} ${html-docs} ${readme-docs} ${zmq-pkgconfig}\n                                       ${CMAKE_CURRENT_BINARY_DIR}/version.rc)\n    else()\n      if (CMAKE_GENERATOR STREQUAL \"Xcode\")\n        add_library(libzmq-static STATIC ${sources} ${public_headers} ${html-docs} ${readme-docs}\n                                         ${zmq-pkgconfig} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)\n      else()\n        add_library(libzmq-static STATIC $<TARGET_OBJECTS:objects> ${public_headers} ${html-docs} ${readme-docs}\n                                         ${zmq-pkgconfig} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)\n      endif()\n    endif()\n    if(CMAKE_SYSTEM_NAME MATCHES \"QNX\")\n      target_link_libraries(libzmq-static m)\n    endif()\n    set_target_properties(\n      libzmq-static PROPERTIES PUBLIC_HEADER \"${public_headers}\" OUTPUT_NAME \"${ZMQ_OUTPUT_BASENAME}\" PREFIX \"lib\")\n  endif()\nendif()\n\nif(BUILD_STATIC)\n  target_compile_definitions(libzmq-static PUBLIC ZMQ_STATIC)\nendif()\n\nlist(APPEND target_outputs \"\")\n\nif(BUILD_SHARED)\n  list(APPEND target_outputs \"libzmq\")\nendif()\n\nif(BUILD_STATIC)\n  list(APPEND target_outputs \"libzmq-static\")\nendif()\n\nset(build_targets ${target_outputs})\nif(TARGET objects)\n  list(APPEND build_targets \"objects\")\nendif()\n\nforeach(target ${build_targets})\n  target_include_directories(\n    ${target} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n                     $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> $<INSTALL_INTERFACE:include>)\n\n  if(ENABLE_DRAFTS)\n    target_compile_definitions(${target} PUBLIC ZMQ_BUILD_DRAFT_API)\n  endif()\nendforeach()\n\nif(BUILD_SHARED)\n  target_link_libraries(libzmq ${CMAKE_THREAD_LIBS_INIT})\n\n  if(QNX)\n    target_link_libraries(libzmq -lsocket)\n  endif()\n\n  if(GNUTLS_FOUND)\n    target_link_libraries(libzmq ${GNUTLS_LIBRARIES})\n    target_include_directories(libzmq PRIVATE \"${GNUTLS_INCLUDE_DIR}\")\n  endif()\n\n  if(NSS3_FOUND)\n    target_link_libraries(libzmq ${NSS3_LIBRARIES})\n  endif()\n\n  if(LIBBSD_FOUND)\n    target_link_libraries(libzmq ${LIBBSD_LIBRARIES})\n  endif()\n\n  if(SODIUM_FOUND)\n    target_link_libraries(libzmq ${SODIUM_LIBRARIES})\n    # On Solaris, libsodium depends on libssp\n    if(${CMAKE_SYSTEM_NAME} MATCHES \"SunOS\")\n      target_link_libraries(libzmq ssp)\n    endif()\n  endif()\n\n  if(WITH_GSSAPI_KRB5)\n    target_link_libraries(libzmq ${GSSAPI_KRB5_LIBRARIES})\n  endif()\n\n  if(HAVE_WS2_32)\n    target_link_libraries(libzmq ws2_32)\n  elseif(HAVE_WS2)\n    target_link_libraries(libzmq ws2)\n  endif()\n\n  if(HAVE_RPCRT4)\n    target_link_libraries(libzmq rpcrt4)\n  endif()\n\n  if(HAVE_IPHLAPI)\n    target_link_libraries(libzmq iphlpapi)\n  endif()\n\n  if(RT_LIBRARY)\n    target_link_libraries(libzmq -lrt)\n  endif()\n\n  if(norm_FOUND)\n      target_link_libraries(libzmq norm::norm)\n  endif()\n\n  if(OPENPGM_FOUND)\n      target_link_libraries(libzmq ${OPENPGM_LIBRARIES})\n  endif()\nendif()\n\nif(BUILD_STATIC)\n  target_link_libraries(libzmq-static ${CMAKE_THREAD_LIBS_INIT})\n  if(GNUTLS_FOUND)\n    target_link_libraries(libzmq-static ${GNUTLS_LIBRARIES})\n    target_include_directories(libzmq-static PRIVATE \"${GNUTLS_INCLUDE_DIR}\")\n  endif()\n\n  if(LIBBSD_FOUND)\n    target_link_libraries(libzmq-static ${LIBBSD_LIBRARIES})\n  endif()\n\n  if(NSS3_FOUND)\n    target_link_libraries(libzmq-static ${NSS3_LIBRARIES})\n  endif()\n\n  if(SODIUM_FOUND)\n    target_link_libraries(libzmq-static ${SODIUM_LIBRARIES})\n    # On Solaris, libsodium depends on libssp\n    if(${CMAKE_SYSTEM_NAME} MATCHES \"SunOS\")\n      target_link_libraries(libzmq-static ssp)\n    endif()\n  endif()\n\n  if(WITH_GSSAPI_KRB5)\n    target_link_libraries(libzmq-static ${GSSAPI_KRB5_LIBRARIES})\n  endif()\n\n  if(HAVE_WS2_32)\n    target_link_libraries(libzmq-static ws2_32)\n  elseif(HAVE_WS2)\n    target_link_libraries(libzmq-static ws2)\n  endif()\n\n  if(HAVE_RPCRT4)\n    target_link_libraries(libzmq-static rpcrt4)\n  endif()\n\n  if(HAVE_IPHLAPI)\n    target_link_libraries(libzmq-static iphlpapi)\n  endif()\n\n  if(RT_LIBRARY)\n    target_link_libraries(libzmq-static -lrt)\n  endif()\n\n  if(CMAKE_SYSTEM_NAME MATCHES \"QNX\")\n    add_definitions(-DUNITY_EXCLUDE_MATH_H)\n  endif()\n\n  if(norm_FOUND)\n      target_link_libraries(libzmq-static norm::norm)\n  endif()\n\n  if(OPENPGM_FOUND)\n      target_link_libraries(libzmq-static ${OPENPGM_LIBRARIES})\n  endif()\nendif()\n\nif(BUILD_SHARED)\n  set(perf-tools\n      local_lat\n      remote_lat\n      local_thr\n      remote_thr\n      inproc_lat\n      inproc_thr\n      proxy_thr)\n\n  if(NOT CMAKE_BUILD_TYPE STREQUAL \"Debug\") # Why?\n    option(WITH_PERF_TOOL \"Build with perf-tools\" ON)\n  else()\n    option(WITH_PERF_TOOL \"Build with perf-tools\" OFF)\n  endif()\n\n  if(WITH_PERF_TOOL)\n    foreach(perf-tool ${perf-tools})\n      add_executable(${perf-tool} perf/${perf-tool}.cpp)\n      target_link_libraries(${perf-tool} libzmq)\n\n      if(GNUTLS_FOUND)\n        target_link_libraries(${perf-tool} ${GNUTLS_LIBRARIES})\n        target_include_directories(${perf-tool} PRIVATE \"${GNUTLS_INCLUDE_DIR}\")\n      endif()\n\n      if(LIBBSD_FOUND)\n        target_link_libraries(${perf-tool} ${LIBBSD_LIBRARIES})\n      endif()\n\n      if(NSS3_FOUND)\n        target_link_libraries(${perf-tool} ${NSS3_LIBRARIES})\n      endif()\n\n      if(SODIUM_FOUND)\n        target_link_libraries(${perf-tool} ${SODIUM_LIBRARIES})\n      endif()\n\n      if(WITH_GSSAPI_KRB5)\n        target_link_libraries(${perf-tool} ${GSSAPI_KRB5_LIBRARIES})\n      endif()\n\n      if(ZMQ_BUILD_FRAMEWORK)\n        # Copy perf-tools binaries into Framework\n        add_custom_command(\n          TARGET libzmq\n          ${perf-tool} POST_BUILD\n          COMMAND ${CMAKE_COMMAND} ARGS -E copy \"$<TARGET_FILE:${perf-tool}>\"\n                  \"${LIBRARY_OUTPUT_PATH}/ZeroMQ.framework/Versions/${ZMQ_VERSION_STRING}/MacOS/${perf-tool}\"\n          VERBATIM\n          COMMENT \"Perf tools\")\n      else()\n        install(TARGETS ${perf-tool} RUNTIME DESTINATION bin COMPONENT PerfTools)\n      endif()\n      if(ZMQ_HAVE_WINDOWS_UWP)\n        set_target_properties(${perf-tool} PROPERTIES LINK_FLAGS_DEBUG \"/OPT:NOICF /OPT:NOREF\")\n      endif()\n    endforeach()\n\n    if(BUILD_STATIC)\n      add_executable(benchmark_radix_tree perf/benchmark_radix_tree.cpp)\n      target_link_libraries(benchmark_radix_tree libzmq-static)\n      target_include_directories(benchmark_radix_tree PUBLIC \"${CMAKE_CURRENT_LIST_DIR}/src\")\n      if(ZMQ_HAVE_WINDOWS_UWP)\n        set_target_properties(benchmark_radix_tree PROPERTIES LINK_FLAGS_DEBUG \"/OPT:NOICF /OPT:NOREF\")\n      endif()\n    endif()\n  elseif(WITH_PERF_TOOL)\n    message(FATAL_ERROR \"Shared library disabled - perf-tools unavailable.\")\n  endif()\nendif()\n\n# -----------------------------------------------------------------------------\n# tests\n\nif(${CMAKE_VERSION} VERSION_LESS 3.12.3)\n  option(BUILD_TESTS \"Whether or not to build the tests\" OFF)\nelse()\n  option(BUILD_TESTS \"Whether or not to build the tests\" ON)\nendif()\n\nset(ZMQ_BUILD_TESTS\n    ${BUILD_TESTS}\n    CACHE BOOL \"Build the tests for ZeroMQ\")\n\nif(ZMQ_BUILD_TESTS)\n  enable_testing() # Enable testing only works in root scope\n  add_subdirectory(tests)\n  if(BUILD_STATIC)\n    add_subdirectory(unittests)\n  else()\n    message(WARNING \"Not building unit tests, since BUILD_STATIC is not enabled\")\n  endif()\nendif()\n\n# -----------------------------------------------------------------------------\n# installer\n\nif(MSVC AND (BUILD_SHARED OR BUILD_STATIC))\n  install(\n    TARGETS ${target_outputs}\n    EXPORT ${PROJECT_NAME}-targets\n    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\n    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT SDK)\n  if(MSVC_IDE)\n    install(\n      FILES ${PDB_OUTPUT_DIRECTORY}/\\${CMAKE_INSTALL_CONFIG_NAME}/${PDB_NAME}.pdb\n      DESTINATION ${CMAKE_INSTALL_BINDIR}\n      COMPONENT SDK\n      OPTIONAL)\n  else()\n    install(\n      FILES ${PDB_OUTPUT_DIRECTORY}/${PDB_NAME}.pdb\n      DESTINATION ${CMAKE_INSTALL_BINDIR}\n      COMPONENT SDK\n      OPTIONAL)\n  endif()\n  if(BUILD_SHARED)\n    install(\n      TARGETS libzmq\n      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\n      PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT Runtime)\n  endif()\nelseif(BUILD_SHARED OR BUILD_STATIC)\n  install(\n    TARGETS ${target_outputs}\n    EXPORT ${PROJECT_NAME}-targets\n    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\n    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    FRAMEWORK DESTINATION \"Library/Frameworks\"\n    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})\nendif()\n\nforeach(readme ${readme-docs})\n  configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${readme} ${CMAKE_CURRENT_BINARY_DIR}/${readme}.txt)\n\n  if(NOT ZMQ_BUILD_FRAMEWORK)\n    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${readme}.txt DESTINATION share/zmq)\n  endif()\nendforeach()\n\nif(WITH_DOC)\n  if(NOT ZMQ_BUILD_FRAMEWORK)\n    install(\n      FILES ${html-docs}\n      DESTINATION doc/zmq\n      COMPONENT RefGuide)\n  endif()\nendif()\n\nif(WIN32 AND NOT MINGW)\n  set(ZEROMQ_CMAKECONFIG_INSTALL_DIR\n      \"CMake\"\n      CACHE STRING \"install path for ZeroMQConfig.cmake\")\nelse()\n  # CMake search path wants either \"share\" (AKA GNUInstallDirs DATAROOTDIR) for arch-independent, or LIBDIR for arch-\n  # dependent, plus \"cmake\" as prefix\n  set(ZEROMQ_CMAKECONFIG_INSTALL_DIR\n      \"${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}\"\n      CACHE STRING \"install path for ZeroMQConfig.cmake\")\nendif()\n\nif((NOT CMAKE_VERSION VERSION_LESS 3.0) AND (BUILD_SHARED OR BUILD_STATIC))\n  export(EXPORT ${PROJECT_NAME}-targets FILE \"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake\")\nendif()\nconfigure_package_config_file(\n  builds/cmake/${PROJECT_NAME}Config.cmake.in \"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake\"\n  INSTALL_DESTINATION ${ZEROMQ_CMAKECONFIG_INSTALL_DIR})\nwrite_basic_package_version_file(\n  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake\n  VERSION ${ZMQ_VERSION_MAJOR}.${ZMQ_VERSION_MINOR}.${ZMQ_VERSION_PATCH}\n  COMPATIBILITY AnyNewerVersion)\nif(BUILD_SHARED OR BUILD_STATIC)\n  install(\n    EXPORT ${PROJECT_NAME}-targets\n    FILE ${PROJECT_NAME}Targets.cmake\n    DESTINATION ${ZEROMQ_CMAKECONFIG_INSTALL_DIR})\n  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake\n                ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake\n          DESTINATION ${ZEROMQ_CMAKECONFIG_INSTALL_DIR})\nendif()\n\noption(ENABLE_CPACK \"Enables cpack rules\" ON)\nif(MSVC AND ENABLE_CPACK)\n  if(${CMAKE_BUILD_TYPE} MATCHES \"Debug\")\n    set(CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY TRUE)\n    set(CMAKE_INSTALL_DEBUG_LIBRARIES TRUE)\n    set(CMAKE_INSTALL_UCRT_LIBRARIES TRUE)\n  endif()\n  include(InstallRequiredSystemLibraries)\n\n  if(CMAKE_CL_64)\n    set(arch_name \"x64\")\n  else()\n    set(arch_name \"x86\")\n  endif()\n\n  set(CPACK_NSIS_DISPLAY_NAME \"ZeroMQ ${ZMQ_VERSION_MAJOR}.${ZMQ_VERSION_MINOR}.${ZMQ_VERSION_PATCH}(${arch_name})\")\n  set(CPACK_PACKAGE_FILE_NAME \"ZeroMQ-${ZMQ_VERSION_MAJOR}.${ZMQ_VERSION_MINOR}.${ZMQ_VERSION_PATCH}-${arch_name}\")\n\n  # TODO: I think this part was intended to be used when running cpack separately from cmake but I don't know how that\n  # works.\n  #\n  # macro(add_crt_version version) set(rel_dir\n  # \"${CMAKE_CURRENT_BINARY_DIR}/build/${arch_name}/${version};ZeroMQ;ALL;/\")\n  # set(debug_dir\n  # \"${CMAKE_CURRENT_BINARY_DIR}/debug/${arch_name}/${version};ZeroMQ;ALL;/\")\n  # if(EXISTS ${rel_dir}) list(APPEND CPACK_INSTALL_CMAKE_PROJECTS ${rel_dir}) endif()\n\n  # if(EXISTS ${debug_dir}) list(APPEND CPACK_INSTALL_CMAKE_PROJECTS ${rel_dir}) endmacro() endmacro()\n\n  # add_crt_version(v110) add_crt_version(v100) add_crt_version(v90)\n\n  list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_BINARY_DIR})\n  set(CPACK_GENERATOR \"NSIS\")\n  set(CPACK_PACKAGE_NAME \"ZeroMQ\")\n  set(CPACK_PACKAGE_DESCRIPTION_SUMMARY \"ZeroMQ lightweight messaging kernel\")\n  set(CPACK_PACKAGE_VENDOR \"Miru\")\n  set(CPACK_NSIS_CONTACT \"Steven McCoy <Steven.McCoy@miru.hk>\")\n  set(CPACK_RESOURCE_FILE_LICENSE \"${CMAKE_CURRENT_BINARY_DIR}\\\\\\\\LICENSE.txt\")\n  # set(CPACK_RESOURCE_FILE_README \"${CMAKE_CURRENT_BINARY_DIR}\\\\\\\\README.txt\") set(CPACK_RESOURCE_FILE_WELCOME\n  # \"${CMAKE_CURRENT_BINARY_DIR}\\\\\\\\WELCOME.txt\") There is a bug in NSI that does not handle full unix paths properly.\n  # Make sure there is at least one set of four(4) backslashes.\n  set(CPACK_NSIS_MUI_ICON \"${CMAKE_CURRENT_SOURCE_DIR}\\\\\\\\installer.ico\")\n  set(CPACK_NSIS_MUI_UNIICON \"${CMAKE_CURRENT_SOURCE_DIR}\\\\\\\\installer.ico\")\n\n  set(CPACK_PACKAGE_ICON \"${CMAKE_CURRENT_SOURCE_DIR}\\\\\\\\branding.bmp\")\n  set(CPACK_NSIS_COMPRESSOR \"/SOLID lzma\")\n  set(CPACK_PACKAGE_VERSION ${ZMQ_VERSION})\n  set(CPACK_PACKAGE_VERSION_MAJOR ${ZMQ_VERSION_MAJOR})\n  set(CPACK_PACKAGE_VERSION_MINOR ${ZMQ_VERSION_MINOR})\n  set(CPACK_PACKAGE_VERSION_PATCH ${ZMQ_VERSION_PATCH})\n  # set(CPACK_PACKAGE_INSTALL_DIRECTORY \"ZMQ Install Directory\") set(CPACK_TEMPORARY_DIRECTORY \"ZMQ Temporary CPack\n  # Directory\")\n\n  include(CPack)\n\n  cpack_add_component_group(Development DISPLAY_NAME \"ZeroMQ software development kit\" EXPANDED)\n  cpack_add_component(PerfTools DISPLAY_NAME \"ZeroMQ performance tools\" INSTALL_TYPES FullInstall DevInstall)\n  cpack_add_component(SourceCode DISPLAY_NAME \"ZeroMQ source code\" DISABLED INSTALL_TYPES FullInstall)\n  cpack_add_component(\n    SDK\n    DISPLAY_NAME\n    \"ZeroMQ headers and libraries\"\n    INSTALL_TYPES\n    FullInstall\n    DevInstall\n    GROUP\n    Development)\n  if(WITH_DOC)\n    cpack_add_component(\n      RefGuide\n      DISPLAY_NAME\n      \"ZeroMQ reference guide\"\n      INSTALL_TYPES\n      FullInstall\n      DevInstall\n      GROUP\n      Development)\n  endif()\n  cpack_add_component(\n    Runtime\n    DISPLAY_NAME\n    \"ZeroMQ runtime files\"\n    REQUIRED\n    INSTALL_TYPES\n    FullInstall\n    DevInstall\n    MinInstall)\n  cpack_add_install_type(FullInstall DISPLAY_NAME \"Full install, including source code\")\n  cpack_add_install_type(DevInstall DISPLAY_NAME \"Developer install, headers and libraries\")\n  cpack_add_install_type(MinInstall DISPLAY_NAME \"Minimal install, runtime only\")\nendif()\n\n# Export this for library to help build this as a sub-project\nset(ZEROMQ_LIBRARY\n    libzmq\n    CACHE STRING \"ZeroMQ library\")\n\n# Workaround for MSVS10 to avoid the Dialog Hell FIXME: This could be removed with future version of CMake.\nif(MSVC_VERSION EQUAL 1600)\n  set(ZMQ_SLN_FILENAME \"${CMAKE_CURRENT_BINARY_DIR}/ZeroMQ.sln\")\n  if(EXISTS \"${ZMQ_SLN_FILENAME}\")\n    file(APPEND \"${ZMQ_SLN_FILENAME}\" \"\\n# This should be regenerated!\\n\")\n  endif()\nendif()\n\n# this cannot be moved, as it does not only contain function/macro definitions\noption(ENABLE_CLANG \"Include Clang\" ON)\nif (ENABLE_CLANG)\n  include(ClangFormat)\nendif()\n\n# fixes https://github.com/zeromq/libzmq/issues/3776 The problem is, both libzmq-static libzmq try to use/generate\n# precompiled.pch at the same time Add a dependency, so they run in order and so they dont get in each others way TODO\n# still generates warning \"build\\x64-Debug\\ninja : warning : multiple rules generate precompiled.hpp. builds involving\n# this target will not be correct; continuing anyway [-w dupbuild=warn]\"\nif(MSVC\n   AND ENABLE_PRECOMPILED\n   AND BUILD_SHARED\n   AND BUILD_STATIC)\n  add_dependencies(libzmq-static libzmq)\nendif()\n\noption(ENABLE_NO_EXPORT \"Build with empty ZMQ_EXPORT macro, bypassing platform-based automated detection\" OFF)\nif(ENABLE_NO_EXPORT)\n  message(STATUS \"Building with empty ZMQ_EXPORT macro\")\n  add_definitions(-DZMQ_NO_EXPORT)\nendif()\n\nif (ENABLE_CURVE)\n  add_executable(curve_keygen tools/curve_keygen.cpp)\n  target_link_libraries(curve_keygen libzmq)\n  install(TARGETS curve_keygen RUNTIME DESTINATION bin)\nendif()\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM debian:buster-slim AS builder\nLABEL maintainer=\"ZeroMQ Project <zeromq@imatix.com>\"\nARG DEBIAN_FRONTEND=noninteractive\nRUN apt-get update -qq \\\n    && apt-get install -qq --yes --no-install-recommends \\\n        autoconf \\\n        automake \\\n        build-essential \\\n        git \\\n        libkrb5-dev \\\n        libsodium-dev \\\n        libtool \\\n        pkg-config \\\n    && rm -rf /var/lib/apt/lists/*\nWORKDIR /opt/libzmq\nCOPY . .\nRUN ./autogen.sh \\\n    && ./configure --prefix=/usr/local --with-libsodium --with-libgssapi_krb5 \\\n    && make \\\n    && make check \\\n    && make install\n\nFROM debian:buster-slim\nLABEL maintainer=\"ZeroMQ Project <zeromq@imatix.com>\"\nARG DEBIAN_FRONTEND=noninteractive\nRUN apt-get update -qq \\\n    && apt-get install -qq --yes --no-install-recommends \\\n        libkrb5-dev \\\n        libsodium23 \\\n    && rm -rf /var/lib/apt/lists/*\nCOPY --from=builder /usr/local /usr/local\nRUN ldconfig && ldconfig -p | grep libzmq\n"
  },
  {
    "path": "Doxygen.cfg",
    "content": "# Doxyfile 1.8.11\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project.\n#\n# All text after a double hash (##) is considered a comment and is placed in\n# front of the TAG it is preceding.\n#\n# All text after a single hash (#) is considered a comment and will be ignored.\n# The format is:\n# TAG = value [value, ...]\n# For lists, items can also be appended using:\n# TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\\\" \\\").\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the config file\n# that follow. The default is UTF-8 which is also the encoding used for all text\n# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv\n# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv\n# for the list of possible encodings.\n# The default value is: UTF-8.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by\n# double-quotes, unless you are using Doxywizard) that should identify the\n# project for which the documentation is generated. This name is used in the\n# title of most generated pages and in a few other places.\n# The default value is: My Project.\n\nPROJECT_NAME           = libzmq\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. This\n# could be handy for archiving the generated documentation or if some version\n# control system is used.\n\nPROJECT_NUMBER         = master\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer a\n# quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          = \"ZeroMQ C++ Core Engine (LIBZMQ)\"\n\nPROJECT_LOGO           = branding.bmp\n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path\n# into which the generated documentation will be written. If a relative path is\n# entered, it will be relative to the location where doxygen was started. If\n# left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = doxygen\n\n# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-\n# directories (in 2 levels) under the output directory of each output format and\n# will distribute the generated files over these directories. Enabling this\n# option can be useful when feeding doxygen a huge amount of source files, where\n# putting all generated files in the same directory would otherwise causes\n# performance problems for the file system.\n# The default value is: NO.\n\nCREATE_SUBDIRS         = YES\n\n# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII\n# characters to appear in the names of generated files. If set to NO, non-ASCII\n# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode\n# U+3044.\n# The default value is: NO.\n\nALLOW_UNICODE_NAMES    = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,\n# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),\n# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,\n# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),\n# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,\n# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,\n# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,\n# Ukrainian and Vietnamese.\n# The default value is: English.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member\n# descriptions after the members that are listed in the file and class\n# documentation (similar to Javadoc). Set to NO to disable this.\n# The default value is: YES.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief\n# description of a member or function before the detailed description\n#\n# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n# The default value is: YES.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator that is\n# used to form the text in various listings. Each string in this list, if found\n# as the leading text of the brief description, will be stripped from the text\n# and the result, after processing the whole list, is used as the annotated\n# text. Otherwise, the brief description is used as-is. If left blank, the\n# following values are used ($name is automatically replaced with the name of\n# the entity):The $name class, The $name widget, The $name file, is, provides,\n# specifies, contains, represents, a, an and the.\n\nABBREVIATE_BRIEF       =\n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# doxygen will generate a detailed section even if there is only a brief\n# description.\n# The default value is: NO.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n# The default value is: NO.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path\n# before files name in the file list and in the header files. If set to NO the\n# shortest path that makes the file name unique will be used\n# The default value is: YES.\n\nFULL_PATH_NAMES        = NO\n\n# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.\n# Stripping is only done if one of the specified strings matches the left-hand\n# part of the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which doxygen is run is used as the path to\n# strip.\n#\n# Note that you can specify absolute paths here, but also relative paths, which\n# will be relative from the directory where doxygen is started.\n# This tag requires that the tag FULL_PATH_NAMES is set to YES.\n\nSTRIP_FROM_PATH        = ../..\n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the\n# path mentioned in the documentation of a class, which tells the reader which\n# header file to include in order to use a class. If left blank only the name of\n# the header file containing the class definition is used. Otherwise one should\n# specify the list of include paths that are normally passed to the compiler\n# using the -I flag.\n\nSTRIP_FROM_INC_PATH    =\n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but\n# less readable) file names. This can be useful is your file systems doesn't\n# support long names like on DOS, Mac, or CD-ROM.\n# The default value is: NO.\n\nSHORT_NAMES            = NO\nJAVADOC_AUTOBRIEF      = NO\nQT_AUTOBRIEF           = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a\n# multi-line C++ special comment block (i.e. a block of //! or /// comments) as\n# a brief description. This used to be the default behavior. The new default is\n# to treat a multi-line C++ comment block as a detailed description. Set this\n# tag to YES if you prefer the old behavior instead.\n#\n# Note that setting this tag to YES also means that rational rose comments are\n# not recognized any more.\n# The default value is: NO.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the\n# documentation from any documented member that it re-implements.\n# The default value is: YES.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new\n# page for each member. If set to NO, the documentation of a member will be part\n# of the file/class/namespace that contains it.\n# The default value is: NO.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen\n# uses this value to replace tabs by spaces in code fragments.\n# Minimum value: 1, maximum value: 16, default value: 4.\n\nTAB_SIZE               = 4\n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources\n# only. Doxygen will then generate output that is more tailored for C. For\n# instance, some of the names that are used will be different. The list of all\n# members will be omitted, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_FOR_C  = NO\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments\n# according to the Markdown format, which allows for more readable\n# documentation. See http://daringfireball.net/projects/markdown/ for details.\n# The output of markdown processing is further processed by doxygen, so you can\n# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in\n# case of backward compatibilities issues.\n# The default value is: YES.\n\nMARKDOWN_SUPPORT       = YES\n\n# When enabled doxygen tries to link words that correspond to documented\n# classes, or namespaces to their corresponding documentation. Such a link can\n# be prevented in individual cases by putting a % sign in front of the word or\n# globally by setting AUTOLINK_SUPPORT to NO.\n# The default value is: YES.\n\nAUTOLINK_SUPPORT       = YES\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should set this\n# tag to YES in order to let doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string);\n# versus func(std::string) {}). This also make the inheritance and collaboration\n# diagrams that involve STL classes more complete and accurate.\n# The default value is: NO.\n\nBUILTIN_STL_SUPPORT    = YES\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n# The default value is: NO.\n\nCPP_CLI_SUPPORT        = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate\n# getter and setter methods for a property. Setting this option to YES will make\n# doxygen to replace the get and set methods by a property in the documentation.\n# This will only work if the methods are indeed getting or setting a simple\n# type. If this is not the case, or you want to show the methods anyway, you\n# should set this option to NO.\n# The default value is: YES.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES then doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n# The default value is: NO.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# If one adds a struct or class to a group and this option is enabled, then also\n# any nested class or struct is added to the same group. By default this option\n# is disabled and one has to add nested compounds explicitly via \\ingroup.\n# The default value is: NO.\n\nGROUP_NESTED_COMPOUNDS = NO\n\n# Set the SUBGROUPING tag to YES to allow class member groups of the same type\n# (for instance a group of public functions) to be put as a subgroup of that\n# type (e.g. under the Public Functions section). Set it to NO to prevent\n# subgrouping. Alternatively, this can be done per class using the\n# \\nosubgrouping command.\n# The default value is: YES.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions\n# are shown inside the group in which they are included (e.g. using \\ingroup)\n# instead of on a separate page (for HTML and Man pages) or section (for LaTeX\n# and RTF).\n#\n# Note that this feature does not work in combination with\n# SEPARATE_MEMBER_PAGES.\n# The default value is: NO.\n\nINLINE_GROUPED_CLASSES = NO\n\n# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions\n# with only public data fields or simple typedef fields will be shown inline in\n# the documentation of the scope in which they are defined (i.e. file,\n# namespace, or group documentation), provided this scope is documented. If set\n# to NO, structs, classes, and unions are shown on a separate page (for HTML and\n# Man pages) or section (for LaTeX and RTF).\n# The default value is: NO.\n\nINLINE_SIMPLE_STRUCTS  = NO\n\n# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or\n# enum is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically be\n# useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n# The default value is: NO.\n\nTYPEDEF_HIDES_STRUCT   = NO\n\n# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This\n# cache is used to resolve symbols given their name and scope. Since this can be\n# an expensive process and often the same symbol appears multiple times in the\n# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small\n# doxygen will become slower. If the cache is too large, memory is wasted. The\n# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range\n# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536\n# symbols. At the end of a run doxygen will report the cache usage and suggest\n# the optimal cache size from a speed point of view.\n# Minimum value: 0, maximum value: 9, default value: 0.\n\nLOOKUP_CACHE_SIZE      = 0\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in\n# documentation are documented, even if no documentation was available. Private\n# class members and static file members will be hidden unless the\n# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.\n# Note: This will also disable the warnings about undocumented members that are\n# normally produced when WARNINGS is set to YES.\n# The default value is: NO.\n\nEXTRACT_ALL            = YES\n\n# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will\n# be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIVATE        = YES\n\n# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal\n# scope will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PACKAGE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be\n# included in the documentation.\n# The default value is: NO.\n\nEXTRACT_STATIC         = YES\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined\n# locally in source files will be included in the documentation. If set to NO,\n# only classes defined in header files are included. Does not have any effect\n# for Java sources.\n# The default value is: YES.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base name of\n# the file that contains the anonymous namespace. By default anonymous namespace\n# are hidden.\n# The default value is: NO.\n\nEXTRACT_ANON_NSPACES   = YES\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all\n# undocumented members inside documented classes or files. If set to NO these\n# members will be included in the various overviews, but no documentation\n# section is generated. This option has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy. If set\n# to NO, these classes will be included in the various overviews. This option\n# has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend\n# (class|struct|union) declarations. If set to NO, these declarations will be\n# included in the documentation.\n# The default value is: NO.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any\n# documentation blocks found inside the body of a function. If set to NO, these\n# blocks will be appended to the function's detailed documentation block.\n# The default value is: NO.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation that is typed after a\n# \\internal command is included. If the tag is set to NO then the documentation\n# will be excluded. Set it to YES to include the internal documentation.\n# The default value is: NO.\n\nINTERNAL_DOCS          = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file\n# names in lower-case letters. If set to YES, upper-case letters are also\n# allowed. This is useful if you have classes or files whose names only differ\n# in case and if your file system supports case sensitive file names. Windows\n# and Mac users are advised to set this option to NO.\n# The default value is: system dependent.\n\nCASE_SENSE_NAMES       = YES\n\n# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with\n# their full class and namespace scopes in the documentation. If set to YES, the\n# scope will be hidden.\n# The default value is: NO.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will\n# append additional text to a page's title, such as Class Reference. If set to\n# YES the compound reference will be hidden.\n# The default value is: NO.\n\nHIDE_COMPOUND_REFERENCE= NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of\n# the files that are included by a file in the documentation of that file.\n# The default value is: YES.\n\nSHOW_INCLUDE_FILES     = YES\n\n# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each\n# grouped member an include statement to the documentation, telling the reader\n# which file to include in order to use the member.\n# The default value is: NO.\n\nSHOW_GROUPED_MEMB_INC  = NO\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include\n# files with double quotes in the documentation rather than with sharp brackets.\n# The default value is: NO.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the\n# documentation for inline members.\n# The default value is: YES.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the\n# (detailed) documentation of file and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order.\n# The default value is: YES.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief\n# descriptions of file, namespace and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order. Note that\n# this will also influence the order of the classes in the class list.\n# The default value is: NO.\n\nSORT_BRIEF_DOCS        = YES\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the\n# (brief and detailed) documentation of class members so that constructors and\n# destructors are listed first. If set to NO the constructors will appear in the\n# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.\n# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief\n# member documentation.\n# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting\n# detailed member documentation.\n# The default value is: NO.\n\nSORT_MEMBERS_CTORS_1ST = YES\n\n# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy\n# of group names into alphabetical order. If set to NO the group names will\n# appear in their defined order.\n# The default value is: NO.\n\nSORT_GROUP_NAMES       = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by\n# fully-qualified names, including namespaces. If set to NO, the class list will\n# be sorted only by class name, not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the alphabetical\n# list.\n# The default value is: NO.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper\n# type resolution of all parameters of a function it will reject a match between\n# the prototype and the implementation of a member function even if there is\n# only one candidate or it is obvious which candidate to choose by doing a\n# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still\n# accept a match between prototype and implementation in such cases.\n# The default value is: NO.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo\n# list. This list is created by putting \\todo commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test\n# list. This list is created by putting \\test commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug\n# list. This list is created by putting \\bug commands in the documentation.\n# The default value is: YES.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)\n# the deprecated list. This list is created by putting \\deprecated commands in\n# the documentation.\n# The default value is: YES.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the\n# initial value of a variable or macro / define can have for it to appear in the\n# documentation. If the initializer consists of more lines than specified here\n# it will be hidden. Use a value of 0 to hide initializers completely. The\n# appearance of the value of individual variables and macros / defines can be\n# controlled using \\showinitializer or \\hideinitializer command in the\n# documentation regardless of this setting.\n# Minimum value: 0, maximum value: 10000, default value: 30.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at\n# the bottom of the documentation of classes and structs. If set to YES, the\n# list will mention the files that were used to generate the documentation.\n# The default value is: YES.\n\nSHOW_USED_FILES        = NO\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This\n# will remove the Files entry from the Quick Index and from the Folder Tree View\n# (if specified).\n# The default value is: YES.\n\nSHOW_FILES             = YES\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces\n# page. This will remove the Namespaces entry from the Quick Index and from the\n# Folder Tree View (if specified).\n# The default value is: YES.\n\nSHOW_NAMESPACES        = NO\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command command input-file, where command is the value of the\n# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided\n# by doxygen. Whatever the program writes to standard output is used as the file\n# version. For an example see the documentation.\n\nFILE_VERSION_FILTER    =\n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. To create the layout file\n# that represents doxygen's defaults, run doxygen with the -l option. You can\n# optionally specify a file name after the option, if omitted DoxygenLayout.xml\n# will be used as the name of the layout file.\n#\n# Note that if you run doxygen from a directory containing a file called\n# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE\n# tag is left empty.\n\nLAYOUT_FILE            =\n\n# The CITE_BIB_FILES tag can be used to specify one or more bib files containing\n# the reference definitions. This must be a list of .bib files. The .bib\n# extension is automatically appended if omitted. This requires the bibtex tool\n# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.\n# For LaTeX the style of the bibliography can be controlled using\n# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the\n# search path. See also \\cite for info how to create references.\n\nCITE_BIB_FILES         =\n\n#---------------------------------------------------------------------------\n# Configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated to\n# standard output by doxygen. If QUIET is set to YES this implies that the\n# messages are off.\n# The default value is: NO.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES\n# this implies that the warnings are on.\n#\n# Tip: Turn warnings on while writing the documentation.\n# The default value is: YES.\n\nWARNINGS               = YES\n\n# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate\n# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: YES.\n\nWARN_IF_UNDOCUMENTED   = NO\n\n# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for\n# potential errors in the documentation, such as not documenting some parameters\n# in a documented function, or documenting parameters that don't exist or using\n# markup commands wrongly.\n# The default value is: YES.\n\nWARN_IF_DOC_ERROR      = YES\n\n# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that\n# are documented, but have no documentation for their parameters or return\n# value. If set to NO, doxygen will only warn about wrong or incomplete\n# parameter documentation, but not about the absence of documentation.\n# The default value is: NO.\n\nWARN_NO_PARAMDOC       = NO\n\n# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when\n# a warning is encountered.\n# The default value is: NO.\n\nWARN_AS_ERROR          = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that doxygen\n# can produce. The string should contain the $file, $line, and $text tags, which\n# will be replaced by the file and line number from which the warning originated\n# and the warning text. Optionally the format may contain $version, which will\n# be replaced by the version of the file (if it could be obtained via\n# FILE_VERSION_FILTER)\n# The default value is: $file:$line: $text.\n\nWARN_FORMAT            =\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning and error\n# messages should be written. If left blank the output is written to standard\n# error (stderr).\n\nWARN_LOGFILE           =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag is used to specify the files and/or directories that contain\n# documented source files. You may enter file names like myfile.cpp or\n# directories like /usr/src/myproject. Separate the files or directories with\n# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING\n# Note: If this tag is empty the current directory is searched.\n\nINPUT                  = include \\\n                         src \\\n                         tests \\\n                         perf \\\n                         README.doxygen.md\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses\n# libiconv (or the iconv built into libc) for the transcoding. See the libiconv\n# documentation (see: http://www.gnu.org/software/libiconv) for the list of\n# possible encodings.\n# The default value is: UTF-8.\n\nINPUT_ENCODING         = UTF-8\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and\n# *.h) to filter out the source-files in the directories.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# read by doxygen.\n#\n# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,\n# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,\n# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,\n# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,\n# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.\n\nFILE_PATTERNS          = *.c \\\n                         *.cpp \\\n                         *.h \\\n                         *.hpp\n\n# The RECURSIVE tag can be used to specify whether or not subdirectories should\n# be searched for input files as well.\n# The default value is: NO.\n\nRECURSIVE              = YES\n\n# The EXCLUDE tag can be used to specify files and/or directories that should be\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n#\n# Note that relative paths are relative to the directory from which doxygen is\n# run.\n\nEXCLUDE                =\n\n# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n# The default value is: NO.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories.\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       =\n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# AClass::ANamespace, ANamespace::*Test\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories use the pattern */test/*\n\nEXCLUDE_SYMBOLS        =\n\n# The EXAMPLE_PATH tag can be used to specify one or more files or directories\n# that contain example code fragments that are included (see the \\include\n# command).\n\nEXAMPLE_PATH           = tests perf\n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and\n# *.h) to filter out the source-files in the directories. If left blank all\n# files are included.\n\nEXAMPLE_PATTERNS       =\n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude commands\n# irrespective of the value of the RECURSIVE tag.\n# The default value is: NO.\n\nEXAMPLE_RECURSIVE      = YES\n\n# The IMAGE_PATH tag can be used to specify one or more files or directories\n# that contain images that are to be included in the documentation (see the\n# \\image command).\n\nIMAGE_PATH             =\n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command:\n#\n# <filter> <input-file>\n#\n# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the\n# name of an input file. Doxygen will then use the output that the filter\n# program writes to standard output. If FILTER_PATTERNS is specified, this tag\n# will be ignored.\n#\n# Note that the filter must not add or remove lines; it is applied before the\n# code is scanned, but not when the output code is generated. If lines are added\n# or removed, the anchors will not be placed correctly.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nINPUT_FILTER           =\n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis. Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match. The filters are a list of the form: pattern=filter\n# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how\n# filters are used. If the FILTER_PATTERNS tag is empty or if none of the\n# patterns match the file name, INPUT_FILTER is applied.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nFILTER_PATTERNS        =\n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER) will also be used to filter the input files that are used for\n# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).\n# The default value is: NO.\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and\n# it is also possible to disable source filtering for a specific pattern using\n# *.ext= (so without naming a filter).\n# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.\n\nFILTER_SOURCE_PATTERNS =\n\n# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that\n# is part of the input, its contents will be placed on the main page\n# (index.html). This can be useful if you have a project on for instance GitHub\n# and want to reuse the introduction page also for the doxygen output.\n\nUSE_MDFILE_AS_MAINPAGE = README.doxygen.md\n\n#---------------------------------------------------------------------------\n# Configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will be\n# generated. Documented entities will be cross-referenced with these sources.\n#\n# Note: To get rid of all source code in the generated output, make sure that\n# also VERBATIM_HEADERS is set to NO.\n# The default value is: NO.\n\nSOURCE_BROWSER         = YES\n\n# Setting the INLINE_SOURCES tag to YES will include the body of functions,\n# classes and enums directly into the documentation.\n# The default value is: NO.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any\n# special comment blocks from generated source code fragments. Normal C, C++ and\n# Fortran comments will always remain visible.\n# The default value is: YES.\n\nSTRIP_CODE_COMMENTS    = NO\n\n# If the REFERENCED_BY_RELATION tag is set to YES then for each documented\n# function all documented functions referencing it will be listed.\n# The default value is: NO.\n\nREFERENCED_BY_RELATION = YES\n\n# If the REFERENCES_RELATION tag is set to YES then for each documented function\n# all documented entities called/used by that function will be listed.\n# The default value is: NO.\n\nREFERENCES_RELATION    = YES\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set\n# to YES then the hyperlinks from functions in REFERENCES_RELATION and\n# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will\n# link to the documentation.\n# The default value is: YES.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the\n# source code will show a tooltip with additional information such as prototype,\n# brief description and links to the definition and documentation. Since this\n# will make the HTML file larger and loading of large files a bit slower, you\n# can opt to disable this feature.\n# The default value is: YES.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nSOURCE_TOOLTIPS        = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code will\n# point to the HTML generated by the htags(1) tool instead of doxygen built-in\n# source browser. The htags tool is part of GNU's global source tagging system\n# (see http://www.gnu.org/software/global/global.html). You will need version\n# 4.8.6 or higher.\n#\n# To use it do the following:\n# - Install the latest version of global\n# - Enable SOURCE_BROWSER and USE_HTAGS in the config file\n# - Make sure the INPUT points to the root of the source tree\n# - Run doxygen as normal\n#\n# Doxygen will invoke htags (and that will in turn invoke gtags), so these\n# tools must be available from the command line (i.e. in the search path).\n#\n# The result: instead of the source browser generated by doxygen, the links to\n# source code will now point to the output of htags.\n# The default value is: NO.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a\n# verbatim copy of the header file for each class for which an include is\n# specified. Set to NO to disable this.\n# See also: Section \\class.\n# The default value is: YES.\n\nVERBATIM_HEADERS       = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all\n# compounds will be generated. Enable this if the project contains a lot of\n# classes, structs, unions or interfaces.\n# The default value is: YES.\n\nALPHABETICAL_INDEX     = YES\n\n# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in\n# which the alphabetical index list will be split.\n# Minimum value: 1, maximum value: 20, default value: 5.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nCOLS_IN_ALPHA_INDEX    = 4\n\n# In case all classes in a project start with a common prefix, all classes will\n# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag\n# can be used to specify a prefix (or a list of prefixes) that should be ignored\n# while generating the index headers.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nIGNORE_PREFIX          =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output\n# The default value is: YES.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each\n# generated HTML page (for example: .htm, .php, .asp).\n# The default value is: .html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a user-defined HTML header file for\n# each generated HTML page. If the tag is left blank doxygen will generate a\n# standard header.\n#\n# To get valid HTML the header file that includes any scripts and style sheets\n# that doxygen needs, which is dependent on the configuration options used (e.g.\n# the setting GENERATE_TREEVIEW). It is highly recommended to start with a\n# default header using\n# doxygen -w html new_header.html new_footer.html new_stylesheet.css\n# YourConfigFile\n# and then modify the file new_header.html. See also section \"Doxygen usage\"\n# for information on how to generate the default header that doxygen normally\n# uses.\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. For a description\n# of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\n# HTML_HEADER            = doxygen.header\n\n# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each\n# generated HTML page. If the tag is left blank doxygen will generate a standard\n# footer. See HTML_HEADER for more information on how to generate a default\n# footer and what special commands can be used inside the footer. See also\n# section \"Doxygen usage\" for information on how to generate the default footer\n# that doxygen normally uses.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\n# HTML_FOOTER            = doxygen.footer\n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style\n# sheet that is used by each HTML page. It can be used to fine-tune the look of\n# the HTML output. If left blank doxygen will generate a default style sheet.\n# See also section \"Doxygen usage\" for information on how to generate the style\n# sheet that doxygen normally uses.\n# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as\n# it is more robust and this tag (HTML_STYLESHEET) will in the future become\n# obsolete.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\n# HTML_STYLESHEET        = doxygen.css\n\n# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# cascading style sheets that are included after the standard style sheets\n# created by doxygen. Using this option one can overrule certain style aspects.\n# This is preferred over using HTML_STYLESHEET since it does not replace the\n# standard style sheet and is therefore more robust against future updates.\n# Doxygen will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list). For an example see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_STYLESHEET  =\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that the\n# files will be copied as-is; there are no commands or markers available.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_FILES       =\n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen\n# will adjust the colors in the style sheet and background images according to\n# this color. Hue is specified as an angle on a colorwheel, see\n# http://en.wikipedia.org/wiki/Hue for more information. For instance the value\n# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300\n# purple, and 360 is red again.\n# Minimum value: 0, maximum value: 359, default value: 220.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\n# HTML_COLORSTYLE_HUE    = 240\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors\n# in the HTML output. For a value of 0 the output will use grayscales only. A\n# value of 255 will produce the most vivid colors.\n# Minimum value: 0, maximum value: 255, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\n#HTML_COLORSTYLE_SAT    = 100\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the\n# luminance component of the colors in the HTML output. Values below 100\n# gradually make the output lighter, whereas values above 100 make the output\n# darker. The value divided by 100 is the actual gamma applied, so 80 represents\n# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not\n# change the gamma.\n# Minimum value: 40, maximum value: 240, default value: 80.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\n#HTML_COLORSTYLE_GAMMA  = 80\n\n# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\n# page will contain the date and time when the page was generated. Setting this\n# to YES can help to show when doxygen was last run and thus if the\n# documentation is up to date.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_TIMESTAMP         = NO\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries\n# shown in the various tree structured indices initially; the user can expand\n# and collapse entries dynamically later on. Doxygen will expand the tree to\n# such a level that at most the specified number of entries are visible (unless\n# a fully collapsed tree already exceeds this amount). So setting the number of\n# entries 1 will produce a full collapsed tree by default. 0 is a special value\n# representing an infinite number of entries and will result in a full expanded\n# tree by default.\n# Minimum value: 0, maximum value: 9999, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_INDEX_NUM_ENTRIES = 100\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files will be\n# generated that can be used as input for Apple's Xcode 3 integrated development\n# environment (see: http://developer.apple.com/tools/xcode/), introduced with\n# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a\n# Makefile in the HTML output directory. Running make will produce the docset in\n# that directory and running make install will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at\n# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html\n# for more information.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_DOCSET        = NO\n\n# This tag determines the name of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# The default value is: Doxygen generated docs.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# This tag specifies a string that should uniquely identify the documentation\n# set bundle. This should be a reverse domain-name style string, e.g.\n# com.mycompany.MyDocSet. Doxygen will append .docset to the name.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_BUNDLE_ID       = org.doxygen.Project\n\n# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n# The default value is: org.doxygen.Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_ID    = org.doxygen.Publisher\n\n# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.\n# The default value is: Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three\n# additional HTML index files: index.hhp, index.hhc, and index.hhk. The\n# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop\n# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on\n# Windows.\n#\n# The HTML Help Workshop contains a compiler that can convert all HTML output\n# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML\n# files are now used as the Windows 98 help format, and will replace the old\n# Windows help format (.hlp) on all Windows platforms in the future. Compressed\n# HTML files also contain an index, a table of contents, and you can search for\n# words in the documentation. The HTML workshop also contains a viewer for\n# compressed HTML files.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_HTMLHELP      = NO\n\n# The CHM_FILE tag can be used to specify the file name of the resulting .chm\n# file. You can add a path in front of the file if the result should not be\n# written to the html output directory.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_FILE               =\n\n# The HHC_LOCATION tag can be used to specify the location (absolute path\n# including file name) of the HTML help compiler (hhc.exe). If non-empty,\n# doxygen will try to run the HTML help compiler on the generated index.hhp.\n# The file has to be specified with full path.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nHHC_LOCATION           =\n\n# The GENERATE_CHI flag controls if a separate .chi index file is generated\n# (YES) or that it should be included in the master .chm file (NO).\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nGENERATE_CHI           = NO\n\n# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)\n# and project file content.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_INDEX_ENCODING     =\n\n# The BINARY_TOC flag controls whether a binary table of contents is generated\n# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it\n# enables the Previous and Next buttons.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members to\n# the table of contents of the HTML help documentation and to the tree view.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nTOC_EXPAND             = NO\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that\n# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help\n# (.qch) of the generated HTML documentation.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify\n# the file name of the resulting .qch file. The path specified is relative to\n# the HTML output folder.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQCH_FILE               =\n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help\n# Project output. For more information please see Qt Help Project / Namespace\n# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_NAMESPACE          = org.doxygen.Project\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt\n# Help Project output. For more information please see Qt Help Project / Virtual\n# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-\n# folders).\n# The default value is: doc.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom\n# filter to add. For more information please see Qt Help Project / Custom\n# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-\n# filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_NAME   =\n\n# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see Qt Help Project / Custom\n# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-\n# filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_ATTRS  =\n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's filter section matches. Qt Help Project / Filter Attributes (see:\n# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_SECT_FILTER_ATTRS  =\n\n# The QHG_LOCATION tag can be used to specify the location of Qt's\n# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the\n# generated .qhp file.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHG_LOCATION           =\n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be\n# generated, together with the HTML files, they form an Eclipse help plugin. To\n# install this plugin and make it available under the help contents menu in\n# Eclipse, the contents of the directory containing the HTML and XML files needs\n# to be copied into the plugins directory of eclipse. The name of the directory\n# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.\n# After copying Eclipse needs to be restarted before the help appears.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the Eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have this\n# name. Each documentation set should have its own identifier.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# If you want full control over the layout of the generated HTML pages it might\n# be necessary to disable the index and replace it with your own. The\n# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top\n# of each HTML page. A value of NO enables the index and the value YES disables\n# it. Since the tabs in the index contain the same information as the navigation\n# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nDISABLE_INDEX          = NO\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information. If the tag\n# value is set to YES, a side panel will be generated containing a tree-like\n# index structure (just like the one that is generated for HTML Help). For this\n# to work a browser that supports JavaScript, DHTML, CSS and frames is required\n# (i.e. any modern browser). Windows users are probably better off using the\n# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can\n# further fine-tune the look of the index. As an example, the default style\n# sheet generated by doxygen has an example that shows how to put an image at\n# the root of the tree instead of the PROJECT_NAME. Since the tree basically has\n# the same information as the tab index, you could consider setting\n# DISABLE_INDEX to YES when enabling this option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_TREEVIEW      = YES\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that\n# doxygen will group on one line in the generated HTML documentation.\n#\n# Note that a value of 0 will completely suppress the enum values from appearing\n# in the overview section.\n# Minimum value: 0, maximum value: 20, default value: 4.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nENUM_VALUES_PER_LINE   = 4\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used\n# to set the initial width (in pixels) of the frame in which the tree is shown.\n# Minimum value: 0, maximum value: 1500, default value: 250.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nTREEVIEW_WIDTH         = 200\n\n# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to\n# external symbols imported via tag files in a separate window.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# Use this tag to change the font size of LaTeX formulas included as images in\n# the HTML documentation. When you change the font size after a successful\n# doxygen run you need to manually remove any form_*.png images from the HTML\n# output directory to force them to be regenerated.\n# Minimum value: 8, maximum value: 50, default value: 10.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_FONTSIZE       = 10\n\n# Use the FORMULA_TRANPARENT tag to determine whether or not the images\n# generated for formulas are transparent PNGs. Transparent PNGs are not\n# supported properly for IE 6.0, but are supported on all modern browsers.\n#\n# Note that when changing this option you need to delete any form_*.png files in\n# the HTML output directory before the changes have effect.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_TRANSPARENT    = YES\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see\n# http://www.mathjax.org) which uses client side Javascript for the rendering\n# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX\n# installed or if you want to formulas look prettier in the HTML output. When\n# enabled you may also need to install MathJax separately and configure the path\n# to it using the MATHJAX_RELPATH option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nUSE_MATHJAX            = NO\n\n# When MathJax is enabled you can set the default output format to be used for\n# the MathJax output. See the MathJax site (see:\n# http://docs.mathjax.org/en/latest/output.html) for more details.\n# Possible values are: HTML-CSS (which is slower, but has the best\n# compatibility), NativeMML (i.e. MathML) and SVG.\n# The default value is: HTML-CSS.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_FORMAT         = HTML-CSS\n\n# When MathJax is enabled you need to specify the location relative to the HTML\n# output directory using the MATHJAX_RELPATH option. The destination directory\n# should contain the MathJax.js script. For instance, if the mathjax directory\n# is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax\n# Content Delivery Network so you can quickly see the result without installing\n# MathJax. However, it is strongly recommended to install a local copy of\n# MathJax from http://www.mathjax.org before deployment.\n# The default value is: http://cdn.mathjax.org/mathjax/latest.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest\n\n# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax\n# extension names that should be enabled during MathJax rendering. For example\n# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_EXTENSIONS     =\n\n# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces\n# of code that will be used on startup of the MathJax code. See the MathJax site\n# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an\n# example see the documentation.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_CODEFILE       =\n\n# When the SEARCHENGINE tag is enabled doxygen will generate a search box for\n# the HTML output. The underlying search engine uses javascript and DHTML and\n# should work on any modern browser. Note that when using HTML help\n# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)\n# there is already a search function so this one should typically be disabled.\n# For large projects the javascript based search engine can be slow, then\n# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to\n# search using the keyboard; to jump to the search box use <access key> + S\n# (what the <access key> is depends on the OS and browser, but it is typically\n# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down\n# key> to jump into the search results window, the results can be navigated\n# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel\n# the search. The filter options can be selected when the cursor is inside the\n# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>\n# to select a filter and <Enter> or <escape> to activate or cancel the filter\n# option.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSEARCHENGINE           = NO\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a web server instead of a web client using Javascript. There\n# are two flavors of web server based searching depending on the EXTERNAL_SEARCH\n# setting. When disabled, doxygen will generate a PHP script for searching and\n# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing\n# and searching needs to be provided by external tools. See the section\n# \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSERVER_BASED_SEARCH    = NO\n\n# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP\n# script for searching. Instead the search results are written to an XML file\n# which needs to be processed by an external indexer. Doxygen will invoke an\n# external search engine pointed to by the SEARCHENGINE_URL option to obtain the\n# search results.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see: http://xapian.org/).\n#\n# See the section \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH        = NO\n\n# The SEARCHENGINE_URL should point to a search engine hosted by a web server\n# which will return the search results when EXTERNAL_SEARCH is enabled.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see: http://xapian.org/). See the section \"External Indexing and\n# Searching\" for details.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\n#SEARCHENGINE_URL       = @searchengine_url@\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed\n# search data is written to a file for indexing by an external tool. With the\n# SEARCHDATA_FILE tag the name of this file can be specified.\n# The default file is: searchdata.xml.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\n#SEARCHDATA_FILE        = searchdata.xml\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the\n# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is\n# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple\n# projects and redirect the results back to the right project.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\n#EXTERNAL_SEARCH_ID     = libzmq\n\n# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen\n# projects other than the one defined by this configuration file, but that are\n# all added to the same external search index. Each project needs to have a\n# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of\n# to a relative location where the documentation can be found. The format is:\n# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\n#EXTRA_SEARCH_MAPPINGS  = @extra_search_mappings@\n\n#---------------------------------------------------------------------------\n# Configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.\n# The default value is: YES.\n\nGENERATE_LATEX         = NO\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_OUTPUT           =\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked.\n#\n# Note that when enabling USE_PDFLATEX this option is only used for generating\n# bitmaps for formulas in the HTML output, but not in the Makefile that is\n# written to the output directory.\n# The default file is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate\n# index for LaTeX.\n# The default file is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used by the\n# printer.\n# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x\n# 14 inches) and executive (7.25 x 10.5 inches).\n# The default value is: a4.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPAPER_TYPE             = a4\n\n# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names\n# that should be included in the LaTeX output. The package can be specified just\n# by its name or with the correct syntax as to be used with the LaTeX\n# \\usepackage command. To get the times font for instance you can specify :\n# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}\n# To use the option intlimits with the amsmath package you can specify:\n# EXTRA_PACKAGES=[intlimits]{amsmath}\n# If left blank no extra packages will be included.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nEXTRA_PACKAGES         =\n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the\n# generated LaTeX document. The header should contain everything until the first\n# chapter. If it is left blank doxygen will generate a standard header. See\n# section \"Doxygen usage\" for information on how to let doxygen write the\n# default header to a separate file.\n#\n# Note: Only use a user-defined header if you know what you are doing! The\n# following commands have a special meaning inside the header: $title,\n# $datetime, $date, $doxygenversion, $projectname, $projectnumber,\n# $projectbrief, $projectlogo. Doxygen will replace $title with the empty\n# string, for the replacement values of the other commands the user is referred\n# to HTML_HEADER.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HEADER           =\n\n# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the\n# generated LaTeX document. The footer should contain everything after the last\n# chapter. If it is left blank doxygen will generate a standard footer. See\n# LATEX_HEADER for more information on how to generate a default footer and what\n# special commands can be used inside the footer.\n#\n# Note: Only use a user-defined footer if you know what you are doing!\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_FOOTER           =\n\n# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# LaTeX style sheets that are included after the standard style sheets created\n# by doxygen. Using this option one can overrule certain style aspects. Doxygen\n# will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_STYLESHEET =\n\n# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the LATEX_OUTPUT output\n# directory. Note that the files will be copied as-is; there are no commands or\n# markers available.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_FILES      =\n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is\n# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will\n# contain links (just like the HTML output) instead of page references. This\n# makes the output suitable for online browsing using a PDF viewer.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPDF_HYPERLINKS         = NO\n\n# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate\n# the PDF file directly from the LaTeX files. Set this option to YES, to get a\n# higher quality PDF documentation.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nUSE_PDFLATEX           = NO\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode\n# command to the generated LaTeX files. This will instruct LaTeX to keep running\n# if errors occur, instead of asking the user for help. This option is also used\n# when generating formulas in HTML.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BATCHMODE        = NO\n\n# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the\n# index chapters (such as File Index, Compound Index, etc.) in the output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HIDE_INDICES     = NO\n\n# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source\n# code with syntax highlighting in the LaTeX output.\n#\n# Note that which sources are shown also depends on other settings such as\n# SOURCE_BROWSER.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_SOURCE_CODE      = NO\n\n# The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n# bibliography, e.g. plainnat, or ieeetr. See\n# http://en.wikipedia.org/wiki/BibTeX and \\cite for more info.\n# The default value is: plain.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BIB_STYLE        = plain\n\n# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated\n# page will contain the date and time when the page was generated. Setting this\n# to NO can help when comparing the output of multiple runs.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_TIMESTAMP        = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The\n# RTF output is optimized for Word 97 and may not look too pretty with other RTF\n# readers/editors.\n# The default value is: NO.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: rtf.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_OUTPUT             =\n\n# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will\n# contain hyperlink fields. The RTF file will contain links (just like the HTML\n# output) instead of page references. This makes the output suitable for online\n# browsing using Word or some other Word compatible readers that support those\n# fields.\n#\n# Note: WordPad (write) and others do not support links.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's config\n# file, i.e. a series of assignments. You only have to provide replacements,\n# missing definitions are set to their default value.\n#\n# See also section \"Doxygen usage\" for information on how to generate the\n# default style sheet that doxygen normally uses.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_STYLESHEET_FILE    =\n\n# Set optional variables used in the generation of an RTF document. Syntax is\n# similar to doxygen's config file. A template extensions file can be generated\n# using doxygen -e rtf extensionFile.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_EXTENSIONS_FILE    =\n\n# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code\n# with syntax highlighting in the RTF output.\n#\n# Note that which sources are shown also depends on other settings such as\n# SOURCE_BROWSER.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_SOURCE_CODE        = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for\n# classes and files.\n# The default value is: NO.\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it. A directory man3 will be created inside the directory specified by\n# MAN_OUTPUT.\n# The default directory is: man.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_OUTPUT             =\n\n# The MAN_EXTENSION tag determines the extension that is added to the generated\n# man pages. In case the manual section does not start with a number, the number\n# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is\n# optional.\n# The default value is: .3.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_EXTENSION          =\n\n# The MAN_SUBDIR tag determines the name of the directory created within\n# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by\n# MAN_EXTENSION with the initial . removed.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_SUBDIR             =\n\n# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it\n# will generate one additional man file for each entity documented in the real\n# man page(s). These additional files only source the real man page, but without\n# them the man command would be unable to find the correct page.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that\n# captures the structure of the code including all documentation.\n# The default value is: NO.\n\nGENERATE_XML           = NO\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: xml.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_OUTPUT             = xml\n\n# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program\n# listings (including syntax highlighting and cross-referencing information) to\n# the XML output. Note that enabling this will significantly increase the size\n# of the XML output.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_PROGRAMLISTING     = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the DOCBOOK output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files\n# that can be used to generate PDF.\n# The default value is: NO.\n\nGENERATE_DOCBOOK       = NO\n\n# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in\n# front of it.\n# The default directory is: docbook.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_OUTPUT         = docbook\n\n# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the\n# program listings (including syntax highlighting and cross-referencing\n# information) to the DOCBOOK output. Note that enabling this will significantly\n# increase the size of the DOCBOOK output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_PROGRAMLISTING = NO\n\n#---------------------------------------------------------------------------\n# Configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an\n# AutoGen Definitions (see http://autogen.sf.net) file that captures the\n# structure of the code including all documentation. Note that this feature is\n# still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module\n# file that captures the structure of the code including all documentation.\n#\n# Note that this feature is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary\n# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI\n# output from the Perl module output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely\n# formatted so it can be parsed by a human reader. This is useful if you want to\n# understand what is going on. On the other hand, if this tag is set to NO, the\n# size of the Perl module output will be much smaller and Perl will parse it\n# just the same.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file are\n# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful\n# so different doxyrules.make files included by the same Makefile don't\n# overwrite each other's variables.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_MAKEVAR_PREFIX =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all\n# C-preprocessor directives found in the sources and include files.\n# The default value is: YES.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names\n# in the source code. If set to NO, only conditional compilation will be\n# performed. Macro expansion can be done in a controlled way by setting\n# EXPAND_ONLY_PREDEF to YES.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nMACRO_EXPANSION        = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then\n# the macro expansion is limited to the macros specified with the PREDEFINED and\n# EXPAND_AS_DEFINED tags.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES, the include files in the\n# INCLUDE_PATH will be searched if a #include is found.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by the\n# preprocessor.\n# This tag requires that the tag SEARCH_INCLUDES is set to YES.\n\nINCLUDE_PATH           = include\n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will be\n# used.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nINCLUDE_FILE_PATTERNS  =\n\n# The PREDEFINED tag can be used to specify one or more macro names that are\n# defined before the preprocessor is started (similar to the -D option of e.g.\n# gcc). The argument of the tag is a list of macros of the form: name or\n# name=definition (no spaces). If the definition and the \"=\" are omitted, \"=1\"\n# is assumed. To prevent a macro definition from being undefined via #undef or\n# recursively expanded use the := operator instead of the = operator.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nPREDEFINED             =\n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this\n# tag can be used to specify a list of macro names that should be expanded. The\n# macro definition that is found in the sources will be used. Use the PREDEFINED\n# tag if you want to use a different macro definition that overrules the\n# definition found in the source code.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_AS_DEFINED      =\n\n# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will\n# remove all references to function-like macros that are alone on a line, have\n# an all uppercase name, and do not end with a semicolon. Such function macros\n# are typically used for boiler-plate code, and will confuse the parser if not\n# removed.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES tag can be used to specify one or more tag files. For each tag\n# file the location of the external documentation should be added. The format of\n# a tag file without this location is as follows:\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where loc1 and loc2 can be relative or absolute paths or URLs. See the\n# section \"Linking to external documentation\" for more information about the use\n# of tag files.\n# Note: Each tag file must have a unique name (where the name does NOT include\n# the path). If a tag file is not located in the directory in which doxygen is\n# run, you must also specify the path to the tagfile here.\n\nTAGFILES               =\n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create a\n# tag file that is based on the input files it reads. See section \"Linking to\n# external documentation\" for more information about the usage of tag files.\n\nGENERATE_TAGFILE       =\n\n# If the ALLEXTERNALS tag is set to YES, all external class will be listed in\n# the class index. If set to NO, only the inherited external classes will be\n# listed.\n# The default value is: NO.\n\nALLEXTERNALS           = YES\n\n# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed\n# in the modules index. If set to NO, only the current project's groups will be\n# listed.\n# The default value is: YES.\n\nEXTERNAL_GROUPS        = YES\n\n# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in\n# the related pages index. If set to NO, only the current project's pages will\n# be listed.\n# The default value is: YES.\n\nEXTERNAL_PAGES         = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script\n# interpreter (i.e. the result of 'which perl').\n# The default file (with absolute path) is: /usr/bin/perl.\n\nPERL_PATH              =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool\n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram\n# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to\n# NO turns the diagrams off. Note that this option also works with HAVE_DOT\n# disabled, but it is recommended to install and use dot, since it yields more\n# powerful graphs.\n# The default value is: YES.\n\nCLASS_DIAGRAMS         = YES\n\n# You can define message sequence charts within doxygen comments using the \\msc\n# command. Doxygen will then run the mscgen tool (see:\n# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the\n# documentation. The MSCGEN_PATH tag allows you to specify the directory where\n# the mscgen tool resides. If left empty the tool is assumed to be found in the\n# default search path.\n\nMSCGEN_PATH            =\n\n# You can include diagrams made with dia in doxygen documentation. Doxygen will\n# then run dia to produce the diagram and insert it in the documentation. The\n# DIA_PATH tag allows you to specify the directory where the dia binary resides.\n# If left empty dia is assumed to be found in the default search path.\n\nDIA_PATH               =\n\n# If set to YES the inheritance and collaboration graphs will hide inheritance\n# and usage relations if the target is undocumented or is not a class.\n# The default value is: YES.\n\nHIDE_UNDOC_RELATIONS   = NO\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz (see:\n# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent\n# Bell Labs. The other options in this section have no effect if this option is\n# set to NO\n# The default value is: NO.\n\nHAVE_DOT               = YES\n\n# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed\n# to run in parallel. When set to 0 doxygen will base this on the number of\n# processors available in the system. You can set it explicitly to a value\n# larger than 0 to get control over the balance between CPU load and processing\n# speed.\n# Minimum value: 0, maximum value: 32, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NUM_THREADS        = 0\n\n# When you want a differently looking font in the dot files that doxygen\n# generates you can specify the font name using DOT_FONTNAME. You need to make\n# sure dot is able to find the font, which can be done by putting it in a\n# standard location or by setting the DOTFONTPATH environment variable or by\n# setting DOT_FONTPATH to the directory containing the font.\n# The default value is: Helvetica.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTNAME           = Helvetica\n\n# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of\n# dot graphs.\n# Minimum value: 4, maximum value: 24, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTSIZE           = 10\n\n# By default doxygen will tell dot to use the default font as specified with\n# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set\n# the path where dot can find it using this tag.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTPATH           =\n\n# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for\n# each documented class showing the direct and indirect inheritance relations.\n# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a\n# graph for each documented class showing the direct and indirect implementation\n# dependencies (inheritance, containment, and class references variables) of the\n# class with other documented classes.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for\n# groups, showing the direct groups dependencies.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LOOK               = NO\n\n# If the UML_LOOK tag is enabled, the fields and methods are shown inside the\n# class node. If there are many fields or methods and many nodes the graph may\n# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the\n# number of items for each type to make the size more manageable. Set this to 0\n# for no limit. Note that the threshold may be exceeded by 50% before the limit\n# is enforced. So when you set the threshold to 10, up to 15 fields may appear,\n# but if the number exceeds 15, the total amount of fields shown is limited to\n# 10.\n# Minimum value: 0, maximum value: 100, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LIMIT_NUM_FIELDS   = 10\n\n# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and\n# collaboration graphs will show the relations between templates and their\n# instances.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nTEMPLATE_RELATIONS     = YES\n\n# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to\n# YES then doxygen will generate a graph for each documented file showing the\n# direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDE_GRAPH          = YES\n\n# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are\n# set to YES then doxygen will generate a graph for each documented file showing\n# the direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDED_BY_GRAPH      = NO\n\n# If the CALL_GRAPH tag is set to YES then doxygen will generate a call\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable call graphs for selected\n# functions only using the \\callgraph command. Disabling a call graph can be\n# accomplished by means of the command \\hidecallgraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALL_GRAPH             = YES\n\n# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable caller graphs for selected\n# functions only using the \\callergraph command. Disabling a caller graph can be\n# accomplished by means of the command \\hidecallergraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALLER_GRAPH           = NO\n\n# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical\n# hierarchy of all classes instead of a textual one.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the\n# dependencies a directory has on other directories in a graphical way. The\n# dependency relations are determined by the #include relations between the\n# files in the directories.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDIRECTORY_GRAPH        = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot. For an explanation of the image formats see the section\n# output formats in the documentation of the dot tool (Graphviz (see:\n# http://www.graphviz.org/)).\n# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order\n# to make the SVG files visible in IE 9+ (other browsers do not have this\n# requirement).\n# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,\n# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and\n# png:gdiplus:gdiplus.\n# The default value is: png.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_IMAGE_FORMAT       = png\n\n# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n# enable generation of interactive SVG images that allow zooming and panning.\n#\n# Note that this requires a modern browser other than Internet Explorer. Tested\n# and working are Firefox, Chrome, Safari, and Opera.\n# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make\n# the SVG files visible. Older versions of IE do not have SVG support.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINTERACTIVE_SVG        = NO\n\n# The DOT_PATH tag can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_PATH               =\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the \\dotfile\n# command).\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOTFILE_DIRS           =\n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the \\mscfile\n# command).\n\nMSCFILE_DIRS           =\n\n# The DIAFILE_DIRS tag can be used to specify one or more directories that\n# contain dia files that are included in the documentation (see the \\diafile\n# command).\n\nDIAFILE_DIRS           =\n\n# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the\n# path where java can find the plantuml.jar file. If left blank, it is assumed\n# PlantUML is not used or called during a preprocessing step. Doxygen will\n# generate a warning when it encounters a \\startuml command in this case and\n# will not generate output for the diagram.\n\nPLANTUML_JAR_PATH      =\n\n# When using plantuml, the specified paths are searched for files specified by\n# the !include statement in a plantuml block.\n\nPLANTUML_INCLUDE_PATH  =\n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes\n# that will be shown in the graph. If the number of nodes in a graph becomes\n# larger than this value, doxygen will truncate the graph, which is visualized\n# by representing a node as a red box. Note that doxygen if the number of direct\n# children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that\n# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n# Minimum value: 0, maximum value: 10000, default value: 50.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_GRAPH_MAX_NODES    = 100\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs\n# generated by dot. A depth value of 3 means that only nodes reachable from the\n# root by following a path via at most 3 edges will be shown. Nodes that lay\n# further from the root node will be omitted. Note that setting this option to 1\n# or 2 may greatly reduce the computation time needed for large code bases. Also\n# note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n# Minimum value: 0, maximum value: 1000, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nMAX_DOT_GRAPH_DEPTH    = 5\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent\n# background. This is disabled by default, because dot on Windows does not seem\n# to support this out of the box.\n#\n# Warning: Depending on the platform used, enabling this option may lead to\n# badly anti-aliased labels on the edges of a graph (i.e. they become hard to\n# read).\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_TRANSPARENT        = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10) support\n# this, this feature is disabled by default.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page\n# explaining the meaning of the various boxes and arrows in the dot generated\n# graphs.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot\n# files that are used to generate the various graphs.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_CLEANUP            = YES\n"
  },
  {
    "path": "INSTALL",
    "content": "Installation Instructions\n*************************\n\nCopyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,\n2006, 2007 Free Software Foundation, Inc.\n\nThis file is free documentation; the Free Software Foundation gives\nunlimited permission to copy, distribute and modify it.\n\nFrom GitHub\n===========\n\nIf you clone the Git repository then you should start by running the\ncommand `./autogen.sh`. This is not necessary if you get the source\npackages.\n\nCMake installation\n==================\n\nThe following options are available for cmake invocation:\n\n- `WITH_PERF_TOOL'\n    Enables the build of performance tools. Default value is ON.\n- `ZMQ_BUILD_TESTS'\n    Builds ZeroMQ tests. Default value is ON.\n- `ENABLE_CPACK'\n    Enables CPack build rules. This option has effect on Windows\n    platform only. Default value is ON. Turn it to OFF if you\n    don't want the runtime libraries to be installed (typically\n    if your installation destination already contains them).\n    \n\nExample: installing ZeroMQ on Windows with no tests, no performance\ntools, and no runtime library copy:\n\ncmake -G \"NMake Makefiles\" -D WITH_PERF_TOOL=OFF -D ZMQ_BUILD_TESTS=OFF\n-D ENABLE_CPACK=OFF -D CMAKE_BUILD_TYPE=Release\n\nWindows Builds\n==============\n\nOn Windows, use CMake for building, or for generating a Visual Studio solution file.\n\nThe library can also be built for the Windows 10 UWP platform through CMake :\ncmake -H. -B<build dir> -G\"Visual Studio 14 2015 Win64\" \\\n   -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 \\\n   -DENABLE_CURVE=OFF -DZMQ_BUILD_TESTS=OFF\n\nIn VS 2012 it is mandatory to increase the default stack size of 1 MB to\nat least 2 MB due to implementation of std::map intermittently requiring\nsubstantial amount of stack and causing stack overflow. \n\nWindows Builds - Static\n=======================\n\nWhen linking statically with libzmq your CFLAGS and/or CPPFLAGS need to include\n`-DZMQ_STATIC` otherwise `__dclspec(dllimport)` will be set for all functions\nand the build will fail.\n\nThis is a workaround for issue:\nhttps://github.com/zeromq/libzmq/issues/2788\n\nWindows Builds - Wine\n=====================\n\nTo use Windows binaries on *nix via Wine, it is necessary to ensure that the\nkernel TCP buffers are large enough. On some systems, like OS X, they are too\nsmall by default.\nThey need to be set to at least one MB as a workaround for issue:\nhttps://github.com/zeromq/libzmq/issues/1608\n\nsudo sysctl -w net.inet.tcp.sendspace=1300000\n\nBasic Installation\n==================\n\nBriefly, the shell commands `./configure; make; make install' should\nconfigure, build, and install this package.  The following\nmore-detailed instructions are generic; see the `README' file for\ninstructions specific to this package.\n\n   The `configure' shell script attempts to guess correct values for\nvarious system-dependent variables used during compilation.  It uses\nthose values to create a `Makefile' in each directory of the package.\nIt may also create one or more `.h' files containing system-dependent\ndefinitions.  Finally, it creates a shell script `config.status' that\nyou can run in the future to recreate the current configuration, and a\nfile `config.log' containing compiler output (useful mainly for\ndebugging `configure').\n\n   It can also use an optional file (typically called `config.cache'\nand enabled with `--cache-file=config.cache' or simply `-C') that saves\nthe results of its tests to speed up reconfiguring.  Caching is\ndisabled by default to prevent problems with accidental use of stale\ncache files.\n\n   If you need to do unusual things to compile the package, please try\nto figure out how `configure' could check whether to do them, and mail\ndiffs or instructions to the address given in the `README' so they can\nbe considered for the next release.  If you are using the cache, and at\nsome point `config.cache' contains results you don't want to keep, you\nmay remove or edit it.\n\n   The file `configure.ac' (or `configure.in') is used to create\n`configure' by a program called `autoconf'.  You need `configure.ac' if\nyou want to change it or regenerate `configure' using a newer version\nof `autoconf'.  If you are building a development version from the\nGithub source, for example, use `./autogen.sh' to generate `configure'\nand other necessary installation scripts.\n\nThe simplest way to compile this package is:\n\n  1. `cd' to the directory containing the package's source code and type\n     `./configure' to configure the package for your system.\n\n     Running `configure' might take a while.  While running, it prints\n     some messages telling which features it is checking for.\n\n  2. Type `make' to compile the package.\n\n  3. Optionally, type `make check' to run any self-tests that come with\n     the package. Note that `make -j check' is not supported as some\n     tests share infrastructure and cannot be run in parallel.\n\n  4. Type `make install' to install the programs and any data files and\n     documentation.\n\n  5. You can remove the program binaries and object files from the\n     source code directory by typing `make clean'.  To also remove the\n     files that `configure' created (so you can compile the package for\n     a different kind of computer), type `make distclean'.  There is\n     also a `make maintainer-clean' target, but that is intended mainly\n     for the package's developers.  If you use it, you may have to get\n     all sorts of other programs in order to regenerate files that came\n     with the distribution.\n\n  6. Often, you can also type `make uninstall' to remove the installed\n     files again.\n\nOS X Builds - Documentation\n===========================\n\nBasic installation on OS X may fail in `Making all in doc' step. This\nerror can be resolved by adding environment variable for shell.\n\nexport XML_CATALOG_FILES=/usr/local/etc/xml/catalog \n\nWrite command above in shell for instant resolve, or append command into\nshell profile file and reload for permanent resolve.\n\nCompilers and Options\n=====================\n\nSome systems require unusual options for compilation or linking that the\n`configure' script does not know about.  Run `./configure --help' for\ndetails on some of the pertinent environment variables.\n\n   You can give `configure' initial values for configuration parameters\nby setting variables in the command line or in the environment.  Here\nis an example:\n\n     ./configure CC=c99 CFLAGS=-g LIBS=-lposix\n\n   *Note Defining Variables::, for more details.\n\nCompiling For Multiple Architectures\n====================================\n\nYou can compile the package for more than one kind of computer at the\nsame time, by placing the object files for each architecture in their\nown directory.  To do this, you can use GNU `make'.  `cd' to the\ndirectory where you want the object files and executables to go and run\nthe `configure' script.  `configure' automatically checks for the\nsource code in the directory that `configure' is in and in `..'.\n\n   With a non-GNU `make', it is safer to compile the package for one\narchitecture at a time in the source code directory.  After you have\ninstalled the package for one architecture, use `make distclean' before\nreconfiguring for another architecture.\n\nInstallation Names\n==================\n\nBy default, `make install' installs the package's commands under\n`/usr/local/bin', include files under `/usr/local/include', etc.  You\ncan specify an installation prefix other than `/usr/local' by giving\n`configure' the option `--prefix=PREFIX'.\n\n   You can specify separate installation prefixes for\narchitecture-specific files and architecture-independent files.  If you\npass the option `--exec-prefix=PREFIX' to `configure', the package uses\nPREFIX as the prefix for installing programs and libraries.\nDocumentation and other data files still use the regular prefix.\n\n   In addition, if you use an unusual directory layout you can give\noptions like `--bindir=DIR' to specify different values for particular\nkinds of files.  Run `configure --help' for a list of the directories\nyou can set and what kinds of files go in them.\n\n   If the package supports it, you can cause programs to be installed\nwith an extra prefix or suffix on their names by giving `configure' the\noption `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.\n\nOptional Features\n=================\n\nSome packages pay attention to `--enable-FEATURE' options to\n`configure', where FEATURE indicates an optional part of the package.\nThey may also pay attention to `--with-PACKAGE' options, where PACKAGE\nis something like `gnu-as' or `x' (for the X Window System).  The\n`README' should mention any `--enable-' and `--with-' options that the\npackage recognizes.\n\n   For packages that use the X Window System, `configure' can usually\nfind the X include and library files automatically, but if it doesn't,\nyou can use the `configure' options `--x-includes=DIR' and\n`--x-libraries=DIR' to specify their locations.\n\nSpecifying the System Type\n==========================\n\nThere may be some features `configure' cannot figure out automatically,\nbut needs to determine by the type of machine the package will run on.\nUsually, assuming the package is built to be run on the _same_\narchitectures, `configure' can figure that out, but if it prints a\nmessage saying it cannot guess the machine type, give it the\n`--build=TYPE' option.  TYPE can either be a short name for the system\ntype, such as `sun4', or a canonical name which has the form:\n\n     CPU-COMPANY-SYSTEM\n\nwhere SYSTEM can have one of these forms:\n\n     OS KERNEL-OS\n\n   See the file `config.sub' for the possible values of each field.  If\n`config.sub' isn't included in this package, then this package doesn't\nneed to know the machine type.\n\n   If you are _building_ compiler tools for cross-compiling, you should\nuse the option `--target=TYPE' to select the type of system they will\nproduce code for.\n\n   If you want to _use_ a cross compiler, that generates code for a\nplatform different from the build platform, you should specify the\n\"host\" platform (i.e., that on which the generated programs will\neventually be run) with `--host=TYPE'.\n\nSharing Defaults\n================\n\nIf you want to set default values for `configure' scripts to share, you\ncan create a site shell script called `config.site' that gives default\nvalues for variables like `CC', `cache_file', and `prefix'.\n`configure' looks for `PREFIX/share/config.site' if it exists, then\n`PREFIX/etc/config.site' if it exists.  Or, you can set the\n`CONFIG_SITE' environment variable to the location of the site script.\nA warning: not all `configure' scripts look for a site script.\n\nDefining Variables\n==================\n\nVariables not defined in a site shell script can be set in the\nenvironment passed to `configure'.  However, some packages may run\nconfigure again during the build, and the customized values of these\nvariables may be lost.  In order to avoid this problem, you should set\nthem in the `configure' command line, using `VAR=value'.  For example:\n\n     ./configure CC=/usr/local2/bin/gcc\n\ncauses the specified `gcc' to be used as the C compiler (unless it is\noverridden in the site shell script).\n\nUnfortunately, this technique does not work for `CONFIG_SHELL' due to\nan Autoconf bug.  Until the bug is fixed you can use this workaround:\n\n     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash\n\n`configure' Invocation\n======================\n\n`configure' recognizes the following options to control how it operates.\n\n`--help'\n`-h'\n     Print a summary of the options to `configure', and exit.\n\n`--version'\n`-V'\n     Print the version of Autoconf used to generate the `configure'\n     script, and exit.\n\n`--cache-file=FILE'\n     Enable the cache: use and save the results of the tests in FILE,\n     traditionally `config.cache'.  FILE defaults to `/dev/null' to\n     disable caching.\n\n`--config-cache'\n`-C'\n     Alias for `--cache-file=config.cache'.\n\n`--quiet'\n`--silent'\n`-q'\n     Do not print messages saying which checks are being made.  To\n     suppress all normal output, redirect it to `/dev/null' (any error\n     messages will still be shown).\n\n`--srcdir=DIR'\n     Look for the package's source code in directory DIR.  Usually\n     `configure' can determine that directory automatically.\n\n`configure' also accepts some other, not widely useful, options.  Run\n`configure --help' for more details.\n\n"
  },
  {
    "path": "Jenkinsfile",
    "content": "pipeline {\n    agent { label \"linux || macosx || bsd || solaris || posix || windows\" }\n    parameters {\n        // Use DEFAULT_DEPLOY_BRANCH_PATTERN and DEFAULT_DEPLOY_JOB_NAME if\n        // defined in this jenkins setup -- in Jenkins Management Web-GUI\n        // see Configure System / Global properties / Environment variables\n        // Default (if unset) is empty => no deployment attempt after good test\n        // See zproject Jenkinsfile-deploy.example for an example deploy job.\n        // TODO: Try to marry MultiBranchPipeline support with pre-set defaults\n        // directly in MultiBranchPipeline plugin, or mechanism like Credentials,\n        // or a config file uploaded to master for all jobs or this job, see\n        // https://jenkins.io/doc/pipeline/examples/#configfile-provider-plugin\n        string (\n            defaultValue: '${DEFAULT_DEPLOY_BRANCH_PATTERN}',\n            description: 'Regular expression of branch names for which a deploy action would be attempted after a successful build and test; leave empty to not deploy. Reasonable value is ^(master|release/.*|feature/*)$',\n            name : 'DEPLOY_BRANCH_PATTERN')\n        string (\n            defaultValue: '${DEFAULT_DEPLOY_JOB_NAME}',\n            description: 'Name of your job that handles deployments and should accept arguments: DEPLOY_GIT_URL DEPLOY_GIT_BRANCH DEPLOY_GIT_COMMIT -- and it is up to that job what to do with this knowledge (e.g. git archive + push to packaging); leave empty to not deploy',\n            name : 'DEPLOY_JOB_NAME')\n        booleanParam (\n            defaultValue: true,\n            description: 'If the deployment is done, should THIS job wait for it to complete and include its success or failure as the build result (true), or should it schedule the job and exit quickly to free up the executor (false)',\n            name: 'DEPLOY_REPORT_RESULT')\n        booleanParam (\n            defaultValue: true,\n            description: 'Attempt stable build without DRAFT API in this run?',\n            name: 'DO_BUILD_WITHOUT_DRAFT_API')\n        booleanParam (\n            defaultValue: true,\n            description: 'Attempt build with DRAFT API in this run?',\n            name: 'DO_BUILD_WITH_DRAFT_API')\n        booleanParam (\n            defaultValue: true,\n            description: 'Attempt a build with docs in this run? (Note: corresponding tools are required in the build environment)',\n            name: 'DO_BUILD_DOCS')\n        booleanParam (\n            defaultValue: false,\n            description: 'Publish as an archive a \"dist\" tarball from a build with docs in this run? (Note: corresponding tools are required in the build environment; enabling this enforces DO_BUILD_DOCS too)',\n            name: 'DO_DIST_DOCS')\n        booleanParam (\n            defaultValue: true,\n            description: 'Attempt \"make check\" in this run?',\n            name: 'DO_TEST_CHECK')\n        booleanParam (\n            defaultValue: false,\n            description: 'Attempt \"make memcheck\" in this run?',\n            name: 'DO_TEST_MEMCHECK')\n        booleanParam (\n            defaultValue: true,\n            description: 'Attempt \"make distcheck\" in this run?',\n            name: 'DO_TEST_DISTCHECK')\n        booleanParam (\n            defaultValue: true,\n            description: 'Attempt a \"make install\" check in this run?',\n            name: 'DO_TEST_INSTALL')\n        string (\n            defaultValue: \"`pwd`/tmp/_inst\",\n            description: 'If attempting a \"make install\" check in this run, what DESTDIR to specify? (absolute path, defaults to \"BUILD_DIR/tmp/_inst\")',\n            name: 'USE_TEST_INSTALL_DESTDIR')\n        booleanParam (\n            defaultValue: true,\n            description: 'Attempt \"cppcheck\" analysis before this run? (Note: corresponding tools are required in the build environment)',\n            name: 'DO_CPPCHECK')\n        booleanParam (\n            defaultValue: true,\n            description: 'Require that there are no files not discovered changed/untracked via .gitignore after builds and tests?',\n            name: 'REQUIRE_GOOD_GITIGNORE')\n        string (\n            defaultValue: \"30\",\n            description: 'When running tests, use this timeout (in minutes; be sure to leave enough for double-job of a distcheck too)',\n            name: 'USE_TEST_TIMEOUT')\n        booleanParam (\n            defaultValue: true,\n            description: 'When using temporary subdirs in build/test workspaces, wipe them after successful builds?',\n            name: 'DO_CLEANUP_AFTER_BUILD')\n    }\n    triggers {\n        pollSCM 'H/2 * * * *'\n    }\n// Note: your Jenkins setup may benefit from similar setup on side of agents:\n//        PATH=\"/usr/lib64/ccache:/usr/lib/ccache:/usr/bin:/bin:${PATH}\"\n    stages {\n        stage ('prepare') {\n                    steps {\n                        dir(\"tmp\") {\n                            sh 'if [ -s Makefile ]; then make -k distclean || true ; fi'\n                            sh 'chmod -R u+w .'\n                            deleteDir()\n                        }\n                        sh './autogen.sh'\n                        stash (name: 'prepped', includes: '**/*', excludes: '**/cppcheck.xml')\n                    }\n        }\n        stage ('compile') {\n            parallel {\n                stage ('build with DRAFT') {\n                    when { expression { return ( params.DO_BUILD_WITH_DRAFT_API ) } }\n                    steps {\n                      dir(\"tmp/build-withDRAFT\") {\n                        deleteDir()\n                        unstash 'prepped'\n                        sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; ./configure --enable-drafts=yes --with-docs=no'\n                        sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; make -k -j4 || make'\n                        sh 'echo \"Are GitIgnores good after make with drafts? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        stash (name: 'built-draft', includes: '**/*', excludes: '**/cppcheck.xml')\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n                stage ('build without DRAFT') {\n                    when { expression { return ( params.DO_BUILD_WITHOUT_DRAFT_API ) } }\n                    steps {\n                      dir(\"tmp/build-withoutDRAFT\") {\n                        deleteDir()\n                        unstash 'prepped'\n                        sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; ./configure --enable-drafts=no --with-docs=no'\n                        sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; make -k -j4 || make'\n                        sh 'echo \"Are GitIgnores good after make without drafts? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        stash (name: 'built-nondraft', includes: '**/*', excludes: '**/cppcheck.xml')\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n                stage ('build with DOCS') {\n                    when { expression { return ( params.DO_BUILD_DOCS || params.DO_DIST_DOCS ) } }\n                    steps {\n                      dir(\"tmp/build-DOCS\") {\n                        deleteDir()\n                        unstash 'prepped'\n                        sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; ./configure --enable-drafts=yes --with-docs=yes'\n                        script {\n                            if ( params.DO_DIST_DOCS ) {\n                                sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; make dist-gzip || exit ; DISTFILE=\"`ls -1tc *.tar.gz | head -1`\" && [ -n \"$DISTFILE\" ] && [ -s \"$DISTFILE\" ] || exit ; mv -f \"$DISTFILE\" __dist.tar.gz'\n                                archiveArtifacts artifacts: '__dist.tar.gz'\n                                sh \"rm -f __dist.tar.gz\"\n                            }\n                        }\n                        sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; make -k -j4 || make'\n                        sh 'echo \"Are GitIgnores good after make with docs? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        stash (name: 'built-docs', includes: '**/*', excludes: '**/cppcheck.xml')\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n            }\n        }\n        stage ('check') {\n            parallel {\n                stage ('cppcheck') {\n                    when { expression { return ( params.DO_CPPCHECK ) } }\n                    steps {\n                        dir(\"tmp/test-cppcheck\") {\n                            deleteDir()\n                            unstash 'prepped'\n                            sh 'cppcheck --std=c++11 --enable=all --inconclusive --xml --xml-version=2 . 2>cppcheck.xml'\n                            archiveArtifacts artifacts: '**/cppcheck.xml'\n                            sh 'rm -f cppcheck.xml'\n                            script {\n                                if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                    deleteDir()\n                                }\n                            }\n                        }\n                    }\n                }\n                stage ('check with DRAFT') {\n                    when { expression { return ( params.DO_BUILD_WITH_DRAFT_API && params.DO_TEST_CHECK ) } }\n                    steps {\n                      dir(\"tmp/test-check-withDRAFT\") {\n                        deleteDir()\n                        unstash 'built-draft'\n                        script {\n                         def RETRY_NUMBER = 0\n                         retry(3) {\n                          RETRY_NUMBER++\n                          timeout (time: \"${params.USE_TEST_TIMEOUT}\".toInteger(), unit: 'MINUTES') {\n                           try {\n                            sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; LD_LIBRARY_PATH=\"`pwd`/src/.libs:$LD_LIBRARY_PATH\"; export LD_LIBRARY_PATH; make LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\" check'\n                           }\n                           catch (Exception e) {\n                            currentBuild.result = 'UNSTABLE' // Jenkins should not let the verdict \"improve\"\n                            sh \"\"\"D=\"`pwd`\"; B=\"`basename \"\\$D\"`\" ; [ \"${RETRY_NUMBER}\" -gt 0 ] && T=\"_try-${RETRY_NUMBER}\" || T=\"\" ; tar czf \"test-suite_${BUILD_TAG}_\\${B}\\${T}.tar.gz\" `find . -name '*.trs'` `find . -name '*.log'`\"\"\"\n                            archiveArtifacts artifacts: \"**/test-suite*.tar.gz\", allowEmpty: true\n                            throw e\n                           }\n                          }\n                         }\n                        }\n                        sh 'echo \"Are GitIgnores good after make check with drafts? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n                stage ('check without DRAFT') {\n                    when { expression { return ( params.DO_BUILD_WITHOUT_DRAFT_API && params.DO_TEST_CHECK ) } }\n                    steps {\n                      dir(\"tmp/test-check-withoutDRAFT\") {\n                        deleteDir()\n                        unstash 'built-nondraft'\n                        script {\n                         def RETRY_NUMBER = 0\n                         retry(3) {\n                          RETRY_NUMBER++\n                          timeout (time: \"${params.USE_TEST_TIMEOUT}\".toInteger(), unit: 'MINUTES') {\n                           try {\n                            sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; LD_LIBRARY_PATH=\"`pwd`/src/.libs:$LD_LIBRARY_PATH\"; export LD_LIBRARY_PATH; make LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\" check'\n                           }\n                           catch (Exception e) {\n                            currentBuild.result = 'UNSTABLE' // Jenkins should not let the verdict \"improve\"\n                            sh \"\"\"D=\"`pwd`\"; B=\"`basename \"\\$D\"`\" ; [ \"${RETRY_NUMBER}\" -gt 0 ] && T=\"_try-${RETRY_NUMBER}\" || T=\"\" ; tar czf \"test-suite_${BUILD_TAG}_\\${B}\\${T}.tar.gz\" `find . -name '*.trs'` `find . -name '*.log'`\"\"\"\n                            archiveArtifacts artifacts: \"**/test-suite*.tar.gz\", allowEmpty: true\n                            throw e\n                           }\n                          }\n                         }\n                        }\n                        sh 'echo \"Are GitIgnores good after make check without drafts? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n                stage ('memcheck with DRAFT') {\n                    when { expression { return ( params.DO_BUILD_WITH_DRAFT_API && params.DO_TEST_MEMCHECK ) } }\n                    steps {\n                      dir(\"tmp/test-memcheck-withDRAFT\") {\n                        deleteDir()\n                        unstash 'built-draft'\n                        script {\n                         def RETRY_NUMBER = 0\n                         retry(3) {\n                          RETRY_NUMBER++\n                          timeout (time: \"${params.USE_TEST_TIMEOUT}\".toInteger(), unit: 'MINUTES') {\n                           try {\n                            sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; LD_LIBRARY_PATH=\"`pwd`/src/.libs:$LD_LIBRARY_PATH\"; export LD_LIBRARY_PATH; make LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\" memcheck && exit 0 ; echo \"Re-running failed ($?) memcheck with greater verbosity\" >&2 ; make LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\" VERBOSE=1 memcheck-verbose'\n                           }\n                           catch (Exception e) {\n                            currentBuild.result = 'UNSTABLE' // Jenkins should not let the verdict \"improve\"\n                            sh \"\"\"D=\"`pwd`\"; B=\"`basename \"\\$D\"`\" ; [ \"${RETRY_NUMBER}\" -gt 0 ] && T=\"_try-${RETRY_NUMBER}\" || T=\"\" ; tar czf \"test-suite_${BUILD_TAG}_\\${B}\\${T}.tar.gz\" `find . -name '*.trs'` `find . -name '*.log'`\"\"\"\n                            archiveArtifacts artifacts: \"**/test-suite*.tar.gz\", allowEmpty: true\n                            throw e\n                           }\n                          }\n                         }\n                        }\n                        sh 'echo \"Are GitIgnores good after make memcheck with drafts? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n                stage ('memcheck without DRAFT') {\n                    when { expression { return ( params.DO_BUILD_WITHOUT_DRAFT_API && params.DO_TEST_MEMCHECK ) } }\n                    steps {\n                      dir(\"tmp/test-memcheck-withoutDRAFT\") {\n                        deleteDir()\n                        unstash 'built-nondraft'\n                        script {\n                         def RETRY_NUMBER = 0\n                         retry(3) {\n                          RETRY_NUMBER++\n                          timeout (time: \"${params.USE_TEST_TIMEOUT}\".toInteger(), unit: 'MINUTES') {\n                           try {\n                            sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; LD_LIBRARY_PATH=\"`pwd`/src/.libs:$LD_LIBRARY_PATH\"; export LD_LIBRARY_PATH; make LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\" memcheck && exit 0 ; echo \"Re-running failed ($?) memcheck with greater verbosity\" >&2 ; make LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\" VERBOSE=1 memcheck-verbose'\n                           }\n                           catch (Exception e) {\n                            currentBuild.result = 'UNSTABLE' // Jenkins should not let the verdict \"improve\"\n                            sh \"\"\"D=\"`pwd`\"; B=\"`basename \"\\$D\"`\" ; [ \"${RETRY_NUMBER}\" -gt 0 ] && T=\"_try-${RETRY_NUMBER}\" || T=\"\" ; tar czf \"test-suite_${BUILD_TAG}_\\${B}\\${T}.tar.gz\" `find . -name '*.trs'` `find . -name '*.log'`\"\"\"\n                            archiveArtifacts artifacts: \"**/test-suite*.tar.gz\", allowEmpty: true\n                            throw e\n                           }\n                          }\n                         }\n                        }\n                        sh 'echo \"Are GitIgnores good after make memcheck without drafts? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n                stage ('distcheck with DRAFT') {\n                    when { expression { return ( params.DO_BUILD_WITH_DRAFT_API && params.DO_TEST_DISTCHECK ) } }\n                    steps {\n                      dir(\"tmp/test-distcheck-withDRAFT\") {\n                        deleteDir()\n                        unstash 'built-draft'\n                        script {\n                         def RETRY_NUMBER = 0\n                         retry(3) {\n                          RETRY_NUMBER++\n                          timeout (time: \"${params.USE_TEST_TIMEOUT}\".toInteger(), unit: 'MINUTES') {\n                           try {\n                            sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; LD_LIBRARY_PATH=\"`pwd`/src/.libs:$LD_LIBRARY_PATH\"; export LD_LIBRARY_PATH; DISTCHECK_CONFIGURE_FLAGS=\"--enable-drafts=yes --with-docs=no\" ; export DISTCHECK_CONFIGURE_FLAGS; make DISTCHECK_CONFIGURE_FLAGS=\"$DISTCHECK_CONFIGURE_FLAGS\" LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\" distcheck'\n                           }\n                           catch (Exception e) {\n                            currentBuild.result = 'UNSTABLE' // Jenkins should not let the verdict \"improve\"\n                            sh \"\"\"D=\"`pwd`\"; B=\"`basename \"\\$D\"`\" ; [ \"${RETRY_NUMBER}\" -gt 0 ] && T=\"_try-${RETRY_NUMBER}\" || T=\"\" ; tar czf \"test-suite_${BUILD_TAG}_\\${B}\\${T}.tar.gz\" `find . -name '*.trs'` `find . -name '*.log'`\"\"\"\n                            archiveArtifacts artifacts: \"**/test-suite*.tar.gz\", allowEmpty: true\n                            throw e\n                           }\n                          }\n                         }\n                        }\n                        sh 'echo \"Are GitIgnores good after make distcheck with drafts? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n                stage ('distcheck without DRAFT') {\n                    when { expression { return ( params.DO_BUILD_WITHOUT_DRAFT_API && params.DO_TEST_DISTCHECK ) } }\n                    steps {\n                      dir(\"tmp/test-distcheck-withoutDRAFT\") {\n                        deleteDir()\n                        unstash 'built-nondraft'\n                        script {\n                         def RETRY_NUMBER = 0\n                         retry(3) {\n                          RETRY_NUMBER++\n                          timeout (time: \"${params.USE_TEST_TIMEOUT}\".toInteger(), unit: 'MINUTES') {\n                           try {\n                            sh 'CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; LD_LIBRARY_PATH=\"`pwd`/src/.libs:$LD_LIBRARY_PATH\"; export LD_LIBRARY_PATH; DISTCHECK_CONFIGURE_FLAGS=\"--enable-drafts=no --with-docs=no\" ; export DISTCHECK_CONFIGURE_FLAGS; make DISTCHECK_CONFIGURE_FLAGS=\"$DISTCHECK_CONFIGURE_FLAGS\" LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\" distcheck'\n                           }\n                           catch (Exception e) {\n                            currentBuild.result = 'UNSTABLE' // Jenkins should not let the verdict \"improve\"\n                            sh \"\"\"D=\"`pwd`\"; B=\"`basename \"\\$D\"`\" ; [ \"${RETRY_NUMBER}\" -gt 0 ] && T=\"_try-${RETRY_NUMBER}\" || T=\"\" ; tar czf \"test-suite_${BUILD_TAG}_\\${B}\\${T}.tar.gz\" `find . -name '*.trs'` `find . -name '*.log'`\"\"\"\n                            archiveArtifacts artifacts: \"**/test-suite*.tar.gz\", allowEmpty: true\n                            throw e\n                           }\n                          }\n                         }\n                        }\n                        sh 'echo \"Are GitIgnores good after make distcheck without drafts? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n                stage ('install with DRAFT') {\n                    when { expression { return ( params.DO_BUILD_WITH_DRAFT_API && params.DO_TEST_INSTALL ) } }\n                    steps {\n                      dir(\"tmp/test-install-withDRAFT\") {\n                        deleteDir()\n                        unstash 'built-draft'\n                        retry(3) {\n                        timeout (time: \"${params.USE_TEST_TIMEOUT}\".toInteger(), unit: 'MINUTES') {\n                            sh \"\"\"CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; LD_LIBRARY_PATH=\"`pwd`/src/.libs:\\${LD_LIBRARY_PATH}\"; export LD_LIBRARY_PATH; make LD_LIBRARY_PATH=\"\\${LD_LIBRARY_PATH}\" DESTDIR=\"${params.USE_TEST_INSTALL_DESTDIR}/withDRAFT\" install\"\"\"\n                        }\n                        }\n                        sh \"\"\"cd \"${params.USE_TEST_INSTALL_DESTDIR}/withDRAFT\" && find . -ls\"\"\"\n                        sh 'echo \"Are GitIgnores good after make install with drafts? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n                stage ('install without DRAFT') {\n                    when { expression { return ( params.DO_BUILD_WITHOUT_DRAFT_API && params.DO_TEST_INSTALL ) } }\n                    steps {\n                      dir(\"tmp/test-install-withoutDRAFT\") {\n                        deleteDir()\n                        unstash 'built-nondraft'\n                        retry(3) {\n                        timeout (time: \"${params.USE_TEST_TIMEOUT}\".toInteger(), unit: 'MINUTES') {\n                            sh \"\"\"CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; LD_LIBRARY_PATH=\"`pwd`/src/.libs:\\${LD_LIBRARY_PATH}\"; export LD_LIBRARY_PATH; make LD_LIBRARY_PATH=\"\\${LD_LIBRARY_PATH}\" DESTDIR=\"${params.USE_TEST_INSTALL_DESTDIR}/withoutDRAFT\" install\"\"\"\n                        }\n                        }\n                        sh \"\"\"cd \"${params.USE_TEST_INSTALL_DESTDIR}/withoutDRAFT\" && find . -ls\"\"\"\n                        sh 'echo \"Are GitIgnores good after make install without drafts? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n                stage ('install with DOCS') {\n                    when { expression { return ( params.DO_BUILD_DOCS && params.DO_TEST_INSTALL ) } }\n                    steps {\n                      dir(\"tmp/test-install-withDOCS\") {\n                        deleteDir()\n                        unstash 'built-docs'\n                        retry(3) {\n                        timeout (time: \"${params.USE_TEST_TIMEOUT}\".toInteger(), unit: 'MINUTES') {\n                            sh \"\"\"CCACHE_BASEDIR=\"`pwd`\" ; export CCACHE_BASEDIR; LD_LIBRARY_PATH=\"`pwd`/src/.libs:\\${LD_LIBRARY_PATH}\"; export LD_LIBRARY_PATH; make LD_LIBRARY_PATH=\"\\${LD_LIBRARY_PATH}\" DESTDIR=\"${params.USE_TEST_INSTALL_DESTDIR}/withDOCS\" install\"\"\"\n                        }\n                        }\n                        sh \"\"\"cd \"${params.USE_TEST_INSTALL_DESTDIR}/withDOCS\" && find . -ls\"\"\"\n                        sh 'echo \"Are GitIgnores good after make install with Docs? (should have no output below)\"; git status -s || if [ \"${params.REQUIRE_GOOD_GITIGNORE}\" = false ]; then echo \"WARNING GitIgnore tests found newly changed or untracked files\" >&2 ; exit 0 ; else echo \"FAILED GitIgnore tests\" >&2 ; exit 1; fi'\n                        script {\n                            if ( params.DO_CLEANUP_AFTER_BUILD ) {\n                                deleteDir()\n                            }\n                        }\n                      }\n                    }\n                }\n            }\n        }\n        stage ('deploy if appropriate') {\n            steps {\n                script {\n                    def myDEPLOY_JOB_NAME = sh(returnStdout: true, script: \"\"\"echo \"${params[\"DEPLOY_JOB_NAME\"]}\" \"\"\").trim();\n                    def myDEPLOY_BRANCH_PATTERN = sh(returnStdout: true, script: \"\"\"echo \"${params[\"DEPLOY_BRANCH_PATTERN\"]}\" \"\"\").trim();\n                    def myDEPLOY_REPORT_RESULT = sh(returnStdout: true, script: \"\"\"echo \"${params[\"DEPLOY_REPORT_RESULT\"]}\" \"\"\").trim().toBoolean();\n                    echo \"Original: DEPLOY_JOB_NAME : ${params[\"DEPLOY_JOB_NAME\"]} DEPLOY_BRANCH_PATTERN : ${params[\"DEPLOY_BRANCH_PATTERN\"]} DEPLOY_REPORT_RESULT : ${params[\"DEPLOY_REPORT_RESULT\"]}\"\n                    echo \"Used:     myDEPLOY_JOB_NAME:${myDEPLOY_JOB_NAME} myDEPLOY_BRANCH_PATTERN:${myDEPLOY_BRANCH_PATTERN} myDEPLOY_REPORT_RESULT:${myDEPLOY_REPORT_RESULT}\"\n                    if ( (myDEPLOY_JOB_NAME != \"\") && (myDEPLOY_BRANCH_PATTERN != \"\") ) {\n                        if ( env.BRANCH_NAME =~ myDEPLOY_BRANCH_PATTERN ) {\n                            def GIT_URL = sh(returnStdout: true, script: \"\"\"git remote -v | grep -E '^origin' | awk '{print \\$2}' | head -1\"\"\").trim()\n                            def GIT_COMMIT = sh(returnStdout: true, script: 'git rev-parse --verify HEAD').trim()\n                            def DIST_ARCHIVE = \"\"\n                            if ( params.DO_DIST_DOCS ) { DIST_ARCHIVE = env.BUILD_URL + \"artifact/__dist.tar.gz\" }\n                            build job: \"${myDEPLOY_JOB_NAME}\", parameters: [\n                                string(name: 'DEPLOY_GIT_URL', value: \"${GIT_URL}\"),\n                                string(name: 'DEPLOY_GIT_BRANCH', value: env.BRANCH_NAME),\n                                string(name: 'DEPLOY_GIT_COMMIT', value: \"${GIT_COMMIT}\"),\n                                string(name: 'DEPLOY_DIST_ARCHIVE', value: \"${DIST_ARCHIVE}\")\n                                ], quietPeriod: 0, wait: myDEPLOY_REPORT_RESULT, propagate: myDEPLOY_REPORT_RESULT\n                        } else {\n                            echo \"Not deploying because branch '${env.BRANCH_NAME}' did not match filter '${myDEPLOY_BRANCH_PATTERN}'\"\n                        }\n                    } else {\n                        echo \"Not deploying because deploy-job parameters are not set\"\n                    }\n                }\n            }\n        }\n    }\n    post {\n        success {\n            script {\n                if (currentBuild.getPreviousBuild()?.result != 'SUCCESS') {\n                    // Uncomment desired notification\n\n                    //slackSend (color: \"#008800\", message: \"Build ${env.JOB_NAME} is back to normal.\")\n                    //emailext (to: \"qa@example.com\", subject: \"Build ${env.JOB_NAME} is back to normal.\", body: \"Build ${env.JOB_NAME} is back to normal.\")\n                }\n            }\n        }\n        failure {\n            // Uncomment desired notification\n            // Section must not be empty, you can delete the sleep once you set notification\n            sleep 1\n            //slackSend (color: \"#AA0000\", message: \"Build ${env.BUILD_NUMBER} of ${env.JOB_NAME} ${currentBuild.result} (<${env.BUILD_URL}|Open>)\")\n            //emailext (to: \"qa@example.com\", subject: \"Build ${env.JOB_NAME} failed!\", body: \"Build ${env.BUILD_NUMBER} of ${env.JOB_NAME} ${currentBuild.result}\\nSee ${env.BUILD_URL}\")\n        }\n    }\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n    means each individual or legal entity that creates, contributes to\n    the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n    means the combination of the Contributions of others (if any) used\n    by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n    means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n    means Source Code Form to which the initial Contributor has attached\n    the notice in Exhibit A, the Executable Form of such Source Code\n    Form, and Modifications of such Source Code Form, in each case\n    including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n    means\n\n    (a) that the initial Contributor has attached the notice described\n        in Exhibit B to the Covered Software; or\n\n    (b) that the Covered Software was made available under the terms of\n        version 1.1 or earlier of the License, but not also under the\n        terms of a Secondary License.\n\n1.6. \"Executable Form\"\n    means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n    means a work that combines Covered Software with other material, in\n    a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n    means this document.\n\n1.9. \"Licensable\"\n    means having the right to grant, to the maximum extent possible,\n    whether at the time of the initial grant or subsequently, any and\n    all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n    means any of the following:\n\n    (a) any file in Source Code Form that results from an addition to,\n        deletion from, or modification of the contents of Covered\n        Software; or\n\n    (b) any new file in Source Code Form that contains any Covered\n        Software.\n\n1.11. \"Patent Claims\" of a Contributor\n    means any patent claim(s), including without limitation, method,\n    process, and apparatus claims, in any patent Licensable by such\n    Contributor that would be infringed, but for the grant of the\n    License, by the making, using, selling, offering for sale, having\n    made, import, or transfer of either its Contributions or its\n    Contributor Version.\n\n1.12. \"Secondary License\"\n    means either the GNU General Public License, Version 2.0, the GNU\n    Lesser General Public License, Version 2.1, the GNU Affero General\n    Public License, Version 3.0, or any later versions of those\n    licenses.\n\n1.13. \"Source Code Form\"\n    means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n    means an individual or a legal entity exercising rights under this\n    License. For legal entities, \"You\" includes any entity that\n    controls, is controlled by, or is under common control with You. For\n    purposes of this definition, \"control\" means (a) the power, direct\n    or indirect, to cause the direction or management of such entity,\n    whether by contract or otherwise, or (b) ownership of more than\n    fifty percent (50%) of the outstanding shares or beneficial\n    ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n    Licensable by such Contributor to use, reproduce, make available,\n    modify, display, perform, distribute, and otherwise exploit its\n    Contributions, either on an unmodified basis, with Modifications, or\n    as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n    for sale, have made, import, and otherwise transfer either its\n    Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n    or\n\n(b) for infringements caused by: (i) Your and any other third party's\n    modifications of Covered Software, or (ii) the combination of its\n    Contributions with other software (except as part of its Contributor\n    Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n    its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n    Form, as described in Section 3.1, and You must inform recipients of\n    the Executable Form how they can obtain a copy of such Source Code\n    Form by reasonable means in a timely manner, at a charge no more\n    than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n    License, or sublicense it under different terms, provided that the\n    license for the Executable Form does not attempt to limit or alter\n    the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n*                                                                      *\n*  6. Disclaimer of Warranty                                           *\n*  -------------------------                                           *\n*                                                                      *\n*  Covered Software is provided under this License on an \"as is\"       *\n*  basis, without warranty of any kind, either expressed, implied, or  *\n*  statutory, including, without limitation, warranties that the       *\n*  Covered Software is free of defects, merchantable, fit for a        *\n*  particular purpose or non-infringing. The entire risk as to the     *\n*  quality and performance of the Covered Software is with You.        *\n*  Should any Covered Software prove defective in any respect, You     *\n*  (not any Contributor) assume the cost of any necessary servicing,   *\n*  repair, or correction. This disclaimer of warranty constitutes an   *\n*  essential part of this License. No use of any Covered Software is   *\n*  authorized under this License except under this disclaimer.         *\n*                                                                      *\n************************************************************************\n\n************************************************************************\n*                                                                      *\n*  7. Limitation of Liability                                          *\n*  --------------------------                                          *\n*                                                                      *\n*  Under no circumstances and under no legal theory, whether tort      *\n*  (including negligence), contract, or otherwise, shall any           *\n*  Contributor, or anyone who distributes Covered Software as          *\n*  permitted above, be liable to You for any direct, indirect,         *\n*  special, incidental, or consequential damages of any character      *\n*  including, without limitation, damages for lost profits, loss of    *\n*  goodwill, work stoppage, computer failure or malfunction, or any    *\n*  and all other commercial damages or losses, even if such party      *\n*  shall have been informed of the possibility of such damages. This   *\n*  limitation of liability shall not apply to liability for death or   *\n*  personal injury resulting from such party's negligence to the       *\n*  extent applicable law prohibits such limitation. Some               *\n*  jurisdictions do not allow the exclusion or limitation of           *\n*  incidental or consequential damages, so this exclusion and          *\n*  limitation may not apply to You.                                    *\n*                                                                      *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n  This Source Code Form is \"Incompatible With Secondary Licenses\", as\n  defined by the Mozilla Public License, v. 2.0.\n"
  },
  {
    "path": "Makefile.am",
    "content": "ACLOCAL_AMFLAGS = -I config\n\nSUBDIRS = doc\n\nDIST_SUBDIRS = doc builds builds/deprecated-msvc\n\npkgconfig_DATA = src/libzmq.pc\n\nAM_CPPFLAGS = \\\n\t-I$(top_builddir)/include \\\n\t-I$(top_srcdir)/include\n\n#\n# libraries/binaries\n#\nlib_LTLIBRARIES = src/libzmq.la\n\ninclude_HEADERS = \\\n\tinclude/zmq.h \\\n\tinclude/zmq_utils.h\n\nsrc_libzmq_la_SOURCES = \\\n\tsrc/address.cpp \\\n\tsrc/address.hpp \\\n\tsrc/array.hpp \\\n\tsrc/atomic_counter.hpp \\\n\tsrc/atomic_ptr.hpp \\\n\tsrc/blob.hpp \\\n\tsrc/channel.cpp \\\n\tsrc/channel.hpp \\\n\tsrc/client.cpp \\\n\tsrc/client.hpp \\\n\tsrc/clock.cpp \\\n\tsrc/clock.hpp \\\n\tsrc/command.hpp \\\n\tsrc/compat.hpp \\\n\tsrc/condition_variable.hpp \\\n\tsrc/config.hpp \\\n\tsrc/ctx.cpp \\\n\tsrc/ctx.hpp \\\n\tsrc/curve_client.cpp \\\n\tsrc/curve_client.hpp \\\n\tsrc/curve_client_tools.hpp \\\n\tsrc/curve_mechanism_base.cpp \\\n\tsrc/curve_mechanism_base.hpp \\\n\tsrc/curve_server.cpp \\\n\tsrc/curve_server.hpp \\\n\tsrc/dbuffer.hpp \\\n\tsrc/dealer.cpp \\\n\tsrc/dealer.hpp \\\n\tsrc/decoder.hpp \\\n\tsrc/devpoll.cpp \\\n\tsrc/devpoll.hpp \\\n\tsrc/dgram.cpp \\\n\tsrc/dgram.hpp \\\n\tsrc/dish.cpp \\\n\tsrc/dish.hpp \\\n\tsrc/dist.cpp \\\n\tsrc/dist.hpp \\\n\tsrc/encoder.hpp \\\n\tsrc/endpoint.hpp \\\n\tsrc/endpoint.cpp \\\n\tsrc/epoll.cpp \\\n\tsrc/epoll.hpp \\\n\tsrc/err.cpp \\\n\tsrc/err.hpp \\\n\tsrc/fd.hpp \\\n\tsrc/fq.cpp \\\n\tsrc/fq.hpp \\\n\tsrc/gather.cpp \\\n\tsrc/gather.hpp \\\n\tsrc/generic_mtrie.hpp \\\n\tsrc/generic_mtrie_impl.hpp \\\n\tsrc/gssapi_mechanism_base.cpp \\\n\tsrc/gssapi_mechanism_base.hpp \\\n\tsrc/gssapi_client.cpp \\\n\tsrc/gssapi_client.hpp \\\n\tsrc/gssapi_server.cpp \\\n\tsrc/gssapi_server.hpp \\\n\tsrc/i_encoder.hpp \\\n\tsrc/i_engine.hpp \\\n\tsrc/i_decoder.hpp \\\n\tsrc/i_mailbox.hpp \\\n\tsrc/i_poll_events.hpp \\\n\tsrc/io_object.cpp \\\n\tsrc/io_object.hpp \\\n\tsrc/io_thread.cpp \\\n\tsrc/io_thread.hpp \\\n\tsrc/ip.cpp \\\n\tsrc/ip.hpp \\\n\tsrc/ip_resolver.cpp \\\n\tsrc/ip_resolver.hpp \\\n\tsrc/ipc_address.cpp \\\n\tsrc/ipc_address.hpp \\\n\tsrc/ipc_connecter.cpp \\\n\tsrc/ipc_connecter.hpp \\\n\tsrc/ipc_listener.cpp \\\n\tsrc/ipc_listener.hpp \\\n\tsrc/kqueue.cpp \\\n\tsrc/kqueue.hpp \\\n\tsrc/lb.cpp \\\n\tsrc/lb.hpp \\\n\tsrc/likely.hpp \\\n\tsrc/macros.hpp \\\n\tsrc/mailbox.cpp \\\n\tsrc/mailbox.hpp \\\n\tsrc/mailbox_safe.cpp \\\n\tsrc/mailbox_safe.hpp \\\n\tsrc/mechanism.cpp \\\n\tsrc/mechanism.hpp  \\\n\tsrc/mechanism_base.cpp \\\n\tsrc/mechanism_base.hpp  \\\n\tsrc/metadata.cpp \\\n\tsrc/metadata.hpp \\\n\tsrc/msg.cpp \\\n\tsrc/msg.hpp \\\n\tsrc/mtrie.cpp \\\n\tsrc/mtrie.hpp \\\n\tsrc/mutex.hpp \\\n\tsrc/norm_engine.cpp \\\n\tsrc/norm_engine.hpp \\\n\tsrc/null_mechanism.cpp \\\n\tsrc/null_mechanism.hpp \\\n\tsrc/object.cpp \\\n\tsrc/object.hpp \\\n\tsrc/options.cpp \\\n\tsrc/options.hpp \\\n\tsrc/own.cpp \\\n\tsrc/own.hpp \\\n\tsrc/pair.cpp \\\n\tsrc/pair.hpp \\\n\tsrc/peer.cpp \\\n\tsrc/peer.hpp \\\n\tsrc/pgm_receiver.cpp \\\n\tsrc/pgm_receiver.hpp \\\n\tsrc/pgm_sender.cpp \\\n\tsrc/pgm_sender.hpp \\\n\tsrc/pgm_socket.cpp \\\n\tsrc/pgm_socket.hpp \\\n\tsrc/pipe.cpp \\\n\tsrc/pipe.hpp \\\n\tsrc/plain_client.cpp \\\n\tsrc/plain_client.hpp \\\n\tsrc/plain_common.hpp \\\n\tsrc/plain_server.cpp \\\n\tsrc/plain_server.hpp \\\n\tsrc/platform.hpp \\\n\tsrc/poll.cpp \\\n\tsrc/poll.hpp \\\n\tsrc/poller.hpp \\\n\tsrc/poller_base.cpp \\\n\tsrc/poller_base.hpp \\\n\tsrc/polling_util.cpp \\\n\tsrc/polling_util.hpp \\\n\tsrc/pollset.cpp \\\n\tsrc/pollset.hpp \\\n\tsrc/precompiled.cpp \\\n\tsrc/precompiled.hpp \\\n\tsrc/proxy.cpp \\\n\tsrc/proxy.hpp \\\n\tsrc/pub.cpp \\\n\tsrc/pub.hpp \\\n\tsrc/pull.cpp \\\n\tsrc/pull.hpp \\\n\tsrc/push.cpp \\\n\tsrc/push.hpp \\\n\tsrc/radio.cpp \\\n\tsrc/radio.hpp \\\n\tsrc/radix_tree.cpp \\\n\tsrc/radix_tree.hpp \\\n\tsrc/random.cpp \\\n\tsrc/random.hpp \\\n\tsrc/raw_decoder.cpp \\\n\tsrc/raw_decoder.hpp \\\n\tsrc/raw_encoder.cpp \\\n\tsrc/raw_encoder.hpp \\\n\tsrc/raw_engine.cpp \\\n\tsrc/raw_engine.hpp \\\n\tsrc/reaper.cpp \\\n\tsrc/reaper.hpp \\\n\tsrc/rep.cpp \\\n\tsrc/rep.hpp \\\n\tsrc/req.cpp \\\n\tsrc/req.hpp \\\n\tsrc/router.cpp \\\n\tsrc/router.hpp \\\n\tsrc/scatter.cpp \\\n\tsrc/scatter.hpp \\\n\tsrc/secure_allocator.hpp \\\n\tsrc/select.cpp \\\n\tsrc/select.hpp \\\n\tsrc/server.cpp \\\n\tsrc/server.hpp \\\n\tsrc/session_base.cpp \\\n\tsrc/session_base.hpp \\\n\tsrc/signaler.cpp \\\n\tsrc/signaler.hpp \\\n\tsrc/socket_base.cpp \\\n\tsrc/socket_base.hpp \\\n\tsrc/socks.cpp \\\n\tsrc/socks.hpp \\\n\tsrc/socks_connecter.cpp \\\n\tsrc/socks_connecter.hpp \\\n\tsrc/stdint.hpp \\\n\tsrc/stream.cpp \\\n\tsrc/stream.hpp \\\n\tsrc/stream_connecter_base.cpp \\\n\tsrc/stream_connecter_base.hpp \\\n\tsrc/stream_listener_base.cpp \\\n\tsrc/stream_listener_base.hpp \\\n\tsrc/stream_engine_base.cpp \\\n\tsrc/stream_engine_base.hpp \\\n\tsrc/sub.cpp \\\n\tsrc/sub.hpp \\\n\tsrc/tcp.cpp \\\n\tsrc/tcp.hpp \\\n\tsrc/tcp_address.cpp \\\n\tsrc/tcp_address.hpp \\\n\tsrc/tcp_connecter.cpp \\\n\tsrc/tcp_connecter.hpp \\\n\tsrc/tcp_listener.cpp \\\n\tsrc/tcp_listener.hpp \\\n\tsrc/thread.cpp \\\n\tsrc/thread.hpp \\\n\tsrc/timers.cpp \\\n\tsrc/timers.hpp \\\n\tsrc/tipc_address.cpp \\\n\tsrc/tipc_address.hpp \\\n\tsrc/tipc_connecter.cpp \\\n\tsrc/tipc_connecter.hpp \\\n\tsrc/tipc_listener.cpp \\\n\tsrc/tipc_listener.hpp \\\n\tsrc/trie.cpp \\\n\tsrc/trie.hpp \\\n\tsrc/udp_address.cpp \\\n\tsrc/udp_address.hpp \\\n\tsrc/udp_engine.cpp \\\n\tsrc/udp_engine.hpp \\\n\tsrc/v1_decoder.cpp \\\n\tsrc/v1_decoder.hpp \\\n\tsrc/v2_decoder.cpp \\\n\tsrc/v2_decoder.hpp \\\n\tsrc/v1_encoder.cpp \\\n\tsrc/v1_encoder.hpp \\\n\tsrc/v2_encoder.cpp \\\n\tsrc/v2_encoder.hpp \\\n\tsrc/v3_1_encoder.cpp \\\n\tsrc/v3_1_encoder.hpp \\\n\tsrc/v2_protocol.hpp \\\n\tsrc/vmci.cpp \\\n\tsrc/vmci.hpp \\\n\tsrc/vmci_address.cpp \\\n\tsrc/vmci_address.hpp \\\n\tsrc/vmci_connecter.cpp \\\n\tsrc/vmci_connecter.hpp \\\n\tsrc/vmci_listener.cpp \\\n\tsrc/vmci_listener.hpp \\\n\tsrc/vsock_address.cpp \\\n\tsrc/vsock_address.hpp \\\n\tsrc/vsock_connecter.cpp \\\n\tsrc/vsock_connecter.hpp \\\n\tsrc/vsock_listener.cpp \\\n\tsrc/vsock_listener.hpp \\\n\tsrc/windows.hpp \\\n\tsrc/wire.hpp \\\n\tsrc/xpub.cpp \\\n\tsrc/xpub.hpp \\\n\tsrc/xsub.cpp \\\n\tsrc/xsub.hpp \\\n\tsrc/ypipe.hpp \\\n\tsrc/ypipe_base.hpp \\\n\tsrc/ypipe_conflate.hpp \\\n\tsrc/yqueue.hpp \\\n\tsrc/zmq.cpp \\\n\tsrc/zmq_utils.cpp \\\n\tsrc/decoder_allocators.cpp \\\n\tsrc/decoder_allocators.hpp \\\n\tsrc/socket_poller.cpp \\\n\tsrc/socket_poller.hpp \\\n\tsrc/zap_client.cpp \\\n\tsrc/zap_client.hpp \\\n\tsrc/zmtp_engine.cpp \\\n\tsrc/zmtp_engine.hpp \\\n\tsrc/zmq_draft.h\n\nif USE_WEPOLL\nsrc_libzmq_la_SOURCES += \\\n\texternal/wepoll/wepoll.c \\\n\texternal/wepoll/wepoll.h\nendif\n\nif HAVE_WS\nsrc_libzmq_la_SOURCES += \\\n\tsrc/ws_address.cpp \\\n\tsrc/ws_address.hpp \\\n\tsrc/wss_address.cpp \\\n\tsrc/wss_address.hpp \\\n\tsrc/ws_connecter.cpp \\\n\tsrc/ws_connecter.hpp \\\n\tsrc/ws_decoder.cpp \\\n\tsrc/ws_decoder.hpp \\\n\tsrc/ws_encoder.cpp \\\n\tsrc/ws_encoder.hpp \\\n\tsrc/ws_engine.cpp \\\n\tsrc/ws_engine.hpp \\\n\tsrc/ws_listener.cpp \\\n\tsrc/ws_listener.hpp \\\n\tsrc/ws_protocol.hpp\nendif\n\nif USE_BUILTIN_SHA1\nsrc_libzmq_la_SOURCES += \\\n\texternal/sha1/sha1.c \\\n\texternal/sha1/sha1.h\nendif\n\nif HAVE_WSS\nsrc_libzmq_la_SOURCES += \\\n\tsrc/wss_engine.cpp \\\n\tsrc/wss_engine.hpp\nendif\n\nif ON_MINGW\nsrc_libzmq_la_LDFLAGS = \\\n\t-no-undefined \\\n\t-avoid-version \\\n\t-version-info @LTVER@ \\\n\t@LIBZMQ_EXTRA_LDFLAGS@\nelse\nif ON_CYGWIN\nsrc_libzmq_la_LDFLAGS = \\\n\t-no-undefined \\\n\t-avoid-version \\\n\t-version-info @LTVER@ \\\n\t@LIBZMQ_EXTRA_LDFLAGS@\nelse\nif ON_ANDROID\nsrc_libzmq_la_LDFLAGS = \\\n\t-avoid-version \\\n\t-version-info @LTVER@ \\\n\t@LIBZMQ_EXTRA_LDFLAGS@\nelse\nsrc_libzmq_la_LDFLAGS = \\\n\t-version-info @LTVER@ \\\n\t@LIBZMQ_EXTRA_LDFLAGS@\nendif\nendif\nendif\n\nif HAVE_VSCRIPT_COMPLEX\nsrc_libzmq_la_LDFLAGS += $(VSCRIPT_LDFLAGS),$(srcdir)/src/libzmq.vers\nendif\n\nsrc_libzmq_la_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS) $(LIBUNWIND_CFLAGS) $(LIBBSD_CFLAGS)\nsrc_libzmq_la_CFLAGS = $(CODE_COVERAGE_CFLAGS) $(LIBUNWIND_CFLAGS) $(LIBBSD_CFLAGS)\nsrc_libzmq_la_CXXFLAGS = @LIBZMQ_EXTRA_CXXFLAGS@ $(CODE_COVERAGE_CXXFLAGS) \\\n\t$(LIBUNWIND_CFLAGS) $(LIBBSD_CFLAGS)\nsrc_libzmq_la_LIBADD = $(CODE_COVERAGE_LDFLAGS) $(LIBUNWIND_LIBS) $(LIBBSD_LIBS)\n\nif USE_NSS\nsrc_libzmq_la_CPPFLAGS += ${NSS3_CFLAGS}\nsrc_libzmq_la_LIBADD += ${NSS3_LIBS}\nendif\n\nif USE_GNUTLS\nsrc_libzmq_la_CPPFLAGS += ${GNUTLS_CFLAGS}\nsrc_libzmq_la_LIBADD += ${GNUTLS_LIBS}\nendif\n\nif USE_LIBSODIUM\nsrc_libzmq_la_CPPFLAGS += ${sodium_CFLAGS}\nsrc_libzmq_la_LIBADD += ${sodium_LIBS}\nendif\n\nif HAVE_PGM\nsrc_libzmq_la_CPPFLAGS += ${pgm_CFLAGS}\nsrc_libzmq_la_LIBADD += ${pgm_LIBS}\nendif\n\nif HAVE_NORM\nsrc_libzmq_la_CPPFLAGS += ${norm_CFLAGS}\nsrc_libzmq_la_LIBADD += ${norm_LIBS}\nendif\n\nif BUILD_GSSAPI\nsrc_libzmq_la_CPPFLAGS += ${gssapi_krb5_CFLAGS}\nsrc_libzmq_la_LIBADD += ${gssapi_krb5_LIBS}\nendif\n\nif ENABLE_PERF\nnoinst_PROGRAMS = \\\n\tperf/local_lat \\\n\tperf/remote_lat \\\n\tperf/local_thr \\\n\tperf/remote_thr \\\n\tperf/inproc_lat \\\n\tperf/inproc_thr \\\n\tperf/proxy_thr\n\nperf_local_lat_LDADD = src/libzmq.la\nperf_local_lat_SOURCES = perf/local_lat.cpp\n\nperf_remote_lat_LDADD = src/libzmq.la\nperf_remote_lat_SOURCES = perf/remote_lat.cpp\n\nperf_local_thr_LDADD = src/libzmq.la\nperf_local_thr_SOURCES = perf/local_thr.cpp\n\nperf_remote_thr_LDADD = src/libzmq.la\nperf_remote_thr_SOURCES = perf/remote_thr.cpp\n\nperf_inproc_lat_LDADD = src/libzmq.la\nperf_inproc_lat_SOURCES = perf/inproc_lat.cpp\n\nperf_inproc_thr_LDADD = src/libzmq.la\nperf_inproc_thr_SOURCES = perf/inproc_thr.cpp\n\nperf_proxy_thr_LDADD = src/libzmq.la\nperf_proxy_thr_SOURCES = perf/proxy_thr.cpp\n\nif ENABLE_STATIC\nnoinst_PROGRAMS += \\\n\tperf/benchmark_radix_tree\n\nperf_benchmark_radix_tree_DEPENDENCIES = src/libzmq.la\nperf_benchmark_radix_tree_CPPFLAGS = -I$(top_srcdir)/src\nperf_benchmark_radix_tree_LDADD = $(top_builddir)/src/.libs/libzmq.a \\\n\t${src_libzmq_la_LIBADD}\nperf_benchmark_radix_tree_SOURCES = perf/benchmark_radix_tree.cpp\nendif\nendif\n\nif ENABLE_CURVE_KEYGEN\nbin_PROGRAMS = tools/curve_keygen\n\ntools_curve_keygen_LDADD = src/libzmq.la\ntools_curve_keygen_SOURCES = tools/curve_keygen.cpp\nendif\n\n#\n# tests\n#\ntest_apps = \\\n\ttests/test_ancillaries \\\n\ttests/test_system \\\n\ttests/test_pair_inproc \\\n\ttests/test_pair_tcp \\\n\ttests/test_reqrep_inproc \\\n\ttests/test_reqrep_tcp \\\n\ttests/test_hwm \\\n\ttests/test_hwm_pubsub \\\n\ttests/test_reqrep_device \\\n\ttests/test_sub_forward \\\n\ttests/test_invalid_rep \\\n\ttests/test_msg_flags \\\n\ttests/test_msg_ffn \\\n\ttests/test_connect_resolve \\\n\ttests/test_immediate \\\n\ttests/test_last_endpoint \\\n\ttests/test_term_endpoint \\\n\ttests/test_srcfd \\\n\ttests/test_monitor \\\n\ttests/test_router_mandatory \\\n\ttests/test_router_mandatory_hwm \\\n\ttests/test_router_handover \\\n\ttests/test_probe_router \\\n\ttests/test_stream \\\n\ttests/test_stream_empty \\\n\ttests/test_stream_disconnect \\\n\ttests/test_stream_timeout \\\n\ttests/test_disconnect_inproc \\\n\ttests/test_unbind_wildcard \\\n\ttests/test_ctx_options \\\n\ttests/test_ctx_destroy \\\n\ttests/test_security_no_zap_handler \\\n\ttests/test_security_null \\\n\ttests/test_security_plain \\\n\ttests/test_security_zap \\\n\ttests/test_iov \\\n\ttests/test_spec_req \\\n\ttests/test_spec_rep \\\n\ttests/test_spec_dealer \\\n\ttests/test_spec_router \\\n\ttests/test_spec_pushpull \\\n\ttests/test_req_correlate \\\n\ttests/test_req_relaxed \\\n\ttests/test_conflate \\\n\ttests/test_inproc_connect \\\n\ttests/test_issue_566 \\\n\ttests/test_proxy_hwm \\\n\ttests/test_proxy_single_socket \\\n\ttests/test_proxy_steerable \\\n\ttests/test_proxy_terminate \\\n\ttests/test_getsockopt_memset \\\n\ttests/test_setsockopt \\\n\ttests/test_diffserv \\\n\ttests/test_connect_rid \\\n\ttests/test_bind_src_address \\\n\ttests/test_metadata \\\n\ttests/test_capabilities \\\n\ttests/test_xpub_nodrop \\\n\ttests/test_xpub_manual \\\n\ttests/test_xpub_topic \\\n\ttests/test_xpub_welcome_msg \\\n\ttests/test_xpub_verbose \\\n\ttests/test_atomics \\\n\ttests/test_sockopt_hwm \\\n\ttests/test_heartbeats \\\n\ttests/test_stream_exceeds_buffer \\\n\ttests/test_pub_invert_matching \\\n\ttests/test_base85 \\\n\ttests/test_bind_after_connect_tcp \\\n\ttests/test_sodium \\\n\ttests/test_reconnect_ivl \\\n\ttests/test_mock_pub_sub \\\n\ttests/test_socket_null \\\n\ttests/test_tcp_accept_filter\n\nUNITY_CPPFLAGS = -I$(top_srcdir)/external/unity -DUNITY_USE_COMMAND_LINE_ARGS -DUNITY_EXCLUDE_FLOAT\nUNITY_LIBS = $(top_builddir)/external/unity/libunity.a\nexternal_unity_libunity_a_SOURCES = external/unity/unity.c \\\n\texternal/unity/unity.h \\\n\texternal/unity/unity_internals.h\n\nTESTUTIL_CPPFLAGS = ${UNITY_CPPFLAGS}\nTESTUTIL_LIBS = $(top_builddir)/tests/libtestutil.a ${UNITY_LIBS}\ntests_libtestutil_a_SOURCES = \\\n        tests/testutil.cpp \\\n        tests/testutil.hpp \\\n        tests/testutil_monitoring.cpp \\\n        tests/testutil_monitoring.hpp \\\n        tests/testutil_security.cpp \\\n        tests/testutil_security.hpp \\\n        tests/testutil_unity.cpp \\\n        tests/testutil_unity.hpp\ntests_libtestutil_a_CPPFLAGS = ${UNITY_CPPFLAGS}\n\nnoinst_LIBRARIES = external/unity/libunity.a tests/libtestutil.a\n\ntests_test_ancillaries_SOURCES = tests/test_ancillaries.cpp\ntests_test_ancillaries_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_ancillaries_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_system_SOURCES = tests/test_system.cpp\ntests_test_system_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_system_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_pair_inproc_SOURCES = tests/test_pair_inproc.cpp\ntests_test_pair_inproc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_pair_inproc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_pair_tcp_SOURCES = tests/test_pair_tcp.cpp\ntests_test_pair_tcp_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_pair_tcp_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_reqrep_inproc_SOURCES = tests/test_reqrep_inproc.cpp\ntests_test_reqrep_inproc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_reqrep_inproc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_reqrep_tcp_SOURCES = tests/test_reqrep_tcp.cpp\ntests_test_reqrep_tcp_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_reqrep_tcp_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_hwm_SOURCES = tests/test_hwm.cpp\ntests_test_hwm_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_hwm_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_hwm_pubsub_SOURCES = tests/test_hwm_pubsub.cpp\ntests_test_hwm_pubsub_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_hwm_pubsub_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_reqrep_device_SOURCES = tests/test_reqrep_device.cpp\ntests_test_reqrep_device_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_reqrep_device_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_sub_forward_SOURCES = tests/test_sub_forward.cpp\ntests_test_sub_forward_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_sub_forward_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_invalid_rep_SOURCES = tests/test_invalid_rep.cpp\ntests_test_invalid_rep_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_invalid_rep_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_msg_flags_SOURCES = tests/test_msg_flags.cpp\ntests_test_msg_flags_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_msg_flags_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_msg_ffn_SOURCES = tests/test_msg_ffn.cpp\ntests_test_msg_ffn_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_msg_ffn_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_connect_resolve_SOURCES = tests/test_connect_resolve.cpp\ntests_test_connect_resolve_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_connect_resolve_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_immediate_SOURCES = tests/test_immediate.cpp\ntests_test_immediate_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_immediate_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_last_endpoint_SOURCES = tests/test_last_endpoint.cpp\ntests_test_last_endpoint_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_last_endpoint_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_term_endpoint_SOURCES = tests/test_term_endpoint.cpp\ntests_test_term_endpoint_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_term_endpoint_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_srcfd_SOURCES = tests/test_srcfd.cpp\ntests_test_srcfd_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_srcfd_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_monitor_SOURCES = tests/test_monitor.cpp\ntests_test_monitor_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_monitor_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_router_mandatory_SOURCES = tests/test_router_mandatory.cpp\ntests_test_router_mandatory_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_router_mandatory_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_router_mandatory_hwm_SOURCES = tests/test_router_mandatory_hwm.cpp\ntests_test_router_mandatory_hwm_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_router_mandatory_hwm_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_router_handover_SOURCES = tests/test_router_handover.cpp\ntests_test_router_handover_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_router_handover_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_probe_router_SOURCES = tests/test_probe_router.cpp\ntests_test_probe_router_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_probe_router_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_stream_SOURCES = tests/test_stream.cpp\ntests_test_stream_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_stream_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_stream_empty_SOURCES = tests/test_stream_empty.cpp\ntests_test_stream_empty_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_stream_empty_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_stream_timeout_SOURCES = tests/test_stream_timeout.cpp\ntests_test_stream_timeout_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_stream_timeout_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_stream_disconnect_SOURCES = tests/test_stream_disconnect.cpp\ntests_test_stream_disconnect_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_stream_disconnect_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_disconnect_inproc_SOURCES = tests/test_disconnect_inproc.cpp\ntests_test_disconnect_inproc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_disconnect_inproc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_unbind_wildcard_SOURCES = tests/test_unbind_wildcard.cpp\ntests_test_unbind_wildcard_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_unbind_wildcard_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_ctx_options_SOURCES = tests/test_ctx_options.cpp\ntests_test_ctx_options_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_ctx_options_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_iov_SOURCES = tests/test_iov.cpp\ntests_test_iov_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_iov_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_ctx_destroy_SOURCES = tests/test_ctx_destroy.cpp\ntests_test_ctx_destroy_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_ctx_destroy_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_security_no_zap_handler_SOURCES = tests/test_security_no_zap_handler.cpp\ntests_test_security_no_zap_handler_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_security_no_zap_handler_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_security_null_SOURCES = tests/test_security_null.cpp\ntests_test_security_null_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_security_null_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_security_plain_SOURCES = tests/test_security_plain.cpp\ntests_test_security_plain_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_security_plain_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_security_zap_SOURCES = tests/test_security_zap.cpp\ntests_test_security_zap_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_security_zap_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_spec_req_SOURCES = tests/test_spec_req.cpp\ntests_test_spec_req_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_spec_req_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_spec_rep_SOURCES = tests/test_spec_rep.cpp\ntests_test_spec_rep_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_spec_rep_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_spec_dealer_SOURCES = tests/test_spec_dealer.cpp\ntests_test_spec_dealer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_spec_dealer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_spec_router_SOURCES = tests/test_spec_router.cpp\ntests_test_spec_router_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_spec_router_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_spec_pushpull_SOURCES = tests/test_spec_pushpull.cpp\ntests_test_spec_pushpull_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_spec_pushpull_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_req_correlate_SOURCES = tests/test_req_correlate.cpp\ntests_test_req_correlate_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_req_correlate_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_req_relaxed_SOURCES = tests/test_req_relaxed.cpp\ntests_test_req_relaxed_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_req_relaxed_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_conflate_SOURCES = tests/test_conflate.cpp\ntests_test_conflate_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_conflate_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_inproc_connect_SOURCES = tests/test_inproc_connect.cpp\ntests_test_inproc_connect_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_inproc_connect_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_issue_566_SOURCES = tests/test_issue_566.cpp\ntests_test_issue_566_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_issue_566_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\n# TODO: gets stuck even with long timeout running under Github Actions\nif !VALGRIND_ENABLED\ntest_apps += tests/test_proxy\n\ntests_test_proxy_SOURCES = tests/test_proxy.cpp\ntests_test_proxy_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_proxy_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\nendif\n\ntests_test_proxy_hwm_SOURCES = tests/test_proxy_hwm.cpp\ntests_test_proxy_hwm_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_proxy_hwm_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_proxy_single_socket_SOURCES = tests/test_proxy_single_socket.cpp\ntests_test_proxy_single_socket_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_proxy_single_socket_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_proxy_steerable_SOURCES = tests/test_proxy_steerable.cpp\ntests_test_proxy_steerable_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_proxy_steerable_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_proxy_terminate_SOURCES = tests/test_proxy_terminate.cpp\ntests_test_proxy_terminate_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_proxy_terminate_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_getsockopt_memset_SOURCES = tests/test_getsockopt_memset.cpp\ntests_test_getsockopt_memset_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_getsockopt_memset_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_diffserv_SOURCES = tests/test_diffserv.cpp\ntests_test_diffserv_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_diffserv_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_connect_rid_SOURCES = tests/test_connect_rid.cpp\ntests_test_connect_rid_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_connect_rid_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_bind_src_address_SOURCES = tests/test_bind_src_address.cpp\ntests_test_bind_src_address_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_bind_src_address_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_metadata_SOURCES = tests/test_metadata.cpp\ntests_test_metadata_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_metadata_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_capabilities_SOURCES = tests/test_capabilities.cpp\ntests_test_capabilities_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_capabilities_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_xpub_nodrop_SOURCES = tests/test_xpub_nodrop.cpp\ntests_test_xpub_nodrop_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_xpub_nodrop_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_xpub_manual_SOURCES = tests/test_xpub_manual.cpp\ntests_test_xpub_manual_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_xpub_manual_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_xpub_topic_SOURCES = tests/test_xpub_topic.cpp\ntests_test_xpub_topic_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_xpub_topic_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_xpub_welcome_msg_SOURCES = tests/test_xpub_welcome_msg.cpp\ntests_test_xpub_welcome_msg_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_xpub_welcome_msg_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_xpub_verbose_SOURCES = tests/test_xpub_verbose.cpp\ntests_test_xpub_verbose_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_xpub_verbose_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_atomics_SOURCES = tests/test_atomics.cpp\ntests_test_atomics_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_atomics_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_sockopt_hwm_SOURCES = tests/test_sockopt_hwm.cpp\ntests_test_sockopt_hwm_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_sockopt_hwm_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_setsockopt_SOURCES = tests/test_setsockopt.cpp\ntests_test_setsockopt_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_setsockopt_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_heartbeats_SOURCES = tests/test_heartbeats.cpp\ntests_test_heartbeats_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_heartbeats_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_stream_exceeds_buffer_SOURCES = tests/test_stream_exceeds_buffer.cpp\ntests_test_stream_exceeds_buffer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_stream_exceeds_buffer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_pub_invert_matching_SOURCES = tests/test_pub_invert_matching.cpp\ntests_test_pub_invert_matching_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_pub_invert_matching_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_bind_after_connect_tcp_SOURCES = tests/test_bind_after_connect_tcp.cpp\ntests_test_bind_after_connect_tcp_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_bind_after_connect_tcp_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_base85_SOURCES = tests/test_base85.cpp\ntests_test_base85_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_base85_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_sodium_SOURCES = tests/test_sodium.cpp\ntests_test_sodium_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_sodium_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_socket_null_SOURCES = tests/test_socket_null.cpp\ntests_test_socket_null_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_socket_null_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_reconnect_ivl_SOURCES = tests/test_reconnect_ivl.cpp\ntests_test_reconnect_ivl_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_reconnect_ivl_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_mock_pub_sub_SOURCES = tests/test_mock_pub_sub.cpp\ntests_test_mock_pub_sub_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_mock_pub_sub_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_tcp_accept_filter_SOURCES = tests/test_tcp_accept_filter.cpp\ntests_test_tcp_accept_filter_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_tcp_accept_filter_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\nif HAVE_CURVE\n\ntest_apps += \\\n\ttests/test_security_curve\n\ntests_test_security_curve_SOURCES = \\\n\ttests/test_security_curve.cpp \\\n        src/curve_client_tools.hpp \\\n\tsrc/clock.hpp \\\n\tsrc/clock.cpp \\\n\tsrc/random.hpp \\\n\tsrc/random.cpp \\\n\tsrc/err.hpp \\\n\tsrc/err.cpp\n\ntests_test_security_curve_LDADD = \\\n        ${TESTUTIL_LIBS} src/libzmq.la $(LIBUNWIND_LIBS) $(LIBBSD_LIBS)\ntests_test_security_curve_CPPFLAGS = \\\n        ${TESTUTIL_CPPFLAGS} \\\n\t${LIBUNWIND_CFLAGS}  ${LIBBSD_CFLAGS}\n\nif USE_LIBSODIUM\ntests_test_security_curve_CPPFLAGS += \\\n\t${sodium_CFLAGS}\ntests_test_security_curve_LDADD += \\\n\t${sodium_LIBS}\nendif\n\nendif\n\nif HAVE_WS\ntest_apps += \\\n\ttests/test_ws_transport\ntests_test_ws_transport_SOURCES = tests/test_ws_transport.cpp\ntests_test_ws_transport_LDADD = ${TESTUTIL_LIBS} src/libzmq.la ${NSS3_LIBS}\ntests_test_ws_transport_CPPFLAGS = ${TESTUTIL_CPPFLAGS} ${NSS3_CFLAGS}\nendif\n\nif HAVE_WSS\ntest_apps += \\\n\ttests/test_wss_transport\ntests_test_wss_transport_SOURCES = tests/test_wss_transport.cpp\ntests_test_wss_transport_LDADD = ${TESTUTIL_LIBS} src/libzmq.la ${GNUTLS_LIBS}\ntests_test_wss_transport_CPPFLAGS = ${TESTUTIL_CPPFLAGS} ${GNUTLS_CFLAGS}\nendif\n\nif !ON_MINGW\nif !ON_CYGWIN\ntest_apps += \\\n\ttests/test_shutdown_stress \\\n\ttests/test_ipc_wildcard \\\n\ttests/test_pair_ipc \\\n\ttests/test_rebind_ipc \\\n\ttests/test_reqrep_ipc \\\n\ttests/test_use_fd \\\n\ttests/test_zmq_poll_fd \\\n\ttests/test_timeo \\\n\ttests/test_filter_ipc\n\ntests_test_shutdown_stress_SOURCES = tests/test_shutdown_stress.cpp\ntests_test_shutdown_stress_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_shutdown_stress_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_ipc_wildcard_SOURCES = tests/test_ipc_wildcard.cpp\ntests_test_ipc_wildcard_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_ipc_wildcard_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_pair_ipc_SOURCES = tests/test_pair_ipc.cpp\ntests_test_pair_ipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_pair_ipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_rebind_ipc_SOURCES = tests/test_rebind_ipc.cpp\ntests_test_rebind_ipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_rebind_ipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_reqrep_ipc_SOURCES = tests/test_reqrep_ipc.cpp\ntests_test_reqrep_ipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_reqrep_ipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_timeo_SOURCES = tests/test_timeo.cpp\ntests_test_timeo_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_timeo_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_filter_ipc_SOURCES = tests/test_filter_ipc.cpp\ntests_test_filter_ipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_filter_ipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_use_fd_SOURCES = tests/test_use_fd.cpp\ntests_test_use_fd_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_use_fd_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_zmq_poll_fd_SOURCES = tests/test_zmq_poll_fd.cpp\ntests_test_zmq_poll_fd_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_zmq_poll_fd_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\nif HAVE_FORK\nif !VALGRIND_ENABLED\ntest_apps += tests/test_fork\n\ntests_test_fork_SOURCES = tests/test_fork.cpp\ntests_test_fork_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_fork_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\nendif\nendif\nendif\nendif\n\nif BUILD_TIPC\ntest_apps += \\\n\ttests/test_connect_delay_tipc \\\n\ttests/test_pair_tipc \\\n\ttests/test_reqrep_device_tipc \\\n\ttests/test_reqrep_tipc \\\n\ttests/test_router_mandatory_tipc \\\n\ttests/test_shutdown_stress_tipc \\\n\ttests/test_sub_forward_tipc \\\n\ttests/test_term_endpoint_tipc \\\n\ttests/test_address_tipc\n\ntests_test_connect_delay_tipc_SOURCES = tests/test_connect_delay_tipc.cpp\ntests_test_connect_delay_tipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_connect_delay_tipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_pair_tipc_SOURCES = tests/test_pair_tipc.cpp\ntests_test_pair_tipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_pair_tipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_reqrep_device_tipc_SOURCES = tests/test_reqrep_device_tipc.cpp\ntests_test_reqrep_device_tipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_reqrep_device_tipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_reqrep_tipc_SOURCES = tests/test_reqrep_tipc.cpp\ntests_test_reqrep_tipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_reqrep_tipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_router_mandatory_tipc_SOURCES = tests/test_router_mandatory_tipc.cpp\ntests_test_router_mandatory_tipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_router_mandatory_tipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_shutdown_stress_tipc_SOURCES = tests/test_shutdown_stress_tipc.cpp\ntests_test_shutdown_stress_tipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_shutdown_stress_tipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_sub_forward_tipc_SOURCES = tests/test_sub_forward_tipc.cpp\ntests_test_sub_forward_tipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_sub_forward_tipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_term_endpoint_tipc_SOURCES = tests/test_term_endpoint_tipc.cpp\ntests_test_term_endpoint_tipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_term_endpoint_tipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_address_tipc_SOURCES = tests/test_address_tipc.cpp\ntests_test_address_tipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_address_tipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\nendif\n\nif BUILD_GSSAPI\ntest_apps += tests/test_security_gssapi\n\ntests_test_security_gssapi_SOURCES = tests/test_security_gssapi.cpp\ntests_test_security_gssapi_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_security_gssapi_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\nendif\n\nif ON_LINUX\ntest_apps += tests/test_abstract_ipc\n\ntests_test_abstract_ipc_SOURCES = tests/test_abstract_ipc.cpp\ntests_test_abstract_ipc_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_abstract_ipc_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\n# TODO: gets stuck even with long timeout running under Github Actions\nif !VALGRIND_ENABLED\ntest_apps += tests/test_socks\n\ntests_test_socks_SOURCES = tests/test_socks.cpp\ntests_test_socks_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_socks_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\nendif\n\n# TODO: enable when https://github.com/zeromq/libzmq/issues/3898 is fixed\nif !ENABLE_ASAN\ntest_apps += tests/test_many_sockets\n\ntests_test_many_sockets_SOURCES = tests/test_many_sockets.cpp\ntests_test_many_sockets_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_many_sockets_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\nendif\n\nendif\n\nif HAVE_VMCI\ntest_apps += tests/test_pair_vmci tests/test_reqrep_vmci\n\ntests_test_pair_vmci_SOURCES = tests/test_pair_vmci.cpp\ntests_test_pair_vmci_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_pair_vmci_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_pair_vmci_LDFLAGS = @LIBZMQ_VMCI_LDFLAGS@\ntests_test_pair_vmci_CXXFLAGS = @LIBZMQ_VMCI_CXXFLAGS@\n\ntests_test_reqrep_vmci_SOURCES = tests/test_reqrep_vmci.cpp\ntests_test_reqrep_vmci_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_reqrep_vmci_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_reqrep_vmci_LDFLAGS = @LIBZMQ_VMCI_LDFLAGS@\ntests_test_reqrep_vmci_CXXFLAGS = @LIBZMQ_VMCI_CXXFLAGS@\n\nendif\n\nif BUILD_VSOCK\ntest_apps += tests/test_pair_vsock tests/test_reqrep_vsock\n\ntests_test_pair_vsock_SOURCES = tests/test_pair_vsock.cpp\ntests_test_pair_vsock_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_pair_vsock_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_reqrep_vsock_SOURCES = tests/test_reqrep_vsock.cpp\ntests_test_reqrep_vsock_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_reqrep_vsock_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\nendif\n\nif ENABLE_DRAFTS\ntest_apps += tests/test_poller \\\n\ttests/test_client_server \\\n\ttests/test_thread_safe \\\n\ttests/test_timers \\\n\ttests/test_radio_dish \\\n\ttests/test_scatter_gather \\\n\ttests/test_dgram \\\n\ttests/test_app_meta \\\n\ttests/test_xpub_manual_last_value \\\n\ttests/test_router_notify \\\n\ttests/test_peer \\\n\ttests/test_peer_disconnect \\\n\ttests/test_reconnect_options \\\n\ttests/test_msg_init \\\n\ttests/test_hello_msg \\\n\ttests/test_disconnect_msg \\\n\ttests/test_channel \\\n\ttests/test_hiccup_msg \\\n\ttests/test_zmq_ppoll_fd \\\n\ttests/test_xsub_verbose \\\n\ttests/test_pubsub_topics_count\n\ntests_test_poller_SOURCES = tests/test_poller.cpp\ntests_test_poller_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_poller_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_client_server_SOURCES = tests/test_client_server.cpp\ntests_test_client_server_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_client_server_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_thread_safe_SOURCES = tests/test_thread_safe.cpp\ntests_test_thread_safe_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_thread_safe_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_timers_SOURCES = tests/test_timers.cpp\ntests_test_timers_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_timers_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_radio_dish_SOURCES = tests/test_radio_dish.cpp\ntests_test_radio_dish_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_radio_dish_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_scatter_gather_SOURCES = tests/test_scatter_gather.cpp\ntests_test_scatter_gather_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_scatter_gather_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_dgram_SOURCES = tests/test_dgram.cpp\ntests_test_dgram_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_dgram_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_xpub_manual_last_value_SOURCES = tests/test_xpub_manual_last_value.cpp\ntests_test_xpub_manual_last_value_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_xpub_manual_last_value_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_app_meta_SOURCES = tests/test_app_meta.cpp\ntests_test_app_meta_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_app_meta_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_router_notify_SOURCES = tests/test_router_notify.cpp\ntests_test_router_notify_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_router_notify_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_peer_SOURCES = tests/test_peer.cpp\ntests_test_peer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_peer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_peer_disconnect_SOURCES = tests/test_peer_disconnect.cpp\ntests_test_peer_disconnect_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_peer_disconnect_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_reconnect_options_SOURCES = tests/test_reconnect_options.cpp\ntests_test_reconnect_options_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_reconnect_options_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_msg_init_SOURCES = tests/test_msg_init.cpp\ntests_test_msg_init_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_msg_init_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_hello_msg_SOURCES = tests/test_hello_msg.cpp\ntests_test_hello_msg_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_hello_msg_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_disconnect_msg_SOURCES = tests/test_disconnect_msg.cpp\ntests_test_disconnect_msg_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_disconnect_msg_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_channel_SOURCES = tests/test_channel.cpp\ntests_test_channel_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_channel_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_hiccup_msg_SOURCES = tests/test_hiccup_msg.cpp\ntests_test_hiccup_msg_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_hiccup_msg_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_zmq_ppoll_fd_SOURCES = tests/test_zmq_ppoll_fd.cpp\ntests_test_zmq_ppoll_fd_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_zmq_ppoll_fd_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_xsub_verbose_SOURCES = tests/test_xsub_verbose.cpp\ntests_test_xsub_verbose_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_xsub_verbose_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_pubsub_topics_count_SOURCES = tests/test_pubsub_topics_count.cpp\ntests_test_pubsub_topics_count_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_pubsub_topics_count_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\nif HAVE_FORK\ntest_apps += tests/test_zmq_ppoll_signals\n\ntests_test_zmq_ppoll_signals_SOURCES = tests/test_zmq_ppoll_signals.cpp\ntests_test_zmq_ppoll_signals_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_zmq_ppoll_signals_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\nendif\nendif\n\nif FUZZING_ENGINE_LIB\nfuzzer_apps = tests/test_bind_null_fuzzer \\\n\ttests/test_connect_null_fuzzer \\\n\ttests/test_bind_fuzzer \\\n\ttests/test_connect_fuzzer \\\n\ttests/test_bind_stream_fuzzer \\\n\ttests/test_connect_stream_fuzzer \\\n\ttests/test_socket_options_fuzzer\n\ntests_test_bind_null_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_bind_null_fuzzer_SOURCES = tests/test_bind_null_fuzzer.cpp\ntests_test_bind_null_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_bind_null_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_bind_null_fuzzer_CXXFLAGS = -std=c++11\n\ntests_test_connect_null_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_connect_null_fuzzer_SOURCES = tests/test_connect_null_fuzzer.cpp\ntests_test_connect_null_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_connect_null_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_connect_null_fuzzer_CXXFLAGS = -std=c++11\n\ntests_test_bind_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_bind_fuzzer_SOURCES = tests/test_bind_fuzzer.cpp\ntests_test_bind_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_bind_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_bind_fuzzer_CXXFLAGS = -std=c++11\n\ntests_test_connect_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_connect_fuzzer_SOURCES = tests/test_connect_fuzzer.cpp\ntests_test_connect_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_connect_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_connect_fuzzer_CXXFLAGS = -std=c++11\n\ntests_test_socket_options_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_socket_options_fuzzer_SOURCES = tests/test_socket_options_fuzzer.cpp\ntests_test_socket_options_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_socket_options_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_socket_options_fuzzer_CXXFLAGS = -std=c++11\n\ntests_test_bind_stream_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_bind_stream_fuzzer_SOURCES = tests/test_bind_stream_fuzzer.cpp\ntests_test_bind_stream_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_bind_stream_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_bind_stream_fuzzer_CXXFLAGS = -std=c++11\n\ntests_test_connect_stream_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_connect_stream_fuzzer_SOURCES = tests/test_connect_stream_fuzzer.cpp\ntests_test_connect_stream_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_connect_stream_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_connect_stream_fuzzer_CXXFLAGS = -std=c++11\n\nif HAVE_CURVE\nfuzzer_apps += tests/test_bind_curve_fuzzer \\\n\ttests/test_connect_curve_fuzzer \\\n\ttests/test_z85_decode_fuzzer\n\ntests_test_bind_curve_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_bind_curve_fuzzer_SOURCES = tests/test_bind_curve_fuzzer.cpp\ntests_test_bind_curve_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_bind_curve_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_bind_curve_fuzzer_CXXFLAGS = -std=c++11\n\ntests_test_connect_curve_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_connect_curve_fuzzer_SOURCES = tests/test_connect_curve_fuzzer.cpp\ntests_test_connect_curve_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_connect_curve_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_connect_curve_fuzzer_CXXFLAGS = -std=c++11\n\ntests_test_z85_decode_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_z85_decode_fuzzer_SOURCES = tests/test_z85_decode_fuzzer.cpp\ntests_test_z85_decode_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_z85_decode_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_z85_decode_fuzzer_CXXFLAGS = -std=c++11\nendif\n\nif HAVE_WS\nfuzzer_apps += tests/test_connect_ws_fuzzer \\\n\ttests/test_bind_ws_fuzzer\n\ntests_test_connect_ws_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_connect_ws_fuzzer_SOURCES = tests/test_connect_ws_fuzzer.cpp\ntests_test_connect_ws_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_connect_ws_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_connect_ws_fuzzer_CXXFLAGS = -std=c++11\n\ntests_test_bind_ws_fuzzer_DEPENDENCIES = src/libzmq.la\ntests_test_bind_ws_fuzzer_SOURCES = tests/test_bind_ws_fuzzer.cpp\ntests_test_bind_ws_fuzzer_LDADD = ${TESTUTIL_LIBS} ${FUZZING_ENGINE_LIB} \\\n\t\t$(top_builddir)/src/.libs/libzmq.a \\\n\t\t${src_libzmq_la_LIBADD}\ntests_test_bind_ws_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\ntests_test_bind_ws_fuzzer_CXXFLAGS = -std=c++11\nendif\n\nFUZZINGdir = ${prefix}/${FUZZING_INSTALLDIR}\nFUZZING_PROGRAMS = ${fuzzer_apps}\nelse\ntest_apps += tests/test_bind_null_fuzzer \\\n\ttests/test_connect_null_fuzzer \\\n\ttests/test_bind_fuzzer \\\n\ttests/test_connect_fuzzer \\\n\ttests/test_bind_stream_fuzzer \\\n\ttests/test_connect_stream_fuzzer \\\n\ttests/test_socket_options_fuzzer\n\ntests_test_bind_null_fuzzer_SOURCES = tests/test_bind_null_fuzzer.cpp\ntests_test_bind_null_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_bind_null_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_connect_null_fuzzer_SOURCES = tests/test_connect_null_fuzzer.cpp\ntests_test_connect_null_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_connect_null_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_bind_fuzzer_SOURCES = tests/test_bind_fuzzer.cpp\ntests_test_bind_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_bind_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_connect_fuzzer_SOURCES = tests/test_connect_fuzzer.cpp\ntests_test_connect_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_connect_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_socket_options_fuzzer_SOURCES = tests/test_socket_options_fuzzer.cpp\ntests_test_socket_options_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_socket_options_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_bind_stream_fuzzer_SOURCES = tests/test_bind_stream_fuzzer.cpp\ntests_test_bind_stream_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_bind_stream_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_connect_stream_fuzzer_SOURCES = tests/test_connect_stream_fuzzer.cpp\ntests_test_connect_stream_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_connect_stream_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\nif HAVE_CURVE\ntest_apps += tests/test_bind_curve_fuzzer \\\n\ttests/test_connect_curve_fuzzer \\\n\ttests/test_z85_decode_fuzzer\n\ntests_test_bind_curve_fuzzer_SOURCES = tests/test_bind_curve_fuzzer.cpp\ntests_test_bind_curve_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_bind_curve_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_connect_curve_fuzzer_SOURCES = tests/test_connect_curve_fuzzer.cpp\ntests_test_connect_curve_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_connect_curve_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_z85_decode_fuzzer_SOURCES = tests/test_z85_decode_fuzzer.cpp\ntests_test_z85_decode_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_z85_decode_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\nendif\n\nif HAVE_WS\ntest_apps += tests/test_connect_ws_fuzzer \\\n\ttests/test_bind_ws_fuzzer\n\ntests_test_connect_ws_fuzzer_SOURCES = tests/test_connect_ws_fuzzer.cpp\ntests_test_connect_ws_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_connect_ws_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\n\ntests_test_bind_ws_fuzzer_SOURCES = tests/test_bind_ws_fuzzer.cpp\ntests_test_bind_ws_fuzzer_LDADD = ${TESTUTIL_LIBS} src/libzmq.la\ntests_test_bind_ws_fuzzer_CPPFLAGS = ${TESTUTIL_CPPFLAGS}\nendif\nendif\n\nif ENABLE_STATIC\n# unit tests - these include individual source files and test the internal functions\ntest_apps += \\\n\tunittests/unittest_poller \\\n\tunittests/unittest_ypipe \\\n\tunittests/unittest_mtrie \\\n\tunittests/unittest_ip_resolver \\\n\tunittests/unittest_udp_address \\\n\tunittests/unittest_radix_tree \\\n\tunittests/unittest_curve_encoding\n\nunittests_unittest_poller_SOURCES = unittests/unittest_poller.cpp\nunittests_unittest_poller_CPPFLAGS = -I$(top_srcdir)/src ${TESTUTIL_CPPFLAGS} $(CODE_COVERAGE_CPPFLAGS)\nunittests_unittest_poller_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS)\nunittests_unittest_poller_LDADD = \\\n        ${TESTUTIL_LIBS} \\\n        $(top_builddir)/src/.libs/libzmq.a \\\n        ${src_libzmq_la_LIBADD} \\\n        $(CODE_COVERAGE_LDFLAGS)\n\nunittests_unittest_ypipe_SOURCES = unittests/unittest_ypipe.cpp\nunittests_unittest_ypipe_CPPFLAGS = -I$(top_srcdir)/src ${TESTUTIL_CPPFLAGS} $(CODE_COVERAGE_CPPFLAGS)\nunittests_unittest_ypipe_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS)\nunittests_unittest_ypipe_LDADD = \\\n        ${TESTUTIL_LIBS} \\\n        $(top_builddir)/src/.libs/libzmq.a \\\n        ${src_libzmq_la_LIBADD} \\\n        $(CODE_COVERAGE_LDFLAGS)\n\nunittests_unittest_mtrie_SOURCES = unittests/unittest_mtrie.cpp\nunittests_unittest_mtrie_CPPFLAGS = -I$(top_srcdir)/src ${TESTUTIL_CPPFLAGS} $(CODE_COVERAGE_CPPFLAGS)\nunittests_unittest_mtrie_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS)\nunittests_unittest_mtrie_LDADD = \\\n        ${TESTUTIL_LIBS} \\\n        $(top_builddir)/src/.libs/libzmq.a \\\n        ${src_libzmq_la_LIBADD} \\\n        $(CODE_COVERAGE_LDFLAGS)\n\nunittests_unittest_ip_resolver_SOURCES = unittests/unittest_ip_resolver.cpp unittests/unittest_resolver_common.hpp\nunittests_unittest_ip_resolver_CPPFLAGS = -I$(top_srcdir)/src ${TESTUTIL_CPPFLAGS} $(CODE_COVERAGE_CPPFLAGS)\nunittests_unittest_ip_resolver_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS)\nunittests_unittest_ip_resolver_LDADD = \\\n        ${TESTUTIL_LIBS} \\\n        $(top_builddir)/src/.libs/libzmq.a \\\n        ${src_libzmq_la_LIBADD} \\\n        $(CODE_COVERAGE_LDFLAGS)\n\nunittests_unittest_udp_address_SOURCES = unittests/unittest_udp_address.cpp unittests/unittest_resolver_common.hpp\nunittests_unittest_udp_address_CPPFLAGS = -I$(top_srcdir)/src ${TESTUTIL_CPPFLAGS} $(CODE_COVERAGE_CPPFLAGS)\nunittests_unittest_udp_address_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS)\nunittests_unittest_udp_address_LDADD = \\\n        ${TESTUTIL_LIBS} \\\n        $(top_builddir)/src/.libs/libzmq.a \\\n        ${src_libzmq_la_LIBADD} \\\n        $(CODE_COVERAGE_LDFLAGS)\n\nunittests_unittest_radix_tree_SOURCES = unittests/unittest_radix_tree.cpp\nunittests_unittest_radix_tree_CPPFLAGS = -I$(top_srcdir)/src ${TESTUTIL_CPPFLAGS} $(CODE_COVERAGE_CPPFLAGS)\nunittests_unittest_radix_tree_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS)\nunittests_unittest_radix_tree_LDADD =  \\\n        ${TESTUTIL_LIBS} \\\n        $(top_builddir)/src/.libs/libzmq.a \\\n        ${src_libzmq_la_LIBADD} \\\n        $(CODE_COVERAGE_LDFLAGS)\n\nunittests_unittest_curve_encoding_SOURCES = unittests/unittest_curve_encoding.cpp\nunittests_unittest_curve_encoding_CPPFLAGS = -I$(top_srcdir)/src ${TESTUTIL_CPPFLAGS} $(CODE_COVERAGE_CPPFLAGS)\nunittests_unittest_curve_encoding_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS)\nunittests_unittest_curve_encoding_LDADD =  \\\n        ${TESTUTIL_LIBS} \\\n        $(top_builddir)/src/.libs/libzmq.a \\\n        ${src_libzmq_la_LIBADD} \\\n        $(CODE_COVERAGE_LDFLAGS)\n\nif USE_LIBSODIUM\nunittests_unittest_curve_encoding_CPPFLAGS += ${sodium_CFLAGS}\nunittests_unittest_curve_encoding_LDADD += ${sodium_LIBS}\nendif\nendif\n\ncheck_PROGRAMS = ${test_apps}\n\n#  Run the test cases\nTESTS = $(test_apps)\nXFAIL_TESTS =\n\nif !ON_LINUX\nXFAIL_TESTS += tests/test_abstract_ipc\nendif\n\n#  GNU/Hurd does not support getsockname on IPC, so ZMQ_LAST_ENDPOINT cannot be\n#  used with IPC, so the following tests will fail\nif ON_GNU\nXFAIL_TESTS += tests/test_ipc_wildcard \\\n\t\ttests/test_reqrep_ipc \\\n\t\ttests/test_pair_ipc \\\n\t\ttests/test_term_endpoint\nendif\n\nEXTRA_DIST = \\\n\texternal/unity/license.txt \\\n\texternal/unity/version.txt \\\n\texternal/wepoll/license.txt \\\n\texternal/wepoll/version.txt \\\n\texternal/wepoll/README.md \\\n\tCMakeLists.txt \\\n\tautogen.sh\t\\\n\tversion.sh\t\\\n\tci_build.sh \\\n\tLICENSE \\\n\tsrc/libzmq.vers \\\n\tsrc/version.rc.in \\\n\ttests/CMakeLists.txt \\\n        tests/test_pair_tcp_cap_net_admin.cpp \\\n\tunittests/CMakeLists.txt \\\n        tools/curve_keygen.cpp\n\nMAINTAINERCLEANFILES = \\\n\t$(srcdir)/aclocal.m4 \\\n\t$(srcdir)/autom4te.cache \\\n\t$(srcdir)/configure \\\n\t`find \"$(srcdir)\" -type f -name Makefile.in -print`\n\nif WITH_CLANG_FORMAT\nALL_SOURCE_FILES = $(wildcard \\\n\t$(top_srcdir)/src/*.c \\\n\t$(top_srcdir)/src/*.cc \\\n\t$(top_srcdir)/src/*.cpp \\\n\t$(top_srcdir)/src/*.h \\\n\t$(top_srcdir)/src/*.hpp \\\n\t$(top_srcdir)/tests/*.c \\\n\t$(top_srcdir)/tests/*.cc \\\n\t$(top_srcdir)/tests/*.cpp \\\n\t$(top_srcdir)/tests/*.h \\\n\t$(top_srcdir)/tests/*.hpp \\\n\t$(top_srcdir)/perf/*.c \\\n\t$(top_srcdir)/perf/*.cc \\\n\t$(top_srcdir)/perf/*.cpp \\\n\t$(top_srcdir)/perf/*.h \\\n\t$(top_srcdir)/perf/*.hpp \\\n\t$(top_srcdir)/tools/*.c \\\n\t$(top_srcdir)/tools/*.cc \\\n\t$(top_srcdir)/tools/*.cpp \\\n\t$(top_srcdir)/tools/*.h \\\n\t$(top_srcdir)/tools/*.hpp \\\n\t$(top_srcdir)/include/*.h \\\n )\n\n# Check if any sources need to be fixed, report the filenames and an error code\nclang-format-check: $(ALL_SOURCE_FILES)\n\t@FAILED=0 ; IFS=\";\" ; IDS=\"`printf '\\n\\b'`\" ; export IFS IDS; \\\n\t for FILE in $(ALL_SOURCE_FILES) ; do \\\n\t\ttest -s $$FILE || continue ; \\\n\t\t$(CLANG_FORMAT) -style=file -output-replacements-xml \"$$FILE\" | grep \"<replacement \" >/dev/null && \\\n\t\t{ echo \"$$FILE is not correctly formatted\" >&2 ; FAILED=1; } ; \\\n\t done; \\\n\t if test \"$$FAILED\" != 0 ; then \\\n\t\texit 1 ; \\\n\t fi\n\n# Change source formatting\nclang-format: $(ALL_SOURCE_FILES)\n\t$(CLANG_FORMAT) -style=file -i $(ALL_SOURCE_FILES)\n\n# Change source formatting AND report the diff\nclang-format-diff: clang-format\n\tgit diff $(ALL_SOURCE_FILES)\n\nelse\nclang-format clang-format-check clang-format-diff:\n\t@echo \"Install the clang-format program, reconfigure and re-run this request\"\n\t@exit 1\nendif\n\n@CODE_COVERAGE_RULES@\n\ndist-hook:\n\t-rm $(distdir)/src/platform.hpp\n\t@if test -d \"$(srcdir)/.git\"; \\\n\tthen \\\n\t\techo Creating ChangeLog && \\\n\t\t( cd \"$(top_srcdir)\" && \\\n\t\t  echo '# Generated by Makefile. Do not edit.'; echo; \\\n\t\t  $(top_srcdir)/config/missing --run git log --stat ) > ChangeLog.tmp \\\n\t\t  && mv -f ChangeLog.tmp $(top_distdir)/ChangeLog \\\n\t\t  || ( rm -f ChangeLog.tmp ; \\\n\t\t       echo Failed to generate ChangeLog >&2 ); \\\n\telse \\\n\t\techo A git clone is required to generate a ChangeLog >&2; \\\n\tfi\n\nmaintainer-clean-local:\n\t-rm -rf $(top_srcdir)/config\n\n@VALGRIND_CHECK_RULES@\n\nVALGRIND_SUPPRESSIONS_FILES = builds/valgrind/valgrind.supp\n"
  },
  {
    "path": "NEWS",
    "content": "0MQ version 4.3.5 stable, released on 2023/10/09\n================================================\n\n* Relicensing from LGPL-3.0+ (with custom exceptions) to MPL-2.0 is now complete.\n  libzmq is now distributed under the Mozilla Public License 2.0. Relicensing\n  grants have been collected from all relevant authors, and some functionality\n  has been clean-room reimplemented where that was not possible. In layman terms,\n  the new license provides the same rights and obligations as before. Source\n  files are now tagged using the SPDX license identifier format.\n  Details of the relicensing process can be seen at:\n  https://github.com/zeromq/libzmq/issues/2376\n  Relicensing grants have been archived at:\n  https://github.com/rlenferink/libzmq-relicense\n  A special thanks to everybody who helped with this long and difficult task,\n  with the process, the reimplementations, the collections and everything else.\n\n* New DRAFT (see NEWS for 4.2.0) socket options:\n  - ZMQ_BUSY_POLL will set the SO_BUSY_POLL socket option on the underlying\n    sockets, if it is supported.\n  - ZMQ_HICCUP_MSG will send a message when the peer has been disconnected.\n  - ZMQ_XSUB_VERBOSE_UNSUBSCRIBE will configure a socket to pass all\n    unsubscription messages, including duplicated ones.\n  - ZMQ_TOPICS_COUNT will return the number of subscribed topics on a\n    PUB/SUB socket.\n  - ZMQ_NORM_MODE, ZMQ_NORM_UNICAST_NACK, ZMQ_NORM_BUFFER_SIZE,\n    ZMQ_NORM_SEGMENT_SIZE, ZMQ_NORM_BLOCK_SIZE, ZMQ_NORM_NUM_PARITY,\n    ZMQ_NORM_NUM_AUTOPARITY and ZMQ_NORM_PUSH to control various aspect of\n    NORM sockets.\n  See doc/zmq_setsockopt.txt and doc/zmq_getsockopt.txt for details.\n\n* New DRAFT (see NEWS for 4.2.0) zmq_ppoll APIs was added that differs from\n  zmq_poll in the same way that ppoll differs from poll.\n  See doc/zmq_ppoll.txt for details.\n\n* Various bug fixes and performance improvements.\n\n\n0MQ version 4.3.4 stable, released on 2021/01/17\n================================================\n\n* New DRAFT (see NEWS for 4.2.0) socket option:\n  - ZMQ_PRIORITY will set the SO_PRIORITY socket option on the underlying\n    sockets. Only supported on Linux.\n  See doc/zmq_setsockopt.txt and doc/zmq_getsockopt.txt for details.\n\n* Fixed #4113 - compilation errors on kFreeBSD and GNU/Hurd\n\n* Fixed #4086 - excessive amount of socket files left behind in Windows TMP\n                directory\n\n* Fixed #4108 - regression that breaks using IPv6 link-local addresses on Linux\n\n* Fixed #4078 - compilation errors on Android\n\n* Fixed #4074 - compilation error with ulibc and libbsd\n\n* Fixed #4060 - stack overflow on Windows x64\n\n* Fixed #4051 - various compilation errors on Windows ARM 32bit\n\n* Fixed #4043 - various compilation warnings with XCode\n\n* Fixed #4038 - return value of zmq_ctx_get changed unintentionally\n\n\n0MQ version 4.3.3 stable, released on 2020/09/07\n================================================\n\n* Security advisories:\n  * CVE-2020-15166: Denial-of-Service on CURVE/ZAP-protected servers by\n    unauthenticated clients.\n    If a raw TCP socket is opened and connected to an endpoint that is fully\n    configured with CURVE/ZAP, legitimate clients will not be able to exchange\n    any message. Handshakes complete successfully, and messages are delivered to\n    the library, but the server application never receives them.\n    For more information see the security advisory:\n    https://github.com/zeromq/libzmq/security/advisories/GHSA-25wp-cf8g-938m\n  * Stack overflow on server running PUB/XPUB socket (CURVE disabled).\n    The PUB/XPUB subscription store (mtrie) is traversed using recursive\n    function calls. In the remove (unsubscription) case, the recursive calls are\n    NOT tail calls, so even with optimizations the stack grows linearly with the\n    length of a subscription topic. Topics are under the control of remote\n    clients - they can send a subscription to arbitrary length topics. An\n    attacker can thus cause a server to create an mtrie sufficiently large such\n    that, when unsubscribing, traversal will cause a stack overflow.\n    For more information see the security advisory:\n    https://github.com/zeromq/libzmq/security/advisories/GHSA-qq65-x72m-9wr8\n  * Memory leak in PUB server induced by malicious client(s) without CURVE/ZAP.\n    Messages with metadata are never processed by PUB sockets, but the metadata\n    is kept referenced in the PUB object and never freed.\n    For more information see the security advisory:\n    https://github.com/zeromq/libzmq/security/advisories/GHSA-4p5v-h92w-6wxw\n  * Memory leak in client induced by malicious server(s) without CURVE/ZAP.\n    When a pipe processes a delimiter and is already not in active state but\n    still has an unfinished message, the message is leaked.\n    For more information see the security advisory:\n    https://github.com/zeromq/libzmq/security/advisories/GHSA-wfr2-29gj-5w87\n  * Heap overflow when receiving malformed ZMTP v1 packets (CURVE disabled).\n    By crafting a packet which is not valid ZMTP v2/v3, and which has two\n    messages larger than 8192 bytes, the decoder can be tricked into changing\n    the recorded size of the 8192 bytes static buffer, which then gets overflown\n    by the next message. The content that gets written in the overflown memory\n    is entirely decided by the sender.\n    For more information see the security advisory:\n    https://github.com/zeromq/libzmq/security/advisories/GHSA-fc3w-qxf5-7hp6\n\n* Note for packagers: an external, self-contained sha1 library is now\n  included in the source tree under external/sha1/ - it is licensed\n  under BSD-3-Clause and thus it is fully compatible with libzmq's\n  license.\n  It is only used if WebSockets support is enabled, and if neither GnuTLS nor\n  NSS are available.\n\n* Note for packagers: an internal reimplementation of strlcpy is now included,\n  for wider platform compatibility.\n  libbsd can be used and is enabled by default if available instead of the\n  internal implementation, for better security maintenance in distros.\n\n* Note for packagers: ZeroMQConfig.cmake is now installed in the arch-dependent\n  subdirectory - eg: /usr/lib/x86_64-linux-gnu/cmake/\n\n* New DRAFT (see NEWS for 4.2.0) socket type:\n  - ZMQ_CHANNEL is a thread-safe alternative to ZMQ_PAIR.\n  See doc/zmq_socket.txt for details.\n\n* New DRAFT (see NEWS for 4.2.0) socket option:\n  - ZMQ_ONLY_FIRST_SUBSCRIBE will cause only the first part of a multipart\n    message to be processed as a subscribe/unsubscribe message, and the rest\n    will be forwarded as user data to the application.\n  - ZMQ_RECONNECT_STOP will cause a connecting socket to stop trying to\n    reconnect in specific circumstances. See the manpage for details.\n  - ZMQ_HELLO_MSG to set a message that will be automatically sent to a new\n    connection.\n  - ZMQ_DISCONNECT_MSG to set a message that will be automatically received when\n    a peer disconnects.\n  See doc/zmq_setsockopt.txt and doc/zmq_getsockopt.txt for details.\n\n* New DRAFT (see NEWS for 4.2.0) zmq_ctx_get_ext/zmq_ctx_set_ext APIs were added\n  to allow enhancing the context options with variable data inputs.\n  See doc/zmq_ctx_get_ext.txt and doc/zmq_ctx_set_ext.txt for details.\n\n* New DRAFT (see NEWS for 4.2.0) transport options WS and WSS added for support\n  of WebSockets (and secure WebSockets via TLS) via the ZWS 2.0 protocol.\n  WSS requires the GnuTLS library for TLS support. ZMQ_WSS_ specific socket\n  options were added to support TLS.\n  WebSockets support is disabled by default if DRAFT APIs are disabled.\n\n* New DRAFT (see NEWS for 4.2.0) socket type, PEER, which is thread safe and a\n  related zmq_connect_peer function which atomically and thread-safely connects\n  and returns a routing-id.\n\n* New DRAFT (see NEWS for 4.2.0) zmq_msg_init_buffer API was added to allow\n  the construction of a message by copying from an existing buffer.\n\n* New DRAFT (see NEWS for 4.2.0) zmq_poller_size API was added to allow querying\n  the number of sockets/fds registered in a zmq_poller.\n\n* ZMTP 3.1 peers will receive subscribe/cancel on PUB/SUB via commands rather\n  than using the first byte of the payload.\n\n* zmq_z85_decode now checks that the input string's length is at least 5 characters\n  and always a multiple of 5 as per API specification.\n\n* Fixed #3566 - malformed CURVE message can cause memory leak\n\n* Fixed #3567 - missing ZeroMQ_INCLUDE_DIR in ZeroMQConfig.cmake when only\n                static lib is built\n\n* Fixed #3576 - CURVE plaintext secrets now stored in libsodium's secure memory\n\n* Fixed #3588 - install debug libraries for debug msvc builds with CMake\n\n* Fixed #3591 - incorrect ZMQ_MAX_SOCKETS default value in doc\n\n* Fixed #3594 - fixed stream_engine use after free due to concurrent heartbeats\n\n* Fixed #3586 - error when compiling with MinGW due to usage of MS-specific\n                __except keyword\n\n* Fixed #3603 - fixed CMake build on SL6.9\n\n* Fixed #3607 - added scripts to ease performance graph generation\n\n* Fixed #3608 - fix for IPv4 mapping not supported in DragonFlyBSD\n\n* Fixed #3636 - added ENABLE_PRECOMPILED CMake option to fix build with Ninja\n\n* Fixed #2862 - UDP engine aborts on networking-related errors from socket\n                syscalls\n\n* Fixed #3656 - segfault on sending data from XSUB to XPUB\n\n* Fixed #3646 - static-only test run fails\n\n* Fixed #3668 - fixed CMAKE_CXX_FLAGS_* regexes on MSVC\n\n* Fixed #110  - do not include winsock2.h in public zmq.h header\n\n* Fixed #3683 - allow \"configure --disable-maintainer-mode\"\n\n* Fixed #3686 - fix documentation about sockets blocking on send operations\n\n* Fixed #3323 - fix behavior of ZMQ_CONFLATE on PUB sockets\n\n* Fixed #3698 - fix build on IBM i/PASE/os400\n\n* Fixed #3705 - zero-sized messages cause assertion when glibc assertion are on\n\n* Fixed #3713 - remove dependency on math library by avoiding std::ceil\n\n* Fixed #3694 - build targeting Windows XP is broken\n\n* Fixed #3691 - added support for IPC on Windows 10 via AF_UNIX\n\n* Fixed #3725 - disable by default test that requires sudo on CMake\n\n* Fixed #3727 - fix zmq_poller documentation example\n\n* Fixed #3729 - do not check for FD_OOB when using WSAEventSelect on Windows\n\n* Fixed #3738 - allow renaming the library in CMake\n\n* Fixed #1808 - use AF_UNIX instead of TCP for the internal socket on Windows 10\n\n* Fixed #3758 - fix pthread_set_affinity detection in CMake\n\n* Fixed #3769 - fix undefined behaviour in array.hpp\n\n* Fixed #3772 - fix compiling under msys2-mingw\n\n* Fixed #3775 - add -latomic to the private libs flag in pkg-config if needed\n\n* Fixed #3778 - fix documentation of zmq_poller's thread safety\n\n* Fixed #3792 - do not allow creation of new sockets after zmq_ctx_shutdown\n\n* Fixed #3805 - improve performance of CURVE by reducing copies\n\n* Fixed #3814 - send subscribe/cancel as commands to ZMTP 3.1 peers\n\n* Fixed #3847 - fix building without PGM and NORM\n\n* Fixed #3849 - install .cmake file in arch-dependent subdirectory\n\n* Fixed #4005 - allow building on Windows ARM/ARM64\n\n0MQ version 4.3.2 stable, released on 2019/07/08\n================================================\n\n* CVE-2019-13132: a remote, unauthenticated client connecting to a\n  libzmq application, running with a socket listening with CURVE\n  encryption/authentication enabled, may cause a stack overflow and\n  overwrite the stack with arbitrary data, due to a buffer overflow in\n  the library. Users running public servers with the above configuration\n  are highly encouraged to upgrade as soon as possible, as there are no\n  known mitigations. All versions from 4.0.0 and upwards are affected.\n  Thank you Fang-Pen Lin for finding the issue and reporting it!\n\n* New DRAFT (see NEWS for 4.2.0) zmq_socket_monitor_versioned API that supports\n  a versioned monitoring events protocol as a parameter. Passing 1 results in\n  the same behaviour as zmq_socket_monitor.\n  Version 2 of the events protocol allows new events, new metadata, different\n  socket types for the monitors and more. It is described in details in\n  doc/zmq_socket_monitor_versioned.txt\n\n* New DRAFT (see NEWS for 4.2.0) zmq_socket_monitor_pipes_stats that triggers\n  a new ZMQ_EVENT_PIPES_STATS to be delivered via zmq_socket_monitor_versioned\n  v2 API, which contains the current status of all the queues owned by the\n  monitored socket. See doc/zmq_socket_monitor_versioned.txt for details.\n\n* New DRAFT (see NEWS for 4.2.0) zmq_poller_fd that returns the FD of a thread\n  safe socket. See doc/zmq_poller.txt for details.\n\n* New DRAFT (see NEWS for 4.2.0) socket options:\n  - ZMQ_XPUB_MANUAL_LAST_VALUE is similar to ZMQ_XPUB_MANUAL but allows to avoid\n    duplicates when using last value caching.\n  - ZMQ_SOCKS_USERNAME and ZMQ_SOCKS_PASSWORD that implement SOCKS5 proxy\n    authentication.\n  See doc/zmq_setsockopt.txt and doc/zmq_getsockopt.txt for details.\n\n* Implemented background thread names for Windows, when the Visual Studio\n  debugger is being used.\n\n* Fixed #3358 - test_security_zap failing due to SIGBUS on SPARC64, hard-coded\n                IPC socket binds in tests cause race conditions\n\n* Fixed #3361 - enabling GSSAPI support (when using autools) does not work due\n                to regression introduced in 4.2.3\n\n* Fixed #3362 - remove documentation for ZMQ_THREAD_PRIORITY context option\n                getter, it's not implemented\n\n* Fixed #3363 - tests fail to build due to stricter compiler printf validation\n                in new versions of GCC\n\n* Fixed #3367 - try to infer cacheline size at build time, first with\n                getconf LEVEL1_DCACHE_LINESIZE, and then by reading\n                /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size\n                (autoconf only), and only then falling back to the previous\n                default of 64 bytes. Avoids false sharing on POWER and s390x.\n                Import ax_func_posix_memalign.m4 as a more reliable check for\n                posix_memalign presence on some unix platforms.\n                Prefer c++11 atomic primitives to compiler intrinsics, when\n                both are available, as the former is more reliable.\n                Set test_pair_ipc and test_rebind_ipc to XFAIL on GNU/Hurd due\n                to non-functioning getsockname on AF_UNIX.\n\n* Fixed #3370 - Make queue length and HWM state observable\n\n* Fixed #3373 - performance regression in zmq_poll on CentOS 6/7\n\n* Fixed #3375 - assign names to all pthreads created by the library to ease\n                debugging\n\n* Fixed #3376 - assigned random TIPC port is not returned by ZMQ_LAST_ENDPOINT\n\n* Fixed #3385 - TCP port in ZMQ_LAST_ENDPOINT depends on global locale\n\n* Fixed #3404 - use std::condition_variable_any when possible\n\n* Fixed #3436 - reconnect interval exponential backoff and may lead to integer\n                overflows\n\n* Fixed #3440 - improve zmq_proxy performance by batching of up to 1000\n                consecutive messages (if any) and add perf/proxy_thr tool\n\n* Fixed #3451 - fix support of /dev/poll on Solaris\n\n* Fixed #3452 - strnlen may not be available\n\n* Fixed #1462 - test failure in test_filter_ipc due to invalid system groups\n\n* Fixed #3269 - Boost.ASIO integration stopped working with v4.3.0\n\n* Fixed #3479 - ZeroMQ does not build for QNX 6.6 with CMake\n\n* Fixed #3481 - add <ios> include to fix uClibc++ compilation\n\n* Fixed #3491 - build broken on Fedora 30\n\n* Fixed #3494 - ZeroMQConfig.cmake fails if shared libraries are not built\n\n* Fixed #3498 - syntax error on Windows related to socket descriptor type\n\n* Fixed #3500 - PLAIN HELLO message incorrectly uses WELCOME literal, regression\n                introduced in 4.3.0\n\n* Fixed #3517 - configure errors because of syntax errors in the use of test\n                shell command\n\n* Fixed #3521 - document how to achieve high performance with the PGM transport\n\n* Fixed #3526 - failure case behavior unclear in zmq_msg_send documentation\n\n* Fixed #3537 - fix build on z/OS by using pthread_equal instead of comparing\n                variables directly\n\n* Fixed #3546 - CMake links with librt on MinGW which is not available\n\n* Many coding style, duplication, testing and static analysis improvements.\n\n\n0MQ version 4.3.1 stable, released on 2019/01/12\n================================================\n\n* CVE-2019-6250: A vulnerability has been found that would allow attackers to\n  direct a peer to jump to and execute from an address indicated by the\n  attacker.\n  This issue has been present since v4.2.0. Older releases are not affected.\n  NOTE: The attacker needs to know in advance valid addresses in the peer's\n  memory to jump to, so measures like ASLR are effective mitigations.\n  NOTE: this attack can only take place after authentication, so peers behind\n  CURVE/GSSAPI are not vulnerable to unauthenticated attackers.\n  See https://github.com/zeromq/libzmq/issues/3351 for more details.\n  Thanks to Guido Vranken for uncovering the issue and providing the fix!\n\n* Note for packagers: as pkg-config's Requires.private is now used to properly\n  propagate dependencies for static builds, the libzmq*-dev or zeromq-devel or\n  equivalent package should now depend on the libfoo-dev or foo-devel packages\n  of all the libraries that zmq is linked against, or pkg-config --libs libzmq\n  will fail due to missing dependencies on end users machines.\n\n* Fixed #3351 - remote code execution vulnerability.\n\n* Fixed #3343 - race condition in ZMQ_PUSH when quickly disconnecting and\n                reconnecting causes last part of multi-part message to get\n                \"stuck\" and resent by mistake to the new socket.\n\n* Fixed #3336 - set Requires.private in generate pkg-config file.\n\n* Fixed #3334 - set TCP_NODELAY after connect() on Windows for the I/O socket.\n\n* Fixed #3326 - assert on Android when opening a socket and disabling WiFi.\n\n* Fixed #3320 - build failure on OpenBSD with GCC.\n\n0MQ version 4.3.0 stable, released on 2018/11/28\n================================================\n\n* The following DRAFT APIs have been marked as STABLE and will not change\n  anymore:\n  - ZMQ_MSG_T_SIZE context option (see doc/zmq_ctx_get.txt)\n  - ZMQ_THREAD_AFFINITY_CPU_ADD and ZMQ_THREAD_AFFINITY_CPU_REMOVE (Posix only)\n    context options, to add/remove CPUs to the affinity set of the I/O threads.\n    See doc/zmq_ctx_set.txt and doc/zmq_ctx_get.txt for details.\n  - ZMQ_THREAD_NAME_PREFIX (Posix only) context option, to add a specific\n    integer prefix to the background threads names, to easily identify them.\n    See doc/zmq_ctx_set.txt and doc/zmq_ctx_get.txt for details.\n  - ZMQ_GSSAPI_PRINCIPAL_NAMETYPE and ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE\n    socket options, for the corresponding GSSAPI features. Additional\n    definitions for principal name types:\n    - ZMQ_GSSAPI_NT_HOSTBASED\n    - ZMQ_GSSAPI_NT_USER_NAME\n    - ZMQ_GSSAPI_NT_KRB5_PRINCIPAL\n    See doc/zmq_gssapi.txt for details.\n  - ZMQ_BINDTODEVICE socket option (Linux only), which will bind the\n    socket(s) to the specified interface. Allows to use Linux VRF, see:\n    https://www.kernel.org/doc/Documentation/networking/vrf.txt\n    NOTE: requires the program to be ran as root OR with CAP_NET_RAW\n  - zmq_timers_* APIs. These functions can be used for cross-platforms timed\n    callbacks. See doc/zmq_timers.txt for details.\n  - The following socket monitor events:\n    - ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL: unknown errors during handshake.\n    - ZMQ_EVENT_HANDSHAKE_SUCCEEDED: Handshake completed with authentication.\n    - ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL: Protocol errors with peers or ZAP.\n    - ZMQ_EVENT_HANDSHAKE_FAILED_AUTH: Failed authentication requests.\n    See doc/zmq_socket_monitor.txt for more details and error codes.\n  - zmq_stopwatch_intermediate which returns the time elapsed without stopping\n    the stopwatch.\n  - zmq_proxy_steerable command 'STATISTICS' to retrieve stats about the amount\n    of messages and bytes sent and received by the proxy.\n    See doc/zmq_proxy_steerable.txt for more information.\n\n* The build-time configuration option to select the poller has been split, and\n  new API_POLLER (CMake) and --with-api-poller (autoconf) options will now\n  determine what system call is used to implement the zmq_poll/zmq_poller APIs.\n  The previous POLLER and --with-poller options now only affects the\n  internal I/O thread. In case API_POLLER is not specified, the behaviour keeps\n  backward compatibility intact and will be the same as with previous releases.\n\n* The non-default \"poll\" poller for the internal I/O thread (note: NOT for the\n  zmq_poll/zmq_poller user APIs!) has been disabled on Windows as WSAPoll does\n  not report connection failures. For more information see:\n  - https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/\n  - https://curl.haxx.se/mail/lib-2012-10/0038.html\n  - https://bugs.python.org/issue16507\n\n* New epoll implementation for Windows, using the following implementation:\n  https://github.com/piscisaureus/wepoll/tree/v1.5.4\n  To use this, select \"epoll\" as the poller option in the build system.\n  Note for distributors: the wepoll source code is embedded and distributed.\n  It is licensed under the BSD-2-Clause and thus it is compatible with LGPL-3.0.\n  Note that, if selected at build time, the license text must be distributed\n  with the binary in accordance to the license terms. A copy can be found at:\n  external/wepoll/license.txt\n\n* The pre-made Visual Studio solutions file are deprecated, and users are\n  encouraged to use the CMake solution generation feature instead.\n\n* New DRAFT (see NEWS for 4.2.0) socket options:\n  - ZMQ_ROUTER_NOTIFY to deliver a notification when a peer connects and/or\n    disconnects in the form of a routing id plus a zero-length frame.\n  - ZMQ_MULTICAST_LOOP to control whether the data sent should be looped back\n    on local listening sockets for UDP multicast sockets (ZMQ_RADIO).\n  See doc/zmq_setsockopt.txt and doc/zmq_getsockopt.txt for details.\n\n* New perf tool, perf/benchmark_radix_tree, to measure the performance of the\n  different internal implementations of the trie algorithm used to track\n  subscriptions. Requires a compiler that supports C++11.\n\n* New autoconf flag \"--enable-force-CXX98-compat\" which will force -std=gnu++98\n  and, if the compiler supports them (clang++ at the moment), it will also add\n  -Wc++98-compat -Wc++98-compat-pedantic so that compatibility with C++98 can\n  be tested.\n\n* Many, many coding style, duplication and static analysis improvements.\n\n* Many, many improvements to the CMake build system, especially on Windows.\n\n* Many, many improvements to unit tests.\n\n* Fixed #3036 - Compilation error when -pedantic is used.\n\n* Fixed #3028 - Failure when zmq_poller_destroy is called after zmq_ctx_term.\n\n* Fixed #2989 - CMake: Linker PDB install rule does not work when Visual Studio\n                generators are used.\n\n* Fixed #3045 - configure.ac: search for dladdr only when using libunwind.\n\n* Fixed #3060 - REQ sockets terminate TCP connection after first heartbeat if\n                ZMQ_HEARTBEAT_IVL is set.\n\n* Fixed #2212 - UDP: need ability to specify bind address separately from\n                multicast address for multi-homed hosts.\n\n* Fixed #2891 - UDP: address name resolution is limited to dotted IPv4 rather\n                than being capable of IPv4, IPv6, and hostname lookup.\n\n* Fixed #3085 - autoconf/CMake getrandom test does not check if it's working but\n                only for its presence.\n\n* Fixed #3090 - compilation broken with Solaris Studio.\n\n* Fixed #3094 - UDP: pass interface via IP[V6]_MULTICAST_IF if provided.\n\n* Fixed #3061 - implement ZMTP 3.1 ping/pong context sending/receiving.\n\n* Fixed #2188 - Added documentation for new zmq_poller API.\n\n* Fixed #3088 - zmq_poller_add/zmq_poller_modify should reject invalid events\n                arguments.\n\n* Fixed #3042 - Fixed compilation on ARM with ZMQ_ATOMIC_PTR_MUTEX.\n\n* Fixed #3107 - test_immediate_3/test_reconnect_inproc do not terminate with\n                POLL as the I/O thread poller under Windows.\n\n* Fixed #3046 - Aborts when iOS abuses EBADF to report a socket has been\n                reclaimed.\n\n* Fixed #3136 - Cannot set ZMQ_HEARTBEAT_TTL to more than 655.3 seconds.\n\n* Fixed #3083 - link with -latomic when needed.\n\n* Fixed #3162 - build failure with MUSL libc.\n\n* Fixed #3158 - -1 value of ZMQ_RECONNECT_IVL was not correctly handled on some\n                platforms.\n\n* Fixed #3170 - improved documentation for ZMQ_PAIR.\n\n* Fixed #3168 - correctly use symbols map on Debian/kFreeBSD and Debian/HURD\n                to avoid exporting standard library symbols.\n\n* Fixed #3168 - correctly process ZMTP 3.1 cancel/subscribe commands.\n\n* Fixed #3171 - improve documentation for ZMQ_CONFLATE.\n\n* Fixed #2876 - stack overflow on Windows 64.\n\n* Fixed #3191 - race condition with received message causes\n                ZMQ_CONNECT_ROUTING_ID to be assigned to wrong socket.\n\n* Fixed #3005 - added documentation for new zmq_timers_* API.\n\n* Fixed #3222 - use /Z7 debug on Release builds too on Windows (CMake).\n\n* Fixed #3226 - possible PGM receiver crash.\n\n* Fixed #3236 - UDP dish socket can't bind to a multicast port already in use.\n\n* Fixed #3242 - improve HWM documentation.\n\n* Fixed #2488 - improve zmq_msg_send doc return value documentation.\n\n* Fixed #3268 - HWM in ZMQ_DGRAM socket does not respect multipart message.\n\n* Fixed #3284 - added support for ZMQ_MULTICAST_HOPS with UDP sockets.\n\n* Fixed #3245 - use-after-free reported in zmq::pipe_t::terminate.\n\n* Fixed #1400 - use patricia trie for subscription to improve performances and\n                memory usage. Note: only active in DRAFT builds for now.\n\n* Fixed #3263 - fix abort on Windows when a large TCP read is requested and\n                fails.\n\n* Fixed #3312 - fix build on Android Things 1.06 with Termux.\n\n\n0MQ version 4.2.5 stable, released on 2018/03/23\n================================================\n\n* Fixed #3018 - fix backward-incompatible change in the NULL auth\n                mechanism that slipped in 4.2.3 and made connections\n                with a ZAP domain set on a socket but without a working\n                ZAP handler fail. See ZMQ_ZAP_ENFORCE_DOMAIN and RFC27.\n\n* Fixed #3016 - clarify in zmq_close manpage that the operation will\n                complete asynchronously.\n\n* Fixed #3012 - fix CMake build problem when using LIBZMQ_WERROR and a\n                compiler other than GCC.\n\n\n0MQ version 4.2.4 stable, released on 2018/03/21\n================================================\n\n* New DRAFT (see NEWS for 4.2.0) socket options:\n  - ZMQ_LOOPBACK_FASTPATH to enable faster TCP loopback on Windows\n  - ZMQ_METADATA to set application-specific metadata on a socket\n  See doc/zmq_setsockopt.txt and doc/zmq_getsockopt.txt for details.\n\n* New DRAFT (see NEWS for 4.2.0) context options:\n  - ZMQ_ZERO_COPY_RECV to disable zero-copy receive to save memory\n    at the expense of slower performance\n  See doc/zmq_ctx_set.txt and doc/zmq_ctx_get.txt for details.\n\n* New DRAFT API zmq_stopwatch_intermediate which returns the time\n  elapsed without stopping the stopwatch.\n\n* TIPC: support addressing TIPC Port Identity addresses.\n\n* Added CMake option to disable tests: BUILD_TESTS\n\n* Added CMake and autotools make targets to support clang-formatter:\n  make clang-format, clang-format-check and clang-format-diff to\n  help developers make sure their code conforms to the style guidelines\n\n* For distributors: a new test framework has been added, which\n  includes a copy of the Unity source code. This source code library is\n  distributed under the MIT license and thus is compatible with\n  libzmq's LGPL3.\n\n* Fixed #2867 - add ZeroMQConfig.cmake.in to distributable tarball\n\n* Fixed #2868 - fix OpenBSD build\n\n* Fixed #2870 - fix VC++ 11.0 (VS2012) build\n\n* Fixed #2879 - prevent duplicate connections on PUB sockets\n\n* Fixed #2872 - fix CMake tests on Windows\n\n* Fixed #2895 - fix assert on Windows with POLL\n\n* Fixed #2920 - fix Windows build with Intel compiler\n\n* Fixed #2930 - use std::atomic when available with VC++ and VS2015\n\n* Fixed #2910 - fix race condition with ZMQ_LINGER socket option\n\n* Fixed #2927 - add support for ZMQ_XPUB_NODROP on ZMQ_RADIO\n\n* Fixed #2820 - further clarify ZMQ_XPUB_VERBOSE(R) documentation.\n\n* Fixed #2911 - ZMQ_DISH over UDP triggers errno_assert() after hitting\n                watermark\n\n* Fixed #2942 - ZMQ_PUB crash when due to high volume of subscribe and\n                unsubscribe messages, an unmatched unsubscribe message is\n                received in certain conditions\n\n* Fixed #2946 - fix Windows CMake build when BUILD_SHARED is off\n\n* Fixed #2960 - fix build with GCC 8\n\n* Fixed #2967 - fix race condition on thread safe sockets due to pthread\n                condvar timeouts on OSX\n\n* Fixed #2977 - fix TIPC build-time availability check to be more relaxed\n\n* Fixed #2966 - add support for WindRiver VxWorks 6.x\n\n* Fixed #2963 - fix some PVS Studio static analysis warnings\n\n* Fixed #2983 - fix MinGW cross-compilation\n\n* Fixed #2991 - fix mutex assert at shutdown when the zmq context is part\n                of a class declared as a global static\n\n\n0MQ version 4.2.3 stable, released on 2017/12/13\n================================================\n\n* API change: previously ZMQ_POLLOUT on a ZMQ_ROUTER socket returned always\n  true due to how the type works. When ZMQ_ROUTER_MANDATORY is set, sending\n  fails when the peer is not available, but ZMQ_POLLOUT always returns true\n  anyway, which does not make sense. Now when ZMQ_ROUTER_MANDATORY is set,\n  ZMQ_POLLOUT on a ZMQ_ROUTER will return true only if at least one peer is\n  available.\n  Given ZMQ_POLLOUT with ZMQ_ROUTER was not usable at all previously, we do\n  not consider this a breakage warranting a major or minor version increase.\n\n* ZMQ_IDENTITY has been renamed to ZMQ_ROUTING_ID and ZMQ_CONNECT_RID has been\n  renamed to ZMQ_CONNTECT_ROUTING_ID to disambiguate. ZMQ_IDENTITY and\n  ZMQ_CONNECT_RID are still available to keep backward compatibility, and will\n  be removed in a future release after further advance notice.\n\n* DRAFT API change: zmq_poller_wait, zmq_poller_wait_all and zmq_poller_poll\n  have been changed to be inline with other existing APIs that have a timeout\n  to return EAGAIN instead of ETIMEDOUT as the errno value.\n  See #2713 for details.\n\n* Existing non-DRAFT socket types ZMQ_REP/REQ, ZMQ_ROUTER/DEALER and\n  ZMQPUB/SUB, that were previously declared deprecated, have been reinstated\n  as stable and supported. See #2699 for details.\n\n* Tweetnacl: add support for, and use preferably if available, getrandom() as\n  a simpler and less error-prone alternative to /dev/urandom on OSes where it\n  is available (eg: Linux 3.18 with glibc 2.25).\n\n* Curve: all remaining traces of debug output to console are now removed, and\n  new DRAFT events are available to properly debug CURVE, PLAIN, GSSAPI and\n  ZAP events and failures. See below for details on the new events.\n\n* New DRAFT (see NEWS for 4.2.0) socket options:\n  - ZMQ_GSSAPI_PRINCIPAL_NAMETYPE and ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE, for\n    the corresponding GSSAPI features. Additional definitions for principal\n    name types:\n    - ZMQ_GSSAPI_NT_HOSTBASED\n    - ZMQ_GSSAPI_NT_USER_NAME\n    - ZMQ_GSSAPI_NT_KRB5_PRINCIPAL\n    See doc/zmq_gssapi.txt for details.\n  - ZMQ_BINDTODEVICE (Linux only), which will bind the socket(s) to the\n    specified interface. Allows to use Linux VRF, see:\n    https://www.kernel.org/doc/Documentation/networking/vrf.txt\n    NOTE: requires the program to be ran as root OR with CAP_NET_RAW\n  - ZMQ_ZAP_ENFORCE_DOMAIN, enables strict RFC 27 compatibility mode and makes\n    the ZAP Domain mandatory when using security. See:\n    https://rfc.zeromq.org/spec:27/ZAP\n  See doc/zmq_setsockopt.txt and doc/zmq_getsockopt.txt for details.\n\n* New DRAFT (see NEWS for 4.2.0) context options:\n  - ZMQ_THREAD_AFFINITY_CPU_ADD and ZMQ_THREAD_AFFINITY_CPU_REMOVE (Posix only),\n    to add and remove CPUs to the affinity set of the I/O threads. Useful to pin\n    the background threads to specific CPUs.\n  - ZMQ_THREAD_NAME_PREFIX (Posix only), to add a specific integer prefix to the\n    background threads names, to easily identify them for debugging purposes.\n  See doc/zmq_ctx_set.txt and doc/zmq_ctx_get.txt for details.\n\n* New DRAFT (see NEWS for 4.2.0) message property name definitions to facilitate\n  the use of zmq_msg_gets:\n  - ZMQ_MSG_PROPERTY_ROUTING_ID\n  - ZMQ_MSG_PROPERTY_SOCKET_TYPE\n  - ZMQ_MSG_PROPERTY_USER_ID\n  - ZMQ_MSG_PROPERTY_PEER_ADDRESS\n  See doc/zmq_msg_gets.txt for details.\n\n* New DRAFT (see NEWS for 4.2.0) API zmq_socket_get_peer_state, to be used to\n  query the state of a specific peer (via routing-id) of a ZMQ_ROUTER socket.\n\n* New DRAFT (see NEWS for 4.2.0) Socket Monitor events:\n  - ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL, unknown system error and returns errno\n  - ZMQ_EVENT_HANDSHAKE_SUCCEEDED, handshake was successful\n  - ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, protocol errors between peers or server\n    and ZAP handler. Returns one of ZMQ_PROTOCOL_ERROR_* - see manpage for list\n  - ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, failed authentication, returns ZAP status\n  These events trigger when the ZMTP security mechanism handshake is\n  completed or failed. See doc/zmq_socket_monitor.txt for more information.\n\n* New DRAFT (see NEWS for 4.2.0) zmq_proxy_steerable command 'STATISTICS' to\n  retrieve stats about the amount of messages and bytes sent and received by\n  the proxy. See doc/zmq_proxy_steerable.txt for more information.\n\n* Add new autoconf --disable-libunwind option to stop building with libunwind\n  even if it is available.\n\n* Add new autoconf --disable-Werror option to avoid building with the Werror\n  flag.\n\n* Use pkg-config as the first method for finding and building with external\n  optional dependencies such as libnorm, libpgm and gssapi.\n\n* On Posix platform where the feature is available, name the ZMQ background\n  threads to simplify debugging: \"ZMQbg/<num_thread>\"\n\n* Improve performance of zmq_poller_* (and zmq_poll and zmq_proxy when building\n  with DRAFT APIs enabled).\n\n* The TCP unit tests have been refactored to bind and connect to random ports\n  rather than hard-coded ones, to allow running tests in parallel.\n  There are 6 exceptions where it is necessary to use an hard-coded port to\n  test specific code paths that would not be exercised when binding to a\n  wildcard port. These are listed in tests/testutil.hpp so that distributions\n  can easily patch them if they wish to and so that they can be unique across\n  all the tests, allowing parallel runs.\n  The IPC unit tests have been changed as well to use unique socket file names\n  per test, where before there were some clashes.\n\n* Fixed #2349 - fix building with libsodium when using CMake\n\n* Fixed #2334 - do not assert when tuning socket options fails due to network\n  errors, but simply retry again when connecting or send a socket monitor\n  ZMQ_EVENT_ACCEPT_FAILED event when binding\n\n* Fixed #2341 - fix source files path in VS2015 solution\n\n* Fixed #2344 - Note that on Windows with VS2012 it is mandatory to increase\n  the default stack size to at least 2MB\n\n* Fixed #2348 - ZMQ_ROUTER send with ZMQ_ROUTER_MANDATORY can be stuck in case of\n  network problem\n\n* Fixed #2358 - occasional abort on zmq_connect on Windows\n\n* Fixed #2370 - zmq_curve_keypair should return an error on failure rather\n  than ignoring them and always returning 0\n\n* Fixed #2452 - __STDC_LIMIT_MACROS before precompiled headers causes VC++\n  warning\n\n* Fixed #2457 - fix building with libsodium in Visual Studio solutions\n\n* Fixed #2466 - add const qualifier to internal and public API that does not\n  modify parameters\n\n* Fixed #2471 - do more checks for OOM conditions when dynamic allocations is\n  used\n\n* Fixed #2476 - assertion causes abort after ZAP stop at shutdown\n\n* Fixed #2479 - improve zmq_poller performance on Windows\n\n* Fixed #2481 - potential memory leaks due to ZMTP handshake failures\n\n* Fixed #2531 - ZMQ_GSSAPI_PRINCIPAL sockopt has no effect on client side\n\n* Fixed #2535 - add BUILD_SHARED and BUILD_STATIC options to CMake, both on by\n  default, to toggle shared and static library builds\n\n* Fixed #2537 - use SYSTEM_CLOCK on OSX and CLOCK_MONOTONIC elsewhere for\n  internal timers to avoid races\n\n* Fixed #2540 - new zmq_poller used by zmq_poll without DRAFTs\n\n* Fixed #2552 - Fix WITH_DOC CMake build to avoid checking for asciidoc if the\n  option is disabled\n\n* Fixed #2567 - Memory leak in REP socket handling\n\n* Fixed #2579 - Compilation issue on Windows with CMake + ninja\n\n* Fixed #2588 - SIGBUS under 64-bit SunOS Sparc\n\n* Fixed #2590 - crash when using ZMQ_IMMEDIATE and ZMQ_LINGER to non-zero\n\n* Fixed #2601 - XPUB_MANUAL subscriptions not removed on peer term\n\n* Fixed #2602 - intermittent memory leak for ZMQ_REQ/REP send/recv\n\n* Fixed #2608 - CURVE server (connect) fails when client rebinds\n\n* Fixed #2610 - print backtraces in mutual exclusion to avoid mixing\n  different traces\n\n* Fixed #2621 - add missing CMake files to distributable tarball\n\n* Fixed #2630 - improve compatibility with OpenBSD w.r.t. IPV6_V6ONLY\n\n* Fixed #2638 - note in INSTALL that when using Windows builds on Linux with\n  Wine it is necessary to increase the minimum TCP buffers\n\n* Fixed #2632 - Fix file descriptor leak when using Tweetnacl (internal NACL\n  implementation) instead of Libsodium, and fix race condition when using\n  multiple ZMQ contexts with Tweetnacl\n\n* Fixed #2681 - Possible buffer overflow in CURVE mechanism handshake.\n  NOTE: this was protected by an assert previously, so there is no security\n  risk.\n\n* Fixed #2704 - test_sockopt_hwm fails occasionally on Windows\n\n* Fixed #2701 - pgm build via cmake doesn't link libzmq with libpgm\n\n* Fixed #2711 - ZAP handler communication errors should be handled consistently\n\n* Fixed #2723 - assertion in src\\select.cpp:111 or hang on zmq_ctx_destroy on\n  Windows\n\n* Fixed #2728 - fix support O_CLOEXEC when building with CMake\n\n* Fixed #2761 - improve compatibility with TrueOS (FreeBSD 12)\n\n* Fixed #2764 - do not unlink IPC socket files when closing a socket to avoid\n  race conditions\n\n* Fixed #2770 - support lcov 1.13 and newer\n\n* Fixed #2787 - add libiphlpapi to PKGCFG_LIBS_PRIVATE for static mingw builds\n\n* Fixed #2788 - document that adding -DZMQ_STATIC is required for Windows\n  static builds with Mingw\n\n* Fixed #2789 - description of zmq_atomic_counter_value return value is cloned\n  from zmq_atomic_counter_new\n\n* Fixed #2791 - fix building with DRAFT APIs on CentOS 6\n\n* Fixed #2794 - router_t methods should not allocate memory for lookup in\n  outpipes\n\n* Fixed #2809 - optimize select() usage on Windows\n\n* Fixed #2816 - add CMake and autoconf check for accept4, as it is not\n  available on old Linux releases, and fallback to accept + FD_CLOEXEC\n\n* Fixed #2824 - ZMQ_REQ socket does not report ZMQ_POLLOUT when ZMQ_REQ_RELAXED\n  is set\n\n* Fixed #2827 - add support for Haiku\n\n* Fixed #2840 - fix building with VS2008\n\n* Fixed #2845 - correct the ZMQ_LINGER documentation to accurately reflect that\n  the default value is -1 (infinite). It never was 30 second in any released\n  version, it was only changed briefly and then changed back, but the manpage\n  was not reverted.\n\n* Fixed #2861 - CMake/MSVC: export ZMQ_STATIC when needed.\n\n0MQ version 4.2.2 stable, released on 2017/02/18\n=============================================\n\n* Improve compatibility with GNU Hurd\n\n* Fixed #2286 - improve CMake on Windows documentation\n\n* Fixed #1235 - improved compatibility with mingw64\n\n* Improve zmq_proxy documentation to state it can return ETERM as well\n\n* Fixed #1442 - SO_NOSIGPIPE and connection closing by peer race condition\n\n* Improve CMake functionality on Windows: ZeroMQConfig.cmake generation CPack\n  option, correct static library filename, ship FindSodium.cmake in tarball\n\n* Fixed #2228 - setting HWM after connect on inproc transport leads to infinite\n  HWM\n\n* Add support for Visual Studio 2017\n\n* New DRAFT (see NEWS for 4.2.0) zmq_has option \"draft\" option that returns\n  true if the library was built with DRAFT enabled. Useful for FFI bindings.\n  See doc/zmq_has.txt for more information\n\n* Fixed #2321 - zmq_z85_decode does not validate its input. The function has\n  been fixed to correctly follow RFC32 and return NULL if the input is invalid\n\n* Fixed #2323 - clock_t related crash on Apple iOS 9.3.2 and 9.3.5\n\n* Fixed #1801 - OSX: Cmake installs libzmq in a weird PATH\n\n* Fixed potential divide by zero in zmq::lb_t::sendpipe\n\n* Improve compatibility with OpenIndiana by skipping epoll and using poll/select\n\n* Fix IPv4-in-IPv6 mapped addresses parsing error\n\n\n0MQ version 4.2.1 stable, released on 2016/12/31\n=============================================\n\n* New DRAFT (see NEWS for 4.2.0) Socket Monitor events:\n  - ZMQ_EVENT_HANDSHAKE_SUCCEED\n  - ZMQ_EVENT_HANDSHAKE_FAILED\n  These events trigger when the ZMTP security mechanism handshake is\n  completed. See doc/zmq_socket_monitor.txt for more information.\n\n* New DRAFT (see NEWS for 4.2.0) Context options:\n  - ZMQ_MSG_T_SIZE\n  See doc/zmq_ctx_get.txt for more information.\n\n* Fixed #2268 - improved compatibility with mingw32\n\n* Fixed #2254 - ZMQ_PUB compatibility with libzmq 2.x broken\n\n* Fixed #2245 - added support for VS2017, Windows SDK 10.0.14393.0, toolset v141\n\n* Fixed #2242 - file descriptors leaks on fork+exec\n\n* Fixed #2239 - retired poller item crash from reaper thread\n\n* Fixed #2234 - improved compatibility with AIX 7.1\n\n* Fixed #2225 - cannot pick select for poller\n\n* Fixed #2217 - CMake build uses library version as the ABI version\n\n* Fixed #2208 - added support for ZMQ_TOS on IPv6\n\n* Fixed #2200 - no documentation for ZMQ_SOCKS_PROXY\n\n* Fixed #2199 - no documentation for zmq_curve_public\n\n* Fixed #2196 - fixed build and runtime errors on kFreeBSD\n\n\n0MQ version 4.2.0 stable, released on 2016/11/04\n=============================================\n\n* For Pieter. Thanks for making all of this possible.\n\n  \"Tell them I was a writer.\n   A maker of software.\n   A humanist. A father.\n   And many things.\n   But above all, a writer.\n   Thank You. :)\"\n   - Pieter Hintjens\n\n* This release introduces new APIs, but it is ABI compatible with\n  libzmq 4.1.2 and up.\n\n* Note for ARM and SPARC users: an alignment problem in zmq_msg_t that could in\n  some cases and on some CPUs cause a SIGBUS error was solved, but it requires\n  a rebuild of your application against the 4.2.0 version of include/zmq.h.\n  To clarify, this change does not affect the internals of the library but only\n  the public definition of zmq_msg_t, so there is no ABI incompatibility.\n\n* Security with Curve is now available by default thanks to Tweetnacl sources:\n  https://tweetnacl.cr.yp.to/index.html\n  Libsodium is still fully supported but has to be enabled with the build flag\n  --with-libsodium. Distribution and package maintainers are encouraged to use\n  libsodium so that the security implementation can be audited and maintained\n  separately.\n\n* New Context options:\n  - ZMQ_MAX_MSGSZ\n  - ZMQ_BLOCKY\n  See doc/zmq_ctx_set.txt and doc/zmq_ctx_get.txt for details.\n\n* New Socket options:\n  - ZMQ_HANDSHAKE_IVL\n  - ZMQ_SOCKS_PROXY\n  - ZMQ_XPUB_NODROP\n  - ZMQ_XPUB_MANUAL\n  - ZMQ_XPUB_WELCOME_MSG\n  - ZMQ_STREAM_NOTIFY\n  - ZMQ_INVERT_MATCHING\n  - ZMQ_HEARTBEAT_IVL\n  - ZMQ_HEARTBEAT_TTL\n  - ZMQ_HEARTBEAT_TIMEOUT\n  - ZMQ_XPUB_VERBOSER\n  - ZMQ_CONNECT_TIMEOUT\n  - ZMQ_TCP_MAXRT\n  - ZMQ_THREAD_SAFE\n  - ZMQ_MULTICAST_MAXTPDU\n  - ZMQ_VMCI_BUFFER_SIZE\n  - ZMQ_VMCI_BUFFER_MIN_SIZE\n  - ZMQ_VMCI_BUFFER_MAX_SIZE\n  - ZMQ_VMCI_CONNECT_TIMEOUT\n  - ZMQ_USE_FD\n  See doc/zmq_setsockopt.txt and doc/zmq_getsockopt.txt for details.\n\n* New CURVE helper function to derive z85 public key from secret key:\n    zmq_curve_public\n\n* New cross-platform atomic counter helper functions:\n    zmq_atomic_counter_new, zmq_atomic_counter_set, zmq_atomic_counter_inc,\n    zmq_atomic_counter_dec, zmq_atomic_counter_value, zmq_atomic_counter_destroy\n  See doc/zmq_atomic_*.txt for details.\n\n* New DRAFT APIs early-release mechanism. New APIs will be introduced early\n  in public releases, and until they are stabilized and guaranteed not to\n  change anymore they will be unavailable unless the new build flag\n  --enable-drafts is used. This will allow developers and early adopters to\n  test new APIs before they are finalized.\n  NOTE: as the name implies, NO GUARANTEE is made on the stability of these APIs.\n  They might change or disappear entirely. Distributions are recommended NOT to\n  build with them.\n\n  New socket types have been introduced in DRAFT state:\n    ZMQ_SERVER, ZMQ_CLIENT, ZMQ_RADIO, ZMQ_DISH, ZMQ_GATHER, ZMQ_SCATTER,\n    ZMQ_DGRAM\n  All these sockets are THREAD SAFE, unlike the existing socket types. They do\n  NOT support multipart messages (ZMQ_SNDMORE/ZMQ_RCVMORE).\n  ZMQ_RADIO, ZMQ_DISH and ZMQ_DGRAM also support UDP as transport,\n  both unicast and multicast. See doc/zmq_udp.txt for more details.\n  New methods to support the new socket types functionality:\n    zmq_join, zmq_leave, zmq_msg_set_routing_id, zmq_msg_routing_id,\n    zmq_msg_set_group, zmq_msg_group\n  See doc/zmq_socket.txt for more details.\n\n  New poller mechanism and APIs have been introduced in DRAFT state:\n    zmq_poller_new, zmq_poller_destroy, zmq_poller_add, zmq_poller_modify,\n    zmq_poller_remove, zmq_poller_wait, zmq_poller_wait_all, zmq_poller_add_fd\n    zmq_poller_modify_fd, zmq_poller_remove_fd\n  and a new supporting struct typedef: zmq_poller_event_t\n  They support existing socket type, new thread-safe socket types and file\n  descriptors (cross-platform).\n  Documentation will be made available in the future before these APIs are declared\n  stable.\n\n  New cross-platform timers helper functions have been introduced in DRAFT state:\n    zmq_timers_new, zmq_timers_destroy, zmq_timers_add, zmq_timers_cancel,\n    zmq_timers_set_interval, zmq_timers_reset, zmq_timers_timeout,\n    zmq_timers_execute\n  and a new supporting callback typedef: zmq_timer_fn\n\n* Many, many bug fixes. The most important fixes are backported and captured in the\n  4.1.x and 4.0.x changelogs.\n\n\n0MQ version 4.2.0 rc1, released on 2016/11/01\n=============================================\n\n* Many changes, see ChangeLog.\n\n\n0MQ version 4.1.6 stable, released on 2016/11/01\n================================================\n\n* Fixed #2051 - getifaddrs can fail with ECONNREFUSED\n\n* Fixed #2091 - testutil.hpp fails to build on Windows XP\n\n* Fixed #2096 - add tests/CMakeLists.in and version.rc.in to dist tar\n\n* Fixed #2107 - zmq_connect with IPv6 \"source:port;dest:port\" broken\n\n* Fixed #2117 - ctx_term assert with inproc zmq_router connect-before-bind\n\n* Fixed #2158 - Socket monitor uses internal Pair from multiple threads\n\n* Fixed #2161 - messages dropped due to HWM race\n\n* Fixed #1325 - alignment issue with zmq_msg_t causes SIGBUS on SPARC and ARM\n\n\n0MQ version 4.1.5 stable, released on 2016/06/17\n================================================\n\n* Fixed #1673 - CMake on Windows put PDB in wrong directory.\n\n* Fixed #1723 - Family is not set when resolving NIC on Android.\n\n* Fixed #1608 - Windows 7 TCP slow start issue.\n\n* Fixed #1806 - uninitialised read in curve getsockopt.\n\n* Fixed #1807 - build broken with GCC 6.\n\n* Fixed #1831 - potential assertion failure with latest libsodium.\n\n* Fixed #1850 - detection issues with tweetnacl/libsodium.\n\n* Fixed #1877 - Avoid terminating connections prematurely\n\n* Fixed #1887 - zmq_bind IPv4 fallback still tries IPv6\n\n* Fixed #1866 - fails to build on SunOS 5.10 / Solaris 10\n\n* Fixed #919 - ZMQ_LINGER (related to #1877)\n\n* Fixed #114 - cannot unbind with same endpoint with IPv6 enabled.\n\n* Fixed #1952 - CMake scripts not part of release tarballs\n\n* Fixed #1542 - Fix a crash on Windows when port 5905 is in use.\n\n* Fixed #2021 - Fix building on sparc32.\n\n\n0MQ version 4.1.4 stable, released on 2015/12/18\n================================================\n\n* Fixed #1315 - socket monitor hangs if bind/setsockopt failed.\n\n* Fixed #1399 - assertion failure in tcp.cpp after network reconnect.\n\n* Fixed #1632 - build failure using latest libsodium.\n\n* Fixed #1644 - assertion failure in msg.cpp:390 on STREAM sockets.\n\n* Fixed #1661 - does not handle IPv6 link local addresses.\n\n\n0MQ version 4.1.3 stable, released on 2015/08/17\n================================================\n\n* Fixed #1532 - getsockopt ZMQ_RCVMORE now resets all bits instead of only 32\n\n* Fixed #1445 - zmq::socket_base_t::connect fails on tcp ipv6 address\n\n\n0MQ version 4.1.2 stable, released on 2015/06/15\n================================================\n\n* Added explicit reference to static link exception in every source file.\n\n* Bumped ABI version to 5:0:0 since 4.1.x changed the ABI.\n\n* Fixed STDINT event interface macros to work with CZMQ 3.0.\n\n* Fixed installation of man pages when BUILD_DOC is not set.\n\n* Fixed #1428 - regression on single-socket proxies.\n\n\n0MQ version 4.1.1 stable, released on 2015/06/02\n================================================\n\n* Fixed #1208 - fix recursion in automake packaging.\n\n* Fixed #1224 - crash when processing empty unsubscribe message.\n\n* Fixed #1213 - properties files were missing from source packages.\n\n* Fixed #1273 - V3 protocol handler vulnerable to downgrade attacks.\n\n* Fixed #1347 - lack way to get peer address.\n\n* Fixed #1362 - SUB socket sometimes fails to resubscribe properly.\n\n* Fixed #1377, #1144 - failed with WSANOTINITIALISED in some cases.\n\n* Fixed #1389 - PUB, PUSH sockets had slow memory leak.\n\n* Fixed #1382 - zmq_proxy did not terminate if there were no readers.\n\n\n0MQ version 4.1.0 rc1, released on 2014/10/14\n=============================================\n\n* All issues that were fixed in 4.0.x\n\n* Improved client reconnection strategy on errors\n\n* GSSAPI security mechanism\n\n* SOCKS5 support (ZMQ_SOCKS_PROXY)\n\n* ZMQ_ROUTER_HANDOVER\n\n* ZMQ_TOS\n\n* ZMQ_CONNECT_RID\n\n* ZMQ_HANDSHAKE_IVL\n\n* ZMQ_IDENTITY_FD\n\n* ZMQ_XPUB_NODROP\n\n* ZMQ_SRCFD and ZMQ_SHARED message options\n\n* Message metadata -- zmq_msg_gets ()\n\n* Probe library configuration -- zmq_has ()\n\n\n0MQ version 4.0.8 stable, released on 2016/06/17\n================================================\n\n* Fixed LIBZMQ-949 - zmq_unbind fails for inproc and wildcard endpoints\n\n* Fixed #1806 - uninitialised read in curve getsockopt.\n\n* Fixed #1807 - build broken with GCC 6.\n\n* Fixed #1877 - Avoid terminating connections prematurely\n\n* Fixed #1887 - zmq_bind IPv4 fallback still tries IPv6\n\n* Fixed #98 - don't require libssp without libsodium on Solaris\n\n* Fixed #919 - ZMQ_LINGER (related to #1877)\n\n* Fixed #139 - \"tempnam\" is deprecated.\n\n\n0MQ version 4.0.7 stable, released on 2015/06/15\n================================================\n\n* Fixed #1428 - regression on single-socket proxies.\n\n\n0MQ version 4.0.6 stable, released on 2015/06/02\n================================================\n\n* Fixed #1273 - V3 protocol handler vulnerable to downgrade attacks.\n\n* Fixed #1362 - SUB socket sometimes fails to resubscribe properly.\n\n* Fixed #1377, #1144 - failed with WSANOTINITIALISED in some cases.\n\n* Fixed #1389 - PUB, PUSH sockets had slow memory leak.\n\n* Fixed #1382 - zmq_proxy did not terminate if there were no readers.\n\n\n0MQ version 4.0.5 stable, released on 2014/10/14\n================================================\n\n* Fixed #1191; CURVE mechanism does not verify short term nonces.\n\n* Fixed #1190; stream_engine is vulnerable to downgrade attacks.\n\n* Fixed #1088; assertion failure for WSAENOTSOCK on Windows.\n\n* Fixed #1015; race condition while connecting inproc sockets.\n\n* Fixed #994; bump so library number to 4.0.0\n\n* Fixed #939, assertion failed: !more (fq.cpp:99) after many ZAP requests.\n\n* Fixed #872; lost first part of message over inproc://.\n\n* Fixed #797, keep-alive on Windows.\n\n\n0MQ version 4.0.4 stable, released on 2014/03/10\n================================================\n\nBug Fixes\n---------\n\n* Fixed #909; out of tree build issue on Linux.\n\n* Fixed #888; hangs on terminate when inproc connected but never bound.\n\n* Fixed #868; assertion failure at ip.cpp:137 when using port scanner.\n\n* Fixed #818; fix timestamp counter on s390/s390x.\n\n* Fixed #817; only export zmq_* symbols.\n\n* Fixed #797; fixed setting TCP keepalive on Windows.\n\n* Fixed #775; compile error on Windows.\n\n* Fixed #763; when talking to a ZMTP v1 peer (libzmq 2.2), a socket would\n  send an extra identity frame at the start of the connection.\n\n* Fixed LIBZMQ-576 - Crash closing a socket after zmq_msg_send returns\n  EAGAIN (reverts LIBZMQ-497)\n\n* Fixed LIBZMQ-584; subscription filters getting lost on reconnection.\n\n\n0MQ version 4.0.3 stable, released on 2013/11/24\n================================================\n\nBug Fixes\n---------\n\n* Fixed test_many_sockets case, which failed when process socket limit\n  was 1024.\n\n\n0MQ version 4.0.2 stable, released on 2013/11/24\n================================================\n\nBug Fixes\n---------\n\n* Fixed LIBZMQ-583 - improved low-res timer for Windows\n* Fixed LIBZMQ-578 - z85_decode was extremely slow\n* Fixed LIBZMQ-577 - fault in man pages.\n* Fixed LIBZMQ-574 - assertion failure when ran out of system file handles\n* Fixed LIBZMQ-571 - test_stream failing in some cases\n* Fixed LIBZMQ-569 - Socket server crashes with random client data and when\n  talking to 2.2 versions\n* Fixed LIBZMQ-39 - Bad file descriptor during shutdown\n* Pulled expected failing test_linger.cpp from release\n* Reduced pause time in tests to allow \"make check\" to run faster\n\n\n0MQ version 4.0.1 stable, released on 2013/10/08\n================================================\n\nChanges\n-------\n\n* Updated CURVE mechanism to track revised RFC 27 (INITIATE vouch).\n\n  The INITIATE command vouch box is Box[C',S](C->S') instead of\n  Box[C'](C->S), to reduce the risk of client impersonation, as per\n  https://codesinchaos.wordpress.com/2012/09/09/curvecp-1/.\n\n* Fixed LIBZMQ-567, adding abstract namespaces for IPC sockets on Linux.\n\n  Converts an initial strudel or \"at sign\" (@) in the Unix socket path to\n  a NULL character ('\\0') indicating that the socket uses the abstract\n  namespace instead of the filesystem namespace.  For instance, binding a\n  socket to 'ipc://@/tmp/tester' will not create a file associated with\n  the socket whereas binding to 'ipc:///tmp/tester' will create the file\n  /tmp/tester. See issue 567 for more information.\n\n* Added zmq_z85_encode and zmq_z85_decode to core libzmq API.\n\n* Added zmq_curve_keypair to core libzmq API.\n\n* Bumped library ABI version to 4:0:1.\n\nBug fixes\n---------\n\n* Fixed some build/test errors on OS/X + Clang++.\n\n* Fixed LIBZMQ-565, typo in code.\n\n* Fixed LIBZMQ-566, dealer-to-router connections sometimes failing.\n\n* Fixed builds for AIX, MSVC 2008, OS/X with clang++, Solaris.\n\n* Improved CURVE handshake error handling.\n\n\n0MQ version 4.0.0 (RC1), released on 2013/09/20\n===============================================\n\nMajor changes\n-------------\n\n* New wire level protocol, ZMTP/3.0, see http://rfc.zeromq.org/spec:23.\n  Does not yet implement the SUBSCRIBE, CANCEL, PING, and PONG commands.\n  \n* New security framework, from plain user+password to strong encryption, \n  see section below. See http://hintjens.com/blog:49 for a tutorial.\n  \n* New ZMQ_STREAM socket type for working as a TCP client or server. See: \n  tests/test_stream.cpp.\n  \nImprovements\n------------\n\n* You can now connect to an inproc:// endpoint that does not already\n  exist. This means inproc:// no longer needs careful set-up, but it may\n  break code that relied on the old behaviour. See: \n  tests/test_inproc_connect.cpp.\n \n* Libzmq now checks socket types at connection time, so that trying to \n  connect a 'wrong' socket type will fail.\n  \n* New zmq_ctx_shutdown API method will shutdown a context and send ETERM\n  to blocking calls, without blocking. Use zmq_ctx_term to finalise the\n  process.\n  \n* The regression test suite has been significantly extended and improved.\n  \n* Contexts can now be terminated in forked child processes. See: \n  tests/test_fork.cpp.\n  \n* zmq_disconnect now respects the linger setting on sockets.\n\n* New zmq_send_const API method to send constant data (without copying).\n  See: tests/test_inproc_connect.cpp.\n  \n* Added CMake support for static libraries.\n\n* Added test cases for socket semantics as defined in RFCs 28, 29, 30, 31.\n  See: tests/test_spec_*.cpp.\n\n* New socket option, ZMQ_PROBE_ROUTER triggers an empty message on connect.\n  See: tests/test_probe_router.cpp.\n  \n* New socket option, ZMQ_REQ_CORRELATE allows for correlation of replies \n  from a REP socket. See: tests/test_req_correlate.cpp.\n  \n* New socket option, ZMQ_REQ_RELAXED, lets you disable the state machine \n  on a REQ socket, so you can send multiple requests without waiting for \n  replies, and without getting an EFSM error. See: \n  tests/test_req_relaxed.cpp.\n  \n* New socket option, ZMQ_CONFLATE restricts the outgoing and incoming \n  socket buffers to a single message. See: tests/test_conflate.cpp.\n\nDeprecated Options\n------------------\n\n* ZMQ_IPV4ONLY deprecated and renamed to ZMQ_IPV6 so that options are\n  consistently \"off\" by default. \n\n* ZMQ_DELAY_ATTACH_ON_CONNECT deprecated, and renamed to ZMQ_IMMEDIATE.\n  See: tests/test_immediate.cpp.\n\nSecurity Framework\n------------------\n\nBased on new ZMTP wire level protocol that negotiates a security \n\"mechanism\" between client and server before exchanging any other data.\n\nSecurity mechanisms are extensible. ZMTP defines three by default:\n\n* NULL - classic ZeroMQ, with no authentication. See \n  http://rfc.zeromq.org/spec:23.\n  \n* PLAIN - plain-text username + password authentication. See\n  http://rfc.zeromq.org/spec:24.\n\n* CURVE - secure authentication and encryption based on elliptic curve \n  cryptography, using the Curve25519 algorithm from Daniel Bernstein and \n  based on CurveCP's security handshake. See http://rfc.zeromq.org/spec:25, \n  http://rfc.zeromq.org/spec:26, and http://curvecp.org.\n  \nAuthentication is done by pluggable \"authenticators\" that connect to libzmq\nover an inproc endpoint, see http://rfc.zeromq.org/spec:27.\n\nSocket options to configure PLAIN security on client or server:\n\n* ZMQ_PLAIN_SERVER, ZMQ_PLAIN_USERNAME, ZMQ_PLAIN_PASSWORD. See \n  tests/test_security_plain.\n  \nSocket options to configure CURVE security on client or server:\n\n* ZMQ_CURVE_SERVER, ZMQ_CURVE_PUBLICKEY, ZMQ_CURVE_SECRETKEY, \n  ZMQ_CURVE_SERVERKEY. See tests/test_security_curve.cpp.\n  \nSocket options to configure \"domain\" for ZAP handler:\n \n* ZMQ_ZAP_DOMAIN, see tests/test_security_null.cpp.\n\nSupport for encoding/decoding CURVE binary keys to ASCII:\n\n* zmq_z85_encode, zmq_z85_decode.\n\nOther issues addressed in this release\n--------------------------------------\n\n* LIBZMQ-525 Multipart upstreaming from XSUB to XPUB\n\n\n0MQ version 3.2.4 stable, released on 2013/09/20\n================================================\n\n* LIBZMQ-84  (Windows) Assertion failed: Address already in use at signaler.cpp:80\n* LIBZMQ-456 ZMQ_XPUB_VERBOSE does not propagate in a tree of XPUB/XSUB devices\n* LIBZMQ-532 (Windows) critical section not released on error\n* LIBZMQ-569 Detect OpenPGM 5.2 system library\n* LIBZMQ-563 Subscribers sometimes stopped receiving messages (aka LIBZMQ-541)\n* LIBZMQ-XXX Added support for Travis Continuous Integration\n* LIBZMQ-XXX Several improvements to MSVC support\n\n\n0MQ version 3.2.3 stable, released on 2013/05/02\n================================================\n\nIssues addressed in this release\n--------------------------------\n\n* LIBZMQ-526 Assertion failure \"Invalid argument (tcp_connecter.cpp:285)\"\n* LIBZMQ-446 Setting the DSCP bits by default causes CAP_NET_ADMIN error\n* LIBZMQ-496 Crash on heavy socket opening/closing: Device or resource busy (mutex.hpp:90)\n* LIBZMQ-462 test_connect_delay fails at test_connect_delay.cpp:80\n* LIBZMQ-497 Messages getting dropped\n* LIBZMQ-488 signaler.cpp leaks the win32 Event Handle\n* LIBZMQ-476 zmq_disconnect has no effect for inproc sockets\n* LIBZMQ-475 zmq_disconnect does not sent unsubscribe messages\n\n\n0MQ version 3.2.2 stable, released on 2012/11/23\n================================================\n\nIssues addressed in this release\n--------------------------------\n\n* LIBZMQ-384 No meta data for ZMQ_EVENT_DISCONNECTED monitor event\n* LIBZMQ-414 Error in ARM/Thumb2 assembly (atomic_ptr.hpp)\n* LIBZMQ-417 zmq_assert (!incomplete_in) in session_base.cpp 228\n* LIBZMQ-447 socket_base_t::recv() packet loss and memory leak at high receiving rate\n* LIBZMQ-448 Builds fail on older versions of GCC\n* LIBZMQ-449 Builds fail on AIX\n* LIBZMQ-450 lt-test_monitor: fails with assertion at test_monitor.cpp:81\n* LIBZMQ-451 ZMQ_ROUTER_MANDATORY blocks forever\n* LIBZMQ-452 test_connect_delay.cpp:175:12: error: 'sleep' was not declared in this scope\n* LIBZMQ-458 lt-test_router_mandatory fails with assertion at test_router_mandatory.cpp:53\n* LIBZMQ-459 Assertion failed: encoder (stream_engine.cpp:266\n* LIBZMQ-464 PUB socket with HWM set leaks memory\n* LIBZMQ-465 PUB/SUB results in 80-90% of CPU load\n* LIBZMQ-468 ZMQ_XPUB_VERBOSE & unsubscribe\n* LIBZMQ-472 Segfault in zmq_poll in REQ to ROUTER dialog\n\n\n0MQ version 3.2.1 (RC2), released on 2012/10/15\n===============================================\n\nIssues addressed in this release\n--------------------------------\n\n* Fixed issue xxx - handle insufficient resources on accept() properly.\n* Fixed issue 443 - added ZMQ_XPUB_VERBOSE setsocket option.\n* Fixed issue 433 - ZeroMQ died on receiving EPIPE\n* Fixed issue 423 - test_pair_tcp hangs\n* Fixed issue 416 - socket_base: fix 'va_list' has not been declared error\n* Fixed issue 409 - Pub-sub interoperability between 2.x and 3.x.\n* Fixed issue 404 - zmq_term can not safely be re-entered with pgm transport\n* Fixed issue 399 - zmq_ctx_set_monitor callback is not works properly\n* Fixed issue 393 - libzmq does not build on Android (socklen_t signed comparison)\n* Fixed issue 392 - Interaction with pyzmq on Android\n* Fixed issue 389 - Assertion failure in mtrie.cpp:317\n* Fixed issue 388 - tests/test_monitor.cpp has no newline at EOF (causes compile error)\n* Fixed issue 387 - \"sa_family_t sa_family;\" in pgm_socket.cpp is unused variable\n* Fixed issue 385 - Rework ZMQ_FAIL_UNROUTABLE socket option to actually work\n* Fixed issue 382 - Current libzmq doesn't compile on Android NDK\n* Fixed issue 377 - ZeroMQ will not build on Windows with OpenPGM\n* Fixed issue 375 - error: unused variable 'sa_family'\n* Fixed issue 373 - Unable to build libzmq/zeromq3.x on AIX7\n* Fixed issue 372 - Unable to build libzmq/zeromq3.x on HPUX 11iv3\n* Fixed issue 371 - Unable to build libzmq/zeromq3.x on RHEL5/SLES10\n* Fixed issue 329 - wsa_error_to_errno() calls abort() on WSAEACCES\n* Fixed issue 309 - Assertion failed: options.recv_identity (socket_base.cpp:864)\n* Fixed issue 211 - Assertion failed: msg_->flags & ZMQ_MSG_MORE (rep.cpp:81)\n\nAPI changes\n-----------\n\n* zmq_device () deprecated and replaced by zmq_proxy ().\n* zmq_ctx_set_monitor () replaced by zmq_socket_monitor ().\n* ZMQ_ROUTER_BEHAVIOR/ZMQ_FAIL_UNROUTABLE renamed experimentally to\n  ZMQ_ROUTER_MANDATORY.\n\n\n0MQ version 3.2.0 (RC1), released on 2012/06/05\n===============================================\n\nBug fixes\n---------\n\n* Fixed issue 264 - Potential bug with linger, messages dropped during\n  socket close.\n\n* Fixed issue 293 - libzmq doesn't follow the ZMTP/1.0 spec (did not\n  set reserved bits to 0).\n\n* Fixed issue 303 - Assertion failure in pgm_sender.cpp:102.\n\n* Fixed issue 320 - Assertion failure in connect_session.cpp:96 when\n  connecting epgm to an invalid endpoint.\n\n* Fixed issue 325 - Assertion failure in xrep.cpp:93, when two sockets\n  connect using the same identity.\n\n* Fixed issue 327 - Assertion failure in mtrie.cpp:246, when\n  unsubscribing from channel.\n\n* Fixed issue 346 - Assertion failure in signaler.cpp:155, when using a\n  closed socket.\n\n* Fixed issue 328 - unsubscribe wrongly clears multiple subscriptions.\n\n* Fixed issue 330 - IPC listener does not remove unix domain stream file\n  when terminated.\n\n* Fixed issue 334 - Memory leak in session_base.cpp:59.\n\n* Fixed issue 369 - ROUTER cannot close/reopen while DEALER connected.\n\nOperating systems\n-----------------\n\n* Fixed issue 301 - HPUX 11iv2 - build fails, CLOCK_MONOTONIC\n  undefined.\n\n* Fixed issue 324 - OS/X - build fails, ECANTROUTE undefined.\n\n* Fixed issue 368 - Solaris / Sun C++ - build fails, no insert method\n  in multimap classes.\n\n* Fixed issue 366 - Windows - ports not freed after crash.\n\n* Fixed issue 355 - Windows - build fails, MSVC solution file is out of\n  date.\n\n* Fixed issue 331 - FreeBSD 8 and 9 - getaddrinfo fails with\n  EAI_BADFLAGS on AI_V4MAPPED flag.\n\n* Fixed issue xxx - Added support for WinCE.\n\nPerformance\n-----------\n\n* Fixed issue xxx - Implemented atomic operations for ARMv7a (runs 15-20% faster).\n\nAPI changes\n-----------\n\n* Fixed issue 337 - Cleaned-up context API:\n\n    zmq_ctx_new() - create new context (will deprecate zmq_init)\n    zmq_ctx_destroy() - destroy context (will deprecate zmq_term)\n    zmq_ctx_set() - set context property\n    zmq_ctx_get() - get context property\n\n* Fixed issue xxx - Cleaned-up message API:\n\n    zmq_msg_send() - send a message (will deprecate zmq_sendmsg)\n    zmq_msg_recv() - receive a message (will deprecate zmq_recvmsg)\n    zmq_msg_more() - indicate whether this is final part of message\n    zmq_msg_get() - get message property\n    zmq_msg_set() - set message property\n\n* Fixed issue xxx - Added context monitoring API:\n\n    zmq_ctx_set_monitor() - configure monitor callback.\n\n* Fixed issue xxx - Added unbind/disconnect API:\n\n    zmq_unbind() - unbind socket.\n    zmq_disconnect() - disconnect socket.\n\n* Fixed issue xxx - Added ZMQ_TCP_ACCEPT_FILTER setsockopt() for listening TCP sockets.\n\n* Fixed issue 336 - Removed sys: transport.\n\n* Fixed issue 333 - Added zmq_device function back to API (was removed\n  in 3.0).\n\n* Fixed issue 340 - Add support for MAX_SOCKETS to new context API.\n\n\nOMQ version 3.1.0 (beta), released on 2011/12/18\n================================================\n\nGeneral information\n-------------------\n\nBased on community consensus, the 0MQ 3.1.x release reverts a number of\nfeatures introduced in version 3.0. The major reason for these changes is\nimproving backward compatibility with 0MQ 2.1.x.\n\nDevelopment of the 0MQ 3.0.x series will be discontinued, and users are\nencouraged to upgrade to 3.1.\n\nThe 0MQ 3.1.x releases use ABI version 3.\n\nReverted functionality\n----------------------\n\nThe following functionality present in 0MQ 3.0 has been reverted:\n\n* Wire format changes. The 0MQ 3.1 wire format is identical to that of 0MQ\n  2.1.\n\n* LABELs and COMMANDs have been removed.\n\n* Explicit identies are re-introduced, however they can be used only for\n  explicit routing, not for durable sockets.\n\n* The ZMQ_ROUTER and ZMQ_DEALER socket types are once again aliases for\n  ZMQ_XREQ and ZMQ_XREP.\n\nNew functionality\n-----------------\n\n* The zmq_getmsgopt() function has been introduced.\n\n* Experimental IPv6 support has been introduced. This is disabled by\n  default, see the zmq_setsockopt() documentation for enabling it.\n\nOther changes\n-------------\n\n* The default HWM for all socket types has been set to 1000.\n\n* Many bug fixes.\n\nBuilding\n--------\n\n* The dependency on libuuid has been removed.\n\n* Support for building on Android, and with MSVC 10 has been added.\n\n0MQ version 3.0.0 (alpha), released on 2011/07/12\n=================================================\n\nNew functionality\n-----------------\n\n* A zmq_ctx_set_monitor() API to register a callback / event sink for changes\n  in socket state.\n\n* POSIX-compliant zmq_send and zmq_recv introduced (uses raw buffer\n  instead of message object).\n\n* ZMQ_MULTICAST_HOPS socket option added. Sets the appropriate field in\n  IP headers of PGM packets.\n\n* Subscription forwarding. Instead of filtering on consumer, the\n  subscription is moved as far as possible towards the publisher and\n  filtering is done there.\n\n* ZMQ_XPUB, ZMQ_XSUB introduced. Allow to create subscription-\n  forwarding-friendly intermediate devices.\n\n* Add sockopt ZMQ_RCVTIMEO/ZMQ_SNDTIMEO. Allow to set timeout for\n  blocking send/recv calls.\n\n* A new LABEL flag was added to the wire format. The flag distinguishes\n  message parts used by 0MQ (labels) from user payload message parts.\n\n* There is a new wire format for the REQ/REP pattern. First, the empty\n  bottom-of-the-stack message part is not needed any more, the LABEL\n  flag is used instead. Secondly, peer IDs are 32-bit integers rather\n  than 17-byte UUIDs.\n\n* The REQ socket now drops duplicate replies.\n\n* Outstanding requests & replies associated with a client are dropped\n  when the clients dies. This is a performance optimisation.\n\n* Introduced ZMQ_ROUTER and ZMQ_DEALER sockets. These mimic the\n  functionality of ZMQ_ROUTER and ZMQ_DEALER in 0MQ/2.1.x. Guarantees\n  backward compatibility for exsiting code.\n\n* Removed dependency on OS socketpair buffer size. No more asserts in\n  mailbox.cpp because of low system limit of sockepair buffer size.\n\nAPI improvements\n----------------\n\n* Obsolete constants ZMQ_UPSTREAM and ZMQ_DOWNSTREAM removed. Use\n  ZMQ_PUSH and ZMQ_PULL instead.\n\n* Timeout in zmq_poll is in milliseconds instead of microseconds. This\n  makes zmq_poll() compliant with POSIX poll()\n\n* ZMQ_MCAST_LOOP removed. There's no support for multicast over\n  loopback any more. Use IPC or TCP isntead.\n\n* zmq_send/zmq_recv was renamed zmq_sendmsg/zmq_recvmsg.\n\n* ZMQ_RECOVERY_IVL and ZMQ_RECOVERY_IVL_MSEC reconciled. The new option\n  is named ZMQ_RECOVERY_IVL and the unit is milliseconds.\n\n* Option types changed. Most of the numeric types are now represented\n  as 'int'.\n\n* ZMQ_HWM split into ZMQ_SNDHWM and ZMQ_RCVHWM. This makes it possible\n  to control message flow separately for each direction.\n\n* ZMQ_NOBLOCK renamed ZMQ_DONTWAIT. That makes it POSIX-compliant.\n\nLess is More\n------------\n\n* Pre-built devices and zmq_device() removed. Should be made available\n  as a separate project(s).\n\n* ZMQ_SWAP removed. Writing data to disk should be done on top of 0MQ,\n  on inside it.\n\n* C++ binding removed from the core. Now it's a separate project, same\n  as any other binding.\n\nBug fixes\n---------\n\n* Many.\n\nBuilding\n--------\n\n* Make pkg-config dependency conditional.\n\nDistribution\n------------\n\n* Removed Debian packaging, which is now available at packages.debian.org\n  or via apt-get.\n\n\n0MQ version 2.2.0 (Stable), released on 2012/04/04\n==================================================\n\nChanges\n-------\n\n* Fixed issue 349, add send/recv timeout socket options.\n\nBug fixes\n---------\n\n* Fixed issue 301, fix builds on HP-UX 11iv3 when using either gcc or aCC.\n\n* Fixed issue 305, memory leakage when using dynamic subscriptions.\n\n* Fixed issue 332, libzmq doesn't compile on Android NDK.\n\n* Fixed issue 293, libzmq doesn't follow ZMTP/1.0 spec.\n\n* Fixed issue 342, cannot build against zmq.hpp under C++11.\n\n\n0MQ version 2.1.11 (Stable), released on 2011/12/18\n===================================================\n\nBug fixes\n---------\n\n* Fixed issue 290, zmq_poll was using system time instead of monotonic\n  clock (Mika Fischer).\n\n* Fixed issue 281, crash on heavy socket creation - assertion failure in\n  mutex.hpp:91. (Mika Fischer).\n\n* Fixed issue 273, O_CLOEXEC flag used in ip.cpp:192 is supported only\n  on Linux kernels 2.6.27+\n\n* Fixed issue 261, assertion failure in kqueue.cpp:76.\n\n* Fixed issue 269, faulty diagnostic code in 2.1.10.\n\n* Fixed issue 254, assertion failure at tcp_socket.cpp:229 on ENOTCONN.\n\nChanges\n-------\n\n* Now builds properly on AIX 6.1 (AJ Lewis).\n\n* Builds using libdcekt on HP-UX (AJ Lewis).\n\n* New upstream OpenPGM maintenance release 5.1.118.\n\n* Enabled debugging on assertion failure on Windows (Paul Betts).\n\n\n0MQ version 2.1.10 (Stable), released on 2011/10/03\n===================================================\n\nBug fixes\n---------\n\n* Fixed issue 140, SWAP failed with assertion failure in pipe.cpp:187\n  if the current directory was not writeable. Behavior now is to return\n  -1 at zmq_setsockopt in this situation.\n\n* Fixed issue 207, assertion failure in zmq_connecter.cpp:48, when an\n  invalid zmq_connect() string was used, or the hostname could not be\n  resolved. The zmq_connect() call now returns -1 in both those cases.\n\n* Fixed issue 218, sockets not opened with SOCK_CLOEXEC, causing fork/exec\n  to sit on sockets unnecessarily.\n\n* Fixed issue 250, build errors on Windows (Mikko Koppanen).\n\n* Fixed issue 252, assertion failure in req.cpp:87 and req.cpp:88 (Mikko\n  Koppanen).\n\n\n0MQ version 2.1.9 (Stable), released on 2011/08/29\n==================================================\n\nBug fixes\n---------\n\n* Fixed issue 240, assertion failure in pgm_socket.cpp:437.\n\n* Fixed issue 238, assertion failure in zmq.cpp:655, when zmq_poll is\n  used on an empty set, on Windows.\n\n* Fixed issue 239, assertion failure in zmq.cpp:223, when ZMQ_SWAP was\n  used with explicit identities and multiple SUB sockets.\n\n* Fixed issue 236, zmq_send() and zmq_recv() did not always return\n  error conditions such as EFSM properly. This bug was introduced in\n  version 2.1.8 by the backport of changes for issue 231.\n\nBuilding\n--------\n\n* 0MQ support for Android added (Bill Roberts, Mikko Koppanen).\n\n\n0MQ version 2.1.8 (RC), released on 2011/07/28\n==============================================\n\nBug fixes\n---------\n\n* Fixed issue 223, assertion failure in tcp_connecter.cpp:300 when\n  connecting to a server that is on an unreachable network (errno is\n  equal to ENETUNREACH).\n\n* Fixed issue 228, assertion failure at rep.cpp:88 when HWM was reached.\n\n* Fixed issue 231, assertion failure at mailbox.cpp:183 when too many\n  pending socketpair operations were queued (major backport from 3.0).\n\n* Fixed issue 234, assertion failure at mailbox.cpp:77 when Ctrl-C was\n  used (only affected git master following backport for 231).\n\n* Fixed issue 230, SIGPIPE killing servers when client disconnected, hit\n  OS/X only.\n\nNote: this release was renamed \"release candidate\" due to issue 236,\nfixed in 2.1.9.\n\n\n0MQ version 2.1.7 (Stable), released on 2011/05/12\n==================================================\n\nBug fixes\n---------\n\n* Fixed issue 188, assert when closing socket that had unread multipart\n  data still on it (affected PULL, SUB, ROUTER, and DEALER sockets).\n\n* Fixed issue 191, message atomicity issue with PUB sockets (an old issue).\n\n* Fixed issue 199 (affected ROUTER/XREP sockets, an old issue).\n\n* Fixed issue 206, assertion failure in zmq.cpp:223, affected all sockets\n  (bug was introduced in 2.1.6 as part of message validity checking).\n\n* Fixed issue 211, REP socket asserted if sent malformed envelope (old issue\n  due to abuse of assertions for error checking).\n\n* Fixed issue 212, reconnect failing after resume from sleep on Windows\n  (due to not handling WSAENETDOWN).\n\n* Properly handle WSAENETUNREACH on Windows (e.g. if client connects\n  before server binds).\n\n* Fixed memory leak with threads on Windows.\n\nChanges\n-------\n\n* Checks zmq_msg_t validity at each operation.\n\n* Inproc performance tests now work on Windows.\n\n* PGM wire format specification improved in zmq_pgm(7)\n\n* Added thread latency/throughput performance examples.\n\n* Added \"--with-system-pgm\" configure option to use already installed\n  OpenPGM.\n\n* Runtime checking of socket and context validity, to catch e.g. using a\n  socket after closing it, or passing an invalid pointer to context/socket\n  methods.\n\n* Test cases moved off port 5555, which conflicts with other services.\n\n* Clarified zmq_poll man page that the resolution of the timeout is 1msec.\n\n\n0MQ version 2.1.6 (Broken), released on 2011/04/26\n==================================================\n\nNote that this version contained a malformed patch and is not usable.\nIt is not available for download, but is available in the git via the\n2.1.6 tag.\n\n0MQ version 2.1.5 (Broken), released on 2011/04/20\n==================================================\n\nNote that this version contained a malformed patch and is not usable.\nIt is not available for download, but is available in the git via the\n2.1.5 tag.\n\n\n0MQ version 2.1.4 (Stable), released on 2011/03/30\n==================================================\n\nBug fixes\n---------\n\n* Fix to OpenPGM which was asserting on small messages (Steven McCoy).\n\nChanges\n-------\n\n* Upgraded OpenPGM to version 5.1.115 (Pieter Hintjens).\n\n* OpenPGM build changed to not install OpenPGM artifacts.\n\n\n0MQ version 2.1.3 (Stable), released on 2011/03/21\n==================================================\n\nBug fixes\n---------\n\n* Fix to PUSH sockets, which would sometimes deliver tail frames of a\n  multipart message to new subscribers (Martin Sustrik).\n\n* Fix to PUB sockets, which would sometimes deliver tail frames of a\n  multipart message to new subscribers (Martin Sustrik).\n\n* Windows build was broken due to EPROTONOSUPPORT not being defined. This\n  has now been fixed (Martin Sustrik).\n\n* Various fixes to make OpenVMS port work (Brett Cameron).\n\n* Corrected Reference Manual to note that ZMQ_LINGER socket option may be\n  set at any time, not just before connecting/binding (Pieter Hintjens).\n\n* Fix to C++ binding to properly close sockets (Guido Goldstein).\n\n* Removed obsolete assert from pgm_socket.cpp (Martin Sustrik).\n\nChanges\n-------\n\n* Removed stand-alone devices (/devices subdirectory) from distribution.\n  These undocumented programs remain available in older packages (Pieter\n  Hintjens).\n\n* OpenPGM default rate raised to 40mbps by default (Steven McCoy).\n\n* ZMQ_DEALER and ZMQ_ROUTER macros provided to ease upgrade to 0MQ/3.0.\n  These are scheduled to replace ZMQ_XREQ and ZMQ_XREP (Pieter Hintjens).\n\n* Added man page for zmq_device(3) which was hereto undocumented (Pieter\n  Hintjens).\n\n* Removed zmq_queue(3), zmq_forwarder(3), zmq_streamer(3) man pages\n  (Pieter Hintjens).\n\nOpenPGM Integration\n-------------------\n\n* Upgraded OpenPGM to version 5.1.114 (Steven McCoy, Mikko Koppanen).\n\n* Build system now calls OpenPGM build process directly, allowing easier\n  future upgrades of OpenPGM (Mikko Koppanen).\n\n* Build system allows configuration with arbitrary versions of OpenPGM\n  (./configure --with-pgm=libpgm-x.y.z) (Mikko Koppanen).\n\n* OpenPGM uses new PGM_ODATA_MAX_RTE controlling original data instead of\n  PGM_TXW_MAX_RTE covering entire channel (Steven McCoy).\n\nBuilding\n--------\n\n* 0MQ builds properly on FreeBSD (Mikko Koppanen).\n\n\n0MQ version 2.1.2 (rc2), released on 2011/03/06\n===============================================\n\nBug fixes\n---------\n\n* 0MQ now correctly handles durable inproc sockets; previously it ignored\n  explicit identities on inproc sockets.\n\n* Various memory leaks were fixed.\n\n* OpenPGM sender/receiver creation fixed.\n\n\n0MQ version 2.1.1 (rc1), released on 2011/02/23\n===============================================\n\nNew functionality\n-----------------\n\n* New socket option ZMQ_RECONNECT_IVL_MAX added, allows for exponential\n  back-off strategy when reconnecting.\n\n* New socket option ZMQ_RECOVERY_IVL_MSEC added, as a fine-grained\n  counterpart to ZMQ_RECOVERY_IVL (for multicast transports).\n\n* If memory is exhausted, 0MQ warns with an explicit message before\n  aborting the process.\n\n* Size of inproc HWM and SWAP is sum of peers' HWMs and SWAPs (Douglas\n  Greager, Martin Sustrik).\n\nBug fixes\n---------\n\n* 0MQ no longer asserts in mailbox.cpp when multiple peers connect with\n  the same identity.\n\n* 0MQ no longer asserts when rejecting an oversized message.\n\n* 0MQ no longer asserts in pipe.cpp when the swap fills up.\n\n* zmq_poll now works correctly with an empty poll set.\n\n* Many more.\n\nBuilding\n--------\n\n* 0MQ now builds correctly on CentOS, Debian 6, and SunOS/gcc3.\n\n* Added WithOpenPGM configuration into MSVC builds.\n\nKnown issues\n------------\n\n* OpenPGM integration is still not fully stable.\n\n\n0MQ version 2.1.0 (Beta), released on 2010/12/01\n================================================\n\nNew functionality\n-----------------\n\n* New semantics for zmq_close () and zmq_term () ensure that all messages\n  are sent before the application terminates. This behaviour may be\n  modified using the new ZMQ_LINGER socket option; for further details\n  refer to the reference manual.\n\n* The new socket options ZMQ_FD and ZMQ_EVENTS provide a way to integrate\n  0MQ sockets into existing poll/event loops.\n\n* Sockets may now be migrated between OS threads, as long as the\n  application ensures that a full memory barrier is issued.\n\n* The 0MQ ABI exported by libzmq.so has been formalised; DSO symbol\n  visibility is used on supported platforms to ensure that only public ABI\n  symbols are exported. The library ABI version has been set to 1.0.0 for\n  this release.\n\n* OpenPGM has been updated to version 5.0.92. This version no longer\n  depends on GLIB, and integration with 0MQ should be much improved.\n\n* zmq_poll() now honors timeouts precisely, and no longer returns if no\n  events are signaled.\n\n* Blocking calls now return EINTR if interrupted by the delivery of a\n  signal; this also means that language bindings which previously had\n  problems with handling SIGINT/^C should now work correctly.\n\n* The ZMQ_TYPE socket option was added; this allows retrieval of the socket\n  type after creation.\n\n* Added a ZMQ_VERSION macro to zmq.h for compile-time API version\n  detection.\n\n* The ZMQ_RECONNECT_IVL and ZMQ_BACKLOG socket options have been added.\n\nBug fixes\n---------\n\n* Forwarder and streamer devices now handle multi-part messages correctly.\n\n* 0MQ no longer asserts when malformed data is received on the wire.\n\n* 0MQ internal timers now work correctly if the TSC jumps backwards.\n\n* The internal signalling functionality (mailbox) has been improved\n  to automatically resize socket buffers on POSIX systems.\n\n* Many more.\n\nBuilding\n--------\n\n* 0MQ now builds correctly with many more non-GCC compilers (Sun Studio,\n  Intel ICC, CLang).\n\n* AIX and HP-UX builds should work now.\n\n* FD_SETSIZE has been set to 1024 by default for MSVC builds.\n\n* Windows builds using GCC (MinGW) now work out of the box.\n\nDistribution\n------------\n\n* A simple framework for regression tests has been added, along with a few\n  basic self-tests. The tests can be run using \"make check\".\n"
  },
  {
    "path": "README.cygwin.md",
    "content": "libzmq-cygwin\n=============\n\nDefinitive build fixes for cygwin  (See https://github.com/zeromq/pyzmq/issues/113 for partial solution)\n\nWhat's changed:\n  ./Makefile.am                       Add cygwin-specific target mostly the same as mingw\n  ./configure.ac                      Add cygwin-specific target mostly the same as mingw\n  ./tests/testutil.hpp                Lengthen socket timeout to 121 seconds\n  \nWhat's new:\n  ./README.cygwin.md                  This file\n  ./builds/cygwin                     Folder for cygwin-specific build files\n  ./builds/cygwin/Makefile.cygwin     Makefile for cygwin targets\n  \n"
  },
  {
    "path": "README.doxygen.md",
    "content": "## Overview\n\nThe ZeroMQ lightweight messaging kernel is a library which extends the\nstandard socket interfaces with features traditionally provided by\nspecialised messaging middleware products. ZeroMQ sockets provide an\nabstraction of asynchronous message queues, multiple messaging patterns,\nmessage filtering (subscriptions), seamless access to multiple transport\nprotocols and more.\n\nThis documentation describes the internal software that makes up the\nZeroMQ C++ core engine, and not how to use its API, however it may help\nyou understand certain aspects better, such as the callgraph of an API method.\nThere are no instructions on using ZeroMQ within this documentation, only\nthe API internals that make up the software.\n\n**Note:** this documentation is generated directly from the source code with\nDoxygen. Since this project is constantly under active development, what you\nare about to read may be out of date! If you notice any errors in the\ndocumentation, or the code comments, then please send a pull request.\n\nPlease refer to the README file for anything else.\n## Resources\n\nExtensive documentation is provided with the distribution. Refer to\ndoc/zmq.html, or \"man zmq\" after you have installed libzmq on your system.\n\n* Website: http://www.zeromq.org/\n* Official API documentation: http://api.zeromq.org/\n\nDevelopment mailing list: zeromq-dev@lists.zeromq.org\n\nAnnouncements mailing list: zeromq-announce@lists.zeromq.org\n\nGit repository: http://github.com/zeromq/libzmq\n\nZeroMQ developers can also be found on the IRC channel \\#zeromq, on the\nFreenode network (irc.freenode.net).\n\n## Copyright\nCopyright (c) 2007-2016 Contributors as noted in the AUTHORS file.  \nThe project license is specified in LICENSE.\n\nThe names \"ØMQ\", \"ZeroMQ\", \"0MQ\", and the ØMQ logo are registered trademarks\nof iMatix Corporation (\"iMatix\") and refers to either (a) the original libzmq\nC++ library, or (b) the community of projects hosted in the\nhttps://github.com/zeromq organization.\n\nThis Doxygen configuration is adapted by Hiten Pandya, for the ZeroMQ project.\n"
  },
  {
    "path": "README.md",
    "content": "# ZeroMQ\n\n[![Build Status](https://github.com/zeromq/libzmq/actions/workflows/CI.yaml/badge.svg)](https://github.com/zeromq/libzmq/actions/workflows/CI.yaml)\n[![Build status](https://ci.appveyor.com/api/projects/status/e2ks424yrs1un3wt?svg=true)](https://ci.appveyor.com/project/zeromq/libzmq)\n[![Coverage Status](https://coveralls.io/repos/github/zeromq/libzmq/badge.svg?branch=master)](https://coveralls.io/github/zeromq/libzmq?branch=master)\n[![Conan Center](https://shields.io/conan/v/zeromq)](https://conan.io/center/zeromq)\n\n## Welcome\n\nThe ZeroMQ lightweight messaging kernel is a library which extends the\nstandard socket interfaces with features traditionally provided by\nspecialised messaging middleware products. ZeroMQ sockets provide an\nabstraction of asynchronous message queues, multiple messaging patterns,\nmessage filtering (subscriptions), seamless access to multiple transport\nprotocols and more.\n\n## Supported platforms <a name=\"#platforms\"/>\n\nLibzmq is mainly written in C++98 with some optional C++11-fragments. For\nconfiguration either autotools or CMake is employed. See below for some lists\nof platforms, where libzmq has been successfully compiled on.\n\n### Supported platforms with primary CI\n\n| OS and version                         | Architecture            | Compiler and version          | Build system | Remarks                                                                                                                               |\n|----------------------------------------|-------------------------|-------------------------------|--------------|---------------------------------------------------------------------------------------------------------------------------------------|\n| Android NDK r25                        | arm, arm64, x86, x86_64 | llvm (see NDK)                | autotools    | DRAFT                                                                                                                                       |\n| Ubuntu 14.04.5 LTS (trusty)            | amd64                   | clang 5.0.0                   | autotools    | STABLE, extras: GSSAPI, PGM, NORM, C++98 mode only                                                                                    |\n| Ubuntu 14.04.5 LTS (trusty)            | amd64                   | gcc 4.8.4                     | autotools    | STABLE, DRAFT, extras: GSSAPI, PGM, NORM, TIPC, IPV6, also POLLER=poll, POLLER=select, also valgrind and address sanitizer executions |\n| Ubuntu 14.04.5 LTS (trusty)            | amd64                   | gcc 4.8.4                     | CMake 3.12.2 | STABLE                                                                                                                                |\n| Windows Server 2012 R2                 | x86                     | Visual Studio 2008            | CMake 3.12.2 | DRAFT                                                                                                                                 |\n| Windows Server 2012 R2                 | x86                     | Visual Studio 2010 SP1        | CMake 3.12.2 | DRAFT                                                                                                                                 |\n| Windows Server 2012 R2                 | x86                     | Visual Studio 2012 Update 5   | CMake 3.12.2 | DRAFT                                                                                                                                 |\n| Windows Server 2012 R2                 | x86, amd64              | Visual Studio 2013 Update 5   | CMake 3.12.2 | DRAFT, STABLE (x86 Release only), also POLLER=epoll                                                                                   |\n| Windows Server 2012 R2                 | x86                     | Visual Studio 2015 Update 3   | CMake 3.12.2 | DRAFT                                                                                                                                 |\n| Windows Server 2016                    | x86                     | Visual Studio 2017 15.9.6     | CMake 3.13.3 | DRAFT                                                                                                                                 |\n| cygwin 3.0.0 on Windows Server 2012 R2 | amd64                   | gcc 7.4.0                     | CMake 3.6.2  | DRAFT                                                                                                                                 |\n| MSYS2 ? on Windows Server 2012 R2      | amd64                   | gcc 6.4.0                     | CMake ?      | DRAFT                                                                                                                                 |\n| Mac OS X 10.13                         | amd64                   | Xcode 9.4.1, Apple LLVM 9.1.0 | autotools    | STABLE, DRAFT                                                                                                                         |\n| Mac OS X 10.13                         | amd64                   | Xcode 9.4.1, Apple LLVM 9.1.0 | CMake 3.11.4 | DRAFT                                                                                                                                 |\n\nNote: the platforms are regularly updated by the service providers, so this information might get out of date\nwithout any changes on the side of libzmq. For Appveyor, refer to https://www.appveyor.com/updates/ regarding\nplatform updates. For travis-ci, refer to https://changelog.travis-ci.com/ regarding platform updates.\n\n### Supported platforms with secondary CI\n\n| OS and version               | Architecture               | Compiler and version | Build system | Remarks |\n|------------------------------|----------------------------|----------------------|--------------|---------|\n| CentOS 6                     | x86, amd64                 | ?                    | autotools    |         |\n| CentOS 7                     | amd64                      | ?                    | autotools    |         |\n| Debian 8.0                   | x86, amd64                 | ?                    | autotools    |         |\n| Debian 9.0                   | ARM64, x86, amd64          | ?                    | autotools    |         |\n| Fedora 28                    | ARM64, ARM32, amd64        | ?                    | autotools    |         |\n| Fedora 29                    | ARM64, ARM32, amd64        | ?                    | autotools    |         |\n| Fedora Rawhide               | ARM64, ARM32, amd64        | ?                    | autotools    |         |\n| RedHat Enterprise Linux 7    | amd64, ppc64               | ?                    | autotools    |         |\n| SuSE Linux Enterprise 12 SP4 | ARM64, amd64, ppc64, s390x | ?                    | autotools    |         |\n| SuSE Linux Enterprise 15     | amd64                      | ?                    | autotools    |         |\n| xUbuntu 12.04                | x86, amd64                 | ?                    | autotools    |         |\n| xUbuntu 14.04                | x86, amd64                 | ?                    | autotools    |         |\n| xUbuntu 16.04                | x86, amd64                 | ?                    | autotools    |         |\n| xUbuntu 18.04                | x86, amd64                 | ?                    | autotools    |         |\n| xUbuntu 18.10                | x86, amd64                 | ?                    | autotools    |         |\n\n### Supported platforms with known active users\n\nAt the time of writing, no explicit reports have been available. Please report your experiences by opening a PR\nadding an entry or moving an entry from the section below.\n\nUnder \"last report\", please name either the SHA1 in case of an unreleased version, or the version number in\ncase of a released version.\n\n| OS and version | Architecture      | Compiler and version | Build system | Last report             | Remarks |\n|----------------|-------------------|----------------------|--------------|-------------------------|---------|\n| Solaris 10     | x86, amd64, sparc | GCC 8.1.0            | CMake        | 2019/03/18              |         |\n| DragonFly BSD  | amd64             | gcc 8.3              | autotools    | 2018/08/07 git-72854e63 |         |\n| IBM i          | ppc64             | gcc 6.3              | autotools    | 2019/10/02 git-25320a3  |         |\n| QNX 7.0        | x86_64            | gcc 5.4.0            | CMake        | 4.3.2                   |         |\n| Windows 10     | ARM64             | Visual Studio 2019   | CMake        | 2021/11/15 git-2375ca8b |         |\n| Windows 10     | ARM64             | clang                | CMake        | 2021/11/15 git-2375ca8b |         |\n\n### Supported platforms without known active users\n\nNote: this list is incomplete and inaccurate and still needs some work.\n\n| OS and version         | Architecture | Compiler and version     | Build system     | Remarks |\n|------------------------|--------------|--------------------------|------------------|---------|\n| Any Linux distribution | x86, amd64   | gcc ?+, clang ?+, icc ?+ | autotools, CMake |         |\n| SunOS, Solaris         | x86, amd64   | SunPro                   | autotools, CMake |         |\n| GNU/kFreeBSD           | ?            | ?                        | autotools, CMake |         |\n| FreeBSD                | ?            | ?                        | autotools, CMake |         |\n| NetBSD                 | ?            | ?                        | autotools, CMake |         |\n| OpenBSD                | ?            | ?                        | autotools, CMake |         |\n| DragonFly BSD          | amd64        | gcc 8.3                  | autotools, CMake |         |\n| HP-UX                  | ?            | ?                        | autotools, CMake |         |\n| GNU/Hurd               | ?            | ?                        | autotools        |         |\n| VxWorks 6.8            | ?            | ?                        | ?                |         |\n| Windows CE             | ?            | ?                        | ?                |         |\n| Windows UWP            | ?            | ?                        | ?                |         |\n| OpenVMS                | ?            | ?                        | ?                |         |\n\n### Unsupported platforms\n\n| OS and version | Architecture | Compiler and version | Remarks                                                                 |\n|----------------|--------------|----------------------|-------------------------------------------------------------------------|\n| QNX 6.3        | ?            | gcc 3.3.5            | see #3371, support was added by a user, but not contributed to upstream |\n\nFor more details, see [here](SupportedPlatforms.md).\n\nFor some platforms (Linux, Mac OS X), [prebuilt binary packages are supplied by the ZeroMQ organization](#installation).\nFor other platforms, you need to [build your own binaries](#build).\n\n## Installation of binary packages <a name=\"installation\"/>\n\n### Linux\n\nFor Linux users, pre-built binary packages are available for most distributions.\nNote that DRAFT APIs can change at any time without warning, pick a STABLE build to\navoid having them enabled.\n\n#### Latest releases\n\n##### DEB\n\n[![OBS release stable](https://img.shields.io/badge/OBS%20master-stable-yellow.svg)](http://software.opensuse.org/download.html?project=network%3Amessaging%3Azeromq%3Arelease-stable&package=libzmq3-dev)\n[![OBS release draft](https://img.shields.io/badge/OBS%20master-draft-yellow.svg)](http://software.opensuse.org/download.html?project=network%3Amessaging%3Azeromq%3Arelease-draft&package=libzmq3-dev)\n\n##### RPM\n\n[![OBS release stable](https://img.shields.io/badge/OBS%20master-stable-yellow.svg)](http://software.opensuse.org/download.html?project=network%3Amessaging%3Azeromq%3Arelease-stable&package=zeromq-devel)\n[![OBS release draft](https://img.shields.io/badge/OBS%20master-draft-yellow.svg)](http://software.opensuse.org/download.html?project=network%3Amessaging%3Azeromq%3Arelease-draft&package=zeromq-devel)\n\n#### Bleeding edge packages\n\n##### DEB\n\n[![OBS release stable](https://img.shields.io/badge/OBS%20master-stable-yellow.svg)](http://software.opensuse.org/download.html?project=network%3Amessaging%3Azeromq%3Agit-stable&package=libzmq3-dev)\n[![OBS release draft](https://img.shields.io/badge/OBS%20master-draft-yellow.svg)](http://software.opensuse.org/download.html?project=network%3Amessaging%3Azeromq%3Agit-draft&package=libzmq3-dev)\n\n##### RPM\n\n[![OBS release stable](https://img.shields.io/badge/OBS%20master-stable-yellow.svg)](http://software.opensuse.org/download.html?project=network%3Amessaging%3Azeromq%3Agit-stable&package=zeromq-devel)\n[![OBS release draft](https://img.shields.io/badge/OBS%20master-draft-yellow.svg)](http://software.opensuse.org/download.html?project=network%3Amessaging%3Azeromq%3Agit-draft&package=zeromq-devel)\n\n#### Example: Debian 9 latest release, no DRAFT apis\n\n    echo \"deb http://download.opensuse.org/repositories/network:/messaging:/zeromq:/release-stable/Debian_9.0/ ./\" >> /etc/apt/sources.list\n    wget https://download.opensuse.org/repositories/network:/messaging:/zeromq:/release-stable/Debian_9.0/Release.key -O- | sudo apt-key add\n    apt-get install libzmq3-dev\n\n### OSX\n\nFor OSX users, packages are available via brew.\n\n    brew install zeromq\n\n## Installation of package manager <a name=\"package manager\"/>\n\n### vcpkg\n\nvcpkg is a full platform package manager, you can easily install libzmq via vcpkg.\n\n    git clone https://github.com/microsoft/vcpkg.git\n    ./bootstrap-vcpkg.bat # For powershell\n    ./bootstrap-vcpkg.sh # For bash\n    ./vcpkg install zeromq\n\n## Build from sources <a name=\"build\"/>\n\nTo build from sources, see the INSTALL file included with the distribution.\n\n### Android\n\nTo build from source, see [README](./builds/android/README.md) file in the\nandroid build directory.\n\n## Resources\n\nExtensive documentation is provided with the distribution. Refer to\ndoc/zmq.html, or \"man zmq\" after you have installed libzmq on your system.\n\nWebsite: http://www.zeromq.org/\n\nDevelopment mailing list: zeromq-dev@lists.zeromq.org\nAnnouncements mailing list: zeromq-announce@lists.zeromq.org\n\nGit repository: http://github.com/zeromq/libzmq\n\nZeroMQ developers can also be found on the IRC channel #zeromq, on the\nLibera Chat network (irc.libera.chat).\n\n## License\n\nThe project license is specified in LICENSE.\n\nlibzmq is free software; you can redistribute it and/or modify it under\nthe terms of the Mozilla Public License Version 2.0.\n\n## Contributing\n\nThis project uses [C4(Collective Code Construction Contract)](https://rfc.zeromq.org/spec:42/C4/) process for contributions.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\n4.x versions are supported with critical and security bug fixes.\n\n| Version | Supported          |\n| ------- | ------------------ |\n| 4.3.x   | :white_check_mark: |\n| 4.2.x   | :white_check_mark: |\n| 4.1.x   | :white_check_mark: |\n| 4.0.x   | :white_check_mark: |\n| < 4.0   | :x:                |\n\n## Reporting a Vulnerability\n\nIf you believe a bug you found could have security implications,\nplease send a GPG encrypted email with the details to the maintainers:\n\n| Maintainer | Email address   | GPG fingerprint |\n| ---------- | --------------- | --------------- |\n| Doron Somech | somdoron@gmail.com | E0B0 E3D1 55DD 6ED6 71FB  2B79 D0B9 CC44 867D 8F3D |\n| Luca Boccassi | luca.boccassi@gmail.com | A9EA 9081 724F FAE0 484C 35A1 A81C EA22 BC8C 7E2E |\n\n## Internal severity classification\n\nWe will attempt to follow this general policy when assigning a severity to\nsecurity issues. These are guidelines more than rules, and as such end\nresults might vary.\n\n\n| Severity | Definition |\n| -------- | ---------- |\n| CRITICAL | endpoints using STRONG authentication are SILENTLY affected |\n| HIGH | endpoints using STRONG authentication are VISIBLY affected |\n| MODERATE | endpoints NOT using STRONG authentication are SILENTLY affected |\n| LOW | endpoints NOT using STRONG authentication are VISIBLY affected |\n\nSTRONG authentication means transports that use cryptography, for example CURVE\nand TLS.\n\nVISIBLY affected means that platform owners are likely to immediately notice\nmisbehaviours, like crashes or loss of connectivity for legitimate peers.\n\nSILENTLY affected means that without close inspection, platform owners are\nunlikely to notice misbehaviours, like remote code executions or data exfiltration.\n\n### Public keys\n<details>\n<summary>Doron Somech</summary>\n\n```\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBF0YXO8BEAD8Be6QQa+ALzIWszeDPtVK9DCGN7ZM1C4Ygq6w7llauhg4wreg\nkQy7YwOFKsFTi9cmIRfkw/lX9tIn+PkNe+kV7tOLDCdAmNCqdERvM/C46uPM/Mx4\nIdaoUXOPVIwbLcCLysiYxickq/M6ymPH7pAT5deCxH9B1DV38T2Mlq+uXXyZ1aFE\n74oCouQ7Vau31NBeOA4DkpPjpdA/WXMVEqoB3PKALUGYs1Ce5CguE0WjdueZFt2k\nDvdYtbUFb+vNLMPCejf1sBWDnUygPfsPPakyimfxBSIRsQLvw/5t6bkiWgtGU4LD\no37skSzum7h0rw1378ryoMUYdaNu/oNlWCwbQzBjD6G+WYbmu5AB5aGSaDjUzg9K\nAIcaNbRFln7OwvHrQdvDuWypZw7JvWYbehaywBagbjSTjIwb+Umki8cF/zxi5sxI\neFRMARDVQa5PAeErDd+4RtMcB55M2a90xWcTcfBdE/VYmwBXsMMWju4ceBtAqBCB\nDTVxxaT54tKjkOKa1Yk75zL4Xu7Sekg2BIaHh/qVMn5aTEX+X6ImeFhWRjhgsk+Q\nXoXo74nJq2aCJ2sSjLRdvnePtc3WM+WfdmdnC12JpBiBn4TFYxMBJlvqfKBxZELU\neZBkB6eTcBO/n5U3jSdFM47SeiBgUlPRiV+0ArZJ4i2Giv9vduWO6XeMVwARAQAB\ntCFEb3JvbiBTb21lY2ggPHNvbWRvcm9uQGdtYWlsLmNvbT6JAjgEEwECACIFAl0Y\nXO8CGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJENC5zESGfY89i0wP/i5k\nsYQkdaPeos9JnfUd3cV588lQzBN2bVhzCtbrjR6wXn9hRhZP9ftCNKoVp8cpC07G\nVq87sKqeB7odaK67jS+XoF4msIUEYS0lN2lPORf523VK3Juy9FW39aEPfx+6P5+h\nh49VveR1t9I7MgdjnKVwmaELcFDKKGQaPlcWlKctSkOLRw/vYFIvajFJ30bkK9+z\nsjgtUvXbSgt4HHHOQ/M6oCNhDsY0YE1zNxDgc8EqRlRxf76+pwldMe47/sIP2U7m\nqI6d/LfsWnK6iJ0ehlp6oPP2GcUM8bH3lh2ugHH7sPSwpvh/rHqQTTxv+KiFeQOC\nyuxvWdjathnDDHRNPVahBR747iKlcebJeaK5X8wObcIDaGBecwnNIjws4hrYAFH0\neNiROIbDkxDjwFhBYLDMfVCPW3xpBDa67EBJ6qTrabxmXOGvUDR2kB0P5lmtU/jL\njdVeFLj9tgwuuL8PW5k/gCdeB4WSBF4VWAHBZ2vDXUPut78dHQQg+dgvHmbnRYZB\nEm6nrYUeoQ4nSOHf7VmdHf05HGwam+ZTWLN2sIEerNJlRCx6mEn20O2S7DE4RMi5\nVjBFHy8/YSR3hRtdOSYfE61AeProeDPTGiei6xxlN00MQ7K/kFhQHIjKz1Ao51LU\no6+KGTtka2+g368boLcQALIchlfp7cfUAEp+dB7UuQINBF0YXO8BEADBXhwad2VN\nXFhD69CPwWR39KmoW019EvT8tNWzCPzx8hQeTJz+fY0bTiXYxMROZwF0SD4kqYet\nnejfH+boUFV64coxmfCmriqOQ0SGZTCfWzrjDrWjj51Xe1NWsGnFNO6vCcL1NNPB\n0ZcE/wskEaKPi6Ui0SwvlDJQFK5UnrnFehmEIxEqi8BFez2Ft7/3I/XRrhlDzMtT\nhDgMb+Ro9BydddH3TRKAdJBzIsozCrv0nn1DIXM+Pocqiuvk72E6iUxS2meeA4F6\nDTG6MIWEcf6WPRVqXdD2bCBzDJ1NYixK9TFdZjo/6jTLwwX711+/NTIblAbpc/KE\nio+0cuRG99gP8Cr+1VVZ2fcK9FpjI/u4YERmj8arMkcFz+QQDaJnXIjmNDpD0zBQ\nDh2v6pKysoEgmOE2xDzBsJbZomluKOytLN9/KcqucB1qkjzHD5JeZe+/S1vxdZUn\n+81Us+SeepiDOfrT84xFYcqJentL+ylFj7zBdeqF4WTnZAT9/xbVuUSYnRm1Sm0z\nvr99Sum0MXUTzgNhY5x3PkFQyg91lllJUFGoXiLivG+3M8JFC7V2K7wXhHFqffVX\nQq6UOm6+kCTjUCgzpQswMpDremB7A2fBQObKOC/3pE0Gbh3uKvylqQkMPTn4lOao\nJ3VSd1hBqHAdb5uxnmxN8w3wIpnaSypBawARAQABiQIfBBgBAgAJBQJdGFzvAhsM\nAAoJENC5zESGfY895WkQAJYvJg/IYBKh0SblT8lGj9O+mLXO6K1q+HfZ6mERm9Ew\n+fgW/cwGzuUrn+DC6vfsXlqtshUwiaxaa6NJccPBfC5IGHAegK5giwnQ/sbrA70A\n7md2u+NK2tNDGK4Gxy8ZWMY1++TmwdVLzNivM5IA/NGotyYgQStDI+/Muvh+0wQ9\nxZjo/InxVXeQcnqQXVKhoouPo2GlXslHev04SRl/ZJYN5sEHCE0Qx6L++esVvrwE\n/N5NT5Rk41l4mXAN2SM0H5AB+Wf1qIiVB6pMLBzXM/7qnCnJS0FZZjf2WRiB0yXj\nxTl+/JUK9MYckkrNcAfnb6yvnvO5W3KDabZhl/Cqw08vVSvcqyYRFXIa4vduiGJP\nL6C8o3USbjVfZhBSHXpuo7JPzR0S4l52QB2ZnTCRIjSBe5vphVum6r3vR5rKAU1n\nHtytqm099TlDapj+4wixSv8TvwlJr9no0uEJloyRAMFMYms4KgLEEZfc2tqpe/sA\nnO6TM9h/hCbrImplSiesHqTxprnKAipudSYkc750zuFTiBQ5WwYbWjkCB2PSEh+l\n8ZCRM5Ropfk4ATMhXH/w2Dxa5mdaHuKWKUc14+YfSBJI8yohbVIzYVsvAclctCQY\nkAh/Z/Fl8W+ftDsZF0/1k3fxyKwExFej+AIsabcQDG0bAHscfH/44atKZRPn72FI\n=Qu19\n-----END PGP PUBLIC KEY BLOCK-----\n```\n\n</details>\n\n<details>\n<summary>Luca Boccassi</summary>\n\n```\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFTKss4BEAC6LdgaSpaSBbMZK8erDulfXpCszvssCvEAI5lshfNNLHqOGy4r\ng+A3xyaGe+ITjoahT56Ly+dylduRvuZaJwbKWZqOKLnZHG0/Y/4K1MSk73TtcFbS\nVn0q1dZmr14ysTKB8E1UJ8XQZO+PO79VANjvj9oEqsYX4xJ5BenWdfqJOGa+8jn8\nou75vYcTFkIlvSnaHT4MkCqPGnuGgqiunEScjpBRFOX6ZIdRZvXcjP4HymdQAIMA\nBDDcV/qT+3VIOwKCn2e1jtxGbgMUwyosfz7nmlNHAdLrnficbSSsjRBIKxLgKN/N\n2fk/jk87mbs7Qz5L2bSxU68emGHZ1BEkBJ4vhiO6VBx8XHolK2RpI/3v0qzdGynZ\nYKTF2yBFqBlDI12gbfxabCQ7FgxwLBmYw/C068NVtXLM0AAMFrJmXRoexE698DJi\nwL/4qxWy2Py/wBHSFInmyUSSVi2CjRkLh2zA/EJ/268HooItcnL7kGnyWo9IJZEz\nMa7QO1FF/513xsW2QyPr/QNvuJ4GT/SyIgz+6Ln/z8wHCJQw8CM7vFRgOCuy2U3R\nsrO926muRbl97pqRmCXbb+OJQMcYaA841FPKHq52kUTeGqkiJW4RocckcEGqhxhh\nzj8KjIb2wBgkYviFQWKLIpZBVxKSAjVXTl/Bzk9m2ZPETjMZKtz09xtloQARAQAB\ntCBMdWNhIEJvY2Nhc3NpIDxibHVjYUBkZWJpYW4ub3JnPokCNwQTAQoAIQUCWab4\npwIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRCoHOoivIx+Lmx3D/0f5Nxi\nLYPDpxPOJDnEGUNqLiHlnyHwlHidV1xROfh8F6WkDrEAO5YfkASJjqBYJY93ZiZU\n/ROUdpcct9sN0K1Vw4yTAHFYpYO2G9oc3ax+3ly0rON4L7t1Xj9cvR1/b2fIIltE\nYied0XP3ukUfjECOkwQZJbmOHjsea61i5da/JEbDFkr32witorIMMIOAsZkZ+tcL\nxo2kRhk5PT7t6yo5cRLd0rLGKvKMBkMrNcPNk/T1V1YKB6yy0gAfo+dhZyI/khNC\nVuYZB59oYX5FS5FkGn/CCmuPN3YkGBqe0vZJjYLe8PK0vPS1obg9gRuYuJXdxIQn\nP8hD/y6Cu1axoy5EPt1uNc1bUSkvWUoJ2pWkeUAEKa/E8I0xKwQfHHo93rA1Xfdc\nc3rivihyj25/CkHo3zP6Xa0fqQLjpvusdf5nxuKL5cQYCAkNV9/sITTCxxYiKhp5\nlto9jhxs5j3/D4WV0+EGaQ/jfwg0i1h5eApzJQWMG+dEiT28s9+zPgFqfYq5oqVk\ncF+3tv39Mk/k06XqEwD+TmhV3Yv/wy1BDrGxvQgMP5GtIPS6p6+PBWFE+HUYYPdZ\n/vFN5DugzvVznjxLETUvj1G7mCQyHFXIkezF3mfr3uk0WiYWYoEqQ1Jdg8nsiTq3\niRTwW3XNsNhB28OoXH461215t/LakjGMVOmUSrQkTHVjYSBCb2NjYXNzaSA8bGJv\nY2Nhc3NAYnJvY2FkZS5jb20+iQIzBDABCgAdBQJZozczFh0gcHJldmlvdXMgam9i\nJ3MgZW1haWwACgkQqBzqIryMfi67IhAAq7Gj+p4Xt5Zc5OhMt7xaz6lGVdgXljGE\nmVmKgmyHWwMnNRpLrsXUWK8iZuvpg9Ges1o0Ckf7f+631XTOle0r3MwsVI+FgWVM\nBzAg7ft9GlIMqgY6suWlV7Rwar+rmzgf4A6tDjDWq4Lr2QTbhzjKoZeVL52Z2tpd\nnq0Iq1RKuXPQ8AEkPcfhYc3Z8ZL0MQ1cL98c42qVRYmoa1JmABen7rSUmIQL3t9v\naZXLqnTNOEtpbJ0QLuhasBTPwUW7FOwvSFr8PSoSKtOJ9VLEGDgJD6wewc/MYJsu\nfMECdfVYipOP/mlX1hrmxyucEm0a6CjFDvrP46sUJ4JoVcmr1Te898VQYKvBRFZK\n7UxJIbp6nZdyW6jI0HdstgUNyh0IzTgOUfgdkn5m8Xw3AaJdzGIy6cu4+g0Qmief\nrbZrReVcWYPswITpnDtEAmghq7C7QJ5OB7PA2G1xWqOeLMQnE2tTGpJfWkuv6FEI\nlG+5utAKSwDz9sZ93wbYGil5/rBSLOS2XoZfS67yROQH8+f1vc2tMpdfD6Z8rtkH\nHfotVwDkx3xIKWCENdmL0ewHbzjKXglSi1VkFGdrxoXyQvpSeAgO2GE0spM3lRIR\ncfNsXrzx4J21TUDrjK9mg/+KVEGA2I7E95d/ByyjDz4w0yx6xv4nyHtptgAc72aP\n41NMSpr0qje0J0x1Y2EgQm9jY2Fzc2kgPGx1Y2EuYm9jY2Fzc2lAZ21haWwuY29t\nPokCOgQTAQgAJAIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUCVMq0wgIZAQAK\nCRCoHOoivIx+LtL+D/4+JIaILWcbIymShr7cOhlWKu7/AqAHrT+y/0s99O3Tu6TD\n7bk5LUMUL5TBZtyVbUQh0KPjVYH+QZyDGICwn9snbkftIACvwD8LgtUv+5PbAQ1D\nof1ZtNjbl5S+VeKoD5Ev01t5QusRfThyiHzFSZOvePiLuRyRe1ixn1fzXl/NxuW2\nd7eJyxNRmyZ6N63SVDnBvOFwbNSJ4awXZa2S23edswfNcfEeYVVrEmEfBsi4U3ZY\nrjHWV+SvHoa63vEfyooynRofXgwPZLeOcsa6f2Q3jTI7WaCVnxL7K0GlxW3pd+MO\nE8HKFj/8MnK29ykQgvfOjvBtKIQmZoPHB1+FT6YIxr0fkLIK2FHGZ0azh0T7sWEh\n0WPQeieGFdDOq0z9Jf6fiWwIeetpwdeEoAzzXQZkHfRNpwzkXx7RlfITUqko3UiW\nl/w5S7t4x2HFyFHVb5osqF+NhCxGaqZGGkkegE/9RRcvFzN8pbUHNMxnwV/KQW8V\n1DZ9P7Kr+a/KV+dmEs/7vAj0vyFzCJbc8qecqOWVOLjY9tzOBjEWa1zvt6PVxZGJ\nI3i+lvdLcpvIWyAI68Gi7kOsTuu8A8iXDxEfzJ8kGlBnflq14sio3VKP6nVIPwbF\n5CwturkRM0vPkKSIliBCvS2MvnC3S+0AkKjhKRl9InBh0mCx1cRylJ8ZltHj9rQr\nTHVjYSBCb2NjYXNzaSA8bHVjYS5ib2NjYXNzaUBtaWNyb3NvZnQuY29tPokCTgQT\nAQoAOBYhBKnqkIFyT/rgSEw1oagc6iK8jH4uBQJccpvuAhsDBQsJCAcDBRUKCQgL\nBRYCAwEAAh4BAheAAAoJEKgc6iK8jH4uA7kP/RbwUH1C8RfWJWvtaDsvoJ5jnoB1\nlJDxUBEd+6j+AWTUD+fAAxLE/bcqxXzsPz4dscwpnoKmqVIpAdhTN+EvRZRLA1r/\nkbKlnDFnEm89MYYS1e8dGtXqa1zAPl+IxL46Da5/l8GsepOr9HftrPBjN56R/HIf\ntOwc9Vir1NLaC+S0CsAKwyAjpq8srjvrxFWr9a82+7GiBz2Wrc60vWIfaZuDKpVE\n4RpvEaiYoGEJEUp4wNhaVdQrhe8m6C0uczwq2t5aSjxuuso+rsN3PK/jvNrmxfbS\na0NMzwhZ92w+J7CFyg85c0OQ6hmZRTf6G2v8pFpWlbcb7sePlvYcEIeZik4Nx73T\nEkqwmX5WC0NPzj+wdBWG/G+fFIcUUaMZzcGjgy9MXD+RVVyGs6W2/Q7iPBzDxny6\nKJLjUK8xMGRLo3rvdAUqug3Gpe6dth/8XBp0cY1gk4n3OUluBWOXSEwW7zm3s77r\nK4s5JC/rBOgCeCNV+qXLydazn4qjQXixqb0ezyGGxO9w/+q9T7MBwQy5/Q25w4qL\nbcCxTLAhRpye2C1nCHt4GvH4SUjdh6wtHdkXjtyYMTRmMU40GN/PL5QFyyMS7nEC\nYiycLB99knGwsh1FX31Q4aU7qUWO6Ejhk9W43IZjQpaITXoyCwKnMaE+X6Uqk745\nio6PFV1+6ix1l8MhuQENBFieLi0BCAC8doYzfmC8HWjtP0Q0s6fpRwjwGTTOaxk8\nqOMW+vgVY5eAIWYOGX8kNdzUE1nnRgrGhqcOe+g0NvXNkE83KIeAZFL5k96/o+K9\nIJTSlrNzjWR3NsQPfjrQ4/pDcuwtxWBIaZNAF7GJNnjGeQ4dvVHwTzi1b3xrELxK\nYO3iiYkku5O2rrHxI2Pv8mBWZ/v6Zr81hutk6TtpsGGWRBEq2sAdS+qV+Bk+C8LJ\nsdOLeZLU9aVILtMPQkL0z3GTcb7IVknLPZ+aeraFRBLXO1k29J2JnTwECEkfOQep\nmBkGJ4FGHQ+eG7ejLd1i8BLFEeLk9ia2wLl6xiij1I2lplcuaLq7ABEBAAGJA1sE\nGAEKACYCGwIWIQSp6pCBck/64EhMNaGoHOoivIx+LgUCXFwb5AUJCWGINgEpwF0g\nBBkBCgAGBQJYni4tAAoJEEspZoBQeFFiy5EIAI2YXvth4tRojymdZ3oYiZRz3Xtx\nOJiiEsjZkP036k4pKdmtn1zxAPzd5W5kprk8AkWjjKyBSNS47i3lvjRFQXpKpUbG\nJ0CdjDCE2CaonMb1oh/pVbQ0VvMoPRyj1Jjz/gFCeXLFq8AcXrRYjh/aW6RNPj0Q\nnqL70ta6qFSavxrLPVkm02mFWEKlWNLtb7uzLM2KfCLI/ZZdsKSkTwZhWDQybp2o\nXO1fZdI7aSoLYQFY6pIjdIuTnQrqIrRKtk+ummBMMKBS18eyiJ1FR7cIp54Vektl\nVcaFOGI+MHDrDO4+hGfE+w59szW5ma60S92keJSWgOJQD4Nu/sPor9M+ZlcJEKgc\n6iK8jH4u21wP/RtYbohWfpBDSReU+ynG5QGLcELpSMHlCRz2ZxaV8bqGblGftjiW\neyvEZePOJpb5Sev20TnUBzzilZc1nLwOxP5tDZpEvo1j2bIY1YamZc7g7XE+xRbl\ndjiwGtj9PA3z2DME0iuxM/xN0Ghaea/vHeMim1miRJ8sbOheHwmwALPQzvTUV1Cq\nNgn8J1eUP/tC6wv/BnBwTkaHugqqmBglE9V8GptIVE5Tam/TfwVQXx72ZW2YHa4A\nbwHf+oUtH2/jOTjOj/kWT7docgSDj7kColJ7mwuZZ0NSwYhA5dKN1CWX7c65ENzN\nh4pIiM9Ula0tInRal2qK9YXy/GV0gFXwV/aFh22G/xtPRs0qqhBxr2lxGOg5XsAk\nSEu+nlCThjEZDQVXxmptdVVvHwh/+Lrconk3o/sUTFgZ9mroQYceJa1z9cIn1A1Z\nPb2SffXWU18lOuuC2Cw7XGx8QN1rWbmVVA0mvNQ6MpUYCOICy7bVIfUYcX6xuoWh\nTfu5lE0qUw8PhBGUaW+pqGvEDcM/PWhopx+mSqq/Ip4LfZ0Cn33KLV4SzJjnhC1Q\nRVQoUYpzBDREgOUo6eqwNSCM1ZxkOIoueOZ6TRoYrUaJUGAJOZvXVl6NfpizQ1bp\nTu1l6dz7U3JqYG/V/kr+IKxWJf/JhYjZ73Da9mx+2SuNOKj1SFohLNL3uQENBFie\nLj4BCADUpbwnWqJsjL6la8HdROHY/LePMvWiCJAK1tZX6HadW07FxCMlQPOhX6jj\nYI85BmYM1AZpEDRLqdkAUf6+lSY9VywXy6G8DsQTSiO+Fn6DWEJ9yYelLIQW0xMJ\ncWd55D9+tDlJFFfiE2OLjrSoxPRGjhB7iajsdNlD6JTjuJq60zAcxF7J2o6Keesw\nHVYooz460MLuVq3BeyNxH/d9B/y5n3ibSVgJc8PYkDRN2Y+ILuAXd/ia0GTphTM5\nj9R+mCJDuRRVZAgNfa9AJMPJ0QbIFnRdnwRTEGt6LYA/AIoBgwjiveTfr8N2LArD\nARNP6rV+Ugf3rW2bZPEoCv82bsx3ABEBAAGJAjwEGAEKACYCGwwWIQSp6pCBck/6\n4EhMNaGoHOoivIx+LgUCXFwb5AUJCWGIJQAKCRCoHOoivIx+LoL6EACYK7c/yOQH\nZtSfzkrfNpd/MiY1j6rpUr0mrbKBVKamJ1N5Ae48E2ETlRfM3B6fk+dqovKbD0gQ\noDHcCo201770pyoFwxyHZleiSWfQjNp4JCoXvGAh+AK6xfiPZIEzfLDrm3nrd38m\nrLEsUPRPdoyemAb2kKBoMmfkPt0e6WnqKxlFBngyF35jOFXnp//yGNCWvr4gibXD\nzIlMnQUXlYzKqZPnIwdEGyQT4KWLAHLCu5lzk6JmvMJPqTPU/uKbgKcHHy8cY0Xm\nxPOAPbnSbSYsuMcJpZMiIKBRozZk26fWdDJorWBPZ91OEmfSCx2X1P99UQId67SJ\n9V4EUbZjGDrsEJcosmg1JN2bFIKzI6VTrYvxA2ghPuowXgKZ3k/BuFXMA41hnP/P\npn8DjsYu/9yzV5TRYvQEVSGrN7c3tJGlyZrbZ3YxyDyniWZhrFmgVqdo3jZfhhgT\nxTnuSfUyhtA6jk5ECVuF+oxmWyjRzJW2XoPPpmYe9CQ2efHZ4RFqCO50keBAH0KH\nUCl3eg2E4HeALu++Aq9v07JyAyA6MYbTvHjrdMmHHDb3kHG3O/rPoH2120wYXHAW\nSBvoOOJZyT/4rF3BNcrLiPxDCi+mOe5vkX5jymHe4fho1kvh0mLLzeC9fKiJjExL\nyF2yrNrTFESt66057r3CIb8BcJXPGhxpXrkBDQRYni5MAQgAnBzmeIfxaXebmSJj\nwbH1ScEHIATXoDs1FtVumWTmfGS851lqoMBoemWPZleBoMTOza5cnv6EzPIGYRYL\nSd+GTDOAzNdnuHxULm8gUqEdoQ8+GwcTXCSjOsvuZJvIWjJ3Siz3JRnTsM8hrYoz\ntZZhDQqsmqmCyrmw5IsxInDfTd6XrdJ834TOS87pJTwFzrt3B4UuhMMGX8IWjPsG\nZ0ZRBbUMhAxt07+JV2lW9o7AA0H733NHjhZ4/mjn62WpDVFzHIkvdVaNbb5hGXrJ\nHbRIqQUj4tX32uYEkpd0Uy7KEtqh/HI+tW1nL47Ba6EEY+3IvFO+XJiy5Zhoe0ku\nNiLebwARAQABiQI8BBgBCgAmAhsgFiEEqeqQgXJP+uBITDWhqBzqIryMfi4FAlxc\nG+QFCQlhiBcACgkQqBzqIryMfi5icA//f5d9VR2F/p/iBRbKudu5HHp3YxAxKLe/\nT5FobOd9LBM4z8G9x6puaVP5bFjN5IMB67piUTVgSTDFwvS5sj538xRddTLg6gdo\ncE8qU6gb0Caj3eDm6aaPH6sz8Dkq0lV0AibiFZAlysgH3Jb0mavTLbES92LVTC+y\njgm6rKxazD7Xf7eKKAtU6Yv5hy8/RtkxqXUjiW5JuvM6GHrplFaoqLQqTTs84jmU\nJdAn5ocTHSZkWnrXD2ymNcSQ1Rb34JYOzhEZmqk7qID0HvTT2g7D52gP2Jw4AzNM\nkmf/tbB/ugWIBsEClwVkk6yUxjSTjjOq5p3Jg/9vqiEEml7xnSNwqY5w/FCIdwV/\nbcrDAvRYAY2whDUtjIBJrD5AzRq3A4FU9ErdkKNGToL1sAUZdyH+qsCuJl0eY/Ry\nlMdgYrKc4HWNOh+viG7ap/RxUULll3wXuwtcDapRe/lg4YABmORzgDPgXcGPODhS\nWdKeQid9kKucWUrjOXogxa28hO9P/6OhngUor9FECHqxa3dTEm9GAxRKJhJhWm8m\nwu2rTGBSOEDk918ffR+HyPJ5CoEUCj03vY1OJwcwhtCaKb83swuiXwDeZ7eXVRL7\n2nRMieLWYxNV8seKDFCm/7fXbNWpYe6HRtZfGiPVICJZbVHS73n4Kglxg03LKSXT\nZEG+OhK+ULy5Ag0EVMqyzgEQAN1wRSjfQMyZRcelT38yhZUiSti6KqljizjkWzVY\nkhFab3IXeW4m5uUv/N8J23h2tUhc4R3di1W5L3dvOMzY9cHeR4KucU3QA7TC/cUS\nQo+tdxj0HgXLMoTHUUeo2w7mX0NTeH7Evq3zEwWOJksAXgb4+8V5t/afBl1IC0gf\nNol/1iHkX6/49kSJ+0HoYEj7cPF8Il7IN55Xe/ZmsuucgjM6Wt3/ndJKmHyssDxA\npUnlK5Uj++039Q7SNRDtLoc8Y1LoL544bSADOMrRAXEKj4ACYNUs8I1pf80w8CTn\nHg7SEILesOqBMfYotz2pQ2x0KqfCOfetSe9YcZIu/Qdjx8qBm3a69Y6wSn40uIws\nW8lfEL+V2ltRsyCtmA1hNmreNc4tXtlXtWF6aZxT2wm97Gn8YjiQTEe7sfvNNcTH\nwP29KUofmIFtXCX2eMeqRWBhtqFE5uaDdI5UQyfjY9Au+Mc/d2WHMS1PGK/Z8NKy\n7huM24/yK7GxFbbPm3pZiWlV5kbl5f4bEPrBoqzdzoK0/N12UsfuWFV5m2YUIwW4\nBXaI26dzUM9Fc9ecbcoJXd7FzgmdKUi0/Gw7NYrbsL09zrAB+AQer602LHW1Aiqr\n93QkkB2ViWupYiGli2sC54qrAR4iEUATAk2AJIyXnjaI3DftExz/c4y8NuMwFXKc\nLxWHABEBAAGJAjwEGAEKACYCGwwWIQSp6pCBck/64EhMNaGoHOoivIx+LgUCXFwb\n4wUJDTUDlQAKCRCoHOoivIx+Lgf8D/0ZoaK2TUxsdcINtHxeKP8zIjnk1HJQxVDs\nLewL90rP/sqHplYdDItBHW3aQT+S82xmb2DaWcy1DJ+kDAPqKIEgYcIVCho+8dD/\nXwY3/vQQnRYt3thxj/REtLid97ldtWn0pw4f4sxwMbs0qXq/R9fnnoNXBBH6ctxA\n6dy4/QkBMY4LyaTnSYzvaB6JSwIC95MGl2/yn1WFCzdRPjxU1SLsSImCkBaG1uhK\nrX/rECSuQCktfG0hy+F2QqMxHofPonBUZTrfLchWHgqIzCx2JXXC0KsXjg7r+s4+\nm2krnB4jKOnyAaNmwhnOY+qqVcy/IvJsvOeOP1J6j2e7oTNtcrHb/tHxOhUVKiOo\nvzSoLB47PtnTv6cVtiBIOFKyfl1dS8Q+vPtRqvjWAW7vcAfygxXwvJUslGUMU46J\nvJwcFFE4RQk4Ixm69AabTCCwLUWV0Pnx3rTNJHMxl+qzpvVwVuogVydxH2oqvBTt\nBpCsfgrhH5gcYRozCBvLGDetFa9YaAV4ZvwGq3lhkFnI/h3EpIDGCeDTsJP4+C+n\nmI2wM/rXt3m1CpgeVKH87E2+vSOoliyqW/DnceBE8JHEwg3nWX50GI+iW0Vm8t2Z\n1Dx2TJsrJdXy2vHYZDFOCfnz4SO6IafJZOGMVHPGNHp2AWH5mY9ZYE2N52QMoyjk\n42IBCOLqCrkCDQRVFuFCARAA+tTCfBs+pRBg7lPr6DtI3SY4M+T5Ip2EQGuWS7t7\nriNP0rbtShc3x1GBokVNEOTOe6n28DTI0TA8D7Wa6WefKnBbDQPVe7AgWCC11gYX\nXIqcRIPlnvW7X8hZn6Fw/b+ep9Fnw6piihRk5fnYyspDBTRE/1DBBzHqOPfepHgI\nzh7qVe8MCfTdpRYsHXZEa9o0WYLoRXeg+yFvKmjj8+Bm4OyLQ5vN7uDqDT3ph8av\nM7RQvvqLZrXhycWuq4btT6Ba9oMZ10UzUF/HXaLgakscDX6FzBwgv2/lVauh3ie4\nJ+Au0lA4hYHCVhNZGgLsGG6aoMEDA2Ab6vLqVIeOj7dbOXLq5wLMJlywAZwtnoSn\nzxyPPKQarCl30lYDaXFakFGZpI10nRrRSy2acRcpuS5662cnU8kZzVl9mbxyrEpI\nzkc54ND+UzHvW6FVKqJLB/y2rQ6ZRE6cLahwO74LZoDc48JpVkdXCkz+F2yI4ust\nWcv0vdUQ+mLHbjUof6zGLcTVRMpteFpIozB6giF1ohayoNAgwywk69tMThNa5O4J\n405dDPDO4lNyl7nGLlxyL0oua16ibpz2WfYUsPsJmRJnB+8KZ5SzIGW7D/aprhYp\norYdpz6qynPtDmkD7zl5RHQCb8PqgrkkHPVVrdjHC7UdP/CcXjq1KIuKEG446xJI\nTXcAEQEAAYkCPAQYAQoAJgIbIBYhBKnqkIFyT/rgSEw1oagc6iK8jH4uBQJcXBvk\nBQkM6NUhAAoJEKgc6iK8jH4uEfoQALPHThbHLBEZ1ueHAnyamgz3kKC7KW4HkwgG\npTvJ/r3cqdt8SBcdPamWORK95HKq1VahEW6yqWSVrsbYxqdXl/mI2mNIJxRBiM/h\nwOuZVLSNpK4Ou/XRz3NMFllZBJtJS6JGGpRtnhGQKrvkw04UtITpDahDlweVdart\nE0FaB89TagWZy7oH32M5wzHqUHSNnOfQR5VpttRBVkuqnN4xRePjJvjJae31LsAq\njOrJcME08Y8zG10p3Pm6x0lOvrM9nf/MMYGEaMhGQFp4XhvQ6hi736nFyyQD6uHU\nvw140+Y51kHMbceKjaoju9qHNzddmhFAL+YMZL0dtNk9F4kDpTCfMNgft4Y0IUQT\nlYAkMDxdYK1l+jYTFrsDZhw5GV1kYQo2s3j66rT+SHlXY8SbyE33Hm544WxAbCGE\ndB/H7ADaQhbFobXalTb+/QfWE2FkAYTvgiRhEhfhdr0ed2zHoolIF+zDWu58D61T\nQj0xx1/+PbaVq4NQAWigimRfhYEJjo0dJCYUFOI9mces4Fh0aUGpB0lyvBub6zWc\nQkHM/2NSsGLWIxCOjxR1qjMdM3cfTQe6BX1ZoE4hjQf1tolhDT3rUx032x4QH1wt\n5CdP4/Wz2Mn8oGCPvRwCNzYLjT/h2V3BFqIcbwNpfiLFMGtEYf0VD6Po5y2uxHNB\nV4vxw1Q7uQINBFUXAM0BEADWd0Gq5bkX2WVMfwI8EQTnuJBRgJLmaLb8INg/Iykr\nztnx0t/D5bxZ7SMmycRpvKEEwST2NMzutPt4bxrbNx5FAAslzy93bd1mHH0r2xQh\nM/NKSNHsYOtpoeyf7vcRPaBkCqu6UzeWCrYcFzbrEDmMqKoeAekSWFyij/1Sm0hP\nYWK9qHYG7dhqS+t5rq0IGuX2LhcSbDubHysCZLvJxWzZspudrFgGkCX68oS94uy3\nERgrUUt9QFweWueC6XJxj+FIlK/1j3ZgKUnJZ13iRXrz2vOr84C82MLpAw/HPmcU\n73qZM5V0+RFCKRP4ISKeGhrLFSMVOLVkyNHYYBq+0os21VIGBA/L2kWv1Gy/MnPD\nyI4p05zzwXUu6f3iAwPqwwRqA+/gj2J5YooZa1mPGUutkz3KmKWymTBlbdr1MR/l\ndnuUAwdgXdOEj/YPskb8VsVzyEjyNpaPTQW1KmsWDJPztuQ/6cAPXCeaECL/110M\nTFY1esS4SM7zd75Rgg1w68hFm0D1TotmuPVW59DN2TzjVUCamOVgMSEfUBERGo00\nPHuGYqDlVt+gLeyOM/WOLJizTEAJEUVpR9tRspFHf9nXIOJdSaoL4opXtLog5nVB\n2sqT9qt9qPtBPbQiHJXimv5rBpjaPeBZA+RxolTMpPkFsSXVkNcvhx3P/uKvD9um\n0QARAQABiQRbBBgBCgAmAhsCFiEEqeqQgXJP+uBITDWhqBzqIryMfi4FAlxcG+QF\nCQzotZYCKcFdIAQZAQgABgUCVRcAzQAKCRAoa/fvzXckHteED/9mP07v96WdQwx/\noNJ2gCAmee43Xll5kLVa4TCuYLI+iPtLt1gKrtViw+M+oYhst5KT2jlfaj6T0GpD\nbbpqBGCzJ2Eas0dsnJRtN6zuvXX+tYWe28/PCEuB9QSOHqkVPG84aabqAsletGhW\nTKHWTQf7Aa1xlXgdBJ8NkZBUkwWQ5MGkKS0BP7xvaK6z5nOZSPskpodhKl51d4IR\ngWwK+j0tKdgsDqSjeSOfw2eM7/z4kSzDTsdxoBWvskaSQtMnw9qibfUrI5zgi/Yc\nkh2ModEoxdIAQWEtKR0dEHwVhOId76lq19sS6I4MKTfHZ7xGnXTozbeqjcTX0edA\n031aFC4XGpDTDlyA/XXABu97582NOvXLkPMcj/N8/P0MWJgtwJHMNwDqBHCsZmSy\nK7ZKHLC71yh5mUCSnLiu0cz/7rLB+VHI+SwPXBO8iPCZAupmf+cyICkINFCwgFyu\nLKYYARhSr6LqbOzo/ekQvz8b9q73ODqvhEN0T945AJdAt2BPtzb0LYOBaAxdEZsu\n2BcnWE+xERVK7mSeGHmfnh6smEZSx6uRawMYm6Y/YLtzQp6iBTqtNwYryl+PbRJ1\nv28e5ispmylCrRyb0CSgNqKbQufhKO71+peBBytb0Nj9VUYXGYe7vHCeZxgvTUnP\nbHoVjUXZSu+Tiu1Gky1EOFtEW/Se8QkQqBzqIryMfi7vyQ//Ttd4ZNBdaZkMYQh+\nCP3WsuXD4Vip8Gh+tcg/+zJMDWqkgoW9OOkWh1MjxJBSBjSLqm8e23GrgJrHdRBm\nfR6WbMCXST5ZmRzEN2MZ9DPFGKuzOe1BeWx3hFc6crCB7h5/I3yiiMhagF/kCiZz\nzQu4Ebcc8gzRH65BbBHbathVWF4EmP4ZUy2hPOspwMClCmGsqVY1zt4KPp1BeB/Y\ngZ5eL1kdLuvCRQkFglPNELDgziKREJYO89g8f6V6teJDy+l6DtuzwnkO3BT1PntQ\n17I8etv3lgGfL42q1QUjhXn0ER6cfWOEeD36MThkZ6WTdtZ+45ROZsvCSl9BlE05\nhT13mBluscvxu0bo1ReAFYG2aHG05mZ/2qyoVY1eJa+Eq/rDhdJP5E8IhDfr/kCm\nAhcpb/916Jc0BTSpinIcuWMQaeWtpwz332Pa87M3SLLm0p390p9R7P+OI2FYVMYU\n/6dEqz9vrsTWaBLZV8bnItjn6r2MOXn7bGD6HW6euE78Bt+/Q9N/D53cgw3HGaDE\n0JqFt4gzT9d7D+jCYy3K5uAWBnKjua3mwMcBnO4GmQwVLauWex8BARlYpBoqqL/V\n5CorLVbhjFLWAiy1GsX4RM9RksG9TN8CMvNp1ZTpnqouwEuTmrWKwdQek1rPBRj0\nXNBso9Rw94Z5NVIXEcH3O44UsWI=\n=AXgM\n-----END PGP PUBLIC KEY BLOCK-----\n```\n\n</details>\n"
  },
  {
    "path": "SupportedPlatforms.md",
    "content": "libzmq supports a large variety of platforms. The list of platforms can be found in the [README](README.md#platforms).\nThe degree to which this support is tested varies.\n\nPlatforms are currently assigned to one of the following categories:\n- supported platforms with primary CI (travis-ci.org, appveyor.com): https://travis-ci.org/zeromq/libzmq, https://ci.appveyor.com/project/zeromq/libzmq\n- supported platforms with secondary CI (openSUSE Build Service): https://build.opensuse.org/project/subprojects/network:messaging:zeromq\n- supported platforms with known active users\n- supported platforms without known active users\n- unsupported platforms\n\nSupported platforms with primary CI\n- have builds and tests run for the master branch\n- have builds and tests run for every pull request\n- it is a precondition for merging a pull request that no builds or tests of these platforms are broken\n- contributors can easily enable these builds and tests for their branches in their fork\n\nSupported platforms with secondary CI\n- have builds and tests run for the master branch\n- these are monitored periodically by the project maintainers, and efforts are made to fix any broken builds or tests in a timely manner\n- it is a precondition for a release that no builds or tests of these platforms are broken\n\nSupported platforms with known active users\n- have recently been reported to the maintainers (e.g. via pull requests modifying this document) as having working builds and possibly tests\n\nSupported platforms without known active users\n- have some platform-specific code within libzmq, but it is not known if it is still working\n- have been reported to the maintainers as having working builds and possibly tests only significant time/changes ago \n- or are assumed to work due to similarity to the above platforms\n\nUnsupported platforms\n- are either reported to be non-working for some reason that is not trivial to fix or are explicitly missing some required platform-specific code\n\n"
  },
  {
    "path": "acinclude.m4",
    "content": "dnl ##############################################################################\ndnl # LIBZMQ_CONFIG_LIBTOOL                                                      #\ndnl # Configure libtool. Requires AC_CANONICAL_HOST                              #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CONFIG_LIBTOOL],  [{\n    AC_REQUIRE([AC_CANONICAL_HOST])\n\n    # Libtool configuration for different targets\n    case \"${host_os}\" in\n        *mingw*|*cygwin*|*msys*)\n            # Disable static build by default\n            AC_DISABLE_STATIC\n        ;;\n        *)\n            # Everything else with static enabled\n            AC_ENABLE_STATIC\n        ;;\n    esac\n}])\n\ndnl ##############################################################################\ndnl # LIBZMQ_CHECK_LANG_ICC([action-if-found], [action-if-not-found])            #\ndnl # Check if the current language is compiled using ICC                        #\ndnl # Adapted from http://software.intel.com/en-us/forums/showthread.php?t=67984 #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CHECK_LANG_ICC],\n          [AC_CACHE_CHECK([whether we are using Intel _AC_LANG compiler],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler],\n          [_AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],\n[[#ifndef __INTEL_COMPILER\n       error if not ICC\n#endif\n]])],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler=\"yes\" ; $1],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler=\"no\" ; $2])\n])])\n\ndnl ##############################################################################\ndnl # LIBZMQ_CHECK_LANG_SUN_STUDIO([action-if-found], [action-if-not-found])     #\ndnl # Check if the current language is compiled using Sun Studio                 #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CHECK_LANG_SUN_STUDIO],\n          [AC_CACHE_CHECK([whether we are using Sun Studio _AC_LANG compiler],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler],\n          [_AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],\n[[#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C)\n       error if not sun studio\n#endif\n]])],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler=\"yes\" ; $1],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler=\"no\" ; $2])\n])])\n\ndnl ##############################################################################\ndnl # LIBZMQ_CHECK_LANG_CLANG([action-if-found], [action-if-not-found])          #\ndnl # Check if the current language is compiled using clang                      #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CHECK_LANG_CLANG],\n          [AC_CACHE_CHECK([whether we are using clang _AC_LANG compiler],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_clang_compiler],\n          [_AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],\n[[#ifndef __clang__\n       error if not clang\n#endif\n]])],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_clang_compiler=\"yes\" ; $1],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_clang_compiler=\"no\" ; $2])\n])])\n\ndnl ##############################################################################\ndnl # LIBZMQ_CHECK_LANG_GCC4([action-if-found], [action-if-not-found])           #\ndnl # Check if the current language is compiled using clang                      #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CHECK_LANG_GCC4],\n          [AC_CACHE_CHECK([whether we are using gcc >= 4 _AC_LANG compiler],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_gcc4_compiler],\n          [_AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],\n[[#if (!defined __GNUC__ || __GNUC__ < 4)\n       error if not gcc4 or higher\n#endif\n]])],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_gcc4_compiler=\"yes\" ; $1],\n          [libzmq_cv_[]_AC_LANG_ABBREV[]_gcc4_compiler=\"no\" ; $2])\n])])\n\ndnl ##############################################################################\ndnl # LIBZMQ_CHECK_DOC_BUILD                                                     #\ndnl # Check whether to build documentation and install man-pages                 #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CHECK_DOC_BUILD], [{\n\n    # Man pages are built/installed if asciidoctor and xmlto are present\n    #   --with-docs=no overrides this\n    AC_ARG_WITH([docs],\n        AS_HELP_STRING([--without-docs],\n            [Don't build and install man pages [default=build]]),\n        [with_docs=$withval])\n    AC_ARG_WITH([documentation], [AS_HELP_STRING([--without-documentation],\n        [Don't build and install man pages [default=build] DEPRECATED: use --without-docs])])\n\n    if test \"x$with_documentation\" = \"xno\"; then\n        AC_MSG_WARN([--without-documentation is DEPRECATED and will be removed in the next release, use --without-docs])\n    fi\n    if test \"x$with_docs\" = \"xno\" || test \"x$with_documentation\" = \"xno\"; then\n        libzmq_build_doc=\"no\"\n        libzmq_install_man=\"no\"\n    else\n        # Determine whether or not documentation should be built and installed.\n        libzmq_build_doc=\"yes\"\n        libzmq_install_man=\"yes\"\n        # Check for asciidoc and xmlto and don't build the docs if these are not installed.\n        AC_CHECK_PROG(libzmq_have_asciidoctor, asciidoctor, yes, no)\n        if test \"x$libzmq_have_asciidoctor\" = \"xno\"; then\n            libzmq_build_doc=\"no\"\n            # Tarballs built with 'make dist' ship with prebuilt documentation.\n            if ! test -f doc/zmq.7; then\n                libzmq_install_man=\"no\"\n                AC_MSG_WARN([You are building an unreleased version of 0MQ and asciidoctor is not installed.])\n                AC_MSG_WARN([Documentation will not be built and manual pages will not be installed.])\n            fi\n        fi\n\n        # Do not install man pages if on mingw\n        if test \"x$libzmq_on_mingw\" = \"xyes\"; then\n            libzmq_install_man=\"no\"\n        fi\n    fi\n\n    AC_MSG_CHECKING([whether to build documentation])\n    AC_MSG_RESULT([$libzmq_build_doc])\n\n    AC_MSG_CHECKING([whether to install manpages])\n    AC_MSG_RESULT([$libzmq_install_man])\n\n    AM_CONDITIONAL(BUILD_DOC, test \"x$libzmq_build_doc\" = \"xyes\")\n    AM_CONDITIONAL(INSTALL_MAN, test \"x$libzmq_install_man\" = \"xyes\")\n}])\n\ndnl ##############################################################################\ndnl # LIBZMQ_CHECK_LANG_COMPILER([action-if-found], [action-if-not-found])       #\ndnl # Check that compiler for the current language actually works                #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CHECK_LANG_COMPILER], [{\n    # Test that compiler for the current language actually works\n    AC_CACHE_CHECK([whether the _AC_LANG compiler works],\n                   [libzmq_cv_[]_AC_LANG_ABBREV[]_compiler_works],\n                   [AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],\n                   [libzmq_cv_[]_AC_LANG_ABBREV[]_compiler_works=\"yes\" ; $1],\n                   [libzmq_cv_[]_AC_LANG_ABBREV[]_compiler_works=\"no\" ; $2])\n                   ])\n\n    if test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_compiler_works\" != \"xyes\"; then\n        AC_MSG_ERROR([Unable to find a working _AC_LANG compiler])\n    fi\n}])\n\ndnl ##############################################################################\ndnl # LIBZMQ_CHECK_COMPILERS                                                     #\ndnl # Check compiler characteristics. This is so that we can AC_REQUIRE checks   #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CHECK_COMPILERS], [{\n    # For that the compiler works and try to come up with the type\n    AC_LANG_PUSH([C])\n    LIBZMQ_CHECK_LANG_COMPILER\n\n    LIBZMQ_CHECK_LANG_ICC\n    LIBZMQ_CHECK_LANG_SUN_STUDIO\n    LIBZMQ_CHECK_LANG_CLANG\n    LIBZMQ_CHECK_LANG_GCC4\n    AC_LANG_POP([C])\n\n    AC_LANG_PUSH(C++)\n    LIBZMQ_CHECK_LANG_COMPILER\n\n    LIBZMQ_CHECK_LANG_ICC\n    LIBZMQ_CHECK_LANG_SUN_STUDIO\n    LIBZMQ_CHECK_LANG_CLANG\n    LIBZMQ_CHECK_LANG_GCC4\n    AC_LANG_POP([C++])\n\n    # Set GCC and GXX variables correctly\n    if test \"x$GCC\" = \"xyes\"; then\n        if test \"xyes\" = \"x$libzmq_cv_c_intel_compiler\"; then\n            GCC=\"no\"\n        fi\n    fi\n\n    if test \"x$GXX\" = \"xyes\"; then\n        if test \"xyes\" = \"x$libzmq_cv_cxx_intel_compiler\"; then\n            GXX=\"no\"\n        fi\n    fi\n}])\n\ndnl ############################################################################\ndnl # LIBZMQ_CHECK_LANG_FLAG([flag], [action-if-found], [action-if-not-found]) #\ndnl # Check if the compiler supports given flag. Works for C and C++           #\ndnl # Sets libzmq_cv_[]_AC_LANG_ABBREV[]_supports_flag_[FLAG]=yes/no           #\ndnl ############################################################################\nAC_DEFUN([LIBZMQ_CHECK_LANG_FLAG], [{\n\n    AC_REQUIRE([AC_PROG_GREP])\n\n    AC_MSG_CHECKING([whether _AC_LANG compiler supports $1])\n\n    libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag_save=$ac_[]_AC_LANG_ABBREV[]_werror_flag\n    ac_[]_AC_LANG_ABBREV[]_werror_flag=\"yes\"\n\n    case \"x[]_AC_LANG_ABBREV\" in\n        xc)\n            libzmq_cv_check_lang_flag_save_CFLAGS=\"$CFLAGS\"\n            CFLAGS=\"$CFLAGS $1\"\n        ;;\n        xcxx)\n            libzmq_cv_check_lang_flag_save_CPPFLAGS=\"$CPPFLAGS\"\n            CPPFLAGS=\"$CPPFLAGS $1\"\n        ;;\n        *)\n            AC_MSG_WARN([testing compiler characteristic on an unknown language])\n        ;;\n    esac\n\n    AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],\n                      # This hack exist for ICC, which outputs unknown options as remarks\n                      # Remarks are not turned into errors even with -Werror on\n                      [if ($GREP 'ignoring unknown' conftest.err ||\n                           $GREP 'not supported' conftest.err) >/dev/null 2>&1; then\n                           eval AS_TR_SH(libzmq_cv_[]_AC_LANG_ABBREV[]_supports_flag_$1)=\"no\"\n                       else\n                           eval AS_TR_SH(libzmq_cv_[]_AC_LANG_ABBREV[]_supports_flag_$1)=\"yes\"\n                       fi],\n                      [eval AS_TR_SH(libzmq_cv_[]_AC_LANG_ABBREV[]_supports_flag_$1)=\"no\"])\n\n    case \"x[]_AC_LANG_ABBREV\" in\n        xc)\n            CFLAGS=\"$libzmq_cv_check_lang_flag_save_CFLAGS\"\n        ;;\n        xcxx)\n            CPPFLAGS=\"$libzmq_cv_check_lang_flag_save_CPPFLAGS\"\n        ;;\n        *)\n            # nothing to restore\n        ;;\n    esac\n\n    # Restore the werror flag\n    ac_[]_AC_LANG_ABBREV[]_werror_flag=$libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag_save\n\n    # Call the action as the flags are restored\n    AS_IF([eval test x$]AS_TR_SH(libzmq_cv_[]_AC_LANG_ABBREV[]_supports_flag_$1)[ = \"xyes\"],\n          [AC_MSG_RESULT(yes) ; $2], [AC_MSG_RESULT(no) ; $3])\n\n}])\n\ndnl ####################################################################################\ndnl # LIBZMQ_CHECK_LANG_FLAG_PREPEND([flag], [action-if-found], [action-if-not-found]) #\ndnl # Check if the compiler supports given flag. Works for C and C++                   #\ndnl # This macro prepends the flag to CFLAGS or CPPFLAGS accordingly                   #\ndnl # Sets libzmq_cv_[]_AC_LANG_ABBREV[]_supports_flag_[FLAG]=yes/no                   #\ndnl ####################################################################################\nAC_DEFUN([LIBZMQ_CHECK_LANG_FLAG_PREPEND], [{\n    LIBZMQ_CHECK_LANG_FLAG([$1])\n    case \"x[]_AC_LANG_ABBREV\" in\n       xc)\n            AS_IF([eval test x$]AS_TR_SH(libzmq_cv_[]_AC_LANG_ABBREV[]_supports_flag_$1)[ = \"xyes\"],\n                  [CFLAGS=\"$1 $CFLAGS\"; $2], $3)\n       ;;\n       xcxx)\n            AS_IF([eval test x$]AS_TR_SH(libzmq_cv_[]_AC_LANG_ABBREV[]_supports_flag_$1)[ = \"xyes\"],\n                  [CPPFLAGS=\"$1 $CPPFLAGS\"; $2], $3)\n       ;;\n    esac\n}])\n\ndnl ##############################################################################\ndnl # LIBZMQ_CHECK_ENABLE_DEBUG([action-if-found], [action-if-not-found])        #\ndnl # Check whether to enable debug build and set compiler flags accordingly     #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CHECK_ENABLE_DEBUG], [{\n\n    # Require compiler specifics\n    AC_REQUIRE([LIBZMQ_CHECK_COMPILERS])\n\n    # This flag is checked also in\n    AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug],\n        [enable debugging information [default=disabled]])])\n\n    AC_MSG_CHECKING(whether to enable debugging information)\n\n    if test \"x$enable_debug\" = \"xyes\"; then\n\n        # GCC, clang and ICC\n        if test \"x$GCC\" = \"xyes\" -o \\\n                \"x$libzmq_cv_c_intel_compiler\" = \"xyes\" -o \\\n                \"x$libzmq_cv_c_clang_compiler\" = \"xyes\"; then\n            CFLAGS=\"-g -O0 \"\n        elif test \"x$libzmq_cv_c_sun_studio_compiler\" = \"xyes\"; then\n            CFLAGS=\"-g0 \"\n        fi\n\n        # GCC, clang and ICC\n        if test \"x$GXX\" = \"xyes\" -o \\\n                \"x$libzmq_cv_cxx_intel_compiler\" = \"xyes\" -o \\\n                \"x$libzmq_cv_cxx_clang_compiler\" = \"xyes\"; then\n            CPPFLAGS=\"-g -O0 \"\n            CXXFLAGS=\"-g -O0 \"\n        # Sun studio\n        elif test \"x$libzmq_cv_cxx_sun_studio_compiler\" = \"xyes\"; then\n            CPPFLAGS=\"-g0 \"\n            CXXFLAGS=\"-g0 \"\n        fi\n\n        if test \"x$ZMQ_ORIG_CFLAGS\" != \"xnone\"; then\n            CFLAGS=\"${CFLAGS} ${ZMQ_ORIG_CFLAGS}\"\n        fi\n        if test \"x$ZMQ_ORIG_CPPFLAGS\" != \"xnone\"; then\n            CPPFLAGS=\"${CPPFLAGS} ${ZMQ_ORIG_CPPFLAGS}\"\n        fi\n        if test \"x$ZMQ_ORIG_CXXFLAGS\" != \"xnone\"; then\n            CXXFLAGS=\"${CXXFLAGS} ${ZMQ_ORIG_CXXFLAGS}\"\n        fi\n        AC_MSG_RESULT(yes)\n    else\n        AC_MSG_RESULT(no)\n    fi\n}])\n\ndnl ##############################################################################\ndnl # LIBZMQ_WITH_GCOV([action-if-found], [action-if-not-found])                 #\ndnl # Check whether to build with code coverage                                  #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_WITH_GCOV], [{\n    # Require compiler specifics\n    AC_REQUIRE([LIBZMQ_CHECK_COMPILERS])\n\n    AC_ARG_WITH(gcov, [AS_HELP_STRING([--with-gcov=yes/no],\n                      [with GCC Code Coverage reporting.])],\n                      [ZMQ_GCOV=\"$withval\"])\n\n    AC_MSG_CHECKING(whether to enable code coverage)\n\n    if test \"x$ZMQ_GCOV\" = \"xyes\"; then\n\n        if test \"x$GXX\" != \"xyes\"; then\n            AC_MSG_ERROR([--with-gcov=yes works only with GCC])\n        fi\n\n        CFLAGS=\"-g -O0 -fprofile-arcs -ftest-coverage\"\n        if test \"x${ZMQ_ORIG_CPPFLAGS}\" != \"xnone\"; then\n            CFLAGS=\"${CFLAGS} ${ZMQ_ORIG_CFLAGS}\"\n        fi\n\n        CPPFLAGS=\"-g -O0 -fprofile-arcs -ftest-coverage\"\n        if test \"x${ZMQ_ORIG_CPPFLAGS}\" != \"xnone\"; then\n            CPPFLAGS=\"${CPPFLAGS} ${ZMQ_ORIG_CPPFLAGS}\"\n        fi\n\n        CXXFLAGS=\"-fprofile-arcs\"\n        if test \"x${ZMQ_ORIG_CXXFLAGS}\" != \"xnone\"; then\n            CXXFLAGS=\"${CXXFLAGS} ${ZMQ_ORIG_CXXFLAGS}\"\n        fi\n\n        LIBS=\"-lgcov ${LIBS}\"\n    fi\n\n    AS_IF([test \"x$ZMQ_GCOV\" = \"xyes\"],\n          [AC_MSG_RESULT(yes) ; $1], [AC_MSG_RESULT(no) ; $2])\n}])\n\ndnl ##############################################################################\ndnl # LIBZMQ_CHECK_WITH_FLAG([flags], [macro])                                   #\ndnl # Runs a normal autoconf check with compiler flags                           #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CHECK_WITH_FLAG], [{\n    libzmq_check_with_flag_save_CFLAGS=\"$CFLAGS\"\n    libzmq_check_with_flag_save_CPPFLAGS=\"$CPPFLAGS\"\n\n    CFLAGS=\"$CFLAGS $1\"\n    CPPFLAGS=\"$CPPFLAGS $1\"\n\n    # Execute the macro\n    $2\n\n    CFLAGS=\"$libzmq_check_with_flag_save_CFLAGS\"\n    CPPFLAGS=\"$libzmq_check_with_flag_save_CPPFLAGS\"\n}])\n\ndnl ##############################################################################\ndnl # LIBZMQ_LANG_WALL([action-if-found], [action-if-not-found])                 #\ndnl # How to define -Wall for the current compiler                               #\ndnl # Sets libzmq_cv_[]_AC_LANG_ABBREV[]__wall_flag variable to found style      #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_LANG_WALL], [{\n\n    AC_MSG_CHECKING([how to enable additional warnings for _AC_LANG compiler])\n\n    libzmq_cv_[]_AC_LANG_ABBREV[]_wall_flag=\"\"\n\n    # C compilers\n    case \"x[]_AC_LANG_ABBREV\" in\n       xc)\n            # GCC, clang and ICC\n            if test \"x$GCC\" = \"xyes\" -o \\\n                    \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler\" = \"xyes\" -o \\\n                    \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_clang_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_wall_flag=\"-Wall\"\n            # Sun studio\n            elif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_wall_flag=\"-v\"\n            fi\n       ;;\n       xcxx)\n            # GCC, clang and ICC\n            if test \"x$GXX\" = \"xyes\" -o \\\n                    \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler\" = \"xyes\" -o \\\n                    \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_clang_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_wall_flag=\"-Wall\"\n            # Sun studio\n            elif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_wall_flag=\"+w\"\n            fi\n       ;;\n       *)\n       ;;\n    esac\n\n    # Call the action\n    if test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_wall_flag\" != \"x\"; then\n        AC_MSG_RESULT([$libzmq_cv_[]_AC_LANG_ABBREV[]_wall_flag])\n        $1\n    else\n        AC_MSG_RESULT([not found])\n        $2\n    fi\n}])\n\ndnl ####################################################################\ndnl # LIBZMQ_LANG_STRICT([action-if-found], [action-if-not-found])     #\ndnl # Check how to turn on strict standards compliance                 #\ndnl ####################################################################\nAC_DEFUN([LIBZMQ_LANG_STRICT], [{\n    AC_MSG_CHECKING([how to enable strict standards compliance in _AC_LANG compiler])\n\n    libzmq_cv_[]_AC_LANG_ABBREV[]_strict_flag=\"\"\n\n    # C compilers\n    case \"x[]_AC_LANG_ABBREV\" in\n       xc)\n            # GCC, clang and ICC\n            if test \"x$GCC\" = \"xyes\" -o \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_clang_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_strict_flag=\"-pedantic\"\n            elif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_strict_flag=\"-strict-ansi\"\n            # Sun studio\n            elif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_strict_flag=\"-Xc\"\n            fi\n       ;;\n       xcxx)\n            # GCC, clang and ICC\n            if test \"x$GXX\" = \"xyes\" -o \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_clang_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_strict_flag=\"-pedantic\"\n            elif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_strict_flag=\"-strict-ansi\"\n            # Sun studio\n            elif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_strict_flag=\"-compat=5\"\n            fi\n       ;;\n       *)\n       ;;\n    esac\n\n    # Call the action\n    if test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_strict_flag\" != \"x\"; then\n        AC_MSG_RESULT([$libzmq_cv_[]_AC_LANG_ABBREV[]_strict_flag])\n        $1\n    else\n        AC_MSG_RESULT([not found])\n        $2\n    fi\n}])\n\ndnl ########################################################################\ndnl # LIBZMQ_LANG_WERROR([action-if-found], [action-if-not-found])         #\ndnl # Check how to turn warnings to errors                                 #\ndnl ########################################################################\nAC_DEFUN([LIBZMQ_LANG_WERROR], [{\n    AC_MSG_CHECKING([how to turn warnings to errors in _AC_LANG compiler])\n\n    libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag=\"\"\n\n    # C compilers\n    case \"x[]_AC_LANG_ABBREV\" in\n       xc)\n            # GCC, clang and ICC\n            if test \"x$GCC\" = \"xyes\" -o \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag=\"-Werror\"\n            # Sun studio\n            elif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag=\"-errwarn=%all\"\n            fi\n       ;;\n       xcxx)\n            # GCC, clang and ICC\n            if test \"x$GXX\" = \"xyes\" -o \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag=\"-Werror\"\n            # Sun studio\n            elif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler\" = \"xyes\"; then\n                libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag=\"-errwarn=%all\"\n            fi\n       ;;\n       *)\n       ;;\n    esac\n\n    # Call the action\n    if test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag\" != \"x\"; then\n        AC_MSG_RESULT([$libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag])\n        $1\n    else\n        AC_MSG_RESULT([not found])\n        $2\n    fi\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_LANG_PRAGMA([pragma], [action-if-found], [action-if-not-found]) #\ndnl # Check if the compiler supports given pragma                                  #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_LANG_PRAGMA], [{\n    # Need to know how to enable all warnings\n    LIBZMQ_LANG_WALL\n\n    AC_MSG_CHECKING([whether _AC_LANG compiler supports pragma $1])\n\n    # Save flags\n    libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag_save=$ac_[]_AC_LANG_ABBREV[]_werror_flag\n    ac_[]_AC_LANG_ABBREV[]_werror_flag=\"yes\"\n\n    if test \"x[]_AC_LANG_ABBREV\" = \"xc\"; then\n        libzmq_cv_check_lang_pragma_save_CFLAGS=\"$CFLAGS\"\n        CFLAGS=\"$CFLAGS $libzmq_cv_[]_AC_LANG_ABBREV[]_wall_flag\"\n    elif test \"x[]_AC_LANG_ABBREV\" = \"xcxx\"; then\n        libzmq_cv_check_lang_pragma_save_CPPFLAGS=\"$CPPFLAGS\"\n        CPPFLAGS=\"$CPPFLAGS $libzmq_cv_[]_AC_LANG_ABBREV[]_wall_flag\"\n    else\n        AC_MSG_WARN([testing compiler characteristic on an unknown language])\n    fi\n\n    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[#pragma $1]])],\n                      [eval AS_TR_SH(libzmq_cv_[]_AC_LANG_ABBREV[]_supports_pragma_$1)=\"yes\" ; AC_MSG_RESULT(yes)],\n                      [eval AS_TR_SH(libzmq_cv_[]_AC_LANG_ABBREV[]_supports_pragma_$1)=\"no\" ; AC_MSG_RESULT(no)])\n\n    if test \"x[]_AC_LANG_ABBREV\" = \"xc\"; then\n        CFLAGS=\"$libzmq_cv_check_lang_pragma_save_CFLAGS\"\n    elif test \"x[]_AC_LANG_ABBREV\" = \"xcxx\"; then\n        CPPFLAGS=\"$libzmq_cv_check_lang_pragma_save_CPPFLAGS\"\n    fi\n\n    ac_[]_AC_LANG_ABBREV[]_werror_flag=$libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag_save\n\n    # Call the action as the flags are restored\n    AS_IF([eval test x$]AS_TR_SH(libzmq_cv_[]_AC_LANG_ABBREV[]_supports_pragma_$1)[ = \"xyes\"],\n          [$2], [$3])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_LANG_VISIBILITY([action-if-found], [action-if-not-found])       #\ndnl # Check if the compiler supports dso visibility                                #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_LANG_VISIBILITY], [{\n\n    libzmq_cv_[]_AC_LANG_ABBREV[]_visibility_flag=\"\"\n\n    if test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler\" = \"xyes\" -o \\\n            \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_clang_compiler\" = \"xyes\" -o \\\n            \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_gcc4_compiler\" = \"xyes\"; then\n        LIBZMQ_CHECK_LANG_FLAG([-fvisibility=hidden],\n                               [libzmq_cv_[]_AC_LANG_ABBREV[]_visibility_flag=\"-fvisibility=hidden\"])\n    elif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler\" = \"xyes\"; then\n        LIBZMQ_CHECK_LANG_FLAG([-xldscope=hidden],\n                               [libzmq_cv_[]_AC_LANG_ABBREV[]_visibility_flag=\"-xldscope=hidden\"])\n    fi\n\n    AC_MSG_CHECKING(whether _AC_LANG compiler supports dso visibility)\n\n    AS_IF([test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_visibility_flag\" != \"x\"],\n          [AC_MSG_RESULT(yes) ; $1], [AC_MSG_RESULT(no) ; $2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_SOCK_CLOEXEC([action-if-found], [action-if-not-found])          #\ndnl # Check if SOCK_CLOEXEC is supported                                           #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_SOCK_CLOEXEC], [{\n    AC_CACHE_CHECK([whether SOCK_CLOEXEC is supported], [libzmq_cv_sock_cloexec],\n        [AC_TRY_RUN([/* SOCK_CLOEXEC test */\n#include <sys/types.h>\n#include <sys/socket.h>\n\nint main (int argc, char *argv [])\n{\n    int s = socket (PF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);\n    return (s == -1);\n}\n        ],\n        [libzmq_cv_sock_cloexec=\"yes\"],\n        [libzmq_cv_sock_cloexec=\"no\"],\n        [libzmq_cv_sock_cloexec=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_sock_cloexec\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_O_CLOEXEC([action-if-found], [action-if-not-found])          #\ndnl # Check if O_CLOEXEC is supported                                           #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_O_CLOEXEC], [{\n    AC_CACHE_CHECK([whether O_CLOEXEC is supported], [libzmq_cv_o_cloexec],\n        [AC_TRY_RUN([/* O_CLOEXEC test */\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n\nint main (int argc, char *argv [])\n{\n    int s = open (\"/dev/null\", O_CLOEXEC | O_RDONLY);\n    return (s == -1);\n}\n        ],\n        [libzmq_cv_o_cloexec=\"yes\"],\n        [libzmq_cv_o_cloexec=\"no\"],\n        [libzmq_cv_o_cloexec=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_o_cloexec\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_EVENTFD_CLOEXEC([action-if-found], [action-if-not-found])          #\ndnl # Check if EFD_CLOEXEC is supported                                           #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_EVENTFD_CLOEXEC], [{\n    AC_CACHE_CHECK([whether EFD_CLOEXEC is supported], [libzmq_cv_efd_cloexec],\n        [AC_TRY_RUN([/* EFD_CLOEXEC test */\n#include <sys/eventfd.h>\n\nint main (int argc, char *argv [])\n{\n    int s = eventfd (0, EFD_CLOEXEC);\n    return (s == -1);\n}\n        ],\n        [libzmq_cv_efd_cloexec=\"yes\"],\n        [libzmq_cv_efd_cloexec=\"no\"],\n        [libzmq_cv_efd_cloexec=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_efd_cloexec\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_ATOMIC_INSTRINSICS([action-if-found], [action-if-not-found])    #\ndnl # Check if compiler supoorts __atomic_Xxx intrinsics                           #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_ATOMIC_INTRINSICS], [{\n    AC_MSG_CHECKING(whether compiler supports __atomic_Xxx intrinsics)\n    AC_LINK_IFELSE([AC_LANG_SOURCE([\n/* atomic intrinsics test */\nint v = 0;\nint main (int, char **)\n{\n    int t = __atomic_add_fetch (&v, 1, __ATOMIC_ACQ_REL);\n    return t;\n}\n    ])],\n    [AC_MSG_RESULT(yes) ; GCC_ATOMIC_BUILTINS_SUPPORTED=1 libzmq_cv_has_atomic_instrisics=\"yes\" ; $1])\n\n    if test \"x$GCC_ATOMIC_BUILTINS_SUPPORTED\" != x1; then\n        save_LIBS=$LIBS\n        LIBS=\"$LIBS -latomic\"\n        AC_LINK_IFELSE([AC_LANG_SOURCE([\n        /* atomic intrinsics test */\n        int v = 0;\n        int main (int, char **)\n        {\n            int t = __atomic_add_fetch (&v, 1, __ATOMIC_ACQ_REL);\n            return t;\n        }\n        ])],\n        [AC_MSG_RESULT(yes) ; libzmq_cv_has_atomic_instrisics=\"yes\" PKGCFG_LIBS_PRIVATE=\"$PKGCFG_LIBS_PRIVATE -latomic\" ; $1],\n        [AC_MSG_RESULT(no) ; libzmq_cv_has_atomic_instrisics=\"no\" LIBS=$save_LIBS ; $2])\n    fi\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_SO_BINDTODEVICE([action-if-found], [action-if-not-found])          #\ndnl # Check if SO_BINDTODEVICE is supported                                           #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_SO_BINDTODEVICE], [{\n    AC_CACHE_CHECK([whether SO_BINDTODEVICE is supported], [libzmq_cv_so_bindtodevice],\n        [AC_TRY_RUN([/* SO_BINDTODEVICE test */\n#include <sys/socket.h>\n\nint main (int argc, char *argv [])\n{\n/* Actually making the setsockopt() call requires CAP_NET_RAW */\n#ifndef SO_BINDTODEVICE\n    return 1;\n#else\n    return 0;\n#endif\n}\n        ],\n        [libzmq_cv_so_bindtodevice=\"yes\"],\n        [libzmq_cv_so_bindtodevice=\"no\"],\n        [libzmq_cv_so_bindtodevice=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_so_bindtodevice\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_SO_KEEPALIVE([action-if-found], [action-if-not-found])          #\ndnl # Check if SO_KEEPALIVE is supported                                           #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_SO_KEEPALIVE], [{\n    AC_CACHE_CHECK([whether SO_KEEPALIVE is supported], [libzmq_cv_so_keepalive],\n        [AC_TRY_RUN([/* SO_KEEPALIVE test */\n#include <sys/types.h>\n#include <sys/socket.h>\n\nint main (int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return (\n        ((s = socket (PF_INET, SOCK_STREAM, 0)) == -1) ||\n        ((rc = setsockopt (s, SOL_SOCKET, SO_KEEPALIVE, (char*) &opt, sizeof (int))) == -1)\n    );\n}\n        ],\n        [libzmq_cv_so_keepalive=\"yes\"],\n        [libzmq_cv_so_keepalive=\"no\"],\n        [libzmq_cv_so_keepalive=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_so_keepalive\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_TCP_KEEPCNT([action-if-found], [action-if-not-found])           #\ndnl # Check if TCP_KEEPCNT is supported                                            #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_TCP_KEEPCNT], [{\n    AC_CACHE_CHECK([whether TCP_KEEPCNT is supported], [libzmq_cv_tcp_keepcnt],\n        [AC_TRY_RUN([/* TCP_KEEPCNT test */\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n\nint main (int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return (\n        ((s = socket (PF_INET, SOCK_STREAM, 0)) == -1) ||\n        ((rc = setsockopt (s, SOL_SOCKET, SO_KEEPALIVE, (char*) &opt, sizeof (int))) == -1) ||\n        ((rc = setsockopt (s, IPPROTO_TCP, TCP_KEEPCNT, (char*) &opt, sizeof (int))) == -1)\n    );\n}\n        ],\n        [libzmq_cv_tcp_keepcnt=\"yes\"],\n        [libzmq_cv_tcp_keepcnt=\"no\"],\n        [libzmq_cv_tcp_keepcnt=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_tcp_keepcnt\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_TCP_KEEPIDLE([action-if-found], [action-if-not-found])          #\ndnl # Check if TCP_KEEPIDLE is supported                                           #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_TCP_KEEPIDLE], [{\n    AC_CACHE_CHECK([whether TCP_KEEPIDLE is supported], [libzmq_cv_tcp_keepidle],\n        [AC_TRY_RUN([/* TCP_KEEPIDLE test */\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n\nint main (int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return (\n        ((s = socket (PF_INET, SOCK_STREAM, 0)) == -1) ||\n        ((rc = setsockopt (s, SOL_SOCKET, SO_KEEPALIVE, (char*) &opt, sizeof (int))) == -1) ||\n        ((rc = setsockopt (s, IPPROTO_TCP, TCP_KEEPIDLE, (char*) &opt, sizeof (int))) == -1)\n    );\n}\n        ],\n        [libzmq_cv_tcp_keepidle=\"yes\"],\n        [libzmq_cv_tcp_keepidle=\"no\"],\n        [libzmq_cv_tcp_keepidle=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_tcp_keepidle\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_TCP_KEEPINTVL([action-if-found], [action-if-not-found])          #\ndnl # Check if TCP_KEEPINTVL is supported                                           #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_TCP_KEEPINTVL], [{\n    AC_CACHE_CHECK([whether TCP_KEEPINTVL is supported], [libzmq_cv_tcp_keepintvl],\n        [AC_TRY_RUN([/* TCP_KEEPINTVL test */\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n\nint main (int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return (\n        ((s = socket (PF_INET, SOCK_STREAM, 0)) == -1) ||\n        ((rc = setsockopt (s, SOL_SOCKET, SO_KEEPALIVE, (char*) &opt, sizeof (int))) == -1) ||\n        ((rc = setsockopt (s, IPPROTO_TCP, TCP_KEEPINTVL, (char*) &opt, sizeof (int))) == -1)\n    );\n}\n        ],\n        [libzmq_cv_tcp_keepintvl=\"yes\"],\n        [libzmq_cv_tcp_keepintvl=\"no\"],\n        [libzmq_cv_tcp_keepintvl=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_tcp_keepintvl\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_TCP_KEEPALIVE([action-if-found], [action-if-not-found])         #\ndnl # Check if TCP_KEEPALIVE is supported                                          #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_TCP_KEEPALIVE], [{\n    AC_CACHE_CHECK([whether TCP_KEEPALIVE is supported], [libzmq_cv_tcp_keepalive],\n        [AC_TRY_RUN([/* TCP_KEEPALIVE test */\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n\nint main (int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return (\n        ((s = socket (PF_INET, SOCK_STREAM, 0)) == -1) ||\n        ((rc = setsockopt (s, SOL_SOCKET, SO_KEEPALIVE, (char*) &opt, sizeof (int))) == -1) ||\n        ((rc = setsockopt (s, IPPROTO_TCP, TCP_KEEPALIVE, (char*) &opt, sizeof (int))) == -1)\n    );\n}\n        ],\n        [libzmq_cv_tcp_keepalive=\"yes\"],\n        [libzmq_cv_tcp_keepalive=\"no\"],\n        [libzmq_cv_tcp_keepalive=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_tcp_keepalive\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_SO_PRIORITY([action-if-found], [action-if-not-found])           #\ndnl # Check if SO_PRIORITY is supported                                            #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_SO_PRIORITY], [{\n    AC_CACHE_CHECK([whether SO_PRIORITY is supported], [libzmq_cv_so_priority],\n        [AC_TRY_RUN([/* SO_PRIORITY test */\n#include <sys/types.h>\n#include <sys/socket.h>\n\nint main (int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return (\n        ((s = socket (PF_INET, SOCK_STREAM, 0)) == -1) ||\n        ((rc = setsockopt (s, SOL_SOCKET, SO_PRIORITY, (char*) &opt, sizeof (int))) == -1)\n    );\n}\n        ],\n        [libzmq_cv_so_priority=\"yes\"],\n        [libzmq_cv_so_priority=\"no\"],\n        [libzmq_cv_so_priority=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_so_priority\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_GETRANDOM([action-if-found], [action-if-not-found])  #\ndnl # Checks if getrandom is supported                                  #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_GETRANDOM], [{\n    AC_CACHE_CHECK([whether getrandom is supported], [libzmq_cv_getrandom],\n        [AC_TRY_RUN([/* thread-local storage test */\n#include <sys/random.h>\n\nint main (int argc, char *argv [])\n{\n    char buf[4];\n    int rc = getrandom(buf, 4, 0);\n    return rc == -1 ? 1 : 0;\n}\n        ],\n        [libzmq_cv_getrandom=\"yes\"],\n        [libzmq_cv_getrandom=\"no\"],\n        [libzmq_cv_getrandom=\"not during cross-compile\"]\n        )]\n    )\n    AS_IF([test \"x$libzmq_cv_getrandom\" = \"xyes\"], [$1], [$2])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_POLLER_KQUEUE([action-if-found], [action-if-not-found])         #\ndnl # Checks kqueue polling system                                                 #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_POLLER_KQUEUE], [{\n    AC_LINK_IFELSE([\n        AC_LANG_PROGRAM([\n#include <sys/types.h>\n#include <sys/event.h>\n#include <sys/time.h>\n        ],[[\nstruct kevent t_kev;\nkqueue();\n        ]])],\n        [$1], [$2]\n    )\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_POLLER_EPOLL_RUN([action-if-found], [action-if-not-found])      #\ndnl # LIBZMQ_CHECK_POLLER_EPOLL_CLOEXEC([action-if-found], [action-if-not-found])  #\ndnl # Checks epoll polling system can actually run #\ndnl # For cross-compile, only requires that epoll can link #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_POLLER_EPOLL], [{\n    AC_RUN_IFELSE([\n        AC_LANG_PROGRAM([\n#include <sys/epoll.h>\n        ],[[\nstruct epoll_event t_ev;\nint r;\nr = epoll_create(10);\nreturn(r < 0);\n        ]])],\n        [$1],[$2],[\n            AC_LINK_IFELSE([\n                AC_LANG_PROGRAM([\n#include <sys/epoll.h>\n                ],[[\nstruct epoll_event t_ev;\nepoll_create(10);\n                ]])],\n                [$1], [$2]\n            )\n        ]\n    )\n}])\n\nAC_DEFUN([LIBZMQ_CHECK_POLLER_EPOLL_CLOEXEC], [{\n    AC_RUN_IFELSE([\n        AC_LANG_PROGRAM([\n#include <sys/epoll.h>\n        ],[[\nstruct epoll_event t_ev;\nint r;\nr = epoll_create1(EPOLL_CLOEXEC);\nreturn(r < 0);\n        ]])],\n        [$1],[$2],[\n            AC_LINK_IFELSE([\n                AC_LANG_PROGRAM([\n#include <sys/epoll.h>\n                ],[[\nstruct epoll_event t_ev;\nepoll_create1(EPOLL_CLOEXEC);\n                ]])],\n                [$1], [$2]\n            )\n        ]\n    )\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_POLLER_DEVPOLL([action-if-found], [action-if-not-found])        #\ndnl # Checks devpoll polling system                                                #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_POLLER_DEVPOLL], [{\n    AC_LINK_IFELSE([\n        AC_LANG_PROGRAM([\n#include <sys/devpoll.h>\n        ],[[\nstruct pollfd t_devpoll;\nint fd = open(\"/dev/poll\", O_RDWR);\n        ]])],\n        [$1], [$2]\n    )\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_POLLER_POLLSET([action-if-found], [action-if-not-found])        #\ndnl # Checks pollset polling system                                                #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_POLLER_POLLSET], [{\n    AC_LINK_IFELSE([\n        AC_LANG_PROGRAM([\n#include <sys/poll.h>\n#include <sys/pollset.h>\n        ],[[\npollset_t ps = pollset_create(-1);\n        ]])],\n        [$1], [$2]\n    )\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_POLLER_POLL([action-if-found], [action-if-not-found])           #\ndnl # Checks poll polling system                                                   #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_POLLER_POLL], [{\n    AC_LINK_IFELSE([\n        AC_LANG_PROGRAM([\n#include <poll.h>\n        ],[[\nstruct pollfd t_poll;\npoll(&t_poll, 1, 1);\n        ]])],\n        [$1], [$2]\n    )\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_POLLER_SELECT([action-if-found], [action-if-not-found])         #\ndnl # Checks select polling system                                                 #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_POLLER_SELECT], [{\n    AC_LINK_IFELSE([\n        AC_LANG_PROGRAM([\n#ifdef ZMQ_HAVE_WINDOWS\n#include \"winsock2.h\"\n#elif defined ZMQ_HAVE_OPENVMS\n#include <sys/types.h>\n#include <sys/time.h>\n#else\n#include <sys/select.h>\n#endif\n        ],[[\nfd_set t_rfds;\nstruct timeval tv;\nFD_ZERO(&t_rfds);\nFD_SET(0, &t_rfds);\ntv.tv_sec = 5;\ntv.tv_usec = 0;\nselect(1, &t_rfds, 0, 0, &tv);\n        ]])],\n        [$1],[$2]\n    )\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_PSELECT([action-if-found], [action-if-not-found])               #\ndnl # Checks pselect polling system                                                #\ndnl ################################################################################\nAC_DEFUN([LIBZMQ_CHECK_PSELECT], [{\n    AC_LINK_IFELSE([\n        AC_LANG_PROGRAM([\n#include <sys/select.h>\n#include <signal.h>\n        ],[[\nfd_set t_rfds;\nstruct timespec ts;\nFD_ZERO(&t_rfds);\nFD_SET(0, &t_rfds);\nts.tv_sec = 5;\nts.tv_nsec = 0;\nsigset_t sigmask, sigmask_without_sigterm;\nsigemptyset(&sigmask);\nsigprocmask(SIG_BLOCK, &sigmask, &sigmask_without_sigterm);\n\npselect(1, &t_rfds, 0, 0, &ts, &sigmask);\n        ]])],\n        [$1],[$2]\n    )\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_POLLER([action-if-found], [action-if-not-found])                #\ndnl # Choose polling system                                                        #\ndnl ################################################################################\n\nAC_DEFUN([LIBZMQ_CHECK_POLLER], [{\n    # Allow user to override poller autodetection\n    AC_ARG_WITH([poller],\n        [AS_HELP_STRING([--with-poller],\n        [choose I/O thread polling system manually. Valid values are 'kqueue', 'epoll', 'devpoll', 'pollset', 'poll', 'select', 'wepoll', or 'auto'. [default=auto]])])\n\n    # Allow user to override poller autodetection\n    AC_ARG_WITH([api_poller],\n        [AS_HELP_STRING([--with-api-poller],\n        [choose zmq_poll(er)_* API polling system manually. Valid values are 'poll', 'select', or 'auto'. [default=auto]])])\n\n    if test \"x$with_poller\" = \"x\"; then\n        pollers=auto\n    else\n        pollers=$with_poller\n    fi\n    if test \"$pollers\" = \"auto\"; then\n        # We search for pollers in this order\n        pollers=\"kqueue epoll devpoll pollset poll select\"\n    fi\n\n    # try to find suitable polling system. the order of testing is:\n    AC_MSG_NOTICE([Choosing I/O thread polling system from '$pollers'...])\n    poller_found=0\n    for poller in $pollers; do\n        case \"$poller\" in\n            kqueue)\n                LIBZMQ_CHECK_POLLER_KQUEUE([\n                    AC_MSG_NOTICE([Using 'kqueue' I/O thread polling system])\n                    AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_KQUEUE, 1, [Use 'kqueue' I/O thread polling system])\n                    poller_found=1\n                ])\n            ;;\n            epoll)\n                case \"$host_os\" in\n                    solaris*|sunos*)\n                        # Recent illumos and Solaris systems did add epoll()\n                        # syntax, but it does not fully satisfy expectations\n                        # that ZMQ has from Linux systems. Unless you undertake\n                        # to fix the integration, do not disable this exception\n                        # and use select() or poll() on Solarish OSes for now.\n                        AC_MSG_NOTICE([NOT using 'epoll' I/O thread polling system on '$host_os']) ;;\n                    *)\n                        LIBZMQ_CHECK_POLLER_EPOLL_CLOEXEC([\n                            AC_MSG_NOTICE([Using 'epoll' I/O thread polling system with CLOEXEC])\n                            AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_EPOLL, 1, [Use 'epoll' I/O thread polling system])\n                            AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC, 1, [Use 'epoll' I/O thread polling system with CLOEXEC])\n                            poller_found=1\n                            ],[\n                            LIBZMQ_CHECK_POLLER_EPOLL([\n                                AC_MSG_NOTICE([Using 'epoll' I/O thread polling system with CLOEXEC])\n                                AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_EPOLL, 1, [Use 'epoll' I/O thread polling system])\n                                poller_found=1\n                            ])\n                        ])\n                        ;;\n                esac\n            ;;\n            devpoll)\n                LIBZMQ_CHECK_POLLER_DEVPOLL([\n                    AC_MSG_NOTICE([Using 'devpoll' I/O thread polling system])\n                    AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_DEVPOLL, 1, [Use 'devpoll' I/O thread polling system])\n                    poller_found=1\n                ])\n            ;;\n            pollset)\n                LIBZMQ_CHECK_POLLER_POLLSET([\n                    AC_MSG_NOTICE([Using 'pollset' I/O thread polling system])\n                    AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_POLLSET, 1, [Use 'pollset' I/O thread polling system])\n                    poller_found=1\n                ])\n            ;;\n            poll)\n                LIBZMQ_CHECK_POLLER_POLL([\n                    AC_MSG_NOTICE([Using 'poll' I/O thread polling system])\n                    AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_POLL, 1, [Use 'poll' I/O thread polling system])\n                    poller_found=1\n                ])\n            ;;\n            select)\n                LIBZMQ_CHECK_POLLER_SELECT([\n                    AC_MSG_NOTICE([Using 'select' I/O thread polling system])\n                    AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_SELECT, 1, [Use 'select' I/O thread polling system])\n                    poller_found=1\n                ])\n            ;;\n            wepoll)\n                # wepoll can only be manually selected\n                AC_MSG_NOTICE([Using 'wepoll' I/O thread polling system])\n                AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_EPOLL, 1, [Use 'epoll' I/O thread polling system])\n                poller_found=1\n            ;;\n        esac\n        test $poller_found -eq 1 && break\n    done\n    if test $poller_found -eq 0; then\n        AC_MSG_ERROR([None of '$pollers' are valid pollers on this platform])\n    fi\n    if test \"x$with_api_poller\" = \"x\"; then\n        with_api_poller=auto\n    fi\n\tif test \"x$with_api_poller\" = \"xauto\"; then\n\t\tif test $poller = \"select\"; then\n\t\t\tapi_poller=select\n\t\telif test $poller = \"wepoll\"; then\n\t\t\tapi_poller=select\n\t\telse\t\t\n\t\t\tapi_poller=poll\n\t\tfi\n\telse\n\t\tapi_poller=$with_api_poller\n\tfi\n\tif test \"$api_poller\" = \"select\"; then\n\t\tAC_MSG_NOTICE([Using 'select' zmq_poll(er)_* API polling system])\n\t\tAC_DEFINE(ZMQ_POLL_BASED_ON_SELECT, 1, [Use 'select' zmq_poll(er)_* API polling system])\n\telif test \"$api_poller\" = \"poll\"; then\n\t\tAC_MSG_NOTICE([Using 'poll' zmq_poll(er)_* API polling system])\n\t\tAC_DEFINE(ZMQ_POLL_BASED_ON_POLL, 1, [Use 'poll' zmq_poll(er)_* API polling system])\n\telse\n        AC_MSG_ERROR([Invalid API poller '$api_poller' specified])\n\tfi\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_PPOLL([action-if-found], [action-if-not-found])                 #\ndnl # Check whether zmq_ppoll can be activated, and do so if it can                #\ndnl ################################################################################\n\nAC_DEFUN([LIBZMQ_CHECK_PPOLL], [{\n    AC_REQUIRE([AC_CANONICAL_HOST])\n\n    case \"${host_os}\" in\n        *mingw*|*cygwin*|*msys*)\n            # Disable ppoll by default on Windows\n            AC_MSG_NOTICE([NOT building active zmq_ppoll on '$host_os']) ;;\n        *)\n            LIBZMQ_CHECK_PSELECT([\n                AC_MSG_NOTICE([Building with zmq_ppoll])\n                AC_DEFINE(ZMQ_HAVE_PPOLL, 1, [Build with zmq_ppoll])\n            ])\n        ;;\n    esac\n}])\n\ndnl ##############################################################################\ndnl # LIBZMQ_CHECK_CACHELINE                                                     #\ndnl # Check cacheline size for alignment purposes                                #\ndnl ##############################################################################\nAC_DEFUN([LIBZMQ_CHECK_CACHELINE], [{\n\n    zmq_cacheline_size=64\n    AC_CHECK_TOOL(libzmq_getconf, getconf)\n    if ! test \"x$libzmq_getconf\" = \"x\"; then\n        zmq_cacheline_size=$($libzmq_getconf LEVEL1_DCACHE_LINESIZE 2>/dev/null || echo 64)\n        if test \"x$zmq_cacheline_size\" = \"x0\" -o  \"x$zmq_cacheline_size\" = \"x-1\" -o \"x$zmq_cacheline_size\" = \"xundefined\"; then\n            # getconf on some architectures does not know the size, try to fallback to\n            # the value the kernel knows on Linux\n            zmq_cacheline_size=$(cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size 2>/dev/null || echo 64)\n        fi\n    fi\n    if test \"x$zmq_cacheline_size\" = \"xundefined\"; then\n        # On some platforms e.g. Fedora33 s390x the cacheline size reported\n        # by getconf as 'undefined'.\n        zmq_cacheline_size=64\n    fi\n\tAC_MSG_NOTICE([Using \"$zmq_cacheline_size\" bytes alignment for lock-free data structures])\n\tAC_DEFINE_UNQUOTED(ZMQ_CACHELINE_SIZE, $zmq_cacheline_size, [Using \"$zmq_cacheline_size\" bytes alignment for lock-free data structures])\n}])\n\ndnl ################################################################################\ndnl # LIBZMQ_CHECK_CV_IMPL([action-if-found], [action-if-not-found])               #\ndnl # Choose condition variable implementation                                     #\ndnl ################################################################################\n\nAC_DEFUN([LIBZMQ_CHECK_CV_IMPL], [{\n    # Allow user to override condition variable autodetection\n    AC_ARG_WITH([cv-impl],\n        [AS_HELP_STRING([--with-cv-impl],\n        [choose condition variable implementation manually. Valid values are 'stl11', 'pthread', 'none', or 'auto'. [default=auto]])])\n\n    if test \"x$with_cv_impl\" = \"x\"; then\n        cv_impl=auto\n    else\n        cv_impl=$with_cv_impl\n    fi\n    case $host_os in\n      vxworks*)\n        cv_impl=\"vxworks\"\n        AC_DEFINE(ZMQ_USE_CV_IMPL_VXWORKS, 1, [Use vxworks condition variable implementation.])\n      ;;\n    esac\n    if test \"$cv_impl\" = \"auto\" || test \"$cv_impl\" = \"stl11\"; then\n        AC_LANG_PUSH([C++])\n        AC_CHECK_HEADERS(condition_variable, [stl11=\"yes\"\n            AC_DEFINE(ZMQ_USE_CV_IMPL_STL11, 1, [Use stl11 condition variable implementation.])],\n            [stl11=\"no\"])\n        AC_LANG_POP([C++])\n        if test \"$cv_impl\" = \"stl11\" && test \"x$stl11\" = \"xno\"; then\n            AC_MSG_ERROR([--with-cv-impl set to stl11 but cannot find condition_variable])\n        fi\n    fi\n    if test \"$cv_impl\" = \"pthread\" || test \"x$stl11\" = \"xno\"; then\n        AC_DEFINE(ZMQ_USE_CV_IMPL_PTHREADS, 1, [Use pthread condition variable implementation.])\n    fi\n    if test \"$cv_impl\" = \"none\"; then\n        AC_DEFINE(ZMQ_USE_CV_IMPL_NONE, 1, [Use no condition variable implementation.])\n    fi\n       AC_MSG_NOTICE([Using \"$cv_impl\" condition variable implementation.])\n}])\n"
  },
  {
    "path": "appveyor.yml",
    "content": "version: build-{build}\n\nshallow_clone: true\n\nos: Visual Studio 2013\n\nenvironment:\n  CMAKE_GENERATOR: \"Visual Studio 12 2013\"\n  MSVCVERSION: \"v120\"\n  MSVCYEAR: \"vs2013\"\n  ENABLE_DRAFTS: ON\n  matrix:\n    - platform: x64\n      configuration: Release\n      WITH_LIBSODIUM: ON\n      ENABLE_CURVE: ON\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019\n      CMAKE_GENERATOR: \"Visual Studio 16 2019\"\n      MSVCVERSION: \"v142\"\n      MSVCYEAR: \"vs2019\"\n      ARTIFACT_NAME: v142-x64\n    - platform: Win32\n      configuration: Release\n      WITH_LIBSODIUM: OFF # unavailable build files for VS2008\n      ENABLE_CURVE: OFF\n      CMAKE_GENERATOR: \"Visual Studio 9 2008\"\n      MSVCVERSION: \"v90\"\n      MSVCYEAR: \"vs2008\"\n      ARTIFACT_NAME: v90\n    - platform: Win32\n      configuration: Release\n      WITH_LIBSODIUM: OFF\n      ENABLE_CURVE: OFF\n      CMAKE_GENERATOR: \"Visual Studio 10 2010\"\n      MSVCVERSION: \"v100\"\n      MSVCYEAR: \"vs2010\"\n      ARTIFACT_NAME: v100\n    - platform: Win32\n      configuration: Release\n      WITH_LIBSODIUM: ON\n      ENABLE_CURVE: ON\n      ARTIFACT_NAME: v120\n    - platform: x64\n      configuration: Release\n      WITH_LIBSODIUM: ON\n      ENABLE_CURVE: ON\n      ARTIFACT_NAME: v120-x64\n    - platform: Win32\n      configuration: Release\n      POLLER: epoll\n      API_POLLER: poll\n      WITH_LIBSODIUM: ON\n      ENABLE_CURVE: ON\n      TEST_OPTIONS: '-E \"(test_many_sockets)\"'\n      ARTIFACT_NAME: v120-epoll\n    - platform: Win32\n      configuration: Debug\n      WITH_LIBSODIUM: ON\n      ENABLE_CURVE: ON\n      TEST_OPTIONS: '-E \"(test_many_sockets)\"'\n      ARTIFACT_NAME: v120-gd\n    - platform: x64\n      configuration: Debug\n      WITH_LIBSODIUM: ON\n      ENABLE_CURVE: ON\n      TEST_OPTIONS: '-E \"(test_many_sockets)\"'\n      ARTIFACT_NAME: v120-gd-x64\n    - platform: Win32\n      configuration: Release\n      WITH_LIBSODIUM: OFF\n      ENABLE_CURVE: OFF\n      ENABLE_DRAFTS: OFF\n      ARTIFACT_NAME: v120-nocurve\n    - platform: Win32\n      configuration: Release\n      WITH_LIBSODIUM: ON\n      ENABLE_CURVE: ON\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015\n      CMAKE_GENERATOR: \"Visual Studio 14 2015\"\n      MSVCVERSION: \"v140\"\n      MSVCYEAR: \"vs2015\"\n      ARTIFACT_NAME: v140\n    - platform: x64\n      configuration: Release\n      WITH_LIBSODIUM: ON\n      ENABLE_CURVE: ON\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015\n      CMAKE_GENERATOR: \"Visual Studio 14 2015\"\n      MSVCVERSION: \"v140\"\n      MSVCYEAR: \"vs2015\"\n      ARTIFACT_NAME: v140-x64\n    - platform: Win32\n      configuration: Release\n      WITH_LIBSODIUM: ON\n      ENABLE_CURVE: ON\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n      CMAKE_GENERATOR: \"Visual Studio 15 2017\"\n      MSVCVERSION: \"v141\"\n      MSVCYEAR: \"vs2017\"\n      TEST_OPTIONS: '-E \"(test_many_sockets)\"'\n      ARTIFACT_NAME: v141\n    - platform: x64\n      configuration: Release\n      WITH_LIBSODIUM: ON\n      ENABLE_CURVE: ON\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n      CMAKE_GENERATOR: \"Visual Studio 15 2017\"\n      MSVCVERSION: \"v141\"\n      MSVCYEAR: \"vs2017\"\n      TEST_OPTIONS: '-E \"(test_many_sockets)\"'\n      ARTIFACT_NAME: v141-x64\n    - platform: cygwin64\n      WITH_LIBSODIUM: OFF\n      ENABLE_CURVE: OFF\n      CMAKE_GENERATOR: \"Unix Makefiles\"\n      ARTIFACT_NAME: cygwin64\n    - platform: mingw64\n      WITH_LIBSODIUM: OFF\n      ENABLE_CURVE: OFF\n      CMAKE_GENERATOR: \"MSYS Makefiles\"\n      ARTIFACT_NAME: mingw64\n    - platform: Win32-uwp\n      configuration: Debug\n      WITH_LIBSODIUM: OFF\n      ENABLE_CURVE: OFF\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n      CMAKE_GENERATOR: \"Visual Studio 15 2017\"\n      MSVCVERSION: \"v141\"\n      MSVCYEAR: \"vs2017\"\n      ARTIFACT_NAME: v141-gd-uwp\n      CMAKE_SYSTEM_NAME: WindowsStore\n      CMAKE_SYSTEM_VERSION: 10.0.18362\n      EXTRA_FLAGS: -DCMAKE_SYSTEM_NAME=%CMAKE_SYSTEM_NAME% -DCMAKE_SYSTEM_VERSION=%CMAKE_SYSTEM_VERSION% -DBUILD_TESTS=OFF\n    - platform: Win32-uwp\n      configuration: Release\n      WITH_LIBSODIUM: OFF\n      ENABLE_CURVE: OFF\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n      CMAKE_GENERATOR: \"Visual Studio 15 2017\"\n      MSVCVERSION: \"v141\"\n      MSVCYEAR: \"vs2017\"\n      ARTIFACT_NAME: v141-uwp\n      CMAKE_SYSTEM_NAME: WindowsStore\n      CMAKE_SYSTEM_VERSION: 10.0.18362\n      EXTRA_FLAGS: -DCMAKE_SYSTEM_NAME=%CMAKE_SYSTEM_NAME% -DCMAKE_SYSTEM_VERSION=%CMAKE_SYSTEM_VERSION% -DBUILD_TESTS=OFF\n\nmatrix:\n  fast_finish: false\n  allow_failures:\n    - platform: cygwin64 # TODO allow failures until tests are fixed\n    - platform: mingw64  # TODO allow failures until tests are fixed\n\ninit:\n  - cmd: if \"%NO_PR%\"==\"TRUE\" (\n            if \"%APPVEYOR_PULL_REQUEST_NUMBER%\" NEQ \"\" (\n                echo \"Build is disabled for PRs, aborting\" &&\n                appveyor exit\n            )\n         )\n  #- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))\n  - cmake --version\n  - msbuild /version\n  - cmd: reg add \"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp\" /v UserAuthentication /t REG_DWORD /d 0 /f\n\ncache:\n    - C:\\projects\\libsodium\n    - C:\\cygwin64\\var\\cache\\setup\n\ninstall:\n  - cmd: if \"%Platform%\"==\"cygwin64\" C:\\cygwin64\\setup-x86_64.exe --quiet-mode --no-shortcuts --upgrade-also --packages cmake,cygwin-devel,gcc-g++,libncurses-devel,make,pkg-config\n  - cmd: if \"%Platform%\"==\"cygwin64\" set PATH=C:\\cygwin64\\bin;%PATH%\n  - cmd: if \"%Platform%\"==\"mingw64\" C:\\msys64\\usr\\bin\\bash -lc \"pacman -Qg\"\n  - cmd: if \"%Platform%\"==\"mingw64\" set PATH=C:\\msys64\\usr\\bin;%PATH%\n  - cmd: if \"%Platform%\"==\"x64\" (if not \"%MSVCVERSION%\"==\"v142\" set \"CMAKE_GENERATOR=%CMAKE_GENERATOR% Win64\")\n  - cmd: echo \"Generator='%CMAKE_GENERATOR%'\"\n  - cmd: echo \"Platform='%Platform%'\"\n  - cmd: if \"%WITH_LIBSODIUM%\"==\"ON\" set LIBSODIUMDIR=C:\\projects\\libsodium\n  - cmd: if \"%WITH_LIBSODIUM%\"==\"ON\" (\n                git config --global user.email \"test@appveyor.com\" &&\n                git config --global user.name \"appveyor\"\n         )\n  - cmd: if \"%WITH_LIBSODIUM%\"==\"ON\" (\n            if not exist \"%LIBSODIUMDIR%\" (\n                git clone --branch stable --depth 1 --quiet \"https://github.com/jedisct1/libsodium.git\" %LIBSODIUMDIR%\n            ) else (\n                git -C \"%LIBSODIUMDIR%\" fetch --all && git -C \"%LIBSODIUMDIR%\" reset --hard origin/stable\n            )\n         )\n  - cmd: if \"%WITH_LIBSODIUM%\"==\"ON\" msbuild /v:minimal /maxcpucount:%NUMBER_OF_PROCESSORS% /p:Configuration=%Configuration%DLL %LIBSODIUMDIR%\\builds\\msvc\\%MSVCYEAR%\\libsodium\\libsodium.vcxproj\n  - cmd: if \"%WITH_LIBSODIUM%\"==\"ON\" set SODIUM_LIBRARY_DIR=\"%LIBSODIUMDIR%\\bin\\%Platform%\\%Configuration%\\%MSVCVERSION%\\dynamic\"\n  - cmd: if \"%WITH_LIBSODIUM%\"==\"ON\" set SODIUM_INCLUDE_DIR=\"%LIBSODIUMDIR%\\src\\libsodium\\include\"\n  - ps: if (${env:WITH_LIBSODIUM} -eq \"ON\") { Copy-Item \"C:\\projects\\libsodium\\bin\\${env:Platform}\\${env:Configuration}\\${env:MSVCVERSION}\\dynamic\\libsodium.lib\" -Destination \"C:\\projects\\libsodium\\bin\\${env:Platform}\\${env:Configuration}\\${env:MSVCVERSION}\\dynamic\\sodium.lib\" }\n\nclone_folder: C:\\projects\\libzmq\n\nbefore_build:\n  - cmd: set LIBZMQ_SRCDIR=%cd%\n  - cmd: set LIBZMQ_BUILDDIR=C:\\projects\\build_libzmq\n  # TODO this does not work with sonarcloud.io, as it misses the sonar-cxx plugin\n  # - cmd: curl -L https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.1.0.1141-windows.zip -o sonar-scanner-cli-3.1.0.1141-windows.zip\n  # - cmd: unzip sonar-scanner-cli-3.1.0.1141-windows.zip\n  # - cmd: set BUILDLOG=\"%LIBZMQ_SRCDIR%\\build.log\"\n  - cmd: md \"%LIBZMQ_BUILDDIR%\"\n  - cd \"%LIBZMQ_BUILDDIR%\"\n  - cmd: if \"%PLATFORM%\" == \"cygwin64\" set APPVEYOR_BUILD_FOLDER=/cygdrive/C/projects/libzmq\n  - cmd: if \"%ENABLE_ANALYSIS%\"==\"ON\" ( set LIBZMQ_WERROR=\"OFF\" ) else ( set LIBZMQ_WERROR=\"ON\" )\n  - cmd: cmake -D CMAKE_INCLUDE_PATH=\"%SODIUM_INCLUDE_DIR%\" -D CMAKE_LIBRARY_PATH=\"%SODIUM_LIBRARY_DIR%\" -D WITH_LIBSODIUM=\"%WITH_LIBSODIUM%\" -D ENABLE_DRAFTS=\"%ENABLE_DRAFTS%\" -D ENABLE_ANALYSIS=\"%ENABLE_ANALYSIS%\" -D ENABLE_CURVE=\"%ENABLE_CURVE%\" -D API_POLLER=\"%API_POLLER%\" -D POLLER=\"%POLLER%\" %EXTRA_FLAGS% -D WITH_LIBSODIUM=\"%WITH_LIBSODIUM%\" -D LIBZMQ_WERROR=\"%LIBZMQ_WERROR%\" -G \"%CMAKE_GENERATOR%\" \"%APPVEYOR_BUILD_FOLDER%\"\n  - cmd: cd \"%LIBZMQ_SRCDIR%\"\n  - ps: $env:ZMQ_VERSION_MAJOR = (Select-String -Path .\\include\\zmq.h -Pattern \".*#define ZMQ_VERSION_MAJOR ([0-9]+).*\").Matches.Groups[1].Value\n  - ps: $env:ZMQ_VERSION_MINOR = (Select-String -Path .\\include\\zmq.h -Pattern \".*#define ZMQ_VERSION_MINOR ([0-9]+).*\").Matches.Groups[1].Value\n  - ps: $env:ZMQ_VERSION_PATCH = (Select-String -Path .\\include\\zmq.h -Pattern \".*#define ZMQ_VERSION_PATCH ([0-9]+).*\").Matches.Groups[1].Value\n  - ps: $env:ZMQ_VERSION = \"${env:ZMQ_VERSION_MAJOR}.${env:ZMQ_VERSION_MINOR}.${env:ZMQ_VERSION_PATCH}\"\n  - cmd: echo \"ZMQ_VERSION is %ZMQ_VERSION%\"\n\nbuild_script:\n  - cmd: set verbosity=Minimal\n  - cmd: if \"%MSVCYEAR%\"==\"vs2008\" set verbosity=Normal\n  - cmd: if \"%MSVCYEAR%\"==\"vs2008\" set path=C:\\Windows\\Microsoft.NET\\Framework\\v3.5;%path% \n  - cmd: cd \"%LIBZMQ_BUILDDIR%\"\n  - cmd: if \"%PLATFORM:~0,5%\" == \"Win32\" (\n            if \"%MSVCYEAR%\"==\"vs2008\" (\n                cmake --build %LIBZMQ_BUILDDIR% --config %configuration% --target install\n            ) else (\n                cmake --build %LIBZMQ_BUILDDIR% --config %configuration% --target install -- -verbosity:Minimal -maxcpucount -logger:\"C:\\Program Files\\AppVeyor\\BuildAgent\\Appveyor.MSBuildLogger.dll\"\n            )\n         )\n  - cmd: if \"%PLATFORM%\" == \"x64\" (\n            cmake --build %LIBZMQ_BUILDDIR% --config %configuration% --target install -- -verbosity:Minimal -maxcpucount -logger:\"C:\\Program Files\\AppVeyor\\BuildAgent\\Appveyor.MSBuildLogger.dll\"\n         )\n  - cmd: if \"%PLATFORM%\" == \"cygwin64\" (\n            cmake --build . -- -j5\n         )\n  - cmd: if \"%PLATFORM%\" == \"mingw64\" (\n            cmake --build . -- -j5\n         )\n\n# TODO this does not work with sonarcloud.io, as it misses the sonar-cxx plugin\n# build_script:\n  # - cmd: msbuild %LIBZMQ_BUILDDIR%\\ZeroMQ.sln /verbosity:detailed >%BUILDLOG%\n\nafter_build:\n  # TODO this does not work with sonarcloud.io, as it misses the sonar-cxx plugin\n  # - cmd: cd \"%LIBZMQ_SRCDIR%\"\n  # - cmd: dir\n  # - cmd: sonar-scanner-3.1.0.1141-windows\\bin\\sonar-scanner \n            # -Dsonar.scm.provider=git \n            # -Dsonar.projectKey=libzmq-msvc \n            # -Dsonar.organization=sigiesec-github \n            # -Dsonar.sources=include,src,tests,unittests \n            # -Dsonar.host.url=https://sonarcloud.io \n            # -Dsonar.login=%SONARQUBE_TOKEN% \n            # -Dsonar.cxx.compiler.parser=\"Visual C++\" \n            # -Dsonar.cxx.compiler.reportPath=build.log \n            # -Dsonar.cxx.compiler.charset=UTF-8 \n            # -Dsonar.cxx.compiler.regex=^(?<filename>.*)\\\\((?<line>[0-9]+)\\\\):\\\\x20warning\\\\x20(?<id>C\\\\d\\\\d\\\\d\\\\d):(?<message>.*)$\n# TODO this should be done differently, using the INSTALL cmake target, the current handling depends on the details of the CMakeLists.txt\n  - cmd: cd %LIBZMQ_BUILDDIR%\\bin\\%Configuration%\"\n  - cmd: if \"%WITH_LIBSODIUM%\"==\"ON\" copy \"%SODIUM_LIBRARY_DIR%\\libsodium.dll\" .\n  - cmd: copy \"%LIBZMQ_SRCDIR%\\include\\zmq.h\" .\n  - cmd: copy ..\\..\\lib\\%Configuration%\\libzmq*.lib . & exit 0\n  - cmd: 7z a -y -bd -mx=9 libzmq.zip *.exe *.dll *.pdb *.h *.lib\n  - ps: Push-AppveyorArtifact \"libzmq.zip\" -Filename \"libzmq-${env:ARTIFACT_NAME}-${env:ZMQ_VERSION_MAJOR}_${env:ZMQ_VERSION_MINOR}_${env:ZMQ_VERSION_PATCH}.zip\"\n\ntest_script:\n  - cmd: cd \"%LIBZMQ_BUILDDIR%\"\n# TODO run tests in parallel only on selected platforms, since they fail on others, see https://github.com/zeromq/libzmq/issues/3123\n  - cmd: if \"%CMAKE_GENERATOR%\"==\"Visual Studio 12 2013\" set PARALLELIZE=ON\n  - cmd: if \"%CMAKE_GENERATOR%\"==\"Visual Studio 14 2015\" set PARALLELIZE=ON\n  - cmd: if \"%CMAKE_GENERATOR%\"==\"Visual Studio 12 2013 Win64\" set PARALLELIZE=ON\n  - cmd: if \"%CMAKE_GENERATOR%\"==\"Visual Studio 14 2015 Win64\" set PARALLELIZE=ON\n  - cmd: if not defined TEST_OPTIONS set \"TEST_OPTIONS= \"\n  - cmd: if \"%PARALLELIZE%\"==\"ON\" (\n            echo \"Running tests in parallel\" &&\n            set TEST_OPTIONS=%TEST_OPTIONS% -j5\n         )\n  - cmd: if \"%APPVEYOR_REPO_TAG%\"==\"false\" (ctest -C \"%Configuration%\" -V %TEST_OPTIONS%)\n\n\n# the analysis build is repeated; apparently appveyor only uses the first section that matches some branch\nfor:\n-\n    branches:\n        only:\n            - master\n    environment:\n        matrix:\n            - platform: Win32\n              configuration: Release\n              API_POLLER: poll\n              WITH_LIBSODIUM: ON\n              ENABLE_CURVE: ON\n              NO_PR: TRUE\n            - platform: x64\n              configuration: Release\n              WITH_LIBSODIUM: ON\n              ENABLE_CURVE: ON\n              NO_PR: TRUE\n            - platform: Win32\n              configuration: Release\n              WITH_LIBSODIUM: ON\n              ENABLE_CURVE: ON\n              NO_PR: TRUE\n            - platform: Win32\n              configuration: Release\n              WITH_LIBSODIUM: ON\n              ENABLE_CURVE: ON\n              ENABLE_ANALYSIS: ON\n              APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n              CMAKE_GENERATOR: \"Visual Studio 15 2017\"\n              MSVCVERSION: \"v141\"\n              MSVCYEAR: \"vs2017\"\n              NO_PR: TRUE\n-\n    branches:\n        only:\n            - /.*analyze$/\n    environment:\n        matrix:\n            - platform: Win32\n              configuration: Release\n              WITH_LIBSODIUM: ON\n              ENABLE_CURVE: ON\n              ENABLE_ANALYSIS: ON\n              APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n              CMAKE_GENERATOR: \"Visual Studio 15 2017\"\n              MSVCVERSION: \"v141\"\n              MSVCYEAR: \"vs2017\"\n              NO_PR: TRUE\n"
  },
  {
    "path": "autogen.sh",
    "content": "#!/bin/sh\n# SPDX-License-Identifier: MPL-2.0\n\n# Script to generate all required files from fresh git checkout.\n\n# Debian and Ubuntu do not ship libtool anymore, but OSX does not ship libtoolize.\ncommand -v libtoolize >/dev/null 2>&1\nif  [ $? -ne 0 ]; then\n    command -v libtool >/dev/null 2>&1\n    if  [ $? -ne 0 ]; then\n        echo \"autogen.sh: error: could not find libtool.  libtool is required to run autogen.sh.\" 1>&2\n        exit 1\n    fi\nfi\n\ncommand -v autoreconf >/dev/null 2>&1\nif [ $? -ne 0 ]; then\n    echo \"autogen.sh: error: could not find autoreconf.  autoconf and automake are required to run autogen.sh.\" 1>&2\n    exit 1\nfi\n\nmkdir -p ./config\nif [ $? -ne 0 ]; then\n    echo \"autogen.sh: error: could not create directory: ./config.\" 1>&2\n    exit 1\nfi\n\nautoreconf --install --force --verbose -I config\nres=$?\nif [ \"$res\" -ne 0 ]; then\n    echo \"autogen.sh: error: autoreconf exited with status $res\" 1>&2\n    exit 1\nfi\n"
  },
  {
    "path": "build_qnx/Makefile",
    "content": "LIST=OS\nifndef QRECURSE\nQRECURSE=recurse.mk\nifdef QCONFIG\nQRDIR=$(dir $(QCONFIG))\nendif\nendif\ninclude $(QRDIR)$(QRECURSE)\n"
  },
  {
    "path": "build_qnx/common.mk",
    "content": "ifndef QCONFIG\nQCONFIG=qconfig.mk\nendif\ninclude $(QCONFIG)\n\nNAME=libzmq\n\n#$(INSTALL_ROOT_$(OS)) is pointing to $QNX_TARGET\n#by default, unless it was manually re-routed to\n#a staging area by setting both INSTALL_ROOT_nto\n#and USE_INSTALL_ROOT\nLIBZMQ_INSTALL_ROOT ?= $(INSTALL_ROOT_$(OS))\n\nLIBZMQ_VERSION = .4.3.4\n\n#choose Release or Debug\nCMAKE_BUILD_TYPE ?= Release\n\n#override 'all' target to bypass the default QNX build system\nALL_DEPENDENCIES = libzmq_all\n.PHONY: libzmq_all install check clean\n\nCFLAGS += $(FLAGS)\nLDFLAGS += -Wl,--build-id=md5\n\ninclude $(MKFILES_ROOT)/qtargets.mk\n\nLIBZMQ_DIR = $(PROJECT_ROOT)/../\n\nCMAKE_ARGS = -DCMAKE_TOOLCHAIN_FILE=$(PROJECT_ROOT)/qnx.nto.toolchain.cmake \\\n             -DCMAKE_INSTALL_PREFIX=$(LIBZMQ_INSTALL_ROOT)/${CPUVARDIR}/usr \\\n             -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) \\\n             -DEXTRA_CMAKE_C_FLAGS=\"$(CFLAGS)\" \\\n             -DEXTRA_CMAKE_CXX_FLAGS=\"$(CFLAGS)\" \\\n             -DEXTRA_CMAKE_ASM_FLAGS=\"$(FLAGS)\" \\\n             -DEXTRA_CMAKE_LINKER_FLAGS=\"$(LDFLAGS)\" \\\n             -DCMAKE_INSTALL_INCLUDEDIR=$(LIBZMQ_INSTALL_ROOT)/usr/include \\\n             -DCMAKE_INSTALL_LIBDIR=$(LIBZMQ_INSTALL_ROOT)/$(CPUVARDIR)/usr/lib \\\n             -DCMAKE_INSTALL_BINDIR=$(LIBZMQ_INSTALL_ROOT)/$(CPUVARDIR)/usr/bin \\\n             -DCPUVARDIR=$(CPUVARDIR)\n\nMAKE_ARGS ?= -j $(firstword $(JLEVEL) 1)\n\nifndef NO_TARGET_OVERRIDE\nlibzmq_all:\n\t@mkdir -p build\n\t@cd build && cmake $(CMAKE_ARGS) $(LIBZMQ_DIR)\n\t@cd build && make VERBOSE=1 all $(MAKE_ARGS)\n\ninstall check: libzmq_all\n\t@cd build && make VERBOSE=1 install\n\nclean iclean spotless:\n\trm -rf build\n\nuninstall:\nendif\n"
  },
  {
    "path": "build_qnx/nto/Makefile",
    "content": "LIST=CPU\nifndef QRECURSE\nQRECURSE=recurse.mk\nifdef QCONFIG\nQRDIR=$(dir $(QCONFIG))\nendif\nendif\ninclude $(QRDIR)$(QRECURSE)\n"
  },
  {
    "path": "build_qnx/nto/aarch64/Makefile",
    "content": "LIST=VARIANT\nifndef QRECURSE\nQRECURSE=recurse.mk\nifdef QCONFIG\nQRDIR=$(dir $(QCONFIG))\nendif\nendif\ninclude $(QRDIR)$(QRECURSE)\n"
  },
  {
    "path": "build_qnx/nto/aarch64/le/Makefile",
    "content": "include ../../../common.mk\n\nCMAKE_ARGS += -DCMAKE_SYSTEM_PROCESSOR=aarch64 \nFLAGS      += $(VFLAG_le) $(CCVFLAG_le)\nLDFLAGS    += $(VFLAG_le) $(LDVFLAG_le)\n"
  },
  {
    "path": "build_qnx/nto/x86_64/Makefile",
    "content": "LIST=VARIANT\nifndef QRECURSE\nQRECURSE=recurse.mk\nifdef QCONFIG\nQRDIR=$(dir $(QCONFIG))\nendif\nendif\ninclude $(QRDIR)$(QRECURSE)\n"
  },
  {
    "path": "build_qnx/nto/x86_64/o/Makefile",
    "content": "include ../../../common.mk\n\nCMAKE_ARGS += -DCMAKE_SYSTEM_PROCESSOR=x86_64\nFLAGS      += $(VFLAG_o) $(CCVFLAG_o)\nLDFLAGS    += $(VFLAG_o) $(LDVFLAG_o)\n"
  },
  {
    "path": "build_qnx/qnx.nto.toolchain.cmake",
    "content": "if(\"$ENV{QNX_HOST}\" STREQUAL \"\")\n    message(FATAL_ERROR \"QNX_HOST environment variable not found. Please set the variable to your host's build tools\")\nendif()\nif(\"$ENV{QNX_TARGET}\" STREQUAL \"\")\n    message(FATAL_ERROR \"QNX_TARGET environment variable not found. Please set the variable to the qnx target location\")\nendif()\n\nif(CMAKE_HOST_WIN32)\n    set(HOST_EXECUTABLE_SUFFIX \".exe\")\n    #convert windows paths to cmake paths\n    file(TO_CMAKE_PATH \"$ENV{QNX_HOST}\" QNX_HOST)\n    file(TO_CMAKE_PATH \"$ENV{QNX_TARGET}\" QNX_TARGET)\nelse()\n    set(QNX_HOST \"$ENV{QNX_HOST}\")\n    set(QNX_TARGET \"$ENV{QNX_TARGET}\")\nendif()\n\nmessage(STATUS \"using QNX_HOST ${QNX_HOST}\")\nmessage(STATUS \"using QNX_TARGET ${QNX_TARGET}\")\n\nset(QNX TRUE)\nset(CMAKE_SYSTEM_NAME QNX)\nset(CMAKE_C_COMPILER ${QNX_HOST}/usr/bin/qcc)\nset(CMAKE_CXX_COMPILER ${QNX_HOST}/usr/bin/qcc)\nset(CMAKE_ASM_COMPILER ${QNX_HOST}/usr/bin/qcc)\nset(CMAKE_AR \"${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ar${HOST_EXECUTABLE_SUFFIX}\" CACHE PATH \"archiver\")\nset(CMAKE_RANLIB \"${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ranlib${HOST_EXECUTABLE_SUFFIX}\" CACHE PATH \"ranlib\")\n\nset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Vgcc_nto${CMAKE_SYSTEM_PROCESSOR} ${EXTRA_CMAKE_C_FLAGS}\" CACHE STRING \"c_flags\")\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Vgcc_nto${CMAKE_SYSTEM_PROCESSOR} -std=gnu++11 ${EXTRA_CMAKE_CXX_FLAGS}\" CACHE STRING \"cxx_flags\")\nset(CMAKE_ASM_FLAGS \"${CMAKE_ASM_FLAGS} -Vgcc_nto${CMAKE_SYSTEM_PROCESSOR} ${EXTRA_CMAKE_ASM_FLAGS}\" CACHE STRING \"asm_flags\")\n\nset(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} ${EXTRA_CMAKE_LINKER_FLAGS}\" CACHE STRING \"exe_linker_flags\")\nset(CMAKE_SHARED_LINKER_FLAGS \"${CMAKE_SHARED_LINKER_FLAGS} ${EXTRA_CMAKE_LINKER_FLAGS}\" CACHE STRING \"so_linker_flags\")\n"
  },
  {
    "path": "builds/Makefile.am",
    "content": "#  Specify all build files that have to go into source packages.\n#  msvc directory does its own stuff.\n\nEXTRA_DIST = \\\n \tcygwin/Makefile.cygwin \\\n\tzos/makelibzmq \\\n\tzos/cxxall \\\n\tzos/README.md \\\n\tzos/makeclean \\\n\tzos/platform.hpp \\\n\tzos/zc++ \\\n\tzos/test_fork.cpp \\\n\tzos/maketests \\\n\tzos/runtests \\\n\tcygwin/Makefile.cygwin \\\n\tmingw32/Makefile.mingw32 \\\n\tmingw32/platform.hpp \\\n\tcmake/ci_build.sh \\\n\tcmake/Modules \\\n\tcmake/NSIS.template32.in \\\n\tcmake/NSIS.template64.in \\\n\tcmake/ZeroMQConfig.cmake.in \\\n\tcmake/clang-format-check.sh.in \\\n\tcmake/platform.hpp.in \\\n\tvalgrind/ci_build.sh \\\n\tvalgrind/valgrind.supp \\\n\tvalgrind/vg \\\n\tnuget/readme.nuget \\\n\tnuget/libzmq.autopkg \\\n\tandroid/Dockerfile \\\n\tandroid/README.md \\\n\tandroid/android_build_helper.sh \\\n\tandroid/ci_build.sh \\\n\tandroid/build.sh\n"
  },
  {
    "path": "builds/README",
    "content": "This directory holds build tools, i.e. tools we use to build the current\ncode tree. Packaging tools (which take released tarballs or github code\nrepos) should go into /packaging.\n\nNote: 'deprecated-msvc' contains deprecated prepared Visual Studio Solution \nfiles for various Visual Studio versions. These are no longer maintained, \nand may or may not work. Please use cmake instead to build with Visual\nStudio. Rationale: The solution and project files are hard to maintain,\nsince there are different variants for each Visual Studio version.\nThe tests have never been included there for this reason, so they were\nnever usable for actual development of libzmq. If you encounter that \nsomething that worked before does not work with CMake, please open as \nissue at https://github.com/zeromq/libzmq/issues.\n\n"
  },
  {
    "path": "builds/abi-compliance-checker/ci_build.sh",
    "content": "#!/usr/bin/env bash\n\nset -x\nset -e\n\ncd ../../\n\nmkdir tmp\nBUILD_PREFIX=$PWD/tmp\n\nCONFIG_OPTS=()\nCONFIG_OPTS+=(\"CFLAGS=-I${BUILD_PREFIX}/include -g -Og\")\nCONFIG_OPTS+=(\"CPPFLAGS=-I${BUILD_PREFIX}/include\")\nCONFIG_OPTS+=(\"CXXFLAGS=-I${BUILD_PREFIX}/include -g -Og\")\nCONFIG_OPTS+=(\"LDFLAGS=-L${BUILD_PREFIX}/lib\")\nCONFIG_OPTS+=(\"PKG_CONFIG_PATH=${BUILD_PREFIX}/lib/pkgconfig\")\nCONFIG_OPTS+=(\"--prefix=${BUILD_PREFIX}\")\nCONFIG_OPTS+=(\"--enable-drafts=no\")\n\nfunction print_abi_api_breakages() {\n   echo \"ABI breakages detected:\"\n   cat compat_reports/libzmq/${LATEST_VERSION}_to_HEAD/abi_affected.txt | c++filt\n   echo \"API breakages detected:\"\n   cat compat_reports/libzmq/${LATEST_VERSION}_to_HEAD/src_affected.txt | c++filt\n   exit 1\n}\n\ngit fetch --unshallow\ngit fetch --all --tags\nLATEST_VERSION=$(git describe --abbrev=0 --tags)\n\n./autogen.sh\n./configure \"${CONFIG_OPTS[@]}\"\nmake VERBOSE=1 -j5\nabi-dumper src/.libs/libzmq.so -o ${BUILD_PREFIX}/libzmq.head.dump -lver HEAD\n\ngit clone --depth 1 -b ${LATEST_VERSION} https://github.com/zeromq/libzmq.git latest_release\ncd latest_release\n./autogen.sh\n./configure \"${CONFIG_OPTS[@]}\"\nmake VERBOSe=1 -j5\nabi-dumper src/.libs/libzmq.so -o ${BUILD_PREFIX}/libzmq.latest.dump -lver ${LATEST_VERSION}\n\nabi-compliance-checker -l libzmq -d1 ${BUILD_PREFIX}/libzmq.latest.dump -d2 ${BUILD_PREFIX}/libzmq.head.dump -list-affected || print_abi_api_breakages\n"
  },
  {
    "path": "builds/android/Dockerfile",
    "content": "# FROM\t\tdebian:7       # APT repo no more available.\n# FROM\t\tdebian:8\n# FROM\t\tdebian:9\n# FROM\t\tdebian:10\n# FROM\t\tdebian:11\n\n# FROM\t\tubuntu:12.04   # APT repo no more available.\n# FROM\t\tubuntu:14.04\n# FROM\t\tubuntu:16.04\n# FROM\t\tubuntu:18.04\n# FROM\t\tubuntu:20.04\nFROM\t\tubuntu:22.04\n\nENV\t\tDEBIAN_FRONTEND=noninteractive\n\nRUN\t\tapt-get update -y -q\n\nRUN\t\tapt-get install -y -q \\\n\t\t\tapt-utils\n\nRUN\t\tapt-get install -y -q \\\n\t\t\tautoconf \\\n\t\t\tautomake \\\n\t\t\tcmake \\\n\t\t\tfile \\\n\t\t\tgit \\\n\t\t\tlibtool \\\n\t\t\tpkg-config \\\n\t\t\tunzip \\\n\t\t\twget\n\n# Create user ZMQ, and run Android build with it.\n# This ensures that nothing weird is performed with\n# ROOT privileges.\nRUN\t\tuseradd -d /home/zmq -m -s /bin/bash zmq\nUSER\t\tzmq\nWORKDIR\t\t/home/zmq\n\n# Install android NDK (up to NDK 22):\n# ENV\t\tNDK_VERSION=android-ndk-r18  # Build failed to detect NDK tools (bug).\n# ENV\t\tNDK_VERSION=android-ndk-r19  # Build passed\n# ENV\t\tNDK_VERSION=android-ndk-r20  # Build passed\n# ENV\t\tNDK_VERSION=android-ndk-r21  # Build passed\n# ENV\t\tNDK_VERSION=android-ndk-r22  # Build passed\n\n# RUN\t\twget -q -O ndk_archive.zip http://dl.google.com/android/repository/${NDK_VERSION}-linux-x86_64.zip\n\n# Install android NDK (from NDK 23):\n# ENV\t\tNDK_VERSION=android-ndk-r23  # Build passed\n# ENV\t\tNDK_VERSION=android-ndk-r24  # Build passed\nENV\t\tNDK_VERSION=android-ndk-r25\n\nRUN\t\twget -q -O ndk_archive.zip http://dl.google.com/android/repository/${NDK_VERSION}-linux.zip\n\nRUN\t\tunzip -q ndk_archive.zip\n\n# Clone and build LIBZMQ\nENV\t\tANDROID_NDK_ROOT=/home/zmq/${NDK_VERSION}\n\nRUN\t\tgit clone --quiet --depth 1 https://github.com/zeromq/libzmq.git\n\nRUN\t\tlibzmq/builds/android/ci_build.sh\n\n"
  },
  {
    "path": "builds/android/README.md",
    "content": "# Android Build\n\n## Preamble\n\nThe last known NDK is automatically downloaded, if not specified otherwise.\n\nAs indicated in the main [README](../../README.md#supported-platforms-with-primary-CI), Android support is still DRAFT.\n\n## Configuration\n\n### Basics\n\nBasically, LIBZMQ build for Android, relies on exported variables.\n\nProvided build scripts can mainly be used like\n\n    export XXX=xxx\n    export YYY=yyy\n    ...\n    cd <libzmq>/builds/android\n    ./<build_script>\n\n\n### Android NDK\n\nLIBZMQ is tested against Android NDK versions r19 to r25.\n\nBy default, LIBZMQ uses NDK `android-ndk-r25`, but you can specify\na different one:\n\n    export NDK_VERSION=android-ndk-r23c\n\nIf you already have installed your favorite NDK somewhere, all you have to\ndo is to export and set NDK_VERSION and ANDROID_NDK_ROOT environment\nvariables, e.g:\n\n    export NDK_VERSION=\"android-ndk-r23b\"\n    export ANDROID_NDK_ROOT=$HOME/${NDK_VERSION}\n\n**Important:** ANDROID_NDK_ROOT must be an absolute path !\n\nIf you specify only NDK_VERSION, ANDROID_NDK_ROOT will be automatically set \nto its default:\n\n    export ANDROID_NDK_ROOT=/tmp/${NDK_VERSION}\n\nTo specify the minimum SDK version set the environment variable below:\n\n    export MIN_SDK_VERSION=21   # Default value if unset\n\nTo specify the build directory set the environment variable below:\n\n    export ANDROID_BUILD_DIR=${HOME}/android_build\n\n**Important:** ANDROID_BUILD_ROOT must be an absolute path !\n\n### Android build folder\n\nAll Android libraries will be generated under:\n\n    ${ANDROID_BUILD_DIR}/prefix/<arch>/lib\n\nwhere <arch> is one of `arm`, `arm64`, `x86` or `x86_64`.\n\n### Android build cleanup\n\nBuild and Dependency storage folders are automatically cleaned,\nby ci_build.sh. This can be avoided with the help of\n\n    ANDROID_BUILD_DIR=\"no\"\n\nIf you turn this to \"no\", make sure to clean what has to be, before\ncalling `build.sh` or `ci_build.sh`.\n\n### Prebuilt Android libraries\n\nAndroid prebuilt libraries have to be stored under\n\n    ANDROID_BUILD_DIR/prefix/<arch>/lib\n\nDo not forget to disable [Android cleanup](#android-build-cleanup).\n\n### Dependencies\n\nBy default, `build.sh` download dependencies under `/tmp/tmp-deps`.\n\nYou can specify another folder with the help of ANDROID_DEPENDENCIES_DIR:\n\n   ANDROID_DEPENDENCIES_DIR=${HOME}/my_dependencies\n\nIf you place your own dependency source trees there, \ndo not forget to disable [Android cleanup](#android-build-cleanup).\n\n### Cryptographic configuration\n\nThe variable CURVE accepts 2 different values:\n\n    \"\"          : LIBZMQ is built without any encryption support.\n    \"libsodium\" : LIBZMQ is built with LIBSODIUM encryption support (see below).\n\n### Other configuration variables\n\nYou can also check configuration variables in `build.sh` itself, in its\n\"Configuration & tuning options\" comment block.\n\n## LIBSODIUM\n\nLIBSODIUM is built along with LIBZMQ, when CURVE=\"libsodium\".\n\n- If you have your own clone of LIBSODIUM, set LIBSODIUM_ROOT to point to\nits folder.\n- If the variable LIBSODIUM_ROOT is not set, LIBZMQ will look for a folder\n'libsodium' close to his own one.\n- If no folder 'libsodium' exists, then LIBZMQ will clone LIBSODIUM from its\nofficial STABLE branch.\n\n## Build\n\nSee chapter [Configuration](#configuration) for configuration options and\nother details.\n\nSelect your preferred parameters:\n\n    export XXX=xxx\n    export YYY=yyy\n    ...\n\nand run:\n\n    cd <libzmq>/builds/android\n    ./build.sh [ arm | arm64 | x86 | x86_64 ]\n\nParameter selection and the calls to build.sh can be located in a\nSHELL script, like in ci_build.sh.\n\n## CI build \n\nBasically, it will call `build.sh` once, for each Android target.\n\nThis script accepts the same configuration variables, but some are set\nwith different default values. For instance, the dependencies are not\ndownloaded or cloned in `/tmp/tmp-deps, but inside LIBZMQ clone.\n\nIt can be used in the same way as build.sh\n\n    export XXX=xxx\n    export YYY=yyy\n    cd <libzmq>/builds/android\n    ./ci_build.sh\n\n\n## Dockerfile\n\nAn example of Docker file is provided, for Ubuntu 22.04\n\nMinimal changes are required to support Debian 9 to 11.\n\nMinimal changes are required to support CentOS (7 only), Rocky Linux (8 & 9),\nand many Fedora (22 to 37).\n\n"
  },
  {
    "path": "builds/android/android_build_helper.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2014, Joe Eli McIlvain\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are met:\n#\n# 1. Redistributions of source code must retain the above copyright notice,\n#    this list of conditions and the following disclaimer.\n#\n# 2. Redistributions in binary form must reproduce the above copyright notice,\n#    this list of conditions and the following disclaimer in the documentation\n#    and/or other materials provided with the distribution.\n#\n# 3. Neither the name of the copyright holder nor the names of its\n#    contributors may be used to endorse or promote products derived from\n#    this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n# THE POSSIBILITY OF SUCH DAMAGE.\n#\n###\n#\n# Courtesy of Joe Eli McIlvain; original code at:\n# https://github.com/jemc/android_build_helper\n#   android_build_helper.sh\n#\n# The following is a helper script for setting up android builds for\n# \"native\" libraries maintained with an autotools build system.\n# It merely helps to create the proper cross-compile environment.\n# It makes no attempt to wrap the library or make it accessible to Java code;\n# the intention is to make the bare library available to other \"native\" code.\n#\n# To get the latest version of this script, please download from:\n#   https://github.com/jemc/android_build_helper\n#\n# You are free to modify and redistribute this script, but if you add\n# improvements, please consider submitting a pull request or patch to the\n# aforementioned upstream repository for the benefit of other users.\n#\n# This script is provided with no express or implied warranties.\n#\n\n########################################################################\n# Utilities & helper functions\n########################################################################\nfunction android_build_trace {\n    if [ -n \"${BUILD_ARCH}\" ] ; then\n        echo \"LIBZMQ (${BUILD_ARCH}) - $*\"\n    else\n        echo \"LIBZMQ - $*\"\n    fi\n}\n\nfunction android_build_check_fail {\n    if [ ! ${#ANDROID_BUILD_FAIL[@]} -eq 0 ]; then\n        android_build_trace \"Android build failed for the following reasons:\"\n        for reason in \"${ANDROID_BUILD_FAIL[@]}\"; do\n            local formatted_reason=\"  ${reason}\"\n            echo \"${formatted_reason}\"\n        done\n        exit 1\n    fi\n}\n\nfunction android_download_ndk {\n    if [ -d \"${ANDROID_NDK_ROOT}\" ] ; then\n        # NDK folder detected, let's assume it's valid ...\n        android_build_trace \"Using existing NDK folder '${ANDROID_NDK_ROOT}'.\"\n        return\n    fi\n    if [ ! -d  \"$(dirname \"${ANDROID_NDK_ROOT}\")\" ] ; then\n        ANDROID_BUILD_FAIL+=(\"Cannot download NDK in a non existing folder\")\n        ANDROID_BUILD_FAIL+=(\"  $(dirname \"${ANDROID_NDK_ROOT}/\")\")\n    fi\n\n    android_build_check_fail\n\n    local filename\n    local platform=\"$(uname | tr '[:upper:]' '[:lower:]')\"\n    case \"${platform}\" in\n        linux*)\n            if [ \"${NDK_NUMBER}\" -ge 2300 ] ; then\n                # Since NDK 23, NDK archives are renamed.\n                filename=${NDK_VERSION}-linux.zip\n            else\n                filename=${NDK_VERSION}-linux-x86_64.zip\n            fi\n            ;;\n        darwin*)\n            if [ \"${NDK_NUMBER}\" -ge 2300 ] ; then\n                # Since NDK 23, NDK archives are renamed.\n                filename=${NDK_VERSION}-darwin.zip\n            else\n                filename=${NDK_VERSION}-darwin-x86_64.zip\n            fi\n            ;;\n        *)    android_build_trace \"Unsupported platform ('${platform}')\" ; exit 1 ;;\n    esac\n\n    if [ -z \"${filename}\" ] ; then\n        ANDROID_BUILD_FAIL+=(\"Unable to detect NDK filename.\")\n    fi\n\n    android_build_check_fail\n\n    android_build_trace \"Downloading NDK '${NDK_VERSION}'...\"\n    (\n        cd \"$(dirname \"${ANDROID_NDK_ROOT}\")\" \\\n        && rm -f \"${filename}\" \\\n        && wget -q \"http://dl.google.com/android/repository/${filename}\" -O \"${filename}\" \\\n        && android_build_trace \"Extracting NDK '${filename}'...\" \\\n        && unzip -q \"${filename}\" \\\n        && android_build_trace \"NDK extracted under '${ANDROID_NDK_ROOT}'.\"\n    ) || {\n        ANDROID_BUILD_FAIL+=(\"Failed to install NDK ('${NDK_VERSION}')\")\n        ANDROID_BUILD_FAIL+=(\"  ${filename}\")\n    }\n\n    android_build_check_fail\n}\n\nfunction android_build_set_env {\n    BUILD_ARCH=$1\n\n    local platform=\"$(uname | tr '[:upper:]' '[:lower:]')\"\n    case \"${platform}\" in\n        linux*)\n            export ANDROID_BUILD_PLATFORM=linux-x86_64\n            ;;\n        darwin*)\n            export ANDROID_BUILD_PLATFORM=darwin-x86_64\n            ;;\n        *)    android_build_trace \"Unsupported platform ('${platform}')\" ; exit 1 ;;\n    esac\n\n    export ANDROID_BUILD_TOOLCHAIN=\"${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/${ANDROID_BUILD_PLATFORM}\"\n    export TOOLCHAIN_PATH=\"${ANDROID_BUILD_TOOLCHAIN}/bin\"\n\n    # Set variables for each architecture\n    if [ \"${BUILD_ARCH}\" == \"arm\" ]; then\n        export TOOLCHAIN_HOST=\"arm-linux-androideabi\"\n        export TOOLCHAIN_COMP=\"armv7a-linux-androideabi${MIN_SDK_VERSION}\"\n        export TOOLCHAIN_ABI=\"armeabi-v7a\"\n        export TOOLCHAIN_ARCH=\"arm\"\n    elif [ \"${BUILD_ARCH}\" == \"x86\" ]; then\n        export TOOLCHAIN_HOST=\"i686-linux-android\"\n        export TOOLCHAIN_COMP=\"i686-linux-android${MIN_SDK_VERSION}\"\n        export TOOLCHAIN_ABI=\"x86\"\n        export TOOLCHAIN_ARCH=\"x86\"\n    elif [ \"${BUILD_ARCH}\" == \"arm64\" ]; then\n        export TOOLCHAIN_HOST=\"aarch64-linux-android\"\n        export TOOLCHAIN_COMP=\"aarch64-linux-android${MIN_SDK_VERSION}\"\n        export TOOLCHAIN_ABI=\"arm64-v8a\"\n        export TOOLCHAIN_ARCH=\"arm64\"\n    elif [ \"${BUILD_ARCH}\" == \"x86_64\" ]; then\n        export TOOLCHAIN_HOST=\"x86_64-linux-android\"\n        export TOOLCHAIN_COMP=\"x86_64-linux-android${MIN_SDK_VERSION}\"\n        export TOOLCHAIN_ABI=\"x86_64\"\n        export TOOLCHAIN_ARCH=\"x86_64\"\n    fi\n\n    # Since NDK r22 the \"platforms\" dir got removed\n    if [ -d \"${ANDROID_NDK_ROOT}/platforms\" ]; then\n        export ANDROID_BUILD_SYSROOT=\"${ANDROID_NDK_ROOT}/platforms/android-${MIN_SDK_VERSION}/arch-${TOOLCHAIN_ARCH}\"\n    else\n        export ANDROID_BUILD_SYSROOT=\"${ANDROID_BUILD_TOOLCHAIN}/sysroot\"\n    fi\n    export ANDROID_BUILD_PREFIX=\"${ANDROID_BUILD_DIR}/prefix/${TOOLCHAIN_ARCH}\"\n\n    # Since NDK r25, libc++_shared.so is no more in 'sources/cxx-stl/...'\n    export ANDROID_STL=\"libc++_shared.so\"\n    if [ -x \"${ANDROID_NDK_ROOT}/sources/cxx-stl/llvm-libc++/libs/${TOOLCHAIN_ABI}/${ANDROID_STL}\" ] ; then\n        export ANDROID_STL_ROOT=\"${ANDROID_NDK_ROOT}/sources/cxx-stl/llvm-libc++/libs/${TOOLCHAIN_ABI}\"\n    else\n        export ANDROID_STL_ROOT=\"${ANDROID_BUILD_SYSROOT}/usr/lib/${TOOLCHAIN_HOST}\"\n\n        # NDK 25 requires -L<path-to-libc.so> ...\n        # I don't understand why, but without it, ./configure fails to build a valid 'conftest'.\n        export ANDROID_LIBC_ROOT=\"${ANDROID_BUILD_SYSROOT}/usr/lib/${TOOLCHAIN_HOST}/${MIN_SDK_VERSION}\"\n    fi\n}\n\nfunction android_build_env {\n    ##\n    # Check that necessary environment variables are set\n\n    if [ -z \"$ANDROID_NDK_ROOT\" ]; then\n        ANDROID_BUILD_FAIL+=(\"Please set the ANDROID_NDK_ROOT environment variable\")\n        ANDROID_BUILD_FAIL+=(\"  (eg. \\\"/home/user/android/android-ndk-r25\\\")\")\n    fi\n\n    if [ -z \"$ANDROID_BUILD_TOOLCHAIN\" ]; then\n        ANDROID_BUILD_FAIL+=(\"Please set the ANDROID_BUILD_TOOLCHAIN environment variable\")\n        ANDROID_BUILD_FAIL+=(\"  (eg. \\\"/home/user/android/android-ndk-r25/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64\\\")\")\n    fi\n\n    if [ -z \"$TOOLCHAIN_PATH\" ]; then\n        ANDROID_BUILD_FAIL+=(\"Please set the TOOLCHAIN_PATH environment variable\")\n        ANDROID_BUILD_FAIL+=(\"  (eg. \\\"/home/user/android/android-ndk-r25/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin\\\")\")\n    fi\n\n    if [ -z \"$TOOLCHAIN_HOST\" ]; then\n        ANDROID_BUILD_FAIL+=(\"Please set the TOOLCHAIN_HOST environment variable\")\n        ANDROID_BUILD_FAIL+=(\"  (eg. \\\"arm-linux-androideabi\\\")\")\n    fi\n\n    if [ -z \"$TOOLCHAIN_COMP\" ]; then\n        ANDROID_BUILD_FAIL+=(\"Please set the TOOLCHAIN_COMP environment variable\")\n        ANDROID_BUILD_FAIL+=(\"  (eg. \\\"armv7a-linux-androideabi\\\")\")\n    fi\n\n    if [ -z \"$TOOLCHAIN_ABI\" ]; then\n        ANDROID_BUILD_FAIL+=(\"Please set the TOOLCHAIN_ABI environment variable\")\n        ANDROID_BUILD_FAIL+=(\"  (eg. \\\"armeabi-v7a\\\")\")\n    fi\n\n    if [ -z \"$TOOLCHAIN_ARCH\" ]; then\n        ANDROID_BUILD_FAIL+=(\"Please set the TOOLCHAIN_ARCH environment variable\")\n        ANDROID_BUILD_FAIL+=(\"  (eg. \\\"arm\\\")\")\n    fi\n\n    android_build_check_fail\n\n    ##\n    # Check that directories given by environment variables exist\n\n    if [ ! -d \"$ANDROID_NDK_ROOT\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The ANDROID_NDK_ROOT directory does not exist\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_NDK_ROOT}\")\n    fi\n\n    if [ ! -d \"$ANDROID_STL_ROOT\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The ANDROID_STL_ROOT directory does not exist\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_STL_ROOT}\")\n    fi\n\n    if [ -n \"${ANDROID_LIBC_ROOT}\" ] && [ ! -d \"${ANDROID_LIBC_ROOT}\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The ANDROID_LIBC_ROOT directory does not exist\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_LIBC_ROOT}\")\n    fi\n\n    if [ ! -d \"${ANDROID_BUILD_TOOLCHAIN}\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The ANDROID_BUILD_TOOLCHAIN directory does not exist\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_BUILD_TOOLCHAIN}\")\n    fi\n\n    if [ ! -d \"$TOOLCHAIN_PATH\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The TOOLCHAIN_PATH directory does not exist\")\n        ANDROID_BUILD_FAIL+=(\"  ${TOOLCHAIN_PATH}\")\n    fi\n\n    ##\n    # Set up some local variables and check them\n\n    if [ ! -d \"$ANDROID_BUILD_SYSROOT\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The ANDROID_BUILD_SYSROOT directory does not exist\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_BUILD_SYSROOT}\")\n    fi\n\n    mkdir -p \"$ANDROID_BUILD_PREFIX\" || {\n        ANDROID_BUILD_FAIL+=(\"Failed to make ANDROID_BUILD_PREFIX directory\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_BUILD_PREFIX}\")\n    }\n\n    android_build_check_fail\n}\n\nfunction _android_build_opts_process_binaries {\n    export ANDROID_BUILD_CC=\"${TOOLCHAIN_PATH}/${TOOLCHAIN_COMP}-clang\"\n    export ANDROID_BUILD_CXX=\"${TOOLCHAIN_PATH}/${TOOLCHAIN_COMP}-clang++\"\n    # Since NDK r22 the \"platforms\" dir got removed and the default linker is LLD\n    if [ -d \"${ANDROID_NDK_ROOT}/platforms\" ]; then\n       export ANDROID_BUILD_LD=\"${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ld\"\n    else\n       export ANDROID_BUILD_LD=\"${TOOLCHAIN_PATH}/ld\"\n    fi\n    # Since NDK r24 this binary was removed due to LLVM being now the default\n    if [ ! -x \"${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-as\" ]; then\n        export ANDROID_BUILD_AS=\"${TOOLCHAIN_PATH}/llvm-as\"\n    else\n        export ANDROID_BUILD_AS=\"${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-as\"\n    fi\n    # Since NDK r23 those binaries were removed due to LLVM being now the default\n    if [ ! -x \"${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ar\" ]; then\n        export ANDROID_BUILD_AR=\"${TOOLCHAIN_PATH}/llvm-ar\"\n        export ANDROID_BUILD_RANLIB=\"${TOOLCHAIN_PATH}/llvm-ranlib\"\n        export ANDROID_BUILD_STRIP=\"${TOOLCHAIN_PATH}/llvm-strip\"\n    else\n        export ANDROID_BUILD_AR=\"${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ar\"\n        export ANDROID_BUILD_RANLIB=\"${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ranlib\"\n        export ANDROID_BUILD_STRIP=\"${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-strip\"\n    fi\n\n    if [ ! -x \"${ANDROID_BUILD_CC}\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The CC binary does not exist or is not executable\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_BUILD_CC}\")\n    fi\n\n    if [ ! -x \"${ANDROID_BUILD_CXX}\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The CXX binary does not exist or is not executable\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_BUILD_CXX}\")\n    fi\n\n    if [ ! -x \"${ANDROID_BUILD_LD}\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The LD binary does not exist or is not executable\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_BUILD_LD}\")\n    fi\n\n    if [ ! -x \"${ANDROID_BUILD_AS}\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The AS binary does not exist or is not executable\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_BUILD_AS}\")\n    fi\n\n    if [ ! -x \"${ANDROID_BUILD_AR}\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The AR binary does not exist or is not executable\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_BUILD_AR}\")\n    fi\n\n    if [ ! -x \"${ANDROID_BUILD_RANLIB}\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The RANLIB binary does not exist or is not executable\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_BUILD_RANLIB}\")\n    fi\n\n    if [ ! -x \"${ANDROID_BUILD_STRIP}\" ]; then\n        ANDROID_BUILD_FAIL+=(\"The STRIP binary does not exist or is not executable\")\n        ANDROID_BUILD_FAIL+=(\"  ${ANDROID_BUILD_STRIP}\")\n    fi\n\n    ANDROID_BUILD_OPTS+=(\"TOOLCHAIN=${ANDROID_BUILD_TOOLCHAIN}\")\n    ANDROID_BUILD_OPTS+=(\"CC=${ANDROID_BUILD_CC}\")\n    ANDROID_BUILD_OPTS+=(\"CXX=${ANDROID_BUILD_CXX}\")\n    ANDROID_BUILD_OPTS+=(\"LD=${ANDROID_BUILD_LD}\")\n    ANDROID_BUILD_OPTS+=(\"AS=${ANDROID_BUILD_AS}\")\n    ANDROID_BUILD_OPTS+=(\"AR=${ANDROID_BUILD_AR}\")\n    ANDROID_BUILD_OPTS+=(\"RANLIB=${ANDROID_BUILD_RANLIB}\")\n    ANDROID_BUILD_OPTS+=(\"STRIP=${ANDROID_BUILD_STRIP}\")\n\n    android_build_check_fail\n}\n\n# Set the ANDROID_BUILD_OPTS variable to a bash array of configure options\nfunction android_build_opts {\n    ANDROID_BUILD_OPTS=()\n\n    _android_build_opts_process_binaries\n\n    if [ ${NDK_NUMBER} -ge 2700 ] ; then\n        # Since NDK r27 symbols like '__aeabi_xxx' are no more exported in the dynamic lib.\n        export ANDROID_BUILD_LIBS=\"-lc -ldl -lm -llog -static-libstdc++\"\n    elif [ ${NDK_NUMBER} -ge 2300 ] ; then\n        # Since NDK r23 we don't need -lgcc due to LLVM being now the default.\n        export ANDROID_BUILD_LIBS=\"-lc -ldl -lm -llog -lc++_shared\"\n    else\n        export ANDROID_BUILD_LIBS=\"-lc -lgcc -ldl -lm -llog -lc++_shared\"\n    fi\n\n    export ANDROID_BUILD_LDFLAGS=\"-L${ANDROID_BUILD_PREFIX}/lib\"\n    if [ -n \"${ANDROID_LIBC_ROOT}\" ] ; then\n        ANDROID_BUILD_LDFLAGS+=\" -L${ANDROID_LIBC_ROOT}\"\n    fi\n    ANDROID_BUILD_LDFLAGS+=\" -L${ANDROID_STL_ROOT}\"\n\n    export ANDROID_BUILD_CFLAGS+=\" -D_GNU_SOURCE -D_REENTRANT -D_THREAD_SAFE\"\n    export ANDROID_BUILD_CPPFLAGS+=\" -I${ANDROID_BUILD_PREFIX}/include\"\n\n    if [ \"${NDK_NUMBER}\" -ge 2400 ] ; then\n        if [ \"${BUILD_ARCH}\" = \"arm64\" ] ; then\n            export ANDROID_BUILD_CXXFLAGS+=\" -mno-outline-atomics\"\n        fi\n    fi\n\n    ANDROID_BUILD_OPTS+=(\"CFLAGS=${ANDROID_BUILD_CFLAGS} ${ANDROID_BUILD_EXTRA_CFLAGS}\")\n    ANDROID_BUILD_OPTS+=(\"CPPFLAGS=${ANDROID_BUILD_CPPFLAGS} ${ANDROID_BUILD_EXTRA_CPPFLAGS}\")\n    ANDROID_BUILD_OPTS+=(\"CXXFLAGS=${ANDROID_BUILD_CXXFLAGS} ${ANDROID_BUILD_EXTRA_CXXFLAGS}\")\n    ANDROID_BUILD_OPTS+=(\"LDFLAGS=${ANDROID_BUILD_LDFLAGS} ${ANDROID_BUILD_EXTRA_LDFLAGS}\")\n    ANDROID_BUILD_OPTS+=(\"LIBS=${ANDROID_BUILD_LIBS} ${ANDROID_BUILD_EXTRA_LIBS}\")\n\n    ANDROID_BUILD_OPTS+=(\"PKG_CONFIG_LIBDIR=${ANDROID_NDK_ROOT}/prebuilt/${ANDROID_BUILD_PLATFORM}/lib/pkgconfig\")\n    ANDROID_BUILD_OPTS+=(\"PKG_CONFIG_PATH=${ANDROID_BUILD_PREFIX}/lib/pkgconfig\")\n    ANDROID_BUILD_OPTS+=(\"PKG_CONFIG_SYSROOT_DIR=${ANDROID_BUILD_SYSROOT}\")\n    ANDROID_BUILD_OPTS+=(\"PKG_CONFIG_DIR=\")\n    ANDROID_BUILD_OPTS+=(\"--with-sysroot=${ANDROID_BUILD_SYSROOT}\")\n    ANDROID_BUILD_OPTS+=(\"--host=${TOOLCHAIN_HOST}\")\n    ANDROID_BUILD_OPTS+=(\"--prefix=${ANDROID_BUILD_PREFIX}\")\n\n    android_build_check_fail\n}\n\n# Parse readelf output to verify the correct linking of libraries.\n#   The first argument should be the soname of the newly built library.\n#   The rest of the arguments should be the sonames of dependencies.\n#   All sonames should be unversioned for android (no trailing numbers).\nfunction android_build_verify_so {\n    local soname=\"$1\"\n    shift # Get rid of first argument - the rest represent dependencies\n\n    local sofile=\"${ANDROID_BUILD_PREFIX}/lib/${soname}\"\n    if [ ! -f \"${sofile}\" ]; then\n        ANDROID_BUILD_FAIL+=(\"Found no library named ${soname}\")\n        ANDROID_BUILD_FAIL+=(\"  ${sofile}\")\n    fi\n    android_build_check_fail\n\n    local readelf=\"${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-readelf\"\n    if command -v \"${readelf}\" >/dev/null 2>&1 ; then\n        export ANDROID_BUILD_READELF=\"${readelf}\"\n    elif command -v readelf >/dev/null 2>&1 ; then\n        export ANDROID_BUILD_READELF=\"readelf\"\n    elif command -v greadelf >/dev/null 2>&1 ; then\n        export ANDROID_BUILD_READELF=\"greadelf\"\n    else\n        ANDROID_BUILD_FAIL+=(\"Could not find any of readelf, greadelf, or ${readelf}\")\n    fi\n    android_build_check_fail\n\n    local elfoutput\n    elfoutput=$(LC_ALL=C ${ANDROID_BUILD_READELF} -d \"${sofile}\")\n\n    local soname_regexp='soname: \\[([[:alnum:]\\.]+)\\]'\n    if [[ $elfoutput =~ $soname_regexp ]]; then\n        local parsed_soname=\"${BASH_REMATCH[1]}\"\n        if [ \"${parsed_soname}\" != \"${soname}\" ]; then\n            ANDROID_BUILD_FAIL+=(\"Actual soname of library ${soname} is incorrect (or versioned):\")\n            ANDROID_BUILD_FAIL+=(\"  ${parsed_soname}\")\n        fi\n    else\n        ANDROID_BUILD_FAIL+=(\"Failed to meaningfully parse readelf output for library ${soname}:\")\n        ANDROID_BUILD_FAIL+=(\"  ${elfoutput}\")\n    fi\n\n    for dep_soname in \"$@\" ; do\n        local dep_sofile=\"${ANDROID_BUILD_PREFIX}/lib/${dep_soname}\"\n        if [ ! -f \"${dep_sofile}\" ]; then\n            ANDROID_BUILD_FAIL+=(\"Found no library named ${dep_soname}\")\n            ANDROID_BUILD_FAIL+=(\"  ${dep_sofile}\")\n        elif [[ $elfoutput != *\"library: [${dep_soname}]\"* ]]; then\n            ANDROID_BUILD_FAIL+=(\"Library ${soname} was expected to be linked to library with soname:\")\n            ANDROID_BUILD_FAIL+=(\"  ${dep_soname}\")\n        fi\n    done\n\n    android_build_check_fail\n}\n\nfunction android_show_configure_opts {\n    local tag=$1\n    shift\n    android_build_trace \"./configure options to build '${tag}':\"\n    for opt in \"$@\"; do\n        echo \"  > ${opt}\"\n    done\n    echo \"\"\n}\n\n# Initialize env variable XXX_ROOT, given dependency name \"xxx\".\n# If XXX_ROOT is not set:\n#    If ${PROJECT_ROOT}/../xxx exists\n#        set XXX_ROOT with it.\n#    Else\n#        set XXX_ROOT with ${ANDROID_DEPENDENCIES_DIR}/xxx.\n# Else\n#    Verify that folder XXX_ROOT exists.\nfunction android_init_dependency_root {\n    local lib_name\n    lib_name=\"$1\"\n    local variable_name\n    variable_name=\"$(echo \"${lib_name}\" | tr '[:lower:]' '[:upper:]')_ROOT\"\n    local variable_value\n    variable_value=\"$(eval echo \"\\${${variable_name}}\")\"\n\n    if [ -z \"${PROJECT_ROOT}\" ] ; then\n        android_build_trace \"Error: Variable PROJECT_ROOT is not set.\"\n        exit 1\n    fi\n    if [ ! -d \"${PROJECT_ROOT}\" ] ; then\n        android_build_trace \"Error: Cannot find folder '${PROJECT_ROOT}'.\"\n        exit 1\n    fi\n\n    if [ -z \"${variable_value}\" ] ; then\n        if [ -d \"${PROJECT_ROOT}/../${lib_name}\" ] ; then\n            eval \"export ${variable_name}=\\\"$(cd \"${PROJECT_ROOT}/../${lib_name}\" && pwd)\\\"\"\n        else\n            eval \"export ${variable_name}=\\\"${ANDROID_DEPENDENCIES_DIR}/${lib_name}\\\"\"\n        fi\n        variable_value=\"$(eval echo \"\\${${variable_name}}\")\"\n    elif [ ! -d \"${variable_value}\" ] ; then\n        android_build_trace \"Error: Folder '${variable_value}' does not exist.\"\n        exit 1\n    fi\n\n    android_build_trace \"${variable_name}=${variable_value}\"\n}\n\nfunction android_download_library {\n    local tag=\"$1\" ; shift\n    local root=\"$1\" ; shift\n    local url=\"$1\" ; shift\n    local parent=\"$(dirname \"${root}\")\"\n    local archive=\"$(basename \"${url}\")\"\n\n    mkdir -p \"${parent}\"\n    cd \"${parent}\"\n\n    android_build_trace \"Downloading ${tag} from '${url}' ...\"\n    rm -f \"${archive}\"\n    wget -q \"${url}\"\n    case \"${archive}\" in\n        *.\"tar.gz\" ) folder=\"$(basename \"${archive}\" \".tar.gz\")\" ;;\n        *.\"tgz\" )    folder=\"$(basename \"${archive}\" \".tgz\")\" ;;\n        * ) android_build_trace \"Unsupported extension for '${archive}'.\" ; exit 1 ;;\n    esac\n    android_build_trace \"Extracting '${archive}' ...\"\n    tar -xzf \"${archive}\"\n    if [ ! -d \"${root}\" ] ; then\n\tmv \"${folder}\" \"${root}\"\n    fi\n    android_build_trace \"${tag} extracted under under '${root}'.\"\n}\n\nfunction android_clone_library {\n    local tag=\"$1\" ; shift\n    local root=\"$1\" ; shift\n    local url=\"$1\" ; shift\n    local branch=\"$1\" ; shift\n\n    mkdir -p \"$(dirname \"${root}\")\"\n    if [ -n \"${branch}\" ] ; then\n        android_build_trace \"Cloning '${url}' (branch '${branch}') under '${root}'.\"\n        git clone --quiet --depth 1 -b \"${branch}\" \"${url}\" \"${root}\"\n    else\n        android_build_trace \"Cloning '${url}' (default branch) under '${root}'.\"\n        git clone --quiet --depth 1 \"${url}\" \"${root}\"\n    fi\n    ( cd \"${root}\" && git log --oneline -n 1)  || exit 1\n}\n\n# Caller must set CONFIG_OPTS[], before call.\nfunction android_build_library {\n    local tag=$1 ; shift\n    local root=$1 ; shift\n\n    android_build_trace \"Cleaning library '${tag}'.\"\n    (\n        if [ -n \"${ANDROID_BUILD_PREFIX}\" ] && [ -d \"${ANDROID_BUILD_PREFIX}\" ] ; then\n            # Remove *.la files as they might cause errors with cross compiled libraries\n            find \"${ANDROID_BUILD_PREFIX}\" -name '*.la' -exec rm {} +\n        fi\n\n        cd \"${root}\" \\\n        && ( make clean || : ) \\\n        && rm -f config.status\n    ) &> /dev/null\n\n    android_build_trace \"Building library '${tag}'.\"\n    (\n        set -e\n\n        android_show_configure_opts \"${tag}\" \"${CONFIG_OPTS[@]}\"\n\n        cd \"${root}\"\n        if [ -e autogen.sh ]; then\n            ./autogen.sh 2> /dev/null\n        fi\n        if [ -e buildconf ]; then\n            ./buildconf 2> /dev/null\n        fi\n        if [ ! -e autogen.sh ] && [ ! -e buildconf ] && [ ! -e ./configure ] && [ -s ./configure.ac ] ; then\n            libtoolize --copy --force && \\\n            aclocal -I . && \\\n            autoheader && \\\n            automake --add-missing --copy && \\\n            autoconf || \\\n            autoreconf -fiv\n        fi\n\n        ./configure \"${CONFIG_OPTS[@]}\"\n        make -j 4\n        make install\n    )\n}\n\n########################################################################\n# Initialization\n########################################################################\n# Get directory of current script (if not already set)\n# This directory is also the basis for the build directories the get created.\nif [ -z \"$ANDROID_BUILD_DIR\" ]; then\n    export ANDROID_BUILD_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nfi\n\n# Where to download our dependencies\nexport ANDROID_DEPENDENCIES_DIR=\"${ANDROID_DEPENDENCIES_DIR:-/tmp/tmp-deps}\"\n\n# Set up a variable to hold the global failure reasons, separated by newlines\n# (Empty string indicates no failure)\nANDROID_BUILD_FAIL=()\n\n########################################################################\n# Sanity checks\n########################################################################\ncase \"${NDK_VERSION}\" in\n    \"android-ndk-r\"[0-9][0-9] ) : ;;\n    \"android-ndk-r\"[0-9][0-9][a-z] ) : ;;\n    \"\" ) android_build_trace \"Variable NDK_VERSION not set.\" ; exit 1 ;;\n    * ) android_build_trace \"Invalid format for NDK_VERSION ('${NDK_VERSION}')\" ; exit 1 ;;\nesac\n\nif [ -z \"${ANDROID_NDK_ROOT}\" ] ; then\n    android_build_trace \"ANDROID_NDK_ROOT not set !\"\n    exit 1\nfi\n\n########################################################################\n# Compute NDK version into a numeric form:\n#   android-ndk-r21e -> 2105\n#   android-ndk-r25  -> 2500\n########################################################################\nexport NDK_NUMBER=\"$(( $(echo \"${NDK_VERSION}\"|sed -e 's|android-ndk-r||g' -e 's|[a-z]||g') * 100 ))\"\nNDK_VERSION_LETTER=\"$(echo \"${NDK_VERSION}\"|sed -e 's|android-ndk-r[0-9][0-9]||g'|tr '[:lower:]' '[:upper:]')\"\nif [ -n \"${NDK_VERSION_LETTER}\" ] ; then\n    NDK_NUMBER=$(( $(( NDK_NUMBER + $(printf '%d' \\'\"${NDK_VERSION_LETTER}\") )) - 64 ))\nfi\nandroid_build_trace \"Configured NDK_VERSION: ${NDK_VERSION} ($NDK_NUMBER).\"\n\n"
  },
  {
    "path": "builds/android/build.sh",
    "content": "#!/usr/bin/env bash\n#\n#   Exit if any step fails\nset -e\n\n# Use directory of current script as the working directory\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\nPROJECT_ROOT=\"$(cd ../.. && pwd)\"\n\n########################################################################\n# Configuration & tuning options.\n########################################################################\n# Set default values used in ci builds\nexport NDK_VERSION=\"${NDK_VERSION:-android-ndk-r25}\"\n\n# Set default path to find Android NDK.\n# Must be of the form <path>/${NDK_VERSION} !!\nexport ANDROID_NDK_ROOT=\"${ANDROID_NDK_ROOT:-/tmp/${NDK_VERSION}}\"\n\n# With NDK r22b, the minimum SDK version range is [16, 31].\n# Since NDK r24, the minimum SDK version range is [19, 31].\n# SDK version 21 is the minimum version for 64-bit builds.\nexport MIN_SDK_VERSION=${MIN_SDK_VERSION:-21}\n\n# Use directory of current script as the build directory\n# ${ANDROID_BUILD_DIR}/prefix/<build_arch>/lib will contain produced libraries\nexport ANDROID_BUILD_DIR=\"${ANDROID_BUILD_DIR:-${PWD}}\"\n\n# Where to download our dependencies: default to /tmp/tmp-deps\nexport ANDROID_DEPENDENCIES_DIR=\"${ANDROID_DEPENDENCIES_DIR:-/tmp/tmp-deps}\"\n\n# Clean before processing\nexport ANDROID_BUILD_CLEAN=\"${ANDROID_BUILD_CLEAN:-no}\"\n\n# Set this to 'no', to enable verbose ./configure\nexport CI_CONFIG_QUIET=\"${CI_CONFIG_QUIET:-no}\"\n\n# Select CURVE implementation:\n# - \"\"               # Do not use any CURVE implementation.\n# - \"libsodium\"      # Use LIBSODIUM implementation.\nexport CURVE=\"${CURVE:-}\"\n\n# By default, dependencies will be cloned to /tmp/tmp-deps.\n# If you have your own source tree for LIBSODIUM, uncomment\n# the line below, and provide its absolute path:\n#    export LIBSODIUM_ROOT=\"<absolute_path_to_LIBSODIUM_source_tree>\"\n\n########################################################################\n# Utilities\n########################################################################\n# Get access to android_build functions and variables\n# Perform some sanity checks and calculate some variables.\nsource \"${PROJECT_ROOT}/builds/android/android_build_helper.sh\"\n\nfunction usage {\n    echo \"LIBZMQ - Usage:\"\n    echo \"  export XXX=xxx\"\n    echo \"  ./build.sh [ arm | arm64 | x86 | x86_64 ]\"\n    echo \"\"\n    echo \"See this file (configuration & tuning options) for details\"\n    echo \"on variables XXX and their values xxx\"\n    exit 1\n}\n\n########################################################################\n# Sanity checks\n########################################################################\nBUILD_ARCH=\"$1\"\n[ -z \"${BUILD_ARCH}\" ] && usage\n\n# Set ROOT path for LIBSODIUM source tree, if CURVE is \"libsodium\"\nif [ \"${CURVE}x\" = \"libsodiumx\" ] ; then\n    # Check or initialize LIBSODIUM_ROOT\n    android_init_dependency_root \"libsodium\"\nfi\n\n########################################################################\n# Compilation\n########################################################################\n# Choose a C++ standard library implementation from the ndk\nexport ANDROID_BUILD_CXXSTL=\"gnustl_shared_49\"\n\n# Additional flags for LIBTOOL, for LIBZMQ and other dependencies.\nexport LIBTOOL_EXTRA_LDFLAGS='-avoid-version'\n\n# Set up android build environment and set ANDROID_BUILD_OPTS array\nandroid_build_set_env \"${BUILD_ARCH}\"\nandroid_download_ndk\nandroid_build_env\nandroid_build_opts\n\n# Check for environment variable to clear the prefix and do a clean build\nif [ \"${ANDROID_BUILD_CLEAN}\" = \"yes\" ]; then\n    android_build_trace \"Doing a clean build (removing previous build and dependencies)...\"\n    rm -rf \"${ANDROID_BUILD_PREFIX:?}\"/*\n\n    # Called shells MUST not clean after ourselves !\n    export ANDROID_BUILD_CLEAN=\"no\"\nfi\n\nDEPENDENCIES=()\nif [ -z \"${CURVE}\" ]; then\n    CURVE=\"--disable-curve\"\nelif [ \"${CURVE}\" == \"libsodium\" ]; then\n    CURVE=\"--with-libsodium=yes\"\n    DEPENDENCIES+=(\"libsodium.so\")\n    ##\n    # Build LIBSODIUM from latest STABLE branch\n\n    (android_build_verify_so \"libsodium.so\" &> /dev/null) || {\n        if [ ! -d \"${LIBSODIUM_ROOT}\" ] ; then\n            android_clone_library \"LIBSODIUM\" \"${LIBSODIUM_ROOT}\" \"https://github.com/jedisct1/libsodium.git\" \"stable\"\n        fi\n\n        (\n            CONFIG_OPTS=()\n            [ \"${CI_CONFIG_QUIET}\" = \"yes\" ] && CONFIG_OPTS+=(\"--quiet\")\n            CONFIG_OPTS+=(\"${ANDROID_BUILD_OPTS[@]}\")\n            CONFIG_OPTS+=(\"--without-docs\")\n            CONFIG_OPTS+=(\"--disable-soname-versions\")\n\n            android_build_library \"LIBSODIUM\" \"${LIBSODIUM_ROOT}\"\n        ) || exit 1\n    }\nfi\n\n##\n# Build libzmq from local source\n\n(android_build_verify_so \"libzmq.so\" \"${DEPENDENCIES[@]}\" &> /dev/null) || {\n    (\n        CONFIG_OPTS=()\n        [ \"${CI_CONFIG_QUIET}\" = \"yes\" ] && CONFIG_OPTS+=(\"--quiet\")\n        CONFIG_OPTS+=(\"${ANDROID_BUILD_OPTS[@]}\")\n        CONFIG_OPTS+=(\"${CURVE}\")\n        CONFIG_OPTS+=(\"--without-docs\")\n\n        android_build_library \"LIBZMQ\" \"${PROJECT_ROOT}\"\n    ) || exit 1\n}\n\n##\n# Fetch the STL as well.\n\ncp \"${ANDROID_STL_ROOT}/${ANDROID_STL}\" \"${ANDROID_BUILD_PREFIX}/lib/.\"\n\n##\n# Verify shared libraries in prefix\nfor library in \"libzmq.so\" \"${DEPENDENCIES[@]}\" ; do\n    android_build_verify_so \"${library}\"\ndone\n\nandroid_build_verify_so \"libzmq.so\" \"${DEPENDENCIES[@]}\" \"${ANDROID_STL}\"\nandroid_build_trace \"Android build successful\"\n"
  },
  {
    "path": "builds/android/ci_build.sh",
    "content": "#!/usr/bin/env bash\n#\n#   Exit if any step fails\nset -e\n\n# Use directory of current script as the working directory\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\n\n# Configuration\nexport NDK_VERSION=\"${NDK_VERSION:-android-ndk-r25}\"\nexport ANDROID_NDK_ROOT=\"${ANDROID_NDK_ROOT:-/tmp/${NDK_VERSION}}\"\nexport MIN_SDK_VERSION=${MIN_SDK_VERSION:-21}\nexport ANDROID_BUILD_DIR=\"${ANDROID_BUILD_DIR:-${PWD}/.build}\"\nexport ANDROID_BUILD_CLEAN=\"${ANDROID_BUILD_CLEAN:-yes}\"\nexport ANDROID_DEPENDENCIES_DIR=\"${ANDROID_DEPENDENCIES_DIR:-${PWD}/.deps}\"\n\n# Cleanup.\nif [ \"${ANDROID_BUILD_CLEAN}\" = \"yes\" ] ; then\n    rm -rf   \"${ANDROID_BUILD_DIR}/prefix\"\n    mkdir -p \"${ANDROID_BUILD_DIR}/prefix\"\n    rm -rf   \"${ANDROID_DEPENDENCIES_DIR}\"\n    mkdir -p \"${ANDROID_DEPENDENCIES_DIR}\"\n\n    # Called shells MUST not clean after ourselves !\n    export ANDROID_BUILD_CLEAN=\"no\"\nfi\n\n./build.sh \"arm\"\n./build.sh \"arm64\"\n./build.sh \"x86\"\n./build.sh \"x86_64\"\n"
  },
  {
    "path": "builds/cmake/Modules/ClangFormat.cmake",
    "content": "# additional target to perform clang-format run, requires clang-format\n\n# get all project files\nfile(GLOB_RECURSE ALL_SOURCE_FILES \n     RELATIVE ${CMAKE_CURRENT_BINARY_DIR} \n     ${CMAKE_SOURCE_DIR}/src/*.cpp ${CMAKE_SOURCE_DIR}/src/*.h ${CMAKE_SOURCE_DIR}/src/*.hpp \n     ${CMAKE_SOURCE_DIR}/tests/*.cpp ${CMAKE_SOURCE_DIR}/tests/*.h ${CMAKE_SOURCE_DIR}/tests/*.hpp \n     ${CMAKE_SOURCE_DIR}/perf/*.cpp ${CMAKE_SOURCE_DIR}/perf/*.h ${CMAKE_SOURCE_DIR}/perf/*.hpp \n     ${CMAKE_SOURCE_DIR}/tools/*.cpp ${CMAKE_SOURCE_DIR}/tools/*.h ${CMAKE_SOURCE_DIR}/tools/*.hpp \n     ${CMAKE_SOURCE_DIR}/include/*.h\n    )\n\nif(\"${CLANG_FORMAT}\" STREQUAL \"\")\n  set(CLANG_FORMAT \"clang-format\")\nendif()\n\nadd_custom_target(\n        clang-format\n        COMMAND ${CLANG_FORMAT} -style=file -i ${ALL_SOURCE_FILES}\n)\n\nfunction(JOIN VALUES GLUE OUTPUT)\n  string (REPLACE \";\" \"${GLUE}\" _TMP_STR \"${VALUES}\")\n  set (${OUTPUT} \"${_TMP_STR}\" PARENT_SCOPE)\nendfunction()\n\nconfigure_file(builds/cmake/clang-format-check.sh.in clang-format-check.sh @ONLY)\n\nadd_custom_target(\n        clang-format-check\n        COMMAND chmod +x clang-format-check.sh\n        COMMAND ./clang-format-check.sh\n        COMMENT \"Checking correct formatting according to .clang-format file using ${CLANG_FORMAT}\"\n)\n\nadd_custom_target(\n        clang-format-diff\n        COMMAND ${CLANG_FORMAT} -style=file -i ${ALL_SOURCE_FILES}\n        COMMAND git diff ${ALL_SOURCE_FILES}\n        COMMENT \"Formatting with clang-format (using ${CLANG_FORMAT}) and showing differences with latest commit\"\n)\n"
  },
  {
    "path": "builds/cmake/Modules/FindAsciiDoctor.cmake",
    "content": "# - Find Asciidoctor\n# this module looks for asciidoctor\n#\n# ASCIIDOCTOR_EXECUTABLE - the full path to asciidoc\n# ASCIIDOCTOR_FOUND - If false, don't attempt to use asciidoc.\nset (PROGRAMFILESX86 \"PROGRAMFILES(X86)\")\n\nfind_program(ASCIIDOCTOR_EXECUTABLE asciidoctor asciidoctor\n             PATHS \"$ENV{ASCIIDOCTOR_ROOT}\"\n                   \"$ENV{PROGRAMW6432}/asciidoctor\"\n                   \"$ENV{PROGRAMFILES}/asciidoctor\"\n                   \"$ENV{${PROGRAMFILESX86}}/asciidoctor\")\n\nfind_program(A2X_EXECUTABLE a2x\n             PATHS \"$ENV{ASCIIDOCTOR_ROOT}\"\n                   \"$ENV{PROGRAMW6432}/asciidoctor\"\n                   \"$ENV{PROGRAMFILES}/asciidoctor\"\n                   \"$ENV{${PROGRAMFILESX86}}/asciidoctor\")\n\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_ARGS(AsciiDoctor REQUIRED_VARS ASCIIDOCTOR_EXECUTABLE)\nmark_as_advanced(ASCIIDOCTOR_EXECUTABLE)\n"
  },
  {
    "path": "builds/cmake/Modules/FindNSS3.cmake",
    "content": "include(FindPackageHandleStandardArgs)\n\nif (NOT MSVC)\n    find_package(PkgConfig REQUIRED)\n    pkg_check_modules(NSS3 \"nss>=3.19\")\n    find_package_handle_standard_args(NSS3 DEFAULT_MSG NSS3_LIBRARIES NSS3_CFLAGS)\nendif()\n\n"
  },
  {
    "path": "builds/cmake/Modules/Findgssapi_krb5.cmake",
    "content": "if (NOT MSVC)\nfind_package(PkgConfig REQUIRED) \npkg_check_modules(PC_GSSAPI_KRB5 \"libgssapi_krb5\")\nif (PC_GSSAPI_KRB5_FOUND)\n  set(pkg_config_names_private \"${pkg_config_names_private} libgssapi_krb5\")\nendif()\nif (NOT PC_GSSAPI_KRB5_FOUND)\n    pkg_check_modules(PC_GSSAPI_KRB5 \"gssapi_krb5\")\n    if (PC_GSSAPI_KRB5_FOUND)\n      set(pkg_config_names_private \"${pkg_config_names_private} gssapi_krb5\")\n    endif()\nendif (NOT PC_GSSAPI_KRB5_FOUND)\nif (PC_GSSAPI_KRB5_FOUND)\n  set(GSSAPI_KRB5_INCLUDE_HINTS ${PC_GSSAPI_KRB5_INCLUDE_DIRS} ${PC_GSSAPI_KRB5_INCLUDE_DIRS}/*)\n  set(GSSAPI_KRB5_LIBRARY_HINTS ${PC_GSSAPI_KRB5_LIBRARY_DIRS} ${PC_GSSAPI_KRB5_LIBRARY_DIRS}/*)\nelse()\n  set(pkg_config_libs_private \"${pkg_config_libs_private} -lgssapi_krb5\")\nendif()\nendif (NOT MSVC)\n\n# some libraries install the headers is a subdirectory of the include dir\n# returned by pkg-config, so use a wildcard match to improve chances of finding\n# headers and libraries.\nfind_path(\n    GSSAPI_KRB5_INCLUDE_DIRS\n    NAMES gssapi/gssapi_krb5.h\n    HINTS ${GSSAPI_KRB5_INCLUDE_HINTS}\n)\n\nset (GSSAPI_NAMES libgssapi_krb5 gssapi_krb5)\nif (${CMAKE_SIZEOF_VOID_P} STREQUAL 8)\n  set (GSSAPI_NAMES ${GSSAPI_NAMES} gssapi64)\nelseif (${CMAKE_SIZEOF_VOID_P} STREQUAL 4)\n  set (GSSAPI_NAMES ${GSSAPI_NAMES} gssapi32)\nendif()\n\nfind_library(\n    GSSAPI_KRB5_LIBRARIES\n    NAMES ${GSSAPI_NAMES}\n    HINTS ${GSSAPI_KRB5_LIBRARY_HINTS}\n)\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(gssapi_krb5 DEFAULT_MSG GSSAPI_KRB5_LIBRARIES GSSAPI_KRB5_INCLUDE_DIRS)\nmark_as_advanced(GSSAPI_KRB5_FOUND GSSAPI_KRB5_LIBRARIES GSSAPI_KRB5_INCLUDE_DIRS)\n"
  },
  {
    "path": "builds/cmake/Modules/Findsodium.cmake",
    "content": "################################################################################\n#  THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY  #\n#  Please refer to the README for information about making permanent changes.  #\n################################################################################\n\nif (NOT MSVC)\nfind_package(PkgConfig REQUIRED) \npkg_check_modules(PC_SODIUM \"libsodium\")\nif (PC_SODIUM_FOUND)\n  set(pkg_config_names_private \"${pkg_config_names_private} libsodium\")\nendif()\nif (NOT PC_SODIUM_FOUND)\n    pkg_check_modules(PC_SODIUM \"sodium\")\n    if (PC_SODIUM_FOUND)\n      set(pkg_config_names_private \"${pkg_config_names_private} sodium\")\n    endif()\nendif (NOT PC_SODIUM_FOUND)\nif (PC_SODIUM_FOUND)\n  set(SODIUM_INCLUDE_HINTS ${PC_SODIUM_INCLUDE_DIRS} ${PC_SODIUM_INCLUDE_DIRS}/*)\n  set(SODIUM_LIBRARY_HINTS ${PC_SODIUM_LIBRARY_DIRS} ${PC_SODIUM_LIBRARY_DIRS}/*)\nelse()\n  set(pkg_config_libs_private \"${pkg_config_libs_private} -lsodium\")\nendif()\nendif (NOT MSVC)\n\n# some libraries install the headers is a subdirectory of the include dir\n# returned by pkg-config, so use a wildcard match to improve chances of finding\n# headers and libraries.\nfind_path(\n    SODIUM_INCLUDE_DIRS\n    NAMES sodium.h\n    HINTS ${SODIUM_INCLUDE_HINTS}\n)\n\nfind_library(\n    SODIUM_LIBRARIES\n    NAMES libsodium sodium\n    HINTS ${SODIUM_LIBRARY_HINTS}\n)\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(sodium DEFAULT_MSG SODIUM_LIBRARIES SODIUM_INCLUDE_DIRS)\nmark_as_advanced(SODIUM_FOUND SODIUM_LIBRARIES SODIUM_INCLUDE_DIRS)\n\n################################################################################\n#  THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY  #\n#  Please refer to the README for information about making permanent changes.  #\n################################################################################\n"
  },
  {
    "path": "builds/cmake/Modules/TestZMQVersion.cmake",
    "content": "\nfile(READ \"${PROJECT_SOURCE_DIR}/include/zmq.h\" _ZMQ_H_CONTENTS)\nstring(REGEX REPLACE \".*#define ZMQ_VERSION_MAJOR ([0-9]+).*\" \"\\\\1\" ZMQ_VERSION_MAJOR \"${_ZMQ_H_CONTENTS}\")\nstring(REGEX REPLACE \".*#define ZMQ_VERSION_MINOR ([0-9]+).*\" \"\\\\1\" ZMQ_VERSION_MINOR \"${_ZMQ_H_CONTENTS}\")\nstring(REGEX REPLACE \".*#define ZMQ_VERSION_PATCH ([0-9]+).*\" \"\\\\1\" ZMQ_VERSION_PATCH \"${_ZMQ_H_CONTENTS}\")\nset(ZMQ_VERSION \"${ZMQ_VERSION_MAJOR}.${ZMQ_VERSION_MINOR}.${ZMQ_VERSION_PATCH}\")\n\nmessage(STATUS \"Detected ZMQ Version - ${ZMQ_VERSION}\")\n"
  },
  {
    "path": "builds/cmake/Modules/ZMQSourceRunChecks.cmake",
    "content": "\n\nmacro(zmq_check_sock_cloexec)\n  message(STATUS \"Checking whether SOCK_CLOEXEC is supported\")\n  check_c_source_runs(\n    \"\n#include <sys/types.h>\n#include <sys/socket.h>\n\nint main(int argc, char *argv [])\n{\n    int s = socket(PF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);\n    return(s == -1);\n}\n\"\n    ZMQ_HAVE_SOCK_CLOEXEC)\nendmacro()\n\nmacro(zmq_check_efd_cloexec)\n  message(STATUS \"Checking whether EFD_CLOEXEC is supported\")\n  check_c_source_runs(\n    \"\n#include <sys/eventfd.h>\n\nint main(int argc, char *argv [])\n{\n    int s = eventfd (0, EFD_CLOEXEC);\n    return(s == -1);\n}\n\"\n    ZMQ_HAVE_EVENTFD_CLOEXEC)\nendmacro()\n\nmacro(zmq_check_o_cloexec)\n  message(STATUS \"Checking whether O_CLOEXEC is supported\")\n  check_c_source_runs(\n    \"\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n\nint main(int argc, char *argv [])\n{\n    int s = open (\\\"/dev/null\\\", O_CLOEXEC | O_RDONLY);\n    return s == -1;\n}\n\"\n    ZMQ_HAVE_O_CLOEXEC)\nendmacro()\n\nmacro(zmq_check_so_bindtodevice)\n  message(STATUS \"Checking whether SO_BINDTODEVICE is supported\")\n  check_c_source_runs(\n\"\n#include <sys/socket.h>\n\nint main(int argc, char *argv [])\n{\n/* Actually making the setsockopt() call requires CAP_NET_RAW */\n#ifndef SO_BINDTODEVICE\n    return 1;\n#else\n    return 0;\n#endif\n}\n\"\n    ZMQ_HAVE_SO_BINDTODEVICE)\nendmacro()\n\n# TCP keep-alives Checks.\n\nmacro(zmq_check_so_keepalive)\n  message(STATUS \"Checking whether SO_KEEPALIVE is supported\")\n  check_c_source_runs(\n\"\n#include <sys/types.h>\n#include <sys/socket.h>\n\nint main(int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return(\n       ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) ||\n       ((rc = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,(char*) &opt, sizeof(int))) == -1)\n    );\n}\n\"\n    ZMQ_HAVE_SO_KEEPALIVE)\nendmacro()\n\nmacro(zmq_check_tcp_keepcnt)\n  message(STATUS \"Checking whether TCP_KEEPCNT is supported\")\n  check_c_source_runs(\n    \"\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n\nint main(int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return(\n       ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) ||\n       ((rc = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,(char*) &opt, sizeof(int))) == -1) ||\n       ((rc = setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT,(char*) &opt, sizeof(int))) == -1)\n    );\n}\n\"\n    ZMQ_HAVE_TCP_KEEPCNT)\nendmacro()\n\nmacro(zmq_check_tcp_keepidle)\n  message(STATUS \"Checking whether TCP_KEEPIDLE is supported\")\n  check_c_source_runs(\n    \"\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n\nint main(int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return(\n       ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) ||\n       ((rc = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,(char*) &opt, sizeof(int))) == -1) ||\n       ((rc = setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE,(char*) &opt, sizeof(int))) == -1)\n    );\n}\n\"\n    ZMQ_HAVE_TCP_KEEPIDLE)\nendmacro()\n\n\nmacro(zmq_check_tcp_keepintvl)\n  message(STATUS \"Checking whether TCP_KEEPINTVL is supported\")\n  check_c_source_runs(\n    \"\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n\nint main(int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return(\n       ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) ||\n       ((rc = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,(char*) &opt, sizeof(int))) == -1) ||\n       ((rc = setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL,(char*) &opt, sizeof(int))) == -1)\n    );\n}\n\n\"\n    ZMQ_HAVE_TCP_KEEPINTVL)\nendmacro()\n\n\nmacro(zmq_check_tcp_keepalive)\n  message(STATUS \"Checking whether TCP_KEEPALIVE is supported\")\n  check_c_source_runs(\n    \"\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n\nint main(int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return(\n       ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) ||\n       ((rc = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,(char*) &opt, sizeof(int))) == -1) ||\n       ((rc = setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE,(char*) &opt, sizeof(int))) == -1)\n    );\n}\n\"\n    ZMQ_HAVE_TCP_KEEPALIVE)\nendmacro()\n\n\nmacro(zmq_check_tcp_tipc)\n  message(STATUS \"Checking whether TIPC is supported\")\n  check_c_source_runs(\n    \"\n#include <stdlib.h>\n#include <string.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <sys/socket.h>\n#include <linux/tipc.h>\n\nint main(int argc, char *argv [])\n{\n    struct sockaddr_tipc topsrv;\n    int sd = socket(PF_TIPC, SOCK_SEQPACKET, 0);\n    memset(&topsrv, 0, sizeof(topsrv));\n    topsrv.family = AF_TIPC;\n    topsrv.addrtype = TIPC_ADDR_NAME;\n    topsrv.addr.name.name.type = TIPC_TOP_SRV;\n    topsrv.addr.name.name.instance = TIPC_TOP_SRV;\n    fcntl(sd, F_SETFL, O_NONBLOCK);\n    tipc_addr(0, 0, 0);\n}\n\"\n    ZMQ_HAVE_TIPC)\nendmacro()\n\n\nmacro(zmq_check_pthread_setname)\n  message(STATUS \"Checking pthread_setname signature\")\n  set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})\n  set(CMAKE_REQUIRED_FLAGS \"-D_GNU_SOURCE -Werror -pthread\")\n  check_c_source_compiles(\n    \"\n#include <pthread.h>\n\nint main(int argc, char *argv [])\n{\n    pthread_setname_np (\\\"foo\\\");\n    return 0;\n}\n\"\n    ZMQ_HAVE_PTHREAD_SETNAME_1)\n  check_c_source_compiles(\n    \"\n#include <pthread.h>\n\nint main(int argc, char *argv [])\n{\n    pthread_setname_np (pthread_self(), \\\"foo\\\");\n    return 0;\n}\n\"\n    ZMQ_HAVE_PTHREAD_SETNAME_2)\n  check_c_source_compiles(\n    \"\n#include <pthread.h>\n\nint main(int argc, char *argv [])\n{\n    pthread_setname_np (pthread_self(), \\\"foo\\\", (void *)0);\n    return 0;\n}\n\"\n    ZMQ_HAVE_PTHREAD_SETNAME_3)\n  check_c_source_compiles(\n    \"\n#include <pthread.h>\n\nint main(int argc, char *argv [])\n{\n    pthread_set_name_np (pthread_self(), \\\"foo\\\");\n    return 0;\n}\n\"\n    ZMQ_HAVE_PTHREAD_SET_NAME)\n  set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS})\nendmacro()\n\nmacro(zmq_check_pthread_setaffinity)\n  message(STATUS \"Checking pthread_setaffinity signature\")\n  set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})\n  set(CMAKE_REQUIRED_FLAGS \"-D_GNU_SOURCE -Werror -pthread\")\n  check_c_source_compiles(\n    \"\n#include <pthread.h>\n\nint main(int argc, char *argv [])\n{\n    cpu_set_t test; \n    pthread_setaffinity_np (pthread_self(), sizeof(cpu_set_t), &test);\n    return 0;\n}\n\"\n    ZMQ_HAVE_PTHREAD_SET_AFFINITY)\n  set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS})\nendmacro()\n\n\nmacro(zmq_check_getrandom)\n  message(STATUS \"Checking whether getrandom is supported\")\n  check_c_source_runs(\n    \"\n#include <sys/random.h>\n\nint main (int argc, char *argv [])\n{\n    char buf[4];\n    int rc = getrandom(buf, 4, 0);\n    return rc == -1 ? 1 : 0;\n}\n\"\n    ZMQ_HAVE_GETRANDOM)\nendmacro()\n\nmacro(zmq_check_noexcept)\n  message(STATUS \"Checking whether noexcept is supported\")\n  check_cxx_source_compiles(\n\"\nstruct X \n{\n    X(int i) noexcept {}\n};\n\nint main(int argc, char *argv [])\n{\n    X x(5);\n    return 0;\n}\n\"\n    ZMQ_HAVE_NOEXCEPT)\nendmacro()\n\nmacro(zmq_check_so_priority)\n  message(STATUS \"Checking whether SO_PRIORITY is supported\")\n  check_c_source_runs(\n    \"\n#include <sys/types.h>\n#include <sys/socket.h>\n\nint main (int argc, char *argv [])\n{\n    int s, rc, opt = 1;\n    return (\n        ((s = socket (PF_INET, SOCK_STREAM, 0)) == -1) ||\n        ((rc = setsockopt (s, SOL_SOCKET, SO_PRIORITY, (char*) &opt, sizeof (int))) == -1)\n    );\n}\n\"\n    ZMQ_HAVE_SO_PRIORITY)\nendmacro()\n"
  },
  {
    "path": "builds/cmake/Modules/ZMQSupportMacros.cmake",
    "content": "macro (zmq_set_with_default var value)\n  if (NOT ${var})\n    set(${var} \"${value}\")\n  endif ()\nendmacro ()\n"
  },
  {
    "path": "builds/cmake/NSIS.template32.in",
    "content": "; CPack install script designed for a nmake build\n\n;--------------------------------\n; You must define these values\n\n  !define VERSION \"@CPACK_PACKAGE_VERSION@\"\n  !define PATCH  \"@CPACK_PACKAGE_VERSION_PATCH@\"\n  !define INST_DIR \"@CPACK_TEMPORARY_DIRECTORY@\"\n\n;--------------------------------\n;Variables\n\n  Var MUI_TEMP\n  Var STARTMENU_FOLDER\n  Var SV_ALLUSERS\n  Var START_MENU\n  Var DO_NOT_ADD_TO_PATH\n  Var ADD_TO_PATH_ALL_USERS\n  Var ADD_TO_PATH_CURRENT_USER\n  Var INSTALL_DESKTOP\n  Var IS_DEFAULT_INSTALLDIR\n;--------------------------------\n;Include Modern UI\n\n  !include \"MUI.nsh\"\n\n  ;Default installation folder\n  InstallDir \"$PROGRAMFILES\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\n  ;InstallDir \"$PROGRAMFILES64\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\n\n;--------------------------------\n;General\n\n  ;Name and file\n  Name \"@CPACK_NSIS_PACKAGE_NAME@\"\n  OutFile \"@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@\"\n\n  ;Set compression\n  SetCompressor @CPACK_NSIS_COMPRESSOR@\n\n@CPACK_NSIS_DEFINES@   \n\n  !include Sections.nsh\n\n;--- Component support macros: ---\n; The code for the add/remove functionality is from:\n;   http://nsis.sourceforge.net/Add/Remove_Functionality\n; It has been modified slightly and extended to provide\n; inter-component dependencies.\nVar AR_SecFlags\nVar AR_RegFlags\n@CPACK_NSIS_SECTION_SELECTED_VARS@\n\n; Loads the \"selected\" flag for the section named SecName into the\n; variable VarName.\n!macro LoadSectionSelectedIntoVar SecName VarName\n SectionGetFlags ${${SecName}} $${VarName}\n IntOp $${VarName} $${VarName} & ${SF_SELECTED}  ;Turn off all other bits\n!macroend\n\n; Loads the value of a variable... can we get around this?\n!macro LoadVar VarName\n  IntOp $R0 0 + $${VarName}\n!macroend\n\n; Sets the value of a variable\n!macro StoreVar VarName IntValue\n  IntOp $${VarName} 0 + ${IntValue}\n!macroend\n\n!macro InitSection SecName\n  ;  This macro reads component installed flag from the registry and\n  ;changes checked state of the section on the components page.\n  ;Input: section index constant name specified in Section command.\n   \n  ClearErrors\n  ;Reading component status from registry\n  ReadRegDWORD $AR_RegFlags HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@\\Components\\${SecName}\" \"Installed\"\n  IfErrors \"default_${SecName}\"\n    ;Status will stay default if registry value not found\n    ;(component was never installed)\n  IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits\n  SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading default section flags\n  IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE  ;Turn lowest (enabled) bit off\n  IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags      ;Change lowest bit\n\n  ; Note whether this component was installed before\n  !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags\n  IntOp $R0 $AR_RegFlags & $AR_RegFlags\n  \n  ;Writing modified flags\n  SectionSetFlags ${${SecName}} $AR_SecFlags\n  \n \"default_${SecName}:\"\n !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected\n!macroend\n \n!macro FinishSection SecName\n  ;  This macro reads section flag set by user and removes the section\n  ;if it is not selected.\n  ;Then it writes component installed flag to registry\n  ;Input: section index constant name specified in Section command.\n \n  SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading section flags\n  ;Checking lowest bit:\n  IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED}\n  IntCmp $AR_SecFlags 1 \"leave_${SecName}\"\n    ;Section is not selected:\n    ;Calling Section uninstall macro and writing zero installed flag\n    !insertmacro \"Remove_${${SecName}}\"\n    WriteRegDWORD HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@\\Components\\${SecName}\" \\\n  \"Installed\" 0\n    Goto \"exit_${SecName}\"\n \n \"leave_${SecName}:\"\n    ;Section is selected:\n    WriteRegDWORD HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@\\Components\\${SecName}\" \\\n  \"Installed\" 1\n \n \"exit_${SecName}:\"\n!macroend\n \n!macro RemoveSection_CPack SecName\n  ;  This macro is used to call section's Remove_... macro\n  ;from the uninstaller.\n  ;Input: section index constant name specified in Section command.\n \n  !insertmacro \"Remove_${${SecName}}\"\n!macroend\n\n; Determine whether the selection of SecName changed\n!macro MaybeSelectionChanged SecName\n  !insertmacro LoadVar ${SecName}_selected\n  SectionGetFlags ${${SecName}} $R1\n  IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits\n  \n  ; See if the status has changed:\n  IntCmp $R0 $R1 \"${SecName}_unchanged\"\n  !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected\n  \n  IntCmp $R1 ${SF_SELECTED} \"${SecName}_was_selected\"\n  !insertmacro \"Deselect_required_by_${SecName}\"\n  goto \"${SecName}_unchanged\"\n  \n  \"${SecName}_was_selected:\"\n  !insertmacro \"Select_${SecName}_depends\"\n  \n  \"${SecName}_unchanged:\"\n!macroend\n;--- End of Add/Remove macros ---\n\n;--------------------------------\n;Interface Settings\n\n  !define MUI_HEADERIMAGE\n  !define MUI_ABORTWARNING\n    \n;--------------------------------\n; path functions\n\n!verbose 3\n!include \"WinMessages.NSH\"\n!verbose 4\n\n;----------------------------------------\n; based upon a script of \"Written by KiCHiK 2003-01-18 05:57:02\"\n;----------------------------------------\n!verbose 3\n!include \"WinMessages.NSH\"\n!verbose 4\n;====================================================\n; get_NT_environment \n;     Returns: the selected environment\n;     Output : head of the stack\n;====================================================\n!macro select_NT_profile UN\nFunction ${UN}select_NT_profile\n   StrCmp $ADD_TO_PATH_ALL_USERS \"1\" 0 environment_single\n      DetailPrint \"Selected environment for all users\"\n      Push \"all\"\n      Return\n   environment_single:\n      DetailPrint \"Selected environment for current user only.\"\n      Push \"current\"\n      Return\nFunctionEnd\n!macroend\n!insertmacro select_NT_profile \"\"\n!insertmacro select_NT_profile \"un.\"\n;----------------------------------------------------\n!define NT_current_env 'HKCU \"Environment\"'\n!define NT_all_env     'HKLM \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\"'\n\n!ifndef WriteEnvStr_RegKey\n  !ifdef ALL_USERS\n    !define WriteEnvStr_RegKey \\\n       'HKLM \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\"'\n  !else\n    !define WriteEnvStr_RegKey 'HKCU \"Environment\"'\n  !endif\n!endif\n \n; AddToPath - Adds the given dir to the search path.\n;        Input - head of the stack\n;        Note - Win9x systems requires reboot\n \nFunction AddToPath\n  Exch $0\n  Push $1\n  Push $2\n  Push $3\n \n  # don't add if the path doesn't exist\n  IfFileExists \"$0\\*.*\" \"\" AddToPath_done\n \n  ReadEnvStr $1 PATH\n  ; if the path is too long for a NSIS variable NSIS will return a 0 \n  ; length string.  If we find that, then warn and skip any path\n  ; modification as it will trash the existing path.\n  StrLen $2 $1\n  IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done\n    CheckPathLength_ShowPathWarning:\n    Messagebox MB_OK|MB_ICONEXCLAMATION \"Warning! PATH too long installer unable to modify PATH!\"\n    Goto AddToPath_done\n  CheckPathLength_Done:\n  Push \"$1;\"\n  Push \"$0;\"\n  Call StrStr\n  Pop $2\n  StrCmp $2 \"\" \"\" AddToPath_done\n  Push \"$1;\"\n  Push \"$0\\;\"\n  Call StrStr\n  Pop $2\n  StrCmp $2 \"\" \"\" AddToPath_done\n  GetFullPathName /SHORT $3 $0\n  Push \"$1;\"\n  Push \"$3;\"\n  Call StrStr\n  Pop $2\n  StrCmp $2 \"\" \"\" AddToPath_done\n  Push \"$1;\"\n  Push \"$3\\;\"\n  Call StrStr\n  Pop $2\n  StrCmp $2 \"\" \"\" AddToPath_done\n \n  Call IsNT\n  Pop $1\n  StrCmp $1 1 AddToPath_NT\n    ; Not on NT\n    StrCpy $1 $WINDIR 2\n    FileOpen $1 \"$1\\autoexec.bat\" a\n    FileSeek $1 -1 END\n    FileReadByte $1 $2\n    IntCmp $2 26 0 +2 +2 # DOS EOF\n      FileSeek $1 -1 END # write over EOF\n    FileWrite $1 \"$\\r$\\nSET PATH=%PATH%;$3$\\r$\\n\"\n    FileClose $1\n    SetRebootFlag true\n    Goto AddToPath_done\n \n  AddToPath_NT:\n    StrCmp $ADD_TO_PATH_ALL_USERS \"1\" ReadAllKey\n      ReadRegStr $1 ${NT_current_env} \"PATH\"\n      Goto DoTrim\n    ReadAllKey:\n      ReadRegStr $1 ${NT_all_env} \"PATH\"\n    DoTrim:\n    StrCmp $1 \"\" AddToPath_NTdoIt\n      Push $1\n      Call Trim\n      Pop $1\n      StrCpy $0 \"$1;$0\"\n    AddToPath_NTdoIt:\n      StrCmp $ADD_TO_PATH_ALL_USERS \"1\" WriteAllKey\n        WriteRegExpandStr ${NT_current_env} \"PATH\" $0\n        Goto DoSend\n      WriteAllKey:\n        WriteRegExpandStr ${NT_all_env} \"PATH\" $0\n      DoSend:\n      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 \"STR:Environment\" /TIMEOUT=5000\n \n  AddToPath_done:\n    Pop $3\n    Pop $2\n    Pop $1\n    Pop $0\nFunctionEnd\n\n \n; RemoveFromPath - Remove a given dir from the path\n;     Input: head of the stack\n \nFunction un.RemoveFromPath\n  Exch $0\n  Push $1\n  Push $2\n  Push $3\n  Push $4\n  Push $5\n  Push $6\n \n  IntFmt $6 \"%c\" 26 # DOS EOF\n \n  Call un.IsNT\n  Pop $1\n  StrCmp $1 1 unRemoveFromPath_NT\n    ; Not on NT\n    StrCpy $1 $WINDIR 2\n    FileOpen $1 \"$1\\autoexec.bat\" r\n    GetTempFileName $4\n    FileOpen $2 $4 w\n    GetFullPathName /SHORT $0 $0\n    StrCpy $0 \"SET PATH=%PATH%;$0\"\n    Goto unRemoveFromPath_dosLoop\n \n    unRemoveFromPath_dosLoop:\n      FileRead $1 $3\n      StrCpy $5 $3 1 -1 # read last char\n      StrCmp $5 $6 0 +2 # if DOS EOF\n        StrCpy $3 $3 -1 # remove DOS EOF so we can compare\n      StrCmp $3 \"$0$\\r$\\n\" unRemoveFromPath_dosLoopRemoveLine\n      StrCmp $3 \"$0$\\n\" unRemoveFromPath_dosLoopRemoveLine\n      StrCmp $3 \"$0\" unRemoveFromPath_dosLoopRemoveLine\n      StrCmp $3 \"\" unRemoveFromPath_dosLoopEnd\n      FileWrite $2 $3\n      Goto unRemoveFromPath_dosLoop\n      unRemoveFromPath_dosLoopRemoveLine:\n        SetRebootFlag true\n        Goto unRemoveFromPath_dosLoop\n \n    unRemoveFromPath_dosLoopEnd:\n      FileClose $2\n      FileClose $1\n      StrCpy $1 $WINDIR 2\n      Delete \"$1\\autoexec.bat\"\n      CopyFiles /SILENT $4 \"$1\\autoexec.bat\"\n      Delete $4\n      Goto unRemoveFromPath_done\n \n  unRemoveFromPath_NT:\n    StrCmp $ADD_TO_PATH_ALL_USERS \"1\" unReadAllKey\n      ReadRegStr $1 ${NT_current_env} \"PATH\"\n      Goto unDoTrim\n    unReadAllKey:\n      ReadRegStr $1 ${NT_all_env} \"PATH\"\n    unDoTrim:\n    StrCpy $5 $1 1 -1 # copy last char\n    StrCmp $5 \";\" +2 # if last char != ;\n      StrCpy $1 \"$1;\" # append ;\n    Push $1\n    Push \"$0;\"\n    Call un.StrStr ; Find `$0;` in $1\n    Pop $2 ; pos of our dir\n    StrCmp $2 \"\" unRemoveFromPath_done\n      ; else, it is in path\n      # $0 - path to add\n      # $1 - path var\n      StrLen $3 \"$0;\"\n      StrLen $4 $2\n      StrCpy $5 $1 -$4 # $5 is now the part before the path to remove\n      StrCpy $6 $2 \"\" $3 # $6 is now the part after the path to remove\n      StrCpy $3 $5$6\n \n      StrCpy $5 $3 1 -1 # copy last char\n      StrCmp $5 \";\" 0 +2 # if last char == ;\n        StrCpy $3 $3 -1 # remove last char\n \n      StrCmp $ADD_TO_PATH_ALL_USERS \"1\" unWriteAllKey\n        WriteRegExpandStr ${NT_current_env} \"PATH\" $3\n        Goto unDoSend\n      unWriteAllKey:\n        WriteRegExpandStr ${NT_all_env} \"PATH\" $3\n      unDoSend:\n      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 \"STR:Environment\" /TIMEOUT=5000\n \n  unRemoveFromPath_done:\n    Pop $6\n    Pop $5\n    Pop $4\n    Pop $3\n    Pop $2\n    Pop $1\n    Pop $0\nFunctionEnd\n \n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; Uninstall sutff\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n###########################################\n#            Utility Functions            #\n###########################################\n \n;====================================================\n; IsNT - Returns 1 if the current system is NT, 0\n;        otherwise.\n;     Output: head of the stack\n;====================================================\n; IsNT\n; no input\n; output, top of the stack = 1 if NT or 0 if not\n;\n; Usage:\n;   Call IsNT\n;   Pop $R0\n;  ($R0 at this point is 1 or 0)\n \n!macro IsNT un\nFunction ${un}IsNT\n  Push $0\n  ReadRegStr $0 HKLM \"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\" CurrentVersion\n  StrCmp $0 \"\" 0 IsNT_yes\n  ; we are not NT.\n  Pop $0\n  Push 0\n  Return\n \n  IsNT_yes:\n    ; NT!!!\n    Pop $0\n    Push 1\nFunctionEnd\n!macroend\n!insertmacro IsNT \"\"\n!insertmacro IsNT \"un.\"\n \n; StrStr\n; input, top of stack = string to search for\n;        top of stack-1 = string to search in\n; output, top of stack (replaces with the portion of the string remaining)\n; modifies no other variables.\n;\n; Usage:\n;   Push \"this is a long ass string\"\n;   Push \"ass\"\n;   Call StrStr\n;   Pop $R0\n;  ($R0 at this point is \"ass string\")\n \n!macro StrStr un\nFunction ${un}StrStr\nExch $R1 ; st=haystack,old$R1, $R1=needle\n  Exch    ; st=old$R1,haystack\n  Exch $R2 ; st=old$R1,old$R2, $R2=haystack\n  Push $R3\n  Push $R4\n  Push $R5\n  StrLen $R3 $R1\n  StrCpy $R4 0\n  ; $R1=needle\n  ; $R2=haystack\n  ; $R3=len(needle)\n  ; $R4=cnt\n  ; $R5=tmp\n  loop:\n    StrCpy $R5 $R2 $R3 $R4\n    StrCmp $R5 $R1 done\n    StrCmp $R5 \"\" done\n    IntOp $R4 $R4 + 1\n    Goto loop\ndone:\n  StrCpy $R1 $R2 \"\" $R4\n  Pop $R5\n  Pop $R4\n  Pop $R3\n  Pop $R2\n  Exch $R1\nFunctionEnd\n!macroend\n!insertmacro StrStr \"\"\n!insertmacro StrStr \"un.\"\n\nFunction Trim ; Added by Pelaca\n\tExch $R1\n\tPush $R2\nLoop:\n\tStrCpy $R2 \"$R1\" 1 -1\n\tStrCmp \"$R2\" \" \" RTrim\n\tStrCmp \"$R2\" \"$\\n\" RTrim\n\tStrCmp \"$R2\" \"$\\r\" RTrim\n\tStrCmp \"$R2\" \";\" RTrim\n\tGoTo Done\nRTrim:\t\n\tStrCpy $R1 \"$R1\" -1\n\tGoto Loop\nDone:\n\tPop $R2\n\tExch $R1\nFunctionEnd\n\nFunction ConditionalAddToRegisty\n  Pop $0\n  Pop $1\n  StrCmp \"$0\" \"\" ConditionalAddToRegisty_EmptyString\n    WriteRegStr SHCTX \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@\" \\\n    \"$1\" \"$0\"\n    ;MessageBox MB_OK \"Set Registry: '$1' to '$0'\"\n    DetailPrint \"Set install registry entry: '$1' to '$0'\"\n  ConditionalAddToRegisty_EmptyString:\nFunctionEnd\n\n;--------------------------------\n\n!ifdef CPACK_USES_DOWNLOAD\nFunction DownloadFile\n    IfFileExists $INSTDIR\\* +2\n    CreateDirectory $INSTDIR\n    Pop $0\n\n    ; Skip if already downloaded\n    IfFileExists $INSTDIR\\$0 0 +2\n    Return\n\n    StrCpy $1 \"@CPACK_DOWNLOAD_SITE@\"\n\n  try_again:\n    NSISdl::download \"$1/$0\" \"$INSTDIR\\$0\"\n    \n    Pop $1\n    StrCmp $1 \"success\" success\n    StrCmp $1 \"Cancelled\" cancel\n    MessageBox MB_OK \"Download failed: $1\"\n  cancel:\n    Return\n  success:\nFunctionEnd\n!endif\n\n;--------------------------------\n; Installation types\n@CPACK_NSIS_INSTALLATION_TYPES@\n\n;--------------------------------\n; Component sections\n@CPACK_NSIS_COMPONENT_SECTIONS@\n\n;--------------------------------\n; Define some macro setting for the gui\n@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@\n@CPACK_NSIS_INSTALLER_ICON_CODE@\n@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@\n\n;--------------------------------\n;Pages\n  !insertmacro MUI_PAGE_WELCOME\n\n  !insertmacro MUI_PAGE_LICENSE \"@CPACK_RESOURCE_FILE_LICENSE@\"\n  Page custom InstallOptionsPage\n  !insertmacro MUI_PAGE_DIRECTORY\n  \n  ;Start Menu Folder Page Configuration\n  !define MUI_STARTMENUPAGE_REGISTRY_ROOT \"SHCTX\" \n  !define MUI_STARTMENUPAGE_REGISTRY_KEY \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \n  !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME \"Start Menu Folder\"\n  !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER\n\n  !define MUI_FINISHPAGE_SHOWREADME \"$INSTDIR\\NEWS.txt\"\n\n  @CPACK_NSIS_PAGE_COMPONENTS@\n\n  !insertmacro MUI_PAGE_INSTFILES\n  !insertmacro MUI_PAGE_FINISH\n\n  !insertmacro MUI_UNPAGE_CONFIRM\n  !insertmacro MUI_UNPAGE_INSTFILES\n  !insertmacro MUI_UNPAGE_FINISH\n\n;--------------------------------\n;Languages\n\n  !insertmacro MUI_LANGUAGE \"English\" ;first language is the default language\n  !insertmacro MUI_LANGUAGE \"Albanian\"\n  !insertmacro MUI_LANGUAGE \"Arabic\"\n  !insertmacro MUI_LANGUAGE \"Basque\"\n  !insertmacro MUI_LANGUAGE \"Belarusian\"\n  !insertmacro MUI_LANGUAGE \"Bosnian\"\n  !insertmacro MUI_LANGUAGE \"Breton\"\n  !insertmacro MUI_LANGUAGE \"Bulgarian\"\n  !insertmacro MUI_LANGUAGE \"Croatian\"\n  !insertmacro MUI_LANGUAGE \"Czech\"\n  !insertmacro MUI_LANGUAGE \"Danish\"\n  !insertmacro MUI_LANGUAGE \"Dutch\"\n  !insertmacro MUI_LANGUAGE \"Estonian\"\n  !insertmacro MUI_LANGUAGE \"Farsi\"\n  !insertmacro MUI_LANGUAGE \"Finnish\"\n  !insertmacro MUI_LANGUAGE \"French\"\n  !insertmacro MUI_LANGUAGE \"German\"\n  !insertmacro MUI_LANGUAGE \"Greek\"\n  !insertmacro MUI_LANGUAGE \"Hebrew\"\n  !insertmacro MUI_LANGUAGE \"Hungarian\"\n  !insertmacro MUI_LANGUAGE \"Icelandic\"\n  !insertmacro MUI_LANGUAGE \"Indonesian\"\n  !insertmacro MUI_LANGUAGE \"Irish\"\n  !insertmacro MUI_LANGUAGE \"Italian\"\n  !insertmacro MUI_LANGUAGE \"Japanese\"\n  !insertmacro MUI_LANGUAGE \"Korean\"\n  !insertmacro MUI_LANGUAGE \"Kurdish\"\n  !insertmacro MUI_LANGUAGE \"Latvian\"\n  !insertmacro MUI_LANGUAGE \"Lithuanian\"\n  !insertmacro MUI_LANGUAGE \"Luxembourgish\"\n  !insertmacro MUI_LANGUAGE \"Macedonian\"\n  !insertmacro MUI_LANGUAGE \"Malay\"\n  !insertmacro MUI_LANGUAGE \"Mongolian\"\n  !insertmacro MUI_LANGUAGE \"Norwegian\"\n  !insertmacro MUI_LANGUAGE \"Polish\"\n  !insertmacro MUI_LANGUAGE \"Portuguese\"\n  !insertmacro MUI_LANGUAGE \"PortugueseBR\"\n  !insertmacro MUI_LANGUAGE \"Romanian\"\n  !insertmacro MUI_LANGUAGE \"Russian\"\n  !insertmacro MUI_LANGUAGE \"Serbian\"\n  !insertmacro MUI_LANGUAGE \"SerbianLatin\"\n  !insertmacro MUI_LANGUAGE \"SimpChinese\"\n  !insertmacro MUI_LANGUAGE \"Slovak\"\n  !insertmacro MUI_LANGUAGE \"Slovenian\"\n  !insertmacro MUI_LANGUAGE \"Spanish\"\n  !insertmacro MUI_LANGUAGE \"Swedish\"\n  !insertmacro MUI_LANGUAGE \"Thai\"\n  !insertmacro MUI_LANGUAGE \"TradChinese\"\n  !insertmacro MUI_LANGUAGE \"Turkish\"\n  !insertmacro MUI_LANGUAGE \"Ukrainian\"\n  !insertmacro MUI_LANGUAGE \"Welsh\"\n\n\n;--------------------------------\n;Reserve Files\n\n  ;These files should be inserted before other files in the data block\n  ;Keep these lines before any File command\n  ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA)\n\n  ReserveFile \"NSIS.InstallOptions.ini\"\n  !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS\n\n;--------------------------------\n;Installer Sections\n\nSection \"-Core installation\"\n  ;Use the entire tree produced by the INSTALL target.  Keep the\n  ;list of directories here in sync with the RMDir commands below.\n  SetOutPath \"$INSTDIR\"\n  @CPACK_NSIS_FULL_INSTALL@\n  \n  ;Store installation folder\n  WriteRegStr SHCTX \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \"\" $INSTDIR\n  \n  ;Create uninstaller\n  WriteUninstaller \"$INSTDIR\\Uninstall.exe\"\n  Push \"DisplayName\"\n  Push \"@CPACK_NSIS_DISPLAY_NAME@\"\n  Call ConditionalAddToRegisty\n  Push \"DisplayVersion\"\n  Push \"@CPACK_PACKAGE_VERSION@\"\n  Call ConditionalAddToRegisty\n  Push \"Publisher\"\n  Push \"@CPACK_PACKAGE_VENDOR@\"\n  Call ConditionalAddToRegisty\n  Push \"UninstallString\"\n  Push \"$INSTDIR\\Uninstall.exe\"\n  Call ConditionalAddToRegisty\n  Push \"NoRepair\"\n  Push \"1\"\n  Call ConditionalAddToRegisty\n  \n  !ifdef CPACK_NSIS_ADD_REMOVE\n  ;Create add/remove functionality\n  Push \"ModifyPath\"\n  Push \"$INSTDIR\\AddRemove.exe\"\n  Call ConditionalAddToRegisty\n  !else\n  Push \"NoModify\"\n  Push \"1\"\n  Call ConditionalAddToRegisty\n  !endif\n  \n  ; Optional registration\n  Push \"DisplayIcon\"\n  Push \"$INSTDIR\\@CPACK_NSIS_INSTALLED_ICON_NAME@\"\n  Call ConditionalAddToRegisty\n  Push \"HelpLink\"\n  Push \"@CPACK_NSIS_HELP_LINK@\"\n  Call ConditionalAddToRegisty\n  Push \"URLInfoAbout\"\n  Push \"@CPACK_NSIS_URL_INFO_ABOUT@\"\n  Call ConditionalAddToRegisty\n  Push \"Contact\"\n  Push \"@CPACK_NSIS_CONTACT@\"\n  Call ConditionalAddToRegisty\n  !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP \"NSIS.InstallOptions.ini\" \"Field 5\" \"State\"\n  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\n  \n  ;Create shortcuts\n  CreateDirectory \"$SMPROGRAMS\\$STARTMENU_FOLDER\"\n@CPACK_NSIS_CREATE_ICONS@\n@CPACK_NSIS_CREATE_ICONS_EXTRA@\n  CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\Uninstall.lnk\" \"$INSTDIR\\Uninstall.exe\"\n\n  ;Read a value from an InstallOptions INI file\n  !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH \"NSIS.InstallOptions.ini\" \"Field 2\" \"State\"\n  !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS \"NSIS.InstallOptions.ini\" \"Field 3\" \"State\"\n  !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER \"NSIS.InstallOptions.ini\" \"Field 4\" \"State\"\n\n  ; Write special uninstall registry entries\n  Push \"StartMenu\"\n  Push \"$STARTMENU_FOLDER\"\n  Call ConditionalAddToRegisty\n  Push \"DoNotAddToPath\"\n  Push \"$DO_NOT_ADD_TO_PATH\"\n  Call ConditionalAddToRegisty\n  Push \"AddToPathAllUsers\"\n  Push \"$ADD_TO_PATH_ALL_USERS\"\n  Call ConditionalAddToRegisty\n  Push \"AddToPathCurrentUser\"\n  Push \"$ADD_TO_PATH_CURRENT_USER\"\n  Call ConditionalAddToRegisty\n  Push \"InstallToDesktop\"\n  Push \"$INSTALL_DESKTOP\"\n  Call ConditionalAddToRegisty\n\n  !insertmacro MUI_STARTMENU_WRITE_END\n\n@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@\n\nSectionEnd\n\nSection \"-Add to path\"\n  Push $INSTDIR\\bin\n  StrCmp \"@CPACK_NSIS_MODIFY_PATH@\" \"ON\" 0 doNotAddToPath\n  StrCmp $DO_NOT_ADD_TO_PATH \"1\" doNotAddToPath 0  \n    Call AddToPath\n  doNotAddToPath:\nSectionEnd\n\n;--------------------------------\n; Create custom pages\nFunction InstallOptionsPage\n  !insertmacro MUI_HEADER_TEXT \"Install Options\" \"Choose options for installing @CPACK_NSIS_PACKAGE_NAME@\"\n  !insertmacro MUI_INSTALLOPTIONS_DISPLAY \"NSIS.InstallOptions.ini\"\n\nFunctionEnd\n\n;--------------------------------\n; determine admin versus local install\nFunction un.onInit\n\n  ClearErrors\n  UserInfo::GetName\n  IfErrors noLM\n  Pop $0\n  UserInfo::GetAccountType\n  Pop $1\n  StrCmp $1 \"Admin\" 0 +3\n    SetShellVarContext all\n    ;MessageBox MB_OK 'User \"$0\" is in the Admin group'\n    Goto done\n  StrCmp $1 \"Power\" 0 +3\n    SetShellVarContext all\n    ;MessageBox MB_OK 'User \"$0\" is in the Power Users group'\n    Goto done\n    \n  noLM:\n    ;Get installation folder from registry if available\n\n  done:\n    \nFunctionEnd\n\n;--- Add/Remove callback functions: ---\n!macro SectionList MacroName\n  ;This macro used to perform operation on multiple sections.\n  ;List all of your components in following manner here.\n@CPACK_NSIS_COMPONENT_SECTION_LIST@\n!macroend\n \nSection -FinishComponents\n  ;Removes unselected components and writes component status to registry\n  !insertmacro SectionList \"FinishSection\"\n  \n!ifdef CPACK_NSIS_ADD_REMOVE  \n  ; Get the name of the installer executable\n  System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1'\n  StrCpy $R3 $R0\n  \n  ; Strip off the last 13 characters, to see if we have AddRemove.exe\n  StrLen $R1 $R0\n  IntOp $R1 $R0 - 13\n  StrCpy $R2 $R0 13 $R1\n  StrCmp $R2 \"AddRemove.exe\" addremove_installed\n  \n  ; We're not running AddRemove.exe, so install it\n  CopyFiles $R3 $INSTDIR\\AddRemove.exe\n  \n  addremove_installed:\n!endif\nSectionEnd\n;--- End of Add/Remove callback functions ---\n\n;--------------------------------\n; Component dependencies\nFunction .onSelChange\n  !insertmacro SectionList MaybeSelectionChanged\nFunctionEnd\n\n;--------------------------------\n;Uninstaller Section\n\nSection \"Uninstall\"\n  ReadRegStr $START_MENU SHCTX \\\n   \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@\" \"StartMenu\"\n  ;MessageBox MB_OK \"Start menu is in: $START_MENU\"\n  ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \\\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@\" \"DoNotAddToPath\"\n  ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \\\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@\" \"AddToPathAllUsers\"\n  ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \\\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@\" \"AddToPathCurrentUser\"\n  ;MessageBox MB_OK \"Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS\"\n  ReadRegStr $INSTALL_DESKTOP SHCTX \\\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@\" \"InstallToDesktop\"\n  ;MessageBox MB_OK \"Install to desktop: $INSTALL_DESKTOP \"\n\n@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@\n\n  ;Remove files we installed.\n  ;Keep the list of directories here in sync with the File commands above.\n@CPACK_NSIS_DELETE_FILES@\n@CPACK_NSIS_DELETE_DIRECTORIES@\n\n!ifdef CPACK_NSIS_ADD_REMOVE  \n  ;Remove the add/remove program\n  Delete \"$INSTDIR\\AddRemove.exe\"\n!endif\n\n  ;Remove the uninstaller itself.\n  Delete \"$INSTDIR\\Uninstall.exe\"\n  DeleteRegKey SHCTX \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@\"\n\n  ;Remove the installation directory if it is empty.\n  RMDir \"$INSTDIR\"\n\n  ; Remove the registry entries.\n  DeleteRegKey SHCTX \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\"\n\n  ; Removes all optional components\n  !insertmacro SectionList \"RemoveSection_CPack\"\n  \n  !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP\n    \n  Delete \"$SMPROGRAMS\\$MUI_TEMP\\Uninstall.lnk\"\n@CPACK_NSIS_DELETE_ICONS@\n@CPACK_NSIS_DELETE_ICONS_EXTRA@\n  \n  ;Delete empty start menu parent directories\n  StrCpy $MUI_TEMP \"$SMPROGRAMS\\$MUI_TEMP\"\n \n  startMenuDeleteLoop:\n    ClearErrors\n    RMDir $MUI_TEMP\n    GetFullPathName $MUI_TEMP \"$MUI_TEMP\\..\"\n    \n    IfErrors startMenuDeleteLoopDone\n  \n    StrCmp \"$MUI_TEMP\" \"$SMPROGRAMS\" startMenuDeleteLoopDone startMenuDeleteLoop\n  startMenuDeleteLoopDone:\n\n  ; If the user changed the shortcut, then untinstall may not work. This should\n  ; try to fix it.\n  StrCpy $MUI_TEMP \"$START_MENU\"\n  Delete \"$SMPROGRAMS\\$MUI_TEMP\\Uninstall.lnk\"\n@CPACK_NSIS_DELETE_ICONS_EXTRA@\n  \n  ;Delete empty start menu parent directories\n  StrCpy $MUI_TEMP \"$SMPROGRAMS\\$MUI_TEMP\"\n \n  secondStartMenuDeleteLoop:\n    ClearErrors\n    RMDir $MUI_TEMP\n    GetFullPathName $MUI_TEMP \"$MUI_TEMP\\..\"\n    \n    IfErrors secondStartMenuDeleteLoopDone\n  \n    StrCmp \"$MUI_TEMP\" \"$SMPROGRAMS\" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop\n  secondStartMenuDeleteLoopDone:\n\n  DeleteRegKey /ifempty SHCTX \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\"\n\n  Push $INSTDIR\\bin\n  StrCmp $DO_NOT_ADD_TO_PATH_ \"1\" doNotRemoveFromPath 0\n    Call un.RemoveFromPath\n  doNotRemoveFromPath:\nSectionEnd\n\n;--------------------------------\n; determine admin versus local install\n; Is install for \"AllUsers\" or \"JustMe\"?\n; Default to \"JustMe\" - set to \"AllUsers\" if admin or on Win9x\n; This function is used for the very first \"custom page\" of the installer.\n; This custom page does not show up visibly, but it executes prior to the\n; first visible page and sets up $INSTDIR properly...\n; Choose different default installation folder based on SV_ALLUSERS...\n; \"Program Files\" for AllUsers, \"My Documents\" for JustMe...\n\nFunction .onInit\n  ; Reads components status for registry\n  !insertmacro SectionList \"InitSection\"\n\n  ; check to see if /D has been used to change \n  ; the install directory by comparing it to the \n  ; install directory that is expected to be the\n  ; default\n  StrCpy $IS_DEFAULT_INSTALLDIR 0\n  StrCmp \"$INSTDIR\" \"$PROGRAMFILES\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\" 0 +2\n    StrCpy $IS_DEFAULT_INSTALLDIR 1\n  \n  StrCpy $SV_ALLUSERS \"JustMe\"\n  ; if default install dir then change the default\n  ; if it is installed for JustMe\n  StrCmp \"$IS_DEFAULT_INSTALLDIR\" \"1\" 0 +2\n    StrCpy $INSTDIR \"$DOCUMENTS\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\n\n  ClearErrors\n  UserInfo::GetName\n  IfErrors noLM\n  Pop $0\n  UserInfo::GetAccountType\n  Pop $1\n  StrCmp $1 \"Admin\" 0 +3\n    SetShellVarContext all\n    ;MessageBox MB_OK 'User \"$0\" is in the Admin group'\n    StrCpy $SV_ALLUSERS \"AllUsers\"\n    Goto done\n  StrCmp $1 \"Power\" 0 +3\n    SetShellVarContext all\n    ;MessageBox MB_OK 'User \"$0\" is in the Power Users group'\n    StrCpy $SV_ALLUSERS \"AllUsers\"\n    Goto done\n    \n  noLM:\n    StrCpy $SV_ALLUSERS \"AllUsers\"\n    ;Get installation folder from registry if available\n\n  done:\n  StrCmp $SV_ALLUSERS \"AllUsers\" 0 +3\n    StrCmp \"$IS_DEFAULT_INSTALLDIR\" \"1\" 0 +2\n      StrCpy $INSTDIR \"$PROGRAMFILES\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\n\n  StrCmp \"@CPACK_NSIS_MODIFY_PATH@\" \"ON\" 0 noOptionsPage\n    !insertmacro MUI_INSTALLOPTIONS_EXTRACT \"NSIS.InstallOptions.ini\"\n\n  noOptionsPage:\nFunctionEnd\n"
  },
  {
    "path": "builds/cmake/NSIS.template64.in",
    "content": "; CPack install script designed for a nmake build\n\n;--------------------------------\n; You must define these values\n\n  !define VERSION \"@CPACK_PACKAGE_VERSION@\"\n  !define PATCH  \"@CPACK_PACKAGE_VERSION_PATCH@\"\n  !define INST_DIR \"@CPACK_TEMPORARY_DIRECTORY@\"\n\n;--------------------------------\n;Variables\n\n  Var MUI_TEMP\n  Var STARTMENU_FOLDER\n  Var SV_ALLUSERS\n  Var START_MENU\n  Var DO_NOT_ADD_TO_PATH\n  Var ADD_TO_PATH_ALL_USERS\n  Var ADD_TO_PATH_CURRENT_USER\n  Var INSTALL_DESKTOP\n  Var IS_DEFAULT_INSTALLDIR\n;--------------------------------\n;Include Modern UI\n\n  !include \"MUI.nsh\"\n\n  ;Default installation folder\n  ;InstallDir \"$PROGRAMFILES\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\n  InstallDir \"$PROGRAMFILES64\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\n\n;--------------------------------\n;General\n\n  ;Name and file\n  Name \"@CPACK_NSIS_PACKAGE_NAME@\"\n  OutFile \"@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@\"\n\n  ;Set compression\n  SetCompressor @CPACK_NSIS_COMPRESSOR@\n\n@CPACK_NSIS_DEFINES@   \n\n  !include Sections.nsh\n\n;--- Component support macros: ---\n; The code for the add/remove functionality is from:\n;   http://nsis.sourceforge.net/Add/Remove_Functionality\n; It has been modified slightly and extended to provide\n; inter-component dependencies.\nVar AR_SecFlags\nVar AR_RegFlags\n@CPACK_NSIS_SECTION_SELECTED_VARS@\n\n; Loads the \"selected\" flag for the section named SecName into the\n; variable VarName.\n!macro LoadSectionSelectedIntoVar SecName VarName\n SectionGetFlags ${${SecName}} $${VarName}\n IntOp $${VarName} $${VarName} & ${SF_SELECTED}  ;Turn off all other bits\n!macroend\n\n; Loads the value of a variable... can we get around this?\n!macro LoadVar VarName\n  IntOp $R0 0 + $${VarName}\n!macroend\n\n; Sets the value of a variable\n!macro StoreVar VarName IntValue\n  IntOp $${VarName} 0 + ${IntValue}\n!macroend\n\n!macro InitSection SecName\n  ;  This macro reads component installed flag from the registry and\n  ;changes checked state of the section on the components page.\n  ;Input: section index constant name specified in Section command.\n   \n  ClearErrors\n  ;Reading component status from registry\n  ReadRegDWORD $AR_RegFlags HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@ (x64)\\Components\\${SecName}\" \"Installed\"\n  IfErrors \"default_${SecName}\"\n    ;Status will stay default if registry value not found\n    ;(component was never installed)\n  IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits\n  SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading default section flags\n  IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE  ;Turn lowest (enabled) bit off\n  IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags      ;Change lowest bit\n\n  ; Note whether this component was installed before\n  !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags\n  IntOp $R0 $AR_RegFlags & $AR_RegFlags\n  \n  ;Writing modified flags\n  SectionSetFlags ${${SecName}} $AR_SecFlags\n  \n \"default_${SecName}:\"\n !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected\n!macroend\n \n!macro FinishSection SecName\n  ;  This macro reads section flag set by user and removes the section\n  ;if it is not selected.\n  ;Then it writes component installed flag to registry\n  ;Input: section index constant name specified in Section command.\n \n  SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading section flags\n  ;Checking lowest bit:\n  IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED}\n  IntCmp $AR_SecFlags 1 \"leave_${SecName}\"\n    ;Section is not selected:\n    ;Calling Section uninstall macro and writing zero installed flag\n    !insertmacro \"Remove_${${SecName}}\"\n    WriteRegDWORD HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@ (x64)\\Components\\${SecName}\" \\\n  \"Installed\" 0\n    Goto \"exit_${SecName}\"\n \n \"leave_${SecName}:\"\n    ;Section is selected:\n    WriteRegDWORD HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@ (x64)\\Components\\${SecName}\" \\\n  \"Installed\" 1\n \n \"exit_${SecName}:\"\n!macroend\n \n!macro RemoveSection_CPack SecName\n  ;  This macro is used to call section's Remove_... macro\n  ;from the uninstaller.\n  ;Input: section index constant name specified in Section command.\n \n  !insertmacro \"Remove_${${SecName}}\"\n!macroend\n\n; Determine whether the selection of SecName changed\n!macro MaybeSelectionChanged SecName\n  !insertmacro LoadVar ${SecName}_selected\n  SectionGetFlags ${${SecName}} $R1\n  IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits\n  \n  ; See if the status has changed:\n  IntCmp $R0 $R1 \"${SecName}_unchanged\"\n  !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected\n  \n  IntCmp $R1 ${SF_SELECTED} \"${SecName}_was_selected\"\n  !insertmacro \"Deselect_required_by_${SecName}\"\n  goto \"${SecName}_unchanged\"\n  \n  \"${SecName}_was_selected:\"\n  !insertmacro \"Select_${SecName}_depends\"\n  \n  \"${SecName}_unchanged:\"\n!macroend\n;--- End of Add/Remove macros ---\n\n;--------------------------------\n;Interface Settings\n\n  !define MUI_HEADERIMAGE\n  !define MUI_ABORTWARNING\n    \n;--------------------------------\n; path functions\n\n!verbose 3\n!include \"WinMessages.NSH\"\n!verbose 4\n\n;----------------------------------------\n; based upon a script of \"Written by KiCHiK 2003-01-18 05:57:02\"\n;----------------------------------------\n!verbose 3\n!include \"WinMessages.NSH\"\n!verbose 4\n;====================================================\n; get_NT_environment \n;     Returns: the selected environment\n;     Output : head of the stack\n;====================================================\n!macro select_NT_profile UN\nFunction ${UN}select_NT_profile\n   StrCmp $ADD_TO_PATH_ALL_USERS \"1\" 0 environment_single\n      DetailPrint \"Selected environment for all users\"\n      Push \"all\"\n      Return\n   environment_single:\n      DetailPrint \"Selected environment for current user only.\"\n      Push \"current\"\n      Return\nFunctionEnd\n!macroend\n!insertmacro select_NT_profile \"\"\n!insertmacro select_NT_profile \"un.\"\n;----------------------------------------------------\n!define NT_current_env 'HKCU \"Environment\"'\n!define NT_all_env     'HKLM \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\"'\n\n!ifndef WriteEnvStr_RegKey\n  !ifdef ALL_USERS\n    !define WriteEnvStr_RegKey \\\n       'HKLM \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\"'\n  !else\n    !define WriteEnvStr_RegKey 'HKCU \"Environment\"'\n  !endif\n!endif\n \n; AddToPath - Adds the given dir to the search path.\n;        Input - head of the stack\n;        Note - Win9x systems requires reboot\n \nFunction AddToPath\n  Exch $0\n  Push $1\n  Push $2\n  Push $3\n \n  # don't add if the path doesn't exist\n  IfFileExists \"$0\\*.*\" \"\" AddToPath_done\n \n  ReadEnvStr $1 PATH\n  ; if the path is too long for a NSIS variable NSIS will return a 0 \n  ; length string.  If we find that, then warn and skip any path\n  ; modification as it will trash the existing path.\n  StrLen $2 $1\n  IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done\n    CheckPathLength_ShowPathWarning:\n    Messagebox MB_OK|MB_ICONEXCLAMATION \"Warning! PATH too long installer unable to modify PATH!\"\n    Goto AddToPath_done\n  CheckPathLength_Done:\n  Push \"$1;\"\n  Push \"$0;\"\n  Call StrStr\n  Pop $2\n  StrCmp $2 \"\" \"\" AddToPath_done\n  Push \"$1;\"\n  Push \"$0\\;\"\n  Call StrStr\n  Pop $2\n  StrCmp $2 \"\" \"\" AddToPath_done\n  GetFullPathName /SHORT $3 $0\n  Push \"$1;\"\n  Push \"$3;\"\n  Call StrStr\n  Pop $2\n  StrCmp $2 \"\" \"\" AddToPath_done\n  Push \"$1;\"\n  Push \"$3\\;\"\n  Call StrStr\n  Pop $2\n  StrCmp $2 \"\" \"\" AddToPath_done\n \n  Call IsNT\n  Pop $1\n  StrCmp $1 1 AddToPath_NT\n    ; Not on NT\n    StrCpy $1 $WINDIR 2\n    FileOpen $1 \"$1\\autoexec.bat\" a\n    FileSeek $1 -1 END\n    FileReadByte $1 $2\n    IntCmp $2 26 0 +2 +2 # DOS EOF\n      FileSeek $1 -1 END # write over EOF\n    FileWrite $1 \"$\\r$\\nSET PATH=%PATH%;$3$\\r$\\n\"\n    FileClose $1\n    SetRebootFlag true\n    Goto AddToPath_done\n \n  AddToPath_NT:\n    StrCmp $ADD_TO_PATH_ALL_USERS \"1\" ReadAllKey\n      ReadRegStr $1 ${NT_current_env} \"PATH\"\n      Goto DoTrim\n    ReadAllKey:\n      ReadRegStr $1 ${NT_all_env} \"PATH\"\n    DoTrim:\n    StrCmp $1 \"\" AddToPath_NTdoIt\n      Push $1\n      Call Trim\n      Pop $1\n      StrCpy $0 \"$1;$0\"\n    AddToPath_NTdoIt:\n      StrCmp $ADD_TO_PATH_ALL_USERS \"1\" WriteAllKey\n        WriteRegExpandStr ${NT_current_env} \"PATH\" $0\n        Goto DoSend\n      WriteAllKey:\n        WriteRegExpandStr ${NT_all_env} \"PATH\" $0\n      DoSend:\n      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 \"STR:Environment\" /TIMEOUT=5000\n \n  AddToPath_done:\n    Pop $3\n    Pop $2\n    Pop $1\n    Pop $0\nFunctionEnd\n\n \n; RemoveFromPath - Remove a given dir from the path\n;     Input: head of the stack\n \nFunction un.RemoveFromPath\n  Exch $0\n  Push $1\n  Push $2\n  Push $3\n  Push $4\n  Push $5\n  Push $6\n \n  IntFmt $6 \"%c\" 26 # DOS EOF\n \n  Call un.IsNT\n  Pop $1\n  StrCmp $1 1 unRemoveFromPath_NT\n    ; Not on NT\n    StrCpy $1 $WINDIR 2\n    FileOpen $1 \"$1\\autoexec.bat\" r\n    GetTempFileName $4\n    FileOpen $2 $4 w\n    GetFullPathName /SHORT $0 $0\n    StrCpy $0 \"SET PATH=%PATH%;$0\"\n    Goto unRemoveFromPath_dosLoop\n \n    unRemoveFromPath_dosLoop:\n      FileRead $1 $3\n      StrCpy $5 $3 1 -1 # read last char\n      StrCmp $5 $6 0 +2 # if DOS EOF\n        StrCpy $3 $3 -1 # remove DOS EOF so we can compare\n      StrCmp $3 \"$0$\\r$\\n\" unRemoveFromPath_dosLoopRemoveLine\n      StrCmp $3 \"$0$\\n\" unRemoveFromPath_dosLoopRemoveLine\n      StrCmp $3 \"$0\" unRemoveFromPath_dosLoopRemoveLine\n      StrCmp $3 \"\" unRemoveFromPath_dosLoopEnd\n      FileWrite $2 $3\n      Goto unRemoveFromPath_dosLoop\n      unRemoveFromPath_dosLoopRemoveLine:\n        SetRebootFlag true\n        Goto unRemoveFromPath_dosLoop\n \n    unRemoveFromPath_dosLoopEnd:\n      FileClose $2\n      FileClose $1\n      StrCpy $1 $WINDIR 2\n      Delete \"$1\\autoexec.bat\"\n      CopyFiles /SILENT $4 \"$1\\autoexec.bat\"\n      Delete $4\n      Goto unRemoveFromPath_done\n \n  unRemoveFromPath_NT:\n    StrCmp $ADD_TO_PATH_ALL_USERS \"1\" unReadAllKey\n      ReadRegStr $1 ${NT_current_env} \"PATH\"\n      Goto unDoTrim\n    unReadAllKey:\n      ReadRegStr $1 ${NT_all_env} \"PATH\"\n    unDoTrim:\n    StrCpy $5 $1 1 -1 # copy last char\n    StrCmp $5 \";\" +2 # if last char != ;\n      StrCpy $1 \"$1;\" # append ;\n    Push $1\n    Push \"$0;\"\n    Call un.StrStr ; Find `$0;` in $1\n    Pop $2 ; pos of our dir\n    StrCmp $2 \"\" unRemoveFromPath_done\n      ; else, it is in path\n      # $0 - path to add\n      # $1 - path var\n      StrLen $3 \"$0;\"\n      StrLen $4 $2\n      StrCpy $5 $1 -$4 # $5 is now the part before the path to remove\n      StrCpy $6 $2 \"\" $3 # $6 is now the part after the path to remove\n      StrCpy $3 $5$6\n \n      StrCpy $5 $3 1 -1 # copy last char\n      StrCmp $5 \";\" 0 +2 # if last char == ;\n        StrCpy $3 $3 -1 # remove last char\n \n      StrCmp $ADD_TO_PATH_ALL_USERS \"1\" unWriteAllKey\n        WriteRegExpandStr ${NT_current_env} \"PATH\" $3\n        Goto unDoSend\n      unWriteAllKey:\n        WriteRegExpandStr ${NT_all_env} \"PATH\" $3\n      unDoSend:\n      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 \"STR:Environment\" /TIMEOUT=5000\n \n  unRemoveFromPath_done:\n    Pop $6\n    Pop $5\n    Pop $4\n    Pop $3\n    Pop $2\n    Pop $1\n    Pop $0\nFunctionEnd\n \n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; Uninstall sutff\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n###########################################\n#            Utility Functions            #\n###########################################\n \n;====================================================\n; IsNT - Returns 1 if the current system is NT, 0\n;        otherwise.\n;     Output: head of the stack\n;====================================================\n; IsNT\n; no input\n; output, top of the stack = 1 if NT or 0 if not\n;\n; Usage:\n;   Call IsNT\n;   Pop $R0\n;  ($R0 at this point is 1 or 0)\n \n!macro IsNT un\nFunction ${un}IsNT\n  Push $0\n  ReadRegStr $0 HKLM \"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\" CurrentVersion\n  StrCmp $0 \"\" 0 IsNT_yes\n  ; we are not NT.\n  Pop $0\n  Push 0\n  Return\n \n  IsNT_yes:\n    ; NT!!!\n    Pop $0\n    Push 1\nFunctionEnd\n!macroend\n!insertmacro IsNT \"\"\n!insertmacro IsNT \"un.\"\n \n; StrStr\n; input, top of stack = string to search for\n;        top of stack-1 = string to search in\n; output, top of stack (replaces with the portion of the string remaining)\n; modifies no other variables.\n;\n; Usage:\n;   Push \"this is a long ass string\"\n;   Push \"ass\"\n;   Call StrStr\n;   Pop $R0\n;  ($R0 at this point is \"ass string\")\n \n!macro StrStr un\nFunction ${un}StrStr\nExch $R1 ; st=haystack,old$R1, $R1=needle\n  Exch    ; st=old$R1,haystack\n  Exch $R2 ; st=old$R1,old$R2, $R2=haystack\n  Push $R3\n  Push $R4\n  Push $R5\n  StrLen $R3 $R1\n  StrCpy $R4 0\n  ; $R1=needle\n  ; $R2=haystack\n  ; $R3=len(needle)\n  ; $R4=cnt\n  ; $R5=tmp\n  loop:\n    StrCpy $R5 $R2 $R3 $R4\n    StrCmp $R5 $R1 done\n    StrCmp $R5 \"\" done\n    IntOp $R4 $R4 + 1\n    Goto loop\ndone:\n  StrCpy $R1 $R2 \"\" $R4\n  Pop $R5\n  Pop $R4\n  Pop $R3\n  Pop $R2\n  Exch $R1\nFunctionEnd\n!macroend\n!insertmacro StrStr \"\"\n!insertmacro StrStr \"un.\"\n\nFunction Trim ; Added by Pelaca\n\tExch $R1\n\tPush $R2\nLoop:\n\tStrCpy $R2 \"$R1\" 1 -1\n\tStrCmp \"$R2\" \" \" RTrim\n\tStrCmp \"$R2\" \"$\\n\" RTrim\n\tStrCmp \"$R2\" \"$\\r\" RTrim\n\tStrCmp \"$R2\" \";\" RTrim\n\tGoTo Done\nRTrim:\t\n\tStrCpy $R1 \"$R1\" -1\n\tGoto Loop\nDone:\n\tPop $R2\n\tExch $R1\nFunctionEnd\n\nFunction ConditionalAddToRegisty\n  Pop $0\n  Pop $1\n  StrCmp \"$0\" \"\" ConditionalAddToRegisty_EmptyString\n    WriteRegStr SHCTX \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@ (x64)\" \\\n    \"$1\" \"$0\"\n    ;MessageBox MB_OK \"Set Registry: '$1' to '$0'\"\n    DetailPrint \"Set install registry entry: '$1' to '$0'\"\n  ConditionalAddToRegisty_EmptyString:\nFunctionEnd\n\n;--------------------------------\n\n!ifdef CPACK_USES_DOWNLOAD\nFunction DownloadFile\n    IfFileExists $INSTDIR\\* +2\n    CreateDirectory $INSTDIR\n    Pop $0\n\n    ; Skip if already downloaded\n    IfFileExists $INSTDIR\\$0 0 +2\n    Return\n\n    StrCpy $1 \"@CPACK_DOWNLOAD_SITE@\"\n\n  try_again:\n    NSISdl::download \"$1/$0\" \"$INSTDIR\\$0\"\n    \n    Pop $1\n    StrCmp $1 \"success\" success\n    StrCmp $1 \"Cancelled\" cancel\n    MessageBox MB_OK \"Download failed: $1\"\n  cancel:\n    Return\n  success:\nFunctionEnd\n!endif\n\n;--------------------------------\n; Installation types\n@CPACK_NSIS_INSTALLATION_TYPES@\n\n;--------------------------------\n; Component sections\n@CPACK_NSIS_COMPONENT_SECTIONS@\n\n;--------------------------------\n; Define some macro setting for the gui\n@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@\n@CPACK_NSIS_INSTALLER_ICON_CODE@\n@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@\n\n;--------------------------------\n;Pages\n  !insertmacro MUI_PAGE_WELCOME\n\n  !insertmacro MUI_PAGE_LICENSE \"@CPACK_RESOURCE_FILE_LICENSE@\"\n  Page custom InstallOptionsPage\n  !insertmacro MUI_PAGE_DIRECTORY\n  \n  ;Start Menu Folder Page Configuration\n  !define MUI_STARTMENUPAGE_REGISTRY_ROOT \"SHCTX\" \n  !define MUI_STARTMENUPAGE_REGISTRY_KEY \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \n  !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME \"Start Menu Folder\"\n  !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER\n\n  !define MUI_FINISHPAGE_SHOWREADME \"$INSTDIR\\NEWS.txt\"\n\n  @CPACK_NSIS_PAGE_COMPONENTS@\n\n  !insertmacro MUI_PAGE_INSTFILES\n  !insertmacro MUI_PAGE_FINISH\n\n  !insertmacro MUI_UNPAGE_CONFIRM\n  !insertmacro MUI_UNPAGE_INSTFILES\n  !insertmacro MUI_UNPAGE_FINISH\n\n;--------------------------------\n;Languages\n\n  !insertmacro MUI_LANGUAGE \"English\" ;first language is the default language\n  !insertmacro MUI_LANGUAGE \"Albanian\"\n  !insertmacro MUI_LANGUAGE \"Arabic\"\n  !insertmacro MUI_LANGUAGE \"Basque\"\n  !insertmacro MUI_LANGUAGE \"Belarusian\"\n  !insertmacro MUI_LANGUAGE \"Bosnian\"\n  !insertmacro MUI_LANGUAGE \"Breton\"\n  !insertmacro MUI_LANGUAGE \"Bulgarian\"\n  !insertmacro MUI_LANGUAGE \"Croatian\"\n  !insertmacro MUI_LANGUAGE \"Czech\"\n  !insertmacro MUI_LANGUAGE \"Danish\"\n  !insertmacro MUI_LANGUAGE \"Dutch\"\n  !insertmacro MUI_LANGUAGE \"Estonian\"\n  !insertmacro MUI_LANGUAGE \"Farsi\"\n  !insertmacro MUI_LANGUAGE \"Finnish\"\n  !insertmacro MUI_LANGUAGE \"French\"\n  !insertmacro MUI_LANGUAGE \"German\"\n  !insertmacro MUI_LANGUAGE \"Greek\"\n  !insertmacro MUI_LANGUAGE \"Hebrew\"\n  !insertmacro MUI_LANGUAGE \"Hungarian\"\n  !insertmacro MUI_LANGUAGE \"Icelandic\"\n  !insertmacro MUI_LANGUAGE \"Indonesian\"\n  !insertmacro MUI_LANGUAGE \"Irish\"\n  !insertmacro MUI_LANGUAGE \"Italian\"\n  !insertmacro MUI_LANGUAGE \"Japanese\"\n  !insertmacro MUI_LANGUAGE \"Korean\"\n  !insertmacro MUI_LANGUAGE \"Kurdish\"\n  !insertmacro MUI_LANGUAGE \"Latvian\"\n  !insertmacro MUI_LANGUAGE \"Lithuanian\"\n  !insertmacro MUI_LANGUAGE \"Luxembourgish\"\n  !insertmacro MUI_LANGUAGE \"Macedonian\"\n  !insertmacro MUI_LANGUAGE \"Malay\"\n  !insertmacro MUI_LANGUAGE \"Mongolian\"\n  !insertmacro MUI_LANGUAGE \"Norwegian\"\n  !insertmacro MUI_LANGUAGE \"Polish\"\n  !insertmacro MUI_LANGUAGE \"Portuguese\"\n  !insertmacro MUI_LANGUAGE \"PortugueseBR\"\n  !insertmacro MUI_LANGUAGE \"Romanian\"\n  !insertmacro MUI_LANGUAGE \"Russian\"\n  !insertmacro MUI_LANGUAGE \"Serbian\"\n  !insertmacro MUI_LANGUAGE \"SerbianLatin\"\n  !insertmacro MUI_LANGUAGE \"SimpChinese\"\n  !insertmacro MUI_LANGUAGE \"Slovak\"\n  !insertmacro MUI_LANGUAGE \"Slovenian\"\n  !insertmacro MUI_LANGUAGE \"Spanish\"\n  !insertmacro MUI_LANGUAGE \"Swedish\"\n  !insertmacro MUI_LANGUAGE \"Thai\"\n  !insertmacro MUI_LANGUAGE \"TradChinese\"\n  !insertmacro MUI_LANGUAGE \"Turkish\"\n  !insertmacro MUI_LANGUAGE \"Ukrainian\"\n  !insertmacro MUI_LANGUAGE \"Welsh\"\n\n\n;--------------------------------\n;Reserve Files\n\n  ;These files should be inserted before other files in the data block\n  ;Keep these lines before any File command\n  ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA)\n\n  ReserveFile \"NSIS.InstallOptions.ini\"\n  !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS\n\n;--------------------------------\n;Installer Sections\n\nSection \"-Core installation\"\n  ;Use the entire tree produced by the INSTALL target.  Keep the\n  ;list of directories here in sync with the RMDir commands below.\n  SetOutPath \"$INSTDIR\"\n  @CPACK_NSIS_FULL_INSTALL@\n  \n  ;Store installation folder\n  WriteRegStr SHCTX \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \"\" $INSTDIR\n  \n  ;Create uninstaller\n  WriteUninstaller \"$INSTDIR\\Uninstall.exe\"\n  Push \"DisplayName\"\n  Push \"@CPACK_NSIS_DISPLAY_NAME@\"\n  Call ConditionalAddToRegisty\n  Push \"DisplayVersion\"\n  Push \"@CPACK_PACKAGE_VERSION@\"\n  Call ConditionalAddToRegisty\n  Push \"Publisher\"\n  Push \"@CPACK_PACKAGE_VENDOR@\"\n  Call ConditionalAddToRegisty\n  Push \"UninstallString\"\n  Push \"$INSTDIR\\Uninstall.exe\"\n  Call ConditionalAddToRegisty\n  Push \"NoRepair\"\n  Push \"1\"\n  Call ConditionalAddToRegisty\n  \n  !ifdef CPACK_NSIS_ADD_REMOVE\n  ;Create add/remove functionality\n  Push \"ModifyPath\"\n  Push \"$INSTDIR\\AddRemove.exe\"\n  Call ConditionalAddToRegisty\n  !else\n  Push \"NoModify\"\n  Push \"1\"\n  Call ConditionalAddToRegisty\n  !endif\n  \n  ; Optional registration\n  Push \"DisplayIcon\"\n  Push \"$INSTDIR\\@CPACK_NSIS_INSTALLED_ICON_NAME@\"\n  Call ConditionalAddToRegisty\n  Push \"HelpLink\"\n  Push \"@CPACK_NSIS_HELP_LINK@\"\n  Call ConditionalAddToRegisty\n  Push \"URLInfoAbout\"\n  Push \"@CPACK_NSIS_URL_INFO_ABOUT@\"\n  Call ConditionalAddToRegisty\n  Push \"Contact\"\n  Push \"@CPACK_NSIS_CONTACT@\"\n  Call ConditionalAddToRegisty\n  !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP \"NSIS.InstallOptions.ini\" \"Field 5\" \"State\"\n  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\n  \n  ;Create shortcuts\n  CreateDirectory \"$SMPROGRAMS\\$STARTMENU_FOLDER\"\n@CPACK_NSIS_CREATE_ICONS@\n@CPACK_NSIS_CREATE_ICONS_EXTRA@\n  CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\Uninstall.lnk\" \"$INSTDIR\\Uninstall.exe\"\n\n  ;Read a value from an InstallOptions INI file\n  !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH \"NSIS.InstallOptions.ini\" \"Field 2\" \"State\"\n  !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS \"NSIS.InstallOptions.ini\" \"Field 3\" \"State\"\n  !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER \"NSIS.InstallOptions.ini\" \"Field 4\" \"State\"\n\n  ; Write special uninstall registry entries\n  Push \"StartMenu\"\n  Push \"$STARTMENU_FOLDER\"\n  Call ConditionalAddToRegisty\n  Push \"DoNotAddToPath\"\n  Push \"$DO_NOT_ADD_TO_PATH\"\n  Call ConditionalAddToRegisty\n  Push \"AddToPathAllUsers\"\n  Push \"$ADD_TO_PATH_ALL_USERS\"\n  Call ConditionalAddToRegisty\n  Push \"AddToPathCurrentUser\"\n  Push \"$ADD_TO_PATH_CURRENT_USER\"\n  Call ConditionalAddToRegisty\n  Push \"InstallToDesktop\"\n  Push \"$INSTALL_DESKTOP\"\n  Call ConditionalAddToRegisty\n\n  !insertmacro MUI_STARTMENU_WRITE_END\n\n@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@\n\nSectionEnd\n\nSection \"-Add to path\"\n  Push $INSTDIR\\bin\n  StrCmp \"@CPACK_NSIS_MODIFY_PATH@\" \"ON\" 0 doNotAddToPath\n  StrCmp $DO_NOT_ADD_TO_PATH \"1\" doNotAddToPath 0  \n    Call AddToPath\n  doNotAddToPath:\nSectionEnd\n\n;--------------------------------\n; Create custom pages\nFunction InstallOptionsPage\n  !insertmacro MUI_HEADER_TEXT \"Install Options\" \"Choose options for installing @CPACK_NSIS_PACKAGE_NAME@\"\n  !insertmacro MUI_INSTALLOPTIONS_DISPLAY \"NSIS.InstallOptions.ini\"\n\nFunctionEnd\n\n;--------------------------------\n; determine admin versus local install\nFunction un.onInit\n\n  ClearErrors\n  UserInfo::GetName\n  IfErrors noLM\n  Pop $0\n  UserInfo::GetAccountType\n  Pop $1\n  StrCmp $1 \"Admin\" 0 +3\n    SetShellVarContext all\n    ;MessageBox MB_OK 'User \"$0\" is in the Admin group'\n    Goto done\n  StrCmp $1 \"Power\" 0 +3\n    SetShellVarContext all\n    ;MessageBox MB_OK 'User \"$0\" is in the Power Users group'\n    Goto done\n    \n  noLM:\n    ;Get installation folder from registry if available\n\n  done:\n\n  ;Disable WoW64 redirection\n  SetRegView 64\n    \nFunctionEnd\n\n;--- Add/Remove callback functions: ---\n!macro SectionList MacroName\n  ;This macro used to perform operation on multiple sections.\n  ;List all of your components in following manner here.\n@CPACK_NSIS_COMPONENT_SECTION_LIST@\n!macroend\n \nSection -FinishComponents\n  ;Removes unselected components and writes component status to registry\n  !insertmacro SectionList \"FinishSection\"\n  \n!ifdef CPACK_NSIS_ADD_REMOVE  \n  ; Get the name of the installer executable\n  System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1'\n  StrCpy $R3 $R0\n  \n  ; Strip off the last 13 characters, to see if we have AddRemove.exe\n  StrLen $R1 $R0\n  IntOp $R1 $R0 - 13\n  StrCpy $R2 $R0 13 $R1\n  StrCmp $R2 \"AddRemove.exe\" addremove_installed\n  \n  ; We're not running AddRemove.exe, so install it\n  CopyFiles $R3 $INSTDIR\\AddRemove.exe\n  \n  addremove_installed:\n!endif\nSectionEnd\n;--- End of Add/Remove callback functions ---\n\n;--------------------------------\n; Component dependencies\nFunction .onSelChange\n  !insertmacro SectionList MaybeSelectionChanged\nFunctionEnd\n\n;--------------------------------\n;Uninstaller Section\n\nSection \"Uninstall\"\n  ReadRegStr $START_MENU SHCTX \\\n   \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@ (x64)\" \"StartMenu\"\n  ;MessageBox MB_OK \"Start menu is in: $START_MENU\"\n  ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \\\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@ (x64)\" \"DoNotAddToPath\"\n  ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \\\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@ (x64)\" \"AddToPathAllUsers\"\n  ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \\\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@ (x64)\" \"AddToPathCurrentUser\"\n  ;MessageBox MB_OK \"Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS\"\n  ReadRegStr $INSTALL_DESKTOP SHCTX \\\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@ (x64)\" \"InstallToDesktop\"\n  ;MessageBox MB_OK \"Install to desktop: $INSTALL_DESKTOP \"\n\n@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@\n\n  ;Remove files we installed.\n  ;Keep the list of directories here in sync with the File commands above.\n@CPACK_NSIS_DELETE_FILES@\n@CPACK_NSIS_DELETE_DIRECTORIES@\n\n!ifdef CPACK_NSIS_ADD_REMOVE  \n  ;Remove the add/remove program\n  Delete \"$INSTDIR\\AddRemove.exe\"\n!endif\n\n  ;Remove the uninstaller itself.\n  Delete \"$INSTDIR\\Uninstall.exe\"\n  DeleteRegKey SHCTX \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_NAME@ (x64)\"\n\n  ;Remove the installation directory if it is empty.\n  RMDir \"$INSTDIR\"\n\n  ; Remove the registry entries.\n  DeleteRegKey SHCTX \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\"\n\n  ; Removes all optional components\n  !insertmacro SectionList \"RemoveSection_CPack\"\n  \n  !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP\n    \n  Delete \"$SMPROGRAMS\\$MUI_TEMP\\Uninstall.lnk\"\n@CPACK_NSIS_DELETE_ICONS@\n@CPACK_NSIS_DELETE_ICONS_EXTRA@\n  \n  ;Delete empty start menu parent directories\n  StrCpy $MUI_TEMP \"$SMPROGRAMS\\$MUI_TEMP\"\n \n  startMenuDeleteLoop:\n    ClearErrors\n    RMDir $MUI_TEMP\n    GetFullPathName $MUI_TEMP \"$MUI_TEMP\\..\"\n    \n    IfErrors startMenuDeleteLoopDone\n  \n    StrCmp \"$MUI_TEMP\" \"$SMPROGRAMS\" startMenuDeleteLoopDone startMenuDeleteLoop\n  startMenuDeleteLoopDone:\n\n  ; If the user changed the shortcut, then untinstall may not work. This should\n  ; try to fix it.\n  StrCpy $MUI_TEMP \"$START_MENU\"\n  Delete \"$SMPROGRAMS\\$MUI_TEMP\\Uninstall.lnk\"\n@CPACK_NSIS_DELETE_ICONS_EXTRA@\n  \n  ;Delete empty start menu parent directories\n  StrCpy $MUI_TEMP \"$SMPROGRAMS\\$MUI_TEMP\"\n \n  secondStartMenuDeleteLoop:\n    ClearErrors\n    RMDir $MUI_TEMP\n    GetFullPathName $MUI_TEMP \"$MUI_TEMP\\..\"\n    \n    IfErrors secondStartMenuDeleteLoopDone\n  \n    StrCmp \"$MUI_TEMP\" \"$SMPROGRAMS\" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop\n  secondStartMenuDeleteLoopDone:\n\n  DeleteRegKey /ifempty SHCTX \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\"\n\n  Push $INSTDIR\\bin\n  StrCmp $DO_NOT_ADD_TO_PATH_ \"1\" doNotRemoveFromPath 0\n    Call un.RemoveFromPath\n  doNotRemoveFromPath:\nSectionEnd\n\n;--------------------------------\n; determine admin versus local install\n; Is install for \"AllUsers\" or \"JustMe\"?\n; Default to \"JustMe\" - set to \"AllUsers\" if admin or on Win9x\n; This function is used for the very first \"custom page\" of the installer.\n; This custom page does not show up visibly, but it executes prior to the\n; first visible page and sets up $INSTDIR properly...\n; Choose different default installation folder based on SV_ALLUSERS...\n; \"Program Files\" for AllUsers, \"My Documents\" for JustMe...\n\nFunction .onInit\n  ; Reads components status for registry\n  !insertmacro SectionList \"InitSection\"\n\n  ; check to see if /D has been used to change \n  ; the install directory by comparing it to the \n  ; install directory that is expected to be the\n  ; default\n  StrCpy $IS_DEFAULT_INSTALLDIR 0\n  ;StrCmp \"$INSTDIR\" \"$PROGRAMFILES\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\" 0 +2\n  StrCmp \"$INSTDIR\" \"$PROGRAMFILES64\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\" 0 +2\n    StrCpy $IS_DEFAULT_INSTALLDIR 1\n  \n  StrCpy $SV_ALLUSERS \"JustMe\"\n  ; if default install dir then change the default\n  ; if it is installed for JustMe\n  StrCmp \"$IS_DEFAULT_INSTALLDIR\" \"1\" 0 +2\n    StrCpy $INSTDIR \"$DOCUMENTS\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\n\n  ;Disable WoW64 redirection\n  SetRegView 64\n\n  ClearErrors\n  UserInfo::GetName\n  IfErrors noLM\n  Pop $0\n  UserInfo::GetAccountType\n  Pop $1\n  StrCmp $1 \"Admin\" 0 +3\n    SetShellVarContext all\n    ;MessageBox MB_OK 'User \"$0\" is in the Admin group'\n    StrCpy $SV_ALLUSERS \"AllUsers\"\n    Goto done\n  StrCmp $1 \"Power\" 0 +3\n    SetShellVarContext all\n    ;MessageBox MB_OK 'User \"$0\" is in the Power Users group'\n    StrCpy $SV_ALLUSERS \"AllUsers\"\n    Goto done\n    \n  noLM:\n    StrCpy $SV_ALLUSERS \"AllUsers\"\n    ;Get installation folder from registry if available\n\n  done:\n  StrCmp $SV_ALLUSERS \"AllUsers\" 0 +3\n    StrCmp \"$IS_DEFAULT_INSTALLDIR\" \"1\" 0 +2\n      ;StrCpy $INSTDIR \"$PROGRAMFILES\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\n      StrCpy $INSTDIR \"$PROGRAMFILES64\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\n\n  StrCmp \"@CPACK_NSIS_MODIFY_PATH@\" \"ON\" 0 noOptionsPage\n    !insertmacro MUI_INSTALLOPTIONS_EXTRACT \"NSIS.InstallOptions.ini\"\n\n  noOptionsPage:\nFunctionEnd\n"
  },
  {
    "path": "builds/cmake/ZeroMQConfig.cmake.in",
    "content": "# ZeroMQ cmake module\n#\n# The following import targets are created\n#\n# ::\n#\n#   libzmq-static\n#   libzmq\n#\n# This module sets the following variables in your project::\n#\n#   ZeroMQ_FOUND - true if ZeroMQ found on the system\n#   ZeroMQ_INCLUDE_DIR - the directory containing ZeroMQ headers\n#   ZeroMQ_LIBRARY - \n#   ZeroMQ_STATIC_LIBRARY\n\n@PACKAGE_INIT@\n\nif(NOT TARGET libzmq AND NOT TARGET libzmq-static)\n  include(\"${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake\")\n\n  if (TARGET libzmq)\n    get_target_property(@PROJECT_NAME@_INCLUDE_DIR libzmq INTERFACE_INCLUDE_DIRECTORIES)\n  else ()\n    get_target_property(@PROJECT_NAME@_INCLUDE_DIR libzmq-static INTERFACE_INCLUDE_DIRECTORIES)\n  endif()\n\n  if (TARGET libzmq)\n    get_target_property(@PROJECT_NAME@_LIBRARY libzmq LOCATION)\n  endif()\n  if (TARGET libzmq-static)\n    get_target_property(@PROJECT_NAME@_STATIC_LIBRARY libzmq-static LOCATION)\n  endif()\nendif()\n"
  },
  {
    "path": "builds/cmake/ci_build.sh",
    "content": "#!/usr/bin/env bash\n\nset -x -e\n\ncd ../..\n\n# always install custom builds from dist\n# to make sure that `make dist` doesn't omit any files required to build & test\nif [ -z \"$DO_CLANG_FORMAT_CHECK\" -a -z \"$CLANG_TIDY\" ]; then\n    ./autogen.sh\n    ./configure\n    make -j5 dist-gzip\n    V=$(./version.sh)\n    tar -xzf zeromq-$V.tar.gz\n    cd zeromq-$V\nfi\n\nmkdir tmp || true\nBUILD_PREFIX=$PWD/tmp\n\nCONFIG_OPTS=()\nCONFIG_OPTS+=(\"CFLAGS=-I${BUILD_PREFIX}/include\")\nCONFIG_OPTS+=(\"CPPFLAGS=-I${BUILD_PREFIX}/include\")\nCONFIG_OPTS+=(\"CXXFLAGS=-I${BUILD_PREFIX}/include\")\nCONFIG_OPTS+=(\"LDFLAGS=-L${BUILD_PREFIX}/lib\")\nCONFIG_OPTS+=(\"PKG_CONFIG_PATH=${BUILD_PREFIX}/lib/pkgconfig\")\n\nCMAKE_OPTS=()\nCMAKE_OPTS+=(\"-DCMAKE_INSTALL_PREFIX:PATH=${BUILD_PREFIX}\")\nCMAKE_OPTS+=(\"-DCMAKE_PREFIX_PATH:PATH=${BUILD_PREFIX}\")\nCMAKE_OPTS+=(\"-DCMAKE_LIBRARY_PATH:PATH=${BUILD_PREFIX}/lib\")\nCMAKE_OPTS+=(\"-DCMAKE_INCLUDE_PATH:PATH=${BUILD_PREFIX}/include\")\nCMAKE_OPTS+=(\"-DENABLE_CAPSH=ON\")\nCMAKE_OPTS+=(\"-DBUILD_TESTS=ON\")\n\nif [ \"$CLANG_FORMAT\" != \"\" ] ; then\n    CMAKE_OPTS+=(\"-DCLANG_FORMAT=${CLANG_FORMAT}\")\nfi\n\nif [ -z $CURVE ]; then\n    CMAKE_OPTS+=(\"-DENABLE_CURVE=OFF\")\nelif [ $CURVE == \"libsodium\" ]; then\n    CMAKE_OPTS+=(\"-DWITH_LIBSODIUM=ON\")\n\n    if ! ((command -v dpkg-query >/dev/null 2>&1 && dpkg-query --list libsodium-dev >/dev/null 2>&1) || \\\n            (command -v brew >/dev/null 2>&1 && brew ls --versions libsodium >/dev/null 2>&1)); then\n        git clone --depth 1 -b stable https://github.com/jedisct1/libsodium.git\n        ( cd libsodium; ./autogen.sh; ./configure --prefix=$BUILD_PREFIX; make install)\n    fi\nfi\n\nif [ \"$GSSAPI\" == \"enabled\" ]; then\n    CMAKE_OPTS+=(\"-DWITH_GSSAPI_KRB5=ON\")\nfi\n\nCMAKE_PREFIXES=()\nMAKE_PREFIXES=()\nPARALLEL_MAKE_OPT=\"-j5\"\nif [ -n \"$CLANG_TIDY\" ] ; then\n    # To allow sonar to process history information, unshallow clone first.\n    git fetch --unshallow\n    curl -L https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip -o build-wrapper-linux-x86.zip\n    unzip build-wrapper-linux-x86.zip\n    export SONARCLOUD_BUILD_WRAPPER_PATH=\"${PWD}/build-wrapper-linux-x86/\"\n    curl -L https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.2.0.1873-linux.zip -o sonar-scanner-cli.zip\n    unzip sonar-scanner-cli.zip\n    export SONAR_SCANNER_CLI_PATH=\"${PWD}/sonar-scanner-4.2.0.1873-linux/bin/\"\n\n    CMAKE_OPTS+=(\"-DCMAKE_BUILD_TYPE=Debug\") # do a debug build to avoid unused variable warnings with assertions, and to speed up build\n    CMAKE_OPTS+=(\"-DCMAKE_CXX_CLANG_TIDY:STRING=${CLANG_TIDY}\")\n    if [ -n ${SONARCLOUD_BUILD_WRAPPER_PATH} ] ; then\n        MAKE_PREFIXES+=(\"${SONARCLOUD_BUILD_WRAPPER_PATH}build-wrapper-linux-x86-64\")\n        MAKE_PREFIXES+=(\"--out-dir\")\n        MAKE_PREFIXES+=(\"${TRAVIS_BUILD_DIR}/bw-output\")\n        \n    fi\n    CMAKE_PREFIXES+=(\"scan-build-10\")\n    MAKE_PREFIXES+=(\"scan-build-10\")\n    MAKE_PREFIXES+=(\"-plist-html\")\n    SCAN_BUILD_OUTPUT=\"$(pwd)/scan-build-report\"\n    MAKE_PREFIXES+=(\"-o ${SCAN_BUILD_OUTPUT}\")\n    # TODO this does not work with sonarcloud.io as it misses the sonar-cxx plugin\n    #MAKE_PREFIXES+=(\"-plist\")\n    IFS=\"/\" read -ra GITHUB_USER <<< \"${TRAVIS_REPO_SLUG}\"\n    PARALLEL_MAKE_OPT=\"\"\nfi\n\n# Build, check, and install from local source\nmkdir build_cmake\ncd build_cmake\nif [ \"$DO_CLANG_FORMAT_CHECK\" = \"1\" ] ; then\n    if ! ( PKG_CONFIG_PATH=${BUILD_PREFIX}/lib/pkgconfig cmake \"${CMAKE_OPTS[@]}\" .. && make clang-format-check) ; then\n        echo \"clang-format version is: $(clang-format --version)\"\n        make clang-format-diff\n        exit 1\n    fi\nelse\n    if [ -n \"$CLANG_TIDY\" ] ; then\n        ${CLANG_TIDY} -explain-config\n    fi\n\n    export CTEST_OUTPUT_ON_FAILURE=1\n    PKG_CONFIG_PATH=${BUILD_PREFIX}/lib/pkgconfig ${CMAKE_PREFIXES[@]} cmake \"${CMAKE_OPTS[@]}\" ..\n    ${MAKE_PREFIXES[@]} make ${PARALLEL_MAKE_OPT} all VERBOSE=1 | tee clang-tidy-report\n    \n    if [ -n \"${SONAR_SCANNER_CLI_PATH}\" ] ; then\n        find ${SCAN_BUILD_OUTPUT} || echo \"WARNING: ${SCAN_BUILD_OUTPUT} does not exist\"\n    \n        ${SONAR_SCANNER_CLI_PATH}sonar-scanner \\\n            -Dsonar.projectKey=${GITHUB_USER}-libzmq \\\n            -Dsonar.organization=${GITHUB_USER}-github \\\n            -Dsonar.projectBaseDir=.. \\\n            -Dsonar.sources=${TRAVIS_BUILD_DIR}/include,${TRAVIS_BUILD_DIR}/src,${TRAVIS_BUILD_DIR}/tests,${TRAVIS_BUILD_DIR}/unittests \\\n            -Dsonar.cfamily.build-wrapper-output=${TRAVIS_BUILD_DIR}/bw-output \\\n            -Dsonar.host.url=https://sonarcloud.io \\\n            -Dsonar.login=${SONARQUBE_TOKEN}\n\n            # TODO this does not work with sonarcloud.io as it misses the sonar-cxx plugin\n            # -Dsonar.cxx.clangtidy.reportPath=clang-tidy-report \\\n            # -Dsonar.cxx.clangsa.reportPath=*.plist \\\n            \n    fi\n\n    make install\n    make ${PARALLEL_MAKE_OPT} test ARGS=\"-V\"\nfi\n"
  },
  {
    "path": "builds/cmake/clang-format-check.sh.in",
    "content": "#!/bin/sh\nFAILED=0\nIFS=\";\"\nFILES=\"@ALL_SOURCE_FILES@\"\nIDS=$(echo -en \"\\n\\b\")\nfor FILE in $FILES\ndo\n\t@CLANG_FORMAT@ -style=file -output-replacements-xml \"$FILE\" | grep \"<replacement \" >/dev/null &&\n    {\n      echo \"$FILE is not correctly formatted\"\n\t  FAILED=1\n\t}\ndone\nif [ \"$FAILED\" -eq \"1\" ] ; then exit 1 ; fi\n"
  },
  {
    "path": "builds/cmake/platform.hpp.in",
    "content": "#ifndef __ZMQ_PLATFORM_HPP_INCLUDED__\n#define __ZMQ_PLATFORM_HPP_INCLUDED__\n\n#cmakedefine ZMQ_USE_CV_IMPL_STL11\n#cmakedefine ZMQ_USE_CV_IMPL_WIN32API\n#cmakedefine ZMQ_USE_CV_IMPL_PTHREADS\n#cmakedefine ZMQ_USE_CV_IMPL_NONE\n\n#cmakedefine ZMQ_IOTHREAD_POLLER_USE_KQUEUE\n#cmakedefine ZMQ_IOTHREAD_POLLER_USE_EPOLL\n#cmakedefine ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC\n#cmakedefine ZMQ_IOTHREAD_POLLER_USE_DEVPOLL\n#cmakedefine ZMQ_IOTHREAD_POLLER_USE_POLLSET\n#cmakedefine ZMQ_IOTHREAD_POLLER_USE_POLL\n#cmakedefine ZMQ_IOTHREAD_POLLER_USE_SELECT\n#cmakedefine ZMQ_HAVE_PPOLL\n\n#cmakedefine ZMQ_POLL_BASED_ON_SELECT\n#cmakedefine ZMQ_POLL_BASED_ON_POLL\n\n#cmakedefine HAVE_POSIX_MEMALIGN @HAVE_POSIX_MEMALIGN@\n#cmakedefine ZMQ_CACHELINE_SIZE @ZMQ_CACHELINE_SIZE@\n\n#cmakedefine ZMQ_FORCE_MUTEXES\n\n#cmakedefine HAVE_FORK\n#cmakedefine HAVE_CLOCK_GETTIME\n#cmakedefine HAVE_GETHRTIME\n#cmakedefine HAVE_MKDTEMP\n#cmakedefine ZMQ_HAVE_UIO\n\n#cmakedefine ZMQ_HAVE_NOEXCEPT\n\n#cmakedefine ZMQ_HAVE_EVENTFD\n#cmakedefine ZMQ_HAVE_EVENTFD_CLOEXEC\n#cmakedefine ZMQ_HAVE_IFADDRS\n#cmakedefine ZMQ_HAVE_SO_BINDTODEVICE\n\n#cmakedefine ZMQ_HAVE_SO_PEERCRED\n#cmakedefine ZMQ_HAVE_LOCAL_PEERCRED\n#cmakedefine ZMQ_HAVE_BUSY_POLL\n\n#cmakedefine ZMQ_HAVE_O_CLOEXEC\n\n#cmakedefine ZMQ_HAVE_SOCK_CLOEXEC\n#cmakedefine ZMQ_HAVE_SO_KEEPALIVE\n#cmakedefine ZMQ_HAVE_SO_PRIORITY\n#cmakedefine ZMQ_HAVE_TCP_KEEPCNT\n#cmakedefine ZMQ_HAVE_TCP_KEEPIDLE\n#cmakedefine ZMQ_HAVE_TCP_KEEPINTVL\n#cmakedefine ZMQ_HAVE_TCP_KEEPALIVE\n#cmakedefine ZMQ_HAVE_PTHREAD_SETNAME_1\n#cmakedefine ZMQ_HAVE_PTHREAD_SETNAME_2\n#cmakedefine ZMQ_HAVE_PTHREAD_SETNAME_3\n#cmakedefine ZMQ_HAVE_PTHREAD_SET_NAME\n#cmakedefine ZMQ_HAVE_PTHREAD_SET_AFFINITY\n#cmakedefine HAVE_ACCEPT4\n#cmakedefine HAVE_STRNLEN\n#cmakedefine ZMQ_HAVE_STRLCPY\n#cmakedefine ZMQ_HAVE_LIBBSD\n\n#cmakedefine ZMQ_HAVE_IPC\n#cmakedefine ZMQ_HAVE_STRUCT_SOCKADDR_UN\n\n#cmakedefine ZMQ_USE_BUILTIN_SHA1\n#cmakedefine ZMQ_USE_NSS\n#cmakedefine ZMQ_HAVE_WS\n#cmakedefine ZMQ_HAVE_WSS\n#cmakedefine ZMQ_HAVE_TIPC\n\n#cmakedefine ZMQ_HAVE_OPENPGM\n#cmakedefine ZMQ_HAVE_NORM\n#cmakedefine ZMQ_HAVE_VMCI\n#cmakedefine ZMQ_HAVE_VSOCK\n\n#cmakedefine ZMQ_MAKE_VALGRIND_HAPPY\n\n#cmakedefine ZMQ_HAVE_CURVE\n#cmakedefine ZMQ_USE_LIBSODIUM\n#cmakedefine SODIUM_STATIC\n#cmakedefine HAVE_LIBGSSAPI_KRB5\n#cmakedefine ZMQ_USE_GNUTLS\n#cmakedefine ZMQ_USE_RADIX_TREE\n#cmakedefine HAVE_IF_NAMETOINDEX\n\n#ifdef _AIX\n  #define ZMQ_HAVE_AIX\n#endif\n\n#if defined __ANDROID__\n  #define ZMQ_HAVE_ANDROID\n#endif\n\n#if defined __CYGWIN__\n  #define ZMQ_HAVE_CYGWIN\n#endif\n\n#if defined __MINGW32__\n  #define ZMQ_HAVE_MINGW32\n#endif\n\n#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)\n  #define ZMQ_HAVE_FREEBSD\n#endif\n\n#if defined(__DragonFly__)\n  #define ZMQ_HAVE_FREEBSD\n  #define ZMQ_HAVE_DRAGONFLY\n#endif\n\n#if defined __hpux\n  #define ZMQ_HAVE_HPUX\n#endif\n\n#if defined __linux__\n  #define ZMQ_HAVE_LINUX\n#endif\n\n#if defined __NetBSD__\n  #define ZMQ_HAVE_NETBSD\n#endif\n\n#if defined __OpenBSD__\n  #define ZMQ_HAVE_OPENBSD\n#endif\n\n// TODO better move OS-specific defines to the automake files, and check for availability of IPC with an explicit test there\n#if defined __VMS\n  #define ZMQ_HAVE_OPENVMS\n  #undef ZMQ_HAVE_IPC\n#endif\n\n#if defined __APPLE__\n  #define ZMQ_HAVE_OSX\n#endif\n\n#if defined __QNXNTO__\n  #define ZMQ_HAVE_QNXNTO\n#endif\n\n#if defined(sun) || defined(__sun)\n  #define ZMQ_HAVE_SOLARIS\n#endif\n\n#cmakedefine ZMQ_HAVE_WINDOWS\n#cmakedefine ZMQ_HAVE_WINDOWS_UWP\n\n#endif\n"
  },
  {
    "path": "builds/coverage/ci_build.sh",
    "content": "#!/usr/bin/env bash\n\nset -x\n\nmkdir tmp\nBUILD_PREFIX=$PWD/tmp\n\nsource ../../config.sh\nset_config_opts\n\nCONFIG_OPTS+=(\"--enable-code-coverage\")\n\n# Build, check, and install from local source\n( cd ../..; ./autogen.sh && ./configure \"${CONFIG_OPTS[@]}\" && make VERBOSE=1 -j5 check-code-coverage CODE_COVERAGE_OUTPUT_FILE=lcov.info CODE_COVERAGE_OUTPUT_DIRECTORY=coverage) || exit 1\n"
  },
  {
    "path": "builds/cygwin/Makefile.cygwin",
    "content": "CC=gcc\nCFLAGS=-Wall -Os -g -DDLL_EXPORT -DFD_SETSIZE=16384 -DZMQ_USE_SELECT -I.\nLIBS=-lws2_32\n\nOBJS = ctx.o reaper.o dist.o err.o \\\n\tclock.o metadata.o random.o \\\n\tobject.o own.o \\\n\tio_object.o io_thread.o \\\n\tlb.o fq.o \\\n\taddress.o tcp_address.o ipc_address.o \\\n\tipc_connecter.o ipc_listener.o \\\n\ttcp_connecter.o tcp_listener.o \\\n\tmailbox.o msg.o mtrie.o \\\n\tpipe.o precompiled.o proxy.o \\\n\tsignaler.o stream_engine.o \\\n\tthread.o trie.o \\\n\tip.o tcp.o \\\n\tpgm_socket.o pgm_receiver.o pgm_sender.o \\\n\traw_decoder.o raw_encoder.o \\\n\tv1_decoder.o v1_encoder.o v2_decoder.o v2_encoder.o \\\n        udp_address.o upd_engine.o radio.o dish.o \\\n\tsocket_base.o session_base.o options.o \\\n\treq.o rep.o push.o pull.o pub.o sub.o pair.o \\\n\tdealer.o router.o xpub.o xsub.o stream.o \\\n\tpoller_base.o select.o poll.o epoll.o kqueue.o devpoll.o \\\n\tcurve_client.o curve_server.o \\\n\tmechanism.o null_mechanism.o plain_client.o plain_server.o \\\n\tzmq.o zmq_utils.o\n\n%.o: ../../src/%.cpp\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n%.o: ../../perf/%.cpp\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\nall: libzmq.dll\n\nperf: inproc_lat.exe inproc_thr.exe local_lat.exe local_thr.exe remote_lat.exe remote_thr.exe\n\nlibzmq.dll: $(OBJS)\n\tg++ -shared -o $@ $^ -Wl,--out-implib,-Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $@.a -Wl,--no-whole-archive $(LIBS)\n\n%.exe: %.o libzmq.dll\n\tg++ -o $@ $^\n\nclean:\n\tdel *.o *.a *.dll *.exe\n\t\n"
  },
  {
    "path": "builds/deprecated-msvc/.gitignore",
    "content": "## Visual Studio 2015 experimental Visual C/C++ Intellisense database\r\n*.VC.db\r\n\r\n\r\n## From https://github.com/github/gitignore\r\n##\r\n## Ignore Visual Studio temporary files, build results, and\r\n## files generated by popular Visual Studio add-ons.\r\n\r\n# User-specific files\r\n*.suo\r\n*.user\r\n*.userosscache\r\n*.sln.docstates\r\n\r\n# User-specific files (MonoDevelop/Xamarin Studio)\r\n*.userprefs\r\n\r\n# Build results\r\n[Dd]ebug/\r\n[Dd]ebugPublic/\r\n[Rr]elease/\r\n[Rr]eleases/\r\nx64/\r\nx86/\r\nbld/\r\n[Bb]in/\r\n[Oo]bj/\r\n[Ll]og/\r\n\r\n# Visual Studio 2015 cache/options directory\r\n.vs/\r\n# Uncomment if you have tasks that create the project's static files in wwwroot\r\n#wwwroot/\r\n\r\n# MSTest test Results\r\n[Tt]est[Rr]esult*/\r\n[Bb]uild[Ll]og.*\r\n\r\n# NUNIT\r\n*.VisualState.xml\r\nTestResult.xml\r\n\r\n# Build Results of an ATL Project\r\n[Dd]ebugPS/\r\n[Rr]eleasePS/\r\ndlldata.c\r\n\r\n# DNX\r\nproject.lock.json\r\nartifacts/\r\n\r\n*_i.c\r\n*_p.c\r\n*_i.h\r\n*.ilk\r\n*.meta\r\n*.obj\r\n*.pch\r\n*.pdb\r\n*.pgc\r\n*.pgd\r\n*.rsp\r\n*.sbr\r\n*.tlb\r\n*.tli\r\n*.tlh\r\n*.tmp\r\n*.tmp_proj\r\n*.log\r\n*.vspscc\r\n*.vssscc\r\n.builds\r\n*.pidb\r\n*.svclog\r\n*.scc\r\n\r\n# Chutzpah Test files\r\n_Chutzpah*\r\n\r\n# Visual C++ cache files\r\nipch/\r\n*.aps\r\n*.ncb\r\n*.opendb\r\n*.opensdf\r\n*.sdf\r\n*.cachefile\r\n\r\n# Visual Studio profiler\r\n*.psess\r\n*.vsp\r\n*.vspx\r\n*.sap\r\n\r\n# TFS 2012 Local Workspace\r\n$tf/\r\n\r\n# Guidance Automation Toolkit\r\n*.gpState\r\n\r\n# ReSharper is a .NET coding add-in\r\n_ReSharper*/\r\n*.[Rr]e[Ss]harper\r\n*.DotSettings.user\r\n\r\n# JustCode is a .NET coding add-in\r\n.JustCode\r\n\r\n# TeamCity is a build add-in\r\n_TeamCity*\r\n\r\n# DotCover is a Code Coverage Tool\r\n*.dotCover\r\n\r\n# NCrunch\r\n_NCrunch_*\r\n.*crunch*.local.xml\r\nnCrunchTemp_*\r\n\r\n# MightyMoose\r\n*.mm.*\r\nAutoTest.Net/\r\n\r\n# Web workbench (sass)\r\n.sass-cache/\r\n\r\n# Installshield output folder\r\n[Ee]xpress/\r\n\r\n# DocProject is a documentation generator add-in\r\nDocProject/buildhelp/\r\nDocProject/Help/*.HxT\r\nDocProject/Help/*.HxC\r\nDocProject/Help/*.hhc\r\nDocProject/Help/*.hhk\r\nDocProject/Help/*.hhp\r\nDocProject/Help/Html2\r\nDocProject/Help/html\r\n\r\n# Click-Once directory\r\npublish/\r\n\r\n# Publish Web Output\r\n*.[Pp]ublish.xml\r\n*.azurePubxml\r\n# TODO: Comment the next line if you want to checkin your web deploy settings\r\n# but database connection strings (with potential passwords) will be unencrypted\r\n*.pubxml\r\n*.publishproj\r\n\r\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\r\n# checkin your Azure Web App publish settings, but sensitive information contained\r\n# in these scripts will be unencrypted\r\nPublishScripts/\r\n\r\n# NuGet Packages\r\n*.nupkg\r\n# The packages folder can be ignored because of Package Restore\r\n**/packages/*\r\n# except build/, which is used as an MSBuild target.\r\n!**/packages/build/\r\n# Uncomment if necessary however generally it will be regenerated when needed\r\n#!**/packages/repositories.config\r\n# NuGet v3's project.json files produces more ignoreable files\r\n*.nuget.props\r\n*.nuget.targets\r\n\r\n# Microsoft Azure Build Output\r\ncsx/\r\n*.build.csdef\r\n\r\n# Microsoft Azure Emulator\r\necf/\r\nrcf/\r\n\r\n# Windows Store app package directories and files\r\nAppPackages/\r\nBundleArtifacts/\r\nPackage.StoreAssociation.xml\r\n_pkginfo.txt\r\n\r\n# Visual Studio cache files\r\n# files ending in .cache can be ignored\r\n*.[Cc]ache\r\n# but keep track of directories ending in .cache\r\n!*.[Cc]ache/\r\n\r\n# Others\r\nClientBin/\r\n~$*\r\n*~\r\n*.dbmdl\r\n*.dbproj.schemaview\r\n*.pfx\r\n*.publishsettings\r\nnode_modules/\r\norleans.codegen.cs\r\n\r\n# Since there are multiple workflows, uncomment next line to ignore bower_components\r\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\r\n#bower_components/\r\n\r\n# RIA/Silverlight projects\r\nGenerated_Code/\r\n\r\n# Backup & report files from converting an old project file\r\n# to a newer Visual Studio version. Backup files are not needed,\r\n# because we have git ;-)\r\n_UpgradeReport_Files/\r\nBackup*/\r\nUpgradeLog*.XML\r\nUpgradeLog*.htm\r\n\r\n# SQL Server files\r\n*.mdf\r\n*.ldf\r\n\r\n# Business Intelligence projects\r\n*.rdl.data\r\n*.bim.layout\r\n*.bim_*.settings\r\n\r\n# Microsoft Fakes\r\nFakesAssemblies/\r\n\r\n# GhostDoc plugin setting file\r\n*.GhostDoc.xml\r\n\r\n# Node.js Tools for Visual Studio\r\n.ntvs_analysis.dat\r\n\r\n# Visual Studio 6 build log\r\n*.plg\r\n\r\n# Visual Studio 6 workspace options file\r\n*.opt\r\n\r\n# Visual Studio LightSwitch build output\r\n**/*.HTMLClient/GeneratedArtifacts\r\n**/*.DesktopClient/GeneratedArtifacts\r\n**/*.DesktopClient/ModelManifest.xml\r\n**/*.Server/GeneratedArtifacts\r\n**/*.Server/ModelManifest.xml\r\n_Pvt_Extensions\r\n\r\n# Paket dependency manager\r\n.paket/paket.exe\r\npaket-files/\r\n\r\n# FAKE - F# Make\r\n.fake/\r\n\r\n# JetBrains Rider\r\n.idea/\r\n*.sln.iml\r\n"
  },
  {
    "path": "builds/deprecated-msvc/Makefile.am",
    "content": "LIBZMQ_DIST = vs2008/libzmq.sln \\\n              vs2008/libzmq/libzmq.vcproj \\\n              vs2010/libzmq.sln \\\n              vs2010/libzmq/libzmq.vcxproj \\\n              vs2010/libzmq/libzmq.vcxproj.filters \\\n              vs2012/libzmq.sln \\\n              vs2012/libzmq/libzmq.vcxproj \\\n              vs2012/libzmq/libzmq.vcxproj.filters \\\n              vs2013/libzmq.sln \\\n              vs2013/libzmq/libzmq.vcxproj \\\n              vs2013/libzmq/libzmq.vcxproj.filters \\\n              vs2015/libzmq.sln \\\n              vs2015/libzmq/libzmq.vcxproj \\\n              vs2015/libzmq/libzmq.vcxproj.filters \\\n              vs2015/libzmq/libzmq.props \\\n              vs2015/libzmq/libzmq.xml \\\n              vs2015/libzmq.import.props \\\n              vs2015/libzmq.import.xml \\\n              errno.cpp \\\n              errno.hpp \\\n              platform.hpp \\\n              resource.h \\\n              resource.rc\n\nPERF_DIST = vs2008/local_lat/local_lat.vcproj \\\n            vs2008/local_thr/local_thr.vcproj \\\n            vs2008/remote_lat/remote_lat.vcproj \\\n            vs2008/remote_thr/remote_thr.vcproj \\\n            vs2008/inproc_lat/inproc_lat.vcproj \\\n            vs2008/inproc_thr/inproc_thr.vcproj \\\n            vs2010/local_lat/local_lat.vcxproj \\\n            vs2010/local_thr/local_thr.vcxproj \\\n            vs2010/remote_lat/remote_lat.vcxproj \\\n            vs2010/remote_thr/remote_thr.vcxproj \\\n            vs2010/inproc_lat/inproc_lat.vcxproj \\\n            vs2010/inproc_thr/inproc_thr.vcxproj \\\n            vs2012/local_lat/local_lat.vcxproj \\\n            vs2012/local_thr/local_thr.vcxproj \\\n            vs2012/remote_lat/remote_lat.vcxproj \\\n            vs2012/remote_thr/remote_thr.vcxproj \\\n            vs2012/inproc_lat/inproc_lat.vcxproj \\\n            vs2012/inproc_thr/inproc_thr.vcxproj \\\n            vs2013/local_lat/local_lat.vcxproj \\\n            vs2013/local_thr/local_thr.vcxproj \\\n            vs2013/remote_lat/remote_lat.vcxproj \\\n            vs2013/remote_thr/remote_thr.vcxproj \\\n            vs2013/inproc_lat/inproc_lat.vcxproj \\\n            vs2013/inproc_thr/inproc_thr.vcxproj \\\n            vs2015/local_lat/local_lat.vcxproj \\\n            vs2015/local_lat/local_lat.props \\\n            vs2015/local_thr/local_thr.vcxproj \\\n            vs2015/local_thr/local_thr.props \\\n            vs2015/remote_lat/remote_lat.vcxproj \\\n            vs2015/remote_lat/remote_lat.props \\\n            vs2015/remote_thr/remote_thr.vcxproj \\\n            vs2015/remote_thr/remote_thr.props \\\n            vs2015/inproc_lat/inproc_lat.vcxproj \\\n            vs2015/inproc_lat/inproc_lat.props \\\n            vs2015/inproc_thr/inproc_thr.vcxproj \\\n            vs2015/inproc_thr/inproc_thr.props\n\nPROPERTIES_DIST = properties/Common.props \\\n                  properties/Debug.props \\\n                  properties/DebugDEXE.props \\\n                  properties/DebugDLL.props \\\n                  properties/DebugLEXE.props \\\n                  properties/DebugLIB.props \\\n                  properties/DebugLTCG.props \\\n                  properties/DebugSEXE.props \\\n                  properties/DLL.props \\\n                  properties/EXE.props \\\n                  properties/LIB.props \\\n                  properties/Link.props \\\n                  properties/LTCG.props \\\n                  properties/Messages.props \\\n                  properties/Output.props \\\n                  properties/Release.props \\\n                  properties/ReleaseDEXE.props \\\n                  properties/ReleaseDLL.props \\\n                  properties/ReleaseLEXE.props \\\n                  properties/ReleaseLIB.props \\\n                  properties/ReleaseLTCG.props \\\n                  properties/ReleaseSEXE.props \\\n                  properties/Win32.props \\\n                  properties/x64.props\n\nPRECOMPILED_DIST = ../../src/precompiled.hpp \\\n                   ../../src/precompiled.cpp\n\nBUILD_DIST = build/build.bat \\\n             build/buildall.bat \\\n             build/buildbase.bat\n\nEXTRA_DIST = $(LIBZMQ_DIST) $(PERF_DIST) $(PROPERTIES_DIST) $(PRECOMPILED_DIST) $(BUILD_DIST)"
  },
  {
    "path": "builds/deprecated-msvc/errno.cpp",
    "content": "#if defined _WIN32_WCE\n\n//#include \"..\\..\\include\\zmq.h\"\n#include \"..\\..\\src\\err.hpp\"\n\nint errno;\nint _doserrno;\nint _sys_nerr;\n\nchar* error_desc_buff = NULL;\n\nchar* strerror(int errno)\n{\n    if (NULL != error_desc_buff)\n    {\n        LocalFree(error_desc_buff);\n        error_desc_buff = NULL;\n    }\n\n    FormatMessage(\n        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,\n        NULL,\n        errno,\n        0,\n        (LPTSTR)&error_desc_buff,\n        1024,\n        NULL\n        );\n    return error_desc_buff;\n}\n\n#endif"
  },
  {
    "path": "builds/deprecated-msvc/errno.hpp",
    "content": "#ifndef ERRNO_H\r\n#define ERRNO_H 1\r\n\r\n//#define EPERM           1\r\n//#define ENOENT          2\r\n//#define ESRCH           3\r\n#define EINTR           4\r\n//#define EIO             5\r\n//#define ENXIO           6\r\n//#define E2BIG           7\r\n//#define ENOEXEC         8\r\n#define EBADF           9\r\n//#define ECHILD          10\r\n#define EAGAIN          11\r\n//#define ENOMEM          12\r\n#define EACCES          13\r\n#define EFAULT          14\r\n//#define EOSERR          15 // rk\r\n//#define EBUSY           16\r\n//#define EEXIST          17\r\n//#define EXDEV           18\r\n//#define ENODEV          19\r\n//#define ENOTDIR         20\r\n//#define EISDIR          21\r\n#define EINVAL          22\r\n//#define ENFILE          23\r\n#define EMFILE          24\r\n//#define ENOTTY          25\r\n//#define EFBIG           27\r\n//#define ENOSPC          28\r\n//#define ESPIPE          29\r\n//#define EROFS           30\r\n//#define EMLINK          31\r\n//#define EPIPE           32\r\n//#define EDOM            33\r\n//#define ERANGE          34\r\n//#define EDEADLK         36\r\n//#define ENOSYS          37\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\nextern int errno;\r\nextern int _doserrno;\r\nextern int _sys_nerr;\r\n\r\nchar* strerror(int errno);\r\n\r\n#define sys_nerr _sys_nerr\r\n\r\n#ifdef __cplusplus\r\n};\r\n#endif\r\n\r\n#endif"
  },
  {
    "path": "builds/deprecated-msvc/platform.hpp",
    "content": "#ifndef __PLATFORM_HPP_INCLUDED__\n#define __PLATFORM_HPP_INCLUDED__\n\n#define ZMQ_HAVE_WINDOWS\n\n// MSVC build configuration is controlled via options exposed in the Visual\n// Studio user interface. The option to use libsodium is not exposed in the\n// user interface unless a sibling `libsodium` directory to that of this\n// repository exists and contains the following files:\n//\n// \\builds\\msvc\\vs2015\\libsodium.import.props\n// \\builds\\msvc\\vs2015\\libsodium.import.xml\n\n#endif\n"
  },
  {
    "path": "builds/deprecated-msvc/properties/Common.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Common Settings</_PropertySheetDisplayName>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(Platform).props\" />\n  </ImportGroup>  \n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <PreprocessorDefinitions>UNICODE;_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level3</WarningLevel>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/DLL.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n    \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Dynamic Library</_PropertySheetDisplayName>\n    <DefaultLinkage>dynamic</DefaultLinkage>\n    <TargetExt>.dll</TargetExt>\n  </PropertyGroup>\n  \n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions>_DLL;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/Debug.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  \n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Common.props\" />\n  </ImportGroup>\n  \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Debug Settings</_PropertySheetDisplayName>\n    <DebugOrRelease>Debug</DebugOrRelease>\n  </PropertyGroup>\n  \n  <ItemDefinitionGroup>\n    <ClCompile>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>    \n  </ItemDefinitionGroup>\n  \n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/DebugDEXE.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Console Debug Dynamic</_PropertySheetDisplayName>\n    <DefaultLinkage>dynamic</DefaultLinkage>\n  </PropertyGroup>\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Debug.props\" />\n    <Import Project=\"EXE.props\" />\n  </ImportGroup>\n  \n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <LinkIncremental>true</LinkIncremental>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  \n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/DebugDLL.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Dynamic Debug Library</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Debug.props\" />\n    <Import Project=\"DLL.props\" />\n  </ImportGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <LinkIncremental>true</LinkIncremental>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  \n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/DebugLEXE.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Console Debug Link Time Code Generation</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Debug.props\" />\n    <Import Project=\"Link.props\" />\n    <Import Project=\"EXE.props\" />\n  </ImportGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/DebugLIB.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Static Debug Library</_PropertySheetDisplayName>\n  </PropertyGroup>\n  \n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Debug.props\" />\n    <Import Project=\"LIB.props\" />\n  </ImportGroup>\n  \n  <ItemDefinitionGroup>\n    <ClCompile>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <LinkIncremental>true</LinkIncremental>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/DebugLTCG.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Static Debug Link Time Code Generation Library</_PropertySheetDisplayName>\n  </PropertyGroup>\n  \n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Debug.props\" />\n    <Import Project=\"LTCG.props\" />\n  </ImportGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/DebugSEXE.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Console Debug Static</_PropertySheetDisplayName>\n    <DefaultLinkage>static</DefaultLinkage>\n  </PropertyGroup>\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Debug.props\" />\n    <Import Project=\"EXE.props\" />\n  </ImportGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <LinkIncremental>true</LinkIncremental>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/EXE.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n    \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Console Application</_PropertySheetDisplayName>\n    <IsExe>true</IsExe>    \n  </PropertyGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/LIB.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Static Library</_PropertySheetDisplayName>\n    <DefaultLinkage>static</DefaultLinkage>\n    <TargetExt>.lib</TargetExt>\n  </PropertyGroup>\n  \n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/LTCG.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Link Time Code Generation Library</_PropertySheetDisplayName>\n  </PropertyGroup>\n  \n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"LIB.props\" />\n    <Import Project=\"Link.props\" />\n  </ImportGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/Link.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n   \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Link Time Code Generation Settings</_PropertySheetDisplayName>\n    <DefaultLinkage>ltcg</DefaultLinkage>\n  </PropertyGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <WholeProgramOptimization>true</WholeProgramOptimization>\n    </ClCompile>\n    <Link>\n      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n    </Link>\n    <Lib>\n      <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>\n    </Lib>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/Messages.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Build Messages</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <Target Name=\"ConfigInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"ConfigurationType : $(ConfigurationType)\" Importance=\"high\"/>\n    <Message Text=\"Configuration     : $(Configuration)\" Importance=\"high\"/>\n    <Message Text=\"PlatformToolset   : $(PlatformToolset)\" Importance=\"high\"/>\n    <Message Text=\"TargetPath        : $(TargetPath)\" Importance=\"high\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/Output.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Output Settings</_PropertySheetDisplayName>\n    <!-- BuildRoot, RepoRoot, SourceRoot, DebugOrRelease and DefaultLinkage are custom props and should therefore not be referenced from *.import.props or nuget target files. -->\n    <BuildRoot>$(ProjectDir)..\\..\\</BuildRoot>\n    <RepoRoot>$(ProjectDir)..\\..\\..\\..\\</RepoRoot>\n    <SourceRoot>$(ProjectDir)..\\..\\..\\..\\..\\</SourceRoot>    \n    <OutDir>$(ProjectDir)..\\..\\..\\..\\bin\\$(PlatformName)\\$(DebugOrRelease)\\$(PlatformToolset)\\$(DefaultLinkage)\\</OutDir>\n    <IntDir>$(ProjectDir)..\\..\\..\\..\\obj\\$(TargetName)\\$(PlatformName)\\$(DebugOrRelease)\\$(PlatformToolset)\\$(DefaultLinkage)\\</IntDir>\n    <TargetDir>$(OutDir)</TargetDir>\n    <TargetName>$(TargetName)</TargetName>\n    <TargetPath>$(TargetDir)$(TargetName)$(TargetExt)</TargetPath>\n  </PropertyGroup>\n  \n  <ItemDefinitionGroup>\n    <Link>\n      <ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>\n    </Link>\n    <BuildLog>\n      <Path>$(OutDir)$(TargetName).log</Path>\n    </BuildLog> \n  </ItemDefinitionGroup>\n  \n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Messages.props\" />\n  </ImportGroup>    \n  \n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/Release.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Common.props\" />\n  </ImportGroup>\n  \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Release Settings</_PropertySheetDisplayName>\n    <DebugOrRelease>Release</DebugOrRelease>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  \n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalOptions>/Oy- %(AdditionalOptions)</AdditionalOptions>\n      <!--<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>-->\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <MinimalRebuild>false</MinimalRebuild>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <!--<GenerateDebugInformation>true</GenerateDebugInformation>-->\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link> \n  </ItemDefinitionGroup>\n\n  <ItemDefinitionGroup Condition=\"'$(Processor)' == 'x86'\">\n    <ClCompile>\n      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/ReleaseDEXE.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Console Release Dynamic</_PropertySheetDisplayName>\n    <DefaultLinkage>dynamic</DefaultLinkage>\n  </PropertyGroup>\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Release.props\" />\n    <Import Project=\"EXE.props\" />\n  </ImportGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/ReleaseDLL.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  \n  <PropertyGroup>\n    <_PropertySheetDisplayName>Dynamic Release Library</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Release.props\" />\n    <Import Project=\"DLL.props\" />\n  </ImportGroup>\n  \n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/ReleaseLEXE.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Console Release Link Time Code Generation</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Release.props\" />\n    <Import Project=\"Link.props\" />\n    <Import Project=\"EXE.props\" />\n  </ImportGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/ReleaseLIB.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Static Release Library</_PropertySheetDisplayName>\n  </PropertyGroup>\n  \n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Release.props\" />\n    <Import Project=\"LIB.props\" />\n  </ImportGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/ReleaseLTCG.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Static Release Link Time Code Generation Library</_PropertySheetDisplayName>\n  </PropertyGroup>\n  \n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Release.props\" />\n    <Import Project=\"LTCG.props\" />\n  </ImportGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/ReleaseSEXE.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>Console Release Static</_PropertySheetDisplayName>\n    <DefaultLinkage>static</DefaultLinkage>\n  </PropertyGroup>\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"Release.props\" />\n    <Import Project=\"EXE.props\" />\n  </ImportGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/Win32.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  \n  <PropertyGroup>\n    <_PropertySheetDisplayName>x86 Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n  \n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions>WIN32;_WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <TargetMachine>MachineX86</TargetMachine>\n    </Link>\n    <Lib>\n      <AdditionalOptions>/MACHINE:X86 %(AdditionalOptions)</AdditionalOptions>\n    </Lib>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/properties/x64.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  \n  <PropertyGroup>\n    <_PropertySheetDisplayName>x64 Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n    \n  <ItemDefinitionGroup>\n    <ClCompile>\n      <!-- Note that Win64 defines may cause WIN32 to become defined when using windows headers, \n      but _WIN32 implies Windows 32 bit or above. If the standard headers are not included \n      these are sometimes required even for 64 bit builds and should never cause harm there.-->\n      <PreprocessorDefinitions>WIN32;_WIN32;WIN64;_WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <TargetMachine>MachineX64</TargetMachine>\n    </Link>\n    <Lib>\n      <AdditionalOptions>/MACHINE:X64 %(AdditionalOptions)</AdditionalOptions>\n    </Lib>\n  </ItemDefinitionGroup>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/readme.txt",
    "content": "For building on Windows, use:\n\n     cd build\n     ./build.bat\n\nThis requires that the CMD.EXE be created using the DevStudio Tools link to create a CMD.EXE window. Also, make sure that the name of the project folder is libzmq (not e.g. libzmq-master) as this is required for correct linking.\n\nVisual Studio product and C++ compiler Versions:\n\nVisual C++ 2008 => Visual C++ 9\nVisual C++ 2010 => Visual C++ 10\nVisual C++ 2012 => Visual C++ 11\nVisual C++ 2013 => Visual C++ 12\nVisual C++ 2015 => Visual C++ 14\nVisual C++ 2017 => Visual C++ 15\n\nNote that solution file icons reflect the compiler version ([9], [10], [11], [12], [14], [15]), not the product version.\n\nThe vs2017/vs2015/vs2013/vs2012/vs2010 solution and project files differ only in versioning.\n\nMore info here:\n\nhttp://en.wikipedia.org/wiki/Visual_C%2B%2B\n\nIf multiple DevStudio versions are installed, you can run build.bat in separate windows each created by the desired DevStudio target.\n\nTo build for all versions of Visual Studio (excluding vs2008), you can run buildall.bat. This is generally a maintainer task.\n"
  },
  {
    "path": "builds/deprecated-msvc/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by resource.rc\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        101\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2008/inproc_lat/inproc_lat.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<VisualStudioProject ProjectType=\"Visual C++\" Version=\"9,00\" Name=\"inproc_lat\" ProjectGUID=\"{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}\" RootNamespace=\"inproc_lat\" TargetFrameworkVersion=\"196613\">\n  <Platforms>\n    <Platform Name=\"Win32\" />\n  </Platforms>\n  <ToolFiles />\n  <Configurations>\n    <Configuration Name=\"Debug|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"0\" MinimalRebuild=\"true\" BasicRuntimeChecks=\"3\" RuntimeLibrary=\"3\" WarningLevel=\"3\" DebugInformationFormat=\"4\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/inproc_lat.exe\" GenerateDebugInformation=\"true\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n    <Configuration Name=\"Release|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\" WholeProgramOptimization=\"1\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"2\" EnableIntrinsicFunctions=\"true\" RuntimeLibrary=\"2\" EnableFunctionLevelLinking=\"true\" WarningLevel=\"3\" DebugInformationFormat=\"3\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/inproc_lat.exe\" GenerateDebugInformation=\"true\" OptimizeReferences=\"2\" EnableCOMDATFolding=\"2\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n  </Configurations>\n  <References />\n  <Files>\n    <Filter Name=\"Source Files\" Filter=\"cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx\" UniqueIdentifier=\"{4FC737F1-C7A5-4376-A066-2A32D752A2FF}\">\n      <File RelativePath=\"..\\..\\..\\..\\perf\\inproc_lat.cpp\" />\n    </Filter>\n  </Files>\n  <Globals />\n</VisualStudioProject>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2008/inproc_thr/inproc_thr.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<VisualStudioProject ProjectType=\"Visual C++\" Version=\"9,00\" Name=\"inproc_thr\" ProjectGUID=\"{1077E977-95DD-4E73-A692-74647DD0CC1E}\" RootNamespace=\"inproc_thr\" TargetFrameworkVersion=\"196613\">\n  <Platforms>\n    <Platform Name=\"Win32\" />\n  </Platforms>\n  <ToolFiles />\n  <Configurations>\n    <Configuration Name=\"Debug|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"0\" MinimalRebuild=\"true\" BasicRuntimeChecks=\"3\" RuntimeLibrary=\"3\" WarningLevel=\"3\" DebugInformationFormat=\"4\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/inproc_thr.exe\" GenerateDebugInformation=\"true\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n    <Configuration Name=\"Release|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\" WholeProgramOptimization=\"1\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"2\" EnableIntrinsicFunctions=\"true\" RuntimeLibrary=\"2\" EnableFunctionLevelLinking=\"true\" WarningLevel=\"3\" DebugInformationFormat=\"3\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/inproc_thr.exe\" GenerateDebugInformation=\"true\" OptimizeReferences=\"2\" EnableCOMDATFolding=\"2\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n  </Configurations>\n  <References />\n  <Files>\n    <Filter Name=\"Source Files\" Filter=\"cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx\" UniqueIdentifier=\"{4FC737F1-C7A5-4376-A066-2A32D752A2FF}\">\n      <File RelativePath=\"..\\..\\..\\..\\perf\\inproc_thr.cpp\" />\n    </Filter>\n  </Files>\n  <Globals />\n</VisualStudioProject>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2008/libzmq/libzmq.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<VisualStudioProject ProjectType=\"Visual C++\" Version=\"9,00\" Name=\"libzmq\" ProjectGUID=\"{641C5F36-32EE-4323-B740-992B651CF9D6}\" RootNamespace=\"libzmq\" TargetFrameworkVersion=\"196613\">\n  <Platforms>\n    <Platform Name=\"Win32\" />\n  </Platforms>\n  <ToolFiles />\n  <Configurations>\n    <Configuration Name=\"Debug|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"2\" CharacterSet=\"2\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCWebServiceProxyGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" AdditionalOptions=\"-DDLL_EXPORT -DFD_SETSIZE=16384 -DZMQ_USE_SELECT -D_CRT_SECURE_NO_WARNINGS\" Optimization=\"0\" PreprocessorDefinitions=\"NOMINMAX\" MinimalRebuild=\"true\" BasicRuntimeChecks=\"3\" RuntimeLibrary=\"3\" WarningLevel=\"3\" DebugInformationFormat=\"4\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" AdditionalDependencies=\"Ws2_32.lib Rpcrt4.lib Advapi32.lib Iphlpapi.lib\" OutputFile=\"../../../../lib/libzmq.dll\" LinkDLL=\"true\" GenerateDebugInformation=\"true\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n    <Configuration Name=\"Release|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"2\" CharacterSet=\"2\" WholeProgramOptimization=\"1\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCWebServiceProxyGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" AdditionalOptions=\"-DDLL_EXPORT -DFD_SETSIZE=16384 -DZMQ_USE_SELECT -D_CRT_SECURE_NO_WARNINGS\" Optimization=\"2\" EnableIntrinsicFunctions=\"true\" RuntimeLibrary=\"2\" EnableFunctionLevelLinking=\"true\" WarningLevel=\"3\" DebugInformationFormat=\"3\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" AdditionalDependencies=\"Ws2_32.lib Rpcrt4.lib Advapi32.lib Iphlpapi.lib\" OutputFile=\"../../../../lib/libzmq.dll\" LinkDLL=\"true\" GenerateDebugInformation=\"true\" OptimizeReferences=\"2\" EnableCOMDATFolding=\"2\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n    <Configuration Name=\"StaticDebug|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"4\" CharacterSet=\"2\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCWebServiceProxyGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" AdditionalOptions=\"-DZMQ_STATIC -DFD_SETSIZE=16384 -DZMQ_USE_SELECT -D_CRT_SECURE_NO_WARNINGS\" Optimization=\"0\" PreprocessorDefinitions=\"NOMINMAX\" MinimalRebuild=\"true\" BasicRuntimeChecks=\"3\" RuntimeLibrary=\"3\" WarningLevel=\"3\" DebugInformationFormat=\"4\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLibrarianTool\" AdditionalOptions=\"/ignore:4006\" AdditionalDependencies=\"Ws2_32.lib Rpcrt4.lib Advapi32.lib Iphlpapi.lib\" OutputFile=\"../../../../lib/libzmq_d.lib\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n    <Configuration Name=\"StaticRelease|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"4\" CharacterSet=\"2\" WholeProgramOptimization=\"1\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCWebServiceProxyGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" AdditionalOptions=\"-DZMQ_STATIC -DFD_SETSIZE=16384 -DZMQ_USE_SELECT -D_CRT_SECURE_NO_WARNINGS\" Optimization=\"2\" EnableIntrinsicFunctions=\"true\" RuntimeLibrary=\"2\" EnableFunctionLevelLinking=\"true\" WarningLevel=\"3\" DebugInformationFormat=\"3\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLibrarianTool\" AdditionalOptions=\"/ignore:4006\" AdditionalDependencies=\"Ws2_32.lib Rpcrt4.lib Advapi32.lib Iphlpapi.lib\" OutputFile=\"../../../../lib/libzmq.lib\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n    <Configuration Name=\"WithOpenPGM|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"2\" CharacterSet=\"2\" WholeProgramOptimization=\"1\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCWebServiceProxyGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" AdditionalOptions=\"-DDLL_EXPORT -DFD_SETSIZE=16384 -DZMQ_USE_SELECT -D_CRT_SECURE_NO_WARNINGS\" Optimization=\"2\" EnableIntrinsicFunctions=\"true\" AdditionalIncludeDirectories=\"../../../../OpenPGM/include\" PreprocessorDefinitions=\"ZMQ_HAVE_OPENPGM\" RuntimeLibrary=\"2\" EnableFunctionLevelLinking=\"true\" WarningLevel=\"3\" DebugInformationFormat=\"3\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" AdditionalDependencies=\"Ws2_32.lib Rpcrt4.lib Advapi32.lib Iphlpapi.lib libpgm.lib\" OutputFile=\"../../../../lib/libzmq.dll\" AdditionalLibraryDirectories=\"../../../../../OpenPGM/lib\" LinkDLL=\"true\" GenerateDebugInformation=\"true\" OptimizeReferences=\"2\" EnableCOMDATFolding=\"2\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n  </Configurations>\n  <References />\n  <Files>\n    <Filter Name=\"Source Files\" Filter=\"cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx\" UniqueIdentifier=\"{4FC737F1-C7A5-4376-A066-2A32D752A2FF}\">\n      <File RelativePath=\"..\\..\\errno.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\address.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\client.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\clock.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ctx.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\curve_client.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\curve_mechanism_base.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\curve_server.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\dealer.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\devpoll.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\dgram.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\dish.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\dist.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\epoll.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\err.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\fq.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\gather.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\gssapi_client.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\gssapi_server.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\io_object.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\io_thread.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ipc_address.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ipc_listener.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ip.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\kqueue.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\lb.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mailbox.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mechanism_base.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mechanism.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\metadata.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\msg.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mtrie.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\norm_engine.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\null_mechanism.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\object.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\options.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\own.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pair.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pgm_sender.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pgm_socket.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pipe.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\plain_client.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\plain_server.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\poll.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\poller_base.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pollset.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\precompiled.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\proxy.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pub.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pull.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\push.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\radio.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\random.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\raw_decoder.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\raw_encoder.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\reaper.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\rep.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\req.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\router.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\scatter.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\select.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\server.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\session_base.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\signaler.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\socket_base.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\socket_poller.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\socks_connecter.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\socks.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\stream.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\stream_engine.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\sub.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tcp_address.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tcp.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tcp_listener.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\thread.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\timers.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tipc_address.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tipc_connecter.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tipc_listener.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\trie.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\udp_address.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\udp_engine.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\v1_decoder.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\v1_encoder.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\v2_decoder.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\v2_encoder.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\vmci_address.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\vmci_connecter.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\vmci.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\vmci_listener.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\xpub.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\xsub.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\zap_client.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\zmq.cpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\zmq_utils.cpp\" />\n    </Filter>\n    <Filter Name=\"Header Files\" Filter=\"h;hpp;hxx;hm;inl;inc;xsd\" UniqueIdentifier=\"{93995380-89BD-4b04-88EB-625FBE52EBFB}\">\n      <File RelativePath=\"..\\..\\errno.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\address.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\array.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\atomic_counter.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\blob.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\client.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\clock.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\command.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\condition_variable.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\config.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ctx.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\curve_client.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\curve_client_tools.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\curve_mechanism_base.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\curve_server.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\dbuffer.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\dealer.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\decoder.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\devpoll.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\dgram.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\dish.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\dist.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\encoder.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\epoll.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\err.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\fd.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\fq.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\gather.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\gssapi_client.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\gssapi_server.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\i_decoder.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\i_encoder.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\i_engine.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\i_mailbox.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\io_object.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\io_thread.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ipc_address.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ipc_listener.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ip.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\i_poll_events.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\kqueue.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\lb.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\likely.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\macros.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mailbox.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mechanism_base.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mechanism.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\metadata.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\msg.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mtrie.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\mutex.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\norm_engine.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\null_mechanism.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\object.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\options.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\own.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pair.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pgm_sender.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pgm_socket.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pipe.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\plain_client.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\plain_server.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\platform.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\poller_base.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\poller.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\poll.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pollset.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\precompiled.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\proxy.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pub.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\pull.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\push.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\radio.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\random.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\raw_decoder.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\raw_encoder.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\reaper.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\rep.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\req.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\router.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\scatter.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\select.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\server.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\session_base.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\signaler.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\socket_base.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\socket_poller.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\socks_connecter.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\socks.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\stdint.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\stream_engine.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\stream.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\sub.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tcp_address.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tcp.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tcp_listener.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\thread.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\timers.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tipc_address.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tipc_connecter.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\tipc_listener.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\trie.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\udp_address.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\udp_engine.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\v1_decoder.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\v1_encoder.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\v2_decoder.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\v2_encoder.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\v2_protocol.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\vmci_address.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\vmci_connecter.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\vmci.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\vmci_listener.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\windows.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\wire.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\xpub.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\xsub.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ypipe_base.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ypipe_conflate.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\ypipe.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\yqueue.hpp\" />\n      <File RelativePath=\"..\\..\\..\\..\\src\\zap_client.hpp\" />\n    </Filter>\n  </Files>\n  <Globals />\n</VisualStudioProject>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2008/libzmq.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 10.00\n# Visual Studio 2008\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libzmq\", \"libzmq\\libzmq.vcproj\", \"{641C5F36-32EE-4323-B740-992B651CF9D6}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_lat\", \"local_lat\\local_lat.vcproj\", \"{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6} = {641C5F36-32EE-4323-B740-992B651CF9D6}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_lat\", \"remote_lat\\remote_lat.vcproj\", \"{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6} = {641C5F36-32EE-4323-B740-992B651CF9D6}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_thr\", \"local_thr\\local_thr.vcproj\", \"{8EF2DF6B-6646-460F-8032-913B70FE0E94}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6} = {641C5F36-32EE-4323-B740-992B651CF9D6}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_thr\", \"remote_thr\\remote_thr.vcproj\", \"{B15E059C-0CBB-4A82-8C42-6567FB650802}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6} = {641C5F36-32EE-4323-B740-992B651CF9D6}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_lat\", \"inproc_lat\\inproc_lat.vcproj\", \"{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6} = {641C5F36-32EE-4323-B740-992B651CF9D6}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_thr\", \"inproc_thr\\inproc_thr.vcproj\", \"{1077E977-95DD-4E73-A692-74647DD0CC1E}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6} = {641C5F36-32EE-4323-B740-992B651CF9D6}\n\tEndProjectSection\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Win32 = Debug|Win32\n\t\tRelease|Win32 = Release|Win32\n\t\tStaticDebug|Win32 = StaticDebug|Win32\n\t\tStaticRelease|Win32 = StaticRelease|Win32\n\t\tWithOpenPGM|Win32 = WithOpenPGM|Win32\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.Release|Win32.Build.0 = Release|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.ActiveCfg = StaticDebug|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.Build.0 = StaticDebug|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.ActiveCfg = StaticRelease|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.Build.0 = StaticRelease|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.WithOpenPGM|Win32.ActiveCfg = WithOpenPGM|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.WithOpenPGM|Win32.Build.0 = WithOpenPGM|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.Release|Win32.Build.0 = Release|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.WithOpenPGM|Win32.ActiveCfg = Release|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.WithOpenPGM|Win32.Build.0 = Release|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.Release|Win32.Build.0 = Release|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.WithOpenPGM|Win32.ActiveCfg = Release|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.WithOpenPGM|Win32.Build.0 = Release|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.Release|Win32.Build.0 = Release|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.WithOpenPGM|Win32.ActiveCfg = Release|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.WithOpenPGM|Win32.Build.0 = Release|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.Release|Win32.Build.0 = Release|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.WithOpenPGM|Win32.ActiveCfg = Release|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.WithOpenPGM|Win32.Build.0 = Release|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.Release|Win32.Build.0 = Release|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.WithOpenPGM|Win32.ActiveCfg = Release|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.WithOpenPGM|Win32.Build.0 = Release|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.Release|Win32.Build.0 = Release|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.WithOpenPGM|Win32.ActiveCfg = Release|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.WithOpenPGM|Win32.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2008/local_lat/local_lat.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<VisualStudioProject ProjectType=\"Visual C++\" Version=\"9.00\" Name=\"local_lat\" ProjectGUID=\"{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}\" RootNamespace=\"local_lat\" TargetFrameworkVersion=\"196613\">\n  <Platforms>\n    <Platform Name=\"Win32\" />\n  </Platforms>\n  <ToolFiles />\n  <Configurations>\n    <Configuration Name=\"Debug|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\">\n      <Tool Name=\"VCPreBuildEventTool\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"0\" AdditionalIncludeDirectories=\"../../../../bindings/c\" MinimalRebuild=\"true\" BasicRuntimeChecks=\"3\" RuntimeLibrary=\"3\" WarningLevel=\"3\" DebugInformationFormat=\"4\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/local_lat.exe\" GenerateDebugInformation=\"true\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n    <Configuration Name=\"Release|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\" WholeProgramOptimization=\"1\">\n      <Tool Name=\"VCPreBuildEventTool\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"2\" EnableIntrinsicFunctions=\"true\" AdditionalIncludeDirectories=\"../../../../bindings/c\" RuntimeLibrary=\"2\" EnableFunctionLevelLinking=\"true\" WarningLevel=\"3\" DebugInformationFormat=\"3\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/local_lat.exe\" GenerateDebugInformation=\"true\" OptimizeReferences=\"2\" EnableCOMDATFolding=\"2\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n  </Configurations>\n  <References />\n  <Files>\n    <Filter Name=\"Source Files\" Filter=\"cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx\" UniqueIdentifier=\"{4FC737F1-C7A5-4376-A066-2A32D752A2FF}\">\n      <File RelativePath=\"..\\..\\..\\..\\perf\\local_lat.cpp\" />\n    </Filter>\n  </Files>\n  <Globals />\n</VisualStudioProject>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2008/local_thr/local_thr.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<VisualStudioProject ProjectType=\"Visual C++\" Version=\"9.00\" Name=\"local_thr\" ProjectGUID=\"{8EF2DF6B-6646-460F-8032-913B70FE0E94}\" RootNamespace=\"local_thr\" TargetFrameworkVersion=\"196613\">\n  <Platforms>\n    <Platform Name=\"Win32\" />\n  </Platforms>\n  <ToolFiles />\n  <Configurations>\n    <Configuration Name=\"Debug|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"0\" AdditionalIncludeDirectories=\"../../../../bindings/c\" MinimalRebuild=\"true\" BasicRuntimeChecks=\"3\" RuntimeLibrary=\"3\" WarningLevel=\"3\" DebugInformationFormat=\"4\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/local_thr.exe\" GenerateDebugInformation=\"true\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n    <Configuration Name=\"Release|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\" WholeProgramOptimization=\"1\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"2\" EnableIntrinsicFunctions=\"true\" AdditionalIncludeDirectories=\"../../../../bindings/c\" RuntimeLibrary=\"2\" EnableFunctionLevelLinking=\"true\" WarningLevel=\"3\" DebugInformationFormat=\"3\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/local_thr.exe\" GenerateDebugInformation=\"true\" OptimizeReferences=\"2\" EnableCOMDATFolding=\"2\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n  </Configurations>\n  <References />\n  <Files>\n    <Filter Name=\"Source Files\" Filter=\"cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx\" UniqueIdentifier=\"{4FC737F1-C7A5-4376-A066-2A32D752A2FF}\">\n      <File RelativePath=\"..\\..\\..\\..\\perf\\local_thr.cpp\" />\n    </Filter>\n  </Files>\n  <Globals />\n</VisualStudioProject>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2008/remote_lat/remote_lat.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<VisualStudioProject ProjectType=\"Visual C++\" Version=\"9.00\" Name=\"remote_lat\" ProjectGUID=\"{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}\" RootNamespace=\"remote_lat\" TargetFrameworkVersion=\"196613\">\n  <Platforms>\n    <Platform Name=\"Win32\" />\n  </Platforms>\n  <ToolFiles />\n  <Configurations>\n    <Configuration Name=\"Debug|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\">\n      <Tool Name=\"VCPreBuildEventTool\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"0\" AdditionalIncludeDirectories=\"../../../../bindings/c\" MinimalRebuild=\"true\" BasicRuntimeChecks=\"3\" RuntimeLibrary=\"3\" WarningLevel=\"3\" DebugInformationFormat=\"4\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/remote_lat.exe\" GenerateDebugInformation=\"true\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n    <Configuration Name=\"Release|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\" WholeProgramOptimization=\"1\">\n      <Tool Name=\"VCPreBuildEventTool\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"2\" EnableIntrinsicFunctions=\"true\" AdditionalIncludeDirectories=\"../../../../bindings/c\" RuntimeLibrary=\"2\" EnableFunctionLevelLinking=\"true\" WarningLevel=\"3\" DebugInformationFormat=\"3\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/remote_lat.exe\" GenerateDebugInformation=\"true\" OptimizeReferences=\"2\" EnableCOMDATFolding=\"2\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n  </Configurations>\n  <References />\n  <Files>\n    <Filter Name=\"Source Files\" Filter=\"cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx\" UniqueIdentifier=\"{4FC737F1-C7A5-4376-A066-2A32D752A2FF}\">\n      <File RelativePath=\"..\\..\\..\\..\\perf\\remote_lat.cpp\" />\n    </Filter>\n  </Files>\n  <Globals />\n</VisualStudioProject>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2008/remote_thr/remote_thr.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<VisualStudioProject ProjectType=\"Visual C++\" Version=\"9.00\" Name=\"remote_thr\" ProjectGUID=\"{B15E059C-0CBB-4A82-8C42-6567FB650802}\" RootNamespace=\"remote_thr\" TargetFrameworkVersion=\"196613\">\n  <Platforms>\n    <Platform Name=\"Win32\" />\n  </Platforms>\n  <ToolFiles />\n  <Configurations>\n    <Configuration Name=\"Debug|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"0\" AdditionalIncludeDirectories=\"../../../../bindings/c\" MinimalRebuild=\"true\" BasicRuntimeChecks=\"3\" RuntimeLibrary=\"3\" WarningLevel=\"3\" DebugInformationFormat=\"4\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/remote_thr.exe\" GenerateDebugInformation=\"true\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n    <Configuration Name=\"Release|Win32\" OutputDirectory=\"$(SolutionDir)$(ConfigurationName)\" IntermediateDirectory=\"$(ConfigurationName)\" ConfigurationType=\"1\" CharacterSet=\"2\" WholeProgramOptimization=\"1\">\n      <Tool Name=\"VCPreBuildEventTool\" CommandLine=\"copy ..\\..\\platform.hpp ..\\..\\..\\..\\src\" />\n      <Tool Name=\"VCCustomBuildTool\" />\n      <Tool Name=\"VCXMLDataGeneratorTool\" />\n      <Tool Name=\"VCMIDLTool\" />\n      <Tool Name=\"VCCLCompilerTool\" Optimization=\"2\" EnableIntrinsicFunctions=\"true\" AdditionalIncludeDirectories=\"../../../../bindings/c\" RuntimeLibrary=\"2\" EnableFunctionLevelLinking=\"true\" WarningLevel=\"3\" DebugInformationFormat=\"3\" />\n      <Tool Name=\"VCManagedResourceCompilerTool\" />\n      <Tool Name=\"VCResourceCompilerTool\" />\n      <Tool Name=\"VCPreLinkEventTool\" />\n      <Tool Name=\"VCLinkerTool\" OutputFile=\"../../../../bin/remote_thr.exe\" GenerateDebugInformation=\"true\" OptimizeReferences=\"2\" EnableCOMDATFolding=\"2\" TargetMachine=\"1\" />\n      <Tool Name=\"VCALinkTool\" />\n      <Tool Name=\"VCManifestTool\" />\n      <Tool Name=\"VCXDCMakeTool\" />\n      <Tool Name=\"VCBscMakeTool\" />\n      <Tool Name=\"VCFxCopTool\" />\n      <Tool Name=\"VCAppVerifierTool\" />\n      <Tool Name=\"VCPostBuildEventTool\" />\n    </Configuration>\n  </Configurations>\n  <References />\n  <Files>\n    <Filter Name=\"Source Files\" Filter=\"cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx\" UniqueIdentifier=\"{4FC737F1-C7A5-4376-A066-2A32D752A2FF}\">\n      <File RelativePath=\"..\\..\\..\\..\\perf\\remote_thr.cpp\" />\n    </Filter>\n  </Files>\n  <Globals />\n</VisualStudioProject>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/inproc_lat/inproc_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ inproc_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\"  Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/inproc_lat/inproc_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}</ProjectGuid>\n    <ProjectName>inproc_lat</ProjectName>\n    <PlatformToolset>v100</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\inproc_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/inproc_thr/inproc_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ inproc_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/inproc_thr/inproc_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{1077E977-95DD-4E73-A692-74647DD0CC1E}</ProjectGuid>\n    <ProjectName>inproc_thr</ProjectName>\n    <PlatformToolset>v100</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\inproc_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/libsodium.import.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"Globals\">\n    <_PropertySheetDisplayName>Libsodium Import Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)libsodium.import.xml\" />\n  </ItemGroup>\n\n  <!-- Linkage -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\src\\libsodium\\include;$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\src\\libsodium\\include\\sodium\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Linkage-libsodium)' == 'static' Or '$(Linkage-libsodium)' == 'ltcg'\">SODIUM_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(Linkage-libsodium)' != ''\">advapi32.lib;libsodium.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Debug')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\$(Linkage-libsodium)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Release')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\$(Linkage-libsodium)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Copy -->\n\n  <Target Name=\"Linkage-libsodium-dynamic\" AfterTargets=\"AfterBuild\" Condition=\"'$(Linkage-libsodium)' == 'dynamic'\">\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libsodium.dll\"\n          DestinationFiles=\"$(TargetDir)libsodium.dll\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libsodium.pdb\"\n          DestinationFiles=\"$(TargetDir)libsodium.pdb\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Release')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\dynamic\\libsodium.dll\"\n          DestinationFiles=\"$(TargetDir)libsodium.dll\"\n          SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <!-- Messages -->\n\n  <Target Name=\"libsodium-info\" BeforeTargets=\"AfterBuild\" Condition=\"'$(Linkage-libsodium)' == 'dynamic'\">\n    <Message Text=\"Copying libsodium.dll -&gt; $(TargetDir)libsodium.dll\" Importance=\"high\"/>\n    <Message Text=\"Copying libsodium.pdb -&gt; $(TargetDir)libsodium.pdb\" Importance=\"high\" Condition=\"$(Configuration.IndexOf('Debug')) != -1\" />\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/libsodium.import.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libsodium-linkage-uiextension\" PageTemplate=\"tool\" DisplayName=\"Local Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"libsodium\" DisplayName=\"libsodium\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-libsodium\" DisplayName=\"Linkage\" Description=\"How libsodium will be linked into the output of this project\" Category=\"libsodium\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/libzmq/libzmq.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ Library Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)$(ProjectName).xml\" />\n  </ItemGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;$(ProjectDir)..\\..\\..\\..\\include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <EnablePREfast>false</EnablePREfast>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>precompiled.hpp</PrecompiledHeaderFile>\n      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;FD_SETSIZE=16384;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_HAVE_CURVE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-openpgm)' == 'true'\">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-gssapi)' == 'true'\">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-draftapi)' == 'true'\">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-usepoll)' == 'true'\">ZMQ_USE_POLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-usepoll)' != 'true'\">ZMQ_USE_SELECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)' == 'StaticLibrary'\">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)' == 'DynamicLibrary'\">DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Ws2_32.lib;Rpcrt4.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Lib Condition=\"'$(ConfigurationType)'=='StaticLibrary'\">\n      <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions>\n    </Lib>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"OptionInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Option-sodium     : $(Option-sodium)\" Importance=\"high\"/>\n    <Message Text=\"Option-openpgm    : $(Option-openpgm)\" Importance=\"high\"/>\n    <Message Text=\"Option-gssapi     : $(Option-gssapi)\" Importance=\"high\"/>\n    <Message Text=\"Option-draftapi   : $(Option-draftapi)\" Importance=\"high\"/>\n    <Message Text=\"Option-usepoll    : $(Option-usepoll)\" Importance=\"high\"/>\n  </Target>\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(Option-sodium)' == 'true'\"/>\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/libzmq/libzmq.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{641C5F36-32EE-4323-B740-992B651CF9D6}</ProjectGuid>\n    <ProjectName>libzmq</ProjectName>\n    <PlatformToolset>v100</PlatformToolset>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDLL|Win32\">\n      <Configuration>DebugDLL</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDLL|Win32\">\n      <Configuration>ReleaseDLL</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDLL|x64\">\n      <Configuration>DebugDLL</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDLL|x64\">\n      <Configuration>ReleaseDLL</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLTCG|Win32\">\n      <Configuration>DebugLTCG</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLTCG|Win32\">\n      <Configuration>ReleaseLTCG</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLTCG|x64\">\n      <Configuration>DebugLTCG</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLTCG|x64\">\n      <Configuration>ReleaseLTCG</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLIB|Win32\">\n      <Configuration>DebugLIB</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLIB|Win32\">\n      <Configuration>ReleaseLIB</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLIB|x64\">\n      <Configuration>DebugLIB</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLIB|x64\">\n      <Configuration>ReleaseLIB</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Configuration\">\n    <ConfigurationType Condition=\"$(Configuration.IndexOf('DLL')) == -1\">StaticLibrary</ConfigurationType>\n    <ConfigurationType Condition=\"$(Configuration.IndexOf('DLL')) != -1\">DynamicLibrary</ConfigurationType>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n    <ClInclude Include=\"..\\..\\resource.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\include\\zmq.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\zmq_draft.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\array.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_counter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\blob.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\clock.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\command.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\condition_variable.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\config.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ctx.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\devpoll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dgram.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dish.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dist.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\epoll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\err.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fd.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fq.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gather.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_poll_events.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_object.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_thread.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_listener.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\kqueue.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\lb.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\likely.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\msg.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mtrie.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mutex.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\object.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\options.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\own.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pair.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_sender.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_socket.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pipe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\precompiled.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\proxy.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pull.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\push.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\radio.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\random.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\reaper.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\rep.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\req.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\scatter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\select.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\session_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\signaler.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socket_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stdint.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stream_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\sub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_listener.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\timers.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\thread.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\trie.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_protocol.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\windows.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\wire.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xpub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xrep.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xreq.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xsub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ypipe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\yqueue.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\clock.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ctx.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dealer.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\devpoll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dgram.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dish.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dist.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\epoll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\err.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\fq.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gather.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_object.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_thread.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_listener.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\kqueue.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\lb.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\metadata.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\msg.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mtrie.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\null_mechanism.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\object.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\options.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\own.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pair.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_sender.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_socket.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pipe.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poller_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\precompiled.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\proxy.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pull.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\push.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\radio.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\random.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\reaper.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\rep.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\req.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\router.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\scatter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\select.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\session_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\signaler.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_poller.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream_engine.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\sub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_listener.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\thread.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\timers.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\trie.cpp\" />\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_engine.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xpub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xsub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zap_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq_utils.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.bat\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.config\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.gsl\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.nuspec\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.targets\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"..\\..\\..\\..\\packaging\\nuget\\package.xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\..\\resource.rc\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/libzmq/libzmq.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\clock.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ctx.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dealer.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\devpoll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dgram.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dist.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\epoll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\err.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\fq.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_object.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_thread.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_listener.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\kqueue.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\lb.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\metadata.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\msg.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mtrie.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\null_mechanism.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\object.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\options.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\own.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pair.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_sender.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_socket.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pipe.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poller_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\proxy.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pull.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\push.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\random.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\reaper.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\rep.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\req.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\router.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\scatter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\select.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\session_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\signaler.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream_engine.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\sub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_listener.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\thread.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\trie.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xpub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xsub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq_utils.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\precompiled.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gather.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_poller.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_engine.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dish.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\radio.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\timers.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\..\\..\\include\\zmq.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\array.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_counter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\blob.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\clock.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\command.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\config.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ctx.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\devpoll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dgram.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dist.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\epoll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\err.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fd.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fq.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_poll_events.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_object.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_thread.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_listener.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\kqueue.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\lb.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\likely.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\msg.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mtrie.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mutex.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\object.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\options.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\own.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pair.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\yqueue.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ypipe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xsub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xreq.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xrep.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xpub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\wire.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\windows.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_protocol.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\trie.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\thread.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_listener.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\sub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stream_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stdint.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socket_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\signaler.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\session_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\scatter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\select.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\req.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\rep.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\reaper.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\random.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\push.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pull.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\proxy.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\precompiled.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\platform.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pipe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_socket.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_sender.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\resource.h\">\n      <Filter>resource</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gather.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\condition_variable.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dish.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\radio.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\timers.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\zmq_draft.h\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"include\">\n      <UniqueIdentifier>{f7e88c6c-e408-4631-959c-fe3568656d70}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"src\">\n      <UniqueIdentifier>{35f0c644-e1d8-4a46-bb33-06bb8b645fff}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"src\\include\">\n      <UniqueIdentifier>{90853975-3420-4f06-8be4-4ab3d9792160}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"packaging\">\n      <UniqueIdentifier>{f5e26e9d-c33d-45c1-95e4-0732acd28b59}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"resource\">\n      <UniqueIdentifier>{e66010e4-a9ea-4e2e-8bc6-12fec14bb009}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.bat\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.config\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.gsl\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.targets\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.nuspec\">\n      <Filter>packaging</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"..\\..\\..\\..\\packaging\\nuget\\package.xml\">\n      <Filter>packaging</Filter>\n    </Xml>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\..\\resource.rc\">\n      <Filter>resource</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/libzmq/libzmq.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libzmq-uiextension\" PageTemplate=\"tool\" DisplayName=\"ZMQ Options\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"sodium\" DisplayName=\"sodium\" />\n      <Category Name=\"openpgm\" DisplayName=\"openpgm\" />\n      <Category Name=\"gssapi\" DisplayName=\"gssapi\" />\n      <Category Name=\"draftapi\" DisplayName=\"draftapi\" />\n      <Category Name=\"usepoll\" DisplayName=\"usepoll\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Option-sodium\" DisplayName=\"Enable Sodium\" Description=\"Enable Sodium build option\" Category=\"sodium\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-openpgm\" DisplayName=\"Enable OpenPGM\" Description=\"Enable OpenPGM build option\" Category=\"openpgm\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-gssapi\" DisplayName=\"Enable GSS API\" Description=\"Enable GSS API build option\" Category=\"gssapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-draftapi\" DisplayName=\"Enable Draft API\" Description=\"Enable Draft API build option\" Category=\"draftapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-usepoll\" DisplayName=\"Enable poll() usage (Vista+ only)\" Description=\"Use poll() instead of select() for waiting on incoming data. Increases performance, but the binary will only run on Windows Vista or later.\" Category=\"usepoll\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/libzmq.import.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"Globals\">\n    <_PropertySheetDisplayName>ZMQ Import Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)libzmq.import.xml\" />\n  </ItemGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-openpgm)' == 'true'\">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-gssapi)' == 'true'\">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-draftapi)' == 'true'\">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <!-- Linkage -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Linkage-libzmq)' == 'static' Or '$(Linkage-libzmq)' == 'ltcg'\">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(Linkage-libzmq)' != ''\">libzmq.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Debug')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\$(Linkage-libzmq)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Release')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\$(Linkage-libzmq)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Copy -->\n\n  <Target Name=\"Linkage-libzmq-dynamic\" AfterTargets=\"AfterBuild\" Condition=\"'$(Linkage-libzmq)' == 'dynamic'\">\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libzmq.dll\"\n          DestinationFiles=\"$(TargetDir)libzmq.dll\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libzmq.pdb\"\n          DestinationFiles=\"$(TargetDir)libzmq.pdb\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Release')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\dynamic\\libzmq.dll\"\n          DestinationFiles=\"$(TargetDir)libzmq.dll\"\n          SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <!-- Messages -->\n\n  <Target Name=\"libzmq-info\" BeforeTargets=\"AfterBuild\" Condition=\"'$(Linkage-libzmq)' == 'dynamic'\">\n    <Message Text=\"Copying libzmq.dll -&gt; $(TargetDir)libzmq.dll\" Importance=\"high\"/>\n    <Message Text=\"Copying libzmq.pdb -&gt; $(TargetDir)libzmq.pdb\" Importance=\"high\" Condition=\"$(Configuration.IndexOf('Debug')) != -1\" />\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/libzmq.import.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libzmq-options-uiextension\" PageTemplate=\"tool\" DisplayName=\"ZMQ Options\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"sodium\" DisplayName=\"sodium\" />\n      <Category Name=\"openpgm\" DisplayName=\"openpgm\" />\n      <Category Name=\"gssapi\" DisplayName=\"gssapi\" />\n      <Category Name=\"draftapi\" DisplayName=\"draftapi\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Option-sodium\" DisplayName=\"Enable Sodium\" Description=\"Enable the Sodium build option\" Category=\"sodium\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-openpgm\" DisplayName=\"Enable OpenPGM\" Description=\"Enable the OpenPGM build option\" Category=\"openpgm\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-gssapi\" DisplayName=\"Enable GSS API\" Description=\"Enable the GSS API build option\" Category=\"gssapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-draftapi\" DisplayName=\"Enable Draft API\" Description=\"Enable Draft API build option\" Category=\"draftapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n  </Rule>\n  <Rule Name=\"libzmq-linkage-uiextension\" PageTemplate=\"tool\" DisplayName=\"Local Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"libzmq\" DisplayName=\"libzmq\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-libzmq\" DisplayName=\"Linkage\" Description=\"How libzmq will be linked into the output of this project\" Category=\"libzmq\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/libzmq.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 11.00\n# Visual Studio 2010\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libzmq\", \"libzmq\\libzmq.vcxproj\", \"{641C5F36-32EE-4323-B740-992B651CF9D6}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_thr\", \"inproc_thr\\inproc_thr.vcxproj\", \"{1077E977-95DD-4E73-A692-74647DD0CC1E}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_lat\", \"inproc_lat\\inproc_lat.vcxproj\", \"{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_thr\", \"remote_thr\\remote_thr.vcxproj\", \"{B15E059C-0CBB-4A82-8C42-6567FB650802}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_lat\", \"remote_lat\\remote_lat.vcxproj\", \"{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_thr\", \"local_thr\\local_thr.vcxproj\", \"{8EF2DF6B-6646-460F-8032-913B70FE0E94}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_lat\", \"local_lat\\local_lat.vcxproj\", \"{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDynDebug|Win32 = DynDebug|Win32\n\t\tDynDebug|x64 = DynDebug|x64\n\t\tDynRelease|Win32 = DynRelease|Win32\n\t\tDynRelease|x64 = DynRelease|x64\n\t\tLtcgDebug|Win32 = LtcgDebug|Win32\n\t\tLtcgDebug|x64 = LtcgDebug|x64\n\t\tLtcgRelease|Win32 = LtcgRelease|Win32\n\t\tLtcgRelease|x64 = LtcgRelease|x64\n\t\tStaticDebug|Win32 = StaticDebug|Win32\n\t\tStaticDebug|x64 = StaticDebug|x64\n\t\tStaticRelease|Win32 = StaticRelease|Win32\n\t\tStaticRelease|x64 = StaticRelease|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|Win32.ActiveCfg = DebugDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|Win32.Build.0 = DebugDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|x64.ActiveCfg = DebugDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|x64.Build.0 = DebugDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|Win32.ActiveCfg = ReleaseDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|Win32.Build.0 = ReleaseDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|x64.ActiveCfg = ReleaseDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|x64.Build.0 = ReleaseDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|Win32.ActiveCfg = DebugLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|Win32.Build.0 = DebugLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|x64.ActiveCfg = DebugLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|x64.Build.0 = DebugLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|Win32.ActiveCfg = ReleaseLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|Win32.Build.0 = ReleaseLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|x64.ActiveCfg = ReleaseLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|x64.Build.0 = ReleaseLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.ActiveCfg = DebugLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.Build.0 = DebugLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|x64.ActiveCfg = DebugLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|x64.Build.0 = DebugLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.ActiveCfg = ReleaseLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.Build.0 = ReleaseLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|x64.ActiveCfg = ReleaseLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|x64.Build.0 = ReleaseLIB|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/local_lat/local_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ local_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/local_lat/local_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}</ProjectGuid>\n    <ProjectName>local_lat</ProjectName>\n    <PlatformToolset>v100</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\local_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/local_thr/local_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ local_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/local_thr/local_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{8EF2DF6B-6646-460F-8032-913B70FE0E94}</ProjectGuid>\n    <ProjectName>local_thr</ProjectName>\n    <PlatformToolset>v100</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\local_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/remote_lat/remote_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ remote_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/remote_lat/remote_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}</ProjectGuid>\n    <ProjectName>remote_lat</ProjectName>\n    <PlatformToolset>v100</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\remote_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/remote_thr/remote_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ remote_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n  \n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2010/remote_thr/remote_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{B15E059C-0CBB-4A82-8C42-6567FB650802}</ProjectGuid>\n    <ProjectName>remote_thr</ProjectName>\n    <PlatformToolset>v100</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\remote_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/inproc_lat/inproc_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ inproc_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\"  Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/inproc_lat/inproc_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}</ProjectGuid>\n    <ProjectName>inproc_lat</ProjectName>\n    <PlatformToolset>v110</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\inproc_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/inproc_thr/inproc_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ inproc_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/inproc_thr/inproc_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{1077E977-95DD-4E73-A692-74647DD0CC1E}</ProjectGuid>\n    <ProjectName>inproc_thr</ProjectName>\n    <PlatformToolset>v110</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\inproc_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/libsodium.import.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"Globals\">\n    <_PropertySheetDisplayName>Libsodium Import Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)libsodium.import.xml\" />\n  </ItemGroup>\n\n  <!-- Linkage -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\src\\libsodium\\include;$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\src\\libsodium\\include\\sodium\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Linkage-libsodium)' == 'static' Or '$(Linkage-libsodium)' == 'ltcg'\">SODIUM_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(Linkage-libsodium)' != ''\">advapi32.lib;libsodium.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Debug')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\$(Linkage-libsodium)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Release')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\$(Linkage-libsodium)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Copy -->\n\n  <Target Name=\"Linkage-libsodium-dynamic\" AfterTargets=\"AfterBuild\" Condition=\"'$(Linkage-libsodium)' == 'dynamic'\">\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libsodium.dll\"\n          DestinationFiles=\"$(TargetDir)libsodium.dll\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libsodium.pdb\"\n          DestinationFiles=\"$(TargetDir)libsodium.pdb\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Release')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\dynamic\\libsodium.dll\"\n          DestinationFiles=\"$(TargetDir)libsodium.dll\"\n          SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <!-- Messages -->\n\n  <Target Name=\"libsodium-info\" BeforeTargets=\"AfterBuild\" Condition=\"'$(Linkage-libsodium)' == 'dynamic'\">\n    <Message Text=\"Copying libsodium.dll -&gt; $(TargetDir)libsodium.dll\" Importance=\"high\"/>\n    <Message Text=\"Copying libsodium.pdb -&gt; $(TargetDir)libsodium.pdb\" Importance=\"high\" Condition=\"$(Configuration.IndexOf('Debug')) != -1\" />\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/libsodium.import.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libsodium-linkage-uiextension\" PageTemplate=\"tool\" DisplayName=\"Local Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"libsodium\" DisplayName=\"libsodium\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-libsodium\" DisplayName=\"Linkage\" Description=\"How libsodium will be linked into the output of this project\" Category=\"libsodium\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/libzmq/libzmq.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ Library Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)$(ProjectName).xml\" />\n  </ItemGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;$(ProjectDir)..\\..\\..\\..\\include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <EnablePREfast>false</EnablePREfast>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>precompiled.hpp</PrecompiledHeaderFile>\n      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;FD_SETSIZE=16384;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_HAVE_CURVE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-openpgm)' == 'true'\">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-gssapi)' == 'true'\">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-draftapi)' == 'true'\">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-usepoll)' == 'true'\">ZMQ_USE_POLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-usepoll)' != 'true'\">ZMQ_USE_SELECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)' == 'StaticLibrary'\">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)' == 'DynamicLibrary'\">DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Ws2_32.lib;Rpcrt4.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Lib Condition=\"'$(ConfigurationType)'=='StaticLibrary'\">\n      <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions>\n    </Lib>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"OptionInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Option-sodium     : $(Option-sodium)\" Importance=\"high\"/>\n    <Message Text=\"Option-openpgm    : $(Option-openpgm)\" Importance=\"high\"/>\n    <Message Text=\"Option-gssapi     : $(Option-gssapi)\" Importance=\"high\"/>\n    <Message Text=\"Option-draftapi   : $(Option-draftapi)\" Importance=\"high\"/>\n    <Message Text=\"Option-usepoll    : $(Option-usepoll)\" Importance=\"high\"/>\n  </Target>\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(Option-sodium)' == 'true'\"/>\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/libzmq/libzmq.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{641C5F36-32EE-4323-B740-992B651CF9D6}</ProjectGuid>\n    <ProjectName>libzmq</ProjectName>\n    <PlatformToolset>v110</PlatformToolset>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDLL|Win32\">\n      <Configuration>DebugDLL</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDLL|Win32\">\n      <Configuration>ReleaseDLL</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDLL|x64\">\n      <Configuration>DebugDLL</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDLL|x64\">\n      <Configuration>ReleaseDLL</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLTCG|Win32\">\n      <Configuration>DebugLTCG</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLTCG|Win32\">\n      <Configuration>ReleaseLTCG</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLTCG|x64\">\n      <Configuration>DebugLTCG</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLTCG|x64\">\n      <Configuration>ReleaseLTCG</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLIB|Win32\">\n      <Configuration>DebugLIB</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLIB|Win32\">\n      <Configuration>ReleaseLIB</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLIB|x64\">\n      <Configuration>DebugLIB</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLIB|x64\">\n      <Configuration>ReleaseLIB</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Configuration\">\n    <ConfigurationType Condition=\"$(Configuration.IndexOf('DLL')) == -1\">StaticLibrary</ConfigurationType>\n    <ConfigurationType Condition=\"$(Configuration.IndexOf('DLL')) != -1\">DynamicLibrary</ConfigurationType>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n    <ClInclude Include=\"..\\..\\resource.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\include\\zmq.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\zmq_draft.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\array.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_counter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\blob.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\clock.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\command.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\condition_variable.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\config.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ctx.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\devpoll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dgram.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dish.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dist.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\epoll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\err.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fd.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fq.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gather.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_poll_events.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_object.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_thread.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_listener.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\kqueue.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\lb.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\likely.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\msg.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mtrie.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mutex.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\object.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\options.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\own.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pair.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_sender.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_socket.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pipe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\precompiled.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\proxy.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pull.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\push.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\radio.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\random.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\reaper.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\rep.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\req.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\scatter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\select.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\session_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\signaler.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socket_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stdint.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stream_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\sub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_listener.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\timers.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\thread.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\trie.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_protocol.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\windows.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\wire.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xpub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xrep.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xreq.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xsub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ypipe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\yqueue.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\clock.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ctx.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dealer.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\devpoll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dgram.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dish.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dist.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\epoll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\err.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\fq.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gather.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_object.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_thread.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_listener.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\kqueue.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\lb.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\metadata.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\msg.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mtrie.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\null_mechanism.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\object.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\options.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\own.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pair.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_sender.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_socket.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pipe.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poller_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\precompiled.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\proxy.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pull.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\push.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\radio.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\random.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\reaper.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\rep.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\req.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\router.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\scatter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\select.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\session_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\signaler.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_poller.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream_engine.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\sub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_listener.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\thread.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\timers.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\trie.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_engine.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xpub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xsub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zap_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq_utils.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.bat\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.config\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.gsl\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.nuspec\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.targets\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"..\\..\\..\\..\\packaging\\nuget\\package.xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\..\\resource.rc\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/libzmq/libzmq.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\clock.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ctx.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dealer.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\devpoll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dgram.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dist.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\epoll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\err.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\fq.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_object.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_thread.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_listener.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\kqueue.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\lb.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\metadata.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\msg.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mtrie.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\null_mechanism.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\object.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\options.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\own.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pair.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_sender.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_socket.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pipe.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poller_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\proxy.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pull.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\push.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\random.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\reaper.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\rep.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\req.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\router.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\scatter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\select.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\session_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\signaler.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream_engine.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\sub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_listener.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\thread.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\trie.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xpub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xsub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq_utils.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\precompiled.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gather.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_poller.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_engine.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dish.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\radio.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\timers.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\..\\..\\include\\zmq.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\array.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_counter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\blob.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\clock.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\command.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\config.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ctx.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\devpoll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dgram.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dist.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\epoll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\err.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fd.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fq.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_poll_events.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_object.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_thread.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_listener.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\kqueue.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\lb.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\likely.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\msg.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mtrie.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mutex.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\object.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\options.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\own.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pair.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\yqueue.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ypipe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xsub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xreq.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xrep.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xpub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\wire.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\windows.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_protocol.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\trie.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\thread.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_listener.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\sub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stream_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stdint.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socket_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\signaler.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\session_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\scatter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\select.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\req.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\rep.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\reaper.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\random.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\push.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pull.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\proxy.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\precompiled.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\platform.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pipe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_socket.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_sender.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\resource.h\">\n      <Filter>resource</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gather.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\condition_variable.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dish.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\radio.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\timers.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\zmq_draft.h\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"include\">\n      <UniqueIdentifier>{f7e88c6c-e408-4631-959c-fe3568656d70}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"src\">\n      <UniqueIdentifier>{35f0c644-e1d8-4a46-bb33-06bb8b645fff}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"src\\include\">\n      <UniqueIdentifier>{90853975-3420-4f06-8be4-4ab3d9792160}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"packaging\">\n      <UniqueIdentifier>{f5e26e9d-c33d-45c1-95e4-0732acd28b59}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"resource\">\n      <UniqueIdentifier>{e66010e4-a9ea-4e2e-8bc6-12fec14bb009}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.bat\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.config\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.gsl\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.targets\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.nuspec\">\n      <Filter>packaging</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"..\\..\\..\\..\\packaging\\nuget\\package.xml\">\n      <Filter>packaging</Filter>\n    </Xml>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\..\\resource.rc\">\n      <Filter>resource</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/libzmq/libzmq.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libzmq-uiextension\" PageTemplate=\"tool\" DisplayName=\"ZMQ Options\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"sodium\" DisplayName=\"sodium\" />\n      <Category Name=\"openpgm\" DisplayName=\"openpgm\" />\n      <Category Name=\"gssapi\" DisplayName=\"gssapi\" />\n      <Category Name=\"draftapi\" DisplayName=\"draftapi\" />\n      <Category Name=\"usepoll\" DisplayName=\"usepoll\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Option-sodium\" DisplayName=\"Enable Sodium\" Description=\"Enable Sodium build option\" Category=\"sodium\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-openpgm\" DisplayName=\"Enable OpenPGM\" Description=\"Enable OpenPGM build option\" Category=\"openpgm\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-gssapi\" DisplayName=\"Enable GSS API\" Description=\"Enable GSS API build option\" Category=\"gssapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-draftapi\" DisplayName=\"Enable Draft API\" Description=\"Enable Draft API build option\" Category=\"draftapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-usepoll\" DisplayName=\"Enable poll() usage (Vista+ only)\" Description=\"Use poll() instead of select() for waiting on incoming data. Increases performance, but the binary will only run on Windows Vista or later.\" Category=\"usepoll\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/libzmq.import.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"Globals\">\n    <_PropertySheetDisplayName>ZMQ Import Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)libzmq.import.xml\" />\n  </ItemGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-openpgm)' == 'true'\">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-gssapi)' == 'true'\">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-draftapi)' == 'true'\">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <!-- Linkage -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Linkage-libzmq)' == 'static' Or '$(Linkage-libzmq)' == 'ltcg'\">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(Linkage-libzmq)' != ''\">libzmq.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Debug')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\$(Linkage-libzmq)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Release')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\$(Linkage-libzmq)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Copy -->\n\n  <Target Name=\"Linkage-libzmq-dynamic\" AfterTargets=\"AfterBuild\" Condition=\"'$(Linkage-libzmq)' == 'dynamic'\">\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libzmq.dll\"\n          DestinationFiles=\"$(TargetDir)libzmq.dll\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libzmq.pdb\"\n          DestinationFiles=\"$(TargetDir)libzmq.pdb\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Release')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\dynamic\\libzmq.dll\"\n          DestinationFiles=\"$(TargetDir)libzmq.dll\"\n          SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <!-- Messages -->\n\n  <Target Name=\"libzmq-info\" BeforeTargets=\"AfterBuild\" Condition=\"'$(Linkage-libzmq)' == 'dynamic'\">\n    <Message Text=\"Copying libzmq.dll -&gt; $(TargetDir)libzmq.dll\" Importance=\"high\"/>\n    <Message Text=\"Copying libzmq.pdb -&gt; $(TargetDir)libzmq.pdb\" Importance=\"high\" Condition=\"$(Configuration.IndexOf('Debug')) != -1\" />\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/libzmq.import.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libzmq-options-uiextension\" PageTemplate=\"tool\" DisplayName=\"ZMQ Options\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"sodium\" DisplayName=\"sodium\" />\n      <Category Name=\"openpgm\" DisplayName=\"openpgm\" />\n      <Category Name=\"gssapi\" DisplayName=\"gssapi\" />\n      <Category Name=\"draftapi\" DisplayName=\"draftapi\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Option-sodium\" DisplayName=\"Enable Sodium\" Description=\"Enable the Sodium build option\" Category=\"sodium\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-openpgm\" DisplayName=\"Enable OpenPGM\" Description=\"Enable the OpenPGM build option\" Category=\"openpgm\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-gssapi\" DisplayName=\"Enable GSS API\" Description=\"Enable the GSS API build option\" Category=\"gssapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-draftapi\" DisplayName=\"Enable Draft API\" Description=\"Enable Draft API build option\" Category=\"draftapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n  </Rule>\n  <Rule Name=\"libzmq-linkage-uiextension\" PageTemplate=\"tool\" DisplayName=\"Local Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"libzmq\" DisplayName=\"libzmq\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-libzmq\" DisplayName=\"Linkage\" Description=\"How libzmq will be linked into the output of this project\" Category=\"libzmq\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/libzmq.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 11.00\n# Visual Studio 2012\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libzmq\", \"libzmq\\libzmq.vcxproj\", \"{641C5F36-32EE-4323-B740-992B651CF9D6}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_thr\", \"inproc_thr\\inproc_thr.vcxproj\", \"{1077E977-95DD-4E73-A692-74647DD0CC1E}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_lat\", \"inproc_lat\\inproc_lat.vcxproj\", \"{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_thr\", \"remote_thr\\remote_thr.vcxproj\", \"{B15E059C-0CBB-4A82-8C42-6567FB650802}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_lat\", \"remote_lat\\remote_lat.vcxproj\", \"{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_thr\", \"local_thr\\local_thr.vcxproj\", \"{8EF2DF6B-6646-460F-8032-913B70FE0E94}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_lat\", \"local_lat\\local_lat.vcxproj\", \"{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDynDebug|Win32 = DynDebug|Win32\n\t\tDynDebug|x64 = DynDebug|x64\n\t\tDynRelease|Win32 = DynRelease|Win32\n\t\tDynRelease|x64 = DynRelease|x64\n\t\tLtcgDebug|Win32 = LtcgDebug|Win32\n\t\tLtcgDebug|x64 = LtcgDebug|x64\n\t\tLtcgRelease|Win32 = LtcgRelease|Win32\n\t\tLtcgRelease|x64 = LtcgRelease|x64\n\t\tStaticDebug|Win32 = StaticDebug|Win32\n\t\tStaticDebug|x64 = StaticDebug|x64\n\t\tStaticRelease|Win32 = StaticRelease|Win32\n\t\tStaticRelease|x64 = StaticRelease|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|Win32.ActiveCfg = DebugDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|Win32.Build.0 = DebugDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|x64.ActiveCfg = DebugDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|x64.Build.0 = DebugDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|Win32.ActiveCfg = ReleaseDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|Win32.Build.0 = ReleaseDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|x64.ActiveCfg = ReleaseDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|x64.Build.0 = ReleaseDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|Win32.ActiveCfg = DebugLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|Win32.Build.0 = DebugLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|x64.ActiveCfg = DebugLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|x64.Build.0 = DebugLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|Win32.ActiveCfg = ReleaseLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|Win32.Build.0 = ReleaseLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|x64.ActiveCfg = ReleaseLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|x64.Build.0 = ReleaseLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.ActiveCfg = DebugLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.Build.0 = DebugLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|x64.ActiveCfg = DebugLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|x64.Build.0 = DebugLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.ActiveCfg = ReleaseLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.Build.0 = ReleaseLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|x64.ActiveCfg = ReleaseLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|x64.Build.0 = ReleaseLIB|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/local_lat/local_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ local_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/local_lat/local_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}</ProjectGuid>\n    <ProjectName>local_lat</ProjectName>\n    <PlatformToolset>v110</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\local_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/local_thr/local_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ local_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/local_thr/local_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{8EF2DF6B-6646-460F-8032-913B70FE0E94}</ProjectGuid>\n    <ProjectName>local_thr</ProjectName>\n    <PlatformToolset>v110</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\local_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/remote_lat/remote_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ remote_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/remote_lat/remote_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}</ProjectGuid>\n    <ProjectName>remote_lat</ProjectName>\n    <PlatformToolset>v110</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\remote_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/remote_thr/remote_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ remote_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n  \n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2012/remote_thr/remote_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{B15E059C-0CBB-4A82-8C42-6567FB650802}</ProjectGuid>\n    <ProjectName>remote_thr</ProjectName>\n    <PlatformToolset>v110</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\remote_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/inproc_lat/inproc_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ inproc_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\"  Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/inproc_lat/inproc_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}</ProjectGuid>\n    <ProjectName>inproc_lat</ProjectName>\n    <PlatformToolset>v120</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\inproc_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/inproc_thr/inproc_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ inproc_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/inproc_thr/inproc_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{1077E977-95DD-4E73-A692-74647DD0CC1E}</ProjectGuid>\n    <ProjectName>inproc_thr</ProjectName>\n    <PlatformToolset>v120</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\inproc_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/libsodium.import.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"Globals\">\n    <_PropertySheetDisplayName>Libsodium Import Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)libsodium.import.xml\" />\n  </ItemGroup>\n\n  <!-- Linkage -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\src\\libsodium\\include;$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\src\\libsodium\\include\\sodium\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Linkage-libsodium)' == 'static' Or '$(Linkage-libsodium)' == 'ltcg'\">SODIUM_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(Linkage-libsodium)' != ''\">advapi32.lib;libsodium.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Debug')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\$(Linkage-libsodium)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Release')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\$(Linkage-libsodium)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Copy -->\n\n  <Target Name=\"Linkage-libsodium-dynamic\" AfterTargets=\"AfterBuild\" Condition=\"'$(Linkage-libsodium)' == 'dynamic'\">\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libsodium.dll\"\n          DestinationFiles=\"$(TargetDir)libsodium.dll\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libsodium.pdb\"\n          DestinationFiles=\"$(TargetDir)libsodium.pdb\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Release')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\dynamic\\libsodium.dll\"\n          DestinationFiles=\"$(TargetDir)libsodium.dll\"\n          SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <!-- Messages -->\n\n  <Target Name=\"libsodium-info\" BeforeTargets=\"AfterBuild\" Condition=\"'$(Linkage-libsodium)' == 'dynamic'\">\n    <Message Text=\"Copying libsodium.dll -&gt; $(TargetDir)libsodium.dll\" Importance=\"high\"/>\n    <Message Text=\"Copying libsodium.pdb -&gt; $(TargetDir)libsodium.pdb\" Importance=\"high\" Condition=\"$(Configuration.IndexOf('Debug')) != -1\" />\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/libsodium.import.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libsodium-linkage-uiextension\" PageTemplate=\"tool\" DisplayName=\"Local Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"libsodium\" DisplayName=\"libsodium\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-libsodium\" DisplayName=\"Linkage\" Description=\"How libsodium will be linked into the output of this project\" Category=\"libsodium\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/libzmq/libzmq.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ Library Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)$(ProjectName).xml\" />\n  </ItemGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;$(ProjectDir)..\\..\\..\\..\\include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <EnablePREfast>false</EnablePREfast>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>precompiled.hpp</PrecompiledHeaderFile>\n      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;FD_SETSIZE=16384;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_HAVE_CURVE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-openpgm)' == 'true'\">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-gssapi)' == 'true'\">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-draftapi)' == 'true'\">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-usepoll)' == 'true'\">ZMQ_USE_POLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-usepoll)' != 'true'\">ZMQ_USE_SELECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)' == 'StaticLibrary'\">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)' == 'DynamicLibrary'\">DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Ws2_32.lib;Rpcrt4.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Lib Condition=\"'$(ConfigurationType)'=='StaticLibrary'\">\n      <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions>\n    </Lib>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"OptionInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Option-sodium     : $(Option-sodium)\" Importance=\"high\"/>\n    <Message Text=\"Option-openpgm    : $(Option-openpgm)\" Importance=\"high\"/>\n    <Message Text=\"Option-gssapi     : $(Option-gssapi)\" Importance=\"high\"/>\n    <Message Text=\"Option-draftapi   : $(Option-draftapi)\" Importance=\"high\"/>\n    <Message Text=\"Option-usepoll    : $(Option-usepoll)\" Importance=\"high\"/>\n  </Target>\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(Option-sodium)' == 'true'\"/>\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/libzmq/libzmq.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <PropertyGroup Label=\"Globals\">\r\n    <ProjectGuid>{641C5F36-32EE-4323-B740-992B651CF9D6}</ProjectGuid>\r\n    <ProjectName>libzmq</ProjectName>\r\n    <PlatformToolset>v120</PlatformToolset>\r\n  </PropertyGroup>\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"DebugDLL|Win32\">\r\n      <Configuration>DebugDLL</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"ReleaseDLL|Win32\">\r\n      <Configuration>ReleaseDLL</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"DebugDLL|x64\">\r\n      <Configuration>DebugDLL</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"ReleaseDLL|x64\">\r\n      <Configuration>ReleaseDLL</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"DebugLTCG|Win32\">\r\n      <Configuration>DebugLTCG</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"ReleaseLTCG|Win32\">\r\n      <Configuration>ReleaseLTCG</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"DebugLTCG|x64\">\r\n      <Configuration>DebugLTCG</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"ReleaseLTCG|x64\">\r\n      <Configuration>ReleaseLTCG</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"DebugLIB|Win32\">\r\n      <Configuration>DebugLIB</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"ReleaseLIB|Win32\">\r\n      <Configuration>ReleaseLIB</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"DebugLIB|x64\">\r\n      <Configuration>DebugLIB</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"ReleaseLIB|x64\">\r\n      <Configuration>ReleaseLIB</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Configuration\">\r\n    <ConfigurationType Condition=\"$(Configuration.IndexOf('DLL')) == -1\">StaticLibrary</ConfigurationType>\r\n    <ConfigurationType Condition=\"$(Configuration.IndexOf('DLL')) != -1\">DynamicLibrary</ConfigurationType>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"PropertySheets\">\r\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\r\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\r\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\r\n  </ImportGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\r\n    <ClInclude Include=\"..\\..\\resource.h\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\include\\zmq.h\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\zmq_draft.h\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\address.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\array.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_counter.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\blob.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\client.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\clock.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\command.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\condition_variable.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\config.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ctx.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_client.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_server.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\devpoll.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dgram.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dish.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dist.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\encoder.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\epoll.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\err.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fd.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fq.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gather.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_client.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_server.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_engine.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_poll_events.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_object.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_thread.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_address.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_listener.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\kqueue.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\lb.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\likely.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\msg.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mtrie.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mutex.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\object.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\options.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\own.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pair.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_sender.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_socket.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pipe.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\server.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks_connecter.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poll.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller_base.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\precompiled.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\proxy.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pub.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pull.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\push.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\radio.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\random.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_decoder.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_encoder.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\reaper.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\rep.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\req.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\scatter.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\select.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\session_base.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\signaler.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socket_base.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stdint.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stream_engine.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\sub.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_address.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_listener.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\timers.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\thread.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\trie.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_address.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_engine.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_decoder.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_encoder.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_protocol.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\windows.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\wire.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xpub.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xrep.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xreq.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xsub.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ypipe.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\..\\src\\yqueue.hpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\address.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\client.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\clock.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ctx.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_client.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_mechanism_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_server.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dealer.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\devpoll.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dgram.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dish.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dist.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\epoll.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\err.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\fq.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gather.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_client.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_server.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_object.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_thread.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_address.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_listener.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\kqueue.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\lb.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\metadata.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\msg.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mtrie.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\null_mechanism.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\object.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\options.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\own.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pair.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_sender.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_socket.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pipe.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_client.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_server.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poll.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poller_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\precompiled.cpp\">\r\n      <PrecompiledHeader>Create</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\proxy.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pub.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pull.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\push.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\radio.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\random.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_decoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_encoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\reaper.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\rep.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\req.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\router.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\scatter.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\select.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\server.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\session_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\signaler.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_poller.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks_connecter.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream_engine.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\sub.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_address.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_listener.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\thread.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\timers.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\trie.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_address.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_engine.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_decoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_encoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_decoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_encoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xpub.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xsub.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zap_client.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq_utils.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.bat\" />\r\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.config\" />\r\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.gsl\" />\r\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.nuspec\" />\r\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.targets\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Xml Include=\"..\\..\\..\\..\\packaging\\nuget\\package.xml\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"..\\..\\resource.rc\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n</Project>\r\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/libzmq/libzmq.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\clock.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ctx.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dealer.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\devpoll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dgram.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dist.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\epoll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\err.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\fq.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_object.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_thread.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_listener.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\kqueue.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\lb.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\metadata.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\msg.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mtrie.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\null_mechanism.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\object.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\options.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\own.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pair.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_sender.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_socket.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pipe.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poller_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\proxy.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pull.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\push.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\random.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\reaper.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\rep.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\req.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\router.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\scatter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\select.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\session_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\signaler.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream_engine.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\sub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_listener.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\thread.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\trie.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xpub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xsub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq_utils.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\precompiled.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gather.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_poller.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_engine.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dish.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\radio.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\timers.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\..\\..\\include\\zmq.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\array.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_counter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\blob.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\clock.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\command.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\config.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ctx.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\devpoll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dgram.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dist.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\epoll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\err.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fd.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fq.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_poll_events.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_object.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_thread.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_listener.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\kqueue.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\lb.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\likely.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\msg.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mtrie.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mutex.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\object.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\options.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\own.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pair.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\yqueue.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ypipe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xsub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xreq.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xrep.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xpub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\wire.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\windows.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_protocol.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\trie.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\thread.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_listener.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\sub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stream_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stdint.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socket_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\signaler.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\session_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\scatter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\select.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\req.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\rep.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\reaper.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\random.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\push.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pull.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\proxy.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\precompiled.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\platform.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pipe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_socket.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_sender.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\resource.h\">\n      <Filter>resource</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gather.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\condition_variable.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dish.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\radio.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\timers.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\zmq_draft.h\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"include\">\n      <UniqueIdentifier>{f7e88c6c-e408-4631-959c-fe3568656d70}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"src\">\n      <UniqueIdentifier>{35f0c644-e1d8-4a46-bb33-06bb8b645fff}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"src\\include\">\n      <UniqueIdentifier>{90853975-3420-4f06-8be4-4ab3d9792160}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"packaging\">\n      <UniqueIdentifier>{f5e26e9d-c33d-45c1-95e4-0732acd28b59}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"resource\">\n      <UniqueIdentifier>{e66010e4-a9ea-4e2e-8bc6-12fec14bb009}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.bat\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.config\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.gsl\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.targets\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.nuspec\">\n      <Filter>packaging</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"..\\..\\..\\..\\packaging\\nuget\\package.xml\">\n      <Filter>packaging</Filter>\n    </Xml>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\..\\resource.rc\">\n      <Filter>resource</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/libzmq/libzmq.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libzmq-uiextension\" PageTemplate=\"tool\" DisplayName=\"ZMQ Options\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"sodium\" DisplayName=\"sodium\" />\n      <Category Name=\"openpgm\" DisplayName=\"openpgm\" />\n      <Category Name=\"gssapi\" DisplayName=\"gssapi\" />\n      <Category Name=\"draftapi\" DisplayName=\"draftapi\" />\n      <Category Name=\"usepoll\" DisplayName=\"usepoll\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Option-sodium\" DisplayName=\"Enable Sodium\" Description=\"Enable Sodium build option\" Category=\"sodium\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-openpgm\" DisplayName=\"Enable OpenPGM\" Description=\"Enable OpenPGM build option\" Category=\"openpgm\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-gssapi\" DisplayName=\"Enable GSS API\" Description=\"Enable GSS API build option\" Category=\"gssapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-draftapi\" DisplayName=\"Enable Draft API\" Description=\"Enable Draft API build option\" Category=\"draftapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-usepoll\" DisplayName=\"Enable poll() usage (Vista+ only)\" Description=\"Use poll() instead of select() for waiting on incoming data. Increases performance, but the binary will only run on Windows Vista or later.\" Category=\"usepoll\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/libzmq.import.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"Globals\">\n    <_PropertySheetDisplayName>ZMQ Import Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)libzmq.import.xml\" />\n  </ItemGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-openpgm)' == 'true'\">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-gssapi)' == 'true'\">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-draftapi)' == 'true'\">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <!-- Linkage -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Linkage-libzmq)' == 'static' Or '$(Linkage-libzmq)' == 'ltcg'\">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(Linkage-libzmq)' != ''\">libzmq.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Debug')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\$(Linkage-libzmq)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Release')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\$(Linkage-libzmq)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Copy -->\n\n  <Target Name=\"Linkage-libzmq-dynamic\" AfterTargets=\"AfterBuild\" Condition=\"'$(Linkage-libzmq)' == 'dynamic'\">\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libzmq.dll\"\n          DestinationFiles=\"$(TargetDir)libzmq.dll\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libzmq.pdb\"\n          DestinationFiles=\"$(TargetDir)libzmq.pdb\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Release')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\dynamic\\libzmq.dll\"\n          DestinationFiles=\"$(TargetDir)libzmq.dll\"\n          SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <!-- Messages -->\n\n  <Target Name=\"libzmq-info\" BeforeTargets=\"AfterBuild\" Condition=\"'$(Linkage-libzmq)' == 'dynamic'\">\n    <Message Text=\"Copying libzmq.dll -&gt; $(TargetDir)libzmq.dll\" Importance=\"high\"/>\n    <Message Text=\"Copying libzmq.pdb -&gt; $(TargetDir)libzmq.pdb\" Importance=\"high\" Condition=\"$(Configuration.IndexOf('Debug')) != -1\" />\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/libzmq.import.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libzmq-options-uiextension\" PageTemplate=\"tool\" DisplayName=\"ZMQ Options\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"sodium\" DisplayName=\"sodium\" />\n      <Category Name=\"openpgm\" DisplayName=\"openpgm\" />\n      <Category Name=\"gssapi\" DisplayName=\"gssapi\" />\n      <Category Name=\"draftapi\" DisplayName=\"draftapi\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Option-sodium\" DisplayName=\"Enable Sodium\" Description=\"Enable the Sodium build option\" Category=\"sodium\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-openpgm\" DisplayName=\"Enable OpenPGM\" Description=\"Enable the OpenPGM build option\" Category=\"openpgm\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-gssapi\" DisplayName=\"Enable GSS API\" Description=\"Enable the GSS API build option\" Category=\"gssapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-draftapi\" DisplayName=\"Enable Draft API\" Description=\"Enable Draft API build option\" Category=\"draftapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n  </Rule>\n  <Rule Name=\"libzmq-linkage-uiextension\" PageTemplate=\"tool\" DisplayName=\"Local Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"libzmq\" DisplayName=\"libzmq\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-libzmq\" DisplayName=\"Linkage\" Description=\"How libzmq will be linked into the output of this project\" Category=\"libzmq\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/libzmq.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 2013\nVisualStudioVersion = 12.0.30110.0\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libzmq\", \"libzmq\\libzmq.vcxproj\", \"{641C5F36-32EE-4323-B740-992B651CF9D6}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_thr\", \"inproc_thr\\inproc_thr.vcxproj\", \"{1077E977-95DD-4E73-A692-74647DD0CC1E}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_lat\", \"inproc_lat\\inproc_lat.vcxproj\", \"{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_thr\", \"remote_thr\\remote_thr.vcxproj\", \"{B15E059C-0CBB-4A82-8C42-6567FB650802}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_lat\", \"remote_lat\\remote_lat.vcxproj\", \"{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_thr\", \"local_thr\\local_thr.vcxproj\", \"{8EF2DF6B-6646-460F-8032-913B70FE0E94}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_lat\", \"local_lat\\local_lat.vcxproj\", \"{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDynDebug|Win32 = DynDebug|Win32\n\t\tDynDebug|x64 = DynDebug|x64\n\t\tDynRelease|Win32 = DynRelease|Win32\n\t\tDynRelease|x64 = DynRelease|x64\n\t\tLtcgDebug|Win32 = LtcgDebug|Win32\n\t\tLtcgDebug|x64 = LtcgDebug|x64\n\t\tLtcgRelease|Win32 = LtcgRelease|Win32\n\t\tLtcgRelease|x64 = LtcgRelease|x64\n\t\tStaticDebug|Win32 = StaticDebug|Win32\n\t\tStaticDebug|x64 = StaticDebug|x64\n\t\tStaticRelease|Win32 = StaticRelease|Win32\n\t\tStaticRelease|x64 = StaticRelease|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|Win32.ActiveCfg = DebugDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|Win32.Build.0 = DebugDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|x64.ActiveCfg = DebugDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|x64.Build.0 = DebugDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|Win32.ActiveCfg = ReleaseDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|Win32.Build.0 = ReleaseDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|x64.ActiveCfg = ReleaseDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|x64.Build.0 = ReleaseDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|Win32.ActiveCfg = DebugLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|Win32.Build.0 = DebugLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|x64.ActiveCfg = DebugLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|x64.Build.0 = DebugLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|Win32.ActiveCfg = ReleaseLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|Win32.Build.0 = ReleaseLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|x64.ActiveCfg = ReleaseLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|x64.Build.0 = ReleaseLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.ActiveCfg = DebugLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.Build.0 = DebugLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|x64.ActiveCfg = DebugLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|x64.Build.0 = DebugLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.ActiveCfg = ReleaseLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.Build.0 = ReleaseLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|x64.ActiveCfg = ReleaseLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|x64.Build.0 = ReleaseLIB|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/local_lat/local_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ local_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/local_lat/local_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}</ProjectGuid>\n    <ProjectName>local_lat</ProjectName>\n    <PlatformToolset>v120</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\local_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/local_thr/local_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ local_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/local_thr/local_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{8EF2DF6B-6646-460F-8032-913B70FE0E94}</ProjectGuid>\n    <ProjectName>local_thr</ProjectName>\n    <PlatformToolset>v120</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\local_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/remote_lat/remote_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ remote_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/remote_lat/remote_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}</ProjectGuid>\n    <ProjectName>remote_lat</ProjectName>\n    <PlatformToolset>v120</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\remote_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/remote_thr/remote_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ remote_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n  \n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2013/remote_thr/remote_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{B15E059C-0CBB-4A82-8C42-6567FB650802}</ProjectGuid>\n    <ProjectName>remote_thr</ProjectName>\n    <PlatformToolset>v120</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\remote_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/inproc_lat/inproc_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ inproc_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\"  Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/inproc_lat/inproc_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}</ProjectGuid>\n    <ProjectName>inproc_lat</ProjectName>\n    <PlatformToolset>v140</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\inproc_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/inproc_thr/inproc_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ inproc_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/inproc_thr/inproc_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{1077E977-95DD-4E73-A692-74647DD0CC1E}</ProjectGuid>\n    <ProjectName>inproc_thr</ProjectName>\n    <PlatformToolset>v140</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\inproc_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/libsodium.import.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"Globals\">\n    <_PropertySheetDisplayName>Libsodium Import Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)libsodium.import.xml\" />\n  </ItemGroup>\n\n  <!-- Linkage -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\src\\libsodium\\include;$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\src\\libsodium\\include\\sodium\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Linkage-libsodium)' == 'static' Or '$(Linkage-libsodium)' == 'ltcg'\">SODIUM_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(Linkage-libsodium)' != ''\">advapi32.lib;libsodium.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Debug')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\$(Linkage-libsodium)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Release')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\$(Linkage-libsodium)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Copy -->\n\n  <Target Name=\"Linkage-libsodium-dynamic\" AfterTargets=\"AfterBuild\" Condition=\"'$(Linkage-libsodium)' == 'dynamic'\">\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libsodium.dll\"\n          DestinationFiles=\"$(TargetDir)libsodium.dll\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libsodium.pdb\"\n          DestinationFiles=\"$(TargetDir)libsodium.pdb\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Release')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\dynamic\\libsodium.dll\"\n          DestinationFiles=\"$(TargetDir)libsodium.dll\"\n          SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <!-- Messages -->\n\n  <Target Name=\"libsodium-info\" BeforeTargets=\"AfterBuild\" Condition=\"'$(Linkage-libsodium)' == 'dynamic'\">\n    <Message Text=\"Copying libsodium.dll -&gt; $(TargetDir)libsodium.dll\" Importance=\"high\"/>\n    <Message Text=\"Copying libsodium.pdb -&gt; $(TargetDir)libsodium.pdb\" Importance=\"high\" Condition=\"$(Configuration.IndexOf('Debug')) != -1\" />\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/libsodium.import.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libsodium-linkage-uiextension\" PageTemplate=\"tool\" DisplayName=\"Local Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"libsodium\" DisplayName=\"libsodium\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-libsodium\" DisplayName=\"Linkage\" Description=\"How libsodium will be linked into the output of this project\" Category=\"libsodium\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/libzmq/libzmq.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ Library Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)$(ProjectName).xml\" />\n  </ItemGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;$(ProjectDir)..\\..\\..\\..\\include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <EnablePREfast>false</EnablePREfast>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>precompiled.hpp</PrecompiledHeaderFile>\n      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;FD_SETSIZE=16384;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_HAVE_CURVE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-openpgm)' == 'true'\">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-gssapi)' == 'true'\">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-draftapi)' == 'true'\">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-usepoll)' == 'true'\">ZMQ_USE_POLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-usepoll)' != 'true'\">ZMQ_USE_SELECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)' == 'StaticLibrary'\">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)' == 'DynamicLibrary'\">DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Ws2_32.lib;Rpcrt4.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Lib Condition=\"'$(ConfigurationType)'=='StaticLibrary'\">\n      <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions>\n    </Lib>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"OptionInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Option-sodium     : $(Option-sodium)\" Importance=\"high\"/>\n    <Message Text=\"Option-openpgm    : $(Option-openpgm)\" Importance=\"high\"/>\n    <Message Text=\"Option-gssapi     : $(Option-gssapi)\" Importance=\"high\"/>\n    <Message Text=\"Option-draftapi   : $(Option-draftapi)\" Importance=\"high\"/>\n    <Message Text=\"Option-usepoll    : $(Option-usepoll)\" Importance=\"high\"/>\n  </Target>\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(Option-sodium)' == 'true'\"/>\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/libzmq/libzmq.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{641C5F36-32EE-4323-B740-992B651CF9D6}</ProjectGuid>\n    <ProjectName>libzmq</ProjectName>\n    <PlatformToolset>v140</PlatformToolset>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDLL|Win32\">\n      <Configuration>DebugDLL</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDLL|Win32\">\n      <Configuration>ReleaseDLL</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDLL|x64\">\n      <Configuration>DebugDLL</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDLL|x64\">\n      <Configuration>ReleaseDLL</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLTCG|Win32\">\n      <Configuration>DebugLTCG</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLTCG|Win32\">\n      <Configuration>ReleaseLTCG</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLTCG|x64\">\n      <Configuration>DebugLTCG</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLTCG|x64\">\n      <Configuration>ReleaseLTCG</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLIB|Win32\">\n      <Configuration>DebugLIB</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLIB|Win32\">\n      <Configuration>ReleaseLIB</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLIB|x64\">\n      <Configuration>DebugLIB</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLIB|x64\">\n      <Configuration>ReleaseLIB</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Configuration\">\n    <ConfigurationType Condition=\"$(Configuration.IndexOf('DLL')) == -1\">StaticLibrary</ConfigurationType>\n    <ConfigurationType Condition=\"$(Configuration.IndexOf('DLL')) != -1\">DynamicLibrary</ConfigurationType>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n    <ClInclude Include=\"..\\..\\resource.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\include\\zmq.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\zmq_draft.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\array.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_counter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\blob.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\clock.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\command.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\condition_variable.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\config.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ctx.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\devpoll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dgram.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dish.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dist.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\epoll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\err.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fd.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fq.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gather.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_poll_events.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_object.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_thread.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip_resolver.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_listener.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\kqueue.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\lb.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\likely.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\msg.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mtrie.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mutex.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\object.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\options.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\own.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pair.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_sender.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_socket.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pipe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\precompiled.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\proxy.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pull.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\push.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\radio.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\random.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\reaper.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\rep.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\req.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\scatter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\select.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\session_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\signaler.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socket_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stdint.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stream_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\sub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_listener.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\timers.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\thread.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\trie.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_protocol.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\windows.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\wire.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xpub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xrep.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xreq.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xsub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ypipe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\yqueue.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\clock.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ctx.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dealer.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\devpoll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dgram.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dish.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dist.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\epoll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\err.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\fq.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gather.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_object.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_thread.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip_resolver.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_listener.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\kqueue.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\lb.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\metadata.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\msg.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mtrie.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\null_mechanism.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\object.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\options.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\own.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pair.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_sender.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_socket.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pipe.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poller_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\precompiled.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\proxy.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pull.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\push.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\radio.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\random.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\reaper.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\rep.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\req.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\router.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\scatter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\select.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\session_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\signaler.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_poller.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream_engine.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\sub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_listener.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\thread.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\timers.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\trie.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_engine.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xpub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xsub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zap_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq_utils.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.bat\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.config\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.gsl\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.nuspec\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.targets\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"..\\..\\..\\..\\packaging\\nuget\\package.xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\..\\resource.rc\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/libzmq/libzmq.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\clock.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ctx.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dealer.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\devpoll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dgram.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dist.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\epoll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\err.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\fq.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_object.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_thread.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_listener.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\kqueue.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\lb.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\metadata.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\msg.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mtrie.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\null_mechanism.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\object.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\options.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\own.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pair.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_sender.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_socket.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pipe.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poller_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\proxy.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pull.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\push.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\random.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\reaper.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\rep.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\req.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\router.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\scatter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\select.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\session_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\signaler.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream_engine.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\sub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_listener.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\thread.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\trie.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xpub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xsub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq_utils.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\precompiled.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gather.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_poller.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_engine.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dish.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\radio.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\timers.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\..\\..\\include\\zmq.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\array.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_counter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\blob.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\clock.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\command.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\config.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ctx.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\devpoll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dgram.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dist.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\epoll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\err.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fd.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fq.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_poll_events.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_object.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_thread.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_listener.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\kqueue.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\lb.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\likely.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\msg.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mtrie.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mutex.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\object.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\options.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\own.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pair.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\yqueue.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ypipe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xsub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xreq.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xrep.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xpub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\wire.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\windows.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_protocol.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\trie.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\thread.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_listener.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\sub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stream_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stdint.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socket_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\signaler.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\session_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\scatter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\select.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\req.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\rep.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\reaper.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\random.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\push.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pull.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\proxy.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\precompiled.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\platform.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pipe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_socket.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_sender.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\resource.h\">\n      <Filter>resource</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gather.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\condition_variable.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dish.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\radio.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\timers.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\zmq_draft.h\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"include\">\n      <UniqueIdentifier>{f7e88c6c-e408-4631-959c-fe3568656d70}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"src\">\n      <UniqueIdentifier>{35f0c644-e1d8-4a46-bb33-06bb8b645fff}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"src\\include\">\n      <UniqueIdentifier>{90853975-3420-4f06-8be4-4ab3d9792160}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"packaging\">\n      <UniqueIdentifier>{f5e26e9d-c33d-45c1-95e4-0732acd28b59}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"resource\">\n      <UniqueIdentifier>{e66010e4-a9ea-4e2e-8bc6-12fec14bb009}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.bat\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.config\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.gsl\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.targets\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.nuspec\">\n      <Filter>packaging</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"..\\..\\..\\..\\packaging\\nuget\\package.xml\">\n      <Filter>packaging</Filter>\n    </Xml>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\..\\resource.rc\">\n      <Filter>resource</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/libzmq/libzmq.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libzmq-uiextension\" PageTemplate=\"tool\" DisplayName=\"ZMQ Options\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"sodium\" DisplayName=\"sodium\" />\n      <Category Name=\"openpgm\" DisplayName=\"openpgm\" />\n      <Category Name=\"gssapi\" DisplayName=\"gssapi\" />\n      <Category Name=\"draftapi\" DisplayName=\"draftapi\" />\n      <Category Name=\"usepoll\" DisplayName=\"usepoll\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Option-sodium\" DisplayName=\"Enable Sodium\" Description=\"Enable Sodium build option\" Category=\"sodium\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-openpgm\" DisplayName=\"Enable OpenPGM\" Description=\"Enable OpenPGM build option\" Category=\"openpgm\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-gssapi\" DisplayName=\"Enable GSS API\" Description=\"Enable GSS API build option\" Category=\"gssapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-draftapi\" DisplayName=\"Enable Draft API\" Description=\"Enable Draft API build option\" Category=\"draftapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-usepoll\" DisplayName=\"Enable poll() usage (Vista+ only)\" Description=\"Use poll() instead of select() for waiting on incoming data. Increases performance, but the binary will only run on Windows Vista or later.\" Category=\"usepoll\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/libzmq.import.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"Globals\">\n    <_PropertySheetDisplayName>ZMQ Import Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)libzmq.import.xml\" />\n  </ItemGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-openpgm)' == 'true'\">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-gssapi)' == 'true'\">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-draftapi)' == 'true'\">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <!-- Linkage -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Linkage-libzmq)' == 'static' Or '$(Linkage-libzmq)' == 'ltcg'\">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(Linkage-libzmq)' != ''\">libzmq.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Debug')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\$(Linkage-libzmq)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Release')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\$(Linkage-libzmq)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Copy -->\n\n  <Target Name=\"Linkage-libzmq-dynamic\" AfterTargets=\"AfterBuild\" Condition=\"'$(Linkage-libzmq)' == 'dynamic'\">\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libzmq.dll\"\n          DestinationFiles=\"$(TargetDir)libzmq.dll\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libzmq.pdb\"\n          DestinationFiles=\"$(TargetDir)libzmq.pdb\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Release')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\dynamic\\libzmq.dll\"\n          DestinationFiles=\"$(TargetDir)libzmq.dll\"\n          SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <!-- Messages -->\n\n  <Target Name=\"libzmq-info\" BeforeTargets=\"AfterBuild\" Condition=\"'$(Linkage-libzmq)' == 'dynamic'\">\n    <Message Text=\"Copying libzmq.dll -&gt; $(TargetDir)libzmq.dll\" Importance=\"high\"/>\n    <Message Text=\"Copying libzmq.pdb -&gt; $(TargetDir)libzmq.pdb\" Importance=\"high\" Condition=\"$(Configuration.IndexOf('Debug')) != -1\" />\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/libzmq.import.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libzmq-options-uiextension\" PageTemplate=\"tool\" DisplayName=\"ZMQ Options\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"sodium\" DisplayName=\"sodium\" />\n      <Category Name=\"openpgm\" DisplayName=\"openpgm\" />\n      <Category Name=\"gssapi\" DisplayName=\"gssapi\" />\n      <Category Name=\"draftapi\" DisplayName=\"draftapi\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Option-sodium\" DisplayName=\"Enable Sodium\" Description=\"Enable the Sodium build option\" Category=\"sodium\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-openpgm\" DisplayName=\"Enable OpenPGM\" Description=\"Enable the OpenPGM build option\" Category=\"openpgm\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-gssapi\" DisplayName=\"Enable GSS API\" Description=\"Enable the GSS API build option\" Category=\"gssapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-draftapi\" DisplayName=\"Enable Draft API\" Description=\"Enable Draft API build option\" Category=\"draftapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n  </Rule>\n  <Rule Name=\"libzmq-linkage-uiextension\" PageTemplate=\"tool\" DisplayName=\"Local Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"libzmq\" DisplayName=\"libzmq\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-libzmq\" DisplayName=\"Linkage\" Description=\"How libzmq will be linked into the output of this project\" Category=\"libzmq\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/libzmq.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 14\nVisualStudioVersion = 14.0.23107.0\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libzmq\", \"libzmq\\libzmq.vcxproj\", \"{641C5F36-32EE-4323-B740-992B651CF9D6}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_thr\", \"inproc_thr\\inproc_thr.vcxproj\", \"{1077E977-95DD-4E73-A692-74647DD0CC1E}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_lat\", \"inproc_lat\\inproc_lat.vcxproj\", \"{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_thr\", \"remote_thr\\remote_thr.vcxproj\", \"{B15E059C-0CBB-4A82-8C42-6567FB650802}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_lat\", \"remote_lat\\remote_lat.vcxproj\", \"{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_thr\", \"local_thr\\local_thr.vcxproj\", \"{8EF2DF6B-6646-460F-8032-913B70FE0E94}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_lat\", \"local_lat\\local_lat.vcxproj\", \"{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDynDebug|Win32 = DynDebug|Win32\n\t\tDynDebug|x64 = DynDebug|x64\n\t\tDynRelease|Win32 = DynRelease|Win32\n\t\tDynRelease|x64 = DynRelease|x64\n\t\tLtcgDebug|Win32 = LtcgDebug|Win32\n\t\tLtcgDebug|x64 = LtcgDebug|x64\n\t\tLtcgRelease|Win32 = LtcgRelease|Win32\n\t\tLtcgRelease|x64 = LtcgRelease|x64\n\t\tStaticDebug|Win32 = StaticDebug|Win32\n\t\tStaticDebug|x64 = StaticDebug|x64\n\t\tStaticRelease|Win32 = StaticRelease|Win32\n\t\tStaticRelease|x64 = StaticRelease|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|Win32.ActiveCfg = DebugDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|Win32.Build.0 = DebugDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|x64.ActiveCfg = DebugDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|x64.Build.0 = DebugDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|Win32.ActiveCfg = ReleaseDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|Win32.Build.0 = ReleaseDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|x64.ActiveCfg = ReleaseDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|x64.Build.0 = ReleaseDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|Win32.ActiveCfg = DebugLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|Win32.Build.0 = DebugLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|x64.ActiveCfg = DebugLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|x64.Build.0 = DebugLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|Win32.ActiveCfg = ReleaseLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|Win32.Build.0 = ReleaseLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|x64.ActiveCfg = ReleaseLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|x64.Build.0 = ReleaseLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.ActiveCfg = DebugLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.Build.0 = DebugLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|x64.ActiveCfg = DebugLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|x64.Build.0 = DebugLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.ActiveCfg = ReleaseLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.Build.0 = ReleaseLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|x64.ActiveCfg = ReleaseLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|x64.Build.0 = ReleaseLIB|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/local_lat/local_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ local_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/local_lat/local_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}</ProjectGuid>\n    <ProjectName>local_lat</ProjectName>\n    <PlatformToolset>v140</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\local_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/local_thr/local_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ local_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/local_thr/local_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{8EF2DF6B-6646-460F-8032-913B70FE0E94}</ProjectGuid>\n    <ProjectName>local_thr</ProjectName>\n    <PlatformToolset>v140</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\local_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/remote_lat/remote_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ remote_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/remote_lat/remote_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}</ProjectGuid>\n    <ProjectName>remote_lat</ProjectName>\n    <PlatformToolset>v140</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\remote_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/remote_thr/remote_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ remote_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n  \n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2015/remote_thr/remote_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{B15E059C-0CBB-4A82-8C42-6567FB650802}</ProjectGuid>\n    <ProjectName>remote_thr</ProjectName>\n    <PlatformToolset>v140</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\remote_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015_xp/libzmq.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <ProjectGuid>{217AD6A0-8CEA-428D-908F-C34B23CECAAF}</ProjectGuid>\r\n    <Keyword>Win32Proj</Keyword>\r\n    <RootNamespace>libzmq</RootNamespace>\r\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v140_xp</PlatformToolset>\r\n    <CharacterSet>NotSet</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v140_xp</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>NotSet</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v140</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v140</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(ProjectDir)..\\..\\..\\bin\\$(PlatformName)\\$(Configuration)\\$(PlatformToolset)\\$(DefaultLinkage)\\</OutDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(ProjectDir)..\\..\\..\\bin\\$(PlatformName)\\$(Configuration)\\$(PlatformToolset)\\$(DefaultLinkage)\\</OutDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>\r\n      </PrecompiledHeader>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>\r\n      </PrecompiledHeader>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;LIBZMQ_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <PrecompiledHeader>\r\n      </PrecompiledHeader>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)</AdditionalIncludeDirectories>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <PrecompiledHeader>\r\n      </PrecompiledHeader>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;LIBZMQ_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"..\\..\\..\\src\\address.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\client.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\clock.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\ctx.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\curve_client.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\curve_mechanism_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\curve_server.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\dealer.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\decoder_allocators.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\devpoll.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\dgram.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\dish.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\dist.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\epoll.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\err.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\fq.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\gather.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\gssapi_client.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\gssapi_mechanism_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\gssapi_server.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\io_object.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\io_thread.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\ip.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\ipc_address.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\ipc_connecter.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\ipc_listener.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\kqueue.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\lb.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\mailbox.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\mailbox_safe.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\mechanism.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\mechanism_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\metadata.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\msg.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\mtrie.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\norm_engine.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\null_mechanism.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\object.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\options.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\own.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\pair.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\pgm_receiver.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\pgm_sender.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\pgm_socket.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\pipe.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\plain_client.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\plain_server.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\poll.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\poller_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\pollset.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\precompiled.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\proxy.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\pub.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\pull.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\push.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\radio.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\random.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\raw_decoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\raw_encoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\reaper.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\rep.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\req.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\router.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\scatter.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\select.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\server.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\session_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\signaler.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\socket_base.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\socket_poller.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\socks.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\socks_connecter.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\stream.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\stream_engine.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\sub.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\tcp.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\tcp_address.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\tcp_connecter.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\tcp_listener.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\thread.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\timers.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\tipc_address.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\tipc_connecter.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\tipc_listener.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\trie.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\udp_address.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\udp_engine.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\v1_decoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\v1_encoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\v2_decoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\v2_encoder.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\vmci.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\vmci_address.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\vmci_connecter.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\vmci_listener.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\xpub.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\xsub.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\zap_client.cpp\" />\r\n    <ClCompile Include=\"..\\..\\..\\src\\zmq.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"..\\..\\..\\src\\condition_variable.hpp\" />\r\n    <ClInclude Include=\"..\\..\\..\\src\\mutex.hpp\" />\r\n    <ClInclude Include=\"platform.hpp\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2015_xp/platform.hpp",
    "content": "#ifndef __PLATFORM_HPP_INCLUDED__\n#define __PLATFORM_HPP_INCLUDED__\n\n#define ZMQ_HAVE_WINDOWS\n#define ZMQ_HAVE_WINDOWS_TARGET_XP\n\n#define ZMQ_BUILD_DRAFT_API\n\n#define ZMQ_USE_SELECT\n#define FD_SETSIZE 1024\n\n#pragma comment(lib,\"ws2_32.lib\")\n#pragma comment(lib,\"Iphlpapi.lib\")\n\n#endif\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015_xp/test_zmq/test_multithread.cpp",
    "content": "﻿/*\r\nServer thread listen ZMQ_SERVER socket and transfer incoming message \r\nto worker threads by ZMQ_PUSH-ZMQ_PULL\r\nWorker thread receive message and send back to ZMQ_SERVER socket\r\n\r\nEach client thread open CLIENT_CONNECTION ZMQ_CLIENT sockets, \r\nsend random size message to each socket and check server answer\r\n*/\r\n\r\n#define ZMQ_BUILD_DRAFT_API\r\n#include \"../../../../include/zmq.h\"\r\n\r\n#pragma comment(lib,\"libzmq.lib\")\r\n\r\n#include <assert.h>\r\n#include <stdlib.h>\r\n#include <thread>\r\n#include <atomic>\r\n\r\n#define SERVER_ADDR \"tcp://127.0.0.1:12345\"\r\n#define SERVER_WORKER_COUNT 3\t// worker threads count\r\n\r\n#define CLIENT_COUNT 5\t\t\t// client threads count\r\n#define CLIENT_CONNECTION 100\t// ZMQ_CLIENT sockets at each client\r\n#define CLIENT_RECONNECT 1000\t// reconnect one socket after messages\r\n\r\n#define MESSAGE_MAX_SIZE 1024\r\n\r\n//*******************************************************************\r\n//****** MESSAGE ****************************************************\r\n//*******************************************************************\r\n\r\nvoid message_fill(zmq_msg_t* msg, int val) {\r\n\tassert(val > 0);\r\n\tint size = sizeof(int) * 2 + val;\r\n\tint rc = zmq_msg_init_size(msg, size); assert(rc == 0);\r\n\tuint8_t* data = (uint8_t*)zmq_msg_data(msg);\r\n\tmemcpy(data, &val, sizeof(int));\r\n\tdata += sizeof(int);\r\n\tmemset(data, val & 0xFF, val);\r\n\tint check_sum = val + (val & 0xFF) * val;\r\n\tdata += val;\r\n\tmemcpy(data, &check_sum, sizeof(int));\r\n}\r\n\r\nint message_check(zmq_msg_t* msg) {\r\n\tuint8_t* data = (uint8_t*)zmq_msg_data(msg);\r\n\tint size = zmq_msg_size(msg);\r\n\tassert(size > sizeof(int) * 2);\r\n\t// check size\r\n\tint val;\r\n\tmemcpy(&val, data, sizeof(int));\r\n\tif(size != sizeof(int) * 2 + val) { \r\n\t\tfprintf(stderr, \"wrong message: val = %d size = %d\\n\", val, size);\r\n\t\treturn -1;\r\n\t}\r\n\t// check sum\r\n\tdata += sizeof(int);\r\n\tint cs = val;\r\n\tfor(int i = 0; i < val; i++) {\r\n\t\tcs += data[i];\r\n\t}\r\n\tdata += val;\r\n\tint check_sum;\r\n\tmemcpy(&check_sum, data, sizeof(int));\r\n\tif(check_sum != cs) {\r\n\t\tfprintf(stderr, \"wrong message: cs = %d check_sum = %d\\n\", cs, check_sum);\r\n\t\treturn -1;\r\n\t}\r\n\treturn val;\r\n}\r\n\r\n//*******************************************************************\r\n//****** SERVER *****************************************************\r\n//*******************************************************************\r\n\r\nvoid *server_ctx = NULL;\r\nvoid *server_sock = NULL;\r\n\r\nstd::atomic<int> worker_cnt[SERVER_WORKER_COUNT] = {0}; // statistic\r\n\r\n// worker thread\r\nvoid worker(int num) {\r\n\tprintf(\"worker %d start\\n\", num);\r\n\tvoid* queue = zmq_socket(server_ctx, ZMQ_PULL); assert(queue);\r\n\tint rc = zmq_connect(queue, \"inproc://queue\"); assert(rc == 0);\r\n\r\n\twhile (1) {\r\n\t\t// receive messages from the queue\r\n\t\tzmq_msg_t msg;\r\n\t\trc = zmq_msg_init(&msg); assert(rc == 0);\r\n\t\trc = zmq_msg_recv(&msg, queue, 0); assert(rc > 0);\r\n\t\t// check message\r\n\t\t//printf(\"worker %d recv %d bytes at %X from %X\\n\", num, zmq_msg_size(&msg), zmq_msg_data(&msg), zmq_msg_routing_id(&msg));\r\n\t\t// send to client\r\n\t\trc = zmq_msg_send(&msg, server_sock, 0); assert(rc != -1);\r\n\t\tworker_cnt[num]++;\r\n\t}\r\n\tzmq_close(queue);\r\n}\r\n\r\n// server thread\r\nvoid server() {\r\n\tserver_ctx = zmq_ctx_new(); assert(server_ctx);\r\n\t// create queue\r\n\tvoid* queue = zmq_socket(server_ctx, ZMQ_PUSH);\tassert(queue);\r\n\tint rc = zmq_bind(queue, \"inproc://queue\"); assert(rc == 0);\r\n\t// start workers\r\n\tstd::thread w[SERVER_WORKER_COUNT];\r\n\tfor (int i = 0; i < SERVER_WORKER_COUNT; i++) w[i] = std::thread(worker, i);\r\n\t// ZMQ_SERVER for client messages\r\n\tserver_sock = zmq_socket(server_ctx, ZMQ_SERVER); assert(server_sock);\r\n\trc = zmq_bind(server_sock, SERVER_ADDR); assert(rc == 0);\r\n\r\n\twhile (1) {\r\n\t\t// wait client message\r\n\t\tzmq_msg_t msg;\r\n\t\trc = zmq_msg_init(&msg); assert(rc == 0); \r\n\t\trc = zmq_msg_recv(&msg, server_sock, 0); assert(rc > 0);\r\n\t\t//printf(\"recv %d bytes at %X from %X\\n\", zmq_msg_size(&msg), zmq_msg_data(&msg), zmq_msg_routing_id(&msg));\r\n\t\t// send message to queue\r\n\t\trc = zmq_msg_send(&msg, queue, 0); assert(rc > 0);\r\n\t}\r\n}\r\n\r\n//*******************************************************************\r\n//****** CLIENT *****************************************************\r\n//*******************************************************************\r\n\r\nstd::atomic<int> client_cnt[CLIENT_COUNT] = { 0 }; // statistic\r\nstd::atomic<int> client_ready = 0; \r\n\r\n// client thread\r\nvoid client(int num)\r\n{\r\n\t//printf(\"client %d start. Open %d connections\\n\", num, CLIENT_CONNECTION);\r\n\r\n\tvoid *ctx = zmq_ctx_new(); assert(ctx);\r\n\r\n\tvoid *sock[CLIENT_CONNECTION];\r\n\tint rc;\r\n\t// open ZMQ_CLIENT connections\r\n\tfor (int i = 0; i < CLIENT_CONNECTION; i++) {\r\n\t\tsock[i] = zmq_socket(ctx, ZMQ_CLIENT); assert(sock[i]);\r\n\t\trc = zmq_connect(sock[i], SERVER_ADDR); assert(rc == 0);\r\n\t\t// test connection\r\n\t\tzmq_msg_t msg;\r\n\t\tint v = rand() % 256 + 1;\r\n\t\tmessage_fill(&msg, v);\r\n\t\trc = zmq_msg_send(&msg, sock[i], 0); assert(rc > 0);\r\n\t\trc = zmq_msg_init(&msg); assert(rc == 0);\r\n\t\trc = zmq_msg_recv(&msg, sock[i], 0); assert(rc > 0);\r\n\t\trc = message_check(&msg); assert(rc == v);\r\n\t\tzmq_msg_close(&msg);\r\n\t}\r\n\tprintf(\"client %d open %d connections\\n\", num, CLIENT_CONNECTION);\r\n\tclient_ready++;\r\n\twhile (client_ready < CLIENT_COUNT) Sleep(10); // wait while all clients open sockets\r\n\r\n\tint reconnect = 0;\r\n\twhile(1) {\r\n\t\tint val[CLIENT_CONNECTION];\r\n\t\tzmq_msg_t msg;\r\n\t\t// send messages\r\n\t\tfor(int i = 0; i < CLIENT_CONNECTION; i++) {\r\n\t\t\tval[i] = rand() % MESSAGE_MAX_SIZE + 1;\r\n\t\t\tmessage_fill(&msg, val[i]);\r\n\t\t\trc = zmq_msg_send(&msg, sock[i], 0); assert(rc > 0);\r\n\t\t}\r\n\t\t// recv and check\r\n\t\tfor (int i = 0; i < CLIENT_CONNECTION; i++) {\r\n\t\t\trc = zmq_msg_init(&msg); assert(rc == 0);\r\n\t\t\trc = zmq_msg_recv(&msg, sock[i], 0); assert(rc > 0);\r\n\t\t\trc = message_check(&msg);\r\n\t\t\tif(rc != val[i] && rc > 0) {\r\n\t\t\t\tfprintf(stderr, \"wrong message: send %d recv %d     \\n\", val[i], rc);\r\n\t\t\t}\r\n\t\t\tzmq_msg_close(&msg);\r\n\t\t\tclient_cnt[num]++;\r\n\t\t}\r\n\t\t// reconnect one\r\n\t\treconnect++;\r\n\t\tif(reconnect == CLIENT_RECONNECT) {\r\n\t\t\tint n = rand() % CLIENT_CONNECTION;\r\n\t\t\tzmq_close(sock[n]);\r\n\t\t\tsock[n] = zmq_socket(ctx, ZMQ_CLIENT); assert(sock[n]);\r\n\t\t\tint rc = zmq_connect(sock[n], SERVER_ADDR); assert(rc == 0);\r\n\t\t}\r\n\t}\r\n}\r\n\r\n//*******************************************************************\r\nint main (void) {\r\n\tint v1, v2, v3; zmq_version(&v1, &v2, &v3);\r\n\tprintf(\"ZMQ version %d.%d.%d. Compile %s %s\\n\", v1, v2, v3, __DATE__, __TIME__);\r\n\r\n\tstd::thread ct[CLIENT_COUNT];\r\n\tfor (int i = 0; i < CLIENT_COUNT; i++) ct[i] = std::thread(client, i);\r\n\r\n\tstd::thread st(server);\r\n\r\n\tint w[SERVER_WORKER_COUNT] = { 0 };\r\n\tint c[CLIENT_COUNT] = { 0 };\r\n\tint total = 0;\r\n\r\n\twhile(1) {\r\n\t\tSleep(1000);\r\n\t\tif (client_ready < CLIENT_COUNT) continue;\r\n\t\t// check workers\r\n\t\tfor(int i = 0; i < SERVER_WORKER_COUNT; i++) {\r\n\t\t\tif(w[i] == worker_cnt[i]) {\r\n\t\t\t\tfprintf(stderr, \"worker %d not work        \\n\", i);\r\n\t\t\t}\r\n\t\t\tw[i] = worker_cnt[i];\r\n\t\t}\r\n\t\t// check clients\r\n\t\tint t = 0;\r\n\t\tfor (int i = 0; i < CLIENT_COUNT; i++) {\r\n\t\t\tif (c[i] == client_cnt[i]) {\r\n\t\t\t\tfprintf(stderr, \"client %d not work        \\n\", i);\r\n\t\t\t}\r\n\t\t\tc[i] = client_cnt[i];\r\n\t\t\tt += c[i];\r\n\t\t}\r\n\t\tprintf(\"\\rTotal %d messages. Speed %d per second  \", t, t - total);\r\n\t\ttotal = t;\r\n\t}\r\n\treturn 0;\r\n}\r\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2015_xp/test_zmq/test_zmq.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <ProjectGuid>{101324AB-CF3E-4D99-8B69-2000CEA487B6}</ProjectGuid>\r\n    <Keyword>Win32Proj</Keyword>\r\n    <RootNamespace>test_zmq</RootNamespace>\r\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v140_xp</PlatformToolset>\r\n    <CharacterSet>NotSet</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v140_xp</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>NotSet</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v140</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v140</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(ProjectDir)..\\..\\..\\..\\bin\\$(PlatformName)\\$(Configuration)\\$(PlatformToolset)\\$(DefaultLinkage)\\</OutDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(ProjectDir)..\\..\\..\\..\\bin\\$(PlatformName)\\$(Configuration)\\$(PlatformToolset)\\$(DefaultLinkage)\\</OutDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>\r\n      </PrecompiledHeader>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <AdditionalLibraryDirectories>$(ProjectDir)..\\..\\..\\..\\bin\\$(PlatformName)\\$(Configuration)\\$(PlatformToolset)\\$(DefaultLinkage)\\</AdditionalLibraryDirectories>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>\r\n      </PrecompiledHeader>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <PrecompiledHeader>\r\n      </PrecompiledHeader>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <AdditionalLibraryDirectories>$(ProjectDir)..\\..\\..\\..\\bin\\$(PlatformName)\\$(Configuration)\\$(PlatformToolset)\\$(DefaultLinkage)\\</AdditionalLibraryDirectories>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <PrecompiledHeader>\r\n      </PrecompiledHeader>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"test_multithread.cpp\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/inproc_lat/inproc_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ inproc_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\"  Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/inproc_lat/inproc_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}</ProjectGuid>\n    <ProjectName>inproc_lat</ProjectName>\n    <PlatformToolset>v141</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\inproc_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/inproc_thr/inproc_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ inproc_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/inproc_thr/inproc_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{1077E977-95DD-4E73-A692-74647DD0CC1E}</ProjectGuid>\n    <ProjectName>inproc_thr</ProjectName>\n    <PlatformToolset>v141</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\inproc_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/libsodium.import.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"Globals\">\n    <_PropertySheetDisplayName>Libsodium Import Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)libsodium.import.xml\" />\n  </ItemGroup>\n\n  <!-- Linkage -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\src\\libsodium\\include;$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\src\\libsodium\\include\\sodium\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Linkage-libsodium)' == 'static' Or '$(Linkage-libsodium)' == 'ltcg'\">SODIUM_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(Linkage-libsodium)' != ''\">advapi32.lib;libsodium.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Debug')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\$(Linkage-libsodium)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Release')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\$(Linkage-libsodium)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Copy -->\n\n  <Target Name=\"Linkage-libsodium-dynamic\" AfterTargets=\"AfterBuild\" Condition=\"'$(Linkage-libsodium)' == 'dynamic'\">\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libsodium.dll\"\n          DestinationFiles=\"$(TargetDir)libsodium.dll\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libsodium.pdb\"\n          DestinationFiles=\"$(TargetDir)libsodium.pdb\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Release')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libsodium\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\dynamic\\libsodium.dll\"\n          DestinationFiles=\"$(TargetDir)libsodium.dll\"\n          SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <!-- Messages -->\n\n  <Target Name=\"libsodium-info\" BeforeTargets=\"AfterBuild\" Condition=\"'$(Linkage-libsodium)' == 'dynamic'\">\n    <Message Text=\"Copying libsodium.dll -&gt; $(TargetDir)libsodium.dll\" Importance=\"high\"/>\n    <Message Text=\"Copying libsodium.pdb -&gt; $(TargetDir)libsodium.pdb\" Importance=\"high\" Condition=\"$(Configuration.IndexOf('Debug')) != -1\" />\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/libsodium.import.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libsodium-linkage-uiextension\" PageTemplate=\"tool\" DisplayName=\"Local Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"libsodium\" DisplayName=\"libsodium\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-libsodium\" DisplayName=\"Linkage\" Description=\"How libsodium will be linked into the output of this project\" Category=\"libsodium\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/libzmq/libzmq.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ Library Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)$(ProjectName).xml\" />\n  </ItemGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;$(ProjectDir)..\\..\\..\\..\\include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <EnablePREfast>false</EnablePREfast>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>precompiled.hpp</PrecompiledHeaderFile>\n      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;FD_SETSIZE=16384;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_HAVE_CURVE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-openpgm)' == 'true'\">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-gssapi)' == 'true'\">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-draftapi)' == 'true'\">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-usepoll)' == 'true'\">ZMQ_USE_POLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-usepoll)' != 'true'\">ZMQ_USE_SELECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)' == 'StaticLibrary'\">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)' == 'DynamicLibrary'\">DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Ws2_32.lib;Rpcrt4.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Lib Condition=\"'$(ConfigurationType)'=='StaticLibrary'\">\n      <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions>\n    </Lib>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"OptionInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Option-sodium     : $(Option-sodium)\" Importance=\"high\"/>\n    <Message Text=\"Option-openpgm    : $(Option-openpgm)\" Importance=\"high\"/>\n    <Message Text=\"Option-gssapi     : $(Option-gssapi)\" Importance=\"high\"/>\n    <Message Text=\"Option-draftapi   : $(Option-draftapi)\" Importance=\"high\"/>\n    <Message Text=\"Option-usepoll    : $(Option-usepoll)\" Importance=\"high\"/>\n  </Target>\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(Option-sodium)' == 'true'\"/>\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/libzmq/libzmq.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{641C5F36-32EE-4323-B740-992B651CF9D6}</ProjectGuid>\n    <ProjectName>libzmq</ProjectName>\n    <PlatformToolset>v141</PlatformToolset>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDLL|Win32\">\n      <Configuration>DebugDLL</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDLL|Win32\">\n      <Configuration>ReleaseDLL</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDLL|x64\">\n      <Configuration>DebugDLL</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDLL|x64\">\n      <Configuration>ReleaseDLL</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLTCG|Win32\">\n      <Configuration>DebugLTCG</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLTCG|Win32\">\n      <Configuration>ReleaseLTCG</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLTCG|x64\">\n      <Configuration>DebugLTCG</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLTCG|x64\">\n      <Configuration>ReleaseLTCG</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLIB|Win32\">\n      <Configuration>DebugLIB</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLIB|Win32\">\n      <Configuration>ReleaseLIB</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLIB|x64\">\n      <Configuration>DebugLIB</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLIB|x64\">\n      <Configuration>ReleaseLIB</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Configuration\">\n    <ConfigurationType Condition=\"$(Configuration.IndexOf('DLL')) == -1\">StaticLibrary</ConfigurationType>\n    <ConfigurationType Condition=\"$(Configuration.IndexOf('DLL')) != -1\">DynamicLibrary</ConfigurationType>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n    <ClInclude Include=\"..\\..\\resource.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\include\\zmq.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\zmq_draft.h\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\array.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_counter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\blob.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\clock.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\command.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\condition_variable.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\config.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ctx.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\devpoll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dgram.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dish.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dist.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\epoll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\err.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fd.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fq.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gather.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_client.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_poll_events.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_object.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_thread.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_listener.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\kqueue.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\lb.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\likely.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\msg.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mtrie.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mutex.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\object.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\options.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\own.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pair.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_sender.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_socket.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pipe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\server.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poll.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\precompiled.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\proxy.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pull.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\push.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\radio.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\random.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\reaper.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\rep.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\req.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\scatter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\select.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\session_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\signaler.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socket_base.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stdint.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stream_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\sub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_listener.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\timers.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\thread.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\trie.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_address.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_engine.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_decoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_encoder.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_protocol.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\windows.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\wire.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xpub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xrep.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xreq.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xsub.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ypipe.hpp\" />\n    <ClInclude Include=\"..\\..\\..\\..\\src\\yqueue.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\clock.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ctx.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dealer.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\devpoll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dgram.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dish.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dist.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\epoll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\err.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\fq.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gather.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_object.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_thread.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_listener.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\kqueue.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\lb.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\metadata.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\msg.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mtrie.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\null_mechanism.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\object.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\options.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\own.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pair.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_sender.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_socket.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pipe.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poll.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poller_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\precompiled.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\proxy.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pull.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\push.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\radio.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\random.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\reaper.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\rep.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\req.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\router.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\scatter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\select.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\server.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\session_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\signaler.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_base.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_poller.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream_engine.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\sub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_listener.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\thread.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\timers.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\trie.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_address.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_engine.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_decoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_encoder.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xpub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xsub.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zap_client.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq_utils.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.bat\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.config\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.gsl\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.nuspec\" />\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.targets\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"..\\..\\..\\..\\packaging\\nuget\\package.xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\..\\resource.rc\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/libzmq/libzmq.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\clock.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ctx.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dealer.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\devpoll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dgram.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dist.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\epoll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\err.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\fq.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_object.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\io_thread.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ip.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\ipc_listener.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\kqueue.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\lb.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mechanism.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\metadata.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\msg.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mtrie.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\null_mechanism.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\object.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\options.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\own.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pair.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_receiver.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_sender.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pgm_socket.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pipe.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\plain_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poll.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\poller_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\proxy.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\pull.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\push.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\random.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\raw_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\reaper.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\rep.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\req.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\router.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\scatter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\select.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\session_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\signaler.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\stream_engine.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\sub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\tcp_listener.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\thread.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\trie.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v1_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_decoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\v2_encoder.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xpub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\xsub.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\zmq_utils.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\precompiled.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\curve_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gather.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\gssapi_client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socks_connecter.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\server.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\client.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\mailbox_safe.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\decoder_allocators.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\socket_poller.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_address.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\udp_engine.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\dish.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\radio.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\..\\..\\src\\timers.cpp\">\n      <Filter>src</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\..\\..\\include\\zmq.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\array.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_counter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\atomic_ptr.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\blob.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\clock.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\command.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\config.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ctx.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\devpoll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dgram.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dist.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\epoll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\err.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fd.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\fq.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\i_poll_events.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_object.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\io_thread.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ip.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ipc_listener.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\kqueue.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\lb.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\likely.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\msg.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mtrie.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mutex.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\object.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\options.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\own.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pair.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_receiver.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\yqueue.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\ypipe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xsub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xreq.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xrep.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\xpub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\wire.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\windows.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_protocol.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\v1_decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\trie.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\thread.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_listener.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\tcp.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\sub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stream_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\stdint.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socket_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\signaler.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\session_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\scatter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\select.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\req.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\rep.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\reaper.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_encoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\raw_decoder.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\random.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\push.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pull.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pub.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\proxy.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\precompiled.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poller.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\poll.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\platform.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pipe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_socket.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\pgm_sender.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\resource.h\">\n      <Filter>resource</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\curve_server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gather.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_mechanism_base.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\gssapi_client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\socks_connecter.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\server.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\client.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\mailbox_safe.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\condition_variable.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\decoder_allocators.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_address.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\udp_engine.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\dish.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\radio.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\timers.hpp\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\..\\..\\src\\zmq_draft.h\">\n      <Filter>src\\include</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"include\">\n      <UniqueIdentifier>{f7e88c6c-e408-4631-959c-fe3568656d70}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"src\">\n      <UniqueIdentifier>{35f0c644-e1d8-4a46-bb33-06bb8b645fff}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"src\\include\">\n      <UniqueIdentifier>{90853975-3420-4f06-8be4-4ab3d9792160}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"packaging\">\n      <UniqueIdentifier>{f5e26e9d-c33d-45c1-95e4-0732acd28b59}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"resource\">\n      <UniqueIdentifier>{e66010e4-a9ea-4e2e-8bc6-12fec14bb009}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.bat\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.config\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.gsl\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.targets\">\n      <Filter>packaging</Filter>\n    </None>\n    <None Include=\"..\\..\\..\\..\\packaging\\nuget\\package.nuspec\">\n      <Filter>packaging</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"..\\..\\..\\..\\packaging\\nuget\\package.xml\">\n      <Filter>packaging</Filter>\n    </Xml>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"..\\..\\resource.rc\">\n      <Filter>resource</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/libzmq/libzmq.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libzmq-uiextension\" PageTemplate=\"tool\" DisplayName=\"ZMQ Options\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"sodium\" DisplayName=\"sodium\" />\n      <Category Name=\"openpgm\" DisplayName=\"openpgm\" />\n      <Category Name=\"gssapi\" DisplayName=\"gssapi\" />\n      <Category Name=\"draftapi\" DisplayName=\"draftapi\" />\n      <Category Name=\"usepoll\" DisplayName=\"usepoll\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Option-sodium\" DisplayName=\"Enable Sodium\" Description=\"Enable Sodium build option\" Category=\"sodium\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-openpgm\" DisplayName=\"Enable OpenPGM\" Description=\"Enable OpenPGM build option\" Category=\"openpgm\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-gssapi\" DisplayName=\"Enable GSS API\" Description=\"Enable GSS API build option\" Category=\"gssapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-draftapi\" DisplayName=\"Enable Draft API\" Description=\"Enable Draft API build option\" Category=\"draftapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-usepoll\" DisplayName=\"Enable poll() usage (Vista+ only)\" Description=\"Use poll() instead of select() for waiting on incoming data. Increases performance, but the binary will only run on Windows Vista or later.\" Category=\"usepoll\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/libzmq.import.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"Globals\">\n    <_PropertySheetDisplayName>ZMQ Import Settings</_PropertySheetDisplayName>\n  </PropertyGroup>\n\n  <!-- User Interface -->\n\n  <ItemGroup Label=\"BuildOptionsExtension\">\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)libzmq.import.xml\" />\n  </ItemGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions Condition=\"'$(Option-sodium)' == 'true'\">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-openpgm)' == 'true'\">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-gssapi)' == 'true'\">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Option-draftapi)' == 'true'\">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <!-- Linkage -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions Condition=\"'$(Linkage-libzmq)' == 'static' Or '$(Linkage-libzmq)' == 'ltcg'\">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(Linkage-libzmq)' != ''\">libzmq.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Debug')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\$(Linkage-libzmq)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <AdditionalLibraryDirectories Condition=\"$(Configuration.IndexOf('Release')) != -1\">$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\$(Linkage-libzmq)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Copy -->\n\n  <Target Name=\"Linkage-libzmq-dynamic\" AfterTargets=\"AfterBuild\" Condition=\"'$(Linkage-libzmq)' == 'dynamic'\">\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libzmq.dll\"\n          DestinationFiles=\"$(TargetDir)libzmq.dll\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Debug')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Debug\\$(PlatformToolset)\\dynamic\\libzmq.pdb\"\n          DestinationFiles=\"$(TargetDir)libzmq.pdb\"\n          SkipUnchangedFiles=\"true\" />\n    <Copy Condition=\"$(Configuration.IndexOf('Release')) != -1\"\n          SourceFiles=\"$(ProjectDir)..\\..\\..\\..\\..\\libzmq\\bin\\$(PlatformName)\\Release\\$(PlatformToolset)\\dynamic\\libzmq.dll\"\n          DestinationFiles=\"$(TargetDir)libzmq.dll\"\n          SkipUnchangedFiles=\"true\" />\n  </Target>\n\n  <!-- Messages -->\n\n  <Target Name=\"libzmq-info\" BeforeTargets=\"AfterBuild\" Condition=\"'$(Linkage-libzmq)' == 'dynamic'\">\n    <Message Text=\"Copying libzmq.dll -&gt; $(TargetDir)libzmq.dll\" Importance=\"high\"/>\n    <Message Text=\"Copying libzmq.pdb -&gt; $(TargetDir)libzmq.pdb\" Importance=\"high\" Condition=\"$(Configuration.IndexOf('Debug')) != -1\" />\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/libzmq.import.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"libzmq-options-uiextension\" PageTemplate=\"tool\" DisplayName=\"ZMQ Options\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"sodium\" DisplayName=\"sodium\" />\n      <Category Name=\"openpgm\" DisplayName=\"openpgm\" />\n      <Category Name=\"gssapi\" DisplayName=\"gssapi\" />\n      <Category Name=\"draftapi\" DisplayName=\"draftapi\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Option-sodium\" DisplayName=\"Enable Sodium\" Description=\"Enable the Sodium build option\" Category=\"sodium\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-openpgm\" DisplayName=\"Enable OpenPGM\" Description=\"Enable the OpenPGM build option\" Category=\"openpgm\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-gssapi\" DisplayName=\"Enable GSS API\" Description=\"Enable the GSS API build option\" Category=\"gssapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n    <EnumProperty Name=\"Option-draftapi\" DisplayName=\"Enable Draft API\" Description=\"Enable Draft API build option\" Category=\"draftapi\">\n      <EnumValue Name=\"\" DisplayName=\"No\" />\n      <EnumValue Name=\"true\" DisplayName=\"Yes\" />\n    </EnumProperty>\n  </Rule>\n  <Rule Name=\"libzmq-linkage-uiextension\" PageTemplate=\"tool\" DisplayName=\"Local Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"libzmq\" DisplayName=\"libzmq\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-libzmq\" DisplayName=\"Linkage\" Description=\"How libzmq will be linked into the output of this project\" Category=\"libzmq\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/libzmq.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.23107.0\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libzmq\", \"libzmq\\libzmq.vcxproj\", \"{641C5F36-32EE-4323-B740-992B651CF9D6}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_thr\", \"inproc_thr\\inproc_thr.vcxproj\", \"{1077E977-95DD-4E73-A692-74647DD0CC1E}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"inproc_lat\", \"inproc_lat\\inproc_lat.vcxproj\", \"{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_thr\", \"remote_thr\\remote_thr.vcxproj\", \"{B15E059C-0CBB-4A82-8C42-6567FB650802}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"remote_lat\", \"remote_lat\\remote_lat.vcxproj\", \"{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_thr\", \"local_thr\\local_thr.vcxproj\", \"{8EF2DF6B-6646-460F-8032-913B70FE0E94}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"local_lat\", \"local_lat\\local_lat.vcxproj\", \"{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDynDebug|Win32 = DynDebug|Win32\n\t\tDynDebug|x64 = DynDebug|x64\n\t\tDynRelease|Win32 = DynRelease|Win32\n\t\tDynRelease|x64 = DynRelease|x64\n\t\tLtcgDebug|Win32 = LtcgDebug|Win32\n\t\tLtcgDebug|x64 = LtcgDebug|x64\n\t\tLtcgRelease|Win32 = LtcgRelease|Win32\n\t\tLtcgRelease|x64 = LtcgRelease|x64\n\t\tStaticDebug|Win32 = StaticDebug|Win32\n\t\tStaticDebug|x64 = StaticDebug|x64\n\t\tStaticRelease|Win32 = StaticRelease|Win32\n\t\tStaticRelease|x64 = StaticRelease|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|Win32.ActiveCfg = DebugDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|Win32.Build.0 = DebugDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|x64.ActiveCfg = DebugDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynDebug|x64.Build.0 = DebugDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|Win32.ActiveCfg = ReleaseDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|Win32.Build.0 = ReleaseDLL|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|x64.ActiveCfg = ReleaseDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.DynRelease|x64.Build.0 = ReleaseDLL|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|Win32.ActiveCfg = DebugLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|Win32.Build.0 = DebugLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|x64.ActiveCfg = DebugLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgDebug|x64.Build.0 = DebugLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|Win32.ActiveCfg = ReleaseLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|Win32.Build.0 = ReleaseLTCG|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|x64.ActiveCfg = ReleaseLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.LtcgRelease|x64.Build.0 = ReleaseLTCG|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.ActiveCfg = DebugLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|Win32.Build.0 = DebugLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|x64.ActiveCfg = DebugLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticDebug|x64.Build.0 = DebugLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.ActiveCfg = ReleaseLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|Win32.Build.0 = ReleaseLIB|Win32\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|x64.ActiveCfg = ReleaseLIB|x64\n\t\t{641C5F36-32EE-4323-B740-992B651CF9D6}.StaticRelease|x64.Build.0 = ReleaseLIB|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{1077E977-95DD-4E73-A692-74647DD0CC1E}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{6FF7436F-B3F6-4AE9-A3AC-CFDE8A3872A0}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{B15E059C-0CBB-4A82-8C42-6567FB650802}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{8EF2DF6B-6646-460F-8032-913B70FE0E94}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|Win32.ActiveCfg = DebugDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|Win32.Build.0 = DebugDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|x64.ActiveCfg = DebugDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynDebug|x64.Build.0 = DebugDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|Win32.ActiveCfg = ReleaseDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|Win32.Build.0 = ReleaseDEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|x64.ActiveCfg = ReleaseDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.DynRelease|x64.Build.0 = ReleaseDEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|Win32.ActiveCfg = DebugLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|Win32.Build.0 = DebugLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|x64.ActiveCfg = DebugLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgDebug|x64.Build.0 = DebugLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|Win32.ActiveCfg = ReleaseLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|Win32.Build.0 = ReleaseLEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|x64.ActiveCfg = ReleaseLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.LtcgRelease|x64.Build.0 = ReleaseLEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticDebug|x64.Build.0 = DebugSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64\n\t\t{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/local_lat/local_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ local_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/local_lat/local_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{4FDB8C73-9D4A-4D87-A4A9-A7FC06DFEA57}</ProjectGuid>\n    <ProjectName>local_lat</ProjectName>\n    <PlatformToolset>v141</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\local_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/local_thr/local_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ local_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/local_thr/local_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{8EF2DF6B-6646-460F-8032-913B70FE0E94}</ProjectGuid>\n    <ProjectName>local_thr</ProjectName>\n    <PlatformToolset>v141</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\local_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/remote_lat/remote_lat.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ remote_lat Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/remote_lat/remote_lat.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{9C20A37C-5D9F-4C4C-A2D9-E6EE91A077D1}</ProjectGuid>\n    <ProjectName>remote_lat</ProjectName>\n    <PlatformToolset>v141</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\remote_lat.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/remote_thr/remote_thr.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <_PropertySheetDisplayName>ZeroMQ remote_thr Common Settings</_PropertySheetDisplayName>\n    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n\n  <!-- Configuration -->\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir)..\\..\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>Advapi32.lib;Rpcrt4.lib;Ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- Dependencies -->\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"..\\libzmq.import.props\" />\n    <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props\"\n            Condition=\"Exists('$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\libsodium\\builds\\msvc\\vs2015\\libsodium.import.props')\" /> \n  </ImportGroup>\n  \n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'dynamic'\">\n    <Linkage-libzmq>dynamic</Linkage-libzmq>\n    <!--<Linkage-libsodium>dynamic</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'ltcg'\">\n    <Linkage-libzmq>ltcg</Linkage-libzmq>\n    <!--<Linkage-libsodium>ltcg</Linkage-libsodium>-->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(DefaultLinkage)' == 'static'\">\n    <Linkage-libzmq>static</Linkage-libzmq>\n    <!--<Linkage-libsodium>static</Linkage-libsodium>-->\n  </PropertyGroup>\n\n  <!-- Messages -->\n\n  <Target Name=\"LinkageInfo\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Linkage-libzmq    : $(Linkage-libzmq)\" Importance=\"high\"/>\n    <Message Text=\"Linkage-libsodium : $(Linkage-libsodium)\" Importance=\"high\" Condition=\"'$(HAVE_LIBSODIUM)'=='1'\"/>\n  </Target>\n\n</Project>"
  },
  {
    "path": "builds/deprecated-msvc/vs2017/remote_thr/remote_thr.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{B15E059C-0CBB-4A82-8C42-6567FB650802}</ProjectGuid>\n    <ProjectName>remote_thr</ProjectName>\n    <PlatformToolset>v141</PlatformToolset>\n    <ConfigurationType>Application</ConfigurationType>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugDEXE|Win32\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|Win32\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugDEXE|x64\">\n      <Configuration>DebugDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseDEXE|x64\">\n      <Configuration>ReleaseDEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|Win32\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|Win32\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugLEXE|x64\">\n      <Configuration>DebugLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseLEXE|x64\">\n      <Configuration>ReleaseLEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|Win32\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|Win32\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugSEXE|x64\">\n      <Configuration>DebugSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseSEXE|x64\">\n      <Configuration>ReleaseSEXE</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\$(Configuration).props\" />\n    <Import Project=\"$(ProjectDir)..\\..\\properties\\Output.props\" />\n    <Import Project=\"$(ProjectDir)$(ProjectName).props\" />\n  </ImportGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\platform.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\..\\..\\perf\\remote_thr.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libzmq\\libzmq.vcxproj\">\n      <Project>{641c5f36-32ee-4323-b740-992b651cf9d6}</Project>\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "builds/fuzz/ci_build.sh",
    "content": "#!/usr/bin/env bash\n# used by oss-fuzz https://github.com/google/oss-fuzz/tree/master/projects/libzmq\n\nset -e\nset -x\n\ncd \"${SRC}/libsodium\"\nDO_NOT_UPDATE_CONFIG_SCRIPTS=1 ./autogen.sh\n./configure --disable-shared --prefix=/install_prefix --disable-asm\nmake -j$(nproc) V=1 install DESTDIR=/tmp/zmq_install_dir\n\ncd \"${SRC}/libzmq\"\n./autogen.sh\nexport LDFLAGS+=\" $(PKG_CONFIG_PATH=/tmp/zmq_install_dir/install_prefix/lib/pkgconfig pkg-config --static --libs --define-prefix libsodium)\"\nexport CXXFLAGS+=\" $(PKG_CONFIG_PATH=/tmp/zmq_install_dir/install_prefix/lib/pkgconfig pkg-config --static --cflags --define-prefix libsodium)\"\n./configure --disable-shared --prefix=/install_prefix --disable-perf --disable-curve-keygen PKG_CONFIG_PATH=/tmp/zmq_install_dir/install_prefix/lib/pkgconfig --with-libsodium=yes --with-fuzzing-installdir=fuzzers --with-fuzzing-engine=$LIB_FUZZING_ENGINE\nmake -j$(nproc) V=1 install DESTDIR=/tmp/zmq_install_dir\n\ncd \"${SRC}/libzmq-fuzz-corpora\"\ncp dictionaries/* /tmp/zmq_install_dir/install_prefix/fuzzers/\nfor t in test_*_seed_corpus; do\n  zip -j --quiet /tmp/zmq_install_dir/install_prefix/fuzzers/${t}.zip ${t}/*\ndone\n\ncp /tmp/zmq_install_dir/install_prefix/fuzzers/* \"${OUT}\"\n"
  },
  {
    "path": "builds/gyp/.gitignore",
    "content": "project.Makefile\n*.mk\nout/\nMakefile\n\n"
  },
  {
    "path": "builds/gyp/build.bat",
    "content": "@echo off\n:-  Needs Visual Studio 2015\n\"\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\vcvars32.bat\"\nmsbuild /m /v:m project.sln\n"
  },
  {
    "path": "builds/gyp/platform.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PLATFORM_HPP_INCLUDED__\n#define __ZMQ_PLATFORM_HPP_INCLUDED__\n\n//  This file provides the configuration for Linux, Windows, and OS/X\n//  as determined by ZMQ_HAVE_XXX macros passed from project.gyp\n\n//  Check that we're being called from our gyp makefile\n#ifndef ZMQ_GYP_BUILD\n#   error \"foreign platform.hpp detected, please re-configure\"\n#endif\n\n//  Set for all platforms\n#define ZMQ_HAVE_CURVE 1\n\n#if defined ZMQ_HAVE_WINDOWS\n#   define ZMQ_USE_SELECT 1\n\n#elif defined ZMQ_HAVE_OSX\n#   define ZMQ_USE_KQUEUE 1\n#   define HAVE_POSIX_MEMALIGN 1\n#   define ZMQ_HAVE_IFADDRS 1\n#   define ZMQ_HAVE_SO_KEEPALIVE 1\n#   define ZMQ_HAVE_TCP_KEEPALIVE 1\n#   define ZMQ_HAVE_TCP_KEEPCNT 1\n#   define ZMQ_HAVE_TCP_KEEPINTVL 1\n#   define ZMQ_HAVE_UIO 1\n#   define HAVE_FORK 1\n\n#elif defined ZMQ_HAVE_LINUX\n#   define ZMQ_USE_EPOLL 1\n#   define HAVE_POSIX_MEMALIGN 1\n#   define ZMQ_HAVE_EVENTFD 1\n#   define ZMQ_HAVE_IFADDRS 1\n#   define ZMQ_HAVE_SOCK_CLOEXEC 1\n#   define ZMQ_HAVE_SO_BINDTODEVICE 1\n#   define ZMQ_HAVE_SO_KEEPALIVE 1\n#   define ZMQ_HAVE_SO_PEERCRED 1\n#   define ZMQ_HAVE_TCP_KEEPCNT 1\n#   define ZMQ_HAVE_TCP_KEEPIDLE 1\n#   define ZMQ_HAVE_TCP_KEEPINTVL 1\n#   define ZMQ_HAVE_UIO 1\n#   define HAVE_CLOCK_GETTIME 1\n#   define HAVE_FORK 1\n#   define HAVE_ACCEPT4 1\n\n#else\n#   error \"No platform defined, abandoning\"\n#endif\n\n#endif\n"
  },
  {
    "path": "builds/gyp/project-tests.gsl",
    "content": ".echo \"Generating project-tests.gypi...\"\n.output \"project-tests.gypi\"\n{\n  'targets': [\n.for test\n    {\n      'target_name': '$(name)',\n      'type': 'executable',\n      'sources': [\n        '../../tests/$(name).cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    }$(last ()?? \"\"? \",\")\n.endfor\n  ]\n}\n"
  },
  {
    "path": "builds/gyp/project-tests.gypi",
    "content": "{\n  'targets': [\n    {\n      'target_name': 'test_system',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_system.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_pair_inproc',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_pair_inproc.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_pair_tcp',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_pair_tcp.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_reqrep_inproc',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_reqrep_inproc.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_reqrep_tcp',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_reqrep_tcp.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_hwm',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_hwm.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_hwm_pubsub',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_hwm_pubsub.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_reqrep_device',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_reqrep_device.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_sub_forward',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_sub_forward.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_invalid_rep',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_invalid_rep.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_msg_flags',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_msg_flags.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_msg_ffn',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_msg_ffn.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_msg_init',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_msg_init.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_connect_resolve',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_connect_resolve.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_immediate',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_immediate.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_last_endpoint',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_last_endpoint.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_term_endpoint',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_term_endpoint.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_srcfd',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_srcfd.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_monitor',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_monitor.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_router_mandatory',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_router_mandatory.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_router_mandatory_hwm',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_router_mandatory_hwm.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_router_handover',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_router_handover.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_probe_router',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_probe_router.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_stream',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_stream.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_stream_empty',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_stream_empty.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_stream_disconnect',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_stream_disconnect.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_stream_timeout',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_stream_timeout.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_disconnect_inproc',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_disconnect_inproc.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_unbind_inproc',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_unbind_inproc.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_unbind_wildcard',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_unbind_wildcard.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_ctx_options',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_ctx_options.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_ctx_destroy',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_ctx_destroy.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_security_null',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_security_null.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_security_plain',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_security_plain.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_security_curve',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_security_curve.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_security_zap',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_security_zap.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_iov',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_iov.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_spec_req',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_spec_req.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_spec_rep',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_spec_rep.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_spec_dealer',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_spec_dealer.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_spec_router',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_spec_router.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_spec_pushpull',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_spec_pushpull.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_req_correlate',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_req_correlate.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_req_relaxed',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_req_relaxed.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_conflate',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_conflate.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_inproc_connect',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_inproc_connect.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_issue_566',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_issue_566.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_proxy',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_proxy.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_proxy_single_socket',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_proxy_single_socket.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_proxy_terminate',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_proxy_terminate.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_getsockopt_memset',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_getsockopt_memset.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_setsockopt',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_setsockopt.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_many_sockets',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_many_sockets.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_ipc_wildcard',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_ipc_wildcard.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_diffserv',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_diffserv.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_connect_rid',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_connect_rid.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_bind_src_address',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_bind_src_address.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_metadata',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_metadata.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_capabilities',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_capabilities.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_xpub_nodrop',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_xpub_nodrop.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_xpub_manual',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_xpub_manual.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_xpub_welcome_msg',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_xpub_welcome_msg.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_atomics',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_atomics.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_client_server',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_client_server.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_thread_safe',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_thread_safe.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_sockopt_hwm',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_sockopt_hwm.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_heartbeats',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_heartbeats.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_stream_exceeds_buffer',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_stream_exceeds_buffer.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_poller',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_poller.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_timers',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_timers.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_radio_dish',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_radio_dish.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_udp',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_udp.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_shutdown_stress',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_shutdown_stress.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_pair_ipc',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_pair_ipc.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_rebind_ipc',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_rebind_ipc.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_reqrep_ipc',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_reqrep_ipc.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_use_fd_ipc',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_use_fd_ipc.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_use_fd_tcp',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_use_fd_tcp.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_timeo',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_timeo.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_filter_ipc',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_filter_ipc.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_fork',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_fork.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_abstract_ipc',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_abstract_ipc.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    },\n    {\n      'target_name': 'test_pubsub',\n      'type': 'executable',\n      'sources': [\n        '../../tests/test_pubsub.cpp',\n        '../../tests/testutil.hpp'\n      ],\n      'dependencies': [\n        'libzmq'\n      ],\n    }\n  ]\n}\n"
  },
  {
    "path": "builds/gyp/project-tests.xml",
    "content": "<tests script = \"project-tests\">\n    <test name = \"test_system\" />\n    <test name = \"test_pair_inproc\" />\n    <test name = \"test_pair_tcp\" />\n    <test name = \"test_reqrep_inproc\" />\n    <test name = \"test_reqrep_tcp\" />\n    <test name = \"test_hwm\" />\n    <test name = \"test_hwm_pubsub\" />\n    <test name = \"test_reqrep_device\" />\n    <test name = \"test_sub_forward\" />\n    <test name = \"test_invalid_rep\" />\n    <test name = \"test_msg_flags\" />\n    <test name = \"test_msg_ffn\" />\n    <test name = \"test_msg_init\" />\n    <test name = \"test_connect_resolve\" />\n    <test name = \"test_immediate\" />\n    <test name = \"test_last_endpoint\" />\n    <test name = \"test_term_endpoint\" />\n    <test name = \"test_srcfd\" />\n    <test name = \"test_monitor\" />\n    <test name = \"test_router_mandatory\" />\n    <test name = \"test_router_mandatory_hwm\" />\n    <test name = \"test_router_handover\" />\n    <test name = \"test_probe_router\" />\n    <test name = \"test_stream\" />\n    <test name = \"test_stream_empty\" />\n    <test name = \"test_stream_disconnect\" />\n    <test name = \"test_stream_timeout\" />\n    <test name = \"test_disconnect_inproc\" />\n    <test name = \"test_unbind_inproc\" />\n    <test name = \"test_unbind_wildcard\" />\n    <test name = \"test_ctx_options\" />\n    <test name = \"test_ctx_destroy\" />\n    <test name = \"test_security_null\" />\n    <test name = \"test_security_plain\" />\n    <test name = \"test_security_curve\" />\n    <test name = \"test_security_zap\" />\n    <test name = \"test_iov\" />\n    <test name = \"test_spec_req\" />\n    <test name = \"test_spec_rep\" />\n    <test name = \"test_spec_dealer\" />\n    <test name = \"test_spec_router\" />\n    <test name = \"test_spec_pushpull\" />\n    <test name = \"test_req_correlate\" />\n    <test name = \"test_req_relaxed\" />\n    <test name = \"test_conflate\" />\n    <test name = \"test_inproc_connect\" />\n    <test name = \"test_issue_566\" />\n    <test name = \"test_proxy\" />\n    <test name = \"test_proxy_single_socket\" />\n    <test name = \"test_proxy_terminate\" />\n    <test name = \"test_getsockopt_memset\" />\n    <test name = \"test_setsockopt\" />\n    <test name = \"test_many_sockets\" />\n    <test name = \"test_ipc_wildcard\" />\n    <test name = \"test_diffserv\" />\n    <test name = \"test_connect_rid\" />\n    <test name = \"test_bind_src_address\" />\n    <test name = \"test_metadata\" />\n    <test name = \"test_capabilities\" />\n    <test name = \"test_xpub_nodrop\" />\n    <test name = \"test_xpub_manual\" />\n    <test name = \"test_xpub_welcome_msg\" />\n    <test name = \"test_atomics\" />\n    <test name = \"test_client_server\" />\n    <test name = \"test_thread_safe\" />\n    <test name = \"test_sockopt_hwm\" />\n    <test name = \"test_heartbeats\" />\n    <test name = \"test_stream_exceeds_buffer\" />\n    <test name = \"test_poller\" />\n    <test name = \"test_timers\" />\n    <test name = \"test_radio_dish\" />\n    <test name = \"test_udp\" />\n    <test name = \"test_shutdown_stress\" />\n    <test name = \"test_pair_ipc\" />\n    <test name = \"test_rebind_ipc\" />\n    <test name = \"test_reqrep_ipc\" />\n    <test name = \"test_use_fd_ipc\" />\n    <test name = \"test_use_fd_tcp\" />\n    <test name = \"test_timeo\" />\n    <test name = \"test_filter_ipc\" />\n    <test name = \"test_fork\" />\n    <test name = \"test_abstract_ipc\" />\n    <test name = \"test_pubsub\" />\n</tests>\n"
  },
  {
    "path": "builds/gyp/project.gyp",
    "content": "#\n#   This is the gyp script for libzmq\n#\n#   Run in builds/gyp, as follows:\n#\n#       gyp --depth=. --format=make\n#       make\n{\n  'includes': [\n    'project-tests.gypi',\n  ],\n  'target_defaults': {\n    'include_dirs': [\n      '../../include',\n      '.'\n    ],\n    'defines': [\n      '_REENTRANT',\n      '_THREAD_SAFE',\n      'ZMQ_CUSTOM_PLATFORM_HPP',\n      'ZMQ_GYP_BUILD'\n    ],\n    'conditions': [\n      [ 'OS==\"win\"', {\n        'defines': [\n          'ZMQ_HAVE_WINDOWS',\n          'ZMQ_STATIC',\n          'FD_SETSIZE=16384',\n          '_CRT_SECURE_NO_WARNINGS',\n          '_WINSOCK_DEPRECATED_NO_WARNINGS'\n        ],\n        'libraries': [\n          'ws2_32',\n          'advapi32',\n          'iphlpapi'\n        ]\n      }],\n      [ 'OS==\"mac\"', {\n        'defines': [\n          'ZMQ_HAVE_OSX'\n        ],\n        'xcode_settings': {\n          'GCC_ENABLE_CPP_RTTI': 'YES'\n        }\n      }],\n      [ 'OS==\"linux\"', {\n        'defines': [\n          'ZMQ_HAVE_LINUX'\n        ],\n        'cflags_cc!': [\n          '-fno-rtti'\n        ],\n        'libraries': [\n          '-lpthread'\n        ]\n      }]\n    ]\n  },\n  'targets': [\n    {\n      'target_name': 'libzmq',\n      'type': 'static_library',\n      'sources': [\n        'platform.hpp',\n        '../../include/zmq.h',\n        '../../src/address.cpp',\n        '../../src/address.hpp',\n        '../../src/array.hpp',\n        '../../src/atomic_counter.hpp',\n        '../../src/atomic_ptr.hpp',\n        '../../src/blob.hpp',\n        '../../src/client.cpp',\n        '../../src/client.hpp',\n        '../../src/clock.cpp',\n        '../../src/clock.hpp',\n        '../../src/command.hpp',\n        '../../src/compat.hpp',\n        '../../src/condition_variable.hpp',\n        '../../src/config.hpp',\n        '../../src/ctx.cpp',\n        '../../src/ctx.hpp',\n        '../../src/curve_client.cpp',\n        '../../src/curve_client.hpp',\n        '../../src/curve_client_tools.hpp',\n        '../../src/curve_mechanism_base.cpp',\n        '../../src/curve_mechanism_base.hpp',\n        '../../src/curve_server.cpp',\n        '../../src/curve_server.hpp',\n        '../../src/dbuffer.hpp',\n        '../../src/dealer.cpp',\n        '../../src/dealer.hpp',\n        '../../src/decoder.hpp',\n        '../../src/decoder_allocators.cpp',\n        '../../src/decoder_allocators.hpp',\n        '../../src/devpoll.cpp',\n        '../../src/devpoll.hpp',\n        '../../src/dish.cpp',\n        '../../src/dish.hpp',\n        '../../src/dist.cpp',\n        '../../src/dist.hpp',\n        '../../src/encoder.hpp',\n        '../../src/epoll.cpp',\n        '../../src/epoll.hpp',\n        '../../src/err.cpp',\n        '../../src/err.hpp',\n        '../../src/fd.hpp',\n        '../../src/fq.cpp',\n        '../../src/fq.hpp',\n        '../../src/gssapi_client.cpp',\n        '../../src/gssapi_client.hpp',\n        '../../src/gssapi_mechanism_base.cpp',\n        '../../src/gssapi_mechanism_base.hpp',\n        '../../src/gssapi_server.cpp',\n        '../../src/gssapi_server.hpp',\n        '../../src/i_decoder.hpp',\n        '../../src/i_encoder.hpp',\n        '../../src/i_engine.hpp',\n        '../../src/i_mailbox.hpp',\n        '../../src/i_poll_events.hpp',\n        '../../src/io_object.cpp',\n        '../../src/io_object.hpp',\n        '../../src/io_thread.cpp',\n        '../../src/io_thread.hpp',\n        '../../src/ip.cpp',\n        '../../src/ip.hpp',\n        '../../src/ipc_address.cpp',\n        '../../src/ipc_address.hpp',\n        '../../src/ipc_connecter.cpp',\n        '../../src/ipc_connecter.hpp',\n        '../../src/ipc_listener.cpp',\n        '../../src/ipc_listener.hpp',\n        '../../src/kqueue.cpp',\n        '../../src/kqueue.hpp',\n        '../../src/lb.cpp',\n        '../../src/lb.hpp',\n        '../../src/likely.hpp',\n        '../../src/mailbox.cpp',\n        '../../src/mailbox.hpp',\n        '../../src/mailbox_safe.cpp',\n        '../../src/mailbox_safe.hpp',\n        '../../src/mechanism.cpp',\n        '../../src/mechanism.hpp ',\n        '../../src/mechanism_base.cpp',\n        '../../src/mechanism_base.hpp ',\n        '../../src/metadata.cpp',\n        '../../src/metadata.hpp',\n        '../../src/msg.cpp',\n        '../../src/msg.hpp',\n        '../../src/mtrie.cpp',\n        '../../src/mtrie.hpp',\n        '../../src/mutex.hpp',\n        '../../src/norm_engine.cpp',\n        '../../src/norm_engine.hpp',\n        '../../src/null_mechanism.cpp',\n        '../../src/null_mechanism.hpp',\n        '../../src/object.cpp',\n        '../../src/object.hpp',\n        '../../src/options.cpp',\n        '../../src/options.hpp',\n        '../../src/own.cpp',\n        '../../src/own.hpp',\n        '../../src/pair.cpp',\n        '../../src/pair.hpp',\n        '../../src/pgm_receiver.cpp',\n        '../../src/pgm_receiver.hpp',\n        '../../src/pgm_sender.cpp',\n        '../../src/pgm_sender.hpp',\n        '../../src/pgm_socket.cpp',\n        '../../src/pgm_socket.hpp',\n        '../../src/pipe.cpp',\n        '../../src/pipe.hpp',\n        '../../src/plain_client.cpp',\n        '../../src/plain_client.hpp',\n        '../../src/plain_server.cpp',\n        '../../src/plain_server.hpp',\n        '../../src/poll.cpp',\n        '../../src/poll.hpp',\n        '../../src/poller.hpp',\n        '../../src/poller_base.cpp',\n        '../../src/poller_base.hpp',\n        '../../src/proxy.cpp',\n        '../../src/proxy.hpp',\n        '../../src/pub.cpp',\n        '../../src/pub.hpp',\n        '../../src/pull.cpp',\n        '../../src/pull.hpp',\n        '../../src/push.cpp',\n        '../../src/push.hpp',\n        '../../src/radio.cpp',\n        '../../src/radio.hpp',\n        '../../src/random.cpp',\n        '../../src/random.hpp',\n        '../../src/raw_decoder.cpp',\n        '../../src/raw_decoder.hpp',\n        '../../src/raw_encoder.cpp',\n        '../../src/raw_encoder.hpp',\n        '../../src/reaper.cpp',\n        '../../src/reaper.hpp',\n        '../../src/rep.cpp',\n        '../../src/rep.hpp',\n        '../../src/req.cpp',\n        '../../src/req.hpp',\n        '../../src/router.cpp',\n        '../../src/router.hpp',\n        '../../src/select.cpp',\n        '../../src/select.hpp',\n        '../../src/server.cpp',\n        '../../src/server.hpp',\n        '../../src/session_base.cpp',\n        '../../src/session_base.hpp',\n        '../../src/signaler.cpp',\n        '../../src/signaler.hpp',\n        '../../src/socket_base.cpp',\n        '../../src/socket_base.hpp',\n        '../../src/socket_poller.cpp',\n        '../../src/socket_poller.hpp',\n        '../../src/socks.cpp',\n        '../../src/socks.hpp',\n        '../../src/socks_connecter.cpp',\n        '../../src/socks_connecter.hpp',\n        '../../src/stdint.hpp',\n        '../../src/stream.cpp',\n        '../../src/stream.hpp',\n        '../../src/stream_engine.cpp',\n        '../../src/stream_engine.hpp',\n        '../../src/sub.cpp',\n        '../../src/sub.hpp',\n        '../../src/tcp.cpp',\n        '../../src/tcp.hpp',\n        '../../src/tcp_address.cpp',\n        '../../src/tcp_address.hpp',\n        '../../src/tcp_connecter.cpp',\n        '../../src/tcp_connecter.hpp',\n        '../../src/tcp_listener.cpp',\n        '../../src/tcp_listener.hpp',\n        '../../src/thread.cpp',\n        '../../src/thread.hpp',\n        '../../src/timers.cpp',\n        '../../src/timers.hpp',\n        '../../src/tipc_address.cpp',\n        '../../src/tipc_address.hpp',\n        '../../src/tipc_connecter.cpp',\n        '../../src/tipc_connecter.hpp',\n        '../../src/tipc_listener.cpp',\n        '../../src/tipc_listener.hpp',\n        '../../src/trie.cpp',\n        '../../src/trie.hpp',\n        '../../src/udp_address.cpp',\n        '../../src/udp_address.hpp',\n        '../../src/udp_engine.cpp',\n        '../../src/udp_engine.hpp',\n        '../../src/v1_decoder.cpp',\n        '../../src/v1_decoder.hpp',\n        '../../src/v1_encoder.cpp',\n        '../../src/v1_encoder.hpp',\n        '../../src/v2_decoder.cpp',\n        '../../src/v2_decoder.hpp',\n        '../../src/v2_encoder.cpp',\n        '../../src/v2_encoder.hpp',\n        '../../src/v2_protocol.hpp',\n        '../../src/vmci.cpp',\n        '../../src/vmci.hpp',\n        '../../src/vmci_address.cpp',\n        '../../src/vmci_address.hpp',\n        '../../src/vmci_connecter.cpp',\n        '../../src/vmci_connecter.hpp',\n        '../../src/vmci_listener.cpp',\n        '../../src/vmci_listener.hpp',\n        '../../src/windows.hpp',\n        '../../src/wire.hpp',\n        '../../src/xpub.cpp',\n        '../../src/xpub.hpp',\n        '../../src/xsub.cpp',\n        '../../src/xsub.hpp',\n        '../../src/ypipe.hpp',\n        '../../src/ypipe_base.hpp',\n        '../../src/ypipe_conflate.hpp',\n        '../../src/yqueue.hpp',\n        '../../src/zap_client.cpp',\n        '../../src/zap_client.hpp',\n        '../../src/zmq.cpp',\n        '../../src/zmq_utils.cpp'\n      ],\n      'copies': [\n        {\n          'destination': '../../src',\n          'files': [\n              'platform.hpp'\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "builds/ios/build_ios.sh",
    "content": "#!/bin/sh\n# This is a first attempt to create a script to libzmq for iOS >= 13.5, including arm64\n# inspired on https://raw.githubusercontent.com/drewcrawford/libzmq-ios/master/libzmq.sh\n\nset -e\nLIBNAME=\"libzmq.a\"\nARCHS=${ARCHS:-\"armv7 armv7s arm64 x86_64\"}\nDEVELOPER=$(xcode-select -print-path)\nLIPO=$(xcrun -sdk iphoneos -find lipo)\nSCRIPTDIR=$( (cd -P $(dirname $0) && pwd) )\nDISTLIBDIR=\"${SCRIPTDIR}/lib\"\nDSTDIR=${SCRIPTDIR}\nBUILDDIR=\"${DSTDIR}/libzmq_build\"\nDISTDIR=\"${DSTDIR}/libzmq_dist\"\nLIBDIR=$(dirname $(dirname ${SCRIPTDIR}))\nSDK=$(xcodebuild -showsdks \\\n    | grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}'\n    )\nIOS_VERSION_MIN=8.0\nOTHER_LDFLAGS=\"\"\nOTHER_CFLAGS=\"-Os -Qunused-arguments\"\n# Enable Bitcode\nOTHER_CPPFLAGS=\"-Os -fembed-bitcode\"\nOTHER_CXXFLAGS=\"-Os\"\n\n${LIBDIR}/autogen.sh\nfor ARCH in $ARCHS\ndo\n    BUILDARCHDIR=\"$BUILDDIR/$ARCH\"\n    mkdir -p ${BUILDARCHDIR}\n\n    case ${ARCH} in\n        armv7)\n\t    PLATFORM=\"iPhoneOS\"\n\t    HOST=\"${ARCH}-apple-darwin\"\n\t    export BASEDIR=\"${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer\"\n\t    export ISDKROOT=\"${BASEDIR}/SDKs/${PLATFORM}${SDK}.sdk\"\n\t    export CXXFLAGS=\"${OTHER_CXXFLAGS}\"\n\t    export CPPFLAGS=\"-arch ${ARCH} -isysroot ${ISDKROOT} -mios-version-min=${IOS_VERSION_MIN} ${OTHER_CPPFLAGS}\"\n\t    export LDFLAGS=\"-arch ${ARCH} -isysroot ${ISDKROOT} ${OTHER_LDFLAGS}\"\n            ;;\n\n        armv7s)\n\t    PLATFORM=\"iPhoneOS\"\n\t    HOST=\"${ARCH}-apple-darwin\"\n\t    export BASEDIR=\"${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer\"\n\t    export ISDKROOT=\"${BASEDIR}/SDKs/${PLATFORM}${SDK}.sdk\"\n\t    export CXXFLAGS=\"${OTHER_CXXFLAGS}\"\n\t    export CPPFLAGS=\"-arch ${ARCH} -isysroot ${ISDKROOT} -mios-version-min=${IOS_VERSION_MIN} ${OTHER_CPPFLAGS}\"\n\t    export LDFLAGS=\"-arch ${ARCH} -isysroot ${ISDKROOT} ${OTHER_LDFLAGS}\"\n            ;;\n\n        arm64)\n\t    PLATFORM=\"iPhoneOS\"\n\t    HOST=\"arm-apple-darwin\"\n\t    export BASEDIR=\"${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer\"\n\t    export ISDKROOT=\"${BASEDIR}/SDKs/${PLATFORM}${SDK}.sdk\"\n\t    export CXXFLAGS=\"${OTHER_CXXFLAGS}\"\n\t    export CPPFLAGS=\"-arch ${ARCH} -isysroot ${ISDKROOT} -mios-version-min=${IOS_VERSION_MIN} ${OTHER_CPPFLAGS}\"\n\t    export LDFLAGS=\"-arch ${ARCH} -isysroot ${ISDKROOT} ${OTHER_LDFLAGS}\"\n            ;;\n\n        x86_64)\n\t    PLATFORM=\"iPhoneSimulator\"\n\t    HOST=\"${ARCH}-apple-darwin\"\n\t    export BASEDIR=\"${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer\"\n\t    export ISDKROOT=\"${BASEDIR}/SDKs/${PLATFORM}${SDK}.sdk\"\n\t    export CXXFLAGS=\"${OTHER_CXXFLAGS}\"\n\t    export CPPFLAGS=\"-arch ${ARCH} -isysroot ${ISDKROOT} -mios-version-min=${IOS_VERSION_MIN} ${OTHER_CPPFLAGS}\"\n\t    export LDFLAGS=\"-arch ${ARCH} ${OTHER_LDFLAGS}\"\n\t    echo \"LDFLAGS $LDFLAGS\"\n            ;;\n        *)\n\t    echo \"Unsupported architecture ${ARCH}\"\n\t    exit 1\n            ;;\n    esac\n\n    echo \"Configuring for ${ARCH}...\"\n    set +e\n    cd ${LIBDIR} \n    set -e\n    ${LIBDIR}/configure \\\n\t--prefix=${BUILDARCHDIR} \\\n\t--disable-shared \\\n\t--enable-static \\\n\t--host=${HOST} \\\n\t--disable-perf \\\n\t--disable-curve-keygen\n\n    echo \"Building ${LIBNAME} for ${ARCH}...\"\n    cd ${LIBDIR}\n    \n    make -j8 \n    make install\n\tmake clean\n\ndone\n\nmkdir -p ${DISTLIBDIR}\nfor ARCH in $ARCHS\ndo\n\tLIBPATH=\"$BUILDDIR/$ARCH/lib/${LIBNAME}\"\n\tLIBLIST+=\" -arch ${ARCH} ${LIBPATH}\"\ndone\n\nset +e\n\n${LIPO} -create ${LIBLIST} -output ${DISTLIBDIR}/${LIBNAME}\n\necho \"Done !\"\n\n"
  },
  {
    "path": "builds/mingw32/Makefile.mingw32",
    "content": "CC=gcc\nCFLAGS=-Wall -Os -g -DDLL_EXPORT -DFD_SETSIZE=16384 -DZMQ_USE_SELECT -I.\nLIBS=-lws2_32 -lIphlpapi -lsodium\n\nOBJS = ctx.o reaper.o dist.o err.o \\\n\tclock.o metadata.o random.o \\\n\tobject.o own.o \\\n\tio_object.o io_thread.o \\\n\tlb.o fq.o \\\n\taddress.o tcp_address.o ipc_address.o \\\n\tipc_connecter.o ipc_listener.o \\\n\ttcp_connecter.o tcp_listener.o \\\n\tmailbox.o msg.o mtrie.o \\\n\tpipe.o precompiled.o proxy.o \\\n\tsignaler.o stream_engine.o \\\n\tthread.o trie.o \\\n\tip.o tcp.o \\\n\tpgm_socket.o pgm_receiver.o pgm_sender.o \\\n\traw_decoder.o raw_encoder.o \\\n\tv1_decoder.o v1_encoder.o v2_decoder.o v2_encoder.o \\\n        udp_address.o udp_engine.o radio.o dish.o \\\n\tsocket_base.o session_base.o options.o \\\n\treq.o rep.o push.o pull.o pub.o sub.o pair.o \\\n\tdealer.o router.o xpub.o xsub.o stream.o \\\n\tpoller_base.o select.o poll.o epoll.o kqueue.o devpoll.o \\\n\tcurve_client.o curve_server.o \\\n\tmechanism.o null_mechanism.o plain_client.o plain_server.o \\\n\tsocks.o server.o decoder_allocators.o socks_connecter.o \\\n\tsocket_poller.o mailbox_safe.o plain_server.o client.o timers.o \\\n\tzmq.o zmq_utils.o gather.o scatter.o dgram.o\n\n%.o: ../../src/%.cpp\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n%.o: ../../perf/%.cpp\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\nall: libzmq.dll\n\nperf: inproc_lat.exe inproc_thr.exe local_lat.exe local_thr.exe remote_lat.exe remote_thr.exe\n\nlibzmq.dll: $(OBJS)\n\tg++ -shared -static -O2 -s -o $@ $^ -Wl,--out-implib,$@.a $(LIBS)\n\n%.exe: %.o libzmq.dll\n\tg++ -o -O2 $@ $^\n\nclean:\n\tdel *.o *.a *.dll *.exe\n"
  },
  {
    "path": "builds/mingw32/platform.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PLATFORM_HPP_INCLUDED__\n#define __ZMQ_PLATFORM_HPP_INCLUDED__\n\n//  This is the platform definition for the MSVC platform.\n//  As a first step of the build process it is copied to\n//  zmq directory to take place of platform.hpp generated from\n//  platform.hpp.in on platforms supported by GNU autotools.\n//  Place any MSVC-specific definitions here.\n\n#define ZMQ_HAVE_WINDOWS\n\n#define ZMQ_USE_LIBSODIUM\n\n#endif\n"
  },
  {
    "path": "builds/nuget/libzmq.autopkg",
    "content": "nuget{\n  nuspec{\n    id = libzmq;\n    version : 4.1.0-alpha;\n    title: ZMQ - Code Connected;\n    authors: { zeromq };\n    owners: { phreed, jgoz };\n    licenseUrl: \"https://www.mozilla.org/MPL/2.0/\";\n    projectUrl: \"http://www.zeromq.org/\";\n    iconUrl: \"http://www.zeromq.org/local--files/admin:css/logo.gif\";\n    requireLicenseAcceptance: false;\n    summary: Code Connected;\n    description: @\" \nZeroMQ \\zeromq\\:\n- Connect your code in any language, on any platform.\n- Carries messages across inproc, IPC, TCP, TPIC, multicast.\n- Smart patterns like pub-sub, push-pull, and router-dealer.\n- High-speed asynchronous I/O engines, in a tiny library.\n- Backed by a large and active open source community.\n- Supports every modern language and platform.\n- Build any architecture: centralized, distributed, small, or large.\n- Free software with full commercial support.\";\n    releaseNotes: \"Made a NuGet package.\";\n    copyright: Copyright 2012 iMatix Corporation and Contributors;\n    tags: {0mq, zeromq, nuget, native; }\n  }\n\n  files{\n    #defines {\n       SDK_ROOT = ..\\..\\;\n       SDK_2010 = ..\\msvc\\;\n    }  \n    include: { \"${SDK_ROOT}include\\*\" };\n    docs: { \"${SDK_ROOT}doc\\*.txt\" };\n\n    [x64,v100,debug] {\n       lib: ${SDK_2010}Debug\\libzmq.lib;     \n       symbols: ${SDK_2010}Debug\\libzmq.pdb;     \n    }    \n\n    [x64,v100,release] {\n       lib: ${SDK_2010}Release\\libzmq.lib;     \n       bin: ${SDK_2010}..\\..\\lib\\libzmq.dll; \n    }    \n\n    targets{\n       Defines += HAS_CPP_ZMQ_SDK;\n    }\n  }\n}\n\n\n"
  },
  {
    "path": "builds/nuget/readme.nuget",
    "content": "\nNuGet is a package management system for MS-Windows.\nIt is similar in spirit to tools like Maven or Gradle.\n\nIt was originally for .Net only packages but it has \nrecently been augmented to working with native packages.\nhttp://docs.nuget.org/docs/reference/support-for-native-projects\n\nThe instructions for building a NuGet package can be found here:\nhttp://coapp.org/pages/tutorials.html\n\n\nThe basic procedure is to first build all \nthe artifacts and then run ...\n Write-NuGetPackage .\\libzmq.autopkg \n\nThe *.nuget files thus produced can then be installed\nin a local repository or uploaded to one of the nuget servers.\n\n\n"
  },
  {
    "path": "builds/openwrt/Makefile",
    "content": "# Copyright (C) [2011-2012] [TheClashingRocks.org]\n#\n# Author: Jiva Nath Bagale <jnbagale@gmail.com>\n# author: Victor Perron <victor@iso3103.net>\n#\n# This is free software, licensed under the GNU General Public License v2.\n# See /LICENSE for more information.\n#\n# \ninclude $(TOPDIR)/rules.mk\n\nPKG_NAME:=zeromq\nPKG_VERSION:=master\nPKG_SOURCE_PROTO:=git\nPKG_SOURCE_URL:=https://github.com/zeromq/libzmq.git\nPKG_SOURCE:=$(PKG_NAME).tar.gz\nPKG_SOURCE_VERSION:=HEAD\nPKG_SOURCE_SUBDIR:=$(PKG_NAME)\n\nPKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)\n\nPKG_INSTALL:=1\n\ninclude $(INCLUDE_DIR)/package.mk\n\ndefine Package/zeromq\n    MAINTAINER:=victor@iso3103.net\n    TITLE:=zeromq\n    SECTION:=libs\n    DEPENDS:=+libstdcpp +libpthread +librt +libsodium\n    CATEGORY:=Libraries\n    URL:=http://www.zeromq.org/\nendef\n\ndefine Package/zeromq/description\n    The library provides light weight messaging services using an intelligent transport layer. \n    It can carry messages across inproc, IPC, TCP and multicast and is faster than TCP for \n    clustered products and supercomputing.\nendef\n\ndefine Build/Configure\n\t( cd $(PKG_BUILD_DIR); ./autogen.sh );\n\t$(call Build/Configure/Default)\nendef\n\nTARGET_CPPFLAGS:=$(filter-out -Werror, $(TARGET_CFLAGS))\n\ndefine Build/InstallDev\n\t$(INSTALL_DIR) \\\n\t\t$(1)/usr/lib \t\\\n\t\t$(1)/usr/include \\\n\t\t$(1)/usr/lib/pkgconfig\n\t$(CP) \\\n\t\t$(PKG_INSTALL_DIR)/usr/lib/* \\\n\t\t$(1)/usr/lib/\n\t$(CP) \\\n\t\t$(PKG_INSTALL_DIR)/usr/include/* \\\n\t\t$(1)/usr/include/\n\t$(CP) \\\n\t\t$(PKG_INSTALL_DIR)/usr/lib/pkgconfig \\\n\t\t$(1)/usr/lib/\n\nendef\n\ndefine Package/zeromq/install\n\t$(INSTALL_DIR) $(1)/usr/lib \n\t$(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so* $(1)/usr/lib/\nendef\n\n$(eval $(call BuildPackage,zeromq))\n"
  },
  {
    "path": "builds/qnx/ToolchainQNX6.6_x86.cmake",
    "content": "set(CMAKE_SYSTEM_NAME QNX)\n\nset(arch gcc_ntox86)\nset(ntoarch x86)\nset(QNX_PROCESSOR x86)\n\nset(CMAKE_C_COMPILER qcc )\nset(CMAKE_C_COMPILER_TARGET ${arch})\n\nset(CMAKE_CXX_COMPILER QCC -lang-c++ -g)\nset(CMAKE_CXX_COMPILER_TARGET ${arch})\n\nset(CMAKE_ASM_COMPILER qcc -V${arch})\nset(CMAKE_ASM_DEFINE_FLAG \"-Wa,--defsym,\")\n\nset(CMAKE_RANLIB $ENV{QNX_HOST}/usr/bin/nto${ntoarch}-ranlib\n\t    CACHE PATH \"QNX ranlib Program\" FORCE)\n    set(CMAKE_AR $ENV{QNX_HOST}/usr/bin/nto${ntoarch}-ar\n\t        CACHE PATH \"QNX ar Program\" FORCE)\n\n"
  },
  {
    "path": "builds/valgrind/ci_build.sh",
    "content": "#!/usr/bin/env bash\n\nset -x\n\nmkdir tmp\nBUILD_PREFIX=$PWD/tmp\n\nCONFIG_OPTS=()\nCONFIG_OPTS+=(\"CFLAGS=-g\")\nCONFIG_OPTS+=(\"CPPFLAGS=-I${BUILD_PREFIX}/include\")\nCONFIG_OPTS+=(\"CXXFLAGS=-g\")\nCONFIG_OPTS+=(\"LDFLAGS=-L${BUILD_PREFIX}/lib\")\nCONFIG_OPTS+=(\"PKG_CONFIG_PATH=${BUILD_PREFIX}/lib/pkgconfig\")\nCONFIG_OPTS+=(\"--prefix=${BUILD_PREFIX}\")\nCONFIG_OPTS+=(\"--enable-valgrind\")\n\nif [ -n \"$TLS\" ] && [ \"$TLS\" == \"enabled\" ]; then\n    CONFIG_OPTS+=(\"--with-tls=yes\")\nfi\n\nif [ -z $CURVE ]; then\n    CONFIG_OPTS+=(\"--disable-curve\")\nelif [ $CURVE == \"libsodium\" ]; then\n    CONFIG_OPTS+=(\"--with-libsodium=yes\")\n\n    if ! ((command -v dpkg-query >/dev/null 2>&1 && dpkg-query --list libsodium-dev >/dev/null 2>&1) || \\\n            (command -v brew >/dev/null 2>&1 && brew ls --versions libsodium >/dev/null 2>&1)); then\n        git clone --depth 1 -b stable https://github.com/jedisct1/libsodium.git\n        ( cd libsodium; ./autogen.sh; ./configure --prefix=$BUILD_PREFIX; make install)\n    fi\nfi\n\n# Build, check, and install from local source\n( cd ../..; ./autogen.sh && ./configure \"${CONFIG_OPTS[@]}\" && make -j5 && make VERBOSE=1 check-valgrind-memcheck) || exit 1\n"
  },
  {
    "path": "builds/valgrind/valgrind.supp",
    "content": "{\n   <socketcall_sendto>\n   Memcheck:Param\n   socketcall.sendto(msg)\n   fun:send\n   ...\n}\n{\n   <socketcall_sendto>\n   Memcheck:Param\n   socketcall.send(msg)\n   fun:send\n   ...\n}\n{\n   <glibc_freeres>\n   Memcheck:Free\n   fun:free\n   ...\n   fun:__libc_freeres\n   ...\n}\n"
  },
  {
    "path": "builds/valgrind/vg",
    "content": "valgrind --tool=memcheck --leak-check=full --suppressions=valgrind.supp $*\n"
  },
  {
    "path": "builds/vxworks/platform.hpp",
    "content": "/* src/platform.hpp.  Generated from platform.hpp.in by configure.  */\n/* src/platform.hpp.in.  Generated from configure.ac by autoheader.  */\n\n/* Define to 1 if you have the <alloca.h> header file. */\n/* #undef HAVE_ALLOCA_H */\n\n/* Define to 1 if you have the <arpa/inet.h> header file. */\n#define HAVE_ARPA_INET_H 1\n\n/* Define to 1 if you have the `clock_gettime' function. */\n#define HAVE_CLOCK_GETTIME 1\n\n/* Define to 1 if you have the declaration of `LOCAL_PEERCRED', and to 0 if\n   you don't. */\n#define HAVE_DECL_LOCAL_PEERCRED 0\n\n/* Define to 1 if you have the declaration of `SO_PEERCRED', and to 0 if you\n   don't. */\n#define HAVE_DECL_SO_PEERCRED 0\n\n/* Define to 1 if you have the <dlfcn.h> header file. */\n#define HAVE_DLFCN_H 1\n\n/* Define to 1 if you have the <errno.h> header file. */\n#define HAVE_ERRNO_H 1\n\n/* Define to 1 if you have the `fork' function. */\n#define HAVE_FORK 1\n\n/* Define to 1 if you have the `freeifaddrs' function. */\n#define HAVE_FREEIFADDRS 1\n\n/* Define to 1 if you have the `gethrtime' function. */\n/* #undef HAVE_GETHRTIME */\n\n/* Define to 1 if you have the `getifaddrs' function. */\n#define HAVE_GETIFADDRS 1\n\n/* Define to 1 if you have the `gettimeofday' function. */\n#define HAVE_GETTIMEOFDAY 1\n\n/* Define to 1 if you have the <ifaddrs.h> header file. */\n//#define HAVE_IFADDRS_H 1\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#define HAVE_INTTYPES_H 1\n\n/* Define to 1 if you have the `gssapi_krb5' library (-lgssapi_krb5). */\n/* #undef HAVE_LIBGSSAPI_KRB5 */\n\n/* Define to 1 if you have the `iphlpapi' library (-liphlpapi). */\n/* #undef HAVE_LIBIPHLPAPI */\n\n/* Define to 1 if you have the `nsl' library (-lnsl). */\n/* #undef HAVE_LIBNSL */\n\n/* Define to 1 if you have the `pthread' library (-lpthread). */\n/* #undef HAVE_LIBPTHREAD */\n\n/* Define to 1 if you have the `rpcrt4' library (-lrpcrt4). */\n/* #undef HAVE_LIBRPCRT4 */\n\n/* Define to 1 if you have the `rt' library (-lrt). */\n/* #undef HAVE_LIBRT */\n\n/* Define to 1 if you have the `socket' library (-lsocket). */\n/* #undef HAVE_LIBSOCKET */\n\n/* Define to 1 if you have the `sodium' library (-lsodium). */\n/* #undef HAVE_LIBSODIUM */\n\n/* Define to 1 if you have the `ws2_32' library (-lws2_32). */\n/* #undef HAVE_LIBWS2_32 */\n\n/* Define to 1 if you have the <limits.h> header file. */\n#define HAVE_LIMITS_H 1\n\n/* Define to 1 if you have the <memory.h> header file. */\n#define HAVE_MEMORY_H 1\n\n/* Define to 1 if you have the `memset' function. */\n#define HAVE_MEMSET 1\n\n/* Define to 1 if you have the <netinet/in.h> header file. */\n#define HAVE_NETINET_IN_H 1\n\n/* Define to 1 if you have the <netinet/tcp.h> header file. */\n#define HAVE_NETINET_TCP_H 1\n\n/* Define to 1 if you have the `perror' function. */\n#define HAVE_PERROR 1\n\n/* Define to 1 if you have the `socket' function. */\n#define HAVE_SOCKET 1\n\n/* Define to 1 if stdbool.h conforms to C99. */\n#define HAVE_STDBOOL_H 1\n\n/* Define to 1 if you have the <stddef.h> header file. */\n#define HAVE_STDDEF_H 1\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#define HAVE_STDINT_H 1\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#define HAVE_STDLIB_H 1\n\n/* Define to 1 if you have the <strings.h> header file. */\n#define HAVE_STRINGS_H 1\n\n/* Define to 1 if you have the <string.h> header file. */\n#define HAVE_STRING_H 1\n\n/* Define to 1 if you have the <sys/eventfd.h> header file. */\n/* #undef HAVE_SYS_EVENTFD_H */\n\n/* Define to 1 if you have the <sys/socket.h> header file. */\n#define HAVE_SYS_SOCKET_H 1\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#define HAVE_SYS_STAT_H 1\n\n/* Define to 1 if you have the <sys/time.h> header file. */\n#define HAVE_SYS_TIME_H 1\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#define HAVE_SYS_TYPES_H 1\n\n/* Define to 1 if you have the <sys/uio.h> header file. */\n#define HAVE_SYS_UIO_H 1\n\n/* Define to 1 if you have the <time.h> header file. */\n#define HAVE_TIME_H 1\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#define HAVE_UNISTD_H 1\n\n/* Define to 1 if you have the <windows.h> header file. */\n/* #undef HAVE_WINDOWS_H */\n\n/* Define to 1 if the system has the type `_Bool'. */\n/* #undef HAVE__BOOL */\n\n/* Define to the sub-directory in which libtool stores uninstalled libraries.\n   */\n#define LT_OBJDIR \".libs/\"\n\n/* Name of package */\n#define PACKAGE \"zeromq\"\n\n/* Define to the address where bug reports for this package should be sent. */\n#define PACKAGE_BUGREPORT \"zeromq-dev@lists.zeromq.org\"\n\n/* Define to the full name of this package. */\n#define PACKAGE_NAME \"zeromq\"\n\n/* Define to the full name and version of this package. */\n#define PACKAGE_STRING \"zeromq 4.1.0\"\n\n/* Define to the one symbol short name of this package. */\n#define PACKAGE_TARNAME \"zeromq\"\n\n/* Define to the home page for this package. */\n#define PACKAGE_URL \"\"\n\n/* Define to the version of this package. */\n#define PACKAGE_VERSION \"4.1.0\"\n\n/* Define as the return type of signal handlers (`int' or `void'). */\n#define RETSIGTYPE void\n\n/* Define to 1 if you have the ANSI C header files. */\n#define STDC_HEADERS 1\n\n/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */\n#define TIME_WITH_SYS_TIME 1\n\n/* Version number of package */\n#define VERSION \"4.1.0\"\n\n/* Enable militant API assertions */\n/* #undef ZMQ_ACT_MILITANT */\n\n/* Force to use mutexes */\n/* #undef ZMQ_FORCE_MUTEXES */\n\n/* Have VxWorks OS */\n#define ZMQ_HAVE_VXWORKS 1\n\n/* Have AIX OS */\n/* #undef ZMQ_HAVE_AIX */\n\n/* Have Android OS */\n/* #undef ZMQ_HAVE_ANDROID */\n\n/* Have Cygwin */\n/* #undef ZMQ_HAVE_CYGWIN */\n\n/* Have eventfd extension. */\n/* #undef ZMQ_HAVE_EVENTFD */\n\n/* Have FreeBSD OS */\n/* #undef ZMQ_HAVE_FREEBSD */\n\n/* Have HPUX OS */\n/* #undef ZMQ_HAVE_HPUX */\n\n/* Have ifaddrs.h header. */\n//#define ZMQ_HAVE_IFADDRS 1\n\n/* Have Linux OS */\n/* #undef ZMQ_HAVE_LINUX */\n\n/* Have LOCAL_PEERCRED socket option */\n/* #undef ZMQ_HAVE_LOCAL_PEERCRED */\n\n/* Have MinGW32 */\n/* #undef ZMQ_HAVE_MINGW32 */\n\n/* Have NetBSD OS */\n/* #undef ZMQ_HAVE_NETBSD */\n\n/* Have NORM protocol extension */\n/* #undef ZMQ_HAVE_NORM */\n\n/* Have OpenBSD OS */\n/* #undef ZMQ_HAVE_OPENBSD */\n\n/* Have OpenPGM extension */\n/* #undef ZMQ_HAVE_OPENPGM */\n\n/* Have DarwinOSX OS */\n/* #undef ZMQ_HAVE_OSX */\n\n/* Have QNX Neutrino OS */\n/* #undef ZMQ_HAVE_QNXNTO */\n\n/* Whether SOCK_CLOEXEC is defined and functioning. */\n/* #undef ZMQ_HAVE_SOCK_CLOEXEC */\n\n/* Have Solaris OS */\n/* #undef ZMQ_HAVE_SOLARIS */\n\n/* Whether SO_KEEPALIVE is supported. */\n#define ZMQ_HAVE_SO_KEEPALIVE 1\n\n/* Have SO_PEERCRED socket option */\n/* #undef ZMQ_HAVE_SO_PEERCRED */\n\n/* Whether TCP_KEEPALIVE is supported. */\n/* #undef ZMQ_HAVE_TCP_KEEPALIVE */\n\n/* Whether TCP_KEEPCNT is supported. */\n/* #undef ZMQ_HAVE_TCP_KEEPCNT */\n\n/* Whether TCP_KEEPIDLE is supported. */\n/* #undef ZMQ_HAVE_TCP_KEEPIDLE */\n\n/* Whether TCP_KEEPINTVL is supported. */\n/* #undef ZMQ_HAVE_TCP_KEEPINTVL */\n\n/* Have TIPC support */\n#define ZMQ_HAVE_TIPC 1\n\n/* Have uio.h header. */\n//#define ZMQ_HAVE_UIO 1\n\n#define ZMQ_USE_SELECT 1\n\n/* Have Windows OS */\n/* #undef ZMQ_HAVE_WINDOWS */\n\n/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,\n   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the\n   #define below would cause a syntax error. */\n/* #undef _UINT32_T */\n\n/* Define to empty if `const' does not conform to ANSI C. */\n/* #undef const */\n\n/* Define to `__inline__' or `__inline' if that's what the C compiler\n   calls it, or to nothing if 'inline' is not supported under any name.  */\n#ifndef __cplusplus\n/* #undef inline */\n#endif\n\n/* Define to `unsigned int' if <sys/types.h> does not define. */\n/* #undef size_t */\n\n/* Define to `int' if <sys/types.h> does not define. */\n/* #undef ssize_t */\n\n/* Define to the type of an unsigned integer type of width exactly 32 bits if\n   such a type exists and the standard includes do not define it. */\n/* #undef uint32_t */\n\n/* Define to empty if the keyword `volatile' does not work. Warning: valid\n   code using `volatile' can become incorrect without. Disable with care. */\n/* #undef volatile */\n\n/* ---- Special case for z/OS Unix Services: openedition ---- */\n#include <vxWorks.h>\n\n#ifndef   NI_MAXHOST\n#define   NI_MAXHOST 1025\n#endif\n"
  },
  {
    "path": "builds/zos/README.md",
    "content": "# ZeroMQ on z/OS UNIX System Services\n\nZeroMQ has been successfully built on z/OS, using [z/OS UNIX System\nServices](http://www-03.ibm.com/systems/z/os/zos/features/unix/),\na certified UNIX environment for the [IBM\nz-series](http://www-03.ibm.com/systems/z/).  The build is possible\nwith the shell scripts in this directory, as described below.\n\nTested build combinations:\n\n* ZeroMQ 4.0.4, using IBM XL C/C++ compiler, as XPLINK in ILP32 mode\n\n* ZeroMQ 4.0.4, using IBM XL C/C++ compiler, as XPLINK in LP64 mode\n\n* ZeroMQ 4.1-git, using IBM XL C/C++ compiler, as XPLINK in ILP32 mode\n\nOther combinations are likely to work, possibly with minor changes,\nbut have not been tested.  Both static library and DLL modes have been\ntested.\n\nThere are some minor limitations (detailed below), but all core\nfunctionality tests run successfully.\n\n\n## Quickstart: building ZeroMQ on z/OS UNIX System Services\n\nAssuming [z/OS UNIX System\nServices](http://www-03.ibm.com/systems/z/os/zos/features/unix/) is\ninstalled, and the [z/OS XL C/C++\ncompiler suite](http://www-03.ibm.com/software/products/en/czos) is \ninstalled, ZeroMQ can be built as follows:\n\n*   Download and extract ZeroMQ tar file\n\n*   Ensure contents of this directory are present at `builds/zos`\n    within that extracted directory (eg, `zeromq-VERSION/builds/zos/`; \n    copy these files in, if not already present, and make sure the\n    shell scripts are executable)\n\n*   (Optional) set ZCXXFLAGS for additional compile flags (see below)\n\n*   Build `libzmq.a` static library and `libzmq.so` dynamic\n    library, with:\n\n        cd zeromq-VERSION\n        builds/zos/makelibzmq\n\n    or to skip the `libzmq.so` dynamic library (only building `libzmq.a`):\n\n        cd zeromq-VERSION\n        BUILD_DLL=false\n        export BUILD_DLL\n        builds/zos/makelibzmq\n\n*   (Optional, but recommended) build and run the core tests with:\n\n        cd zeromq-VERSION\n        builds/zos/maketests\n        builds/zos/runtests\n\n*   To remove built files, to start again (eg, rebuild with different\n    compile/link flags):\n\n        cd zeromq-VERSION\n        builds/zos/makeclean\n\nThere are details on specifying alternative compilation flags below.\n\n\n## Quickstart: using ZeroMQ on z/OS UNIX System Services\n\n### Static linking\n\nInstall `include/*.h` somewhere on your compiler include path.\n\nInstall `src/libzmq.a` somewhere on your library search path.\n\nCompile and link application with:\n\n    c++ -Wc,xplink -Wl,xplink ... -+ -o myprog myprog.cpp -lzmq\n\nRun with:\n\n    ./myprog\n\n\n### Dynamic linking\n\nInstall `include/*.h` somewhere on your compiler include path.\n\nInstall `src/libzmq.so` somewhere on your LIBPATH.\n\nInstall `src/libzmq.x` somewhere you can reference for import linking.\n\nCompile and link application:\n\n    c++ -Wc,xplink -Wc,dll ... -+ -c -o myprog.o myprog.cpp\n    c++ -Wl,xplink -o myprog myprog.o /PATH/TO/libzmq.x\n\nRun with:\n\n    LIBPATH=/DIR/OF/LIBZMQ.SO:/lib:/usr/lib:...    # if not in default path\n    export LIBPATH\n    ./myprog\n\n\n## ZeroMQ on z/OS UNIX System Services: Application considerations\n\nz/0S UNIX System Services does not provide a way to block the\n[`SIGPIPE` signal being generated when a thread writes to a closed socket](http://pic.dhe.ibm.com/infocenter/zvm/v6r2/index.jsp?topic=%2Fcom.ibm.zos.r12.cbcpx01%2Fcbcpg1b0287.htm)\n(compare with other platforms that support the `SO_NOSIGPIPE` socket\noption, and/or the `MSG_NOSIGNAL` flag on `send()`; z/OS UNIX System\nServices supports neither).\n\nAs a result, applications using ZeroMQ on z/OS UNIX System Services\nhave to expect to encounter `SIGPIPE` at various times during the use\nof the library, if sockets are unexpectedly disconnected.  Normally\n`SIGPIPE` will terminate the application.\n\nA simple solution, if `SIGPIPE` is not required for normal operation\nof the application (eg, it is not part of a unix pipeline, the\ntraditional use of `SIGPIPE`), is to set `SIGPIPE` to be ignored\nwith code like:\n\n    #include <signal.h>\n    ...\n    signal(SIGPIPE, SIG_IGN);\n\nnear the start of the application (eg, before initialising the ZeroMQ\nlibrary).\n\nIf `SIGPIPE` is required for normal operation it is recommended that\nthe application install a signal handler that flags the signal was\nreceived, and allows the application main loop to determine if it\nwas received for one of its own file descriptors -- and ignores it if it\nnone of the applications own file descriptors seems to have changed.\n\nLinking to the `libzmq.a` static library will pull in substantially\nall of the library code, which will add about 4MB to the application\nsize (per executable statically linked with ZeroMQ).  If this is a\nsignificant consideration, use of the DLL version is recommended.\n\nSee also ZeroMQ test status on z/OS UNIX System Services below\nfor other caveats.\n\n\n## Setting other compilation flags\n\n### Optimisation\n\nTo build with optimisation:\n\n*   set `ZCXXFLAGS` to \"`-O2`\" before starting build process above\n\n\n### Full debugging symbols\n\nTo build with debugging symbols:\n\n*   set `ZCXXFLAGS` to \"`-g`\" before starting build process above\n\n### 64-bit mode (LP64/amode=64)\n\nTo build in 64-bit mode:\n\nThe default build is\n[ILP32](http://publib.boulder.ibm.com/infocenter/zvm/v6r1/index.jsp?topic=/com.ibm.zos.r9.cbcux01/lp64cop.htm),\nthe default for the IBM XL C/C++ compiler.  To build in LP64 mode\n(64-bit):\n\n*    set  `ZCXXFLAGS` to \"`-Wc,lp64 -Wl,lp64`\" before starting build\n\n(64-bit mode can be combined with optimisation or debug symbols.)\n\n### Combining compilation flags\n\nOther build flags can be used in `ZXCCFLAGS` if desired.  Beware that\nthey are passed through (Bourne) shell expansion, and passed to both\nthe compile and link stages; some experimentation of argument quoting\nmay be required (and arguments requiring parenthesis are particularly\ncomplicated).\n\n\n## ZeroMQ test status on z/OS UNIX System Services\n\nAs of 2014-07-22, 41 of the 43 tests in the core ZeroMQ test suite\npass. There are two tests that are expected to fail:\n\n0.  `test_abstract_ipc`: tests Linux-specific IPC functions, and is\n    expected to fail on non-Linux platforms.\n\n0.  `test_fork`: tests ability to use ZeroMQ both before *and* after\n    fork (and before exec()); this relies on the ability to use \n    pthreads both before *and* after fork.  On z/OS (and some other\n    UNIX compliant platforms) functions like `pthreads_create` (used\n    by ZeroMQ) cannot be used after fork and before exec; on z/OS the\n    call after fork fails with `ELEMULTITHREADFORK` (errno=257) if\n    ZeroMQ was also used before fork.  (On z/OS it appears possible\n    to use z/OS *after* fork, *providing* it has not been used before\n    fork -- the problem is the two separate initialisations of the\n    threading library, before and after fork, attempting to mix\n    together.)  In practice this is unlikely to affect many real-world\n    programs -- most programs use threads or fork without exec, but\n    not both.\n\n0.  `test_diffserv`: tests ability to set IP_TOS ([IP Type of\n    Service](http://en.wikipedia.org/wiki/Type_of_service), or\n    [DiffServ](http://en.wikipedia.org/wiki/Differentiated_Services_Code_Point))\n    values on sockets.  While z/OS UNIX System Services has the\n    preprocessor defines required, it appears not to support the\n    required functionality (call fails with \"EDC8109I Protocol not\n    available.\")\n\nThese three \"expected to fail\" tests are listed as XFAIL_TESTS, and\n`runtests` will still consider the test run successful when they fail\nas expected.  (`builds/zos/runtests` will automatically skip these\n\"expected to fail\" tests if running \"all\" tests.)\n\nIn addition `test_security_curve` does not do any meaningful testing,\nas a result of the CURVE support not being compiled in; it requires\n[`libsodium`](http://doc.libsodium.org/), which has not been\nported to z/OS UNIX System Services yet.\n\nMulticast (via `libpgm`) is also not ported or compiled in.\n\n[TIPC](http://hintjens.com/blog:70), a cluster IPC protocol,\nis only supported on Linux, so it is not compiled into the z/OS\nUNIX System Services port -- and the tests are automatically skipped\nif running \"all\" tests.  (However they are not listed in XFAIL_TESTS\nbecause without the TIPC support there is no point in even running\nthem, and it would be non-trivial to track them by hand.)\n\n\n## ZeroMQ on z/OS UNIX System Services: Library portability notes\n\n### *.cpp\n\nThe source code in ZeroMQ is a combination of a C++ core library\n(in `*.cpp` and `*.hpp` files), and a C wrapper (also in `*.cpp`\nfiles).  It is all compiled with the C++ compiler.  The IBM XL C/C++\ncompiler (at least the version used for initial porting) insists\nthat C++ source be in `*.C` files (note capital C).  To work around\nthis issue the compile flag `-+` is used (specified in the `zc++`\ncompiler wrapper), which tells the compiler the file should be\nconsidered C++ despite the file extension.\n\n### XPLINK\n\nThe library (and tests) are built in\n[XPLINK](http://www.redbooks.ibm.com/abstracts/sg245991.html) mode\nwith the flags `-Wc,xplink -Wl,xplink` (specified in  the `zc++`\ncompiler wrapper).  This is [recommended by IBM for C++\ncode](http://publib.boulder.ibm.com/infocenter/zvm/v5r4/index.jsp?topic=/com.ibm.zos.r9.ceea200/xplrunt.htm)\ndue to the small functions.  (Amongst other things, using XPLINK\nenables function calls with some arguments passed in registers.)\n\n### long long\n\nZeroMQ makes use of `uint64_t` (which is `unsigned long long` in ILP32\nmode).  To enable this the compile flag `-Wc,lang(longlong)` is passed\nto enable `long long`.  This is passed from the `zc++` compiler wrapper\nin order to be able to specifically quote the argument to protect the \nparentheses from shell expansion.\n\n### BSD-style sockets, with IPv6 support\n\nZeroMQ uses BSD-style socket handling, with extensions to support IPv6.\nBSD-style sockets were merged into SysV-derived UNIX at least a decade\nago, and are required as part of the X/Open Portability Guide at least\nas of XPG 4.2.  To access this functionality two feature macros are \ndefined:\n\n    _XOPEN_SOURCE_EXTENDED=1\n\n    _OPEN_SYS_SOCK_IPV6\n\nThe first enables the XPG 4.2 features (including functionality like\n`getsockname()`), and the latter exposes IPv6 specific functionality\nlike `sa_family_t`.  These flags are defined in the `cxxall` script.\n\n(The traditional BSD-sockets API, exposed with `_OE_SOCKETS` cannot\nbe used because it does not support functions like `getsockname()`,\nnor does it support IPv6 -- and the API definitions prevent compiling\nin LP64 mode due to assumptions about long being 32 bits.  Using\n`_XOPEN_SOURCE_EXTENDED=1` avoids all these problems.)\n\n### pthreads\n\nZeroMQ uses the pthreads library to create additional threads to handle\nbackground communication without blocking the main application.  This\nfunctionaity is enabled on z/OS UNIX System Services by defining:\n\n    _OPEN_THREADS=3\n\nwhich is done in the `cxxall` script.  (The \"3\" value exposes later\npthreads functionality like `pthread_atfork`, although ZeroMQ does not\ncurrently use all these features.)\n\nIf compiling on a *recent* version of z/OS UNIX System Services it\nmay be worth compiling with:\n\n    _UNIX03_THREADS=1\n\nwhich enables a later version of the threading support, potentially\nincluding `pthread_getschedparam` and pthread_setschedparam`; at\npresent in the z/OS UNIX System Services port these functions are\nhidden and never called.  (See [IBM z/OS pthread.h\ndocumentation](http://pic.dhe.ibm.com/infocenter/zos/v1r11/index.jsp?topic=/com.ibm.zos.r11.bpxbd00/pthrdh.htm)\nfor details on the differences.)\n\n\n## `platform.hpp` on z/OS UNIX System Services\n\nThe build (described above) on z/OS UNIX System Services uses a static\npre-built `platform.hpp` file.  (By default `src/platform.hpp` is \ndynamically generated as a result of running the `./configure` script.)\nThe master version of this is in `builds/zos/platform.hpp`.\n\nBeware that this file contains the version number for libzmq (usually\nincluded during the configure phase).  If taking the `platform.hpp` from\nan older version to use on a newer libzmq be sure to update the version\ninformation near the top of the file.\n\nThe pre-built file is used because z/OS does not have the GNU auto tools\n(`automake`, `autoconf`, `libtool`, etc) installed, and particularly the\nlibtool replacement does not work properly with the IBM XL C/C++\ncompiler.\n\nThe `./configure` script (only supplied in the tarballs); built with\n`automake` and `autoconf` on another platform), with one small edit,\nwas used to generate the z/OS `platform.hpp` and then two small changes\n(described below) were made by hand to the generated `platform.hpp`.\n\nTo be able to run the ./configure script to completion (in tcsh \nsyntax):\n\n*   Edit `./configure` and add:\n\n        openedition)\n              ;;\n\n    immediately before the line:\n\n        as_fn_error $? \"unsupported system: ${host_os}.\" \"$LINENO\" 5\n\n    (somewhere around 17637).  This avoids the configure script giving\n    up early because `openedition` is not recognised.\n\n*   set `CXX` to point that the full  path to the `builds/zos/zc++` wrapper, eg\n\n        setenv CXX \"/u/0mq/zeromq-4.0.4/builds/zos/zc++\"\n\n*   set `CPPFLAGS` to for the feature macros required, eg:\n\n        setenv CPPFLAGS \"-D_XOPEN_SOURCE_EXTENDED=1 -D_OPEN_THREADS=3 -D_OPEN_SYS_SOCK_IPV6 -DZMQ_HAVE_ZOS\"\n\n*   set `CXXFLAGS` to enable XPLINK:\n\n        setenv CXXFLAGS \"-Wc,xplink -Wl,xplink -+\"\n\n*   run configure script with `--disable-eventfd` (`sys/eventfd.h` does\n    not exist, but the test for its existence has a false positive on\n    z/OS UNIX System Services, apparently due to the way the `c++`\n    compiler wrapper passes errors back from the IBM XL C/C++ compiler),\n    and with `--with-poller=poll` because `poll` is the most advanced\n    of the file descriptor status tests available on z/OS.  That is:\n\n        ./configure --disable-eventfd --with-poller=poll\n\nAll going well several Makefiles, and `src/platform.hpp` should be\nproduced.  Two additional changes are required to `src/platform.hpp`\nwhich can be appended to the end:\n\n    /* ---- Special case for z/OS Unix Services: openedition ---- */\n    #include <pthread.h>\n    #ifndef   NI_MAXHOST\n    #define   NI_MAXHOST 1025\n    #endif\n\n(many includes require pthreads-related methods or data structures to\nbe defined, but not all of them include `pthread.h`, and the value\n`NI_MAXHOST` is not defined on z/OS UNIX System Services -- the 1025\nvalue is the conventional value on other platforms).\n\nHaving done this the Makefiles can be used to compile individual files\nif desired, eg:\n\n    cd src\n    make zmq.o\n\nbut note:\n\n*   IBM Make will warn of duplicate prerequisites on *every* run of\n    `make`, and both the generated `src/Makefile` and `tests/Makefile`\n    have several duplicates.  (For `src/Makefile` edit\n    `libzmq_la_SOURCES` to remove the duplicates.)\n\n*   IBM Make does not understand the `@` prefix (eg, `@echo`) as a way\n    to avoid echoing the command, resulting in an error and the command\n    being echoed anyway.\n\n*   Many of the make targets result in GNU auto tools (`aclocal`, etc)\n    being invoked, which are likely to fail, and most of the\n    library-related targets will invoke `libtool` which will cause\n    compile failures (due to differences in expected arguments).\n\nHowever running `./configure` to regenerate `src/platform.hpp` may \nbe useful for later versions of ZeroMQ which add more feature tests.\n\n\n## Transferring from GitHub to z/OS UNIX System Services\n\nThe process of transferring files from GitHub to z/OS UNIX System\nServices is somewhat convoluted because:\n\n*   There is not a port of git for z/OS UNIX System Services; and\n\n*   z/OS uses the EBCDIC (IBM-1047) character set rather than the\n    ASCII/ISO-8859-1 character set used by the ZeroMQ source code\n    on GitHub\n\nA workable transfer process is:\n\n*   On an ASCII/ISO-8859-1/UTF-8 system with `git` (eg, a Linux system):\n\n        git clone https://github.com/zeromq/libzmq.git\n        git archive --prefix=libzmq-git/ -o /var/tmp/libzmq-git.tar master\n\n*   On a ASCII/ISO-8859-1/UTF-8 system with `tar`, and `pax`, and\n    optionally the GNU auto tools (eg, the same Linux system):\n\n        mkdir /var/tmp/zos\n        cd /var/tmp/zos\n        tar -xpf /var/tmp/libzmq-git.tar\n        cd libzmq-git\n        ./autogen.sh             # Optional: to be able to run ./configure\n        cd ..\n        pax -wf /var/tmp/libzmq-git.pax libzmq-git\n        compress libzmq-git.pax  # If available, reduce transfer size\n\n*   Transfer the resulting file (`libzmq-git.pax` or `libzmq-git.pax.Z`)\n    to the z/OS UNIX System Services system.  If using FTP be sure to\n    transfer the file in `bin` (binary/Image) mode to avoid corruption.\n\n*   On the z/OS UNIX System Services system, unpack the `pax` file and\n    convert all the files to EBCDIC with:\n\n        pax -o from=iso8859-1 -pp -rvf  libzmq-git-2014-07-23.pax\n\n    or if the file was compressed:\n\n        pax -o from=iso8859-1 -pp -rvzf libzmq-git-2014-07-23.pax.Z\n\nThe result should be a `libzmq-git` directory with the source in\nEBCDIC format, on the z/OS UNIX System Services system ready to start\nbuilding.\n\nSee also the [`pax` man\npage](http://pic.dhe.ibm.com/infocenter/zos/v1r13/index.jsp?topic=%2Fcom.ibm.zos.r13.bpxa500%2Fr4paxsh.htm),\nsome [`pax` conversion\nexamples](http://pic.dhe.ibm.com/infocenter/zos/v1r13/index.jsp?topic=%2Fcom.ibm.zos.r13.bpxa400%2Fbpxza4c0291.htm),\nand [IBM's advice on ASCII to EBCDIC conversion\noptions](http://www-03.ibm.com/systems/z/os/zos/features/unix/bpxa1p03.html)\n"
  },
  {
    "path": "builds/zos/cxxall",
    "content": "#! /bin/sh\n# Attempt to compile all *.cpp files in the current directory, that are\n# not already compiled.  Uses zc++ wrapper around C++ compiler, to add\n# additional compile arguments.\n#\n# Written by Ewen McNeill <ewen@imatix.com>, 2014-07-19\n# Updated by Ewen McNeill <ewen@imatix.com>, 2014-07-24\n#---------------------------------------------------------------------------\n\nVERBOSE=\"${VERBOSE:-}\"    # Set to non-empty for already done status\nexport VERBOSE\n\n# Locate compiler wrapper\nBIN_DIR=$(dirname $0)\nif [ -z \"${BIN_DIR}\" ]; then BIN_DIR=\".\"; fi\ncase \"${BIN_DIR}\" in\n  .)  BIN_DIR=\"$(pwd)\";            ;;\n  /*)                              ;; \n  *)  BIN_DIR=\"$(pwd)/${BIN_DIR}\"; ;;\nesac\nZCXX=\"${BIN_DIR}/zc++\"\n\n# Determine compile flags\nCPPFLAGS=\"-D_XOPEN_SOURCE_EXTENDED=1 -D_OPEN_THREADS=3 -D_OPEN_SYS_SOCK_IPV6\"\nCXXFLAGS=\"-DZMQ_HAVE_ZOS -DHAVE_CONFIG_H -D_REENTRANT -D_THREAD_SAFE -DZMQ_USE_POLL\"\ncase $(pwd) in\n  *src)   CXXFLAGS=\"${CXXFLAGS} -I.\"\n          ;;\n  *tests) CXXFLAGS=\"${CXXFLAGS} -I. -I../src -I../include\"\n          ;;\n  *)      echo \"Currently only builds in src/ and tests/\" >&2\n          exit 1\n          ;;\nesac\n\nskip() {\n  SRC=\"$1\"\n  OBJ=\"$2\"\n  if [ -n \"${VERBOSE}\" ]; then\n    echo \"    ${SRC} compiled already\"\n  fi\n}\n\ncompile() {\n  SRC=\"$1\"\n  OBJ=\"$2\"\n  echo \"CXX ${SRC}\"\n  \"${ZCXX}\" ${CXXFLAGS} ${CPPFLAGS} -+ -c -o \"${OBJ}\" \"${SRC}\"\n}\n\nfor SRC in *.cpp; do \n  OBJ=$(echo $SRC | sed 's/\\.cpp/.o/;')\n  if [ -f \"${OBJ}\" ]; then \n    if [ \"${OBJ}\" -nt \"${SRC}\" ]; then\n      skip \"${SRC}\" \"${OBJ}\"\n    else\n      compile \"${SRC}\" \"${OBJ}\"\n    fi\n  else\n    compile \"${SRC}\" \"${OBJ}\"\n  fi\ndone\n"
  },
  {
    "path": "builds/zos/makeclean",
    "content": "#! /bin/sh\n# Remove built object files and test executables\n#\n# Written by Ewen McNeill <ewen@imatix.com>, 2014-07-22\n# Updated by Ewen McNeill <ewen@imatix.com>, 2014-07-24\n#---------------------------------------------------------------------------\n\nset -e    # Stop on errors\n\n# Figure out where we are\nBIN_DIR=$(dirname $0)\nif [ -z \"${BIN_DIR}\" ]; then BIN_DIR=\".\"; fi\ncase \"${BIN_DIR}\" in\n  .)  BIN_DIR=\"$(pwd)\";            ;;\n  /*)                              ;; \n  *)  BIN_DIR=\"$(pwd)/${BIN_DIR}\"; ;;\nesac\n\n# Locate top of source tree, assuming we're in builds/zos\nTOP=\"${BIN_DIR}/../..\"\nSRC=\"${TOP}/src\"\nTESTS=\"${TOP}/tests\"\n\n# Remove object/library files\necho \"Removing libzmq built files\"\n(cd \"${SRC}\" && rm -f *.o *.a *.dbg *.x *.so libzmq)\n\n# Remove test object files\necho \"Removing libzmq tests\"\n(cd \"${TESTS}\" && rm -f *.o *.dbg)\n(cd \"${TESTS}\"; \n EXES=$(ls test_* | grep -v \"\\.\")\n if [ -n \"${EXES}\" ]; then\n   rm ${EXES}\n fi\n)\n"
  },
  {
    "path": "builds/zos/makelibzmq",
    "content": "#! /bin/sh\n# Build libzmq.a static library and libzmq.so dynamic library\n#\n# Usage: makelibzmq\n#        BUILD_DLL=false makelibzmq     # Skip building DLL\n#\n# NOTE: We do a single compile run for both static and dynamic libraries\n# which results in the static library having -Wc,exportall compiled objects;\n# in practice this doesn't seem to cause a problem beyond using some extra\n# space (around 10%).\n#\n# Written by Ewen McNeill <ewen@imatix.com>, 2014-07-21\n# Updated by Ewen McNeill <ewen@imatix.com>, 2014-07-22\n#---------------------------------------------------------------------------\n\nset -e    # Stop on errors\n\nBUILD_DLL=\"${BUILD_DLL:-true}\"     # Build DLL by default\n\n# Figure out where we are\nBIN_DIR=$(dirname $0)\nif [ -z \"${BIN_DIR}\" ]; then BIN_DIR=\".\"; fi\ncase \"${BIN_DIR}\" in\n  .)  BIN_DIR=\"$(pwd)\";            ;;\n  /*)                              ;; \n  *)  BIN_DIR=\"$(pwd)/${BIN_DIR}\"; ;;\nesac\nZCXX=\"${BIN_DIR}/zc++\"\n\n# Locate top of source tree, assuming we're in builds/zos\nTOP=\"${BIN_DIR}/../..\"\nSRC=\"${TOP}/src\"\n\n# Install pre-generated platform.hpp\ncp -p \"${BIN_DIR}/platform.hpp\" \"${SRC}/platform.hpp\"\n\n# Compile all the source (optionally ready for a DLL)\nif [ \"${BUILD_DLL}\" = \"true\" ]; then\n  ZCXXFLAGS=\"${ZCXXFLAGS} -Wc,exportall\"\n  export ZCXXFLAGS\n  #echo \"Building DLL with ${ZCXXFLAGS}\"\nfi\n\ncd \"${SRC}\"\n\"${BIN_DIR}/cxxall\"\n\n# Make static library\nar r libzmq.a *.o\n\n# Optionally Make dynamic library\nif [ \"${BUILD_DLL}\" = \"true\" ]; then\n  #echo \"Building libzmq.so DLL\"\n  \"${ZCXX}\" -Wl,DLL -o libzmq.so *.o\nfi\n"
  },
  {
    "path": "builds/zos/maketests",
    "content": "#! /bin/sh\n# Build tests/* executables; assumes that libzmq.a or libzmq.so/libzmq.x\n# is already built\n#\n# If libzmq.so and libzmq.x exist, then dynamic linking is used, otherwise\n# static linking is used.\n#\n# Written by Ewen McNeill <ewen@imatix.com>, 2014-07-21\n# Updated by Ewen McNeill <ewen@imatix.com>, 2014-07-22\n#---------------------------------------------------------------------------\n\nset -e    # Stop on errors\n\nVERBOSE=\"${VERBOSE:-}\"    # Set to non-empty for already done status\nexport VERBOSE\n\n# Figure out where we are\nBIN_DIR=$(dirname $0)\nif [ -z \"${BIN_DIR}\" ]; then BIN_DIR=\".\"; fi\ncase \"${BIN_DIR}\" in\n  .)  BIN_DIR=\"$(pwd)\";            ;;\n  /*)                              ;; \n  *)  BIN_DIR=\"$(pwd)/${BIN_DIR}\"; ;;\nesac\n\n# Locate compiler wrapper\nZCXX=\"${BIN_DIR}/zc++\"\n\n# Locate top of source tree, assuming we're in builds/zos\nTOP=\"${BIN_DIR}/../..\"\nSRC=\"${TOP}/src\"\nTESTS=\"${TOP}/tests\"\n\n# Figure out how we are going to link to ZMQ\nLINK_TYPE=unknown\n\nif [ -f \"${SRC}/platform.hpp\" -a -f \"${SRC}/libzmq.so\" -a -f \"${SRC}/libzmq.x\" ]; then\n  LINK_TYPE=dynamic\nelif [ -f \"${SRC}/platform.hpp\" -a -f \"${SRC}/libzmq.a\" ]; then\n  LINK_TYPE=static\nelse\n  echo \"Error: run makezmqlib to build libzmq.a and/or libzmq.so/libzmq.x first\" >&2\n  exit 1\nfi\n\n# Copy in replacement test with timeout, if main version is not already\n# up to date\n#\nif [ -f \"${TESTS}/test_fork.cpp\" ] && \n     grep \"TIMEOUT\" \"${TESTS}/test_fork.cpp\" >/dev/null 2>&1; then\n  :  # Already copied in\nelse\n  echo \"Updating test_fork.cpp to version with master timeout\"\n  cp -p \"${BIN_DIR}/test_fork.cpp\" \"${TESTS}/test_fork.cpp\"\nfi\n\n# Compile all the source\nif [ \"${LINK_TYPE}\" = \"dynamic\" ]; then\n  ZCXXFLAGS=\"${ZCXXFLAGS} -Wc,DLL\"\n  export ZXCCFLAGS\n  echo \"Building tests to use DLL: ${ZCXXFLAGS}\"\nfi\n\ncd \"${TESTS}\"\n\"${BIN_DIR}/cxxall\"\n\n# Link all the executables that are not already linked\nskip() {\n  OBJ=\"$1\"\n  EXE=\"$2\"\n  if [ -n \"${VERBOSE}\" ]; then\n    echo \"${OBJ} linked to ${EXE}\"\n  fi    \n}\n\nlink() {\n  OBJ=\"$1\"\n  EXE=\"$2\"\n  echo \" LD ${EXE}\"\n  case \"${LINK_TYPE}\" in\n    static)  \"${ZCXX}\" -L ../src -o \"${EXE}\" \"${OBJ}\" -lzmq\n             ;;\n    dynamic) \"${ZCXX}\" -o \"${EXE}\" \"${OBJ}\" ../src/libzmq.x\n             ;;\n    *)       echo \"Do not know how to do ${LINK_TYPE} linking!\" 2>&1\n             exit 1\n             ;;\n  esac\n}\n\nfor OBJ in *.o; do \n  EXE=$(echo \"${OBJ}\" | sed 's/\\.o//;')\n  if [ -f \"${EXE}\" ]; then \n    if [ \"${EXE}\" -nt\t\"${OBJ}\" ]; then\n      skip \"${OBJ}\" \"${EXE}\"\n    else\n      link \"${OBJ}\" \"${EXE}\"\n    fi\n  else\n    link \"${OBJ}\" \"${EXE}\"\n  fi\ndone\n"
  },
  {
    "path": "builds/zos/platform.hpp",
    "content": "/* src/platform.hpp.  Generated from platform.hpp.in by configure.  */\n/* src/platform.hpp.in.  Generated from configure.ac by autoheader.  */\n\n/* Define to 1 if you have the <alloca.h> header file. */\n/* #undef HAVE_ALLOCA_H */\n\n/* Define to 1 if you have the <arpa/inet.h> header file. */\n#define HAVE_ARPA_INET_H 1\n\n/* Define to 1 if you have the `clock_gettime' function. */\n/* #undef HAVE_CLOCK_GETTIME */\n\n/* Define to 1 if you have the declaration of `LOCAL_PEERCRED', and to 0 if\n   you don't. */\n#define HAVE_DECL_LOCAL_PEERCRED 0\n\n/* Define to 1 if you have the declaration of `SO_PEERCRED', and to 0 if you\n   don't. */\n#define HAVE_DECL_SO_PEERCRED 0\n\n/* Define to 1 if you have the <dlfcn.h> header file. */\n#define HAVE_DLFCN_H 1\n\n/* Define to 1 if you have the <errno.h> header file. */\n#define HAVE_ERRNO_H 1\n\n/* Define to 1 if you have the `fork' function. */\n#define HAVE_FORK 1\n\n/* Define to 1 if you have the `freeifaddrs' function. */\n#define HAVE_FREEIFADDRS 1\n\n/* Define to 1 if you have the `gethrtime' function. */\n/* #undef HAVE_GETHRTIME */\n\n/* Define to 1 if you have the `getifaddrs' function. */\n#define HAVE_GETIFADDRS 1\n\n/* Define to 1 if you have the `gettimeofday' function. */\n#define HAVE_GETTIMEOFDAY 1\n\n/* Define to 1 if you have the <ifaddrs.h> header file. */\n#define HAVE_IFADDRS_H 1\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#define HAVE_INTTYPES_H 1\n\n/* Define to 1 if you have the `gssapi_krb5' library (-lgssapi_krb5). */\n/* #undef HAVE_LIBGSSAPI_KRB5 */\n\n/* Define to 1 if you have the `iphlpapi' library (-liphlpapi). */\n/* #undef HAVE_LIBIPHLPAPI */\n\n/* Define to 1 if you have the `nsl' library (-lnsl). */\n/* #undef HAVE_LIBNSL */\n\n/* Define to 1 if you have the `pthread' library (-lpthread). */\n/* #undef HAVE_LIBPTHREAD */\n\n/* Define to 1 if you have the `rpcrt4' library (-lrpcrt4). */\n/* #undef HAVE_LIBRPCRT4 */\n\n/* Define to 1 if you have the `rt' library (-lrt). */\n/* #undef HAVE_LIBRT */\n\n/* Define to 1 if you have the `socket' library (-lsocket). */\n/* #undef HAVE_LIBSOCKET */\n\n/* Define to 1 if you have the `sodium' library (-lsodium). */\n/* #undef HAVE_LIBSODIUM */\n\n/* Define to 1 if you have the `ws2_32' library (-lws2_32). */\n/* #undef HAVE_LIBWS2_32 */\n\n/* Define to 1 if you have the <limits.h> header file. */\n#define HAVE_LIMITS_H 1\n\n/* Define to 1 if you have the <memory.h> header file. */\n#define HAVE_MEMORY_H 1\n\n/* Define to 1 if you have the `memset' function. */\n#define HAVE_MEMSET 1\n\n/* Define to 1 if you have the <netinet/in.h> header file. */\n#define HAVE_NETINET_IN_H 1\n\n/* Define to 1 if you have the <netinet/tcp.h> header file. */\n#define HAVE_NETINET_TCP_H 1\n\n/* Define to 1 if you have the `perror' function. */\n#define HAVE_PERROR 1\n\n/* Define to 1 if you have the `socket' function. */\n#define HAVE_SOCKET 1\n\n/* Define to 1 if stdbool.h conforms to C99. */\n/* #undef HAVE_STDBOOL_H */\n\n/* Define to 1 if you have the <stddef.h> header file. */\n#define HAVE_STDDEF_H 1\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#define HAVE_STDINT_H 1\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#define HAVE_STDLIB_H 1\n\n/* Define to 1 if you have the <strings.h> header file. */\n#define HAVE_STRINGS_H 1\n\n/* Define to 1 if you have the <string.h> header file. */\n#define HAVE_STRING_H 1\n\n/* Define to 1 if you have the <sys/eventfd.h> header file. */\n/* #undef HAVE_SYS_EVENTFD_H */\n\n/* Define to 1 if you have the <sys/socket.h> header file. */\n#define HAVE_SYS_SOCKET_H 1\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#define HAVE_SYS_STAT_H 1\n\n/* Define to 1 if you have the <sys/time.h> header file. */\n#define HAVE_SYS_TIME_H 1\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#define HAVE_SYS_TYPES_H 1\n\n/* Define to 1 if you have the <sys/uio.h> header file. */\n#define HAVE_SYS_UIO_H 1\n\n/* Define to 1 if you have the <time.h> header file. */\n#define HAVE_TIME_H 1\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#define HAVE_UNISTD_H 1\n\n/* Define to 1 if you have the <windows.h> header file. */\n/* #undef HAVE_WINDOWS_H */\n\n/* Define to 1 if the system has the type `_Bool'. */\n/* #undef HAVE__BOOL */\n\n/* Define to the sub-directory in which libtool stores uninstalled libraries.\n   */\n#define LT_OBJDIR \".libs/\"\n\n/* Name of package */\n#define PACKAGE \"zeromq\"\n\n/* Define to the address where bug reports for this package should be sent. */\n#define PACKAGE_BUGREPORT \"zeromq-dev@lists.zeromq.org\"\n\n/* Define to the full name of this package. */\n#define PACKAGE_NAME \"zeromq\"\n\n/* Define to the full name and version of this package. */\n#define PACKAGE_STRING \"zeromq 4.1.0\"\n\n/* Define to the one symbol short name of this package. */\n#define PACKAGE_TARNAME \"zeromq\"\n\n/* Define to the home page for this package. */\n#define PACKAGE_URL \"\"\n\n/* Define to the version of this package. */\n#define PACKAGE_VERSION \"4.1.0\"\n\n/* Define as the return type of signal handlers (`int' or `void'). */\n#define RETSIGTYPE void\n\n/* Define to 1 if you have the ANSI C header files. */\n#define STDC_HEADERS 1\n\n/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */\n#define TIME_WITH_SYS_TIME 1\n\n/* Version number of package */\n#define VERSION \"4.1.0\"\n\n/* Enable militant API assertions */\n/* #undef ZMQ_ACT_MILITANT */\n\n/* Force to use mutexes */\n/* #undef ZMQ_FORCE_MUTEXES */\n\n/* Have AIX OS */\n/* #undef ZMQ_HAVE_AIX */\n\n/* Have Android OS */\n/* #undef ZMQ_HAVE_ANDROID */\n\n/* Have Cygwin */\n/* #undef ZMQ_HAVE_CYGWIN */\n\n/* Have eventfd extension. */\n/* #undef ZMQ_HAVE_EVENTFD */\n\n/* Have FreeBSD OS */\n/* #undef ZMQ_HAVE_FREEBSD */\n\n/* Have HPUX OS */\n/* #undef ZMQ_HAVE_HPUX */\n\n/* Have ifaddrs.h header. */\n#define ZMQ_HAVE_IFADDRS 1\n\n/* Have Linux OS */\n/* #undef ZMQ_HAVE_LINUX */\n\n/* Have LOCAL_PEERCRED socket option */\n/* #undef ZMQ_HAVE_LOCAL_PEERCRED */\n\n/* Have MinGW32 */\n/* #undef ZMQ_HAVE_MINGW32 */\n\n/* Have NetBSD OS */\n/* #undef ZMQ_HAVE_NETBSD */\n\n/* Have NORM protocol extension */\n/* #undef ZMQ_HAVE_NORM */\n\n/* Have OpenBSD OS */\n/* #undef ZMQ_HAVE_OPENBSD */\n\n/* Have OpenPGM extension */\n/* #undef ZMQ_HAVE_OPENPGM */\n\n/* Have DarwinOSX OS */\n/* #undef ZMQ_HAVE_OSX */\n\n/* Have QNX Neutrino OS */\n/* #undef ZMQ_HAVE_QNXNTO */\n\n/* Whether SOCK_CLOEXEC is defined and functioning. */\n/* #undef ZMQ_HAVE_SOCK_CLOEXEC */\n\n/* Have Solaris OS */\n/* #undef ZMQ_HAVE_SOLARIS */\n\n/* Whether SO_KEEPALIVE is supported. */\n#define ZMQ_HAVE_SO_KEEPALIVE 1\n\n/* Have SO_PEERCRED socket option */\n/* #undef ZMQ_HAVE_SO_PEERCRED */\n\n/* Whether TCP_KEEPALIVE is supported. */\n/* #undef ZMQ_HAVE_TCP_KEEPALIVE */\n\n/* Whether TCP_KEEPCNT is supported. */\n/* #undef ZMQ_HAVE_TCP_KEEPCNT */\n\n/* Whether TCP_KEEPIDLE is supported. */\n/* #undef ZMQ_HAVE_TCP_KEEPIDLE */\n\n/* Whether TCP_KEEPINTVL is supported. */\n/* #undef ZMQ_HAVE_TCP_KEEPINTVL */\n\n/* Have TIPC support */\n/* #undef ZMQ_HAVE_TIPC */\n\n/* Have uio.h header. */\n#define ZMQ_HAVE_UIO 1\n\n/* Have Windows OS */\n/* #undef ZMQ_HAVE_WINDOWS */\n\n/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,\n   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the\n   #define below would cause a syntax error. */\n/* #undef _UINT32_T */\n\n/* Define to empty if `const' does not conform to ANSI C. */\n/* #undef const */\n\n/* Define to `__inline__' or `__inline' if that's what the C compiler\n   calls it, or to nothing if 'inline' is not supported under any name.  */\n#ifndef __cplusplus\n/* #undef inline */\n#endif\n\n/* Define to `unsigned int' if <sys/types.h> does not define. */\n/* #undef size_t */\n\n/* Define to `int' if <sys/types.h> does not define. */\n/* #undef ssize_t */\n\n/* Define to the type of an unsigned integer type of width exactly 32 bits if\n   such a type exists and the standard includes do not define it. */\n/* #undef uint32_t */\n\n/* Define to empty if the keyword `volatile' does not work. Warning: valid\n   code using `volatile' can become incorrect without. Disable with care. */\n/* #undef volatile */\n\n/* ---- Special case for z/OS Unix Services: openedition ---- */\n#include <pthread.h>\n#ifndef   NI_MAXHOST\n#define   NI_MAXHOST 1025\n#endif\n"
  },
  {
    "path": "builds/zos/runtests",
    "content": "#! /bin/sh\n# Run ZeroMQ tests, in order.  This is extracted from the tests/Makefile\n# which won't run as-is because it relies on libtool building things, and \n# thus creating various libtool files, which don't work well on z/OS\n#\n# noinst_PROGRAMS needs to be kept in sync with tests/Makefile.am, as it\n# defines the order in which tests are run.\n#\n# Written by Ewen McNeill <ewen@imatix.com>, 2014-07-19\n# Updated by Ewen McNeill <ewen@imatix.com>, 2014-07-24\n#---------------------------------------------------------------------------\n\nset -e    # Stop if a test fails\n\n#---------------------------------------------------------------------------\n# Change to tests directory if necessary\n\n# Figure out where we are\nBIN_DIR=$(dirname $0)\nif [ -z \"${BIN_DIR}\" ]; then BIN_DIR=\".\"; fi\ncase \"${BIN_DIR}\" in\n  .)  BIN_DIR=\"$(pwd)\";            ;;\n  /*)                              ;; \n  *)  BIN_DIR=\"$(pwd)/${BIN_DIR}\"; ;;\nesac\n\n# Locate top of source tree, assuming we're in builds/zos\nTOP=\"${BIN_DIR}/../..\"\nSRCDIR=\"${TOP}/src\"\nTESTDIR=\"${TOP}/tests\"\n\ncase \"$(pwd)\" in\n  *tests) ;;\n  *)      echo \"Changing to ${TESTDIR}\"\n          cd \"${TESTDIR}\"\n          ;;\nesac\n\nif [ -x \"test_system\" ]; then\n  :\nelse\n  echo \"Run makelibzmq and maketests before runtests\" >&2\n  exit 1\nfi\n\n#---------------------------------------------------------------------------\n# Explanation of tests expected to fail:\n# test_abstract_ipc: Relies on Linux-specific IPC functionality\n# test_fork:         Relies on using pthreads _after_ fork, _before_ exec\n# test_diffserv:     Needs IP_PROTO, IP_TOS setsockopt(); the headers\n#                    are present on z/OS UNIX System Services, but\n#                    fails with:\n#                    EDC8109I Protocol not available. (./ip.cpp:164)\n#    NOTE: not listed as a valid IP setsockopt() option at:\n#       http://pic.dhe.ibm.com/infocenter/zos/v2r1/index.jsp?topic=%2Fcom.ibm.zos.v2r1.bpxbd00%2Fsetopt.htm\n#\nXFAIL_TESTS=\"test_abstract_ipc|test_fork|test_diffserv\"\n\n# BUILD_TIPC is not defined, so we skip all these tests\nSKIP_TESTS=\"test_.*_tipc\"\n\n# Extract list of all test programs from tests/Makefile.am\n#\n# Excluding tests we know will fail because of missing functionality\n#\nnoinst_PROGRAMS=$(grep \"test_\" Makefile.am | grep -E -v \"_SOURCES|XFAIL\" |\n                  sed 's/noinst_PROGRAMS.* test/test/; s/^ *//; s/ *\\\\ *$//;' |\n                  grep -v \"${SKIP_TESTS}\" | grep -E -v \"${XFAIL_TESTS}\")\n#echo \"Found tetsts: ${noinst_PROGRAMS}\"\n\n# Run tests on command line, or all tests we found\nif [ -n \"${1}\" ]; then\n  TESTS=\"$*\"     # Run tests on command line\nelse\n  TESTS=\"${noinst_PROGRAMS}\"\nfi\n\nverbose() {\n   echo \"Starting: $@\" >&2\n   \"$@\"\n}\n\n# Uncomment TESTS_ENVIRONMENT=verbose to see \"Starting: TEST\" messages\n#TESTS_ENVIRONMENT=verbose\nTESTS_ENVIRONMENT=\n\n#---------------------------------------------------------------------------\n# Explicitly add SRCDIR into library search path, to make sure we\n# use our just-built version\nLIBPATH=\"${SRCDIR}:/lib:/usr/lib\"\nexport LIBPATH\n\n#---------------------------------------------------------------------------\n# check-TESTS: target from tests/Makefile, converted from Make syntax to\n# shell syntax\n\nfailed=0; all=0; xfail=0; xpass=0; skip=0; \nsrcdir=.; export srcdir; \nlist=\"${TESTS}\";\nred=\"\"; grn=\"\"; lgn=\"\"; blu=\"\"; std=\"\";\nif test -n \"$list\"; then \n  for tst in $list; do \n    if test -f ./$tst; then dir=./; \n    elif test -f $tst; then dir=; \n    else dir=\"${srcdir}/\"; fi; \n    if ${TESTS_ENVIRONMENT} ${dir}$tst; then \n      all=`expr $all + 1`; \n      case \" ${XFAIL_TESTS} \" in \n      *\"$tst\"*) \n        xpass=`expr $xpass + 1`; \n        failed=`expr $failed + 1`; \n        col=$red; res=XPASS; \n      ;; \n      *) \n        col=$grn; res=PASS; \n      ;; \n      esac; \n    elif test $? -ne 77; then \n      all=`expr $all + 1`; \n      case \" ${XFAIL_TESTS} \" in \n       *\"$tst\"*) \n        xfail=`expr $xfail + 1`; \n        col=$lgn; res=XFAIL; \n      ;; \n      *) \n        failed=`expr $failed + 1`; \n        col=$red; res=FAIL; \n      ;; \n      esac; \n    else \n      skip=`expr $skip + 1`; \n      col=$blu; res=SKIP; \n    fi; \n    echo \"${col}$res${std}: $tst\"; \n  done; \n  if test \"$all\" -eq 1; then \n    tests=\"test\"; \n    All=\"\"; \n  else \n    tests=\"tests\"; \n    All=\"All \"; \n  fi; \n  if test \"$failed\" -eq 0; then \n    if test \"$xfail\" -eq 0; then \n      banner=\"$All$all $tests passed\"; \n    else \n      if test \"$xfail\" -eq 1; then failures=failure; else failures=failures; fi;\n      banner=\"$All$all $tests behaved as expected ($xfail expected $failures)\"; \n    fi; \n  else \n    if test \"$xpass\" -eq 0; then \n      banner=\"$failed of $all $tests failed\"; \n    else \n      if test \"$xpass\" -eq 1; then passes=pass; else passes=passes; fi;\n      \n      banner=\"$failed of $all $tests did not behave as expected ($xpass unexpected $passes)\"; \n    fi; \n  fi; \n  dashes=\"$banner\"; \n  skipped=\"\"; \n  if test \"$skip\" -ne 0; then \n    if test \"$skip\" -eq 1; then \n      skipped=\"($skip test was not run)\"; \n    else \n      skipped=\"($skip tests were not run)\"; \n    fi; \n    test `echo \"$skipped\" | wc -c` -le `echo \"$banner\" | wc -c` || \n       dashes=\"$skipped\"; \\        \n  fi; \n  report=\"\"; \n  if test \"$failed\" -ne 0 && test -n \"${PACKAGE_BUGREPORT}\"; then \n    report=\"Please report to ${PACKAGE_BUGREPORT}\"; \n    test `echo \"$report\" | wc -c` -le `echo \"$banner\" | wc -c` || \n      dashes=\"$report\"; \n  fi; \n  dashes=`echo \"$dashes\" | sed s/./=/g`; \n  if test \"$failed\" -eq 0; then \n    col=\"$grn\"; \n  else \n    col=\"$red\"; \n  fi; \n  echo \"${col}$dashes${std}\"; \n  echo \"${col}$banner${std}\"; \n  test -z \"$skipped\" || echo \"${col}$skipped${std}\"; \n  test -z \"$report\" || echo \"${col}$report${std}\"; \n  echo \"${col}$dashes${std}\"; \n  test \"$failed\" -eq 0; \nelse :; fi\n"
  },
  {
    "path": "builds/zos/test_fork.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include <unistd.h>           // For alarm()\n\nconst char *address = \"tcp://127.0.0.1:6571\";\n\n#define NUM_MESSAGES 5\n#define TIMEOUT_SECS 5        // Global timeout\n\nint main (void)\n{\n    setup_test_environment ();\n    void *ctx = zmq_ctx_new ();\n    assert (ctx);\n\n    //  Create and bind pull socket to receive messages\n    void *pull = zmq_socket (ctx, ZMQ_PULL);\n    assert (pull);\n    int rc = zmq_bind (pull, address);\n    assert (rc == 0);\n\n    int pid = fork ();\n    if (pid == 0) {\n        //  Child process\n        //  Immediately close parent sockets and context\n        zmq_close (pull);\n        zmq_ctx_term (ctx);\n\n        //  Create new context, socket, connect and send some messages\n        void *child_ctx = zmq_ctx_new ();\n        assert (child_ctx);\n        void *push = zmq_socket (child_ctx, ZMQ_PUSH);\n        assert (push);\n        rc = zmq_connect (push, address);\n        assert (rc == 0);\n        int count;\n        for (count = 0; count < NUM_MESSAGES; count++)\n            zmq_send (push, \"Hello\", 5, 0);\n\n        zmq_close (push);\n        zmq_ctx_destroy (child_ctx);\n        exit (0);\n    }\n    else {\n        //  Parent process\n        alarm(TIMEOUT_SECS);   // Set upper limit on runtime\n\n        int count;\n        for (count = 0; count < NUM_MESSAGES; count++) {\n            char buffer [5];\n            int num_bytes = zmq_recv (pull, buffer, 5, 0);\n            assert (num_bytes == 5);\n        }\n        int child_status;\n        while (true) {\n            rc = waitpid (pid, &child_status, 0);\n            if (rc == -1 && errno == EINTR)\n                continue;\n            assert (rc > 0);\n            //  Verify the status code of the child was zero\n            assert (WEXITSTATUS (child_status) == 0);\n            break;\n        }\n        exit (0);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "builds/zos/zc++",
    "content": "#! /bin/sh\n# Wrapper around IBM C++ compiler to add \"-+\" to preprocessor calls\n# and thus work with C++ in files other than *.C.  Also add -Wc,lang(longlong)\n# with appropriate quoting to avoid shell confusion -- this is difficult \n# to get through both ./configure arguments _and_ Makefile/shell expansion\n# safely so more easily added in this wrapper.\n#\n# Finally, by default will enable xplink for C++ compatibility and performance\n# (c++ standard library requires xplink enabled).\n#\n# Additional compile/link flags can be passed in as ZCXXFLAGS, eg:\n#\n# For debug:  ZXCCFLAGS=-g ...\n#\n# Written by Ewen McNeill <ewen@imatix.com>, 2014-07-18\n# Updated by Ewen McNeill <ewen@imatix.com>, 2014-07-21\n#---------------------------------------------------------------------------\n\nCPPFLAGS=\"-+\"\nLONGLONG=\"-Wc,lang(longlong)\"\nXPLINK=\"${XPLINK:--Wc,xplink -Wl,xplink}\"\nCXX=\"/bin/c++\"\nZCXXFLAGS=\"${ZCXXFLAGS:-}\"   # Extra compile/link arguments, eg \"-g\"\n\n# For debugging calling conventions issues\n#echo \"Called with: $0 $@\" >>/tmp/zc++.log 2>&1\n#exec >>/tmp/zc++.log 2>&1\n#set -x\n\ncase \"$1\" in \n  -E) exec \"${CXX}\"                            \"${CPPFLAGS}\"           \"$@\"\n      ;;\n  -o) exec \"${CXX}\" ${ZCXXFLAGS} \"${LONGLONG}\" \"${CPPFLAGS}\" ${XPLINK} \"$@\"\n      ;;\n  -c) exec \"${CXX}\" ${ZCXXFLAGS} \"${LONGLONG}\" \"${CPPFLAGS}\" ${XPLINK} \"$@\"\n      ;;\n  -L) # Special case for linking via C++, called from linkall\n      exec \"${CXX}\" ${ZCXXFLAGS}                             ${XPLINK} \"$@\"\n      ;;\n  *)  exec \"${CXX}\" ${ZCXXFLAGS} \"${LONGLONG}\"               ${XPLINK} \"$@\"\n      ;;\nesac\n"
  },
  {
    "path": "ci_build.sh",
    "content": "#!/usr/bin/env bash\n\nset -x\nset -e\n\nif [ $BUILD_TYPE = \"default\" ]; then\n    mkdir tmp\n    BUILD_PREFIX=$PWD/tmp\n\n    source config.sh\n    set_config_opts\n\n    # Build and check this project\n    (\n        ./autogen.sh &&\n        ./configure \"${CONFIG_OPTS[@]}\" &&\n        export DISTCHECK_CONFIGURE_FLAGS=\"${CONFIG_OPTS[@]}\" &&\n        make VERBOSE=1 -j5 ${CHECK}\n    ) || exit 1\nelse\n    cd ./builds/${BUILD_TYPE} && ./ci_build.sh\nfi\n"
  },
  {
    "path": "ci_deploy.sh",
    "content": "#!/usr/bin/env bash\n\n# do NOT set -x or it will log the secret tokens!\nset -e\n\nif [[ $BUILD_TYPE == \"default\" && $CURVE == \"libsodium\" && -z $DRAFT ]]; then\n    # Tell travis to deploy all files in dist\n    mkdir dist\n    export LIBZMQ_DEPLOYMENT=dist/*\n    # Move archives to dist\n    mv *.tar.gz dist\n    mv *.zip dist\n    # Generate hash sums\n    cd dist\n    md5sum *.zip *.tar.gz > MD5SUMS\n    sha1sum *.zip *.tar.gz > SHA1SUMS\n    cd -\nelse\n    export LIBZMQ_DEPLOYMENT=\"\"\nfi\n"
  },
  {
    "path": "config.sh",
    "content": "#!/usr/bin/env bash\n\nfunction set_config_opts() {\n    CONFIG_OPTS=()\n    CONFIG_OPTS+=(\"CFLAGS=-g\")\n    CONFIG_OPTS+=(\"CPPFLAGS=-I${BUILD_PREFIX}/include\")\n    CONFIG_OPTS+=(\"CXXFLAGS=-g\")\n    CONFIG_OPTS+=(\"LDFLAGS=-L${BUILD_PREFIX}/lib\")\n    CONFIG_OPTS+=(\"PKG_CONFIG_PATH=${BUILD_PREFIX}/lib/pkgconfig\")\n    CONFIG_OPTS+=(\"--prefix=${BUILD_PREFIX}\")\n    CHECK=\"distcheck\"\n\n    if [ -n \"$ADDRESS_SANITIZER\" ] && [ \"$ADDRESS_SANITIZER\" = \"enabled\" ]; then\n        CONFIG_OPTS+=(\"--enable-address-sanitizer=yes\")\n        # distcheck does an out-of-tree build, and the fuzzer tests use a hard-coded relative path for simplicity\n        CHECK=\"check\"\n        git clone --depth 1 https://github.com/zeromq/libzmq-fuzz-corpora.git tests/libzmq-fuzz-corpora\n    fi\n\n    if [ \"$USE_NSS\" = \"yes\" ]; then\n        CONFIG_OPTS+=(\"--with-nss\")\n    fi\n\n    if [ -z \"$CURVE\" ]; then\n        CONFIG_OPTS+=(\"--disable-curve\")\n    elif [ \"$CURVE\" = \"libsodium\" ]; then\n        CONFIG_OPTS+=(\"--with-libsodium=yes\")\n\n        if ! ((command -v dpkg-query >/dev/null 2>&1 && dpkg-query --list libsodium-dev >/dev/null 2>&1) || \\\n                (command -v brew >/dev/null 2>&1 && brew ls --versions libsodium >/dev/null 2>&1)); then\n            git clone --depth 1 -b stable https://github.com/jedisct1/libsodium.git\n            ( cd libsodium; ./autogen.sh; ./configure --prefix=$BUILD_PREFIX; make install)\n        fi\n    fi\n\n    if [ -n \"$GSSAPI\" ] && [ \"$GSSAPI\" = \"enabled\" ]; then\n        CONFIG_OPTS+=(\"--with-libgssapi_krb5=yes\")\n    fi\n\n    if [ -n \"$PGM\" ] && [ \"$PGM\" = \"enabled\" ]; then\n        CONFIG_OPTS+=(\"--with-pgm=yes\")\n    fi\n\n    if [ -n \"$NORM\" ] && [ \"$NORM\" = \"enabled\" ]; then\n        CONFIG_OPTS+=(\"--with-norm=yes\")\n    fi\n\n    if [ -n \"$TIPC\" ] && [ \"$TIPC\" = \"enabled\" ]; then\n        sudo modprobe tipc\n    fi\n\n    if [ -n \"$POLLER\" ]; then\n        CONFIG_OPTS+=(\"--with-poller=${POLLER}\")\n    fi\n\n    if [ -n \"$TLS\" ] && [ \"$TLS\" = \"enabled\" ]; then\n        CONFIG_OPTS+=(\"--with-tls=yes\")\n    fi\n\n    if [ -z \"$DRAFT\" ] || [ \"$DRAFT\" = \"disabled\" ]; then\n        CONFIG_OPTS+=(\"--enable-drafts=no\")\n    elif [ \"$DRAFT\" = \"enabled\" ]; then\n        CONFIG_OPTS+=(\"--enable-drafts=yes\")\n    fi\n\n    if [ -n \"$FORCE_98\" ] && [ \"$FORCE_98\" = \"enabled\" ]; then\n        CONFIG_OPTS+=(\"--enable-force-CXX98-compat=yes\")\n    fi\n\n    if [ -n \"$VMCI\" ] && [ \"$VMCI\" = \"enabled\" ]; then\n        CONFIG_OPTS+=(\"--with-vmci=$PWD/vmci\")\n        # VMWare headeers are not ISO C++ compliant\n        CONFIG_OPTS+=(\"--disable-pedantic\")\n        git clone --depth 1 https://github.com/vmware/open-vm-tools.git\n        mkdir -p vmci\n        # Linux headers are redefined, so we can't just add -I to the whole dir\n        cp open-vm-tools/open-vm-tools/lib/include/vmci_* vmci/\n    fi\n}\n"
  },
  {
    "path": "configure.ac",
    "content": "#                                               -*- Autoconf -*-\n# Process this file with autoconf to produce a configure script.\nAC_PREREQ(2.61)\n#\n# The 0MQ version number is extracted from include/zmq.h using\n# the version.sh script. Hence, it should be updated there.\n# The version in git should reflect the *next* version planned.\n#\nAC_INIT([zeromq],[m4_esyscmd([./version.sh])],[zeromq-dev@lists.zeromq.org])\n\nAC_CONFIG_AUX_DIR(config)\nAC_CONFIG_MACRO_DIR(config)\nAC_CONFIG_HEADERS([src/platform.hpp])\nAM_INIT_AUTOMAKE(foreign subdir-objects tar-ustar dist-zip)\n# Allow \"configure --disable-maintainer-mode\" to disable timestamp checking \nAM_MAINTAINER_MODE([enable])\n\nm4_pattern_allow([AC_PROG_CC_C99])\nm4_include([m4/ax_check_compile_flag.m4])\nm4_include([m4/ax_cxx_compile_stdcxx_11.m4])\nm4_include([m4/ax_code_coverage.m4])\nm4_include([m4/ax_valgrind_check.m4])\nm4_include([m4/ax_check_vscript.m4])\nm4_include([m4/ax_func_posix_memalign.m4])\nm4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])\n\n# This lets us use PACKAGE_VERSION in Makefiles\nAC_SUBST(PACKAGE_VERSION)\n\n# Libtool -version-info (ABI version)\n#\n# Don't change this unless you know exactly what you're doing and have read and\n# understand:\n# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html\n#\n# Changes:\n#\n# ZeroMQ versions prior to 2.1.0 use 0:0:0 (undefined)\n# ZeroMQ versions 2.1.x: 1:0:0 (ABI version 1)\n# ZeroMQ version 3.0: 2:0:0 (ABI version 2)\n# ZeroMQ version 3.1: 3:0:0 (ABI version 3)\n# ZeroMQ version 4.0: 4:0:0 (ABI version 4)\n# ZeroMQ version 4.1: 5:0:0 (ABI version 5)\n# ZeroMQ version 4.2.0: 6:0:1 (ABI version 5)\n# ZeroMQ version 4.2.1: 6:1:1 (ABI version 5)\n# ZeroMQ version 4.2.2: 6:2:1 (ABI version 5)\n# ZeroMQ version 4.2.3: 6:3:1 (ABI version 5)\n# ZeroMQ version 4.2.4: 6:4:1 (ABI version 5)\n# ZeroMQ version 4.2.5: 6:5:1 (ABI version 5)\n# ZeroMQ version 4.3.0: 7:0:2 (ABI version 5)\n# ZeroMQ version 4.3.1: 7:1:2 (ABI version 5)\n# ZeroMQ version 4.3.2: 7:2:2 (ABI version 5)\n# ZeroMQ version 4.3.3: 7:3:2 (ABI version 5)\n# ZeroMQ version 4.3.4: 7:4:2 (ABI version 5)\n# ZeroMQ version 4.3.5: 7:5:2 (ABI version 5)\n# ZeroMQ version 4.3.6: 7:6:2 (ABI version 5)\n#\n# libzmq -version-info current:revision:age\nLTVER=\"7:6:2\"\nAC_SUBST(LTVER)\n\n# Take a copy of original flags\nZMQ_ORIG_CFLAGS=\"${CFLAGS:-none}\"\nZMQ_ORIG_CPPFLAGS=\"${CPPFLAGS:-none}\"\nZMQ_ORIG_CXXFLAGS=\"${CXXFLAGS:-none}\"\n\n# Checks for programs.\nAC_PROG_CC\nAX_CHECK_COMPILE_FLAG([-std=c11], [CFLAGS=\"${CFLAGS} -std=c11 -D_DEFAULT_SOURCE\"], [AC_PROG_CC_C99])\nAC_PROG_CXX\nAX_CODE_COVERAGE\nAM_PROG_CC_C_O\nAC_PROG_SED\nAC_PROG_AWK\nPKG_PROG_PKG_CONFIG\nm4_pattern_forbid([^PKG_[A-Z_]+$], [missing some pkg-config macros (pkg-config package)])\n\n# Libtool configuration for different targets. See acinclude.m4\nLIBZMQ_CONFIG_LIBTOOL\nAC_LIBTOOL_WIN32_DLL\nAC_PROG_LIBTOOL\nAX_VALGRIND_CHECK\nAX_CHECK_VSCRIPT\nAX_FUNC_POSIX_MEMALIGN\n\nAC_ARG_ENABLE([force-CXX98-compat],\n    [AS_HELP_STRING([--enable-force-CXX98-compat], [force C++98 build [default=disabled]])])\nif test \"x$enable_force_CXX98_compat\" = \"xyes\"; then\n    AC_LANG_PUSH([C++])\n    AX_CHECK_COMPILE_FLAG([-std=gnu++98], [CXXFLAGS=\"${CXXFLAGS} -std=gnu++98\"], [])\n    AX_CHECK_COMPILE_FLAG([-Wc++98-compat -Wc++98-compat-pedantic], [CXXFLAGS=\"${CXXFLAGS} -Wc++98-compat\"], [])\n    AC_LANG_POP([C++])\nelse\n    AX_CXX_COMPILE_STDCXX_11([ext], [optional])\nfi\n\n# Check whether to build a with debug symbols\nLIBZMQ_CHECK_ENABLE_DEBUG\n\n# Check whether to enable code coverage\nLIBZMQ_WITH_GCOV\n\nAC_MSG_CHECKING([if TIPC is available and supports nonblocking connect])\n\nAC_RUN_IFELSE(\n    [AC_LANG_PROGRAM([[\n            #include <stdlib.h>\n            #include <string.h>\n            #include <fcntl.h>\n            #include <errno.h>\n            #include <sys/socket.h>\n            #include <linux/tipc.h>\n        ]],[[\n            struct sockaddr_tipc topsrv;\n            int sd = socket(AF_TIPC, SOCK_SEQPACKET, 0);\n            memset(&topsrv, 0, sizeof(topsrv));\n            topsrv.family = AF_TIPC;\n            topsrv.addrtype = TIPC_ADDR_NAME;\n            topsrv.addr.name.domain = tipc_addr (10, 10, 10);\n            topsrv.addr.name.name.type = TIPC_TOP_SRV;\n            topsrv.addr.name.name.instance = TIPC_TOP_SRV;\n            fcntl(sd, F_SETFL, O_NONBLOCK);\n        ]])\n    ],\n    [libzmq_tipc_support=yes],\n    [libzmq_tipc_support=no],\n    [libzmq_tipc_support=no])\n\nAC_MSG_RESULT([$libzmq_tipc_support])\n\n\n# check vsock support\nAC_MSG_CHECKING([if vsock is available ])\n\nAC_CHECK_HEADERS([linux/vm_sockets.h],\n   [libzmq_vsock_support=yes],\n   [libzmq_vsock_support=no],\n   [\n    #include <sys/socket.h>\n    #include <linux/vm_sockets.h>\n   ]\n)\n\n\nAC_ARG_ENABLE([pedantic],\n    [AS_HELP_STRING([--disable-pedantic], [disable pedantic compiler checks [default=enabled]])],\n    [libzmq_pedantic=$enableval], [libzmq_pedantic=yes])\n\nAC_ARG_WITH([militant],\n    [AS_HELP_STRING([--with-militant],\n        [enable militant API assertions])],\n    [zmq_militant=\"yes\"],\n    [])\n\nif test \"x$zmq_militant\" = \"xyes\"; then\n    AC_DEFINE(ZMQ_ACT_MILITANT, 1, [Enable militant API assertions])\nfi\n\n# Disable IPC on unsupported platforms.\ncase \"${host_os}\" in\n    *vxworks*|*openvms*|*mingw*)\n        ;;\n    *)\n        AC_DEFINE(ZMQ_HAVE_IPC, 1, [Have AF_UNIX sockets for ipc transport])\n        ;;\nesac\n\n# Data race/deadlock detection\n# NOTE: Running libzmq under TSAN doesn't make much sense -- synchronization in libzmq is to some extent\n# handled by the code \"knowing\" what threads are allowed to do, rather than by enforcing those\n# restrictions, so TSAN generates a lot of (presumably) false positives from libzmq.\n# The settings below are intended to enable libzmq to be built with minimal support for TSAN\n# such that it can be used along with other code that is also built with TSAN.\nAC_MSG_CHECKING([whether to enable TSan])\nAC_ARG_ENABLE(thread-sanitizer, [AS_HELP_STRING([--enable-thread-sanitizer=yes/no],\n                  [Build with clang Thread Sanitizer instrumentation])],\n                  [ZMQ_TSAN=\"$enableval\"])\n\nif test \"x${ZMQ_TSAN}\" = \"xyes\"; then\n    TSAN_FLAGS=\"-fno-omit-frame-pointer -fsanitize=thread\"\n    TSAN_CCFLAGS=\"${TSAN_CCFLAGS} -mllvm -tsan-instrument-memory-accesses=0\"\n    TSAN_CCFLAGS=\"${TSAN_CCFLAGS} -mllvm -tsan-instrument-atomics=0\"\n    TSAN_CCFLAGS=\"${TSAN_CCFLAGS} -mllvm -tsan-instrument-func-entry-exit=1\"\n    CFLAGS=\"${CFLAGS} ${TSAN_FLAGS} ${TSAN_CCFLAGS}\"\n    CXXFLAGS=\"${CXXFLAGS} ${TSAN_FLAGS} ${TSAN_CCFLAGS}\"\n    LDFLAGS=\"${LDFLAGS} ${TSAN_FLAGS} -pie\"\n\n    AM_CONDITIONAL(ENABLE_TSAN, true)\n    AC_MSG_RESULT([yes])\nelse\n    AM_CONDITIONAL(ENABLE_TSAN, false)\n    AC_MSG_RESULT([no])\nfi\n\n# Memory mis-use detection\nAC_MSG_CHECKING([whether to enable ASan])\nAC_ARG_ENABLE(address-sanitizer, [AS_HELP_STRING([--enable-address-sanitizer=yes/no],\n                  [Build with GCC Address Sanitizer instrumentation])],\n                  [ZMQ_ASAN=\"$enableval\"])\n\nif test \"x${ZMQ_ASAN}\" = \"xyes\"; then\n    CFLAGS=\"${CFLAGS} -fsanitize=address -fsanitize=undefined -fsanitize=leak -fno-sanitize-recover=all\"\n    CXXFLAGS=\"${CXXFLAGS} -fsanitize=address -fsanitize=undefined -fsanitize=leak -fno-sanitize-recover=all\"\n\n    AM_CONDITIONAL(ENABLE_ASAN, true)\n    AC_MSG_RESULT([yes])\nelse\n    AM_CONDITIONAL(ENABLE_ASAN, false)\n    AC_MSG_RESULT([no])\nfi\n\n# By default compiling with -Werror except on OSX and Solaris when building\n# with libsodium.\nAC_ARG_ENABLE([Werror],\n    [AS_HELP_STRING([--disable-Werror], [disable Werror compiler flag [default=enabled]])],\n    [libzmq_werror=$enableval], [libzmq_werror=yes])\n\n# By default use DSO visibility\nlibzmq_dso_visibility=\"yes\"\n\n# Platform specific checks\nlibzmq_on_mingw=\"no\"\nlibzmq_on_cygwin=\"no\"\nlibzmq_on_android=\"no\"\nlibzmq_on_linux=\"no\"\nlibzmq_on_gnu=\"no\"\n\n# Set some default features required by ZeroMQ code\nCPPFLAGS=\"-D_REENTRANT -D_THREAD_SAFE $CPPFLAGS\"\nCXXFLAGS=\"-Wno-long-long $CXXFLAGS\"\n\n# Will be used to add flags to pkg-config useful when apps want to statically link\nPKGCFG_LIBS_PRIVATE=\"\"\nPKGCFG_NAMES_PRIVATE=\"\"\n\n# For host type checks\nAC_CANONICAL_HOST\n\n# OS-specific tests\ncase \"${host_os}\" in\n    *linux*)\n        # Define on Linux to enable all library features. Define if using a gnu compiler\n        if test \"x$GXX\" = \"xyes\"; then\n            CPPFLAGS=\"-D_GNU_SOURCE $CPPFLAGS\"\n        fi\n        AC_DEFINE(ZMQ_HAVE_LINUX, 1, [Have Linux OS])\n        libzmq_on_linux=\"yes\"\n\n        if test \"x$libzmq_tipc_support\" = \"xyes\"; then\n            AC_DEFINE(ZMQ_HAVE_TIPC, 1, [Have TIPC support])\n        fi\n\n        if test \"x$libzmq_vsock_support\" = \"xyes\"; then\n            AC_DEFINE(ZMQ_HAVE_VSOCK, 1, [Have vsock support])\n        fi\n        case \"${host_os}\" in\n            *android*)\n                AC_DEFINE(ZMQ_HAVE_ANDROID, 1, [Have Android OS])\n                libzmq_on_android=\"yes\"\n            ;;\n        esac\n        ;;\n    *solaris*)\n        # Define on Solaris to enable all library features\n        CPPFLAGS=\"-D_PTHREADS $CPPFLAGS\"\n        CXXFLAGS=\"-Wno-sign-compare $CXXFLAGS\"\n        AC_DEFINE(ZMQ_HAVE_SOLARIS, 1, [Have Solaris OS])\n        AC_CHECK_LIB(socket, socket)\n        AC_CHECK_LIB(nsl, gethostbyname)\n        AC_MSG_CHECKING([whether atomic operations can be used])\n        AC_COMPILE_IFELSE([AC_LANG_PROGRAM(\n            [[#include <atomic.h>]],\n            [[uint32_t value;\n              atomic_cas_32 (&value, 0, 0);\n              return 0;]])],\n            [solaris_has_atomic=yes],\n            [solaris_has_atomic=no])\n        AC_MSG_RESULT([$solaris_has_atomic])\n        # Solaris 8 does not have atomic operations exported to user space.\n        if test \"x$solaris_has_atomic\" = \"xno\"; then\n            AC_DEFINE(ZMQ_FORCE_MUTEXES, 1, [Force to use mutexes])\n        fi\n        ;;\n    *freebsd*)\n        # Define on FreeBSD to enable all library features\n        CPPFLAGS=\"-D__BSD_VISIBLE $CPPFLAGS\"\n        AC_DEFINE(ZMQ_HAVE_FREEBSD, 1, [Have FreeBSD OS])\n        ;;\n    *dragonfly*)\n        CPPFLAGS=\"-D__BSD_VISIBLE $CPPFLAGS\"\n        AC_DEFINE(ZMQ_HAVE_FREEBSD, 1, [Have DragonFly OS])\n        AC_DEFINE(ZMQ_HAVE_DRAGONFLY, 1, [Have DragonFly OS])\n        ;;\n    *darwin*)\n        # Define on Darwin to enable all library features\n        CPPFLAGS=\"-D_DARWIN_C_SOURCE $CPPFLAGS\"\n        libzmq_pedantic=\"no\"\n        AC_DEFINE(ZMQ_HAVE_OSX, 1, [Have DarwinOSX OS])\n        ;;\n    *haiku*)\n        AC_DEFINE(ZMQ_HAVE_HAIKU, 1, [Have Haiku OS])\n        AC_CHECK_LIB(network, socket)\n        ;;\n    *netbsd*)\n        # Define on NetBSD to enable all library features\n        CPPFLAGS=\"-D_NETBSD_SOURCE $CPPFLAGS\"\n        AC_DEFINE(ZMQ_HAVE_NETBSD, 1, [Have NetBSD OS])\n        # NetBSD 5.0 and newer provides atomic operations but we can\n        # only use these on systems where PR #42842 has been fixed so\n        # we must try and link a test program using C++.\n        libzmq_netbsd_has_atomic=no\n        AC_MSG_CHECKING([whether atomic operations can be used])\n        AC_LANG_PUSH([C++])\n        AC_LINK_IFELSE([AC_LANG_PROGRAM(\n            [[#include <atomic.h>]],\n            [[uint32_t value;\n              atomic_cas_32 (&value, 0, 0);\n              return 0;]])],\n            [libzmq_netbsd_has_atomic=yes],\n            [libzmq_netbsd_has_atomic=no])\n        AC_LANG_POP([C++])\n        AC_MSG_RESULT([$libzmq_netbsd_has_atomic])\n        if test \"x$libzmq_netbsd_has_atomic\" = \"xno\"; then\n            AC_DEFINE(ZMQ_FORCE_MUTEXES, 1, [Force to use mutexes])\n        fi\n        # NetBSD Current (to become 10) has changed the type of udata in it's\n        # kevent struct from intptr_t to void * to align with darwin and other\n        # BSDs, see upstream commit:\n        # https://github.com/NetBSD/src/commit/e5ead823eb916b56589d2c6c560dbcfe4a2d0afc\n        AC_MSG_CHECKING([whether kevent udata type is intptr_t])\n        AC_LANG_PUSH([C++])\n        AC_LINK_IFELSE([AC_LANG_PROGRAM(\n            [[#include <sys/types.h>\n              #include <sys/event.h>\n              #include <sys/time.h>]],\n            [[struct kevent ev;\n              intptr_t udata;\n              EV_SET(&ev, 0, 0, EV_ADD, 0, 0, udata);\n              return 0;]])],\n            [libzmq_netbsd_kevent_udata_intptr_t=yes],\n            [libzmq_netbsd_kevent_udata_intptr_t=no])\n        AC_LANG_POP([C++])\n        AC_MSG_RESULT([$libzmq_netbsd_kevent_udata_intptr_t])\n        if test \"x$libzmq_netbsd_kevent_udata_intptr_t\" = \"xyes\"; then\n            AC_DEFINE(ZMQ_NETBSD_KEVENT_UDATA_INTPTR_T, 1, [kevent udata type is intptr_t])\n        fi\n        ;;\n    *openbsd*|*bitrig*)\n        # Define on OpenBSD to enable all library features\n        CPPFLAGS=\"-D_BSD_SOURCE $CPPFLAGS\"\n        AC_DEFINE(ZMQ_HAVE_OPENBSD, 1, [Have OpenBSD OS])\n        ;;\n    *nto-qnx*)\n        libzmq_pedantic=\"no\"\n        AC_DEFINE(ZMQ_HAVE_QNXNTO, 1, [Have QNX Neutrino OS])\n        AC_CHECK_LIB(socket, socket)\n        ;;\n    *aix*|*os400*)\n        AC_DEFINE(ZMQ_HAVE_AIX, 1, [Have AIX OS])\n        ;;\n    *hpux*)\n        # Define on HP-UX to enable all library features\n        CPPFLAGS=\"-D_POSIX_C_SOURCE=200112L $CPPFLAGS\"\n        AC_DEFINE(ZMQ_HAVE_HPUX, 1, [Have HPUX OS])\n        LIBZMQ_CHECK_LANG_FLAG_PREPEND([-Ae])\n        AC_CHECK_FUNCS(gethrtime)\n        ;;\n    *mingw*|*msys*)\n        AC_DEFINE(ZMQ_HAVE_WINDOWS, 1, [Have Windows OS])\n        AC_DEFINE(ZMQ_HAVE_MINGW, 1, [Have MinGW])\n        AC_CHECK_HEADERS(windows.h)\n        AC_CHECK_LIB(ws2_32, main, ,\n            [AC_MSG_ERROR([cannot link with ws2_32.dll.])])\n        AC_CHECK_LIB(rpcrt4, main, ,\n            [AC_MSG_ERROR([cannot link with rpcrt4.dll.])])\n        AC_CHECK_LIB(iphlpapi, main, ,\n            [AC_MSG_ERROR([cannot link with iphlpapi.dll.])])\n        libzmq_on_mingw=\"yes\"\n        libzmq_dso_visibility=\"no\"\n\n        if test \"x$enable_static\" = \"xyes\"; then\n            CPPFLAGS=\"-DZMQ_STATIC $CPPFLAGS\"\n            PKGCFG_LIBS_PRIVATE=\"$PKGCFG_LIBS_PRIVATE -liphlpapi -lws2_32\"\n        fi\n\t# Set FD_SETSIZE to 16384\n\tCPPFLAGS=\" -DFD_SETSIZE=16384 $CPPFLAGS\"\n        ;;\n    *cygwin*)\n        # Define on Cygwin to enable all library features\n        CPPFLAGS=\"-D_GNU_SOURCE $CPPFLAGS\"\n        AC_DEFINE(ZMQ_HAVE_CYGWIN, 1, [Have Cygwin])\n        libzmq_on_cygwin=\"yes\"\n        libzmq_dso_visibility=\"no\"\n        if test \"x$enable_static\" = \"xyes\"; then\n            AC_MSG_ERROR([Building static libraries is not supported under Cygwin])\n        fi\n        ;;\n    gnu*)\n        # Define on GNU/Hurd to enable all library features. Define if using a gnu compiler\n        if test \"x$GXX\" = \"xyes\"; then\n            CPPFLAGS=\"-D_GNU_SOURCE $CPPFLAGS\"\n        fi\n        AC_DEFINE(ZMQ_HAVE_GNU, 1, [Have GNU/Hurd OS])\n        libzmq_on_gnu=\"yes\"\n\tAC_CHECK_LIB(rt, sem_init)\n        ;;\n    *)\n        AC_MSG_ERROR([unsupported system: ${host_os}.])\n        ;;\nesac\n\n# Sun Studio does not like anonymous structures in unions and does not have weak attribute\nif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler\" = \"xyes\"; then\n    CXXFLAGS=\"${CXXFLAGS} -features=extensions\"\n    CFLAGS=\"${CFLAGS} -features=extensions\"\n    CPPFLAGS=\"${CPPFLAGS} -DUNITY_WEAK_PRAGMA\"\nfi\n\n# Checks for libraries\nAC_CHECK_LIB([pthread], [pthread_create])\nif test \"x$ac_cv_lib_pthread_pthread_create\" = \"xyes\"; then\n    PKGCFG_LIBS_PRIVATE=\"$PKGCFG_LIBS_PRIVATE -lpthread\"\nfi\nAC_CHECK_LIB([rt], [clock_gettime])\nif test \"x$ac_cv_lib_rt_clock_gettime\" = \"xyes\"; then\n    PKGCFG_LIBS_PRIVATE=\"$PKGCFG_LIBS_PRIVATE -lrt\"\nfi\n\n#\n# Check if the compiler supports -fvisibility=hidden flag. MinGW uses __declspec\n#\nif test \"x$libzmq_dso_visibility\" = \"xyes\"; then\n    AC_LANG_PUSH([C++])\n    LIBZMQ_CHECK_LANG_VISIBILITY([LIBZMQ_EXTRA_CXXFLAGS=\"$libzmq_cv_[]_AC_LANG_ABBREV[]_visibility_flag ${LIBZMQ_EXTRA_CXXFLAGS}\"])\n    AC_LANG_POP([C++])\nfi\n\n# CPU-specific optimizations\ncase \"${host_cpu}\" in\n    *sparc64*)\n        AC_LANG_PUSH([C++])\n        LIBZMQ_CHECK_LANG_FLAG_PREPEND([-mcpu=v9])\n        AC_LANG_POP([C++])\n    ;;\n    *)\n    ;;\nesac\n\n# Check whether to build docs / install man pages\nLIBZMQ_CHECK_DOC_BUILD\n\n# Check polling system, set appropriate macro in src/platform.hpp\nLIBZMQ_CHECK_POLLER\n\n# Check for pselect to activate ppoll, set appropriate macro in src/platform.hpp\nLIBZMQ_CHECK_PPOLL\n\n# Check cacheline size, set appropriate macro in src/platform.hpp\nLIBZMQ_CHECK_CACHELINE\n\n# Check condition variable implementation, set appropriate macro in src/platform.hpp\nLIBZMQ_CHECK_CV_IMPL\n\n# Checks for header files.\nAC_HEADER_STDC\nAC_CHECK_HEADERS(\\\n    errno.h \\\n    time.h \\\n    unistd.h \\\n    limits.h \\\n    stddef.h \\\n    stdlib.h \\\n    string.h \\\n    arpa/inet.h \\\n    netinet/tcp.h \\\n    netinet/in.h \\\n    sys/socket.h \\\n    sys/time.h)\n\n# Check if we have ifaddrs.h header file.\nAC_CHECK_HEADERS(ifaddrs.h, [AC_DEFINE(ZMQ_HAVE_IFADDRS, 1, [Have ifaddrs.h header.])])\n\n# Check if we have sys/uio.h header file.\nAC_CHECK_HEADERS(sys/uio.h, [AC_DEFINE(ZMQ_HAVE_UIO, 1, [Have uio.h header.])])\n\n# Force not to use eventfd\nAC_ARG_ENABLE([eventfd],\n    [AS_HELP_STRING([--disable-eventfd], [disable eventfd [default=enabled]])],\n    [zmq_enable_eventfd=$enableval],\n    [zmq_enable_eventfd=yes])\n\nif test \"x$zmq_enable_eventfd\" = \"xyes\"; then\n    # Check if we have eventfd.h header file.\n    AC_CHECK_HEADERS(sys/eventfd.h, [\n        AC_DEFINE(ZMQ_HAVE_EVENTFD, 1, [Have eventfd extension])\n        LIBZMQ_CHECK_EVENTFD_CLOEXEC([\n            AC_DEFINE([ZMQ_HAVE_EVENTFD_CLOEXEC],\n               [1],\n               [Whether EFD_CLOEXEC is defined and functioning.])\n            ])\n    ])\nfi\n\n# Conditionally build performance measurement tools\nAC_ARG_ENABLE([perf],\n    [AS_HELP_STRING([--disable-perf], [don't build performance measurement tools [default=build]])],\n    [zmq_enable_perf=$enableval],\n    [zmq_enable_perf=yes])\n\nAM_CONDITIONAL(ENABLE_PERF, test \"x$zmq_enable_perf\" = \"xyes\")\n\n# Conditionally build curve key generation tool\nAC_ARG_ENABLE([curve-keygen],\n    [AS_HELP_STRING([--disable-curve-keygen], [don't build curve-keygen tool [default=build]])],\n    [zmq_enable_curve_keygen=$enableval],\n    [zmq_enable_curve_keygen=yes])\n\n# Use c++ in subsequent tests\nAC_LANG_PUSH(C++)\n\nAC_CHECK_DECLS([SO_PEERCRED],\n    [AC_DEFINE(ZMQ_HAVE_SO_PEERCRED, 1, [Have SO_PEERCRED socket option])],\n    [],\n    [#include <sys/socket.h>])\n\nAC_CHECK_DECLS([LOCAL_PEERCRED],\n    [AC_DEFINE(ZMQ_HAVE_LOCAL_PEERCRED, 1, [Have LOCAL_PEERCRED socket option])],\n    [],\n    [#include <sys/socket.h>])\n\nAM_CONDITIONAL(HAVE_IPC_PEERCRED, test \"x$ac_cv_have_decl_SO_PEERCRED\" = \"xyes\" || test \"x$ac_cv_have_decl_LOCAL_PEERCRED\" = \"xyes\")\n\nAC_HEADER_STDBOOL\nAC_C_CONST\nAC_C_INLINE\n\n# Checks for typedefs, structures, and compiler characteristics.\nif test \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_intel_compiler\" = \"xyes\"; then\n    dnl 279: controlling expression is constant\n    dnl Fixes build with ICC 12.x\n    LIBZMQ_CHECK_WITH_FLAG([-wd279], [AC_TYPE_SIZE_T])\n    LIBZMQ_CHECK_WITH_FLAG([-wd279], [AC_TYPE_SSIZE_T])\nelse\n    AC_TYPE_SIZE_T\n    AC_TYPE_SSIZE_T\nfi\n\nAC_HEADER_TIME\nAC_TYPE_UINT32_T\nAC_C_VOLATILE\n\n# build using libgssapi_krb5\nAC_ARG_WITH([libgssapi_krb5], [AS_HELP_STRING([--with-libgssapi_krb5],\n    [require libzmq build with libgssapi_krb5 [default=no]])],\n    [require_libgssapi_krb5_ext=$withval],\n    [require_libgssapi_krb5_ext=no])\n\n# conditionally require libgssapi_krb5\nif test \"x$require_libgssapi_krb5_ext\" != \"xno\"; then\n    PKG_CHECK_MODULES([gssapi_krb5], [krb5-gssapi], [\n        have_gssapi_library=\"yes\"\n        PKGCFG_NAMES_PRIVATE=\"$PKGCFG_NAMES_PRIVATE krb5-gssapi\"\n    ], [\n        AC_CHECK_HEADERS(gssapi/gssapi_generic.h)\n        AC_SEARCH_LIBS([gss_init_sec_context], [gssapi_krb5 gssapi],\n            have_gssapi_library=\"yes\",\n            AC_MSG_ERROR(libgssapi_krb5 is needed for GSSAPI security))\n        PKGCFG_LIBS_PRIVATE=\"$PKGCFG_LIBS_PRIVATE -lgssapi_krb5\"\n    ])\nfi\nif test \"x$have_gssapi_library\" = \"xyes\"; then\n    AC_DEFINE(HAVE_LIBGSSAPI_KRB5, [1], [Enabled GSSAPI security])\nfi\nAM_CONDITIONAL(BUILD_GSSAPI, test \"x$have_gssapi_library\" = \"xyes\")\n\n# Select curve encryption library, defaults to disabled\n# To use libsodium instead, use --with-libsodium (must be installed)\n# To disable curve, use --disable-curve\n\nAC_ARG_WITH([libsodium],\n    [AS_HELP_STRING([--with-libsodium], [use libsodium [default=no]])])\n\nAS_IF([test \"x$with_libsodium\" = \"xyes\"], [\n    PKG_CHECK_MODULES([sodium], [libsodium], [libsodium_found=yes], [\n        AC_MSG_ERROR(libsodium is not installed. Install it, then run configure again)\n    ])\n])\n\nAC_ARG_ENABLE([curve],\n    [AS_HELP_STRING([--disable-curve], [disable CURVE security [default=no]])])\n\nAC_ARG_ENABLE(\n    [libsodium_randombytes_close],\n    [AS_HELP_STRING(\n        [--disable-libsodium_randombytes_close],\n        [Do not call libsodium randombytes_close() when terminating contexts.\n        If disabled, may leave one FD open on /dev/urandom\n        until randombytes_close() is called explicitly,\n        but fixes a crash when multiple contexts are used with CURVE.\n        Has no effect when getrandom() is available. [default=enabled]]\n    )],\n    [],\n    [enable_libsodium_randombytes_close=yes]\n)\n\nif test \"x$enable_curve\" = \"xno\"; then\n    curve_library=\"\"\n    AC_MSG_NOTICE([CURVE security is disabled])\n\nelif test \"x$with_libsodium\" = \"xyes\"; then\n    AC_MSG_NOTICE([Using libsodium for CURVE security])\n    AC_DEFINE(ZMQ_HAVE_CURVE, [1], [Using curve encryption])\n    AC_DEFINE(ZMQ_USE_LIBSODIUM, [1], [Using libsodium for curve encryption])\n    if test \"x$enable_libsodium_randombytes_close\" = \"xyes\"; then\n        AC_DEFINE(ZMQ_LIBSODIUM_RANDOMBYTES_CLOSE, [1], [Automatically close libsodium randombytes. Not threadsafe without getrandom()])\n    else\n        AC_MSG_NOTICE([Disabling libsodium randombytes_close(). randombytes_close() may need to be called in application code.])\n    fi\n\n    curve_library=\"libsodium\"\n    enable_curve=\"yes\"\n\n    case \"${host_os}\" in\n        *solaris*)\n            dnl On Solaris, libsodium depends on libssp\n            LDFLAGS=\"-lssp $LDFLAGS\"\n            libzmq_pedantic=\"no\"\n            libzmq_werror=\"no\"\n        ;;\n        *darwin*)\n            dnl On Darwin, building with libsodium causes\n            dnl macro redefinition warnings\n            libzmq_werror=\"no\"\n        ;;\n    esac\n\n    PKGCFG_NAMES_PRIVATE=\"$PKGCFG_NAMES_PRIVATE libsodium\"\nfi\n\nAM_CONDITIONAL(ENABLE_CURVE_KEYGEN, test \"x$enable_curve\" = \"xyes\" -a \"x$zmq_enable_curve_keygen\" = \"xyes\")\n\nAM_CONDITIONAL(USE_LIBSODIUM, test \"$curve_library\" = \"libsodium\")\nAM_CONDITIONAL(HAVE_CURVE, test \"x$curve_library\" != \"x\")\nAM_CONDITIONAL(USE_WEPOLL, test \"$poller\" = \"wepoll\")\n\n# Check requiring packages for WebSocket\nws_crypto_library=\"\"\n\nAC_ARG_ENABLE([ws],\n    [AS_HELP_STRING([--enable-ws], [Enable WebSocket transport [default=state of DRAFT]])],\n    [enable_ws=$enableval],\n    [enable_ws=$enable_drafts])\n\nAC_ARG_WITH([nss],\n    [AS_HELP_STRING([--with-nss], [use nss instead of built-in sha1 [default=no]])])\n\nAC_ARG_WITH([tls],\n    [AS_HELP_STRING([--with-tls], [Enable TLS (WSS transport) [default=no]])])\n\nif test \"x$enable_ws\" != \"xno\"; then\n    if test \"x$with_tls\" = \"xyes\"; then\n        PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.1.4], [\n            PKGCFG_NAMES_PRIVATE=\"$PKGCFG_NAMES_PRIVATE gnutls >= 3.1.4\"\n            ws_crypto_library=\"gnutls\"\n            AC_DEFINE(ZMQ_USE_GNUTLS, [1], [Use GNUTLS for TLS])\n            AC_DEFINE(ZMQ_HAVE_WS, [1], [Using websocket])\n            AC_DEFINE(ZMQ_HAVE_WSS, [1], [WSS enabled])\n            AC_MSG_NOTICE(Using gnutls)\n        ],[\n          AC_MSG_ERROR([GnuTLS is not installed. Install it, then run configure again])\n        ])\n    elif test \"x$with_nss\" = \"xyes\"; then\n        PKG_CHECK_MODULES([NSS3], [nss], [\n            PKGCFG_NAMES_PRIVATE=\"$PKGCFG_NAMES_PRIVATE nss\"\n            AC_DEFINE(ZMQ_USE_NSS, [1], [Using NSS])\n            AC_DEFINE(ZMQ_HAVE_WS, [1], [Using websocket])\n            ws_crypto_library=\"nss\"\n            AC_MSG_NOTICE(Using NSS)\n        ], [\n            AC_MSG_ERROR([nss is not installed. Install it, then run configure again])\n        ])\n    else\n        AC_DEFINE(ZMQ_HAVE_WS, [1], [Using websocket])\n        AC_DEFINE(ZMQ_USE_BUILTIN_SHA1, [1], [Using built-in sha1])\n        AC_MSG_NOTICE(Using built-in SHA1)\n        ws_crypto_library=\"builtin\"\n    fi\nfi\n\nAM_CONDITIONAL(HAVE_WS, test \"x$ws_crypto_library\" != \"x\")\nAM_CONDITIONAL(USE_NSS, test \"x$ws_crypto_library\" = \"xnss\")\nAM_CONDITIONAL(USE_BUILTIN_SHA1, test \"x$ws_crypto_library\" = \"xbuiltin\")\nAM_CONDITIONAL(USE_GNUTLS, test \"x$ws_crypto_library\" = \"xgnutls\")\nAM_CONDITIONAL(HAVE_WSS, test \"x$ws_crypto_library\" = \"xgnutls\")\n\n# build using pgm\nhave_pgm_library=\"no\"\n\nAC_ARG_WITH([pgm], [AS_HELP_STRING([--with-pgm],\n    [build libzmq with PGM extension. Requires pkg-config [default=no]])],\n    [with_pgm_ext=$withval],\n    [with_pgm_ext=no])\n\n# conditionally require pgm package\nif test \"x$with_pgm_ext\" != \"xno\"; then\n    PKG_CHECK_MODULES([pgm], [openpgm-5.3 >= 5.3], [\n        have_pgm_library=\"yes\"\n        PKGCFG_NAMES_PRIVATE=\"$PKGCFG_NAMES_PRIVATE openpgm-5.3 >= 5.3\"\n    ], [\n        PKG_CHECK_MODULES([pgm], [openpgm-5.2 >= 5.2], [\n            have_pgm_library=\"yes\"\n            PKGCFG_NAMES_PRIVATE=\"$PKGCFG_NAMES_PRIVATE openpgm-5.2 >= 5.2\"\n        ], [\n            PKG_CHECK_MODULES([pgm], [openpgm-5.1 >= 5.1], [\n                have_pgm_library=\"yes\"\n                PKGCFG_NAMES_PRIVATE=\"$PKGCFG_NAMES_PRIVATE openpgm-5.1 >= 5.1\"\n            ])\n        ])\n    ])\nfi\n\nif test \"x$have_pgm_library\" = \"xyes\"; then\n    AC_DEFINE(ZMQ_HAVE_OPENPGM, [1], [Have OpenPGM extension])\n    # When using CXX98 mode 'restrict will not be defined, so redefine it, as it\n    # is used in the PGM headers\n    if test \"x$enable_force_CXX98_compat\" = \"xyes\"; then\n        CPPFLAGS=\"-Drestrict=__restrict__ $CPPFLAGS\"\n    fi\nfi\n\nAM_CONDITIONAL(HAVE_PGM, test \"x$have_pgm_library\" = \"xyes\")\n\n\n# This uses \"--with-norm\" to point to the \"norm\" directory\n# for \"norm/include\" and \"norm/lib\"\n#(if \"--with-norm=yes\" is given, then assume installed on system)\nAC_ARG_WITH([norm],\n    [AS_HELP_STRING([--with-norm],\n        [build libzmq with NORM protocol extension, optionally specifying norm path [default=no]])],\n    [with_norm_ext=$withval],\n    [with_norm_ext=no])\n\nAC_MSG_CHECKING(\"with_norm_ext = ${with_norm_ext}\")\n\nif test \"x$with_norm_ext\" != \"xno\"; then\n    PKG_CHECK_MODULES([norm], [norm], [\n        have_norm_library=\"yes\"\n        PKGCFG_NAMES_PRIVATE=\"$PKGCFG_NAMES_PRIVATE norm\"\n    ], [\n        AC_MSG_RESULT([yes])\n\n        norm_LIBS=\"\"\n        norm_CFLAGS=\"\"\n        if test \"x$with_norm_ext\" != \"xyes\"; then\n            norm_path=\"${with_norm_ext}\"\n            norm_CFLAGS=\"${norm_CFLAGS} -I${norm_path}/include\"\n            norm_LIBS=\"${norm_LIBS} -L${norm_path}/lib\"\n        fi\n        norm_LIBS=\"${norm_LIBS} -lnorm\"\n        have_norm_library=\"yes\"\n        PKGCFG_LIBS_PRIVATE=\"$PKGCFG_LIBS_PRIVATE $norm_LIBS\"\n        AC_SUBST(norm_LIBS)\n        AC_SUBST(norm_CFLAGS)\n    ])\nelse\n    AC_MSG_RESULT([no])\nfi\nif test \"x$have_norm_library\" = \"xyes\"; then\n    AC_DEFINE(ZMQ_HAVE_NORM, [1], [Have NORM protocol extension])\nfi\nAM_CONDITIONAL(HAVE_NORM, test \"x$have_norm_library\" = \"xyes\")\n\n# build using vmci\nhave_vmci_library=\"no\"\n\nAC_ARG_WITH([vmci], [AS_HELP_STRING([--with-vmci],\n    [build libzmq with VMCI transport [default=no]])],\n    [have_vmci_ext=$withval],\n    [have_vmci_ext=no])\n\nif test \"x$have_vmci_ext\" != \"xno\"; then\n    AC_DEFINE(ZMQ_HAVE_VMCI, 1, [Have VMCI transport])\n\n    if test \"x$have_vmci_ext\" != \"xyes\"; then\n        vmci_path=\"${have_vmci_ext}\"\n        LIBZMQ_VMCI_CXXFLAGS=\"-I${vmci_path}\"\n        LIBZMQ_VMCI_LDFLAGS=\"-I${vmci_path}\"\n        LIBZMQ_EXTRA_CXXFLAGS=\"${LIBZMQ_VMCI_CXXFLAGS} ${LIBZMQ_EXTRA_CXXFLAGS}\"\n        LIBZMQ_EXTRA_LDFLAGS=\"${LIBZMQ_VMCI_LDFLAGS} ${LIBZMQ_EXTRA_LDFLAGS}\"\n    fi\nfi\n\nAM_CONDITIONAL(HAVE_VMCI, test \"x$have_vmci_ext\" != \"xno\")\n\n\n# Set -Wall, -Werror and -pedantic\nAC_LANG_PUSH([C++])\n\n# Check how to enable -Wall\nLIBZMQ_LANG_WALL([CXXFLAGS=\"$libzmq_cv_[]_AC_LANG_ABBREV[]_wall_flag $CXXFLAGS\"])\n\nif test \"x$libzmq_werror\" = \"xyes\" -a \"x$libzmq_cv_[]_AC_LANG_ABBREV[]_sun_studio_compiler\" != \"xyes\"; then\n    LIBZMQ_LANG_WERROR([CXXFLAGS=\"$libzmq_cv_[]_AC_LANG_ABBREV[]_werror_flag $CXXFLAGS\"])\nfi\n\nif test \"x$libzmq_pedantic\" = \"xyes\"; then\n    LIBZMQ_LANG_STRICT([CXXFLAGS=\"$libzmq_cv_[]_AC_LANG_ABBREV[]_strict_flag $CXXFLAGS\"])\nfi\nAC_LANG_POP([C++])\n\nAM_CONDITIONAL(BUILD_VSOCK, test \"x$libzmq_vsock_support\" = \"xyes\")\nAM_CONDITIONAL(BUILD_TIPC, test \"x$libzmq_tipc_support\" = \"xyes\")\nAM_CONDITIONAL(ON_MINGW, test \"x$libzmq_on_mingw\" = \"xyes\")\nAM_CONDITIONAL(ON_CYGWIN, test \"x$libzmq_on_cygwin\" = \"xyes\")\nAM_CONDITIONAL(ON_ANDROID, test \"x$libzmq_on_android\" = \"xyes\")\nAM_CONDITIONAL(ON_LINUX, test \"x$libzmq_on_linux\" = \"xyes\")\nAM_CONDITIONAL(ON_GNU, test \"x$libzmq_on_gnu\" = \"xyes\")\n\n# Check for __atomic_Xxx compiler intrinsics\nAC_LANG_PUSH([C++])\nAX_CHECK_COMPILE_FLAG([-Watomic-alignment],\n    [CXXFLAGS=\"${CXXFLAGS} -Wno-atomic-alignment\"],\n    [],\n    [-Werror])\nLIBZMQ_CHECK_ATOMIC_INTRINSICS([\n    AC_DEFINE([ZMQ_HAVE_ATOMIC_INTRINSICS],\n              [1],\n              [Whether compiler has __atomic_Xxx intrinsics.])\n    ])\nAC_LANG_POP([C++])\n\n# Checks for library functions.\nAC_TYPE_SIGNAL\nAC_CHECK_FUNCS(perror gettimeofday clock_gettime memset socket getifaddrs freeifaddrs mkdtemp accept4)\nAC_CHECK_HEADERS([alloca.h])\n\n# AC_CHECK_FUNCS(fork) fails on gcc 7\nAC_MSG_CHECKING([whether fork is available])\nAC_COMPILE_IFELSE(\n\t[AC_LANG_PROGRAM(\n\t\t[[#include <unistd.h>]],\n\t\t[[return fork();]])\n\t],[\n\t\tAC_MSG_RESULT([yes])\n\t\tAC_DEFINE(HAVE_FORK, [1], [fork is available])\n\t\tAM_CONDITIONAL(HAVE_FORK, true)\n\t],[\n\t\tAC_MSG_RESULT([no])\n\t\tAM_CONDITIONAL(HAVE_FORK, false)\n])\n\n# string.h doesn't seem to be included by default in Fedora 30\nAC_MSG_CHECKING([whether strnlen is available])\nAC_COMPILE_IFELSE(\n\t[AC_LANG_PROGRAM(\n\t\t[[#include <string.h>]],\n\t\t[[size_t bar = strnlen (\"foo\", 1); (void)bar; return 0;]])\n\t],[\n\t\tAC_MSG_RESULT([yes])\n\t\tAC_DEFINE(HAVE_STRNLEN, [1],\n\t\t    [strnlen is available])\n\t],[\n\t\tAC_MSG_RESULT([no])\n])\n\nAC_MSG_CHECKING([whether if_nametoindex is available])\nAC_COMPILE_IFELSE(\n    [AC_LANG_PROGRAM([[\n        #ifdef _WIN32\n        #include <iphlpapi.h>\n        #else\n        #include <sys/types.h>\n        #include <sys/socket.h>\n        #include <net/if.h>\n        #endif]], [[\n        if_nametoindex(\"\");\n    ]])],[\n        AC_MSG_RESULT([yes])\n        AC_DEFINE(HAVE_IF_NAMETOINDEX, [1],\n        [if_nametoindex is available])\n    ],[\n        AC_MSG_RESULT([no])\n])\n\nAC_ARG_ENABLE([libbsd],\n    [AS_HELP_STRING([--enable-libbsd],\n        [enable libbsd [default=auto]])],\n    [enable_libbsd=$enableval],\n    [enable_libbsd=\"auto\"])\n\nif test \"x$enable_libbsd\" != \"xno\"; then\n    PKG_CHECK_MODULES(LIBBSD, [libbsd],\n        [\n            AC_DEFINE(ZMQ_HAVE_LIBBSD, 1, [The libbsd library is to be used])\n            AC_SUBST([LIBBSD_CFLAGS])\n            AC_SUBST([LIBBSD_LIBS])\n            PKGCFG_NAMES_PRIVATE=\"$PKGCFG_NAMES_PRIVATE libbsd\"\n            found_libbsd=\"yes\"\n        ],\n        [\n            found_libbsd=\"no\"\n            if test \"x$enable_libbsd\" = \"xyes\"; then\n                AC_MSG_ERROR([Cannot find libbsd])\n            else\n                AC_MSG_WARN([Cannot find libbsd])\n            fi\n        ])\nfi\nAC_MSG_CHECKING([whether strlcpy is available])\nAC_COMPILE_IFELSE(\n    [AC_LANG_PROGRAM(\n        [[#include <string.h>]],\n        [[char buf [100]; size_t bar = strlcpy (buf, \"foo\", 100); (void)bar; return 0;]])\n    ],[\n        AC_MSG_RESULT([yes])\n        AC_DEFINE(ZMQ_HAVE_STRLCPY, [1],\n            [strlcpy is available])\n    ],[\n        AC_MSG_RESULT([no])\n])\n\n# pthread_setname is non-posix, and there are at least 4 different implementations\nAC_MSG_CHECKING([whether signature of pthread_setname_np() has 1 argument])\nAC_COMPILE_IFELSE(\n\t[AC_LANG_PROGRAM(\n\t\t[[#include <pthread.h>]],\n\t\t[[pthread_setname_np (\"foo\"); return 0;]])\n\t],[\n\t\tAC_MSG_RESULT([yes])\n\t\tAC_DEFINE(ZMQ_HAVE_PTHREAD_SETNAME_1, [1],\n\t\t    [Whether pthread_setname_np() has 1 argument])\n\t],[\n\t\tAC_MSG_RESULT([no])\n])\nAC_MSG_CHECKING([whether signature of pthread_setname_np() has 2 arguments])\nAC_COMPILE_IFELSE(\n\t[AC_LANG_PROGRAM(\n\t\t[[#include <pthread.h>]],\n\t\t[[pthread_setname_np (pthread_self (), \"foo\"); return 0;]])\n\t],[\n\t\tAC_MSG_RESULT([yes])\n\t\tAC_DEFINE(ZMQ_HAVE_PTHREAD_SETNAME_2, [1],\n\t\t    [Whether pthread_setname_np() has 2 arguments])\n\t],[\n\t\tAC_MSG_RESULT([no])\n])\nAC_MSG_CHECKING([whether signature of pthread_setname_np() has 3 arguments])\nAC_COMPILE_IFELSE(\n\t[AC_LANG_PROGRAM(\n\t\t[[#include <pthread.h>]],\n\t\t[[pthread_setname_np (pthread_self(), \"foo\", (void *)0); return 0;]])\n\t],[\n\t\tAC_MSG_RESULT([yes])\n\t\tAC_DEFINE(ZMQ_HAVE_PTHREAD_SETNAME_3, [1],\n\t\t    [Whether pthread_setname_np() has 3 arguments])\n\t],[\n\t\tAC_MSG_RESULT([no])\n])\nAC_MSG_CHECKING([whether pthread_set_name_np() exists])\nAC_COMPILE_IFELSE(\n\t[AC_LANG_PROGRAM(\n\t\t[[#include <pthread.h>]],\n\t\t[[pthread_set_name_np (pthread_self(), \"foo\"); return 0;]])\n\t],[\n\t\tAC_MSG_RESULT([yes])\n\t\tAC_DEFINE(ZMQ_HAVE_PTHREAD_SET_NAME, [1],\n\t\t    [Whether pthread_set_name_np() exists])\n\t],[\n\t\tAC_MSG_RESULT([no])\n])\n\n\n# pthread_setaffinity_np is non-posix:\nAC_MSG_CHECKING([whether pthread_setaffinity_np() exists])\nAC_COMPILE_IFELSE(\n\t[AC_LANG_PROGRAM(\n\t\t[[#include <pthread.h>]],\n\t\t[[cpu_set_t test; pthread_setaffinity_np (pthread_self(), sizeof(cpu_set_t), &test); return 0;]])\n\t],[\n\t\tAC_MSG_RESULT([yes])\n\t\tAC_DEFINE(ZMQ_HAVE_PTHREAD_SET_AFFINITY, [1],\n\t\t    [Whether pthread_setaffinity_np() exists])\n\t],[\n\t\tAC_MSG_RESULT([no])\n])\n\n\nLIBZMQ_CHECK_SOCK_CLOEXEC([\n    AC_DEFINE([ZMQ_HAVE_SOCK_CLOEXEC],\n        [1],\n        [Whether SOCK_CLOEXEC is defined and functioning.])\n    ])\n\nLIBZMQ_CHECK_O_CLOEXEC([\n    AC_DEFINE([ZMQ_HAVE_O_CLOEXEC],\n        [1],\n        [Whether O_CLOEXEC is defined and functioning.])\n    ])\n\nLIBZMQ_CHECK_SO_BINDTODEVICE([\n    AC_DEFINE([ZMQ_HAVE_SO_BINDTODEVICE],\n        [1],\n        [Whether SO_BINDTODEVICE is supported.])\n    ])\n\n# TCP keep-alives Checks.\nLIBZMQ_CHECK_SO_KEEPALIVE([\n    AC_DEFINE([ZMQ_HAVE_SO_KEEPALIVE],\n        [1],\n        [Whether SO_KEEPALIVE is supported.])\n    ])\n\nLIBZMQ_CHECK_TCP_KEEPCNT([\n    AC_DEFINE([ZMQ_HAVE_TCP_KEEPCNT],\n        [1],\n        [Whether TCP_KEEPCNT is supported.])\n    ])\n\nLIBZMQ_CHECK_TCP_KEEPIDLE([\n    AC_DEFINE([ZMQ_HAVE_TCP_KEEPIDLE],\n        [1],\n        [Whether TCP_KEEPIDLE is supported.])\n    ])\n\nLIBZMQ_CHECK_TCP_KEEPINTVL([\n    AC_DEFINE([ZMQ_HAVE_TCP_KEEPINTVL],\n        [1],\n        [Whether TCP_KEEPINTVL is supported.])\n    ])\n\nLIBZMQ_CHECK_TCP_KEEPALIVE([\n    AC_DEFINE([ZMQ_HAVE_TCP_KEEPALIVE],\n        [1],\n        [Whether TCP_KEEPALIVE is supported.])\n    ])\n\nLIBZMQ_CHECK_SO_PRIORITY([\n    AC_DEFINE([ZMQ_HAVE_SO_PRIORITY],\n        [1],\n        [Whether SO_PRIORITY is supported.])\n    ])\n\nLIBZMQ_CHECK_GETRANDOM([\n    AC_DEFINE([ZMQ_HAVE_GETRANDOM],\n        [1],\n        [Whether getrandom is supported.])\n    ])\n\nif test \"x$cross_compiling\" = \"xyes\"; then\n    #   Enable draft by default when cross-compiling\n    defaultval=yes\nelse\n    # enable draft API by default if we're in a git repository\n    # else disable it by default; then allow --enable-drafts=yes/no override\n    AC_CHECK_FILE($srcdir/.git, [defaultval=yes], [defaultval=no])\nfi\n\nAC_ARG_ENABLE([drafts],\n    AS_HELP_STRING([--enable-drafts],\n        [Build and install draft classes and methods [default=yes]]),\n    [enable_drafts=$enableval],\n    [enable_drafts=$defaultval])\n\nAM_CONDITIONAL([ENABLE_DRAFTS], [test x$enable_drafts != xno])\n\nif test \"x$enable_drafts\" = \"xyes\"; then\n    AC_MSG_NOTICE([Building stable and legacy API + draft API])\n    AC_DEFINE(ZMQ_BUILD_DRAFT_API, 1, [Provide draft classes and methods])\n    AC_SUBST(pkg_config_defines, \"-DZMQ_BUILD_DRAFT_API=1\")\nelse\n    AC_MSG_NOTICE([Building stable and legacy API (no draft API)])\n    AC_SUBST(pkg_config_defines, \"\")\nfi\n\nAC_ARG_ENABLE([libunwind],\n    [AS_HELP_STRING([--enable-libunwind],\n        [enable libunwind [default=auto]])],\n    [enable_libunwind=$enableval],\n    [enable_libunwind=\"auto\"])\n\nif test \"x$enable_libunwind\" != \"xno\"; then\n    PKG_CHECK_MODULES(LIBUNWIND, [libunwind],\n        [\n            AC_DEFINE(HAVE_LIBUNWIND, 1, [The libunwind library is to be used])\n            AC_SUBST([LIBUNWIND_CFLAGS])\n            AC_SUBST([LIBUNWIND_LIBS])\n            AC_CHECK_LIB([dl], [dladdr], [\n                PKGCFG_LIBS_PRIVATE=\"$PKGCFG_LIBS_PRIVATE -ldl\"\n                LIBS=\"-ldl $LIBS\"\n            ], [\n                AC_CHECK_LIB([dld], [dladdr], [\n                    PKGCFG_LIBS_PRIVATE=\"$PKGCFG_LIBS_PRIVATE -ldld\"\n                    LIBS=\"-ldld $LIBS\"\n                ])\n            ])\n            PKGCFG_NAMES_PRIVATE=\"$PKGCFG_NAMES_PRIVATE libunwind\"\n        ],\n        [\n            if test \"x$enable_libunwind\" = \"xyes\"; then\n                AC_MSG_ERROR([Cannot find libunwind])\n            else\n                AC_MSG_WARN([Cannot find libunwind])\n            fi\n        ])\nfi\n\nAC_ARG_ENABLE([radix-tree],\n    AS_HELP_STRING([--enable-radix-tree],\n        [Use radix tree implementation to manage subscriptions [default=DRAFT]]),\n    [radix_tree=$enableval],\n    [radix_tree=$enable_drafts])\n\nAM_CONDITIONAL([ENABLE_RADIX_TREE], [test x$radix_tree != xno])\n\nif test \"x$radix_tree\" = \"xyes\"; then\n    AC_MSG_NOTICE([Using radix tree implementation to manage subscriptions])\n    AC_DEFINE(ZMQ_USE_RADIX_TREE, 1, [Use radix tree implementation to manage subscriptions])\nelse\n    AC_MSG_NOTICE([Using mtree implementation to manage subscriptions])\nfi\n\n# See if clang-format is in PATH; the result unblocks the relevant recipes\nWITH_CLANG_FORMAT=\"\"\nAS_IF([test x\"$CLANG_FORMAT\" = x],\n    [AC_PATH_PROG([CLANG_FORMAT], [clang-format], [])],\n    [AC_CHECK_PROG([WITH_CLANG_FORMAT], [$CLANG_FORMAT], [true], [fail])])\nAS_IF([test x\"$CLANG_FORMAT\" != x && test x\"$WITH_CLANG_FORMAT\" = x],\n    [AS_IF([test -x \"$CLANG_FORMAT\"],\n        [WITH_CLANG_FORMAT=true],\n        [AC_CHECK_PROG([WITH_CLANG_FORMAT], [$CLANG_FORMAT], [true], [false])])])\nAS_IF([test \"$WITH_CLANG_FORMAT\" = fail],\n    [AC_MSG_ERROR([Caller explicitly referenced CLANG_FORMAT=$CLANG_FORMAT which was not found])])\nAM_CONDITIONAL([WITH_CLANG_FORMAT], [$WITH_CLANG_FORMAT])\n\n# unittests will not build without the static libzmq.a\nAM_CONDITIONAL(ENABLE_STATIC, test \"x$enable_static\" = \"xyes\")\n\n# build using a fuzzing engine - fuzzers will be built separately and statically\nAC_ARG_WITH([fuzzing-engine], [AS_HELP_STRING([--with-fuzzing-engine],\n    [build libzmq with an exernal fuzzing engine [default=no]])],\n    [have_fuzzing_engine_ext=$withval],\n    [have_fuzzing_engine_ext=no])\nAC_ARG_WITH([fuzzing-installdir],\n    AS_HELP_STRING([--with-fuzzing-installdir=PATH],\n        [Path where to install fuzzer binaries]),\n    [fuzzing_installdir=\"$withval\"])\n\nif test \"x$have_fuzzing_engine_ext\" != \"xno\" && test \"x$fuzzing_installdir\" != \"x\" && test \"x$enable_static\" = \"xyes\"; then\n    FUZZING_ENGINE_LIB=\"${have_fuzzing_engine_ext}\"\n    FUZZING_INSTALLDIR=\"${fuzzing_installdir}\"\n    AC_SUBST(FUZZING_ENGINE_LIB)\n    AC_SUBST(FUZZING_INSTALLDIR)\n    AC_DEFINE(ZMQ_USE_FUZZING_ENGINE, 1, [fuzz tests will be built with fuzzing engine])\nfi\nAM_CONDITIONAL(FUZZING_ENGINE_LIB, test \"x$FUZZING_ENGINE_LIB\" != \"x\")\n\n# clang 6 has a warning that does not make sense on multi-platform code\nAC_LANG_PUSH([C])\nAX_CHECK_COMPILE_FLAG([-Wtautological-constant-compare],\n    [CFLAGS=\"${CFLAGS} -Wno-tautological-constant-compare\"],\n    [],\n    [-Werror])\nAC_LANG_POP([C])\nAX_CHECK_COMPILE_FLAG([-Wtautological-constant-compare],\n    [CXXFLAGS=\"${CXXFLAGS} -Wno-tautological-constant-compare\"],\n    [],\n    [-Werror])\n\n# LTO is enabled by default on SUSE Tumbleweed and RPM lint generates an error if\n# the flag is not used to compile archives:\n# E: lto-no-text-in-archive\nAC_LANG_PUSH([C])\nAX_CHECK_COMPILE_FLAG([-ffat-lto-objects],\n    [CFLAGS=\"${CFLAGS} -ffat-lto-objects\"],\n    [],\n    [-Werror])\nAC_LANG_POP([C])\nAX_CHECK_COMPILE_FLAG([-ffat-lto-objects],\n    [CXXFLAGS=\"${CXXFLAGS} -ffat-lto-objects\"],\n    [],\n    [-Werror])\n\n# Subst LIBZMQ_EXTRA_CFLAGS & CXXFLAGS & LDFLAGS\nAC_SUBST(LIBZMQ_EXTRA_CFLAGS)\nAC_SUBST(LIBZMQ_EXTRA_CXXFLAGS)\nAC_SUBST(LIBZMQ_EXTRA_LDFLAGS)\n\nAC_SUBST(LIBZMQ_VMCI_CXXFLAGS)\nAC_SUBST(LIBZMQ_VMCI_LDFLAGS)\n\nAC_SUBST(pkg_config_libs_private, $PKGCFG_LIBS_PRIVATE)\nAC_SUBST(pkg_config_names_private, $PKGCFG_NAMES_PRIVATE)\n\n# set pkgconfigdir, allow override\nAC_ARG_WITH([pkgconfigdir],\n    AS_HELP_STRING([--with-pkgconfigdir=PATH],\n        [Path to the pkgconfig directory [[LIBDIR/pkgconfig]]]),\n    [pkgconfigdir=\"$withval\"],\n    [pkgconfigdir='${libdir}/pkgconfig'])\nAC_SUBST([pkgconfigdir])\n\nAC_ARG_ENABLE([no-export],\n    [AS_HELP_STRING([--enable-no-export],\n        [Build libzmq with empty ZMQ_EXPORT macro, bypassing platform-based automated detection [default=no]])],\n    [CPPFLAGS=\"-DZMQ_NO_EXPORT $CPPFLAGS\"])\n\nAC_CONFIG_FILES([ \\\n    Makefile \\\n    src/libzmq.pc \\\n    doc/Makefile \\\n    builds/Makefile \\\n    builds/deprecated-msvc/Makefile])\n\nAC_OUTPUT\n"
  },
  {
    "path": "doc/Makefile.am",
    "content": "#\n# documentation\n#\nMAN3 = \\\n    zmq_bind.3 zmq_unbind.3 zmq_connect.3 zmq_connect_peer.3 zmq_disconnect_peer.3 zmq_disconnect.3 zmq_close.3 \\\n    zmq_ctx_new.3 zmq_ctx_term.3 zmq_ctx_get.3 zmq_ctx_set.3 zmq_ctx_shutdown.3 \\\n    zmq_msg_init.3 zmq_msg_init_data.3 zmq_msg_init_size.3 zmq_msg_init_buffer.3 \\\n    zmq_msg_move.3 zmq_msg_copy.3 zmq_msg_size.3 zmq_msg_data.3 zmq_msg_close.3 \\\n    zmq_msg_send.3 zmq_msg_recv.3 \\\n    zmq_msg_routing_id.3 zmq_msg_set_routing_id.3 \\\n    zmq_send.3 zmq_recv.3 zmq_send_const.3 \\\n    zmq_msg_get.3 zmq_msg_set.3 zmq_msg_more.3 zmq_msg_gets.3 \\\n    zmq_getsockopt.3 zmq_setsockopt.3 \\\n    zmq_socket.3 zmq_socket_monitor.3 zmq_poll.3 zmq_ppoll.3 \\\n    zmq_socket_monitor_versioned.3 \\\n    zmq_errno.3 zmq_strerror.3 zmq_version.3 \\\n    zmq_sendmsg.3 zmq_recvmsg.3 \\\n    zmq_proxy.3 zmq_proxy_steerable.3 \\\n    zmq_z85_encode.3 zmq_z85_decode.3 zmq_curve_keypair.3 zmq_curve_public.3 \\\n    zmq_has.3 \\\n    zmq_timers.3 zmq_poller.3 \\\n    zmq_atomic_counter_new.3 zmq_atomic_counter_set.3 \\\n    zmq_atomic_counter_inc.3 zmq_atomic_counter_dec.3 \\\n    zmq_atomic_counter_value.3 zmq_atomic_counter_destroy.3\n\nMAN7 = \\\n    zmq.7 zmq_tcp.7 zmq_pgm.7 zmq_inproc.7 zmq_ipc.7 \\\n    zmq_null.7 zmq_plain.7 zmq_curve.7 zmq_tipc.7 zmq_vmci.7 zmq_udp.7 \\\n    zmq_gssapi.7 zmq_vsock.7\n\n# ASCIIDOC_DOC_WITHOUT_INDEX contains all the Asciidoc files checked into the git repo, except for index.adoc\nASCIIDOC_DOC_WITHOUT_INDEX = $(MAN3:%.3=%.adoc) $(MAN7:%.7=%.adoc)\n\n# MAN_DOC contains all the MANPAGE documentation (generated from asciidoc files)\nMAN_DOC = $(MAN3) $(MAN7) \n\n# HTML_DOC contains all the HTML documentation (generated from asciidoc files)\nHTML_DOC = index.html $(ASCIIDOC_DOC_WITHOUT_INDEX:%.adoc=%.html)\n\nMAINTAINERCLEANFILES =\nEXTRA_DIST = $(ASCIIDOC_DOC_WITHOUT_INDEX)\n\n\n#\n# BUILD_DOC is set when Asciidoctor has been found\n# Declare here all the rules to produce documentation from .adoc files\n#\nif BUILD_DOC\n\nEXTRA_DIST += $(HTML_DOC) $(MAN_DOC)\nMAINTAINERCLEANFILES += $(HTML_DOC) $(MAN_DOC)\nSUFFIXES=.html .adoc .3 .7\n\n.adoc.html:\n\tasciidoctor --backend html  --attribute stylesheet=asciidoctor.css --attribute zmq_version=@PACKAGE_VERSION@  $<\n.adoc.3:\n\tasciidoctor --backend manpage --attribute zmq_version=@PACKAGE_VERSION@  $<\n.adoc.7:\n\tasciidoctor --backend manpage --attribute zmq_version=@PACKAGE_VERSION@  $<\n\ndist-hook : $(MAN_DOC) $(HTML_DOC)\n\n# the following Bash snippet is used to automatically generate an alphabetical list included by index.adoc:\n$(builddir)/__pagelist:\n\t$(srcdir)/create_page_list.sh \"$@\" \"$(abs_srcdir)\"\n\n# there are a number of constraints in auto-generating files for Asciidoctor:\n# - out-of-tree builds\n# - read-only source tree\n# - target being invoked into RPM buildroot\n# etc, so we have special rules to build the index.html page, which requires auto-generated list of doc pages\nindex.html:\n\t$(MAKE) $(builddir)/__pagelist\n\tasciidoctor --backend html \\\n        --attribute zmq_version=@PACKAGE_VERSION@ --attribute zmq_pagelist_dir=$(abs_builddir) --attribute stylesheet=asciidoctor.css \\\n            $(srcdir)/index.adoc\n\nall-local : $(MAN_DOC) $(HTML_DOC)\n\nclean-local :\n\trm -f $(MAN_DOC) $(HTML_DOC) $(builddir)/__pagelist\n\nendif\n\n\n\n#\n# INSTALL_MAN is set when BUILD_DOC was set and additionally the manpages need to be installed\n#\nif INSTALL_MAN\ndist_man_MANS = $(MAN_DOC)\nendif\n"
  },
  {
    "path": "doc/asciidoctor.css",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n/* \n  CSS file for Asciidoctor HTML documentation\n  See https://docs.asciidoctor.org/asciidoctor/latest/html-backend/default-stylesheet/#customize-extend\n  See also https://github.com/darshandsoni/asciidoctor-skins/ for custom \"skins\"\n\n/* import the default Asciidoctor CSS file */\n@import \"https://cdn.jsdelivr.net/gh/asciidoctor/asciidoctor@2.0/data/stylesheets/asciidoctor-default.css\";\n\n/* just make the default HTML list more compact: */\n.ulist p {\n  padding: 0;\n  margin-right: -4px;\n  margin-bottom: -4px;\n}\n"
  },
  {
    "path": "doc/create_page_list.sh",
    "content": "#!/bin/bash\n\n# This Bash snippet is used to automatically generate an alphabetical list included by index.adoc\n# It's invoked by at least 2 callers:\n# - the Makefile[.am] for automake builds\n# - the ReadTheDocs pipeline, see .readthedocs.yaml\n\nOUTPUT_FILE=\"$1\"\nASCIIDOC_DIR=\"$2\"\n\necho >$OUTPUT_FILE\nfor adocfile in $(ls ${ASCIIDOC_DIR}/*.adoc); do\n    adocfile_basename=$(basename ${adocfile})\n\n    # this script is used to produce an Asciidoc snippet that goes inside index.adoc... avoid listing index.adoc itself!\n    if [ \"${adocfile_basename}\" != \"index.adoc\" ]; then\n        adocfile_basename_noext=${adocfile_basename//.adoc/}\n        echo \"* xref:${adocfile_basename}[${adocfile_basename_noext}]\" >>$OUTPUT_FILE\n    fi\ndone\n"
  },
  {
    "path": "doc/index.adoc",
    "content": "= ZMQ API reference\n\nThis documentation is for libzmq {zmq_version}.\n\nA suggested start to understand 0MQ (also written as ZMQ or ZeroMQ) is the xref:zmq.adoc[zmq] manpage.\n\n== Alphabetic list of documentation pages\n\ninclude::{zmq_pagelist_dir}/__pagelist[]\n"
  },
  {
    "path": "doc/zmq.adoc",
    "content": "= zmq(7)\n\n\n== NAME\nzmq - 0MQ lightweight messaging kernel\n\n\n== SYNOPSIS\n*#include <zmq.h>*\n\n*cc* ['flags'] 'files' *-lzmq* ['libraries']\n\n\n== DESCRIPTION\nThe 0MQ lightweight messaging kernel is a library which extends the standard\nsocket interfaces with features traditionally provided by specialised\n_messaging middleware_ products. 0MQ sockets provide an abstraction of\nasynchronous _message queues_, multiple _messaging patterns_, message\nfiltering (_subscriptions_), seamless access to multiple _transport protocols_\nand more.\n\nThis documentation presents an overview of 0MQ concepts, describes how 0MQ\nabstracts standard sockets and provides a reference manual for the functions\nprovided by the 0MQ library.\n\n\nContext\n~~~~~~~\nThe 0MQ 'context' keeps the list of sockets and manages the async I/O thread\nand internal queries.\n\nBefore using any 0MQ library functions you must create a 0MQ 'context'. When\nyou exit your application you must destroy the 'context'. These functions let\nyou work with 'contexts':\n\nCreate a new 0MQ context::\n * xref:zmq_ctx_new.adoc[zmq_ctx_new]\n\nWork with context properties::\n * xref:zmq_ctx_set.adoc[zmq_ctx_set]\n * xref:zmq_ctx_get.adoc[zmq_ctx_get]\n\nDestroy a 0MQ context::\n * xref:zmq_ctx_shutdown.adoc[zmq_ctx_shutdown]\n * xref:zmq_ctx_term.adoc[zmq_ctx_term]\n\nThread safety\n^^^^^^^^^^^^^\nA 0MQ 'context' is thread safe and may be shared among as many application\nthreads as necessary, without any additional locking required on the part of\nthe caller.\n\nIndividual 0MQ 'sockets' are _not_ thread safe except in the case where full\nmemory barriers are issued when migrating a socket from one thread to another.\nIn practice this means applications can create a socket in one thread with\n_zmq_socket()_ and then pass it to a _newly created_ thread as part of thread\ninitialisation, for example via a structure passed as an argument to\n_pthread_create()_.\n\n\nMultiple contexts\n^^^^^^^^^^^^^^^^^\nMultiple 'contexts' may coexist within a single application. Thus, an\napplication can use 0MQ directly and at the same time make use of any number of\nadditional libraries or components which themselves make use of 0MQ as long as\nthe above guidelines regarding thread safety are adhered to.\n\n\nMessages\n~~~~~~~~\nA 0MQ message is a discrete unit of data passed between applications or\ncomponents of the same application. 0MQ messages have no internal structure and\nfrom the point of view of 0MQ itself they are considered to be opaque binary\ndata.\n\nThe following functions are provided to work with messages:\n\nInitialise a message::\n * xref:zmq_msg_init.adoc[zmq_msg_init]\n * xref:zmq_msg_init_size.adoc[zmq_msg_init_size]\n * xref:zmq_msg_init_buffer.adoc[zmq_msg_init_buffer]\n * xref:zmq_msg_init_data.adoc[zmq_msg_init_data]\n\nSending and receiving a message::\n * xref:zmq_msg_send.adoc[zmq_msg_send]\n * xref:zmq_msg_recv.adoc[zmq_msg_recv]\n\nRelease a message::\n * xref:zmq_msg_close.adoc[zmq_msg_close]\n\nAccess message content::\n * xref:zmq_msg_data.adoc[zmq_msg_data]\n * xref:zmq_msg_size.adoc[zmq_msg_size]\n * xref:zmq_msg_more.adoc[zmq_msg_more]\n\nWork with message properties::\n * xref:zmq_msg_gets.adoc[zmq_msg_gets]\n * xref:zmq_msg_get.adoc[zmq_msg_get]\n * xref:zmq_msg_set.adoc[zmq_msg_set]\n\nMessage manipulation::\n * xref:zmq_msg_copy.adoc[zmq_msg_copy]\n * xref:zmq_msg_move.adoc[zmq_msg_move]\n\n\nSockets\n~~~~~~~\n0MQ sockets present an abstraction of an asynchronous _message queue_, with the\nexact queueing semantics depending on the socket type in use. See\nxref:zmq_socket.adoc[zmq_socket] for the socket types provided.\n\nThe following functions are provided to work with sockets:\n\nCreating a socket::\n * xref:zmq_socket.adoc[zmq_socket]\n\nClosing a socket::\n * xref:zmq_close.adoc[zmq_close]\n\nManipulating socket options::\n * xref:zmq_getsockopt.adoc[zmq_getsockopt]\n * xref:zmq_setsockopt.adoc[zmq_setsockopt]\n\nEstablishing a message flow::\n * xref:zmq_bind.adoc[zmq_bind]\n * xref:zmq_connect.adoc[zmq_connect]\n\nSending and receiving messages::\n * xref:zmq_msg_send.adoc[zmq_msg_send]\n * xref:zmq_msg_recv.adoc[zmq_msg_recv]\n * xref:zmq_send.adoc[zmq_send]\n * xref:zmq_recv.adoc[zmq_recv]\n * xref:zmq_send_const.adoc[zmq_send_const]\n\nMonitoring socket events::\n * xref:zmq_socket_monitor.adoc[zmq_socket_monitor]\n\n.Input/output multiplexing\n0MQ provides a mechanism for applications to multiplex input/output events over\na set containing both 0MQ sockets and standard sockets. This mechanism mirrors\nthe standard _poll()_ system call, and is described in detail in\nxref:zmq_poll.adoc[zmq_poll] This API is deprecated, however.\n\nThere is a new DRAFT API with multiple zmq_poller_* function, which is described\nin xref:zmq_poller.adoc[zmq_poller]\n\n\nTransports\n~~~~~~~~~~\nA 0MQ socket can use multiple different underlying transport mechanisms.\nEach transport mechanism is suited to a particular purpose and has its own\nadvantages and drawbacks.\n\nThe following transport mechanisms are provided:\n\nUnicast transport using TCP::\n * xref:zmq_tcp.adoc[zmq_tcp]\n\nReliable multicast transport using PGM::\n * xref:zmq_pgm.adoc[zmq_pgm]\n\nLocal inter-process communication transport::\n * xref:zmq_ipc.adoc[zmq_ipc]\n\nLocal in-process (inter-thread) communication transport::\n * xref:zmq_inproc.adoc[zmq_inproc]\n\nVirtual Machine Communications Interface (VMCI) transport::\n * xref:zmq_vmci.adoc[zmq_vmci]\n\nUnreliable unicast and multicast using UDP::\n * xref:zmq_udp.adoc[zmq_udp]\n\nLinux VSOCK (AF_VSOCK) transport::\n * xref:zmq_vsock.adoc[zmq_vsock]\n\nProxies\n~~~~~~~\n0MQ provides 'proxies' to create fanout and fan-in topologies. A proxy connects\na 'frontend' socket to a 'backend' socket and switches all messages between the\ntwo sockets, opaquely. A proxy may optionally capture all traffic to a third\nsocket. To start a proxy in an application thread, use xref:zmq_proxy.adoc[zmq_proxy]\n\n\nSecurity\n~~~~~~~~\nA 0MQ socket can select a security mechanism. Both peers must use the same\nsecurity mechanism.\n\nThe following security mechanisms are provided for IPC and TCP connections:\n\nNull security::\n * xref:zmq_null.adoc[zmq_null]\n\nPlain-text authentication using username and password::\n * xref:zmq_plain.adoc[zmq_plain]\n\nElliptic curve authentication and encryption::\n * xref:zmq_curve.adoc[zmq_curve]\n\nGenerate a CURVE keypair in armored text format::\n * xref:zmq_curve_keypair.adoc[zmq_curve_keypair]\n\nDerive a CURVE public key from a secret key::\n * xref:zmq_curve_public.adoc[zmq_curve_public]\n\nConverting keys to/from armoured text strings::\n * xref:zmq_z85_decode.adoc[zmq_z85_decode]\n * xref:zmq_z85_encode.adoc[zmq_z85_encode]\n\n\n== ERROR HANDLING\nThe 0MQ library functions handle errors using the standard conventions found on\nPOSIX systems. Generally, this means that upon failure a 0MQ library function\nshall return either a NULL value (if returning a pointer) or a negative value\n(if returning an integer), and the actual error code shall be stored in the\n'errno' variable.\n\nOn non-POSIX systems some users may experience issues with retrieving the\ncorrect value of the 'errno' variable. The _zmq_errno()_ function is provided\nto assist in these cases; for details refer to xref:zmq_errno.adoc[zmq_errno]\n\nThe _zmq_strerror()_ function is provided to translate 0MQ-specific error codes\ninto error message strings; for details refer to xref:zmq_strerror.adoc[zmq_strerror]\n\n\n== UTILITY\nThe following utility functions are provided:\n\nWorking with atomic counters::\n * xref:zmq_atomic_counter_new.adoc[zmq_atomic_counter_new]\n * xref:zmq_atomic_counter_set.adoc[zmq_atomic_counter_set]\n * xref:zmq_atomic_counter_inc.adoc[zmq_atomic_counter_inc]\n * xref:zmq_atomic_counter_dec.adoc[zmq_atomic_counter_dec]\n * xref:zmq_atomic_counter_value.adoc[zmq_atomic_counter_value]\n * xref:zmq_atomic_counter_destroy.adoc[zmq_atomic_counter_destroy]\n\n\n== MISCELLANEOUS\nThe following miscellaneous functions are provided:\n\nReport 0MQ library version::\n * xref:zmq_version.adoc[zmq_version]\n\n\n== LANGUAGE BINDINGS\nThe 0MQ library provides interfaces suitable for calling from programs in any\nlanguage; this documentation documents those interfaces as they would be used\nby C programmers. The intent is that programmers using 0MQ from other languages\nshall refer to this documentation alongside any documentation provided by the\nvendor of their language binding.\n\nLanguage bindings ($$C++$$, Python, PHP, Ruby, Java and more) are provided by\nmembers of the 0MQ community and pointers can be found on the 0MQ website.\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n\n\n== RESOURCES\nMain web site: <http://www.zeromq.org/>\n\nReport bugs to the 0MQ development mailing list: <zeromq-dev@lists.zeromq.org>\n\n\n== LICENSE\nFree use of this software is granted under the terms of the Mozilla Public\nLicense Version 2.0 (MPL-2.0). For details see the file `LICENSE` included with\nthe 0MQ distribution.\n"
  },
  {
    "path": "doc/zmq_atomic_counter_dec.adoc",
    "content": "= zmq_atomic_counter_dec(3)\n\n\n== NAME\nzmq_atomic_counter_dec - decrement an atomic counter\n\n\n== SYNOPSIS\n*int zmq_atomic_counter_dec (void *counter);*\n\n\n== DESCRIPTION\nThe _zmq_atomic_counter_dec_ function decrements an atomic counter in\na threadsafe fashion. This function uses platform specific atomic\noperations.\n\n\n== RETURN VALUE\nThe _zmq_atomic_counter_dec()_ function returns 1 if the counter is\ngreater than zero after decrementing, or zero if the counter reached\nzero.\n\n\n== EXAMPLE\n.Test code for atomic counters\n----\nvoid *counter = zmq_atomic_counter_new ();\nassert (zmq_atomic_counter_value (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 1);\nassert (zmq_atomic_counter_inc (counter) == 2);\nassert (zmq_atomic_counter_value (counter) == 3);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_set (counter, 2);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_destroy (&counter);\nreturn 0;\n----\n\n\n== SEE ALSO\n* xref:zmq_atomic_counter_new.adoc[zmq_atomic_counter_new]\n* xref:zmq_atomic_counter_set.adoc[zmq_atomic_counter_set]\n* xref:zmq_atomic_counter_inc.adoc[zmq_atomic_counter_inc]\n* xref:zmq_atomic_counter_value.adoc[zmq_atomic_counter_value]\n* xref:zmq_atomic_counter_destroy.adoc[zmq_atomic_counter_destroy]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_atomic_counter_destroy.adoc",
    "content": "= zmq_atomic_counter_destroy(3)\n\n\n== NAME\nzmq_atomic_counter_destroy - destroy an atomic counter\n\n\n== SYNOPSIS\n*void zmq_atomic_counter_destroy (void **counter_p);*\n\n\n== DESCRIPTION\nThe _zmq_atomic_counter_destroy_ function destroys an atomic counter and\nnullifies its reference. Pass the address of an atomic counter (void **)\nrather than the counter itself. You must destroy all counters that you\ncreate, to avoid memory leakage. This function uses platform specific\natomic operations.\n\n\n== RETURN VALUE\nThe _zmq_atomic_counter_destroy()_ function has no return value.\n\n\n== EXAMPLE\n.Test code for atomic counters\n----\nvoid *counter = zmq_atomic_counter_new ();\nassert (zmq_atomic_counter_value (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 1);\nassert (zmq_atomic_counter_inc (counter) == 2);\nassert (zmq_atomic_counter_value (counter) == 3);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_set (counter, 2);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_destroy (&counter);\nreturn 0;\n----\n\n\n== SEE ALSO\n* xref:zmq_atomic_counter_new.adoc[zmq_atomic_counter_new]\n* xref:zmq_atomic_counter_set.adoc[zmq_atomic_counter_set]\n* xref:zmq_atomic_counter_inc.adoc[zmq_atomic_counter_inc]\n* xref:zmq_atomic_counter_dec.adoc[zmq_atomic_counter_dec]\n* xref:zmq_atomic_counter_value.adoc[zmq_atomic_counter_value]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_atomic_counter_inc.adoc",
    "content": "= zmq_atomic_counter_inc(3)\n\n\n== NAME\nzmq_atomic_counter_inc - increment an atomic counter\n\n\n== SYNOPSIS\n*int zmq_atomic_counter_inc (void *counter);*\n\n\n== DESCRIPTION\nThe _zmq_atomic_counter_inc_ function increments an atomic counter in a\nthreadsafe fashion. This function uses platform specific atomic\noperations.\n\n\n== RETURN VALUE\nThe _zmq_atomic_counter_inc()_ function returns the old value of the\ncounter, before incrementing.\n\n\n== EXAMPLE\n.Test code for atomic counters\n----\nvoid *counter = zmq_atomic_counter_new ();\nassert (zmq_atomic_counter_value (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 1);\nassert (zmq_atomic_counter_inc (counter) == 2);\nassert (zmq_atomic_counter_value (counter) == 3);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_set (counter, 2);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_destroy (&counter);\nreturn 0;\n----\n\n\n== SEE ALSO\n* xref:zmq_atomic_counter_new.adoc[zmq_atomic_counter_new]\n* xref:zmq_atomic_counter_set.adoc[zmq_atomic_counter_set]\n* xref:zmq_atomic_counter_dec.adoc[zmq_atomic_counter_dec]\n* xref:zmq_atomic_counter_value.adoc[zmq_atomic_counter_value]\n* xref:zmq_atomic_counter_destroy.adoc[zmq_atomic_counter_destroy]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_atomic_counter_new.adoc",
    "content": "= zmq_atomic_counter_new(3)\n\n\n== NAME\nzmq_atomic_counter_new - create a new atomic counter\n\n\n== SYNOPSIS\n*void *zmq_atomic_counter_new (void);*\n\n\n== DESCRIPTION\nThe _zmq_atomic_counter_new_ function creates a new atomic counter. You\ncan use this in multithreaded applications to do, for example, reference\ncounting of shared objects. The atomic counter is at least 32 bits large.\nThis function uses platform specific atomic operations.\n\n\n== RETURN VALUE\nThe _zmq_atomic_counter_new()_ function returns the new atomic counter\nif successful. Otherwise it returns NULL.\n\n\n== EXAMPLE\n.Test code for atomic counters\n----\nvoid *counter = zmq_atomic_counter_new ();\nassert (zmq_atomic_counter_value (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 1);\nassert (zmq_atomic_counter_inc (counter) == 2);\nassert (zmq_atomic_counter_value (counter) == 3);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_set (counter, 2);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_destroy (&counter);\nreturn 0;\n----\n\n\n== SEE ALSO\n* xref:zmq_atomic_counter_set.adoc[zmq_atomic_counter_set]\n* xref:zmq_atomic_counter_inc.adoc[zmq_atomic_counter_inc]\n* xref:zmq_atomic_counter_dec.adoc[zmq_atomic_counter_dec]\n* xref:zmq_atomic_counter_value.adoc[zmq_atomic_counter_value]\n* xref:zmq_atomic_counter_destroy.adoc[zmq_atomic_counter_destroy]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_atomic_counter_set.adoc",
    "content": "= zmq_atomic_counter_set(3)\n\n\n== NAME\nzmq_atomic_counter_set - set atomic counter to new value\n\n\n== SYNOPSIS\n*void zmq_atomic_counter_set (void *counter, int value);*\n\n\n== DESCRIPTION\nThe _zmq_atomic_counter_set_ function sets the counter to a new value,\nin a threadsafe fashion. The largest value that is guaranteed to work\nacross all platforms is 2^31-1. This function uses platform specific\natomic operations.\n\n\n== RETURN VALUE\nThe _zmq_atomic_counter_set()_ function has no return value.\n\n\n== EXAMPLE\n.Test code for atomic counters\n----\nvoid *counter = zmq_atomic_counter_new ();\nassert (zmq_atomic_counter_value (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 1);\nassert (zmq_atomic_counter_inc (counter) == 2);\nassert (zmq_atomic_counter_value (counter) == 3);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_set (counter, 2);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_destroy (&counter);\nreturn 0;\n----\n\n\n== SEE ALSO\n* xref:zmq_atomic_counter_new.adoc[zmq_atomic_counter_new]\n* xref:zmq_atomic_counter_inc.adoc[zmq_atomic_counter_inc]\n* xref:zmq_atomic_counter_dec.adoc[zmq_atomic_counter_dec]\n* xref:zmq_atomic_counter_value.adoc[zmq_atomic_counter_value]\n* xref:zmq_atomic_counter_destroy.adoc[zmq_atomic_counter_destroy]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_atomic_counter_value.adoc",
    "content": "= zmq_atomic_counter_value(3)\n\n\n== NAME\nzmq_atomic_counter_value - return value of atomic counter\n\n\n== SYNOPSIS\n*int zmq_atomic_counter_value (void *counter);*\n\n\n== DESCRIPTION\nThe _zmq_atomic_counter_value_ function returns the value of an atomic\ncounter created by _zmq_atomic_counter_new()_. This function uses platform \nspecific atomic operations.\n\n\n== RETURN VALUE\nThe _zmq_atomic_counter_value()_ function returns the value of the \natomic counter. If _counter_ does not point to an atomic counter created by\n_zmq_atomic_counter_new()_, the behaviour is undefined.\n\n\n== EXAMPLE\n.Test code for atomic counters\n----\nvoid *counter = zmq_atomic_counter_new ();\nassert (zmq_atomic_counter_value (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 0);\nassert (zmq_atomic_counter_inc (counter) == 1);\nassert (zmq_atomic_counter_inc (counter) == 2);\nassert (zmq_atomic_counter_value (counter) == 3);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_set (counter, 2);\nassert (zmq_atomic_counter_dec (counter) == 1);\nassert (zmq_atomic_counter_dec (counter) == 0);\nzmq_atomic_counter_destroy (&counter);\nreturn 0;\n----\n\n\n== SEE ALSO\n* xref:zmq_atomic_counter_new.adoc[zmq_atomic_counter_new]\n* xref:zmq_atomic_counter_set.adoc[zmq_atomic_counter_set]\n* xref:zmq_atomic_counter_inc.adoc[zmq_atomic_counter_inc]\n* xref:zmq_atomic_counter_dec.adoc[zmq_atomic_counter_dec]\n* xref:zmq_atomic_counter_destroy.adoc[zmq_atomic_counter_destroy]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_bind.adoc",
    "content": "= zmq_bind(3)\n\n\n== NAME\nzmq_bind - accept incoming connections on a socket\n\n\n== SYNOPSIS\n*int zmq_bind (void '*socket', const char '*endpoint');*\n\n\n== DESCRIPTION\nThe _zmq_bind()_ function binds the 'socket' to a local 'endpoint' and then\naccepts incoming connections on that endpoint.\n\nThe 'endpoint' is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to bind to.\n\n0MQ provides the the following transports:\n\n'tcp':: unicast transport using TCP, see xref:zmq_tcp.adoc[zmq_tcp]\n'ipc':: local inter-process communication transport, see xref:zmq_ipc.adoc[zmq_ipc]\n'inproc':: local in-process (inter-thread) communication transport, see xref:zmq_inproc.adoc[zmq_inproc]\n'pgm', 'epgm':: reliable multicast transport using PGM, see xref:zmq_pgm.adoc[zmq_pgm]\n'vmci':: virtual machine communications interface (VMCI), see xref:zmq_vmci.adoc[zmq_vmci]\n'udp':: unreliable unicast and multicast using UDP, see xref:zmq_udp.adoc[zmq_udp]\n'vsock':: Linux VSOCK, see xref:zmq_vsock.adoc[zmq_vsock]\n\nEvery 0MQ socket type except 'ZMQ_PAIR' and 'ZMQ_CHANNEL' supports one-to-many and many-to-one\nsemantics. The precise semantics depend on the socket type and are defined in\nxref:zmq_socket.adoc[zmq_socket]\n\nThe 'ipc', 'tcp', 'vmci', 'udp' and 'vsock' transports accept wildcard addresses: see\nxref:zmq_ipc.adoc[zmq_ipc], xref:zmq_tcp.adoc[zmq_tcp], xref:zmq_vmci.adoc[zmq_vmci],\nxref:zmq_udp.adoc[zmq_udp] and xref:zmq_vsock.adoc[zmq_vsock] for details.\n\nNOTE: the address syntax may be different for _zmq_bind()_ and _zmq_connect()_\nespecially for the 'tcp', 'pgm' and 'epgm' transports.\n\nNOTE: following a _zmq_bind()_, the socket enters a 'mute' state unless or\nuntil at least one incoming or outgoing connection is made, at which point\nthe socket enters a 'ready' state. In the mute state, the socket blocks or\ndrops messages according to the socket type, as defined in xref:zmq_socket.adoc[zmq_socket]\nBy contrast, following a libzmq:zmq_connect, the socket enters the 'ready' state.\n\n\n== RETURN VALUE\nThe _zmq_bind()_ function returns zero if successful. Otherwise it returns\n`-1` and sets 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EINVAL*::\nThe endpoint supplied is invalid.\n*EPROTONOSUPPORT*::\nThe requested 'transport' protocol is not supported.\n*ENOCOMPATPROTO*::\nThe requested 'transport' protocol is not compatible with the socket type.\n*EADDRINUSE*::\nThe requested 'address' is already in use.\n*EADDRNOTAVAIL*::\nThe requested 'address' was not local.\n*ENODEV*::\nThe requested 'address' specifies a nonexistent interface.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EMTHREAD*::\nNo I/O thread is available to accomplish the task.\n\n\n== EXAMPLE\n.Binding a publisher socket to an in-process and a TCP transport\n----\n/* Create a ZMQ_PUB socket */\nvoid *socket = zmq_socket (context, ZMQ_PUB);\nassert (socket);\n/* Bind it to a in-process transport with the address 'my_publisher' */\nint rc = zmq_bind (socket, \"inproc://my_publisher\");\nassert (rc == 0);\n/* Bind it to a TCP transport on port 5555 of the 'eth0' interface */\nrc = zmq_bind (socket, \"tcp://eth0:5555\");\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_close.adoc",
    "content": "= zmq_close(3)\n\n\n== NAME\nzmq_close - close 0MQ socket\n\n\n== SYNOPSIS\n*int zmq_close (void '*socket');*\n\n\n== DESCRIPTION\nThe _zmq_close()_ function shall destroy the socket referenced by the 'socket'\nargument. Any outstanding messages physically received from the network but not\nyet received by the application with _zmq_recv()_ shall be discarded. The\nbehaviour for discarding messages sent by the application with _zmq_send()_ but\nnot yet physically transferred to the network depends on the value of the\n_ZMQ_LINGER_ socket option for the specified 'socket'.\n\n_zmq_close()_ must be called exactly once for each socket. If it is never called,\n_zmq_ctx_term()_ will block forever. If it is called multiple times for the same \nsocket or if 'socket' does not point to a socket, the behaviour is undefined.\n\nNOTE: The default setting of _ZMQ_LINGER_ does not discard unsent messages;\nthis behaviour may cause the application to block when calling _zmq_ctx_term()_.\nFor details refer to xref:zmq_setsockopt.adoc[zmq_setsockopt] and xref:zmq_ctx_term.adoc[zmq_ctx_term]\n\nNOTE: This API will complete asynchronously, so not everything will be deallocated\nafter it returns. See above for details about linger.\n\n\n== RETURN VALUE\nThe _zmq_close()_ function shall return zero if successful. Otherwise it shall\nreturn `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*ENOTSOCK*::\nThe provided 'socket' was NULL.\n\n\n== SEE ALSO\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq_ctx_term.adoc[zmq_ctx_term]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_connect.adoc",
    "content": "= zmq_connect(3)\n\n\n== NAME\nzmq_connect - create outgoing connection from socket\n\n\n== SYNOPSIS\n*int zmq_connect (void '*socket', const char '*endpoint');*\n\n\n== DESCRIPTION\nThe _zmq_connect()_ function connects the 'socket' to an 'endpoint' and then\naccepts incoming connections on that endpoint.\n\nThe 'endpoint' is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to connect to.\n\n0MQ provides the the following transports:\n\n'tcp':: unicast transport using TCP, see xref:zmq_tcp.adoc[zmq_tcp]\n'ipc':: local inter-process communication transport, see xref:zmq_ipc.adoc[zmq_ipc]\n'inproc':: local in-process (inter-thread) communication transport, see xref:zmq_inproc.adoc[zmq_inproc]\n'pgm', 'epgm':: reliable multicast transport using PGM, see xref:zmq_pgm.adoc[zmq_pgm]\n'vmci':: virtual machine communications interface (VMCI), see xref:zmq_vmci.adoc[zmq_vmci]\n'udp':: unreliable unicast and multicast using UDP, see xref:zmq_udp.adoc[zmq_udp]\n'vsock':: Linux VSOCK, see xref:zmq_vsock.adoc[zmq_vsock]\n\nEvery 0MQ socket type except 'ZMQ_PAIR' and 'ZMQ_CHANNEL' supports one-to-many and many-to-one\nsemantics. The precise semantics depend on the socket type and are defined in\nxref:zmq_socket.adoc[zmq_socket]\n\nNOTE: for most transports and socket types the connection is not performed\nimmediately but as needed by 0MQ. Thus a successful call to _zmq_connect()_\ndoes not mean that the connection was or could actually be established.\nBecause of this, for most transports and socket types the order in which\na 'server' socket is bound and a 'client' socket is connected to it does not\nmatter. The _ZMQ_PAIR_ and _ZMQ_CHANNEL_ sockets are an exception, as they do not automatically\nreconnect to endpoints.\n\nNOTE: following a _zmq_connect()_, for socket types except for ZMQ_ROUTER,\nthe socket enters its normal 'ready' state. By contrast, following a\n_zmq_bind()_ alone, the socket enters a 'mute' state in which the socket\nblocks or drops messages according to the socket type, as defined in\nxref:zmq_socket.adoc[zmq_socket] A ZMQ_ROUTER socket enters its normal 'ready' state\nfor a specific peer only when handshaking is complete for that peer, which\nmay take an arbitrary time.\n\nNOTE: for some socket types, multiple connections to the same endpoint\ndon't really make sense\n(see https://github.com/zeromq/libzmq/issues/788).\nFor those socket types, any attempt to connect to an already connected endpoint\nis silently ignored (i.e., returns zero).  This behavior applies to ZMQ_DEALER,\nZMQ_SUB, ZMQ_PUB, and ZMQ_REQ socket types.\n\n\n== RETURN VALUE\nThe _zmq_connect()_ function returns zero if successful. Otherwise it returns\n`-1` and sets 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EINVAL*::\nThe endpoint supplied is invalid.\n*EPROTONOSUPPORT*::\nThe requested 'transport' protocol is not supported.\n*ENOCOMPATPROTO*::\nThe requested 'transport' protocol is not compatible with the socket type.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EMTHREAD*::\nNo I/O thread is available to accomplish the task.\n\n\n== EXAMPLE\n.Connecting a subscriber socket to an in-process and a TCP transport\n----\n/* Create a ZMQ_SUB socket */\nvoid *socket = zmq_socket (context, ZMQ_SUB);\nassert (socket);\n/* Connect it to an in-process transport with the address 'my_publisher' */\nint rc = zmq_connect (socket, \"inproc://my_publisher\");\nassert (rc == 0);\n/* Connect it to the host server001, port 5555 using a TCP transport */\nrc = zmq_connect (socket, \"tcp://server001:5555\");\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_connect_peer.adoc",
    "content": "= zmq_connect_peer(3)\n\n\n== NAME\nzmq_connect_peer - create outgoing connection from socket and return the connection routing id in thread-safe and atomic way.\n\n\n== SYNOPSIS\n*uint32_t zmq_connect_peer (void '*socket', const char '*endpoint');*\n\n\n== DESCRIPTION\nThe _zmq_connect_peer()_ function connects a 'ZMQ_PEER' socket to an 'endpoint' and then returns the endpoint 'routing_id'.\n\nThe 'endpoint' is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to connect to.\n\nThe function is supported only on the 'ZMQ_PEER' socket type and would return `0` with 'errno' set to 'ENOTSUP' otherwise.\n\nThe _zmq_connect_peer()_ support the following transports:\n\n'tcp':: unicast transport using TCP, see xref:zmq_tcp.adoc[zmq_tcp]\n'ipc':: local inter-process communication transport, see xref:zmq_ipc.adoc[zmq_ipc]\n'inproc':: local in-process (inter-thread) communication transport, see xref:zmq_inproc.adoc[zmq_inproc]\n'ws':: unicast transport using WebSockets, see xref:zmq_ws.adoc[zmq_ws]\n'wss':: unicast transport using WebSockets over TLS, see xref:zmq_wss.adoc[zmq_wss]\n\n== RETURN VALUE\nThe _zmq_connect_peer()_ function returns the peer 'routing_id' if successful. Otherwise it returns\n`0` and sets 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EINVAL*::\nThe endpoint supplied is invalid.\n*EPROTONOSUPPORT*::\nThe requested 'transport' protocol is not supported with 'ZMQ_PEER'.\n*ENOCOMPATPROTO*::\nThe requested 'transport' protocol is not compatible with the socket type.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EMTHREAD*::\nNo I/O thread is available to accomplish the task.\n*ENOTSUP*::\nThe socket is not of type 'ZMQ_PEER'.\n*EFAULT*::\nThe 'ZMQ_IMMEDIATE' option is set on the socket.\n\n== EXAMPLE\n.Connecting a peer socket to a TCP transport and sending a message\n----\n/* Create a ZMQ_SUB socket */\nvoid *socket = zmq_socket (context, ZMQ_PEER);\nassert (socket);\n/* Connect it to the host server001, port 5555 using a TCP transport */\nuint32_t routing_id = zmq_connect (socket, \"tcp://server001:5555\");\nassert (routing_id == 0);\n/* Sending a message to the peer  */\nzmq_msg_t msg;\nint rc = zmq_msg_init_data (&msg, \"HELLO\", 5, NULL, NULL);\nassert (rc == 0);\nrc = zmq_msg_set_routing_id (&msg, routing_id);\nassert (rc == 0);\nrc = zmq_msg_send (&msg, socket, 0);\nassert (rc == 5);\nrc = zmq_msg_close (&msg);\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_ctx_get.adoc",
    "content": "= zmq_ctx_get(3)\n\n\n== NAME\n\nzmq_ctx_get - get context options\n\n\n== SYNOPSIS\n*int zmq_ctx_get (void '*context', int 'option_name');*\n\n\n== DESCRIPTION\nThe _zmq_ctx_get()_ function shall return the option specified by the\n'option_name' argument.\n\nThe _zmq_ctx_get()_ function accepts the following option names:\n\n\nZMQ_IO_THREADS: Get number of I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_IO_THREADS' argument returns the size of the 0MQ thread pool\nfor this context.\n\n\nZMQ_MAX_SOCKETS: Get maximum number of sockets\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_MAX_SOCKETS' argument returns the maximum number of sockets\nallowed for this context.\n\n\nZMQ_MAX_MSGSZ: Get maximum message size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_MAX_MSGSZ' argument returns the maximum size of a message\nallowed for this context. Default value is INT_MAX.\n\n\nZMQ_ZERO_COPY_RECV: Get message decoding strategy\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_ZERO_COPY_RECV' argument return whether message decoder uses a zero copy\nstrategy when receiving messages. Default value is 1.\nNOTE: in DRAFT state, not yet available in stable releases.\n\n\nZMQ_SOCKET_LIMIT: Get largest configurable number of sockets\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_SOCKET_LIMIT' argument returns the largest number of sockets that\nxref:zmq_ctx_set.adoc[zmq_ctx_set] will accept.\n\n\nZMQ_IPV6: Set IPv6 option\n~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_IPV6' argument returns the IPv6 option for the context.\n\n\nZMQ_BLOCKY: Get blocky setting\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_BLOCKY' argument returns 1 if the context will block on terminate,\nzero if the \"block forever on context termination\" gambit was disabled by\nsetting ZMQ_BLOCKY to false on all new contexts.\n\n\nZMQ_THREAD_SCHED_POLICY: Get scheduling policy for I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_THREAD_SCHED_POLICY' argument returns the scheduling policy for\ninternal context's thread pool.\n\n\nZMQ_THREAD_NAME_PREFIX: Get name prefix for I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_THREAD_NAME_PREFIX' argument gets the numeric prefix of each thread\ncreated for the internal context's thread pool.\n\n\nZMQ_MSG_T_SIZE: Get the zmq_msg_t size at runtime\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_MSG_T_SIZE' argument returns the size of the zmq_msg_t structure at\nruntime, as defined in the include/zmq.h public header.\nThis is useful for example for FFI bindings that can't simply do a sizeof().\n\n\n== RETURN VALUE\nThe _zmq_ctx_get()_ function returns a value of 0 or greater if successful.\nOtherwise it returns `-1` and sets 'errno' to one of the values defined\nbelow.\n\n\n== ERRORS\n*EINVAL*::\nThe requested option _option_name_ is unknown.\n*EFAULT*::\nThe provided 'context' is invalid.\n\n\n== EXAMPLE\n.Setting a limit on the number of sockets\n----\nvoid *context = zmq_ctx_new ();\nzmq_ctx_set (context, ZMQ_MAX_SOCKETS, 256);\nint max_sockets = zmq_ctx_get (context, ZMQ_MAX_SOCKETS);\nassert (max_sockets == 256);\n----\n.Switching off the context deadlock gambit\n----\nzmq_ctx_set (ctx, ZMQ_BLOCKY, false);\n----\n\n\n== SEE ALSO\n* xref:zmq_ctx_set.adoc[zmq_ctx_set]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_ctx_get_ext.adoc",
    "content": "= zmq_ctx_get_ext(3)\n\n\n== NAME\n\nzmq_ctx_get_ext - get extended context options\n\n\n== SYNOPSIS\n*int zmq_ctx_get_ext (void '*context', int 'option_name', void '*option_value', size_t '*option_len');*\n\n\n== DESCRIPTION\nThe _zmq_ctx_get()_ function shall retrieve the value for the option\nspecified by the 'option_name' argument and store it in the buffer pointed to\nby the 'option_value' argument. \nThe 'option_len' argument is the size in bytes of the buffer pointed\nto by 'option_value'; upon successful completion _zmq_ctx_get_ext()_ shall\nmodify the 'option_len' argument to indicate the actual size of the option\nvalue stored in the buffer.\n\nThe _zmq_ctx_get_ext()_ function accepts all the option names accepted by\n_zmq_ctx_get()_.\nOptions that make most sense to retrieve using _zmq_ctx_get_ext()_ instead of\n_zmq_ctx_get()_ are:\n\nZMQ_THREAD_NAME_PREFIX: Get name prefix for I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_THREAD_NAME_PREFIX' argument gets the string prefix of each thread\ncreated for the internal context's thread pool.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: empty string\n\n\n== RETURN VALUE\nThe _zmq_ctx_get_ext()_ function returns a value of 0 or greater if successful.\nOtherwise it returns `-1` and sets 'errno' to one of the values defined\nbelow.\n\n\n== ERRORS\n*EINVAL*::\nThe requested option _option_name_ is unknown.\n*EFAULT*::\nThe provided 'context' is invalid.\n\n\n== EXAMPLE\n.Setting a prefix on internal ZMQ thread names:\n----\nvoid *context = zmq_ctx_new ();\nconst char prefix[] = \"MyApp\";\nsize_t prefixLen = sizeof(prefix);\nzmq_ctx_set (context, ZMQ_THREAD_NAME_PREFIX, &prefix, &prefixLen);\n\nchar buff[256];\nsize_t buffLen = sizeof(buff);\nint rc = zmq_ctx_get (context, ZMQ_THREAD_NAME_PREFIX, &buff, &buffLen);\nassert (rc == 0);\nassert (buffLen == prefixLen);\n\n----\n\n\n== SEE ALSO\n* xref:zmq_ctx_get.adoc[zmq_ctx_get]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_ctx_new.adoc",
    "content": "= zmq_ctx_new(3)\n\n\n== NAME\nzmq_ctx_new - create new 0MQ context\n\n\n== SYNOPSIS\n*void *zmq_ctx_new ();*\n\n\n== DESCRIPTION\nThe _zmq_ctx_new()_ function creates a new 0MQ 'context'.\n\nThis function replaces the deprecated function xref:zmq_init.adoc[zmq_init]\n\n.Thread safety\nA 0MQ 'context' is thread safe and may be shared among as many application\nthreads as necessary, without any additional locking required on the part of\nthe caller.\n\n\n== RETURN VALUE\nThe _zmq_ctx_new()_ function shall return an opaque handle to the newly created\n'context' if successful. Otherwise it shall return NULL and set 'errno' to one\nof the values defined below.\n\n\n== ERRORS\n*EMFILE*::\nThe limit on the total number of open files has been reached and it\nwasn't possible to create a new context.\n*EMFILE*::\nThe limit on the total number of open files in system has been reached\nand it wasn't possible to create a new context.\n\n\n== SEE ALSO\n* xref:zmq.adoc[zmq]\n* xref:zmq_ctx_set.adoc[zmq_ctx_set]\n* xref:zmq_ctx_get.adoc[zmq_ctx_get]\n* xref:zmq_ctx_term.adoc[zmq_ctx_term]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_ctx_set.adoc",
    "content": "= zmq_ctx_set(3)\n\n\n== NAME\n\nzmq_ctx_set - set context options\n\n\n== SYNOPSIS\n*int zmq_ctx_set (void '*context', int 'option_name', int 'option_value');*\n\n\n== DESCRIPTION\nThe _zmq_ctx_set()_ function shall set the option specified by the\n'option_name' argument to the value of the 'option_value' argument.\n\nThe _zmq_ctx_set()_ function accepts the following options:\n\n\nZMQ_BLOCKY: Fix blocky behavior\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nBy default the context will block, forever, on a zmq_ctx_term call. The\nassumption behind this behavior is that abrupt termination will cause\nmessage loss. Most real applications use some form of handshaking to ensure\napplications receive termination messages, and then terminate the context\nwith 'ZMQ_LINGER' set to zero on all sockets. This setting is an easier way\nto get the same result. When 'ZMQ_BLOCKY' is set to false, all new sockets\nare given a linger timeout of zero. You must still close all sockets before\ncalling zmq_ctx_term.\n\n[horizontal]\nDefault value:: true (old behavior)\n\n\nZMQ_IO_THREADS: Set number of I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_IO_THREADS' argument specifies the size of the 0MQ thread pool to\nhandle I/O operations. If your application is using only the 'inproc'\ntransport for messaging you may set this to zero, otherwise set it to at\nleast one. This option only applies before creating any sockets on the\ncontext.\n\n[horizontal]\nDefault value:: 1\n\n\nZMQ_THREAD_SCHED_POLICY: Set scheduling policy for I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_THREAD_SCHED_POLICY' argument sets the scheduling policy for\ninternal context's thread pool. This option is not available on windows.\nSupported values for this option can be found in sched.h file,\nor at http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html.\nThis option only applies before creating any sockets on the context.\n\n[horizontal]\nDefault value:: -1\n\n\nZMQ_THREAD_PRIORITY: Set scheduling priority for I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_THREAD_PRIORITY' argument sets scheduling priority for\ninternal context's thread pool. This option is not available on windows.\nSupported values for this option depend on chosen scheduling policy.\nOn Linux, when the scheduler policy is SCHED_OTHER, SCHED_IDLE or SCHED_BATCH, the OS scheduler\nwill not use the thread priority but rather the thread \"nice value\"; in such cases,\nif 'ZMQ_THREAD_PRIORITY' is set to a strictly positive value,\nthe system call \"nice\" will be used to set the nice value to -20 (max priority) instead of\nadjusting the thread priority (which must be zero for those scheduling policies).\nDetails can be found in sched.h file, or at http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html.\nThis option only applies before creating any sockets on the context.\n\n[horizontal]\nDefault value:: -1\n\n\nZMQ_THREAD_AFFINITY_CPU_ADD: Add a CPU to list of affinity for I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_THREAD_AFFINITY_CPU_ADD' argument adds a specific CPU to the affinity list for the internal\ncontext's thread pool. This option is only supported on Linux.\nThis option only applies before creating any sockets on the context.\nThe default affinity list is empty and means that no explicit CPU-affinity will be set on\ninternal context's threads.\n\n[horizontal]\nDefault value:: -1\n\n\nZMQ_THREAD_AFFINITY_CPU_REMOVE: Remove a CPU to list of affinity for I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_THREAD_AFFINITY_CPU_REMOVE' argument removes a specific CPU to the affinity list for the internal\ncontext's thread pool. This option is only supported on Linux.\nThis option only applies before creating any sockets on the context.\nThe default affinity list is empty and means that no explicit CPU-affinity will be set on\ninternal context's threads.\n\n[horizontal]\nDefault value:: -1\n\n\nZMQ_THREAD_NAME_PREFIX: Set name prefix for I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_THREAD_NAME_PREFIX' argument sets a numeric prefix to each thread\ncreated for the internal context's thread pool. This option is only supported on Linux.\nThis option is useful to help  debugging done via \"top -H\" or \"gdb\"; in case\nmultiple processes on the system are using ZeroMQ it is useful to provide through\nthis context option an application-specific prefix to distinguish ZeroMQ background\nthreads that belong to different processes.\nThis option only applies before creating any sockets on the context.\n\n[horizontal]\nDefault value:: -1\n\n\n\nZMQ_MAX_MSGSZ: Set maximum message size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_MAX_MSGSZ' argument sets the maximum allowed size\nof a message sent in the context. You can query the maximal\nallowed value with xref:zmq_ctx_get.adoc[zmq_ctx_get] using the\n'ZMQ_MAX_MSGSZ' option.\n\n[horizontal]\nDefault value:: INT_MAX\nMaximum value:: INT_MAX\n\n\nZMQ_ZERO_COPY_RECV: Specify message decoding strategy\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_ZERO_COPY_RECV' argument specifies whether the message decoder should\nuse a zero copy strategy when receiving messages. The zero copy strategy can\nlead to increased memory usage in some cases. This option allows you to use the\nolder copying strategy. You can query the value of this option with\nxref:zmq_ctx_get.adoc[zmq_ctx_get] using the 'ZMQ_ZERO_COPY_RECV' option.\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nDefault value:: 1\n\n\nZMQ_MAX_SOCKETS: Set maximum number of sockets\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_MAX_SOCKETS' argument sets the maximum number of sockets allowed\non the context. You can query the maximal allowed value with\nxref:zmq_ctx_get.adoc[zmq_ctx_get] using the 'ZMQ_SOCKET_LIMIT' option.\n\n[horizontal]\nDefault value:: 1023\n\n\nZMQ_IPV6: Set IPv6 option\n~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_IPV6' argument sets the IPv6 value for all sockets created in\nthe context from this point onwards. A value of `1` means IPv6 is\nenabled, while `0` means the socket will use only IPv4. When IPv6 is\nenabled, a socket will connect to, or accept connections from, both\nIPv4 and IPv6 hosts.\n\n[horizontal]\nDefault value:: 0\n\n\n== RETURN VALUE\nThe _zmq_ctx_set()_ function returns zero if successful. Otherwise it\nreturns `-1` and sets 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EINVAL*::\nThe requested option _option_name_ is unknown.\n\n\n== EXAMPLE\n.Setting a limit on the number of sockets\n----\nvoid *context = zmq_ctx_new ();\nzmq_ctx_set (context, ZMQ_MAX_SOCKETS, 256);\nint max_sockets = zmq_ctx_get (context, ZMQ_MAX_SOCKETS);\nassert (max_sockets == 256);\n----\n\n\n== SEE ALSO\n* xref:zmq_ctx_get.adoc[zmq_ctx_get]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_ctx_set_ext.adoc",
    "content": "= zmq_ctx_set_ext(3)\n\n\n== NAME\n\nzmq_ctx_set_ext - set extended context options\n\n\n== SYNOPSIS\n*int zmq_ctx_set_ext (void '*context', int 'option_name', const void '*option_value', size_t 'option_len');*\n\n\n== DESCRIPTION\n\nThe _zmq_ctx_set_ext()_ function shall set the option specified by the\n'option_name' argument to the value pointed to by the 'option_value' argument\nfor the 0MQ context pointed to by the 'context' argument. The 'option_len'\nargument is the size of the option value in bytes. For options taking a value of\ntype \"character string\", the provided byte data should either contain no zero\nbytes, or end in a single zero byte (terminating ASCII NUL character).\n\nThe _zmq_ctx_set_ext()_ function accepts all the option names accepted by\n_zmq_ctx_set()_.\nOptions that make most sense to set using _zmq_ctx_set_ext()_ instead of\n_zmq_ctx_set()_ are the following options:\n\nZMQ_THREAD_NAME_PREFIX: Set name prefix for I/O threads\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_THREAD_NAME_PREFIX' argument sets a string prefix to each thread\ncreated for the internal context's thread pool. This option is only supported on Linux.\nThis option is useful to help  debugging done via \"top -H\" or \"gdb\"; in case\nmultiple processes on the system are using ZeroMQ it is useful to provide through\nthis context option an application-specific prefix to distinguish ZeroMQ background\nthreads that belong to different processes.\nThis option only applies before creating any sockets on the context.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: empty string\n\n\n== RETURN VALUE\nThe _zmq_ctx_set_ext()_ function returns zero if successful. Otherwise it\nreturns `-1` and sets 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EINVAL*::\nThe requested option _option_name_ is unknown.\n*EFAULT*::\nThe provided 'context' is invalid.\n\n\n== EXAMPLE\n.Setting a prefix on internal ZMQ thread names:\n----\nvoid *context = zmq_ctx_new ();\nconst char prefix[] = \"MyApp\";\nsize_t prefixLen = sizeof(prefix);\nzmq_ctx_set (context, ZMQ_THREAD_NAME_PREFIX, &prefix, &prefixLen);\n\nchar buff[256];\nsize_t buffLen = sizeof(buff);\nint rc = zmq_ctx_get (context, ZMQ_THREAD_NAME_PREFIX, &buff, &buffLen);\nassert (rc == 0);\nassert (buffLen == prefixLen);\n\n----\n\n\n== SEE ALSO\n* xref:zmq_ctx_set.adoc[zmq_ctx_set]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_ctx_shutdown.adoc",
    "content": "= zmq_ctx_shutdown(3)\n\n\n== NAME\nzmq_ctx_shutdown - shutdown a 0MQ context\n\n\n== SYNOPSIS\n*int zmq_ctx_shutdown (void '*context');*\n\n\n== DESCRIPTION\nThe _zmq_ctx_shutdown()_ function shall shutdown the 0MQ context 'context'.\n\nContext shutdown will cause any blocking operations currently in progress on \nsockets open within 'context' to return immediately with an error code of ETERM.\nWith the exception of _zmq_close()_, any further operations on sockets open within\n'context' shall fail with an error code of ETERM. No further sockets can be created\nusing _zmq_socket()_ on a context for which _zmq_ctx_shutdown()_ has been called,\nit will return and set errno to ETERM.\n\nThis function is optional, client code is still required to call the xref:zmq_ctx_term.adoc[zmq_ctx_term]\nfunction to free all resources allocated by zeromq.\n\n\n== RETURN VALUE\nThe _zmq_ctx_shutdown()_ function shall return zero if successful. Otherwise\nit shall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EFAULT*::\nThe provided 'context' was invalid.\n\n\n== SEE ALSO\n* xref:zmq.adoc[zmq]\n* xref:zmq_init.adoc[zmq_init]\n* xref:zmq_ctx_term.adoc[zmq_ctx_term]\n* xref:zmq_close.adoc[zmq_close]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_ctx_term.adoc",
    "content": "= zmq_ctx_term(3)\n\n\n== NAME\nzmq_ctx_term - terminate a 0MQ context\n\n\n== SYNOPSIS\n*int zmq_ctx_term (void '*context');*\n\n\n== DESCRIPTION\nThe _zmq_ctx_term()_ function shall destroy the 0MQ context 'context'.\n\nContext termination is performed in the following steps:\n\n1. Any blocking operations currently in progress on sockets open within\n   'context' shall return immediately with an error code of ETERM.  With the\n   exception of _zmq_close()_, any further operations on sockets open within\n   'context' shall fail with an error code of ETERM.\n\n2. After interrupting all blocking calls, _zmq_ctx_term()_ shall _block_ until\n   the following conditions are satisfied:\n\n   * All sockets open within 'context' have been closed with _zmq_close()_.\n\n   * For each socket within 'context', all messages sent by the application\n     with _zmq_send()_ have either been physically transferred to a network\n     peer, or the socket's linger period set with the _ZMQ_LINGER_ socket\n     option has expired.\n\nFor further details regarding socket linger behaviour refer to the _ZMQ_LINGER_\noption in xref:zmq_setsockopt.adoc[zmq_setsockopt]\n\nThis function replaces the deprecated functions xref:zmq_term.adoc[zmq_term] and\nxref:zmq_ctx_destroy.adoc[zmq_ctx_destroy]\n\n\n== RETURN VALUE\nThe _zmq_ctx_term()_ function shall return zero if successful. Otherwise\nit shall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EFAULT*::\nThe provided 'context' was invalid.\n*EINTR*::\nTermination was interrupted by a signal. It can be restarted if needed.\n\n\n== SEE ALSO\n* xref:zmq.adoc[zmq]\n* xref:zmq_init.adoc[zmq_init]\n* xref:zmq_close.adoc[zmq_close]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_curve.adoc",
    "content": "= zmq_curve(7)\n\n\n== NAME\nzmq_curve - secure authentication and confidentiality\n\n\n== SYNOPSIS\nThe CURVE mechanism defines a mechanism for secure authentication and \nconfidentiality for communications between a client and a server. CURVE \nis intended for use on public networks. The CURVE mechanism is defined \nby this document: <http://rfc.zeromq.org/spec:25>.\n\n\n== CLIENT AND SERVER ROLES\nA socket using CURVE can be either client or server, at any moment, but \nnot both. The role is independent of bind/connect direction.\n\nA socket can change roles at any point by setting new options. The role\naffects all zmq_connect and zmq_bind calls that follow it.\n\nTo become a CURVE server, the application sets the ZMQ_CURVE_SERVER option\non the socket, and then sets the ZMQ_CURVE_SECRETKEY option to provide the\nsocket with its long-term secret key. The application does not provide the\nsocket with its long-term public key, which is used only by clients.\n\nTo become a CURVE client, the application sets the ZMQ_CURVE_SERVERKEY \noption with the long-term public key of the server it intends to connect\nto, or accept connections from, next. The application then sets the \nZMQ_CURVE_PUBLICKEY and ZMQ_CURVE_SECRETKEY options with its client \nlong-term key pair.\n\nIf the server does authentication it will be based on the client's long\nterm public key.\n\n== KEY ENCODING\nThe standard representation for keys in source code is either 32 bytes of\nbase 256 (binary) data, or 40 characters of base 85 data encoded using the\nZ85 algorithm defined by http://rfc.zeromq.org/spec:32.\n\nThe Z85 algorithm is designed to produce printable key strings for use in\nconfiguration files, the command line, and code. There is a reference\nimplementation in C at https://github.com/zeromq/rfc/tree/master/src.\n\n    \n== TEST KEY VALUES\nFor test cases, the client shall use this long-term key pair (specified\nas hexadecimal and in Z85):\n\n----\npublic: \n    BB88471D65E2659B30C55A5321CEBB5AAB2B70A398645C26DCA2B2FCB43FC518\n    Yne@$w-vo<fVvi]a<NY6T1ed:M$fCG*[IaLV{hID\n\nsecret: \n    7BB864B489AFA3671FBE69101F94B38972F24816DFB01B51656B3FEC8DFD0888\n    D:)Q[IlAW!ahhC2ac:9*A}h:p?([4%wOTJ%JR%cs\n----\n\nAnd the server shall use this long-term key pair (specified as hexadecimal \nand in Z85):\n\n----\npublic: \n    54FCBA24E93249969316FB617C872BB0C1D1FF14800427C594CBFACF1BC2D652\n    rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7\n\nsecret: \n    8E0BDD697628B91D8F245587EE95C5B04D48963F79259877B49CD9063AEAD3B7\n    JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6\n----\n\n== SEE ALSO\n* xref:zmq_z85_encode.adoc[zmq_z85_encode]\n* xref:zmq_z85_decode.adoc[zmq_z85_decode]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq_null.adoc[zmq_null]\n* xref:zmq_plain.adoc[zmq_plain]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_curve_keypair.adoc",
    "content": "= zmq_curve_keypair(3)\n\n\n== NAME\nzmq_curve_keypair - generate a new CURVE keypair\n\n\n== SYNOPSIS\n*int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key);*\n\n\n== DESCRIPTION\nThe _zmq_curve_keypair()_ function shall return a newly generated random\nkeypair consisting of a public key and a secret key. The caller provides\ntwo buffers, each at least 41 octets large, in which this method will\nstore the keys. The keys are encoded using xref:zmq_z85_encode.adoc[zmq_z85_encode].\n\n\n== RETURN VALUE\nThe _zmq_curve_keypair()_ function shall return 0 if successful, else it\nshall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*ENOTSUP*::\nThe libzmq library was not built with cryptographic support (libsodium).\n\n\n== EXAMPLE\n.Generating a new CURVE keypair\n----\nchar public_key [41];\nchar secret_key [41];\nint rc = zmq_curve_keypair (public_key, secret_key);\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_z85_encode.adoc[zmq_z85_encode]\n* xref:zmq_z85_decode.adoc[zmq_z85_decode]\n* xref:zmq_curve.adoc[zmq_curve]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_curve_public.adoc",
    "content": "= zmq_curve_public(3)\n\n\n== NAME\nzmq_curve_public - derive the public key from a private key\n\n\n== SYNOPSIS\n*int zmq_curve_public (char *z85_public_key, char *z85_secret_key);*\n\n\n== DESCRIPTION\nThe _zmq_curve_public()_ function shall derive the public key from a\nprivate key. The caller provides two buffers, each at least 41 octets\nlarge. In z85_secret_key the caller shall provide the private key, and\nthe function will store the public key in z85_public_key. The keys are\nencoded using xref:zmq_z85_encode.adoc[zmq_z85_encode].\n\n\n== RETURN VALUE\nThe _zmq_curve_public()_ function shall return 0 if successful, else it\nshall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*ENOTSUP*::\nThe libzmq library was not built with cryptographic support (libsodium).\n\n\n== EXAMPLE\n.Deriving the public key from a CURVE private key\n----\nchar public_key [41];\nchar secret_key [41];\nint rc = zmq_curve_keypair (public_key, secret_key);\nassert (rc == 0);\nchar derived_public[41];\nrc = zmq_curve_public (derived_public, secret_key);\nassert (rc == 0);\nassert (!strcmp (derived_public, public_key));\n----\n\n\n== SEE ALSO\n* xref:zmq_z85_encode.adoc[zmq_z85_encode]\n* xref:zmq_z85_decode.adoc[zmq_z85_decode]\n* xref:zmq_curve_keypair.adoc[zmq_curve_keypair]\n* xref:zmq_curve.adoc[zmq_curve]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_disconnect.adoc",
    "content": "= zmq_disconnect(3)\n\n\n== NAME\nzmq_disconnect - Disconnect a socket from an endpoint\n\n\n== SYNOPSIS\n*int zmq_disconnect (void '*socket', const char '*endpoint');*\n\n\n== DESCRIPTION\nThe _zmq_disconnect()_ function shall disconnect a socket specified\nby the 'socket' argument from the endpoint specified by the 'endpoint'\nargument. Note the actual disconnect system call might occur at a later time.\n\nUpon disconnection the will also stop receiving messages originating from\nthis endpoint. Moreover, the socket will no longer be able\nto queue outgoing messages to this endpoint. The outgoing message queue\nassociated with the endpoint will be discarded. However, if the socket's linger\nperiod is non-zero, libzmq will still attempt to transmit these discarded messages,\nuntil the linger period expires.\n\nThe 'endpoint' argument is as described in xref:zmq_connect.adoc[zmq_connect]\n\nNOTE: The default setting of _ZMQ_LINGER_ does not discard unsent messages;\nthis behaviour may cause the application to block when calling _zmq_ctx_term()_.\nFor details refer to xref:zmq_setsockopt.adoc[zmq_setsockopt] and xref:zmq_ctx_term.adoc[zmq_ctx_term]\n\n== RETURN VALUE\nThe _zmq_disconnect()_ function shall return zero if successful. Otherwise it\nshall return `-1` and set 'errno' to one of the values defined below.\n\n== ERRORS\n*EINVAL*::\nThe endpoint supplied is invalid.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*ENOENT*::\nThe provided endpoint is not in use by the socket.\n\n\n== EXAMPLE\n.Connecting a subscriber socket to an in-process and a TCP transport\n----\n/* Create a ZMQ_SUB socket */\nvoid *socket = zmq_socket (context, ZMQ_SUB);\nassert (socket);\n/* Connect it to the host server001, port 5555 using a TCP transport */\nrc = zmq_connect (socket, \"tcp://server001:5555\");\nassert (rc == 0);\n/* Disconnect from the previously connected endpoint */\nrc = zmq_disconnect (socket, \"tcp://server001:5555\");\nassert (rc == 0);\n----\n\n== SEE ALSO\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_disconnect_peer.adoc",
    "content": "= zmq_disconnect_peer(3)\n\n\n== NAME\nzmq_disconnect_peer - disconnect a specific peer connection by routing id.\n\n\n== SYNOPSIS\n*int zmq_disconnect_peer (void '*socket', uint32_t 'routing_id');*\n\n\n== DESCRIPTION\nThe _zmq_disconnect_peer()_ function disconnects a specific connection from a\nsocket given the peer 'routing_id'. After a successful disconnection, attempts\nto send messages addressed with that 'routing_id' will fail with 'EHOSTUNREACH'\nuntil a new connection with a different 'routing_id' is established.\n\nThis function is supported on socket types that manage per-peer routing ids:\n'ZMQ_SERVER' and 'ZMQ_PEER'. Calling it on other socket types will fail with\n'ENOTSUP'.\n\n\n== RETURN VALUE\nThe _zmq_disconnect_peer()_ function returns `0` if successful. Otherwise it\nreturns `-1` and sets 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EHOSTUNREACH*::\nNo connection exists for the given 'routing_id'.\n*ENOTSUP*::\nThe socket type does not support disconnecting by 'routing_id'.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n\n\n== EXAMPLE\n.Disconnect a peer by routing id\n----\nvoid *server = zmq_socket (context, ZMQ_SERVER);\nassert (server);\nassert (zmq_bind (server, \"tcp://*:5555\") == 0);\n/* ... receive a message and read its routing id ... */\nuint32_t routing_id = /* obtained from zmq_msg_routing_id(...) */;\n/* Disconnect that specific peer */\nint rc = zmq_disconnect_peer (server, routing_id);\nassert (rc == 0);\n/* Any attempt to send to that routing id now will fail with EHOSTUNREACH */\n----\n\n\n== SEE ALSO\n* xref:zmq_connect_peer.adoc[zmq_connect_peer]\n* xref:zmq_disconnect.adoc[zmq_disconnect]\n* xref:zmq_msg_routing_id.adoc[zmq_msg_routing_id]\n* xref:zmq_msg_set_routing_id.adoc[zmq_msg_set_routing_id]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n\n\n"
  },
  {
    "path": "doc/zmq_errno.adoc",
    "content": "= zmq_errno(3)\n\n\n== NAME\nzmq_errno - retrieve value of errno for the calling thread\n\n\n== SYNOPSIS\n*int zmq_errno (void);*\n\n\n== DESCRIPTION\nThe _zmq_errno()_ function shall retrieve the value of the 'errno' variable for\nthe calling thread.\n\nThe _zmq_errno()_ function is provided to assist users on non-POSIX systems who\nare experiencing issues with retrieving the correct value of 'errno' directly.\nSpecifically, users on Win32 systems whose application is using a different C\nrun-time library from the C run-time library in use by 0MQ will need to use\n_zmq_errno()_ for correct operation.\n\nIMPORTANT: Users not experiencing issues with retrieving the correct value of\n'errno' should not use this function and should instead access the 'errno'\nvariable directly.\n\n\n== RETURN VALUE\nThe _zmq_errno()_ function shall return the value of the 'errno' variable for\nthe calling thread.\n\n\n== ERRORS\nNo errors are defined.\n\n\n== SEE ALSO\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_getsockopt.adoc",
    "content": "= zmq_getsockopt(3)\n\n\n== NAME\n\nzmq_getsockopt - get 0MQ socket options\n\n\n== SYNOPSIS\n*int zmq_getsockopt (void '*socket', int 'option_name', void '*option_value', size_t '*option_len');*\n\n\n== DESCRIPTION\nThe _zmq_getsockopt()_ function shall retrieve the value for the option\nspecified by the 'option_name' argument for the 0MQ socket pointed to by the\n'socket' argument, and store it in the buffer pointed to by the 'option_value'\nargument. The 'option_len' argument is the size in bytes of the buffer pointed\nto by 'option_value'; upon successful completion _zmq_getsockopt()_ shall\nmodify the 'option_len' argument to indicate the actual size of the option\nvalue stored in the buffer.\n\nThe following options can be retrieved with the _zmq_getsockopt()_ function:\n\n\nZMQ_AFFINITY: Retrieve I/O thread affinity\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_AFFINITY' option shall retrieve the I/O thread affinity for newly\ncreated connections on the specified 'socket'.\n\nAffinity determines which threads from the 0MQ I/O thread pool associated with\nthe socket's _context_ shall handle newly created connections.  A value of zero\nspecifies no affinity, meaning that work shall be distributed fairly among all\n0MQ I/O threads in the thread pool. For non-zero values, the lowest bit\ncorresponds to thread 1, second lowest bit to thread 2 and so on.  For example,\na value of 3 specifies that subsequent connections on 'socket' shall be handled\nexclusively by I/O threads 1 and 2.\n\nSee also xref:zmq_init.adoc[zmq_init] for details on allocating the number of I/O\nthreads for a specific _context_.\n\n[horizontal]\nOption value type:: uint64_t\nOption value unit:: N/A (bitmap)\nDefault value:: 0\nApplicable socket types:: N/A\n\n\nZMQ_BACKLOG: Retrieve maximum length of the queue of outstanding connections\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_BACKLOG' option shall retrieve the maximum length of the queue of\noutstanding peer connections for the specified 'socket'; this only applies to\nconnection-oriented transports. For details refer to your operating system\ndocumentation for the 'listen' function.\n\n[horizontal]\nOption value type:: int\nOption value unit:: connections\nDefault value:: 100\nApplicable socket types:: all, only for connection-oriented transports\n\n\nZMQ_BINDTODEVICE: Retrieve name of device the socket is bound to\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_BINDTODEVICE' option retrieves the name of the device this socket is\nbound to, eg. an interface or VRF. If a socket is bound to an interface, only\npackets received from that interface are processed by the socket. If device\nis a VRF device, then subsequent binds/connects to that socket use addresses\nin the VRF routing table.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all, when using TCP or UDP transports.\n\n\nZMQ_CONNECT_TIMEOUT: Retrieve connect() timeout\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRetrieves how long to wait before timing-out a connect() system call.\nThe connect() system call normally takes a long time before it returns a\ntime out error. Setting this option allows the library to time out the call\nat an earlier interval.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 0 (disabled)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_CURVE_PUBLICKEY: Retrieve current CURVE public key\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nRetrieves the current long term public key for the socket. You can\nprovide either a 32 byte buffer, to retrieve the binary key value, or\na 41 byte buffer, to retrieve the key in a printable Z85 format.\nNOTE: to fetch a printable key, the buffer must be 41 bytes large\nto hold the 40-char key value and one null byte.\n\n[horizontal]\nOption value type:: binary data or Z85 text string\nOption value size:: 32 or 41\nDefault value:: null\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_CURVE_SECRETKEY: Retrieve current CURVE secret key\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nRetrieves the current long term secret key for the socket. You can\nprovide either a 32 byte buffer, to retrieve the binary key value, or\na 41 byte buffer, to retrieve the key in a printable Z85 format.\nNOTE: to fetch a printable key, the buffer must be 41 bytes large\nto hold the 40-char key value and one null byte.\n\n[horizontal]\nOption value type:: binary data or Z85 text string\nOption value size:: 32 or 41\nDefault value:: null\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_CURVE_SERVERKEY: Retrieve current CURVE server key\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nRetrieves the current server key for the client socket. You can\nprovide either a 32 byte buffer, to retrieve the binary key value, or\na 41-byte buffer, to retrieve the key in a printable Z85 format.\nNOTE: to fetch a printable key, the buffer must be 41 bytes large\nto hold the 40-char key value and one null byte.\n\n[horizontal]\nOption value type:: binary data or Z85 text string\nOption value size:: 32 or 41\nDefault value:: null\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_EVENTS: Retrieve socket event state\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_EVENTS' option shall retrieve the event state for the specified\n'socket'.  The returned value is a bit mask constructed by OR'ing a combination\nof the following event flags:\n\n*ZMQ_POLLIN*::\nIndicates that at least one message may be received from the specified socket\nwithout blocking.\n\n*ZMQ_POLLOUT*::\nIndicates that at least one message may be sent to the specified socket without\nblocking.\n\nThe combination of a file descriptor returned by the 'ZMQ_FD' option being\nready for reading but no actual events returned by a subsequent retrieval of\nthe 'ZMQ_EVENTS' option is valid; applications should simply ignore this case\nand restart their polling operation/event loop.\n\n[horizontal]\nOption value type:: int\nOption value unit:: N/A (flags)\nDefault value:: N/A\nApplicable socket types:: all\n\n\nZMQ_FD: Retrieve file descriptor associated with the socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_FD' option shall retrieve the file descriptor associated with the\nspecified 'socket'. The returned file descriptor can be used to integrate the\nsocket into an existing event loop; the 0MQ library shall signal any pending\nevents on the socket in an _edge-triggered_ fashion by making the file\ndescriptor become ready for reading.\n\nNOTE: The ability to read from the returned file descriptor does not\nnecessarily indicate that messages are available to be read from, or can be\nwritten to, the underlying socket; applications must retrieve the actual event\nstate with a subsequent retrieval of the 'ZMQ_EVENTS' option.\n\nNOTE: The returned file descriptor is also used internally by the 'zmq_send'\nand 'zmq_recv' functions. As the descriptor is edge triggered, applications\nmust update the state of 'ZMQ_EVENTS' after each invocation of 'zmq_send'\nor 'zmq_recv'.To be more explicit: after calling 'zmq_send' the socket may\nbecome readable (and vice versa) without triggering a read event on the\nfile descriptor.\n\nCAUTION: The returned file descriptor is intended for use with a 'poll' or\nsimilar system call only. Applications must never attempt to read or write data\nto it directly, neither should they try to close it.\n\n[horizontal]\nOption value type:: int on POSIX systems, SOCKET on Windows\nOption value unit:: N/A\nDefault value:: N/A\nApplicable socket types:: all\n\n\nZMQ_GSSAPI_PLAINTEXT: Retrieve GSSAPI plaintext or encrypted status\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nReturns the 'ZMQ_GSSAPI_PLAINTEXT' option, if any, previously set on the\nsocket.  A value of '1' means  that communications will be plaintext.  A value\nof '0' means communications will be encrypted.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0 (false)\nApplicable socket types:: all, when using TCP or IPC transports\n\n\nZMQ_GSSAPI_PRINCIPAL: Retrieve the name of the GSSAPI principal\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_GSSAPI_PRINCIPAL' option shall retrieve the principal name set for the\nGSSAPI security mechanism. The returned value shall be a NULL-terminated string\nand MAY be empty. The returned size SHALL include the terminating null byte.\n\n[horizontal]\nOption value type:: NULL-terminated character string\nOption value unit:: N/A\nDefault value:: null string\nApplicable socket types:: all, when using TCP or IPC transports\n\n\nZMQ_GSSAPI_SERVER: Retrieve current GSSAPI server role\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nReturns the 'ZMQ_GSSAPI_SERVER' option, if any, previously set on the socket.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0 (false)\nApplicable socket types:: all, when using TCP or IPC transports\n\n\nZMQ_GSSAPI_SERVICE_PRINCIPAL: Retrieve the name of the GSSAPI service principal\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_GSSAPI_SERVICE_PRINCIPAL' option shall retrieve the principal name of\nthe GSSAPI server to which a GSSAPI client socket intends to connect.  The\nreturned value shall be a NULL-terminated string and MAY be empty. The returned\nsize SHALL include the terminating null byte.\n\n[horizontal]\nOption value type:: NULL-terminated character string\nOption value unit:: N/A\nDefault value:: null string\nApplicable socket types:: all, when using TCP or IPC transports\n\nZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE: Retrieve nametype for service principal\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nReturns the 'ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE' option, if any, previously\nset on the socket.  A value of 'ZMQ_GSSAPI_NT_HOSTBASED' (0) means the name\nspecified with 'ZMQ_GSSAPI_SERVICE_PRINCIPAL' is interpreted as a host based\nname.  A value of 'ZMQ_GSSAPI_NT_USER_NAME' (1) means it is interpreted as\na local user name.  A value of 'ZMQ_GSSAPI_NT_KRB5_PRINCIPAL' (2) means it\nis interpreted as an unparsed principal name string (valid only with the\nkrb5 GSSAPI mechanism).\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1, 2\nDefault value:: 0 (ZMQ_GSSAPI_NT_HOSTBASED)\nApplicable socket types:: all, when using TCP or IPC transports\n\nZMQ_GSSAPI_PRINCIPAL_NAMETYPE: Retrieve nametype for service principal\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nReturns the 'ZMQ_GSSAPI_PRINCIPAL_NAMETYPE' option, if any, previously\nset on the socket.  A value of 'ZMQ_GSSAPI_NT_HOSTBASED' (0) means the name\nspecified with 'ZMQ_GSSAPI_PRINCIPAL' is interpreted as a host based\nname.  A value of 'ZMQ_GSSAPI_NT_USER_NAME' (1) means it is interpreted as\na local user name.  A value of 'ZMQ_GSSAPI_NT_KRB5_PRINCIPAL' (2) means it\nis interpreted as an unparsed principal name string (valid only with the\nkrb5 GSSAPI mechanism).\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1, 2\nDefault value:: 0 (ZMQ_GSSAPI_NT_HOSTBASED)\nApplicable socket types:: all, when using TCP or IPC transports\n\nZMQ_HANDSHAKE_IVL: Retrieve maximum handshake interval\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_HANDSHAKE_IVL' option shall retrieve the maximum handshake interval\nfor the specified 'socket'. Handshaking is the exchange of socket configuration\ninformation (socket type, routing id, security) that occurs when a connection\nis first opened, only for connection-oriented transports. If handshaking does\nnot complete within the configured time, the connection shall be closed.\nThe value 0 means no handshake time limit.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 30000\nApplicable socket types:: all but ZMQ_STREAM, only for connection-oriented transports\n\n\nZMQ_IDENTITY: Retrieve socket identity\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThis option name is now deprecated. Use ZMQ_ROUTING_ID instead.\nZMQ_IDENTITY remains as an alias for now.\n\n\nZMQ_IMMEDIATE: Retrieve attach-on-connect value\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRetrieve the state of the attach on connect value. If set to `1`, will delay the\nattachment of a pipe on connect until the underlying connection has completed.\nThis will cause the socket to block if there are no other connections, but will\nprevent queues from filling on pipes awaiting connection.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 0 (false)\nApplicable socket types:: all, primarily when using TCP/IPC transports.\n\n\nZMQ_INVERT_MATCHING: Retrieve inverted filtering status\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nReturns the value of the 'ZMQ_INVERT_MATCHING' option. A value of `1`\nmeans the socket uses inverted prefix matching.\n\nOn 'PUB' and 'XPUB' sockets, this causes messages to be sent to all\nconnected sockets 'except' those subscribed to a prefix that matches\nthe message. On 'SUB' sockets, this causes only incoming messages that\ndo 'not' match any of the socket's subscriptions to be received by the user.\n\nWhenever 'ZMQ_INVERT_MATCHING' is set to 1 on a 'PUB' socket, all 'SUB'\nsockets connecting to it must also have the option set to 1. Failure to\ndo so will have the 'SUB' sockets reject everything the 'PUB' socket sends\nthem. 'XSUB' sockets do not need to do this because they do not filter\nincoming messages.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0,1\nDefault value:: 0\nApplicable socket types:: ZMQ_PUB, ZMQ_XPUB, ZMQ_SUB\n\n\nZMQ_IPV4ONLY: Retrieve IPv4-only socket override status\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRetrieve the IPv4-only option for the socket. This option is deprecated.\nPlease use the ZMQ_IPV6 option.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 1 (true)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_IPV6: Retrieve IPv6 socket status\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRetrieve the IPv6 option for the socket. A value of `1` means IPv6 is\nenabled on the socket, while `0` means the socket will use only IPv4.\nWhen IPv6 is enabled the socket will connect to, or accept connections\nfrom, both IPv4 and IPv6 hosts.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 0 (false)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_LAST_ENDPOINT: Retrieve the last endpoint set\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_LAST_ENDPOINT' option shall retrieve the last endpoint bound for\nTCP and IPC transports. The returned value will be a string in the form of\na ZMQ DSN. Note that if the TCP host is INADDR_ANY, indicated by a *, then\nthe returned address will be 0.0.0.0 (for IPv4).\nNote: not supported on GNU/Hurd with IPC due to non-working getsockname().\n\n[horizontal]\nOption value type:: NULL-terminated character string\nOption value unit:: N/A\nDefault value:: NULL\nApplicable socket types:: all, when binding TCP or IPC transports\n\n\nZMQ_LINGER: Retrieve linger period for socket shutdown\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_LINGER' option shall retrieve the linger period for the specified\n'socket'.  The linger period determines how long pending messages which have\nyet to be sent to a peer shall linger in memory after a socket is closed with\nxref:zmq_close.adoc[zmq_close], and further affects the termination of the socket's\ncontext with xref:zmq_ctx_term.adoc[zmq_ctx_term] The following outlines the different\nbehaviours:\n\n* The default value of '-1' specifies an infinite linger period. Pending\n  messages shall not be discarded after a call to _zmq_close()_; attempting to\n  terminate the socket's context with _zmq_ctx_term()_ shall block until all\n  pending messages have been sent to a peer.\n\n* The value of '0' specifies no linger period. Pending messages shall be\n  discarded immediately when the socket is closed with _zmq_close()_.\n\n* Positive values specify an upper bound for the linger period in milliseconds.\n  Pending messages shall not be discarded after a call to _zmq_close()_;\n  attempting to terminate the socket's context with _zmq_ctx_term()_ shall block\n  until either all pending messages have been sent to a peer, or the linger\n  period expires, after which any pending messages shall be discarded.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: -1 (infinite)\nApplicable socket types:: all\n\n\nZMQ_MAXMSGSIZE: Maximum acceptable inbound message size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe option shall retrieve limit for the inbound messages. If a peer sends\na message larger than ZMQ_MAXMSGSIZE it is disconnected. Value of -1 means\n'no limit'.\n\n[horizontal]\nOption value type:: int64_t\nOption value unit:: bytes\nDefault value:: -1\nApplicable socket types:: all\n\n\nZMQ_MECHANISM: Retrieve current security mechanism\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_MECHANISM' option shall retrieve the current security mechanism\nfor the socket.\n\n[horizontal]\nOption value type:: int\nOption value unit:: ZMQ_NULL, ZMQ_PLAIN, ZMQ_CURVE, or ZMQ_GSSAPI\nDefault value:: ZMQ_NULL\nApplicable socket types:: all, when using TCP or IPC transports\n\n\nZMQ_MULTICAST_HOPS: Maximum network hops for multicast packets\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe option shall retrieve time-to-live used for outbound multicast packets.\nThe default of 1 means that the multicast packets don't leave the local network.\n\n[horizontal]\nOption value type:: int\nOption value unit:: network hops\nDefault value:: 1\nApplicable socket types:: all, when using multicast transports\n\n\nZMQ_MULTICAST_MAXTPDU: Maximum transport data unit size for multicast packets\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_MULTICAST_MAXTPDU' option shall retrieve the maximum transport\ndata unit size used for outbound multicast packets.\n\nThis must be set at or below the minimum Maximum Transmission Unit (MTU) for\nall network paths over which multicast reception is required.\n\n[horizontal]\nOption value type:: int\nOption value unit:: bytes\nDefault value:: 1500\nApplicable socket types:: all, when using multicast transports\n\n\nZMQ_PLAIN_PASSWORD: Retrieve current password\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_PLAIN_PASSWORD' option shall retrieve the last password set for\nthe PLAIN security mechanism. The returned value shall be a NULL-terminated\nstring and MAY be empty. The returned size SHALL include the terminating\nnull byte.\n\n[horizontal]\nOption value type:: NULL-terminated character string\nOption value unit:: N/A\nDefault value:: null string\nApplicable socket types:: all, when using TCP or IPC transports\n\n\nZMQ_PLAIN_SERVER: Retrieve current PLAIN server role\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nReturns the 'ZMQ_PLAIN_SERVER' option, if any, previously set on the socket.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: int\nApplicable socket types:: all, when using TCP or IPC transports\n\n\nZMQ_PLAIN_USERNAME: Retrieve current PLAIN username\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_PLAIN_USERNAME' option shall retrieve the last username set for\nthe PLAIN security mechanism. The returned value shall be a NULL-terminated\nstring and MAY be empty. The returned size SHALL include the terminating\nnull byte.\n\n[horizontal]\nOption value type:: NULL-terminated character string\nOption value unit:: N/A\nDefault value:: null string\nApplicable socket types:: all, when using TCP or IPC transports\n\n\nZMQ_USE_FD: Retrieve the pre-allocated socket file descriptor\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_USE_FD' option shall retrieve the pre-allocated file\ndescriptor that has been assigned to a ZMQ socket, if any. -1 shall be\nreturned if a pre-allocated file descriptor was not set for the socket.\n\n[horizontal]\nOption value type:: int\nOption value unit:: file descriptor\nDefault value:: -1\nApplicable socket types:: all bound sockets, when using IPC or TCP transport\n\n\nZMQ_PRIORITY: Retrieve the Priority on socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets the protocol-defined priority for all packets to be sent on this\nsocket, where supported by the OS.\n\n[horizontal]\nOption value type:: int\nOption value unit:: >0\nDefault value:: 0\nApplicable socket types:: all, only for connection-oriented transports\n\n\nZMQ_RATE: Retrieve multicast data rate\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RATE' option shall retrieve the maximum send or receive data rate for\nmulticast transports using the specified 'socket'.\n\n[horizontal]\nOption value type:: int\nOption value unit:: kilobits per second\nDefault value:: 100\nApplicable socket types:: all, when using multicast transports\n\n\nZMQ_RCVBUF: Retrieve kernel receive buffer size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RCVBUF' option shall retrieve the underlying kernel receive buffer\nsize for the specified 'socket'. For details refer to your operating system\ndocumentation for the 'SO_RCVBUF' socket option.\n\n[horizontal]\nOption value type:: int\nOption value unit:: bytes\nDefault value:: 8192\nApplicable socket types:: all\n\n\nZMQ_RCVHWM: Retrieve high water mark for inbound messages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RCVHWM' option shall return the high water mark for inbound messages on\nthe specified 'socket'. The high water mark is a hard limit on the maximum\nnumber of outstanding messages 0MQ shall queue in memory for any single peer\nthat the specified 'socket' is communicating with. A value of zero means no\nlimit.\n\nIf this limit has been reached the socket shall enter an exceptional state and\ndepending on the socket type, 0MQ shall take appropriate action such as\nblocking or dropping sent messages. Refer to the individual socket descriptions\nin xref:zmq_socket.adoc[zmq_socket] for details on the exact action taken for each socket\ntype.\n\n[horizontal]\nOption value type:: int\nOption value unit:: messages\nDefault value:: 1000\nApplicable socket types:: all\n\n\nZMQ_RCVMORE: More message data parts to follow\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RCVMORE' option shall return True (1) if the message part last\nreceived from the 'socket' was a data part with more parts to follow. If there\nare no data parts to follow, this option shall return False (0).\n\nRefer to xref:zmq_send.adoc[zmq_send] and xref:zmq_recv.adoc[zmq_recv] for a detailed description\nof multi-part messages.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: N/A\nApplicable socket types:: all\n\n\nZMQ_RCVTIMEO: Maximum time before a socket operation returns with EAGAIN\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRetrieve the timeout for recv operation on the socket.  If the value is `0`,\n_zmq_recv(3)_ will return immediately, with a EAGAIN error if there is no\nmessage to receive. If the value is `-1`, it will block until a message is\navailable. For all other values, it will wait for a message for that amount\nof time before returning with an EAGAIN error.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: -1 (infinite)\nApplicable socket types:: all\n\n\nZMQ_RECONNECT_IVL: Retrieve reconnection interval\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RECONNECT_IVL' option shall retrieve the initial reconnection interval\nfor the specified 'socket'.  The reconnection interval is the period 0MQ shall\nwait between attempts to reconnect disconnected peers when using\nconnection-oriented transports. The value -1 means no reconnection.\n\nNOTE: The reconnection interval may be randomized by 0MQ to prevent\nreconnection storms in topologies with a large number of peers per socket.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 100\nApplicable socket types:: all, only for connection-oriented transports\n\n\nZMQ_RECONNECT_IVL_MAX: Retrieve max reconnection interval\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RECONNECT_IVL_MAX' option shall retrieve the max reconnection interval\nfor the specified 'socket'. 0MQ shall wait at most the configured interval between\nreconnection attempts. The interval grows exponentionally (i.e.: it is doubled)\nwith each attempt until it reaches ZMQ_RECONNECT_IVL_MAX. Default value means\nthat the reconnect interval is based exclusively on ZMQ_RECONNECT_IVL and no\nexponential backoff is performed.\n\nNOTE:  Value has to be greater or equal than ZMQ_RECONNECT_IVL, or else it will\n       be ignored.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 0 (ZMQ_RECONNECT_IVL will be used)\nApplicable socket types:: all, only for connection-oriented transport\n\n\nZMQ_RECONNECT_STOP: Retrieve condition where reconnection will stop\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RECONNECT_STOP' option shall retrieve the conditions under which\nautomatic reconnection will stop.\n\nThe 'ZMQ_RECONNECT_STOP_CONN_REFUSED' option will stop reconnection when 0MQ\nreceives the ECONNREFUSED return code from the connect.  This indicates that\nthere is no code bound to the specified endpoint.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 'ZMQ_RECONNECT_STOP_CONN_REFUSED'\nDefault value:: 0\nApplicable socket types:: all, only for connection-oriented transports\n\n\nZMQ_RECOVERY_IVL: Get multicast recovery interval\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RECOVERY_IVL' option shall retrieve the recovery interval for\nmulticast transports using the specified 'socket'.  The recovery interval\ndetermines the maximum time in milliseconds that a receiver can be absent from a\nmulticast group before unrecoverable data loss will occur.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 10000\nApplicable socket types:: all, when using multicast transports\n\n\nZMQ_ROUTING_ID: Retrieve socket routing id\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_ROUTING_ID' option shall retrieve the routing id of the specified 'socket'.\nRouting ids are used only by the request/reply pattern. Specifically, it can be used\nin tandem with ROUTER socket to route messages to the peer with a specific\nrouting id.\n\nA routing id must be at least one byte and at most 255 bytes long. Identities\nstarting with a zero byte are reserved for use by the 0MQ infrastructure.\n\n[horizontal]\nOption value type:: binary data\nOption value unit:: N/A\nDefault value:: NULL\nApplicable socket types:: ZMQ_REP, ZMQ_REQ, ZMQ_ROUTER, ZMQ_DEALER.\n\n\nZMQ_SNDBUF: Retrieve kernel transmit buffer size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_SNDBUF' option shall retrieve the underlying kernel transmit buffer\nsize for the specified 'socket'. For details refer to your operating system\ndocumentation for the 'SO_SNDBUF' socket option.\n\n[horizontal]\nOption value type:: int\nOption value unit:: bytes\nDefault value:: 8192\nApplicable socket types:: all\n\n\nZMQ_SNDHWM: Retrieves high water mark for outbound messages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_SNDHWM' option shall return the high water mark for outbound messages\non the specified 'socket'. The high water mark is a hard limit on the maximum\nnumber of outstanding messages 0MQ shall queue in memory for any single peer\nthat the specified 'socket' is communicating with. A value of zero means no\nlimit.\n\nIf this limit has been reached the socket shall enter an exceptional state and\ndepending on the socket type, 0MQ shall take appropriate action such as\nblocking or dropping sent messages. Refer to the individual socket descriptions\nin xref:zmq_socket.adoc[zmq_socket] for details on the exact action taken for each socket\ntype.\n\n[horizontal]\nOption value type:: int\nOption value unit:: messages\nDefault value:: 1000\nApplicable socket types:: all\n\n\nZMQ_SNDTIMEO: Maximum time before a socket operation returns with EAGAIN\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRetrieve the timeout for send operation on the socket. If the value is `0`,\n_zmq_send(3)_ will return immediately, with a EAGAIN error if the message\ncannot be sent. If the value is `-1`, it will block until the message is sent.\nFor all other values, it will try to send the message for that amount of time\nbefore returning with an EAGAIN error.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: -1 (infinite)\nApplicable socket types:: all\n\n\nZMQ_SOCKS_PROXY: Retrieve SOCKS5 proxy address\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_SOCKS_PROXY' option shall retrieve the SOCKS5 proxy address in string\nformat. The returned value shall be a NULL-terminated string and MAY be empty.\nThe returned size SHALL include the terminating null byte.\n\n[horizontal]\nOption value type:: NULL-terminated character string\nOption value unit:: N/A\nDefault value:: null string\nApplicable socket types:: all, when using TCP transports\n\n\nZMQ_TCP_KEEPALIVE: Override SO_KEEPALIVE socket option\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOverride 'SO_KEEPALIVE' socket option(where supported by OS).\nThe default value of `-1` means to skip any overrides and leave it to OS default.\n\n[horizontal]\nOption value type:: int\nOption value unit:: -1,0,1\nDefault value:: -1 (leave to OS default)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_TCP_KEEPALIVE_CNT: Override TCP_KEEPCNT socket option\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOverride 'TCP_KEEPCNT' socket option(where supported by OS).\nThe default value of `-1` means to skip any overrides and leave it to OS default.\n\n[horizontal]\nOption value type:: int\nOption value unit:: -1,>0\nDefault value:: -1 (leave to OS default)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_TCP_KEEPALIVE_IDLE: Override TCP_KEEPIDLE (or TCP_KEEPALIVE on some OS)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOverride 'TCP_KEEPIDLE'(or 'TCP_KEEPALIVE' on some OS) socket option (where\nsupported by OS). The default value of `-1` means to skip any overrides and\nleave it to OS default.\n\n[horizontal]\nOption value type:: int\nOption value unit:: -1,>0\nDefault value:: -1 (leave to OS default)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_TCP_KEEPALIVE_INTVL: Override TCP_KEEPINTVL socket option\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOverride 'TCP_KEEPINTVL' socket option(where supported by OS).\nThe default value of `-1` means to skip any overrides and leave it to OS default.\n\n[horizontal]\nOption value type:: int\nOption value unit:: -1,>0\nDefault value:: -1 (leave to OS default)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_TCP_MAXRT: Retrieve Max TCP Retransmit Timeout\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOn OSes where it is supported, retrieves how long before an unacknowledged TCP\nretransmit times out. The system normally attempts many TCP retransmits\nfollowing an exponential backoff strategy. This means that after a network\noutage, it may take a long time before the session can be re-established.\nSetting this option allows the timeout to happen at a shorter interval.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 0 (leave to OS default)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_THREAD_SAFE: Retrieve socket thread safety\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_THREAD_SAFE' option shall retrieve a boolean value indicating whether\nor not the socket is threadsafe. See xref:zmq_socket.adoc[zmq_socket] for which sockets are\nthread-safe.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nApplicable socket types:: all\n\n\nZMQ_TOS: Retrieve the Type-of-Service socket override status\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRetrieve the IP_TOS option for the socket.\n\n[horizontal]\nOption value type:: int\nOption value unit:: >0\nDefault value:: 0\nApplicable socket types:: all, only for connection-oriented transports\n\n\nZMQ_TYPE: Retrieve socket type\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_TYPE' option shall retrieve the socket type for the specified\n'socket'.  The socket type is specified at socket creation time and\ncannot be modified afterwards.\n\n[horizontal]\nOption value type:: int\nOption value unit:: N/A\nDefault value:: N/A\nApplicable socket types:: all\n\n\nZMQ_ZAP_DOMAIN: Retrieve RFC 27 authentication domain\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe 'ZMQ_ZAP_DOMAIN' option shall retrieve the last ZAP domain set for\nthe socket. The returned value shall be a NULL-terminated string and MAY\nbe empty. An empty string means that ZAP authentication is disabled.\nThe returned size SHALL include the terminating null byte.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_ZAP_ENFORCE_DOMAIN: Retrieve ZAP domain handling mode\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_ZAP_ENFORCE_DOMAIN' option shall retrieve the flag that determines\nwhether a ZAP domain is strictly required or not.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: all, when using ZAP\n\n\nZMQ_VMCI_BUFFER_SIZE: Retrieve buffer size of the VMCI socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe `ZMQ_VMCI_BUFFER_SIZE` option shall retrieve the size of the underlying\nbuffer for the socket. Used during negotiation before the connection is established.\n\n[horizontal]\nOption value type:: uint64_t\nOption value unit:: bytes\nDefault value:: 65546\nApplicable socket types:: all, when using VMCI transport\n\n\nZMQ_VMCI_BUFFER_MIN_SIZE: Retrieve min buffer size of the VMCI socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe `ZMQ_VMCI_BUFFER_MIN_SIZE` option shall retrieve the min size of the underlying\nbuffer for the socket. Used during negotiation before the connection is established.\n\n[horizontal]\nOption value type:: uint64_t\nOption value unit:: bytes\nDefault value:: 128\nApplicable socket types:: all, when using VMCI transport\n\n\nZMQ_VMCI_BUFFER_MAX_SIZE: Retrieve max buffer size of the VMCI socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe `ZMQ_VMCI_BUFFER_MAX_SIZE` option shall retrieve the max size of the underlying\nbuffer for the socket. Used during negotiation before the connection is established.\n\n[horizontal]\nOption value type:: uint64_t\nOption value unit:: bytes\nDefault value:: 262144\nApplicable socket types:: all, when using VMCI transport\n\n\nZMQ_VMCI_CONNECT_TIMEOUT: Retrieve connection timeout of the VMCI socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe `ZMQ_VMCI_CONNECT_TIMEOUT` option shall retrieve connection timeout\nfor the socket.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: -1\nApplicable socket types:: all, when using VMCI transport\n\n\nZMQ_MULTICAST_LOOP: Retrieve multicast local loopback configuration\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRetrieve the current multicast loopback configuration. A value of `1`\nmeans that the multicast packets sent on this socket will be looped\nback to local listening interface.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 1\nApplicable socket types:: ZMQ_RADIO, when using UDP multicast transport\n\n\nZMQ_ROUTER_NOTIFY: Retrieve router socket notification settings\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRetrieve the current notification settings of a router socket. The returned\nvalue is a bitmask composed of ZMQ_NOTIFY_CONNECT and ZMQ_NOTIFY_DISCONNECT\nflags, meaning connect and disconnect notifications are enabled, respectively.\nA value of '0' means the notifications are off.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, ZMQ_NOTIFY_CONNECT, ZMQ_NOTIFY_DISCONNECT, ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT\nDefault value:: 0\nApplicable socket types:: ZMQ_ROUTER\n\n\nZMQ_IN_BATCH_SIZE: Maximal receive batch size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets the maximal amount of messages that can be received in a single\n'recv' system call.\n\nCannot be zero.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: messages\nDefault value:: 8192\nApplicable socket types:: All, when using TCP, IPC, PGM or NORM transport.\n\n\nZMQ_OUT_BATCH_SIZE: Maximal send batch size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets the maximal amount of messages that can be sent in a single\n'send' system call.\n\nCannot be zero.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: messages\nDefault value:: 8192\nApplicable socket types:: All, when using TCP, IPC, PGM or NORM transport.\n\n\nZMQ_TOPICS_COUNT: Number of topic subscriptions received\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets the number of topic (prefix) subscriptions either\n* received on a (X)PUB socket from all the connected (X)SUB sockets or\n* acknowledged on an (X)SUB socket from all the connected (X)PUB sockets\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: N/A\nDefault value:: 0\nApplicable socket types:: ZMQ_PUB, ZMQ_XPUB, ZMQ_SUB, ZMQ_XSUB\n\n\nZMQ_NORM_MODE: Retrieve NORM Sender Mode\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets the NORM sender mode to control the operation of the NORM transport. NORM\nsupports fixed rate operation (0='ZMQ_NORM_FIXED'), congestion control mode \n(1='ZMQ_NORM_CC'), loss-tolerant congestion control (2='ZMQ_NORM_CCL'), explicit\ncongestion notification (ECN)-enabled congestion control (3='ZMQ_NORM_CCE'), and\nECN-only congestion control (4='ZMQ_NORM_CCE_ECNONLY'). The default value is \nTCP-friendly congestion control mode. Fixed rate mode (using datarate set by\n'ZMQ_RATE') offers better performance, but care must be taken to prevent data\nloss.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1, 2, 3, 4\nDefault value:: 1 ('ZMQ_NORM_CC')\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_UNICAST_NACK: Retrieve NORM Unicast NACK mode\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nRetrieves status of NORM unicast NACK mode setting for multicast receivers. If\nset, NORM receiver will send Negative ACKnowledgements (NACKs) back to the\nsender using unicast instead of multicast.  NORM transport endpoints specifying\na unicast address will use unicast NACKs by default (without setting\n'ZMQ_NORM_UNICAST_NACK').\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 0 (false)\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_BUFFER_SIZE: Retrieve NORM buffer size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets NORM buffer size for NORM transport sender, receiver, and stream.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: kilobytes\nDefault value:: 2048\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_SEGMENT_SIZE: Retrieve NORM segment size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets NORM sender segment size, which is the maximum message payload size of\nindividual NORM messages (ZMQ messages may be split over multiple NORM\nmessages).  Ideally, this value should fit within the system/network maximum\ntransmission unit (MTU) after accounting for additional NORM message headers\n(up to 48 bytes).\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: bytes\nDefault value:: 1400\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_BLOCK_SIZE: Retrieve NORM block size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets NORM sender block size, which is the number of segments in a NORM FEC\ncoding block. NORM repair operations take place at block boundaries. Maximum\nvalue is 255, but parity packets ('ZMQ_NORM_NUM_PARITY') are limited to a value\nof (255 - 'ZMQ_NORM_BLOCK_SIZE'). Minimum value is ('ZMQ_NORM_NUM_PARITY' + 1).\nEffective value may be different based on the settings of 'ZMQ_NORM_NUM_PARITY'\nand 'ZMQ_NORM_NUM_AUTOPARITY' if invalid settings are provided.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: >0, <=255\nDefault value:: 16\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_NUM_PARITY: Retrieve NORM parity segment setting\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets the maximum number of NORM parity symbol segments that the sender is\nwilling to calculate per FEC coding block for the purpose of reparing lost data.\nMaximum value is 255, but is further limited to a value of\n(255 - 'ZMQ_NORM_BLOCK_SIZE'). Minimum value is 'ZMQ_NORM_NUM_AUTOPARITY'.\nEffective value may be different based on the setting of\n'ZMQ_NORM_NUM_AUTOPARITY' if invalid settings are provided.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: >0, <255\nDefault value:: 4\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_NUM_AUTOPARITY: Retrieve proactive NORM parity segment setting\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets the number of NORM parity symbol segments that the sender will proactively\nsend at the end of each FEC coding block. By default, no proactive parity\nsegments will be sent; instead, parity segments will only be sent in response to\nrepair requests (NACKs). Maximum value is 255, but is further limited to a \nmaximum value of 'ZMQ_NORM_NUM_PARITY'.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: >=0, <255\nDefault value:: 0\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_PUSH: Retrieve NORM push mode\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGets status of NORM stream push mode, which alters the behavior of the sender\nwhen enqueueing new data. By default, NORM will stop accepting new messages\nwhile waiting for old data to be transmitted and/or repaired. Enabling push mode\ndiscards the oldest data (which may be pending repair or may never have been\ntransmitted) in favor of accepting new data. This may be useful in cases where\nit is more important to quickly deliver new data instead of reliably delivering\nolder data.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 0 (false)\nApplicable socket types:: All, when using NORM transport.\n\n\n== RETURN VALUE\nThe _zmq_getsockopt()_ function shall return zero if successful. Otherwise it\nshall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EINVAL*::\nThe requested option _option_name_ is unknown, or the requested _option_len_ or\n_option_value_ is invalid, or the size of the buffer pointed to by\n_option_value_, as specified by _option_len_, is insufficient for storing the\noption value.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EINTR*::\nThe operation was interrupted by delivery of a signal.\n\n\n== EXAMPLE\n.Retrieving the high water mark for outgoing messages\n----\n/* Retrieve high water mark into sndhwm */\nint sndhwm;\nsize_t sndhwm_size = sizeof (sndhwm);\nrc = zmq_getsockopt (socket, ZMQ_SNDHWM, &sndhwm, &sndhwm_size);\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_gssapi.adoc",
    "content": "= zmq_gssapi(7)\n\n\n== NAME\nzmq_gssapi - secure authentication and confidentiality\n\n\n== SYNOPSIS\n\nThe GSSAPI mechanism defines a mechanism for secure authentication and\nconfidentiality for communications between a client and a server using the\nGeneric Security Service Application Program Interface (GSSAPI).  The GSSAPI\nmechanism can be used on both public and private networks.  GSSAPI itself is\ndefined in IETF RFC-2743: <http://tools.ietf.org/html/rfc2743>. The ZeroMQ\nGSSAPI mechanism is defined by this document: <http://rfc.zeromq.org/spec:38>.\n\n\n== CLIENT AND SERVER ROLES\nA socket using GSSAPI can be either client or server, but not both.\n\nTo become a GSSAPI server, the application sets the ZMQ_GSSAPI_SERVER\noption on the socket.\n\nTo become a GSSAPI client, the application sets the ZMQ_GSSAPI_SERVICE_PRINCIPAL\noption to the name of the principal on the server to which it intends to\nconnect.\n\nOn client or server, the application may additionally set the\nZMQ_GSSAPI_PRINCIPAL option to provide the socket with the name of the\nprincipal for whom GSSAPI credentials should be acquired.  If this option\nis not set, default credentials are used.\n\n\n== OPTIONAL ENCRYPTION\nBy default, the GSSAPI mechanism will encrypt all communications between client\nand server.  If encryption is not desired (e.g. on private networks), the\nclient and server applications can disable it by setting the\nZMQ_GSSAPI_PLAINTEXT option.  Both the client and server must set this option\nto the same value.\n\n\n== PRINCIPAL NAMES\nPrincipal names specified with the ZMQ_GSSAPI_SERVICE_PRINCIPAL or\nZMQ_GSSAPI_PRINCIPAL options are interpreted as \"host based\" name types\nby default.  The ZMQ_GSSAPI_PRINCIPAL_NAMETYPE and\nZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE options may be used to change the\nname type to one of:\n\n*ZMQ_GSSAPI_NT_HOSTBASED*::\nThe name should be of the form \"service\" or \"service@hostname\",\nwhich will parse into a principal of \"service/hostname\"\nin the local realm.  This is the default name type.\n*ZMQ_GSSAPI_NT_USER_NAME*::\nThe name should be a local username, which will parse into a single-component\nprincipal in the local realm.\n*ZMQ_GSSAPI_NT_KRB5_PRINCIPAL*::\nThe name is a principal name string.  This name type only works with\nthe krb5 GSSAPI mechanism.\n\n\n== SEE ALSO\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq_null.adoc[zmq_null]\n* xref:zmq_curve.adoc[zmq_curve]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_has.adoc",
    "content": "= zmq_has(3)\n\n\n== NAME\nzmq_has - check a ZMQ capability\n\n\n== SYNOPSIS\n*int zmq_has (const char *capability);*\n\n\n== DESCRIPTION\nThe _zmq_has()_ function shall report whether a specified capability is\navailable in the library. This allows bindings and applications to probe\na library directly, for transport and security options.\n\nCapabilities shall be lowercase strings. The following capabilities are\ndefined:\n\n* ipc - the library supports the ipc:// protocol\n* pgm - the library supports the pgm:// protocol\n* tipc - the library supports the tipc:// protocol\n* norm - the library supports the norm:// protocol\n* curve - the library supports the CURVE security mechanism\n* gssapi - the library supports the GSSAPI security mechanism\n* draft - the library is built with the draft api\n\nWhen this method is provided, the zmq.h header file will define\nZMQ_HAS_CAPABILITIES.\n\n== RETURN VALUE\nThe _zmq_has()_ function shall return 1 if the specified capability is\nprovided. Otherwise it shall return 0.\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_inproc.adoc",
    "content": "= zmq_inproc(7)\n\n\n== NAME\nzmq_inproc - 0MQ local in-process (inter-thread) communication transport\n\n\n== SYNOPSIS\nThe in-process transport passes messages via memory directly between threads\nsharing a single 0MQ 'context'.\n\nNOTE: No I/O threads are involved in passing messages using the 'inproc'\ntransport. Therefore, if you are using a 0MQ 'context' for in-process messaging\nonly you can initialise the 'context' with zero I/O threads. See\nxref:zmq_init.adoc[zmq_init] for details.\n\n\n== ADDRESSING\nA 0MQ endpoint is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to connect to.\n\nFor the in-process transport, the transport is `inproc`, and the meaning of\nthe 'address' part is defined below.\n\n\nAssigning a local address to a socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen assigning a local address to a 'socket' using _zmq_bind()_ with the\n'inproc' transport, the 'endpoint' shall be interpreted as an arbitrary string\nidentifying the 'name' to create. The 'name' must be unique within the 0MQ\n'context' associated with the 'socket' and may be up to 256 characters in\nlength.  No other restrictions are placed on the format of the 'name'.\n\n\nConnecting a socket\n~~~~~~~~~~~~~~~~~~~\nWhen connecting a 'socket' to a peer address using _zmq_connect()_ with the\n'inproc' transport, the 'endpoint' shall be interpreted as an arbitrary string\nidentifying the 'name' to connect to.  Before version 4.0 he 'name' must have\nbeen previously created by assigning it to at least one 'socket' within the\nsame 0MQ 'context' as the 'socket' being connected.  Since version 4.0 the\norder of _zmq_bind()_ and _zmq_connect()_ does not matter just like for the tcp\ntransport type.\n\n\n== EXAMPLES\n.Assigning a local address to a socket\n----\n//  Assign the in-process name \"#1\"\nrc = zmq_bind(socket, \"inproc://#1\");\nassert (rc == 0);\n//  Assign the in-process name \"my-endpoint\"\nrc = zmq_bind(socket, \"inproc://my-endpoint\");\nassert (rc == 0);\n----\n\n.Connecting a socket\n----\n//  Connect to the in-process name \"#1\"\nrc = zmq_connect(socket, \"inproc://#1\");\nassert (rc == 0);\n//  Connect to the in-process name \"my-endpoint\"\nrc = zmq_connect(socket, \"inproc://my-endpoint\");\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_ipc.adoc[zmq_ipc]\n* xref:zmq_tcp.adoc[zmq_tcp]\n* xref:zmq_pgm.adoc[zmq_pgm]\n* xref:zmq_vmci.adoc[zmq_vmci]\n* xref:zmq_vsock.adoc[zmq_vsock]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_ipc.adoc",
    "content": "= zmq_ipc(7)\n\n\n== NAME\nzmq_ipc - 0MQ local inter-process communication transport\n\n\n== SYNOPSIS\nThe inter-process transport passes messages between local processes using a\nsystem-dependent IPC mechanism.\n\nNOTE: The inter-process transport is currently only implemented on operating\nsystems that provide UNIX domain sockets.\n\n\n== ADDRESSING\nA 0MQ endpoint is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to connect to.\n\nFor the inter-process transport, the transport is `ipc`, and the meaning of\nthe 'address' part is defined below.\n\n\nBinding a socket\n~~~~~~~~~~~~~~~~\nWhen binding a 'socket' to a local address using _zmq_bind()_ with the 'ipc'\ntransport, the 'endpoint' shall be interpreted as an arbitrary string\nidentifying the 'pathname' to create. The 'pathname' must be unique within the\noperating system namespace used by the 'ipc' implementation, and must fulfill\nany restrictions placed by the operating system on the format and length of a\n'pathname'.\n\nWhen the address is wild-card `*`, _zmq_bind()_ shall generate a unique temporary\npathname. The caller should retrieve this pathname using the ZMQ_LAST_ENDPOINT\nsocket option. See xref:zmq_getsockopt.adoc[zmq_getsockopt] for details.\n\nNOTE: any existing binding to the same endpoint shall be overridden. That is,\nif a second process binds to an endpoint already bound by a process, this\nwill succeed and the first process will lose its binding. In this behaviour,\nthe 'ipc' transport is not consistent with the 'tcp' or 'inproc' transports.\n\nNOTE: the endpoint pathname must be writable by the process. When the endpoint\nstarts with '/', e.g., `ipc:///pathname`, this will be an _absolute_ pathname.\nIf the endpoint specifies a directory that does not exist, the bind shall fail.\n\nNOTE: on Linux only, when the endpoint pathname starts with `@`, the abstract\nnamespace shall be used.  The abstract namespace is independent of the\nfilesystem and if a process attempts to bind an endpoint already bound by a\nprocess, it will fail.  See unix(7) for details.\n\nNOTE: IPC pathnames have a maximum size that depends on the operating system.\nOn Linux, the maximum is 113 characters including the \"ipc://\" prefix (107\ncharacters for the real path name).\n\nUnbinding wild-card address from a socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen wild-card `*` 'endpoint' was used in _zmq_bind()_, the caller should use\nreal 'endpoint' obtained from the ZMQ_LAST_ENDPOINT socket option to unbind\nthis 'endpoint' from a socket using _zmq_unbind()_.\n\nConnecting a socket\n~~~~~~~~~~~~~~~~~~~\nWhen connecting a 'socket' to a peer address using _zmq_connect()_ with the\n'ipc' transport, the 'endpoint' shall be interpreted as an arbitrary string\nidentifying the 'pathname' to connect to.  The 'pathname' must have been\npreviously created within the operating system namespace by assigning it to a\n'socket' with _zmq_bind()_.\n\n\n== EXAMPLES\n.Assigning a local address to a socket\n----\n//  Assign the pathname \"/tmp/feeds/0\"\nrc = zmq_bind(socket, \"ipc:///tmp/feeds/0\");\nassert (rc == 0);\n----\n\n.Connecting a socket\n----\n//  Connect to the pathname \"/tmp/feeds/0\"\nrc = zmq_connect(socket, \"ipc:///tmp/feeds/0\");\nassert (rc == 0);\n----\n\n== SEE ALSO\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_inproc.adoc[zmq_inproc]\n* xref:zmq_tcp.adoc[zmq_tcp]\n* xref:zmq_pgm.adoc[zmq_pgm]\n* xref:zmq_vmci.adoc[zmq_vmci]\n* xref:zmq_vsock.adoc[zmq_vsock]\n* xref:zmq_getsockopt.adoc[zmq_getsockopt]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_close.adoc",
    "content": "= zmq_msg_close(3)\n\n\n== NAME\nzmq_msg_close - release 0MQ message\n\n\n== SYNOPSIS\n*int zmq_msg_close (zmq_msg_t '*msg');*\n\n\n== DESCRIPTION\nThe _zmq_msg_close()_ function shall inform the 0MQ infrastructure that any\nresources associated with the message object referenced by 'msg' are no longer\nrequired and may be released. Actual release of resources associated with the\nmessage object shall be postponed by 0MQ until all users of the message or\nunderlying data buffer have indicated it is no longer required.\n\nApplications should ensure that _zmq_msg_close()_ is called once a message is\nno longer required, otherwise memory leaks may occur. Note that this is NOT\nnecessary after a successful _zmq_msg_send()_.\n\nCAUTION: Never access 'zmq_msg_t' members directly, instead always use the\n_zmq_msg_ family of functions.\n\n\n== RETURN VALUE\nThe _zmq_msg_close()_ function shall return zero if successful. Otherwise\nit shall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EFAULT*::\nInvalid message.\n\n\n== SEE ALSO\n* xref:zmq_msg_init.adoc[zmq_msg_init]\n* xref:zmq_msg_init_size.adoc[zmq_msg_init_size]\n* xref:zmq_msg_init_buffer.adoc[zmq_msg_init_buffer]\n* xref:zmq_msg_init_data.adoc[zmq_msg_init_data]\n* xref:zmq_msg_data.adoc[zmq_msg_data]\n* xref:zmq_msg_size.adoc[zmq_msg_size]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_copy.adoc",
    "content": "= zmq_msg_copy(3)\n\n\n== NAME\nzmq_msg_copy - copy content of a message to another message\n\n\n== SYNOPSIS\n*int zmq_msg_copy (zmq_msg_t '*dest', zmq_msg_t '*src');*\n\n\n== DESCRIPTION\nThe _zmq_msg_copy()_ function shall copy the message object referenced by 'src'\nto the message object referenced by 'dest'. The original content of 'dest', if\nany, shall be released. You must initialise 'dest' before copying to it.\n\nCAUTION: The implementation may choose not to physically copy the message\ncontent, rather to share the underlying buffer between 'src' and 'dest'. Avoid\nmodifying message content after a message has been copied with\n_zmq_msg_copy()_, doing so can result in undefined behaviour. If what you need\nis an actual hard copy, initialize a new message using _zmq_msg_init_buffer()_\nwith the message content.\n\nCAUTION: Never access 'zmq_msg_t' members directly, instead always use the\n_zmq_msg_ family of functions.\n\n\n== RETURN VALUE\nThe _zmq_msg_copy()_ function shall return zero if successful. Otherwise it\nshall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EFAULT*::\nInvalid message.\n\n\n== EXAMPLE\n.Copying a message\n----\nzmq_msg_t msg;\nzmq_msg_init_buffer (&msg, \"Hello, World\", 12);\nzmq_msg_t copy;\nzmq_msg_init (&copy);\nzmq_msg_copy (&copy, &msg);\n...\nzmq_msg_close (&copy);\nzmq_msg_close (&msg);\n----\n\n== SEE ALSO\n* xref:zmq_msg_move.adoc[zmq_msg_move]\n* xref:zmq_msg_init.adoc[zmq_msg_init]\n* xref:zmq_msg_init_size.adoc[zmq_msg_init_size]\n* xref:zmq_msg_init_buffer.adoc[zmq_msg_init_buffer]\n* xref:zmq_msg_init_data.adoc[zmq_msg_init_data]\n* xref:zmq_msg_close.adoc[zmq_msg_close]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_data.adoc",
    "content": "= zmq_msg_data(3)\n\n\n== NAME\nzmq_msg_data - retrieve pointer to message content\n\n\n== SYNOPSIS\n*void *zmq_msg_data (zmq_msg_t '*msg');*\n\n\n== DESCRIPTION\nThe _zmq_msg_data()_ function shall return a pointer to the message content of\nthe message object referenced by 'msg'.\n\nCAUTION: Never access 'zmq_msg_t' members directly, instead always use the\n_zmq_msg_ family of functions.\n\n\n== RETURN VALUE\nUpon successful completion, _zmq_msg_data()_ shall return a pointer to the\nmessage content.\n\n\n== ERRORS\nNo errors are defined.\n\n\n== SEE ALSO\n* xref:zmq_msg_size.adoc[zmq_msg_size]\n* xref:zmq_msg_init.adoc[zmq_msg_init]\n* xref:zmq_msg_init_size.adoc[zmq_msg_init_size]\n* xref:zmq_msg_init_buffer.adoc[zmq_msg_init_buffer]\n* xref:zmq_msg_init_data.adoc[zmq_msg_init_data]\n* xref:zmq_msg_close.adoc[zmq_msg_close]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_get.adoc",
    "content": "= zmq_msg_get(3)\n\n\n== NAME\nzmq_msg_get - get message property\n\n\n== SYNOPSIS\n*int zmq_msg_get (zmq_msg_t '*message', int 'property');*\n\n\n== DESCRIPTION\nThe _zmq_msg_get()_ function shall return the value for the property\nspecified by the 'property' argument for the message pointed to by the\n'message' argument.\n\nThe following properties can be retrieved with the _zmq_msg_get()_ function:\n\n*ZMQ_MORE*::\nIndicates that there are more message frames to follow after the 'message'.\n\n*ZMQ_SRCFD*::\nReturns the file descriptor of the socket the 'message' was read from. This\nallows application to retrieve the remote endpoint via 'getpeername(2)'. Be\naware that the respective socket might be closed already, reused even.\nCurrently only implemented for TCP sockets.\n\n*ZMQ_SHARED*::\nIndicates that a message MAY share underlying storage with another copy of\nthis message.\n\n== RETURN VALUE\nThe _zmq_msg_get()_ function shall return the value for the property if\nsuccessful. Otherwise it shall return `-1` and set 'errno' to one of the\nvalues defined below.\n\n\n== ERRORS\n*EINVAL*::\nThe requested _property_ is unknown.\n\n\n== EXAMPLE\n.Receiving a multi-frame message\n----\nzmq_msg_t frame;\nwhile (true) {\n    //  Create an empty 0MQ message to hold the message frame\n    int rc = zmq_msg_init (&frame);\n    assert (rc == 0);\n    //  Block until a message is available to be received from socket\n    rc = zmq_msg_recv (socket, &frame, 0);\n    assert (rc != -1);\n    if (zmq_msg_get (&frame, ZMQ_MORE))\n        fprintf (stderr, \"more\\n\");\n    else {\n        fprintf (stderr, \"end\\n\");\n        break;\n    }\n    zmq_msg_close (&frame);\n}\n----\n\n\n== SEE ALSO\n* xref:zmq_msg_set.adoc[zmq_msg_set]\n* xref:zmq_msg_init.adoc[zmq_msg_init]\n* xref:zmq_msg_close.adoc[zmq_msg_close]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_gets.adoc",
    "content": "= zmq_msg_gets(3)\n\n\n== NAME\nzmq_msg_gets - get message metadata property\n\n\n== SYNOPSIS\n*const char *zmq_msg_gets (zmq_msg_t '*message', const char *'property');*\n\n\n== DESCRIPTION\nThe _zmq_msg_gets()_ function shall return the string value for the metadata\nproperty specified by the 'property' argument for the message pointed to by\nthe 'message' argument. Both the 'property' argument and the 'value'\nshall be NULL-terminated UTF8-encoded strings.\n\nMetadata is defined on a per-connection basis during the ZeroMQ connection\nhandshake as specified in <rfc.zeromq.org/spec:37>. Applications can set\nmetadata properties using xref:zmq_setsockopt.adoc[zmq_setsockopt] option ZMQ_METADATA.\nApplication metadata properties must be prefixed with 'X-'.\n\nIn addition to application metadata, the following ZMTP properties can be\nretrieved with the _zmq_msg_gets()_ function:\n\n    Socket-Type\n    Routing-Id\n\nNote: 'Identity' is a deprecated alias for 'Routing-Id'.\n\nAdditionally, when available for the underlying transport, the *Peer-Address*\nproperty will return the IP address of the remote endpoint as returned by\ngetnameinfo(2).\n\nThe names of these properties are also defined in _zmq.h_ as\n_ZMQ_MSG_PROPERTY_SOCKET_TYPE_ _ZMQ_MSG_PROPERTY_ROUTING_ID_, and \n_ZMQ_MSG_PROPERTY_PEER_ADDRESS_.\nCurrently, these definitions are only available as a DRAFT API.\n\nOther properties may be defined based on the underlying security mechanism,\nsee ZAP authenticated connection sample below.\n\n== RETURN VALUE\nThe _zmq_msg_gets()_ function shall return the string value for the property\nif successful. Otherwise it shall return NULL and set 'errno' to one of the\nvalues defined below. The caller shall not modify or free the returned value,\nwhich shall be owned by the message. The encoding of the property and value\nshall be UTF8.\n\n\n== ERRORS\n*EINVAL*::\nThe requested _property_ is unknown.\n\n\n== EXAMPLE\n.Getting the ZAP authenticated user id for a message:\n----\nzmq_msg_t msg;\nzmq_msg_init (&msg);\nrc = zmq_msg_recv (&msg, dealer, 0);\nassert (rc != -1);\nconst char *user_id = zmq_msg_gets (&msg, ZMQ_MSG_PROPERTY_USER_ID);\nzmq_msg_close (&msg);\n----\n\n\n== SEE ALSO\n* xref:zmq.adoc[zmq]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_init.adoc",
    "content": "= zmq_msg_init(3)\n\n\n== NAME\nzmq_msg_init - initialise empty 0MQ message\n\n\n== SYNOPSIS\n*int zmq_msg_init (zmq_msg_t '*msg');*\n\n\n== DESCRIPTION\nThe _zmq_msg_init()_ function shall initialise the message object referenced by\n'msg' to represent an empty message.  This function is most useful when called\nbefore receiving a message with _zmq_msg_recv()_.\n\nCAUTION: Never access 'zmq_msg_t' members directly, instead always use the\n_zmq_msg_ family of functions.\n\nCAUTION: The functions _zmq_msg_init()_, _zmq_msg_init_data()_,\n_zmq_msg_init_size()_ and _zmq_msg_init_buffer()_ are mutually exclusive.\nNever initialise the same 'zmq_msg_t' twice.\n\n\n== RETURN VALUE\nThe _zmq_msg_init()_ function always returns zero.\n\n\n== ERRORS\nNo errors are defined.\n\n\n== EXAMPLE\n.Receiving a message from a socket\n----\nzmq_msg_t msg;\nrc = zmq_msg_init (&msg);\nassert (rc == 0);\nint nbytes = zmq_msg_recv (socket, &msg, 0);\nassert (nbytes != -1);\n----\n\n\n== SEE ALSO\n* xref:zmq_msg_init_size.adoc[zmq_msg_init_size]\n* xref:zmq_msg_init_buffer.adoc[zmq_msg_init_buffer]\n* xref:zmq_msg_init_data.adoc[zmq_msg_init_data]\n* xref:zmq_msg_close.adoc[zmq_msg_close]\n* xref:zmq_msg_data.adoc[zmq_msg_data]\n* xref:zmq_msg_size.adoc[zmq_msg_size]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_init_buffer.adoc",
    "content": "= zmq_msg_init_buffer(3)\n\n\n== NAME\nzmq_msg_init_buffer - initialise 0MQ message with buffer copy\n\n\n== SYNOPSIS\n*int zmq_msg_init_buffer (zmq_msg_t '*msg', const void '*buf', size_t 'size');*\n\n\n== DESCRIPTION\nThe _zmq_msg_init_buffer()_ function shall allocate any resources required to\nstore a message 'size' bytes long and initialise the message object referenced\nby 'msg' to represent a copy of the buffer referenced by the 'buf' and\n'size' arguments.\n\nThe implementation shall choose whether to store message content on the stack\n(small messages) or on the heap (large messages).\n\nCAUTION: Never access 'zmq_msg_t' members directly, instead always use the\n_zmq_msg_ family of functions.\n\nCAUTION: The functions _zmq_msg_init()_, _zmq_msg_init_data()_,\n_zmq_msg_init_buffer()_ and _zmq_msg_init_buffer()_ are mutually exclusive.\nNever initialise the same 'zmq_msg_t' twice.\n\n\n== RETURN VALUE\nThe _zmq_msg_init_buffer()_ function shall return zero if successful. Otherwise\nit shall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*ENOMEM*::\nInsufficient storage space is available.\n\n\n== SEE ALSO\n* xref:zmq_msg_init_data.adoc[zmq_msg_init_data]\n* xref:zmq_msg_init_size.adoc[zmq_msg_init_size]\n* xref:zmq_msg_init.adoc[zmq_msg_init]\n* xref:zmq_msg_close.adoc[zmq_msg_close]\n* xref:zmq_msg_data.adoc[zmq_msg_data]\n* xref:zmq_msg_size.adoc[zmq_msg_size]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_init_data.adoc",
    "content": "= zmq_msg_init_data(3)\n\n\n== NAME\nzmq_msg_init_data - initialise 0MQ message from a supplied buffer\n\n\n== SYNOPSIS\n*typedef void (zmq_free_fn) (void '*data', void '*hint');*\n\n*int zmq_msg_init_data (zmq_msg_t '*msg', void '*data', size_t 'size', zmq_free_fn '*ffn', void '*hint');*\n\n\n== DESCRIPTION\nThe _zmq_msg_init_data()_ function shall initialise the message object\nreferenced by 'msg' to represent the content referenced by the buffer located\nat address 'data', 'size' bytes long. No copy of 'data' shall be performed and\n0MQ shall take ownership of the supplied buffer.\n\nIf provided, the deallocation function 'ffn' shall be called once the data\nbuffer is no longer required by 0MQ, with the 'data' and 'hint' arguments\nsupplied to _zmq_msg_init_data()_.\n\nCAUTION: Never access 'zmq_msg_t' members directly, instead always use the\n_zmq_msg_ family of functions.\n\nCAUTION: The deallocation function 'ffn' needs to be thread-safe, since it\nwill be called from an arbitrary thread.\n\nCAUTION: If the deallocation function is not provided, the allocated memory\nwill not be freed, and this may cause a memory leak.\n\n\nCAUTION: The functions _zmq_msg_init()_, _zmq_msg_init_data()_,\n_zmq_msg_init_size()_ and _zmq_msg_init_buffer()_ are mutually exclusive.\nNever initialise the same 'zmq_msg_t' twice.\n\n\n== RETURN VALUE\nThe _zmq_msg_init_data()_ function shall return zero if successful. Otherwise\nit shall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*ENOMEM*::\nInsufficient storage space is available.\n\n\n\n== EXAMPLE\n.Initialising a message from a supplied buffer\n----\nvoid my_free (void *data, void *hint) \n{\n    free (data);\n}\n\n    /*  ...  */\n\nvoid *data = malloc (6);\nassert (data);\nmemcpy (data, \"ABCDEF\", 6);\nzmq_msg_t msg;\nrc = zmq_msg_init_data (&msg, data, 6, my_free, NULL);\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_msg_init_size.adoc[zmq_msg_init_size]\n* xref:zmq_msg_init_buffer.adoc[zmq_msg_init_buffer]\n* xref:zmq_msg_init.adoc[zmq_msg_init]\n* xref:zmq_msg_close.adoc[zmq_msg_close]\n* xref:zmq_msg_data.adoc[zmq_msg_data]\n* xref:zmq_msg_size.adoc[zmq_msg_size]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_init_size.adoc",
    "content": "= zmq_msg_init_size(3)\n\n\n== NAME\nzmq_msg_init_size - initialise 0MQ message of a specified size\n\n\n== SYNOPSIS\n*int zmq_msg_init_size (zmq_msg_t '*msg', size_t 'size');*\n\n\n== DESCRIPTION\nThe _zmq_msg_init_size()_ function shall allocate any resources required to\nstore a message 'size' bytes long and initialise the message object referenced\nby 'msg' to represent the newly allocated message.\n\nThe implementation shall choose whether to store message content on the stack\n(small messages) or on the heap (large messages). For performance reasons\n_zmq_msg_init_size()_ shall not clear the message data.\n\nCAUTION: Never access 'zmq_msg_t' members directly, instead always use the\n_zmq_msg_ family of functions.\n\nCAUTION: The functions _zmq_msg_init()_, _zmq_msg_init_data()_,\n_zmq_msg_init_size()_ and _zmq_msg_init_buffer()_ are mutually exclusive.\nNever initialise the same 'zmq_msg_t' twice.\n\n\n== RETURN VALUE\nThe _zmq_msg_init_size()_ function shall return zero if successful. Otherwise\nit shall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*ENOMEM*::\nInsufficient storage space is available.\n\n\n== SEE ALSO\n* xref:zmq_msg_init_data.adoc[zmq_msg_init_data]\n* xref:zmq_msg_init_buffer.adoc[zmq_msg_init_buffer]\n* xref:zmq_msg_init.adoc[zmq_msg_init]\n* xref:zmq_msg_close.adoc[zmq_msg_close]\n* xref:zmq_msg_data.adoc[zmq_msg_data]\n* xref:zmq_msg_size.adoc[zmq_msg_size]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_more.adoc",
    "content": "= zmq_msg_more(3)\n\n\n== NAME\nzmq_msg_more - indicate if there are more message parts to receive\n\n\n== SYNOPSIS\n*int zmq_msg_more (zmq_msg_t '*message');*\n\n\n== DESCRIPTION\nThe _zmq_msg_more()_ function indicates whether this is part of a multi-part\nmessage, and there are further parts to receive. This method can safely be\ncalled after _zmq_msg_close()_. This method is identical to _zmq_msg_get()_\nwith an argument of ZMQ_MORE.\n\n\n== RETURN VALUE\nThe _zmq_msg_more()_ function shall return zero if this is the final part of\na multi-part message, or the only part of a single-part message. It shall\nreturn 1 if there are further parts to receive.\n\n\n== EXAMPLE\n.Receiving a multi-part message\n----\nzmq_msg_t part;\nwhile (true) {\n    //  Create an empty 0MQ message to hold the message part\n    int rc = zmq_msg_init (&part);\n    assert (rc == 0);\n    //  Block until a message is available to be received from socket\n    rc = zmq_msg_recv (socket, &part, 0);\n    assert (rc != -1);\n    if (zmq_msg_more (&part))\n        fprintf (stderr, \"more\\n\");\n    else {\n        fprintf (stderr, \"end\\n\");\n        break;\n    }\n    zmq_msg_close (&part);\n}\n----\n\n\n== SEE ALSO\n* xref:zmq_msg_get.adoc[zmq_msg_get]\n* xref:zmq_msg_set.adoc[zmq_msg_set]\n* xref:zmq_msg_init.adoc[zmq_msg_init]\n* xref:zmq_msg_close.adoc[zmq_msg_close]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_move.adoc",
    "content": "= zmq_msg_move(3)\n\n\n== NAME\nzmq_msg_move - move content of a message to another message\n\n\n== SYNOPSIS\n*int zmq_msg_move (zmq_msg_t '*dest', zmq_msg_t '*src');*\n\n\n== DESCRIPTION\nThe _zmq_msg_move()_ function shall move the content of the message object\nreferenced by 'src' to the message object referenced by 'dest'. No actual\ncopying of message content is performed, 'dest' is simply updated to reference\nthe new content. 'src' becomes an empty message after calling _zmq_msg_move()_.\nThe original content of 'dest', if any, shall be released.\n\nCAUTION: Never access 'zmq_msg_t' members directly, instead always use the\n_zmq_msg_ family of functions.\n\n\n== RETURN VALUE\nThe _zmq_msg_move()_ function shall return zero if successful. Otherwise it\nshall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EFAULT*::\nInvalid message.\n\n\n== SEE ALSO\n* xref:zmq_msg_copy.adoc[zmq_msg_copy]\n* xref:zmq_msg_init.adoc[zmq_msg_init]\n* xref:zmq_msg_init_size.adoc[zmq_msg_init_size]\n* xref:zmq_msg_init_buffer.adoc[zmq_msg_init_buffer]\n* xref:zmq_msg_init_data.adoc[zmq_msg_init_data]\n* xref:zmq_msg_close.adoc[zmq_msg_close]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_recv.adoc",
    "content": "= zmq_msg_recv(3)\n\n\n== NAME\nzmq_msg_recv - receive a message part from a socket\n\n\n== SYNOPSIS\n*int zmq_msg_recv (zmq_msg_t '*msg', void '*socket', int 'flags');*\n\n\n== DESCRIPTION\nThe _zmq_msg_recv()_ function is identical to xref:zmq_recvmsg.adoc[zmq_recvmsg], which\nshall be deprecated in future versions. _zmq_msg_recv()_ is more consistent\nwith other message manipulation functions.\n\nThe _zmq_msg_recv()_ function shall receive a message part from the socket\nreferenced by the 'socket' argument and store it in the message referenced by\nthe 'msg' argument. Any content previously stored in 'msg' shall be properly\ndeallocated. If there are no message parts available on the specified 'socket'\nthe _zmq_msg_recv()_ function shall block until the request can be satisfied.\nThe 'flags' argument is a combination of the flags defined below:\n\n*ZMQ_DONTWAIT*::\nSpecifies that the operation should be performed in non-blocking mode. If there\nare no messages available on the specified 'socket', the _zmq_msg_recv()_\nfunction shall fail with 'errno' set to EAGAIN.\n\n\nMulti-part messages\n~~~~~~~~~~~~~~~~~~~\nA 0MQ message is composed of 1 or more message parts. Each message\npart is an independent 'zmq_msg_t' in its own right. 0MQ ensures atomic\ndelivery of messages: peers shall receive either all _message parts_ of a\nmessage or none at all. The total number of message parts is unlimited except\nby available memory.\n\nAn application that processes multi-part messages must use the _ZMQ_RCVMORE_\nxref:zmq_getsockopt.adoc[zmq_getsockopt] option after calling _zmq_msg_recv()_ to determine if\nthere are further parts to receive.\n\n\n== RETURN VALUE\nThe _zmq_msg_recv()_ function shall return number of bytes in the message\nif successful. Otherwise it shall return `-1` and set 'errno' to one of the\nvalues defined below.\n\n\n== ERRORS\n*EAGAIN*::\nEither the timeout set via the socket-option ZMQ_RCVTIMEO (see xref:zmq_setsockopt.adoc[zmq_setsockopt])\nhas been reached (flag ZMQ_DONTWAIT not set) without being able to read a message\nfrom the socket or there are no messages available at the moment (flag ZMQ_DONTWAIT set)\nand the operation would block.\n*ENOTSUP*::\nThe _zmq_msg_recv()_ operation is not supported by this socket type.\n*EFSM*::\nThe _zmq_msg_recv()_ operation cannot be performed on this socket at the moment\ndue to the socket not being in the appropriate state.  This error may occur with\nsocket types that switch between several states, such as ZMQ_REP.  See the\n_messaging patterns_ section of xref:zmq_socket.adoc[zmq_socket] for more information.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EINTR*::\nThe operation was interrupted by delivery of a signal before a message was\navailable.\n*EFAULT*::\nThe message passed to the function was invalid.\n\n\n== EXAMPLE\n.Receiving a message from a socket\n----\n/* Create an empty 0MQ message */\nzmq_msg_t msg;\nint rc = zmq_msg_init (&msg);\nassert (rc == 0);\n/* Block until a message is available to be received from socket */\nrc = zmq_msg_recv (&msg, socket, 0);\nassert (rc != -1);\n/* Release message */\nzmq_msg_close (&msg);\n----\n\n.Receiving a multi-part message\n----\nint more;\nsize_t more_size = sizeof (more);\ndo {\n    /* Create an empty 0MQ message to hold the message part */\n    zmq_msg_t part;\n    int rc = zmq_msg_init (&part);\n    assert (rc == 0);\n    /* Block until a message is available to be received from socket */\n    rc = zmq_msg_recv (&part, socket, 0);\n    assert (rc != -1);\n    /* Determine if more message parts are to follow */\n    rc = zmq_getsockopt (socket, ZMQ_RCVMORE, &more, &more_size);\n    assert (rc == 0);\n    zmq_msg_close (&part);\n} while (more);\n----\n\n\n== SEE ALSO\n* xref:zmq_recv.adoc[zmq_recv]\n* xref:zmq_send.adoc[zmq_send]\n* xref:zmq_msg_send.adoc[zmq_msg_send]\n* xref:zmq_getsockopt.adoc[zmq_getsockopt]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_routing_id.adoc",
    "content": "= zmq_msg_routing_id(3)\n\n\n== NAME\nzmq_msg_routing_id - return routing ID for message, if any\n\n\n== SYNOPSIS\n*uint32_t zmq_msg_routing_id (zmq_msg_t '*message');*\n\n\n== DESCRIPTION\nThe _zmq_msg_routing_id()_ function returns the routing ID for the message,\nif any. The routing ID is set on all messages received from a 'ZMQ_SERVER'\nsocket. To send a message to a 'ZMQ_SERVER' socket you must set the routing\nID of a connected 'ZMQ_CLIENT' peer. Routing IDs are transient.\n\n\n== RETURN VALUE\nThe _zmq_msg_routing_id()_ function shall return zero if there is no routing\nID, otherwise it shall return an unsigned 32-bit integer greater than zero.\n\n\n== EXAMPLE\n.Receiving a client message and routing ID\n----\nvoid *ctx = zmq_ctx_new ();\nassert (ctx);\n\nvoid *server = zmq_socket (ctx, ZMQ_SERVER);\nassert (server);\nint rc = zmq_bind (server, \"tcp://127.0.0.1:8080\");\nassert (rc == 0);\n\nzmq_msg_t message;\nrc = zmq_msg_init (&message);\nassert (rc == 0);\n\n//  Receive a message from socket\nrc = zmq_msg_recv (server, &message, 0);\nassert (rc != -1);\nuint32_t routing_id = zmq_msg_routing_id (&message);\nassert (routing_id);\n----\n\n\n== SEE ALSO\n* xref:zmq_msg_set_routing_id.adoc[zmq_msg_set_routing_id]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_send.adoc",
    "content": "= zmq_msg_send(3)\n\n\n== NAME\nzmq_msg_send - send a message part on a socket\n\n\n== SYNOPSIS\n*int zmq_msg_send (zmq_msg_t '*msg', void '*socket', int 'flags');*\n\n\n== DESCRIPTION\nThe _zmq_msg_send()_ function is identical to xref:zmq_sendmsg.adoc[zmq_sendmsg], which\nshall be deprecated in future versions. _zmq_msg_send()_ is more consistent\nwith other message manipulation functions.\n\nThe _zmq_msg_send()_ function shall queue the message referenced by the 'msg'\nargument to be sent to the socket referenced by the 'socket' argument.  The\n'flags' argument is a combination of the flags defined below:\n\n*ZMQ_DONTWAIT*::\nFor socket types (DEALER, PUSH) that block (either with ZMQ_IMMEDIATE option set\nand no peer available, or all peers having full high-water mark), specifies that\nthe operation should be performed in non-blocking mode. If the message cannot be\nqueued on the 'socket', the _zmq_msg_send()_ function shall fail with 'errno' set\nto EAGAIN.\n\n*ZMQ_SNDMORE*::\nSpecifies that the message being sent is a multi-part message, and that further\nmessage parts are to follow. Refer to the section regarding multi-part messages\nbelow for a detailed description.\n\nThe _zmq_msg_t_ structure passed to _zmq_msg_send()_ is nullified on a\nsuccessful call. If you want to send the same message to multiple sockets you\nhave to copy it (e.g. using _zmq_msg_copy()_). If the call fails, the\n_zmq_msg_t_ structure stays intact, and must be consumed by another call to\n_zmq_msg_send()_ on the same or another socket, or released using\n_zmq_msg_close()_ to avoid a memory leak.\n\nNOTE: A successful invocation of _zmq_msg_send()_ does not indicate that the\nmessage has been transmitted to the network, only that it has been queued on\nthe 'socket' and 0MQ has assumed responsibility for the message. You do not need\nto call _zmq_msg_close()_ after a successful _zmq_msg_send()_.\n\n\nMulti-part messages\n~~~~~~~~~~~~~~~~~~~\nA 0MQ message is composed of 1 or more message parts. Each message\npart is an independent 'zmq_msg_t' in its own right. 0MQ ensures atomic\ndelivery of messages: peers shall receive either all _message parts_ of a\nmessage or none at all. The total number of message parts is unlimited except\nby available memory.\n\nAn application that sends multi-part messages must use the _ZMQ_SNDMORE_ flag\nwhen sending each message part except the final one.\n\n== RETURN VALUE\nThe _zmq_msg_send()_ function shall return number of bytes in the message\nif successful (if number of bytes is higher than 'MAX_INT', the function will\nreturn 'MAX_INT'). Otherwise it shall return `-1` and set 'errno' to one of the\nvalues defined below.\n\n\n== ERRORS\n*EAGAIN*::\nNon-blocking mode was requested and the message cannot be sent at the moment.\n*ENOTSUP*::\nThe _zmq_msg_send()_ operation is not supported by this socket type.\n*EINVAL*::\nThe sender tried to send multipart data, which the socket type does not allow.\n*EFSM*::\nThe _zmq_msg_send()_ operation cannot be performed on this socket at the moment\ndue to the socket not being in the appropriate state.  This error may occur with\nsocket types that switch between several states, such as ZMQ_REP.  See the\n_messaging patterns_ section of xref:zmq_socket.adoc[zmq_socket] for more information.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EINTR*::\nThe operation was interrupted by delivery of a signal before the message was\nsent.\n*EFAULT*::\nInvalid message.\n*EHOSTUNREACH*::\nThe message cannot be routed.\n\n\n== EXAMPLE\n.Filling in a message and sending it to a socket\n----\n/* Create a new message, allocating 6 bytes for message content */\nzmq_msg_t msg;\nint rc = zmq_msg_init_size (&msg, 6);\nassert (rc == 0);\n/* Fill in message content with 'AAAAAA' */\nmemset (zmq_msg_data (&msg), 'A', 6);\n/* Send the message to the socket */\nrc = zmq_msg_send (&msg, socket, 0);\nassert (rc == 6);\n----\n\n.Sending a multi-part message\n----\n/* Send a multi-part message consisting of three parts to socket */\nrc = zmq_msg_send (&part1, socket, ZMQ_SNDMORE);\nrc = zmq_msg_send (&part2, socket, ZMQ_SNDMORE);\n/* Final part; no more parts to follow */\nrc = zmq_msg_send (&part3, socket, 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_recv.adoc[zmq_recv]\n* xref:zmq_send.adoc[zmq_send]\n* xref:zmq_msg_recv.adoc[zmq_msg_recv]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_set.adoc",
    "content": "= zmq_msg_set(3)\n\n\n== NAME\n\nzmq_msg_set - set message property\n\n\n== SYNOPSIS\n*int zmq_msg_set (zmq_msg_t '*message', int 'property', int 'value');*\n\n\n== DESCRIPTION\nThe _zmq_msg_set()_ function shall set the property specified by the\n'property' argument to the value of the 'value' argument for the 0MQ\nmessage fragment pointed to by the 'message' argument.\n\nCurrently the _zmq_msg_set()_ function does not support any property names.\n\n\n== RETURN VALUE\nThe _zmq_msg_set()_ function shall return zero if successful. Otherwise it\nshall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EINVAL*::\nThe requested property _property_ is unknown.\n\n\n== SEE ALSO\n* xref:zmq_msg_get.adoc[zmq_msg_get]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_set_routing_id.adoc",
    "content": "= zmq_msg_set_routing_id(3)\n\n\n== NAME\n\nzmq_msg_set_routing_id - set routing ID property on message\n\n\n== SYNOPSIS\n*int zmq_msg_set_routing_id (zmq_msg_t '*message', uint32_t 'routing_id');*\n\n\n== DESCRIPTION\nThe _zmq_msg_set_routing_id()_ function sets the 'routing_id' specified, on the\nthe message pointed to by the 'message' argument. The 'routing_id' must be\ngreater than zero. To get a valid routing ID, you must receive a message\nfrom a 'ZMQ_SERVER' socket, and use the libzmq:zmq_msg_routing_id method.\nRouting IDs are transient.\n\n\n== RETURN VALUE\nThe _zmq_msg_set_routing_id()_ function shall return zero if successful. Otherwise it\nshall return `-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EINVAL*::\nThe provided 'routing_id' is zero.\n\n\n== SEE ALSO\n* xref:zmq_msg_routing_id.adoc[zmq_msg_routing_id]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_msg_size.adoc",
    "content": "= zmq_msg_size(3)\n\n\n== NAME\nzmq_msg_size - retrieve message content size in bytes\n\n\n== SYNOPSIS\n*size_t zmq_msg_size (zmq_msg_t '*msg');*\n\n\n== DESCRIPTION\nThe _zmq_msg_size()_ function shall return the size in bytes of the content of\nthe message object referenced by 'msg'.\n\nCAUTION: Never access 'zmq_msg_t' members directly, instead always use the\n_zmq_msg_ family of functions.\n\n\n== RETURN VALUE\nUpon successful completion, _zmq_msg_size()_ shall return the size of the\nmessage content in bytes.\n\n\n== ERRORS\nNo errors are defined.\n\n\n== SEE ALSO\n* xref:zmq_msg_data.adoc[zmq_msg_data]\n* xref:zmq_msg_init.adoc[zmq_msg_init]\n* xref:zmq_msg_init_size.adoc[zmq_msg_init_size]\n* xref:zmq_msg_init_buffer.adoc[zmq_msg_init_buffer]\n* xref:zmq_msg_init_data.adoc[zmq_msg_init_data]\n* xref:zmq_msg_close.adoc[zmq_msg_close]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_null.adoc",
    "content": "= zmq_null(7)\n\n\n== NAME\nzmq_null - no security or confidentiality\n\n\n== SYNOPSIS\nThe NULL mechanism is defined by the ZMTP 3.0 specification: \n<http://rfc.zeromq.org/spec:23>. This is the default security mechanism\nfor ZeroMQ sockets.\n\n\n== SEE ALSO\n* xref:zmq_plain.adoc[zmq_plain]\n* xref:zmq_curve.adoc[zmq_curve]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_pgm.adoc",
    "content": "= zmq_pgm(7)\n\n\n== NAME\nzmq_pgm - 0MQ reliable multicast transport using PGM\n\n\n== SYNOPSIS\nPGM (Pragmatic General Multicast) is a protocol for reliable multicast\ntransport of data over IP networks.\n\n\n== DESCRIPTION\n0MQ implements two variants of PGM, the standard protocol where PGM datagrams\nare layered directly on top of IP datagrams as defined by RFC 3208 (the 'pgm'\ntransport) and \"Encapsulated PGM\" or EPGM where PGM datagrams are encapsulated\ninside UDP datagrams (the 'epgm' transport).\n\nThe 'pgm' and 'epgm' transports can only be used with the 'ZMQ_PUB' and\n'ZMQ_SUB' socket types.\n\nFurther, PGM sockets are rate limited by default. For details, refer to the\n'ZMQ_RATE', and 'ZMQ_RECOVERY_IVL' options documented in\nxref:zmq_setsockopt.adoc[zmq_setsockopt]\n\nCAUTION: The 'pgm' transport implementation requires access to raw IP sockets.\nAdditional privileges may be required on some operating systems for this\noperation. Applications not requiring direct interoperability with other PGM\nimplementations are encouraged to use the 'epgm' transport instead which does\nnot require any special privileges.\n\n\n== ADDRESSING\nA 0MQ endpoint is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to connect to.\n\nFor the PGM transport, the transport is `pgm`, and for the EPGM protocol the\ntransport is `epgm`. The meaning of the 'address' part is defined below.\n\n\nConnecting a socket\n~~~~~~~~~~~~~~~~~~~\nWhen connecting a socket to a peer address using _zmq_connect()_ with the 'pgm'\nor 'epgm' transport, the 'endpoint' shall be interpreted as an 'interface'\nfollowed by a semicolon, followed by a 'multicast address', followed by a colon\nand a port number.\n\nAn 'interface' may be specified by either of the following:\n\n* The interface name as defined by the operating system.\n* The primary IPv4 address assigned to the interface, in its numeric\n  representation.\n\nNOTE: Interface names are not standardised in any way and should be assumed to\nbe arbitrary and platform dependent. On Win32 platforms no short interface\nnames exist, thus only the primary IPv4 address may be used to specify an\n'interface'. The 'interface' part can be omitted, in that case the default one\nwill be selected.\n\nA 'multicast address' is specified by an IPv4 multicast address in its numeric\nrepresentation.\n\n\n== WIRE FORMAT\nConsecutive PGM datagrams are interpreted by 0MQ as a single continuous stream\nof data where 0MQ messages are not necessarily aligned with PGM datagram\nboundaries and a single 0MQ message may span several PGM datagrams. This stream\nof data consists of 0MQ messages encapsulated in 'frames' as described in\nxref:zmq_tcp.adoc[zmq_tcp]\n\n\nPGM datagram payload\n~~~~~~~~~~~~~~~~~~~~\nThe following ABNF grammar represents the payload of a single PGM datagram as\nused by 0MQ:\n\n....\ndatagram               = (offset data)\noffset                 = 2OCTET\ndata                   = *OCTET\n....\n\nIn order for late joining consumers to be able to identify message boundaries,\neach PGM datagram payload starts with a 16-bit unsigned integer in network byte\norder specifying either the offset of the first message 'frame' in the datagram\nor containing the value `0xFFFF` if the datagram contains solely an\nintermediate part of a larger message.\n\nNote that offset specifies where the first message begins rather than the first\nmessage part. Thus, if there are trailing message parts at the beginning of\nthe packet the offset ignores them and points to first initial message part\nin the packet.\n\nThe following diagram illustrates the layout of a single PGM datagram payload:\n\n....\n+------------------+----------------------+\n| offset (16 bits) |         data         |\n+------------------+----------------------+\n....\n\nThe following diagram further illustrates how three example 0MQ frames are laid\nout in consecutive PGM datagram payloads:\n\n....\nFirst datagram payload\n+--------------+-------------+---------------------+\n| Frame offset |   Frame 1   |   Frame 2, part 1   |\n|    0x0000    | (Message 1) | (Message 2, part 1) |\n+--------------+-------------+---------------------+\n\nSecond datagram payload\n+--------------+---------------------+\n| Frame offset |   Frame 2, part 2   |\n| 0xFFFF       | (Message 2, part 2) |\n+--------------+---------------------+\n\nThird datagram payload\n+--------------+----------------------------+-------------+\n| Frame offset |   Frame 2, final 8 bytes   |   Frame 3   |\n| 0x0008       | (Message 2, final 8 bytes) | (Message 3) |\n+--------------+----------------------------+-------------+\n....\n\n\n== CONFIGURATION\n\nThe PGM is protocol is capable of multicasting data at high rates (500Mbps+)\nwith large messages (1MB+), however it requires setting the relevant ZMQ socket\noptions that are documented in xref:zmq_setsockopt.adoc[zmq_setsockopt]:\n\n* The 'ZMQ_RATE' should be set sufficiently high, e.g. 1Gbps\n* The 'ZMQ_RCVBUF' should be increased on the subscriber, e.g. 4MB\n* The 'ZMQ_SNDBUF' should be increased on the publisher, e.g. 4MB\n\nIt's important to note that the 'ZMQ_RCVBUF' and 'ZMQ_SNDBUF' options are\nlimited by the underlying host OS tx/rx buffer size limit. On linux, these can\nbe increased for the current session with the following commands:\n\n....\n# set tx/rx buffers to 4MB (default can also be read as the initial buffer size)\nsudo sysctl -w net.core.rmem_max=4194304\nsudo sysctl -w net.core.wmem_max=4194304\nsudo sysctl -w net.core.rmem_default=4194304\nsudo sysctl -w net.core.wmem_default=4194304\n....\n\n\n== EXAMPLE\n.Connecting a socket\n----\n//  Connecting to the multicast address 239.192.1.1, port 5555,\n//  using the first Ethernet network interface on Linux\n//  and the Encapsulated PGM protocol\nrc = zmq_connect(socket, \"epgm://eth0;239.192.1.1:5555\");\nassert (rc == 0);\n//  Connecting to the multicast address 239.192.1.1, port 5555,\n//  using the network interface with the address 192.168.1.1\n//  and the standard PGM protocol\nrc = zmq_connect(socket, \"pgm://192.168.1.1;239.192.1.1:5555\");\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq_tcp.adoc[zmq_tcp]\n* xref:zmq_ipc.adoc[zmq_ipc]\n* xref:zmq_inproc.adoc[zmq_inproc]\n* xref:zmq_vmci.adoc[zmq_vmci]\n* xref:zmq_vsock.adoc[zmq_vsock]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_plain.adoc",
    "content": "= zmq_plain(7)\n\n\n== NAME\nzmq_plain - clear-text authentication\n\n\n== SYNOPSIS\nThe PLAIN mechanism defines a simple username/password mechanism that \nlets a server authenticate a client. PLAIN makes no attempt at security \nor confidentiality. It is intended for use on internal networks where \nsecurity requirements are low. The PLAIN mechanism is defined by this \ndocument: <http://rfc.zeromq.org/spec:24>.\n\n\n== USAGE\nTo use PLAIN, the server shall set the ZMQ_PLAIN_SERVER option, and the \nclient shall set the ZMQ_PLAIN_USERNAME and ZMQ_PLAIN_PASSWORD socket \noptions. Which peer binds, and which connects, is not relevant.\n\n\n== SEE ALSO\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq_null.adoc[zmq_null]\n* xref:zmq_curve.adoc[zmq_curve]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_poll.adoc",
    "content": "= zmq_poll(3)\n\n\n== NAME\nzmq_poll - input/output multiplexing\n\n\n== SYNOPSIS\n\n*int zmq_poll (zmq_pollitem_t '*items', int 'nitems', long 'timeout');*\n\n\n== DESCRIPTION\nThe _zmq_poll()_ function provides a mechanism for applications to multiplex\ninput/output events in a level-triggered fashion over a set of sockets. Each\nmember of the array pointed to by the 'items' argument is a *zmq_pollitem_t*\nstructure. The 'nitems' argument specifies the number of items in the 'items'\narray. The *zmq_pollitem_t* structure is defined as follows:\n\n[\"literal\", subs=\"quotes\"]\ntypedef struct\n{\n    void '*socket';\n    zmq_fd_t 'fd';\n    short 'events';\n    short 'revents';\n} zmq_pollitem_t;\n\nFor each *zmq_pollitem_t* item, _zmq_poll()_ shall examine either the 0MQ\nsocket referenced by 'socket' *or* the standard socket specified by the file\ndescriptor 'fd', for the event(s) specified in 'events'. If both 'socket' and\n'fd' are set in a single *zmq_pollitem_t*, the 0MQ socket referenced by\n'socket' shall take precedence and the value of 'fd' shall be ignored.\n\nFor each *zmq_pollitem_t* item, _zmq_poll()_ shall first clear the 'revents'\nmember, and then indicate any requested events that have occurred by setting the\nbit corresponding to the event condition in the 'revents' member.\n\nIf none of the requested events have occurred on any *zmq_pollitem_t* item,\n_zmq_poll()_ shall wait 'timeout' milliseconds for an event to occur on\nany of the requested items. If the value of 'timeout' is `0`, _zmq_poll()_\nshall return immediately. If the value of 'timeout' is `-1`, _zmq_poll()_ shall\nblock indefinitely until a requested event has occurred on at least one\n*zmq_pollitem_t*.\n\nThe 'events' and 'revents' members of *zmq_pollitem_t* are bit masks constructed\nby OR'ing a combination of the following event flags:\n\n*ZMQ_POLLIN*::\nFor 0MQ sockets, at least one message may be received from the 'socket' without\nblocking. For standard sockets this is equivalent to the 'POLLIN' flag of the\n_poll()_ system call and generally means that at least one byte of data may be\nread from 'fd' without blocking.\n\n*ZMQ_POLLOUT*::\nFor 0MQ sockets, at least one message may be sent to the 'socket' without\nblocking. For standard sockets this is equivalent to the 'POLLOUT' flag of the\n_poll()_ system call and generally means that at least one byte of data may be\nwritten to 'fd' without blocking.\n\n*ZMQ_POLLERR*::\nFor standard sockets, this flag is passed through _zmq_poll()_ to the\nunderlying _poll()_ system call and generally means that some sort of error\ncondition is present on the socket specified by 'fd'. For 0MQ sockets this flag\nhas no effect if set in 'events', and shall never be returned in 'revents' by\n_zmq_poll()_.\n\n*ZMQ_POLLPRI*::\nFor 0MQ sockets this flags is of no use. For standard sockets this means there\nis urgent data to read. Refer to the POLLPRI flag for more information.\nFor file descriptor, refer to your use case: as an example, GPIO interrupts\nare signaled through a POLLPRI event.\nThis flag has no effect on Windows.\n\nNOTE: The _zmq_poll()_ function may be implemented or emulated using operating\nsystem interfaces other than _poll()_, and as such may be subject to the limits\nof those interfaces in ways not defined in this documentation.\n\n== THREAD SAFETY\nThe *zmq_pollitem_t* array must only be used by the thread which \nwill/is calling _zmq_poll_.\n\nIf a socket is contained in multiple *zmq_pollitem_t* arrays, each owned by a\ndifferent thread, the socket itself needs to be thread-safe (Server, Client, ...).\nOtherwise, behaviour is undefined.\n\n\n== RETURN VALUE\nUpon successful completion, the _zmq_poll()_ function shall return the number\nof *zmq_pollitem_t* structures with events signaled in 'revents' or `0` if no\nevents have been signaled. Upon failure, _zmq_poll()_ shall return `-1` and set\n'errno' to one of the values defined below.\n\n\n== ERRORS\n*ETERM*::\nAt least one of the members of the 'items' array refers to a 'socket' whose\nassociated 0MQ 'context' was terminated.\n*EFAULT*::\nThe provided 'items' was not valid (NULL).\n*EINTR*::\nThe operation was interrupted by delivery of a signal before any events were\navailable.\n\n\n== EXAMPLE\n.Polling indefinitely for input events on both a 0MQ socket and a standard socket.\n----\nzmq_pollitem_t items [2];\n/* First item refers to 0MQ socket 'socket' */\nitems[0].socket = socket;\nitems[0].events = ZMQ_POLLIN;\n/* Second item refers to standard socket 'fd' */\nitems[1].socket = NULL;\nitems[1].fd = fd;\nitems[1].events = ZMQ_POLLIN;\n/* Poll for events indefinitely */\nint rc = zmq_poll (items, 2, -1);\nassert (rc >= 0);\n/* Returned events will be stored in items[].revents */\n----\n\n\n== SEE ALSO\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq_send.adoc[zmq_send]\n* xref:zmq_recv.adoc[zmq_recv]\n* xref:zmq.adoc[zmq]\n\nYour operating system documentation for the _poll()_ system call.\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_poller.adoc",
    "content": "= zmq_poller(3)\n\n\n== NAME\nzmq_poller - input/output multiplexing\n\n\n== SYNOPSIS\n\n*void *zmq_poller_new (void);*\n\n*int zmq_poller_destroy (void '****poller_p');*\n\n*int zmq_poller_size (void '*poller');*\n\n*int zmq_poller_add (void '*poller', void '*socket', void '*user_data', short 'events');*\n\n*int zmq_poller_modify (void '*poller', void '*socket', short 'events');*\n\n*int zmq_poller_remove (void '*poller', void '*socket');*\n\n*int zmq_poller_add_fd (void '*poller', int 'fd', void '*user_data', short 'events');*\n\n*int zmq_poller_modify_fd (void '*poller', int 'fd', short 'events');*\n\n*int zmq_poller_remove_fd (void '*poller', int 'fd');*\n\n*int zmq_poller_wait (void '*poller',\n                          zmq_poller_event_t '*event',\n                          long 'timeout');*\n\n*int zmq_poller_wait_all (void '*poller',\n                          zmq_poller_event_t '*events',\n                          int 'n_events',\n                          long 'timeout');*\n\n*int zmq_poller_fd (void '*poller', zmq_fd_t '*fd');*\n\n== DESCRIPTION\nThe _zmq_poller_*_ functions provide a mechanism for applications to multiplex\ninput/output events in a level-triggered fashion over a set of sockets.\n\n_zmq_poller_new_ and _zmq_poller_destroy_ manage the lifetime of a poller\ninstance. _zmq_poller_new_ creates and returns a new poller instance, while\n_zmq_poller_destroy_ destroys it. A pointer to a valid poller must be passed\nas the _poller_p_ argument of _zmq_poller_destroy_. In particular,\n_zmq_poller_destroy_ may not be called multiple times for the same poller\ninstance. _zmq_poller_destroy_ sets the passed pointer to NULL in case of a\nsuccessful execution. _zmq_poller_destroy_ implicitly unregisters all\nregistered sockets and file descriptors.\n\n_zmq_poller_size_ queries the number of sockets or file descriptors registered\nwith a poller. The initial size of a poller is 0, a successful add operation\nincreases the size by 1 and a successful remove operation decreases the size\nby 1. The size is unaffected by the events specified.\n\n_zmq_poller_add_, _zmq_poller_modify_ and _zmq_poller_remove_ manage the 0MQ\nsockets registered with a poller.\n\n_zmq_poller_add_ registers a new _socket_ with a given _poller_. Both _poller_\nand _socket_ must point to valid 0MQ objects. The _events_ parameter specifies\nwhich event types the client wants to subscribe to. It is legal to specify no\nevents (i.e. 0), and activate them later with _zmq_poller_modify_.\nIn addition, _user_data_ may be specified, which is not used by the poller, but\npassed back to the caller when an event was signalled in a call to\n_zmq_poller_wait_ or _zmq_poller_wait_all_. _user_data_ may be NULL. If it is\nnot NULL, it must be a valid pointer. Otherwise, behaviour is undefined.\nYou must only add a socket to a single poller instance once (unless \n_zmq_poller_remove_ has been called for that socket before). You may\nadd a socket to multiple poller instances, if the socket itself\nis explicitly thread-safe (Server, Client, ...). If the socket is not,\nyou may invoke undefined behavior.\n\n_zmq_poller_modify_ modifies the subscribed events for a socket. It is\nlegal to specify no events (i.e. 0) to disable events temporarily, and\nreactivate them later with another call to _zmq_poller_modify_.\n\n_zmq_poller_remove_ removes a socket registration completely.\n_zmq_poller_remove_ must be called before a socket is closed with _zmq_close_.\n\nNote that it is not necessary to call _zmq_poller_remove_ for any socket\nbefore calling _zmq_poller_destroy_.\n\nAlso note that calling _zmq_poller_remove_ is not equivalent to calling\n_zmq_poller_modify_ with no events. _zmq_poller_modify_ does not free resources\nassociated with the socket registration, and requires that the _socket_\nremains valid.\n\n_zmq_poller_add_fd_, _zmq_poller_modify_fd_ and _zmq_poller_remove_fd_ are\nanalogous to the previous functions but manage regular file descriptors\nregistered with a poller. On Windows, these functions can only be used with\nWinSock sockets.\n\nIn the following, 0MQ sockets added with _zmq_poller_add_ and file descriptors\nadded with _zmq_poller_add_fd_ are referred to as 'registered objects'.\n\nThe *zmq_poller_event_t* structure is defined as follows:\n\n[\"literal\", subs=\"quotes\"]\ntypedef struct\n{\n    void *socket;\n    zmq_fd_t fd;\n    void *user_data;\n    short events;\n} zmq_poller_event_t;\n\nFor each registered object, _zmq_poller_wait_all()_ shall examine the\nregistered objects for the event(s) currently registered.\n\nIf none of the registered events have occurred, _zmq_poller_wait_all_ shall \nwait 'timeout' milliseconds for an event to occur on any of the registered \nobjects. If the value of 'timeout' is `0`, _zmq_poller_wait_all_ shall \nreturn immediately. If the value of 'timeout' is `-1`, _zmq_poller_wait_all_ \nshall block indefinitely until one event has occurred on any of the \nregistered objects.\n\nThe 'events' argument _zmq_poller_wait_all_ must be a pointer to an array of\nat least 'n_events' elements. Behaviour is undefined if 'events' does not point\nto an array of at least 'n_events' elements.\n\n_zmq_poller_wait_all_ returns at most 'n_events' events. If more than\n'n_events' events were signalled, only an unspecified subset of the signalled \nevents is returned through 'events'. \n\nA caller is advised to ensure that 'n_events' is equal to the number of \nregistered objects. Otherwise, a livelock situation may result: If more than \n'n_events' registered objects have an active event on each call to \n_zmq_poller_wait_all_, it might happen that the same subset of registered \nobjects is always returned, and the caller never notices the events on the \nothers. The number of objects registered can be queried with\n_zmq_poller_size_.\n\n_zmq_poller_wait_all_ returns the number of valid elements. The valid elements\nare placed in positions '0' to 'n_events - 1' in the 'events' array. All\nmembers of a valid element are set to valid values by _zmq_poller_wait_all_.\nFor socket events 'socket' is non-null and 'fd' is an operating system\nspecific value for an invalid socket (-1 or INVALID_SOCKET). For fd events\n'socket' is NULL and 'fd' is a valid file descriptor.\nThe client does therefore not need to initialize the contents of the events\narray before a call to _zmq_poller_wait_all_. It is unspecified whether the\nthe remaining elements of 'events' are written to by _zmq_poller_wait_all_.\n\n_zmq_poller_fd_ queries the file descriptor associated with the zmq_poller,\nand stores it in the address pointer to by 'fd'.\nThe zmq_poller is only guaranteed to have a file descriptor if\nat least one thread-safe socket is currently registered.\n\nNote that closing a socket that is registered in a poller leads to undefined\nbehavior. The socket must be unregistered first.\n\n== EVENT TYPES\n\nThe 'events' parameter of _zmq_poller_add_ and _zmq_poller_modify_, and the\n'events' member of the zmq_poller_event_t structure are bit masks constructed\nby OR'ing a combination of the following event flags:\n\n*ZMQ_POLLIN*::\nFor 0MQ sockets, at least one message may be received from the 'socket' without\nblocking. For standard sockets this is equivalent to the 'POLLIN' flag of the\n_poll()_ system call and generally means that at least one byte of data may be\nread from 'fd' without blocking.\n\n*ZMQ_POLLOUT*::\nFor 0MQ sockets, at least one message may be sent to the 'socket' without\nblocking. For standard sockets this is equivalent to the 'POLLOUT' flag of the\n_poll()_ system call and generally means that at least one byte of data may be\nwritten to 'fd' without blocking.\n\n*ZMQ_POLLERR*::\nFor 0MQ sockets this flag has no effect on the _zmq_poller_add_ and\n_zmq_poller_modify_ functions, and is never set in the\n'events' member of the zmq_poller_event_t structure.\nFor standard sockets, this flag is passed through _zmq_poller_wait_all_ to the\nunderlying _poll()_ system call and generally means that some sort of error\ncondition is present on the socket specified by 'fd'.\n\n*ZMQ_POLLPRI*::\nFor 0MQ sockets this flag has no effect on the _zmq_poller_add_ and\n_zmq_poller_modify_ functions, and is never set in the\n'events' member of the zmq_poller_event_t structure.\nFor standard sockets this means there\nis urgent data to read. Refer to the POLLPRI flag for more information.\nFor a file descriptor, refer to your OS documentation: as an example, GPIO\ninterrupts are signaled through a POLLPRI event.\nThis flag has no effect on Windows.\n\nNOTE: The _zmq_poller_*_ functions may be implemented or emulated using operating\nsystem interfaces other than _poll()_, and as such may be subject to the limits\nof those interfaces in ways not defined in this documentation.\n\n== THREAD SAFETY\nLike most other 0MQ objects, a poller is not thread-safe. All operations must\nbe called from the same thread. Otherwise, behaviour is undefined.\n\nIn addition to that, if you want to add a socket to multiple existing poller\ninstances, the socket itself needs to be thread-safe (Server, Client, ...).\nOtherwise, behaviour is undefined. \n\n== RETURN VALUE\n_zmq_poller_new_ returns a valid pointer to a poller, or NULL in case of a failure.\n\nAll functions that return an int, return -1 in case of a failure. In that case,\nzmq_errno() can be used to query the type of the error as described below.\n\n_zmq_poller_wait_all_ returns the number of events signalled and returned in \nthe events array. It never returns 0.\n\nAll other functions return 0 in case of a successful execution.\n\n== ERRORS\nOn _zmq_poller_new_:\n\n*ENOMEM*::\nA new poller could not be allocated successfully.\n\nOn _zmq_poller_destroy_:\n\n*EFAULT*::\n_poller_p_ did not point to a valid poller. Note that passing an invalid pointer (e.g.\npointer to deallocated memory) may cause undefined behaviour (e.g. an access violation).\n\nOn _zmq_poller_size_:\n\n*EFAULT*::\n_poller_ did not point to a valid poller. Note that passing an\ninvalid pointer (e.g. pointer to deallocated memory) may cause undefined\nbehaviour (e.g. an access violation).\n\nOn _zmq_poller_add_, _zmq_poller_modify_ and _zmq_poller_remove_:\n\n*EFAULT*::\n_poller_ did not point to a valid poller. Note that passing an\ninvalid pointer (e.g. pointer to deallocated memory) may cause undefined\nbehaviour (e.g. an access violation).\n*ENOTSOCK*::\n_socket_ did not point to a valid socket. Note that passing an\ninvalid pointer (e.g. pointer to deallocated memory) may cause undefined\nbehaviour (e.g. an access violation).\n\nOn _zmq_poller_add_:\n\n*EMFILE*::\nTODO\n\nOn _zmq_poller_add_ or _zmq_poller_add_fd_:\n\n*ENOMEM*::\nNecessary resources could not be allocated.\n*EINVAL*::\n_socket_ resp. _fd_ was already registered with the poller.\n\nOn _zmq_poller_modify_, _zmq_poller_modify_fd_, _zmq_poller_remove_ or\n_zmq_poller_remove_fd_:\n\n*EINVAL*::\n_socket_ resp. _fd_ was not registered with the poller.\n\nOn _zmq_poller_add_fd_, _zmq_poller_modify_fd_ and _zmq_poller_remove_fd_:\n\n*EBADF*::\nThe _fd_ specified was the retired fd.\n\nOn _zmq_poller_wait_ and _zmq_poller_wait_all_:\n\n*ENOMEM*::\nNecessary resources could not be allocated.\n*ETERM*::\nAt least one of the registered objects is a 'socket' whose associated 0MQ \n'context' was terminated.\n*EFAULT*::\nThe provided 'events' was NULL, or 'poller' did not point to a valid poller,\nor there are no registered objects or all event subscriptions are disabled\nand 'timeout' was negative.\n*EINTR*::\nThe operation was interrupted by delivery of a signal before any events were\navailable.\n*EAGAIN*::\nNo registered event was signalled before the timeout was reached.\n\nOn _zmq_poller_fd_:\n\n*EINVAL*::\nThe poller has no associated file descriptor.\n*EFAULT*::\nThe provided 'poller' did not point to a valid poller.\n\n== EXAMPLE\n.Polling indefinitely for input events on both a 0MQ socket and a standard socket.\n----\nvoid *poller = zmq_poller_new ();\n\n/* First item refers to 0MQ socket 'socket' */\nzmq_poller_add (poller, socket, NULL, ZMQ_POLLIN);\n/* Second item refers to standard socket 'fd' */\nzmq_poller_add_fd (poller, fd, NULL, ZMQ_POLLIN);\n\nzmq_poller_event_t events [2];\n/* Poll for events indefinitely */\nint rc = zmq_poller_wait_all (poller, events, 2, -1);\nassert (rc >= 0);\n/* Returned events will be stored in 'events' */\nfor (int i = 0; i < 2; ++i) {\n    if (events[i].socket == socket && events[i].events & ZMQ_POLLIN) {\n        // ...\n    } else if (events[i].fd == fd && events[i].events & ZMQ_POLLIN)) {\n        // ...\n    }\n}\nzmq_poller_destroy (&poller);\n----\n\n\n== SEE ALSO\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq_send.adoc[zmq_send]\n* xref:zmq_recv.adoc[zmq_recv]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_ppoll.adoc",
    "content": "= zmq_poll(3)\n\n\n== NAME\nzmq_ppoll - input/output multiplexing with signal mask\n\n\n== SYNOPSIS\n\n*int zmq_ppoll (zmq_pollitem_t '*items', int 'nitems', long 'timeout', const sigset_t '*sigmask');*\n\n\n== DESCRIPTION\nThe relationship between _zmq_poll()_ and _zmq_ppoll()_ is analogous to the\nrelationship between poll(2) and ppoll(2) and between select(2) and\npselect(2): _zmq_ppoll()_ allows an application to safely wait until either a\nfile descriptor becomes ready or until a signal is caught.\n\nWhen using _zmq_ppoll()_ with 'sigmask' set to NULL, its behavior is identical\nto that of _zmq_poll()_. See xref:zmq_poll.adoc[zmq_poll] for more on this.\n\nTo make full use of _zmq_ppoll()_, a non-NULL pointer to a signal mask must be\nconstructed and passed to 'sigmask'. See sigprocmask(2) for more details. When\nthis is done, inside the actual _ppoll()_ (or _pselect()_, see note below)\nsystem call, an atomic operation consisting of three steps is performed:\n  1. The current signal mask is replaced by the one pointed to by 'sigmask'.\n  2. The actual _poll()_ call is done.\n  3. The original signal mask is restored.\nBecause these operations are done atomically, there is no opportunity for race\nconditions in between the calls changing the signal mask and the poll/select\nsystem call. This means that only during this (atomic) call, we can unblock\ncertain signals, so that they can be handled *at that time only*, not outside\nof the call. This means that effectively, we extend our poller into a function\nthat not only watches sockets for changes, but also watches the \"POSIX signal\nsocket\" for incoming signals. At other times, these signals will be blocked,\nand we will not have to deal with interruptions in system calls at these other\ntimes.\n\nNOTE: The _zmq_ppoll()_ function may be implemented or emulated using operating\nsystem interfaces other than _ppoll()_, and as such may be subject to the\nlimits of those interfaces in ways not defined in this documentation.\n\nNOTE: There is no _ppoll_ or _pselect_ on Windows, so _zmq_ppoll()_ is not\nsupported in Windows builds. It is still callable, but its 'sigmask' has void\npointer type (because 'sigset_t' is also not available on Windows) and\n_zmq_ppoll()_ will return with an error (see error section below).\n\n== THREAD SAFETY\nThe *zmq_pollitem_t* array must only be used by the thread which\nwill/is calling _zmq_ppoll_.\n\nIf a socket is contained in multiple *zmq_pollitem_t* arrays, each owned by a\ndifferent thread, the socket itself needs to be thead-safe (Server, Client, ...).\nOtherwise, behaviour is undefined.\n\n\n== RETURN VALUE\nUpon successful completion, the _zmq_ppoll()_ function shall return the number\nof *zmq_pollitem_t* structures with events signaled in 'revents' or `0` if no\nevents have been signaled. Upon failure, _zmq_ppoll()_ shall return `-1` and set\n'errno' to one of the values defined below.\n\n\n== ERRORS\n*ETERM*::\nAt least one of the members of the 'items' array refers to a 'socket' whose\nassociated 0MQ 'context' was terminated.\n*EFAULT*::\nThe provided 'items' was not valid (NULL).\n*EINTR*::\nThe operation was interrupted by delivery of a signal before any events were\navailable.\n*EINTR*::\nThe operation was interrupted by delivery of a signal before any events were\navailable.\n*ENOTSUP*::\n_zmq_ppoll()_ was not activated in this build.\n\n\n== EXAMPLE\n.Polling indefinitely for input events on both a 0MQ socket and a standard socket.\nSee the _example section_ of xref:zmq_poll.adoc[zmq_poll] One only needs to replace\nthe _zmq_poll_ call with _zmq_ppoll_ and add a _NULL_ argument for the 'sigmask'\nparameter.\n\n.Handle SIGTERM during _zmq_ppoll_ (and block it otherwise).\n----\n// simple global signal handler for SIGTERM\nstatic bool sigterm_received = false;\nvoid handle_sigterm (int signum) {\n    sigterm_received = true;\n}\n\n// set up signal mask and install handler for SIGTERM\nsigset_t sigmask, sigmask_without_sigterm;\nsigemptyset(&sigmask);\nsigaddset(&sigmask, SIGTERM);\nsigprocmask(SIG_BLOCK, &sigmask, &sigmask_without_sigterm);\nstruct sigaction sa;\nmemset(&sa, '\\0', sizeof(sa));\nsa.sa_handler = handle_sigterm;\n\n// poll\nzmq_pollitem_t items [1];\n// Just one item, which refers to 0MQ socket 'socket' */\nitems[0].socket = socket;\nitems[0].events = ZMQ_POLLIN;\n// Poll for events indefinitely, but also exit on SIGTERM\nint rc = zmq_poll (items, 2, -1, &sigmask_without_sigterm);\nif (rc < 0 && errno == EINTR && sigterm_received) {\n  // do your SIGTERM business\n} else {\n  // do your non-SIGTERM error handling\n}\n----\n\n\n== SEE ALSO\n* xref:zmq_poll.adoc[zmq_poll]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq_send.adoc[zmq_send]\n* xref:zmq_recv.adoc[zmq_recv]\n* xref:zmq.adoc[zmq]\n\nYour operating system documentation for the _poll()_ system call.\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_proxy.adoc",
    "content": "= zmq_proxy(3)\n\n== NAME\nzmq_proxy - start built-in 0MQ proxy\n\n\n== SYNOPSIS\n*int zmq_proxy (void '*frontend', void '*backend', void '*capture');*\n\n\n== DESCRIPTION\nThe _zmq_proxy()_ function starts the built-in 0MQ proxy in the current\napplication thread.\n\nThe proxy connects a frontend socket to a backend socket. Conceptually, data\nflows from frontend to backend. Depending on the socket types, replies may flow\nin the opposite direction. The direction is conceptual only; the proxy is fully\nsymmetric and there is no technical difference between frontend and backend.\n\nBefore calling _zmq_proxy()_ you must set any socket options, and connect or\nbind both frontend and backend sockets. The two conventional proxy models are:\n\n_zmq_proxy()_ runs in the current thread and returns only if/when the current\ncontext is closed.\n\nIf the capture socket is not NULL, the proxy shall send all messages, received\non both frontend and backend, to the capture socket. The capture socket should\nbe a 'ZMQ_PUB', 'ZMQ_DEALER', 'ZMQ_PUSH', or 'ZMQ_PAIR' socket.\n\nRefer to xref:zmq_socket.adoc[zmq_socket] for a description of the available socket types.\n\n== EXAMPLE USAGE\n\nShared Queue\n~~~~~~~~~~~~\n\nWhen the frontend is a ZMQ_ROUTER socket, and the backend is a ZMQ_DEALER\nsocket, the proxy shall act as a shared queue that collects requests from a\nset of clients, and distributes these fairly among a set of services.\nRequests shall be fair-queued from frontend connections and distributed evenly\nacross backend connections. Replies shall automatically return to the client\nthat made the original request.\n\nForwarder\n~~~~~~~~~\n\nWhen the frontend is a ZMQ_XSUB socket, and the backend is a ZMQ_XPUB socket,\nthe proxy shall act as a message forwarder that collects messages from a set\nof publishers and forwards these to a set of subscribers. This may be used to\nbridge networks transports, e.g. read on tcp:// and forward on pgm://.\n\nStreamer\n~~~~~~~~\n\nWhen the frontend is a ZMQ_PULL socket, and the backend is a ZMQ_PUSH socket,\nthe proxy shall collect tasks from a set of clients and forwards these to a set\nof workers using the pipeline pattern.\n\n== RETURN VALUE\nThe _zmq_proxy()_ function always returns `-1` and 'errno' set to *ETERM* or\n*EINTR* (the 0MQ 'context' associated with either of the specified sockets was\nterminated) or *EFAULT* (the provided 'frontend' or 'backend' was invalid).\n\n\n== EXAMPLE\n.Creating a shared queue proxy\n----\n//  Create frontend and backend sockets\nvoid *frontend = zmq_socket (context, ZMQ_ROUTER);\nassert (frontend);\nvoid *backend = zmq_socket (context, ZMQ_DEALER);\nassert (backend);\n//  Bind both sockets to TCP ports\nassert (zmq_bind (frontend, \"tcp://*:5555\") == 0);\nassert (zmq_bind (backend, \"tcp://*:5556\") == 0);\n//  Start the queue proxy, which runs until ETERM\nzmq_proxy (frontend, backend, NULL);\n----\n\n\n== SEE ALSO\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_proxy_steerable.adoc",
    "content": "= zmq_proxy_steerable(3)\n\n== NAME\nzmq_proxy_steerable - built-in 0MQ proxy with control flow\n\n\n== SYNOPSIS\n*int zmq_proxy_steerable (const void '*frontend', const void '*backend', \n     const void '*capture', const void '*control');*\n\n\n== DESCRIPTION\n\nThe _zmq_proxy_steerable()_ function is a variant of the _zmq_proxy()_ function.\nIt accepts a fourth _control_ socket.  When the _control_ socket is _NULL_ the\ntwo functions operate identically.\n\nWhen a _control_ socket of type _REP_ or _PAIR_ is provided to the proxy function the\napplication may send commands to the proxy.  The following commands are\nsupported.\n\n_PAUSE_::\n    The proxy will cease transferring messages between its endpoints.  _REP_ control socket will reply with an empty message. No response otherwise.\n\n_RESUME_::\n    The proxy will resume transferring messages between its endpoints.  _REP_ control socket will reply with an empty message. No response otherwise. \n\n_TERMINATE_::\n    The proxy function will exit with a return value of 0.  _REP_ control socket will reply with an empty message. No response otherwise.\n\n_STATISTICS_::\n    The proxy state will remain unchanged and reply with a set of simple summary values of the messages that have been sent through the proxy as described next. Control socket must support sending.\n\nThere are eight statistics values, each of size _uint64_t_ in the multi-part\nmessage reply to the _STATISTICS_ command.  These are:\n\n- number of messages received by the frontend socket\n\n- number of bytes received by the frontend socket\n\n- number of messages sent by the frontend socket\n\n- number of bytes sent by the frontend socket\n\n- number of messages received by the backend socket\n\n- number of bytes received by the backend socket\n\n- number of messages sent by the backend socket\n\n- number of bytes sent by the backend socket\n\nMessage totals count each part in a multipart message individually.\n\n\n== RETURN VALUE\nThe _zmq_proxy_steerable()_ function returns 0 if TERMINATE is received on its\ncontrol socket.  Otherwise, it returns -1 and errno set to ETERM or EINTR (the\n0MQ context associated with either of the specified sockets was terminated) or\nEFAULT (the provided frontend or backend was invalid).\n\n\n== EXAMPLE\n.Create a function to run the proxy\n----\n// Create the frontend and backend sockets to be proxied\nvoid *frontend = zmq_socket (context, ZMQ_ROUTER);\nvoid *backend = zmq_socket (context, ZMQ_DEALER);\n\n// Create the proxy control socket\nvoid *control = zmq_socket (context, ZMQ_REP);\n\n// Bind the sockets.  \nzmq_bind (frontend, \"tcp://*:5555\");\nzmq_bind (backend, \"tcp://*:5556\");\nzmq_bind (control, \"tcp://*:5557\");\n\nzmq_proxy_steerable(frontend, backend, NULL, control);\n----\n.Code in another thread/process to steer the proxy.\n----\nvoid *control = zmq_socket (context, ZMQ_REQ);\nzmq_connect (control, \"tcp://*:5557\");\n\nzmq_msg_t msg;\n\nzmq_send (control, \"PAUSE\", 5, 0);\nzmq_msg_recv (&msg, control, 0));\n\nzmq_send (control, \"RESUME\", 6, 0);\nzmq_msg_recv (&msg, control, 0));\n\nzmq_send (control, \"STATISTICS\", 10, 0);\nwhile (1) {\n    zmq_msg_recv (&msg, control, 0));\n    printf(\" %lu\", *(uint64_t *)zmq_msg_data (&msg));\n    if (!zmq_msg_get (&msg, ZMQ_MORE))\n        break;\n}\nprintf(\"\\n\");\n\nzmq_send (control, \"TERMINATE\", 9, 0);\nzmq_msg_recv (&msg, control, 0));\n\nzmq_close(frontend);\nzmq_close(backend);\nzmq_close(control);\n----\n\n\n== SEE ALSO\n* xref:zmq_proxy.adoc[zmq_proxy]\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_recv.adoc",
    "content": "= zmq_recv(3)\n\n\n== NAME\nzmq_recv - receive a message part from a socket\n\n\n== SYNOPSIS\n*int zmq_recv (void '*socket', void '*buf', size_t 'len', int 'flags');*\n\n\n== DESCRIPTION\nThe _zmq_recv()_ function shall receive a message from the socket referenced\nby the 'socket' argument and store it in the buffer referenced by the 'buf'\nargument. Any bytes exceeding the length specified by the 'len' argument shall\nbe truncated. If there are no messages available on the specified 'socket'\nthe _zmq_recv()_ function shall block until the request can be satisfied.\nThe 'flags' argument is a combination of the flags defined below: The 'buf'\nargument may be null if len is zero.\n\n*ZMQ_DONTWAIT*::\nSpecifies that the operation should be performed in non-blocking mode. If there\nare no messages available on the specified 'socket', the _zmq_recv()_\nfunction shall fail with 'errno' set to EAGAIN.\n\n\nMulti-part messages\n~~~~~~~~~~~~~~~~~~~\nA 0MQ message is composed of 1 or more message parts. 0MQ ensures atomic\ndelivery of messages: peers shall receive either all _message parts_ of a\nmessage or none at all. The total number of message parts is unlimited except\nby available memory.\n\nAn application that processes multi-part messages must use the _ZMQ_RCVMORE_\nxref:zmq_getsockopt.adoc[zmq_getsockopt] option after calling _zmq_recv()_ to determine if\nthere are further parts to receive.\n\n== RETURN VALUE\nThe _zmq_recv()_ function shall return number of bytes in the message\nif successful. Note that the value can exceed the value of the 'len' parameter\nin case the message was truncated. If not successful the function shall return\n`-1` and set 'errno' to one of the values defined below.\n\n\n== ERRORS\n*EAGAIN*::\nEither the timeout set via the socket-option ZMQ_RCVTIMEO (see xref:zmq_setsockopt.adoc[zmq_setsockopt])\nhas been reached (flag ZMQ_DONTWAIT not set) without being able to read a message\nfrom the socket or there are no messages available at the moment (flag ZMQ_DONTWAIT set)\nand the operation would block.\n*ENOTSUP*::\nThe _zmq_recv()_ operation is not supported by this socket type.\n*EFSM*::\nThe _zmq_recv()_ operation cannot be performed on this socket at the moment\ndue to the socket not being in the appropriate state.  This error may occur with\nsocket types that switch between several states, such as ZMQ_REP.  See the\n_messaging patterns_ section of xref:zmq_socket.adoc[zmq_socket] for more information.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EINTR*::\nThe operation was interrupted by delivery of a signal before a message was\navailable.\n\n\n== EXAMPLE\n.Receiving a message from a socket\n----\nchar buf [256];\nnbytes = zmq_recv (socket, buf, 256, 0);\nassert (nbytes != -1);\n----\n\n\n== SEE ALSO\n* xref:zmq_send.adoc[zmq_send]\n* xref:zmq_getsockopt.adoc[zmq_getsockopt]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_recvmsg.adoc",
    "content": "= zmq_recvmsg(3)\n\n\n== NAME\nzmq_recvmsg - receive a message part from a socket\n\n\n== SYNOPSIS\n*int zmq_recvmsg (void '*socket', zmq_msg_t '*msg', int 'flags');*\n\n\n== DESCRIPTION\nThe _zmq_recvmsg()_ function shall receive a message part from the socket\nreferenced by the 'socket' argument and store it in the message referenced by\nthe 'msg' argument. Any content previously stored in 'msg' shall be properly\ndeallocated. If there are no message parts available on the specified 'socket'\nthe _zmq_recvmsg()_ function shall block until the request can be satisfied.\nThe 'flags' argument is a combination of the flags defined below:\n\n*ZMQ_DONTWAIT*::\nSpecifies that the operation should be performed in non-blocking mode. If there\nare no messages available on the specified 'socket', the _zmq_recvmsg()_\nfunction shall fail with 'errno' set to EAGAIN.\n\nNOTE: this API method is deprecated in favor of zmq_msg_recv(3).\n\n\nMulti-part messages\n~~~~~~~~~~~~~~~~~~~\nA 0MQ message is composed of 1 or more message parts. Each message\npart is an independent 'zmq_msg_t' in its own right. 0MQ ensures atomic\ndelivery of messages: peers shall receive either all _message parts_ of a\nmessage or none at all. The total number of message parts is unlimited except\nby available memory.\n\nAn application that processes multi-part messages must use the _ZMQ_RCVMORE_\nxref:zmq_getsockopt.adoc[zmq_getsockopt] option after calling _zmq_recvmsg()_ to determine if\nthere are further parts to receive.\n\n\n== RETURN VALUE\nThe _zmq_recvmsg()_ function shall return number of bytes in the message\nif successful. Otherwise it shall return `-1` and set 'errno' to one of the\nvalues defined below.\n\n\n== ERRORS\n*EAGAIN*::\nEither the timeout set via the socket-option ZMQ_RCVTIMEO (see xref:zmq_setsockopt.adoc[zmq_setsockopt])\nhas been reached (flag ZMQ_DONTWAIT not set) without being able to read a message\nfrom the socket or there are no messages available at the moment (flag ZMQ_DONTWAIT set)\nand the operation would block.\n*ENOTSUP*::\nThe _zmq_recvmsg()_ operation is not supported by this socket type.\n*EFSM*::\nThe _zmq_recvmsg()_ operation cannot be performed on this socket at the moment\ndue to the socket not being in the appropriate state.  This error may occur with\nsocket types that switch between several states, such as ZMQ_REP.  See the\n_messaging patterns_ section of xref:zmq_socket.adoc[zmq_socket] for more information.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EINTR*::\nThe operation was interrupted by delivery of a signal before a message was\navailable.\n*EFAULT*::\nThe message passed to the function was invalid.\n\n\n== EXAMPLE\n.Receiving a message from a socket\n----\n/* Create an empty 0MQ message */\nzmq_msg_t msg;\nint rc = zmq_msg_init (&msg);\nassert (rc == 0);\n/* Block until a message is available to be received from socket */\nrc = zmq_recvmsg (socket, &msg, 0);\nassert (rc != -1);\n/* Release message */\nzmq_msg_close (&msg);\n----\n\n.Receiving a multi-part message\n----\nint more;\nsize_t more_size = sizeof (more);\ndo {\n    /* Create an empty 0MQ message to hold the message part */\n    zmq_msg_t part;\n    int rc = zmq_msg_init (&part);\n    assert (rc == 0);\n    /* Block until a message is available to be received from socket */\n    rc = zmq_recvmsg (socket, &part, 0);\n    assert (rc != -1);\n    /* Determine if more message parts are to follow */\n    rc = zmq_getsockopt (socket, ZMQ_RCVMORE, &more, &more_size);\n    assert (rc == 0);\n    zmq_msg_close (&part);\n} while (more);\n----\n\n\n== SEE ALSO\n* xref:zmq_recv.adoc[zmq_recv]\n* xref:zmq_send.adoc[zmq_send]\n* xref:zmq_getsockopt.adoc[zmq_getsockopt]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_send.adoc",
    "content": "= zmq_send(3)\n\n\n== NAME\nzmq_send - send a message part on a socket\n\n\n== SYNOPSIS\n*int zmq_send (void '*socket', const void '*buf', size_t 'len', int 'flags');*\n\n\n== DESCRIPTION\nThe _zmq_send()_ function shall queue a message created from the buffer\nreferenced by the 'buf' and 'len' arguments. The 'flags' argument is\na combination of the flags defined below:\n\n*ZMQ_DONTWAIT*::\nFor socket types (DEALER, PUSH) that block (either with ZMQ_IMMEDIATE option set\nand no peer available, or all peers having full high-water mark), specifies that\nthe operation should be performed in non-blocking mode. If the message cannot be\nqueued on the 'socket', the _zmq_send()_ function shall fail with 'errno' set\nto EAGAIN.\n\n*ZMQ_SNDMORE*::\nSpecifies that the message being sent is a multi-part message, and that further\nmessage parts are to follow. Refer to the section regarding multi-part messages\nbelow for a detailed description.\n\nNOTE: A successful invocation of _zmq_send()_ does not indicate that the\nmessage has been transmitted to the network, only that it has been queued on\nthe 'socket' and 0MQ has assumed responsibility for the message.\n\n\nMulti-part messages\n~~~~~~~~~~~~~~~~~~~\nA 0MQ message is composed of 1 or more message parts. 0MQ ensures atomic\ndelivery of messages: peers shall receive either all _message parts_ of a\nmessage or none at all. The total number of message parts is unlimited except\nby available memory.\n\nAn application that sends multi-part messages must use the _ZMQ_SNDMORE_ flag\nwhen sending each message part except the final one.\n\n\n== RETURN VALUE\nThe _zmq_send()_ function shall return number of bytes in the message\nif successful. Otherwise it shall return `-1` and set 'errno' to one of the\nvalues defined below.\n\n\n== ERRORS\n*EAGAIN*::\nNon-blocking mode was requested and the message cannot be sent at the moment.\n*ENOTSUP*::\nThe _zmq_send()_ operation is not supported by this socket type.\n*EINVAL*::\nThe sender tried to send multipart data, which the socket type does not allow.\n*EFSM*::\nThe _zmq_send()_ operation cannot be performed on this socket at the moment\ndue to the socket not being in the appropriate state.  This error may occur with\nsocket types that switch between several states, such as ZMQ_REP.  See the\n_messaging patterns_ section of xref:zmq_socket.adoc[zmq_socket] for more information.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EINTR*::\nThe operation was interrupted by delivery of a signal before the message was\nsent.\n*EHOSTUNREACH*::\nThe message cannot be routed.\n\n\n== EXAMPLE\n.Sending a multi-part message\n----\n/* Send a multi-part message consisting of three parts to socket */\nrc = zmq_send (socket, \"ABC\", 3, ZMQ_SNDMORE);\nassert (rc == 3);\nrc = zmq_send (socket, \"DEFGH\", 5, ZMQ_SNDMORE);\nassert (rc == 5);\n/* Final part; no more parts to follow */\nrc = zmq_send (socket, \"JK\", 2, 0);\nassert (rc == 2);\n----\n\n== SEE ALSO\n* xref:zmq_send_const.adoc[zmq_send_const]\n* xref:zmq_recv.adoc[zmq_recv]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_send_const.adoc",
    "content": "= zmq_send_const(3)\n\n\n== NAME\nzmq_send_const - send a constant-memory message part on a socket\n\n\n== SYNOPSIS\n*int zmq_send_const (void '*socket', const void '*buf', size_t 'len', int 'flags');*\n\n\n== DESCRIPTION\nThe _zmq_send_const()_ function shall queue a message created from the buffer\nreferenced by the 'buf' and 'len' arguments. The message buffer is assumed\nto be constant-memory and will therefore not be copied or deallocated\nin any way. The 'flags' argument is a combination of the flags defined below:\n\n*ZMQ_DONTWAIT*::\nFor socket types (DEALER, PUSH) that block (either with ZMQ_IMMEDIATE option set\nand no peer available, or all peers having full high-water mark), specifies that\nthe operation should be performed in non-blocking mode. If the message cannot be\nqueued on the 'socket', the _zmq_send_const()_ function shall fail with 'errno' set\nto EAGAIN.\n\n*ZMQ_SNDMORE*::\nSpecifies that the message being sent is a multi-part message, and that further\nmessage parts are to follow. Refer to the section regarding multi-part messages\nbelow for a detailed description.\n\nNOTE: A successful invocation of _zmq_send_const()_ does not indicate that the\nmessage has been transmitted to the network, only that it has been queued on\nthe 'socket' and 0MQ has assumed responsibility for the message.\n\n\nMulti-part messages\n~~~~~~~~~~~~~~~~~~~\nA 0MQ message is composed of 1 or more message parts. 0MQ ensures atomic\ndelivery of messages: peers shall receive either all _message parts_ of a\nmessage or none at all. The total number of message parts is unlimited except\nby available memory.\n\nAn application that sends multi-part messages must use the _ZMQ_SNDMORE_ flag\nwhen sending each message part except the final one.\n\n\n== RETURN VALUE\nThe _zmq_send_const()_ function shall return number of bytes in the message\nif successful. Otherwise it shall return `-1` and set 'errno' to one of the\nvalues defined below.\n\n\n== ERRORS\n*EAGAIN*::\nNon-blocking mode was requested and the message cannot be sent at the moment.\n*ENOTSUP*::\nThe _zmq_send_const()_ operation is not supported by this socket type.\n*EFSM*::\nThe _zmq_send_const()_ operation cannot be performed on this socket at the moment\ndue to the socket not being in the appropriate state.  This error may occur with\nsocket types that switch between several states, such as ZMQ_REP.  See the\n_messaging patterns_ section of xref:zmq_socket.adoc[zmq_socket] for more information.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EINTR*::\nThe operation was interrupted by delivery of a signal before the message was\nsent.\n*EHOSTUNREACH*::\nThe message cannot be routed.\n\n\n== EXAMPLE\n.Sending a multi-part message\n----\n/* Send a multi-part message consisting of three parts to socket */\nrc = zmq_send_const (socket, \"ABC\", 3, ZMQ_SNDMORE);\nassert (rc == 3);\nrc = zmq_send_const (socket, \"DEFGH\", 5, ZMQ_SNDMORE);\nassert (rc == 5);\n/* Final part; no more parts to follow */\nrc = zmq_send_const (socket, \"JK\", 2, 0);\nassert (rc == 2);\n----\n\n== SEE ALSO\n* xref:zmq_send.adoc[zmq_send]\n* xref:zmq_recv.adoc[zmq_recv]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_sendmsg.adoc",
    "content": "= zmq_sendmsg(3)\n\n\n== NAME\nzmq_sendmsg - send a message part on a socket\n\n\n== SYNOPSIS\n*int zmq_sendmsg (void '*socket', zmq_msg_t '*msg', int 'flags');*\n\n\n== DESCRIPTION\nThe _zmq_sendmsg()_ function shall queue the message referenced by the 'msg'\nargument to be sent to the socket referenced by the 'socket' argument.  The\n'flags' argument is a combination of the flags defined below:\n\n*ZMQ_DONTWAIT*::\nFor socket types (DEALER, PUSH) that block (either with ZMQ_IMMEDIATE option set\nand no peer available, or all peers having full high-water mark), specifies that\nthe operation should be performed in non-blocking mode. If the message cannot be\nqueued on the 'socket', the _zmq_sendmsg()_ function shall fail with 'errno' set\nto EAGAIN.\n\n*ZMQ_SNDMORE*::\nSpecifies that the message being sent is a multi-part message, and that further\nmessage parts are to follow. Refer to the section regarding multi-part messages\nbelow for a detailed description.\n\nThe _zmq_msg_t_ structure passed to _zmq_sendmsg()_ is nullified during the\ncall. If you want to send the same message to multiple sockets you have to copy\nit (e.g. using _zmq_msg_copy()_).\n\nNOTE: A successful invocation of _zmq_sendmsg()_ does not indicate that the\nmessage has been transmitted to the network, only that it has been queued on\nthe 'socket' and 0MQ has assumed responsibility for the message.\n\nNOTE: this API method is deprecated in favor of zmq_msg_send(3).\n\nMulti-part messages\n~~~~~~~~~~~~~~~~~~~\nA 0MQ message is composed of 1 or more message parts. Each message\npart is an independent 'zmq_msg_t' in its own right. 0MQ ensures atomic\ndelivery of messages: peers shall receive either all _message parts_ of a\nmessage or none at all. The total number of message parts is unlimited except\nby available memory.\n\nAn application that sends multi-part messages must use the _ZMQ_SNDMORE_ flag\nwhen sending each message part except the final one.\n\n== RETURN VALUE\nThe _zmq_sendmsg()_ function shall return number of bytes in the message\nif successful. Otherwise it shall return `-1` and set 'errno' to one of the\nvalues defined below.\n\n\n== ERRORS\n*EAGAIN*::\nNon-blocking mode was requested and the message cannot be sent at the moment.\n*ENOTSUP*::\nThe _zmq_sendmsg()_ operation is not supported by this socket type.\n*EINVAL*::\nThe sender tried to send multipart data, which the socket type does not allow.\n*EFSM*::\nThe _zmq_sendmsg()_ operation cannot be performed on this socket at the moment\ndue to the socket not being in the appropriate state.  This error may occur with\nsocket types that switch between several states, such as ZMQ_REP.  See the\n_messaging patterns_ section of xref:zmq_socket.adoc[zmq_socket] for more information.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EINTR*::\nThe operation was interrupted by delivery of a signal before the message was\nsent.\n*EFAULT*::\nInvalid message.\n*EHOSTUNREACH*::\nThe message cannot be routed.\n\n\n== EXAMPLE\n.Filling in a message and sending it to a socket\n----\n/* Create a new message, allocating 6 bytes for message content */\nzmq_msg_t msg;\nint rc = zmq_msg_init_size (&msg, 6);\nassert (rc == 0);\n/* Fill in message content with 'AAAAAA' */\nmemset (zmq_msg_data (&msg), 'A', 6);\n/* Send the message to the socket */\nrc = zmq_sendmsg (socket, &msg, 0);\nassert (rc == 6);\n----\n\n.Sending a multi-part message\n----\n/* Send a multi-part message consisting of three parts to socket */\nrc = zmq_sendmsg (socket, &part1, ZMQ_SNDMORE);\nrc = zmq_sendmsg (socket, &part2, ZMQ_SNDMORE);\n/* Final part; no more parts to follow */\nrc = zmq_sendmsg (socket, &part3, 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_recv.adoc[zmq_recv]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_setsockopt.adoc",
    "content": "= zmq_setsockopt(3)\n\n\n== NAME\n\nzmq_setsockopt - set 0MQ socket options\n\n\n== SYNOPSIS\n*int zmq_setsockopt (void '*socket', int 'option_name', const void '*option_value', size_t 'option_len');*\n\nCaution: All options, with the exception of ZMQ_SUBSCRIBE, ZMQ_UNSUBSCRIBE,\nZMQ_LINGER, ZMQ_ROUTER_HANDOVER, ZMQ_ROUTER_MANDATORY, ZMQ_PROBE_ROUTER,\nZMQ_XPUB_VERBOSE, ZMQ_XPUB_VERBOSER, ZMQ_REQ_CORRELATE,\nZMQ_REQ_RELAXED, ZMQ_SNDHWM and ZMQ_RCVHWM, only take effect for\nsubsequent socket bind/connects.\n\nSpecifically, security options take effect for subsequent bind/connect calls,\nand can be changed at any time to affect subsequent binds and/or connects.\n\n== DESCRIPTION\nThe _zmq_setsockopt()_ function shall set the option specified by the\n'option_name' argument to the value pointed to by the 'option_value' argument\nfor the 0MQ socket pointed to by the 'socket' argument. The 'option_len'\nargument is the size of the option value in bytes. For options taking a value of\ntype \"character string\", the provided byte data should either contain no zero\nbytes, or end in a single zero byte (terminating ASCII NUL character).\n\nThe following socket options can be set with the _zmq_setsockopt()_ function:\n\n\nZMQ_AFFINITY: Set I/O thread affinity\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_AFFINITY' option shall set the I/O thread affinity for newly created\nconnections on the specified 'socket'.\n\nAffinity determines which threads from the 0MQ I/O thread pool associated with\nthe socket's _context_ shall handle newly created connections.  A value of zero\nspecifies no affinity, meaning that work shall be distributed fairly among all\n0MQ I/O threads in the thread pool. For non-zero values, the lowest bit\ncorresponds to thread 1, second lowest bit to thread 2 and so on.  For example,\na value of 3 specifies that subsequent connections on 'socket' shall be handled\nexclusively by I/O threads 1 and 2.\n\nSee also xref:zmq_init.adoc[zmq_init] for details on allocating the number of I/O\nthreads for a specific _context_.\n\n[horizontal]\nOption value type:: uint64_t\nOption value unit:: N/A (bitmap)\nDefault value:: 0\nApplicable socket types:: N/A\n\n\nZMQ_BACKLOG: Set maximum length of the queue of outstanding connections\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_BACKLOG' option shall set the maximum length of the queue of\noutstanding peer connections for the specified 'socket'; this only applies to\nconnection-oriented transports. For details refer to your operating system\ndocumentation for the 'listen' function.\n\n[horizontal]\nOption value type:: int\nOption value unit:: connections\nDefault value:: 100\nApplicable socket types:: all, only for connection-oriented transports.\n\n\nZMQ_BINDTODEVICE: Set name of device to bind the socket to\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_BINDTODEVICE' option binds this socket to a particular device, eg.\nan interface or VRF. If a socket is bound to an interface, only packets\nreceived from that particular interface are processed by the socket. If device\nis a VRF device, then subsequent binds/connects to that socket use addresses\nin the VRF routing table.\n\nNOTE: requires setting CAP_NET_RAW on the compiled program.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all, when using TCP or UDP transports.\n\n\nZMQ_BUSY_POLL: This removes delays caused by the interrupt and the resultant context switch.\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nBusy polling helps reduce latency in the network receive path by allowing socket layer code\nto poll the receive queue of a network device, and disabling network interrupts. This removes\ndelays caused by the interrupt and the resultant context switch. However, it also increases\nCPU utilization. Busy polling also prevents the CPU from sleeping, which can incur additional\npower consumption.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0,1\nDefault value:: 0\nApplicable socket types:: all\n\n\nZMQ_CONNECT_RID: Assign the next outbound connection id\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThis option name is now deprecated. Use ZMQ_CONNECT_ROUTING_ID instead.\nZMQ_CONNECT_RID remains as an alias for now.\n\n\nZMQ_CONNECT_ROUTING_ID: Assign the next outbound routing id\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_CONNECT_ROUTING_ID' option sets the peer id of the peer connected\nvia the next zmq_connect() call, such that that connection is immediately ready for\ndata transfer with the given routing id.  This option applies only to the first\nsubsequent call to zmq_connect(), zmq_connect() calls thereafter use the default\nconnection behaviour.\n\nTypical use is to set this socket option ahead of each zmq_connect() call.\nEach connection MUST be assigned a unique routing id. Assigning a\nrouting id that is already in use is not allowed.\n\nUseful when connecting ROUTER to ROUTER, or STREAM to STREAM, as it\nallows for immediate sending to peers. Outbound routing id framing requirements\nfor ROUTER and STREAM sockets apply.\n\nThe routing id must be from 1 to 255 bytes long and MAY NOT start with\na zero byte (such routing ids are reserved for internal use by the 0MQ\ninfrastructure).\n\n[horizontal]\nOption value type:: binary data\nOption value unit:: N/A\nDefault value:: NULL\nApplicable socket types:: ZMQ_ROUTER, ZMQ_STREAM\n\n\nZMQ_CONFLATE: Keep only last message\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nIf set, a socket shall keep only one message in its inbound/outbound\nqueue, this message being the last message received/the last message\nto be sent. Ignores 'ZMQ_RCVHWM' and 'ZMQ_SNDHWM' options. Does not\nsupport multi-part messages, in particular, only one part of it is kept\nin the socket internal queue.\n\nNOTE: If recv is not called on the inbound socket, the queue and memory will\ngrow with each message received. Use xref:zmq_getsockopt.adoc[zmq_getsockopt] with ZMQ_EVENTS\nto trigger the conflation of the messages.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 0 (false)\nApplicable socket types:: ZMQ_PULL, ZMQ_PUSH, ZMQ_SUB, ZMQ_PUB, ZMQ_DEALER\n\n\nZMQ_CONNECT_TIMEOUT: Set connect() timeout\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets how long to wait before timing-out a connect() system call.\nThe connect() system call normally takes a long time before it returns a\ntime out error. Setting this option allows the library to time out the call\nat an earlier interval.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 0 (disabled)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_CURVE_PUBLICKEY: Set CURVE public key\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the socket's long term public key. You must set this on CURVE client\nsockets, see xref:zmq_curve.adoc[zmq_curve] You can provide the key as 32 binary\nbytes, or as a 40-character string encoded in the Z85 encoding format and\nterminated in a null byte. The public key must always be used with the\nmatching secret key. To generate a public/secret key pair, use\nxref:zmq_curve_keypair.adoc[zmq_curve_keypair] To derive the public key from a secret key,\nuse xref:zmq_curve_public.adoc[zmq_curve_public]\n\nNOTE: an option value size of 40 is supported for backwards compatibility,\nthough is deprecated.\n\n[horizontal]\nOption value type:: binary data or Z85 text string\nOption value size:: 32 or 41\nDefault value:: NULL\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_CURVE_SECRETKEY: Set CURVE secret key\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the socket's long term secret key. You must set this on both CURVE\nclient and server sockets, see xref:zmq_curve.adoc[zmq_curve] You can provide the\nkey as 32 binary bytes, or as a 40-character string encoded in the Z85\nencoding format and terminated in a null byte. To generate a public/secret\nkey pair, use xref:zmq_curve_keypair.adoc[zmq_curve_keypair] To derive the public key from\na secret key, use xref:zmq_curve_public.adoc[zmq_curve_public]\n\nNOTE: an option value size of 40 is supported for backwards compatibility,\nthough is deprecated.\n\n[horizontal]\nOption value type:: binary data or Z85 text string\nOption value size:: 32 or 41\nDefault value:: NULL\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_CURVE_SERVER: Set CURVE server role\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nDefines whether the socket will act as server for CURVE security, see\nxref:zmq_curve.adoc[zmq_curve] A value of '1' means the socket will act as\nCURVE server. A value of '0' means the socket will not act as CURVE\nserver, and its security role then depends on other option settings.\nSetting this to '0' shall reset the socket security to NULL. When you\nset this you must also set the server's secret key using the\nZMQ_CURVE_SECRETKEY option. A server socket does not need to know\nits own public key.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_CURVE_SERVERKEY: Set CURVE server key\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the socket's long term server key. You must set this on CURVE client\nsockets, see xref:zmq_curve.adoc[zmq_curve] You can provide the key as 32 binary\nbytes, or as a 40-character string encoded in the Z85 encoding format and\nterminated in a null byte. This key must have been generated together with\nthe server's secret key. To generate a public/secret key pair, use\nxref:zmq_curve_keypair.adoc[zmq_curve_keypair]\n\nNOTE: an option value size of 40 is supported for backwards compatibility,\nthough is deprecated.\n\n[horizontal]\nOption value type:: binary data or Z85 text string\nOption value size:: 32 or 41\nDefault value:: NULL\nApplicable socket types:: all, when using TCP transport\n\nZMQ_DISCONNECT_MSG: set a disconnect message that the socket will generate when accepted peer disconnect\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen set, the socket will generate a disconnect message when accepted peer has been disconnected.\nYou may set this on ROUTER, SERVER and PEER sockets.\nThe combination with ZMQ_HEARTBEAT_IVL is powerful and simplify protocols, when heartbeat recognize a connection drop it\nwill generate a disconnect message that can match the protocol of the application.\n\n[horizontal]\nOption value type:: binary data\nOption value unit:: N/A\nDefault value:: NULL\nApplicable socket types:: ZMQ_ROUTER, ZMQ_SERVER and ZMQ_PEER\n\n\nZMQ_HICCUP_MSG: set a hiccup message that the socket will generate when connected peer temporarily disconnect\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen set, the socket will generate a hiccup message when connect peer has been disconnected.\nYou may set this on DEALER, CLIENT and PEER sockets.\nThe combination with ZMQ_HEARTBEAT_IVL is powerful and simplify protocols, when heartbeat recognize a connection drop it\nwill generate a hiccup message that can match the protocol of the application.\n\n[horizontal]\nOption value type:: binary data\nOption value unit:: N/A\nDefault value:: NULL\nApplicable socket types:: ZMQ_DEALER, ZMQ_CLIENT and ZMQ_PEER\n\n\nZMQ_GSSAPI_PLAINTEXT: Disable GSSAPI encryption\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nDefines whether communications on the socket will be encrypted, see\nxref:zmq_gssapi.adoc[zmq_gssapi] A value of '1' means  that communications will be\nplaintext.  A value of '0' means communications will be encrypted.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0 (false)\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_GSSAPI_PRINCIPAL: Set name of GSSAPI principal\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the name of the principal for whom GSSAPI credentials should be acquired.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_GSSAPI_SERVER: Set GSSAPI server role\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nDefines whether the socket will act as server for GSSAPI security, see\nxref:zmq_gssapi.adoc[zmq_gssapi] A value of '1' means the socket will act as GSSAPI\nserver. A value of '0' means the socket will act as GSSAPI client.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0 (false)\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_GSSAPI_SERVICE_PRINCIPAL: Set name of GSSAPI service principal\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the name of the principal of the GSSAPI server to which a GSSAPI client\nintends to connect.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all, when using TCP transport\n\nZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE: Set name type of service principal\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the name type of the GSSAPI service principal.  A value of\n'ZMQ_GSSAPI_NT_HOSTBASED' (0) means the name specified with\n'ZMQ_GSSAPI_SERVICE_PRINCIPAL' is interpreted as a host based name.  A value\nof 'ZMQ_GSSAPI_NT_USER_NAME' (1) means it is interpreted as a local user name.\nA value of 'ZMQ_GSSAPI_NT_KRB5_PRINCIPAL' (2) means it is interpreted as an\nunparsed principal name string (valid only with the krb5 GSSAPI mechanism).\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1, 2\nDefault value:: 0 (ZMQ_GSSAPI_NT_HOSTBASED)\nApplicable socket types:: all, when using TCP or IPC transport\n\nZMQ_GSSAPI_PRINCIPAL_NAMETYPE: Set name type of principal\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the name type of the GSSAPI principal.  A value of\n'ZMQ_GSSAPI_NT_HOSTBASED' (0) means the name specified with\n'ZMQ_GSSAPI_PRINCIPAL' is interpreted as a host based name.  A value of\n'ZMQ_GSSAPI_NT_USER_NAME' (1) means it is interpreted as a local user name.\nA value of 'ZMQ_GSSAPI_NT_KRB5_PRINCIPAL' (2) means it is interpreted as an\nunparsed principal name string (valid only with the krb5 GSSAPI mechanism).\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1, 2\nDefault value:: 0 (ZMQ_GSSAPI_NT_HOSTBASED)\nApplicable socket types:: all, when using TCP or IPC transport\n\nZMQ_HANDSHAKE_IVL: Set maximum handshake interval\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_HANDSHAKE_IVL' option shall set the maximum handshake interval for\nthe specified 'socket'. Handshaking is the exchange of socket configuration\ninformation (socket type, routing id, security) that occurs when a connection\nis first opened, only for connection-oriented transports. If handshaking does\nnot complete within the configured time, the connection shall be closed.\nThe value 0 means no handshake time limit.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 30000\nApplicable socket types:: all but ZMQ_STREAM, only for connection-oriented transports\n\nZMQ_HELLO_MSG: set an hello message that will be sent when a new peer connect\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen set, the socket will automatically send an hello message when a new connection is made or accepted.\nYou may set this on DEALER, ROUTER, CLIENT, SERVER and PEER sockets.\nThe combination with ZMQ_HEARTBEAT_IVL is powerful and simplify protocols,\nas now heartbeat and sending the hello message can be left out of protocols and be handled by zeromq.\n\n[horizontal]\nOption value type:: binary data\nOption value unit:: N/A\nDefault value:: NULL\nApplicable socket types:: ZMQ_ROUTER, ZMQ_DEALER, ZMQ_CLIENT, ZMQ_SERVER and ZMQ_PEER\n\nZMQ_HEARTBEAT_IVL: Set interval between sending ZMTP heartbeats\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_HEARTBEAT_IVL' option shall set the interval between sending ZMTP heartbeats\nfor the specified 'socket'. If this option is set and is greater than 0, then a 'PING'\nZMTP command will be sent every 'ZMQ_HEARTBEAT_IVL' milliseconds.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 0\nApplicable socket types:: all, when using connection-oriented transports\n\n\nZMQ_HEARTBEAT_TIMEOUT: Set timeout for ZMTP heartbeats\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_HEARTBEAT_TIMEOUT' option shall set how long to wait before timing-out a\nconnection after sending a 'PING' ZMTP command and not receiving any traffic. This\noption is only valid if 'ZMQ_HEARTBEAT_IVL' is also set, and is greater than 0. The\nconnection will time out if there is no traffic received after sending the 'PING'\ncommand, but the received traffic does not have to be a 'PONG' command - any received\ntraffic will cancel the timeout.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 0 normally, ZMQ_HEARTBEAT_IVL if it is set\nApplicable socket types:: all, when using connection-oriented transports\n\n\nZMQ_HEARTBEAT_TTL: Set the TTL value for ZMTP heartbeats\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_HEARTBEAT_TTL' option shall set the timeout on the remote peer for ZMTP\nheartbeats. If this option is greater than 0, the remote side shall time out the\nconnection if it does not receive any more traffic within the TTL period. This option\ndoes not have any effect if 'ZMQ_HEARTBEAT_IVL' is not set or is 0. Internally, this\nvalue is rounded down to the nearest decisecond, any value less than 100 will have\nno effect.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 0\nMaximum value:: 6553599 (which is 2^16-1 deciseconds)\nApplicable socket types:: all, when using connection-oriented transports\n\n\nZMQ_IDENTITY: Set socket identity\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThis option name is now deprecated. Use ZMQ_ROUTING_ID instead.\nZMQ_IDENTITY remains as an alias for now.\n\n\nZMQ_IMMEDIATE: Queue messages only to completed connections\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nBy default queues will fill on outgoing connections even if the connection has\nnot completed. This can lead to \"lost\" messages on sockets with round-robin\nrouting (REQ, PUSH, DEALER). If this option is set to `1`, messages shall be\nqueued only to completed connections. This will cause the socket to block if\nthere are no other connections, but will prevent queues from filling on pipes\nawaiting connection.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 0 (false)\nApplicable socket types:: all, only for connection-oriented transports.\n\n\nZMQ_INVERT_MATCHING: Invert message filtering\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nReverses the filtering behavior of PUB-SUB sockets, when set to 1.\n\nOn 'PUB' and 'XPUB' sockets, this causes messages to be sent to all\nconnected sockets 'except' those subscribed to a prefix that matches\nthe message. On 'SUB' sockets, this causes only incoming messages that\ndo 'not' match any of the socket's subscriptions to be received by the user.\n\nWhenever 'ZMQ_INVERT_MATCHING' is set to 1 on a 'PUB' socket, all 'SUB'\nsockets connecting to it must also have the option set to 1. Failure to\ndo so will have the 'SUB' sockets reject everything the 'PUB' socket sends\nthem. 'XSUB' sockets do not need to do this because they do not filter\nincoming messages.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0,1\nDefault value:: 0\nApplicable socket types:: ZMQ_PUB, ZMQ_XPUB, ZMQ_SUB\n\n\nZMQ_IPV6: Enable IPv6 on socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSet the IPv6 option for the socket. A value of `1` means IPv6 is\nenabled on the socket, while `0` means the socket will use only IPv4.\nWhen IPv6 is enabled the socket will connect to, or accept connections\nfrom, both IPv4 and IPv6 hosts.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 0 (false)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_LINGER: Set linger period for socket shutdown\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_LINGER' option shall set the linger period for the specified 'socket'.\nThe linger period determines how long pending messages which have yet to be\nsent to a peer shall linger in memory after a socket is disconnected with\nxref:zmq_disconnect.adoc[zmq_disconnect] or closed with xref:zmq_close.adoc[zmq_close], and further\naffects the termination of the socket's context with xref:zmq_ctx_term.adoc[zmq_ctx_term]\nThe following outlines the different behaviours:\n\n* A value of '-1' specifies an infinite linger period. Pending\n  messages shall not be discarded after a call to _zmq_disconnect()_ or\n  _zmq_close()_; attempting to terminate the socket's context with _zmq_ctx_term()_\n  shall block until all pending messages have been sent to a peer.\n\n* The value of '0' specifies no linger period. Pending messages shall be\n  discarded immediately after a call to _zmq_disconnect()_ or _zmq_close()_.\n\n* Positive values specify an upper bound for the linger period in milliseconds.\n  Pending messages shall not be discarded after a call to _zmq_disconnect()_ or\n  _zmq_close()_; attempting to terminate the socket's context with _zmq_ctx_term()_\n  shall block until either all pending messages have been sent to a peer, or the\n  linger period expires, after which any pending messages shall be discarded.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: -1 (infinite)\nApplicable socket types:: all\n\n\nZMQ_MAXMSGSIZE: Maximum acceptable inbound message size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nLimits the size of the inbound message. If a peer sends a message larger than\nZMQ_MAXMSGSIZE it is disconnected. Value of -1 means 'no limit'.\n\n[horizontal]\nOption value type:: int64_t\nOption value unit:: bytes\nDefault value:: -1\nApplicable socket types:: all\n\n\nZMQ_METADATA: Add application metadata properties to a socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe _ZMQ_METADATA_ option shall add application metadata to the specified _socket_,\nthe metadata is exchanged with peers during connection setup. A metadata property is\nspecified as a string, delimited by a colon, starting with the metadata _property_\nfollowed by the metadata value, for example \"X-key:value\".\n_Property_ names are restricted to maximum 255 characters and must be prefixed by \"X-\".\nMultiple application metadata properties can be added to a socket by executing zmq_setsockopt()\nmultiple times. As the argument is a null-terminated string, binary data must be encoded\nbefore it is added e.g. using Z85 (xref:zmq_z85_encode.adoc[zmq_z85_encode]).\n\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all\n\n\nZMQ_MULTICAST_HOPS: Maximum network hops for multicast packets\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the time-to-live field in every multicast packet sent from this socket.\nThe default is 1 which means that the multicast packets don't leave the local\nnetwork.\n\n[horizontal]\nOption value type:: int\nOption value unit:: network hops\nDefault value:: 1\nApplicable socket types:: all, when using multicast transports\n\n\nZMQ_MULTICAST_MAXTPDU: Maximum transport data unit size for multicast packets\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the maximum transport data unit size used for outbound multicast\npackets.\n\nThis must be set at or below the minimum Maximum Transmission Unit (MTU) for\nall network paths over which multicast reception is required.\n\n[horizontal]\nOption value type:: int\nOption value unit:: bytes\nDefault value:: 1500\nApplicable socket types:: all, when using multicast transports\n\n\nZMQ_PLAIN_PASSWORD: Set PLAIN security password\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the password for outgoing connections over TCP or IPC. If you set this\nto a non-null value, the security mechanism used for connections shall be\nPLAIN, see xref:zmq_plain.adoc[zmq_plain] If you set this to a null value, the security\nmechanism used for connections shall be NULL, see xref:zmq_null.adoc[zmq_null]\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_PLAIN_SERVER: Set PLAIN server role\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nDefines whether the socket will act as server for PLAIN security, see\nxref:zmq_plain.adoc[zmq_plain] A value of '1' means the socket will act as\nPLAIN server. A value of '0' means the socket will not act as PLAIN\nserver, and its security role then depends on other option settings.\nSetting this to '0' shall reset the socket security to NULL.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_PLAIN_USERNAME: Set PLAIN security username\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the username for outgoing connections over TCP or IPC. If you set this\nto a non-null value, the security mechanism used for connections shall be\nPLAIN, see xref:zmq_plain.adoc[zmq_plain] If you set this to a null value, the security\nmechanism used for connections shall be NULL, see xref:zmq_null.adoc[zmq_null]\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_USE_FD: Set the pre-allocated socket file descriptor\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen set to a positive integer value before zmq_bind is called on the socket,\nthe socket shall use the corresponding file descriptor for connections over\nTCP or IPC instead of allocating a new file descriptor.\nUseful for writing systemd socket activated services. If set to -1 (default),\na new file descriptor will be allocated instead (default behaviour).\n\nNOTE: if set after calling zmq_bind, this option shall have no effect.\nNOTE: the file descriptor passed through MUST have been ran through the \"bind\"\n      and \"listen\" system calls beforehand. Also, socket option that would\n      normally be passed through zmq_setsockopt like TCP buffers length,\n      IP_TOS or SO_REUSEADDR MUST be set beforehand by the caller, as they\n      must be set before the socket is bound.\n\n[horizontal]\nOption value type:: int\nOption value unit:: file descriptor\nDefault value:: -1\nApplicable socket types:: all bound sockets, when using IPC or TCP transport\n\n\nZMQ_PRIORITY: Set the Priority on socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the protocol-defined priority for all packets to be sent on this\nsocket, where supported by the OS. In Linux, values greater than 6\nrequire admin capability (CAP_NET_ADMIN)\n\n[horizontal]\nOption value type:: int\nOption value unit:: >0\nDefault value:: 0\nApplicable socket types:: all, only for connection-oriented transports\n\n\nZMQ_PROBE_ROUTER: bootstrap connections to ROUTER sockets\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen set to 1, the socket will automatically send an empty message when a\nnew connection is made or accepted. You may set this on REQ, DEALER, or\nROUTER sockets connected to a ROUTER socket. The application must filter\nsuch empty messages. The ZMQ_PROBE_ROUTER option in effect provides the\nROUTER application with an event signaling the arrival of a new peer.\n\nNOTE: do not set this option on a socket that talks to any other socket\ntypes: the results are undefined.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_ROUTER, ZMQ_DEALER, ZMQ_REQ\n\n\nZMQ_RATE: Set multicast data rate\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RATE' option shall set the maximum send or receive data rate for\nmulticast transports such as xref:zmq_pgm.adoc[zmq_pgm] using the specified 'socket'.\n\n[horizontal]\nOption value type:: int\nOption value unit:: kilobits per second\nDefault value:: 100\nApplicable socket types:: all, when using multicast transports\n\n\nZMQ_RCVBUF: Set kernel receive buffer size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RCVBUF' option shall set the underlying kernel receive buffer size for\nthe 'socket' to the specified size in bytes.  A value of -1 means leave the\nOS default unchanged. For details refer to your operating system documentation\nfor the 'SO_RCVBUF' socket option.\n\n[horizontal]\nOption value type:: int\nOption value unit:: bytes\nDefault value:: -1\nApplicable socket types:: all\n\n\nZMQ_RCVHWM: Set high water mark for inbound messages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RCVHWM' option shall set the high water mark for inbound messages on\nthe specified 'socket'. The high water mark is a hard limit on the maximum\nnumber of outstanding messages 0MQ shall queue in memory for any single peer\nthat the specified 'socket' is communicating with. A value of zero means no\nlimit.\n\nIf this limit has been reached the socket shall enter an exceptional state and\ndepending on the socket type, 0MQ shall take appropriate action such as\nblocking or dropping sent messages. Refer to the individual socket descriptions\nin xref:zmq_socket.adoc[zmq_socket] for details on the exact action taken for each socket\ntype.\n\nNOTE: 0MQ does not guarantee that the socket will be able to queue as many as ZMQ_RCVHWM\nmessages, and the actual limit may be lower or higher, depending on socket transport.\nA notable example is for sockets using TCP transport; see xref:zmq_tcp.adoc[zmq_tcp]\n\n[horizontal]\nOption value type:: int\nOption value unit:: messages\nDefault value:: 1000\nApplicable socket types:: all\n\n\nZMQ_RCVTIMEO: Maximum time before a recv operation returns with EAGAIN\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the timeout for receive operation on the socket. If the value is `0`,\n_zmq_recv(3)_ will return immediately, with a EAGAIN error if there is no\nmessage to receive. If the value is `-1`, it will block until a message is\navailable. For all other values, it will wait for a message for that amount\nof time before returning with an EAGAIN error.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: -1 (infinite)\nApplicable socket types:: all\n\n\nZMQ_RECONNECT_IVL: Set reconnection interval\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RECONNECT_IVL' option shall set the initial reconnection interval for\nthe specified 'socket'.  The reconnection interval is the period 0MQ\nshall wait between attempts to reconnect disconnected peers when using\nconnection-oriented transports. The value -1 means no reconnection.\n\nNOTE: The reconnection interval may be randomized by 0MQ to prevent\nreconnection storms in topologies with a large number of peers per socket.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 100\nApplicable socket types:: all, only for connection-oriented transports\n\n\nZMQ_RECONNECT_IVL_MAX: Set max reconnection interval\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RECONNECT_IVL_MAX' option shall set the max reconnection interval for\nthe specified 'socket'. 0MQ shall wait at most the configured interval between\nreconnection attempts. The interval grows exponentionally (i.e.: it is doubled)\nwith each attempt until it reaches ZMQ_RECONNECT_IVL_MAX. Default value means\nthat the reconnect interval is based exclusively on ZMQ_RECONNECT_IVL and no\nexponential backoff is performed.\n\nNOTE:  Value has to be greater or equal than ZMQ_RECONNECT_IVL, or else it will\n       be ignored.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 0 (ZMQ_RECONNECT_IVL will be used)\nApplicable socket types:: all, only for connection-oriented transports\n\n\nZMQ_RECONNECT_STOP: Set condition where reconnection will stop\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RECONNECT_STOP' option shall set the conditions under which automatic\nreconnection will stop.  This can be useful when a process binds to a\nwild-card port, where the OS supplies an ephemeral port.\n\nThe 'ZMQ_RECONNECT_STOP_CONN_REFUSED' option will stop reconnection when 0MQ\nreceives the ECONNREFUSED return code from the connect.  This indicates that\nthere is no code bound to the specified endpoint.\n\nThe 'ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED' option will stop reconnection if\nthe 0MQ handshake fails.  This can be used to detect and/or prevent errant\nconnection attempts to non-0MQ sockets.  Note that when specifying this option\nyou may also want to set `ZMQ_HANDSHAKE_IVL` -- the default handshake interval\nis 30000 (30 seconds), which is typically too large.\n\nThe 'ZMQ_RECONNECT_STOP_AFTER_DISCONNECT' option will stop reconnection when\nzmq_disconnect() has been called. This can be useful when the user's request failed\n(server not ready), as the socket does not need to continue to reconnect after\nuser disconnect actively.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, ZMQ_RECONNECT_STOP_CONN_REFUSED, ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED, ZMQ_RECONNECT_STOP_CONN_REFUSED | ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED\nDefault value:: 0\nApplicable socket types:: all, only for connection-oriented transports (ZMQ_HANDSHAKE_IVL is\nnot applicable for ZMQ_STREAM sockets)\n\n\nZMQ_RECOVERY_IVL: Set multicast recovery interval\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_RECOVERY_IVL' option shall set the recovery interval for multicast\ntransports using the specified 'socket'. The recovery interval determines the\nmaximum time in milliseconds that a receiver can be absent from a multicast\ngroup before unrecoverable data loss will occur.\n\nCAUTION: Exercise care when setting large recovery intervals as the data\nneeded for recovery will be held in memory. For example, a 1 minute recovery\ninterval at a data rate of 1Gbps requires a 7GB in-memory buffer.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 10000\nApplicable socket types:: all, when using multicast transports\n\n\nZMQ_REQ_CORRELATE: match replies with requests\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe default behaviour of REQ sockets is to rely on the ordering of messages to\nmatch requests and responses and that is usually sufficient. When this option\nis set to 1, the REQ socket will prefix outgoing messages with an extra frame\ncontaining a request id. That means the full message is (request id, 0,\nuser frames...). The REQ socket will discard all incoming messages that don't\nbegin with these two frames.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_REQ\n\n\nZMQ_REQ_RELAXED: relax strict alternation between request and reply\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nBy default, a REQ socket does not allow initiating a new request with\n_zmq_send(3)_ until the reply to the previous one has been received.\nWhen set to 1, sending another message is allowed and previous replies will\nbe discarded if any. The request-reply state machine is reset and a new\nrequest is sent to the next available peer.\n\nIf set to 1, also enable ZMQ_REQ_CORRELATE to ensure correct matching of\nrequests and replies. Otherwise a late reply to an aborted request can be\nreported as the reply to the superseding request.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_REQ\n\n\nZMQ_ROUTER_HANDOVER: handle duplicate client routing ids on ROUTER sockets\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nIf two clients use the same routing id when connecting to a ROUTER, the\nresults shall depend on the ZMQ_ROUTER_HANDOVER option setting. If that\nis not set (or set to the default of zero), the ROUTER socket shall reject\nclients trying to connect with an already-used routing id. If that option\nis set to 1, the ROUTER socket shall hand-over the connection to the new\nclient and disconnect the existing one.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_ROUTER\n\n\nZMQ_ROUTER_MANDATORY: accept only routable messages on ROUTER sockets\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the ROUTER socket behaviour when an unroutable message is encountered. A\nvalue of `0` is the default and discards the message silently when it cannot be\nrouted or the peers SNDHWM is reached.  A value of `1` returns an\n'EHOSTUNREACH' error code if the message cannot be routed or 'EAGAIN' error\ncode if the SNDHWM is reached and ZMQ_DONTWAIT was used. Without ZMQ_DONTWAIT\nit will block until the SNDTIMEO is reached or a spot in the send queue opens\nup.\n\nWhen ZMQ_ROUTER_MANDATORY is set to `1`, 'ZMQ_POLLOUT' events will be generated\nif one or more messages can be sent to at least one of the peers. If\nZMQ_ROUTER_MANDATORY is set to `0`, the socket will generate a 'ZMQ_POLLOUT'\nevent on every call to 'zmq_poll' resp. 'zmq_poller_wait_all'.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_ROUTER\n\n\nZMQ_ROUTER_RAW: switch ROUTER socket to raw mode\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the raw mode on the ROUTER, when set to 1. When the ROUTER socket is in\nraw mode, and when using the tcp:// transport, it will read and write TCP data\nwithout 0MQ framing. This lets 0MQ applications talk to non-0MQ applications.\nWhen using raw mode, you cannot set explicit identities, and the ZMQ_SNDMORE\nflag is ignored when sending data messages. In raw mode you can close a specific\nconnection by sending it a zero-length message (following the routing id frame).\n\nNOTE: This option is deprecated, please use ZMQ_STREAM sockets instead.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_ROUTER\n\n\nZMQ_ROUTING_ID: Set socket routing id\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_ROUTING_ID' option shall set the routing id of the specified 'socket'\nwhen connecting to a ROUTER socket.\n\nA routing id must be at least one byte and at most 255 bytes long. Identities\nstarting with a zero byte are reserved for use by the 0MQ infrastructure.\n\nIf two clients use the same routing id when connecting to a ROUTER, the\nresults shall depend on the ZMQ_ROUTER_HANDOVER option setting. If that\nis not set (or set to the default of zero), the ROUTER socket shall reject\nclients trying to connect with an already-used routing id. If that option\nis set to 1, the ROUTER socket shall hand-over the connection to the new\nclient and disconnect the existing one.\n\n[horizontal]\nOption value type:: binary data\nOption value unit:: N/A\nDefault value:: NULL\nApplicable socket types:: ZMQ_REQ, ZMQ_REP, ZMQ_ROUTER, ZMQ_DEALER.\n\n\nZMQ_SNDBUF: Set kernel transmit buffer size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_SNDBUF' option shall set the underlying kernel transmit buffer size\nfor the 'socket' to the specified size in bytes.  A value of -1 means leave\nthe OS default unchanged. For details please refer to your operating system\ndocumentation for the 'SO_SNDBUF' socket option.\n\n[horizontal]\nOption value type:: int\nOption value unit:: bytes\nDefault value:: -1\nApplicable socket types:: all\n\n\nZMQ_SNDHWM: Set high water mark for outbound messages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_SNDHWM' option shall set the high water mark for outbound messages on\nthe specified 'socket'. The high water mark is a hard limit on the maximum\nnumber of outstanding messages 0MQ shall queue in memory for any single peer\nthat the specified 'socket' is communicating with. A value of zero means no\nlimit.\n\nIf this limit has been reached the socket shall enter an exceptional state and\ndepending on the socket type, 0MQ shall take appropriate action such as\nblocking or dropping sent messages. Refer to the individual socket descriptions\nin xref:zmq_socket.adoc[zmq_socket] for details on the exact action taken for each socket\ntype.\n\nNOTE: 0MQ does not guarantee that the socket will accept as many as ZMQ_SNDHWM\nmessages, and the actual limit may be as much as 90% lower depending on the\nflow of messages on the socket. The socket may even be able to accept more messages\nthan the ZMQ_SNDHWM threshold; a notable example is for sockets using TCP transport;\nsee xref:zmq_tcp.adoc[zmq_tcp]\n\n[horizontal]\nOption value type:: int\nOption value unit:: messages\nDefault value:: 1000\nApplicable socket types:: all\n\n\nZMQ_SNDTIMEO: Maximum time before a send operation returns with EAGAIN\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the timeout for send operation on the socket. If the value is `0`,\n_zmq_send(3)_ will return immediately, with a EAGAIN error if the message\ncannot be sent. If the value is `-1`, it will block until the message is sent.\nFor all other values, it will try to send the message for that amount of time\nbefore returning with an EAGAIN error.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: -1 (infinite)\nApplicable socket types:: all\n\n\nZMQ_SOCKS_PROXY: Set SOCKS5 proxy address\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the SOCKS5 proxy address that shall be used by the socket for the TCP\nconnection(s). Supported authentication methods are: no authentication\nor basic authentication when setup with ZMQ_SOCKS_USERNAME. If the endpoints\nare domain names instead of addresses they shall not be resolved and they\nshall be forwarded unchanged to the SOCKS proxy service in the client\nconnection request message (address type 0x03 domain name).\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_SOCKS_USERNAME: Set SOCKS username and select basic authentication\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the username for authenticated connection to the SOCKS5 proxy.\nIf you set this to a non-null and non-empty value, the authentication\nmethod used for the SOCKS5 connection shall be basic authentication.\nIn this case, use ZMQ_SOCKS_PASSWORD option in order to set the password.\nIf you set this to a null value or empty value, the authentication method\nshall be no authentication, the default.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_SOCKS_PASSWORD: Set SOCKS basic authentication password\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the password for authenticating to the SOCKS5 proxy server.\nThis is used only when the SOCKS5 authentication method has been\nset to basic authentication through the ZMQ_SOCKS_USERNAME option.\nSetting this to a null value (the default) is equivalent to an\nempty password string.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: not set\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_STREAM_NOTIFY: send connect and disconnect notifications\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nEnables connect and disconnect notifications on a STREAM socket, when set\nto 1. When notifications are enabled, the socket delivers a zero-length\nmessage when a peer connects or disconnects.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 1\nApplicable socket types:: ZMQ_STREAM\n\n\nZMQ_SUBSCRIBE: Establish message filter\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_SUBSCRIBE' option shall establish a new message filter on a 'ZMQ_SUB'\nsocket. Newly created 'ZMQ_SUB' sockets shall filter out all incoming messages,\ntherefore you should call this option to establish an initial message filter.\n\nAn empty 'option_value' of length zero shall subscribe to all incoming\nmessages. A non-empty 'option_value' shall subscribe to all messages beginning\nwith the specified prefix. Multiple filters may be attached to a single\n'ZMQ_SUB' socket, in which case a message shall be accepted if it matches at\nleast one filter.\n\n[horizontal]\nOption value type:: binary data\nOption value unit:: N/A\nDefault value:: N/A\nApplicable socket types:: ZMQ_SUB\n\n\nZMQ_TCP_KEEPALIVE: Override SO_KEEPALIVE socket option\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOverride 'SO_KEEPALIVE' socket option (where supported by OS).\nThe default value of `-1` means to skip any overrides and leave it to OS default.\n\n[horizontal]\nOption value type:: int\nOption value unit:: -1,0,1\nDefault value:: -1 (leave to OS default)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_TCP_KEEPALIVE_CNT: Override TCP_KEEPCNT socket option\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOverride 'TCP_KEEPCNT' socket option (where supported by OS). The default\nvalue of `-1` means to skip any overrides and leave it to OS default.\n\n[horizontal]\nOption value type:: int\nOption value unit:: -1,>0\nDefault value:: -1 (leave to OS default)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_TCP_KEEPALIVE_IDLE: Override TCP_KEEPIDLE (or TCP_KEEPALIVE on some OS)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOverride 'TCP_KEEPIDLE' (or 'TCP_KEEPALIVE' on some OS) socket option (where\nsupported by OS). The default value of `-1` means to skip any overrides and\nleave it to OS default.\n\n[horizontal]\nOption value type:: int\nOption value unit:: -1,>0\nDefault value:: -1 (leave to OS default)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_TCP_KEEPALIVE_INTVL: Override TCP_KEEPINTVL socket option\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOverride 'TCP_KEEPINTVL' socket option(where supported by OS). The default\nvalue of `-1` means to skip any overrides and leave it to OS default.\n\n[horizontal]\nOption value type:: int\nOption value unit:: -1,>0\nDefault value:: -1 (leave to OS default)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_TCP_MAXRT: Set TCP Maximum Retransmit Timeout\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOn OSes where it is supported, sets how long before an unacknowledged TCP\nretransmit times out. The system normally attempts many TCP retransmits\nfollowing an exponential backoff strategy. This means that after a network\noutage, it may take a long time before the session can be re-established.\nSetting this option allows the timeout to happen at a shorter interval.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: 0 (leave to OS default)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_TOS: Set the Type-of-Service on socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the ToS fields (Differentiated services (DS) and Explicit Congestion\nNotification (ECN) field of the IP header. The ToS field is typically used\nto specify a packets priority. The availability of this option is dependent\non intermediate network equipment that inspect the ToS field and provide a\npath for low-delay, high-throughput, highly-reliable service, etc.\n\n[horizontal]\nOption value type:: int\nOption value unit:: >0\nDefault value:: 0\nApplicable socket types:: all, only for connection-oriented transports\n\n\nZMQ_UNSUBSCRIBE: Remove message filter\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe 'ZMQ_UNSUBSCRIBE' option shall remove an existing message filter on a\n'ZMQ_SUB' socket. The filter specified must match an existing filter previously\nestablished with the 'ZMQ_SUBSCRIBE' option. If the socket has several\ninstances of the same filter attached the 'ZMQ_UNSUBSCRIBE' option shall remove\nonly one instance, leaving the rest in place and functional.\n\n[horizontal]\nOption value type:: binary data\nOption value unit:: N/A\nDefault value:: N/A\nApplicable socket types:: ZMQ_SUB\n\n\nZMQ_XPUB_VERBOSE: pass duplicate subscribe messages on XPUB socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the 'XPUB' socket behaviour on new duplicated subscriptions. If enabled,\nthe socket passes all subscribe messages to the caller. If disabled,\nonly the first subscription to each filter will be passed. The default is 0\n(disabled).\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_XPUB\n\n\nZMQ_XPUB_VERBOSER: pass duplicate subscribe and unsubscribe messages on XPUB socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the 'XPUB' socket behaviour on new duplicated subscriptions and\nunsubscriptions. If enabled, the socket passes all subscribe and unsubscribe\nmessages to the caller. If disabled, only the first subscription to each filter and\nthe last unsubscription from each filter will be passed. The default is 0\n(disabled).\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_XPUB\n\n\nZMQ_XPUB_MANUAL: change the subscription handling to manual\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the 'XPUB' socket subscription handling mode manual/automatic.\nA value of '0' is the default and subscription requests will be handled automatically.\nA value of '1' will change the subscription requests handling to manual,\nwith manual mode subscription requests are not added to the subscription list.\nTo add subscription the user need to call setsockopt with ZMQ_SUBSCRIBE on XPUB socket.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_XPUB\n\n\nZMQ_XPUB_MANUAL_LAST_VALUE: change the subscription handling to manual\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThis option is similar to ZMQ_XPUB_MANUAL.\nThe difference is that ZMQ_XPUB_MANUAL_LAST_VALUE changes the 'XPUB' socket\nbehaviour to send the first message to the last subscriber after the socket\nreceives a subscription and call setsockopt with ZMQ_SUBSCRIBE on 'XPUB' socket.\nThis prevents duplicated messages when using last value caching(LVC).\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_XPUB\n\n\nZMQ_XPUB_NODROP: do not silently drop messages if SENDHWM is reached\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the 'XPUB' socket behaviour to return error EAGAIN if SENDHWM is\nreached and the message could not be send.\n\nA value of `0` is the default and drops the message silently when the peers\nSNDHWM is reached.  A value of `1` returns an 'EAGAIN' error code if the\nSNDHWM is reached and ZMQ_DONTWAIT was used.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_XPUB, ZMQ_PUB\n\n\nZMQ_XPUB_WELCOME_MSG: set welcome message that will be received by subscriber when connecting\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets a welcome message the will be received by subscriber when connecting.\nSubscriber must subscribe to the Welcome message before connecting.\nWelcome message will also be sent on reconnecting.\nFor welcome message to work well user must poll on incoming subscription messages on the XPUB socket and handle them.\n\nUse NULL and length of zero to disable welcome message.\n\n[horizontal]\nOption value type:: binary data\nOption value unit:: N/A\nDefault value:: NULL\nApplicable socket types:: ZMQ_XPUB\n\n\nZMQ_XSUB_VERBOSE_UNSUBSCRIBE: pass duplicate unsubscribe messages on XSUB socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the 'XSUB' socket behaviour on duplicated unsubscriptions. If enabled, the socket\npasses all unsubscribe messages to the caller. If disabled, only the last unsubscription\nfrom each filter will be passed. The default is 0 (disabled).\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: ZMQ_XSUB\n\n\nZMQ_ONLY_FIRST_SUBSCRIBE: Process only first subscribe/unsubscribe in a multipart message\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nIf set, only the first part of the multipart message is processed as\na subscribe/unsubscribe message. The rest are forwarded as user data\nregardless of message contents.\n\nIt not set (default), subscribe/unsubscribe messages in a multipart message\nare processed as such regardless of their number and order.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 0 (false)\nApplicable socket types:: ZMQ_XSUB, ZMQ_XPUB\n\n\nZMQ_ZAP_DOMAIN: Set RFC 27 authentication domain\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the domain for ZAP (ZMQ RFC 27) authentication. A ZAP domain must be\nspecified to enable authentication. When the ZAP domain is empty, which is\nthe default, ZAP authentication is disabled. This is not compatible with\nprevious versions of libzmq, so it can be controlled by ZMQ_ZAP_ENFORCE_DOMAIN\nwhich for now is disabled by default.\nSee http://rfc.zeromq.org/spec:27 for more details.\n\n[horizontal]\nOption value type:: character string\nOption value unit:: N/A\nDefault value:: empty\nApplicable socket types:: all, when using TCP transport\n\n\nZMQ_ZAP_ENFORCE_DOMAIN: Set ZAP domain handling to strictly adhere the RFC\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe ZAP (ZMQ RFC 27) authentication protocol specifies that a domain must\nalways be set. Older versions of libzmq did not follow the spec and allowed\nan empty domain to be set.\nThis option can be used to enabled or disable the stricter, backward\nincompatible behaviour. For now it is disabled by default, but in a future\nversion it will be enabled by default.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 0\nApplicable socket types:: all, when using ZAP\n\n\nZMQ_TCP_ACCEPT_FILTER: Assign filters to allow new TCP connections\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nAssign an arbitrary number of filters that will be applied for each new TCP\ntransport connection on a listening socket. If no filters are applied, then\nthe TCP transport allows connections from any IP address. If at least one\nfilter is applied then new connection source ip should be matched. To clear\nall filters call zmq_setsockopt(socket, ZMQ_TCP_ACCEPT_FILTER, NULL, 0).\nFilter is a null-terminated string with ipv6 or ipv4 CIDR.\n\nNOTE: This option is deprecated, please use authentication via the ZAP API\nand IP address allowing / blocking.\n\n[horizontal]\nOption value type:: binary data\nOption value unit:: N/A\nDefault value:: no filters (allow from all)\nApplicable socket types:: all listening sockets, when using TCP transports.\n\n\nZMQ_IPC_FILTER_GID: Assign group ID filters to allow new IPC connections\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nAssign an arbitrary number of filters that will be applied for each new IPC\ntransport connection on a listening socket. If no IPC filters are applied, then\nthe IPC transport allows connections from any process. If at least one UID,\nGID, or PID filter is applied then new connection credentials should be\nmatched. To clear all GID filters call zmq_setsockopt(socket,\nZMQ_IPC_FILTER_GID, NULL, 0).\n\nNOTE: GID filters are only available on platforms supporting SO_PEERCRED or\nLOCAL_PEERCRED socket options (currently only Linux and later versions of\nOS X).\n\nNOTE: This option is deprecated, please use authentication via the ZAP API\nand IPC allowing / blocking.\n\n[horizontal]\nOption value type:: gid_t\nOption value unit:: N/A\nDefault value:: no filters (allow from all)\nApplicable socket types:: all listening sockets, when using IPC transports.\n\n\nZMQ_IPC_FILTER_PID: Assign process ID filters to allow new IPC connections\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nAssign an arbitrary number of filters that will be applied for each new IPC\ntransport connection on a listening socket. If no IPC filters are applied, then\nthe IPC transport allows connections from any process. If at least one UID,\nGID, or PID filter is applied then new connection credentials should be\nmatched. To clear all PID filters call zmq_setsockopt(socket,\nZMQ_IPC_FILTER_PID, NULL, 0).\n\nNOTE: PID filters are only available on platforms supporting the SO_PEERCRED\nsocket option (currently only Linux).\n\nNOTE: This option is deprecated, please use authentication via the ZAP API\nand IPC allowing / blocking.\n\n[horizontal]\nOption value type:: pid_t\nOption value unit:: N/A\nDefault value:: no filters (allow from all)\nApplicable socket types:: all listening sockets, when using IPC transports.\n\n\nZMQ_IPC_FILTER_UID: Assign user ID filters to allow new IPC connections\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nAssign an arbitrary number of filters that will be applied for each new IPC\ntransport connection on a listening socket. If no IPC filters are applied, then\nthe IPC transport allows connections from any process. If at least one UID,\nGID, or PID filter is applied then new connection credentials should be\nmatched. To clear all UID filters call zmq_setsockopt(socket,\nZMQ_IPC_FILTER_UID, NULL, 0).\n\nNOTE: UID filters are only available on platforms supporting SO_PEERCRED or\nLOCAL_PEERCRED socket options (currently only Linux and later versions of\nOS X).\n\nNOTE: This option is deprecated, please use authentication via the ZAP API\nand IPC allowing / blocking.\n\n[horizontal]\nOption value type:: uid_t\nOption value unit:: N/A\nDefault value:: no filters (allow from all)\nApplicable socket types:: all listening sockets, when using IPC transports.\n\n\nZMQ_IPV4ONLY: Use IPv4-only on socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSet the IPv4-only option for the socket. This option is deprecated.\nPlease use the ZMQ_IPV6 option.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 1 (true)\nApplicable socket types:: all, when using TCP transports.\n\n\nZMQ_VMCI_BUFFER_SIZE: Set buffer size of the VMCI socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe `ZMQ_VMCI_BUFFER_SIZE` option shall set the size of the underlying\nbuffer for the socket. Used during negotiation before the connection is established.\n\n[horizontal]\nOption value type:: uint64_t\nOption value unit:: bytes\nDefault value:: 65546\nApplicable socket types:: all, when using VMCI transport\n\n\nZMQ_VMCI_BUFFER_MIN_SIZE: Set min buffer size of the VMCI socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe `ZMQ_VMCI_BUFFER_MIN_SIZE` option shall set the min size of the underlying\nbuffer for the socket. Used during negotiation before the connection is established.\n\n[horizontal]\nOption value type:: uint64_t\nOption value unit:: bytes\nDefault value:: 128\nApplicable socket types:: all, when using VMCI transport\n\n\nZMQ_VMCI_BUFFER_MAX_SIZE: Set max buffer size of the VMCI socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe `ZMQ_VMCI_BUFFER_MAX_SIZE` option shall set the max size of the underlying\nbuffer for the socket. Used during negotiation before the connection is established.\n\n[horizontal]\nOption value type:: uint64_t\nOption value unit:: bytes\nDefault value:: 262144\nApplicable socket types:: all, when using VMCI transport\n\n\nZMQ_VMCI_CONNECT_TIMEOUT: Set connection timeout of the VMCI socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe `ZMQ_VMCI_CONNECT_TIMEOUT` option shall set connection timeout\nfor the socket.\n\n[horizontal]\nOption value type:: int\nOption value unit:: milliseconds\nDefault value:: -1\nApplicable socket types:: all, when using VMCI transport\n\n\nZMQ_MULTICAST_LOOP: Control multicast local loopback\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nFor multicast UDP sender sockets this option sets whether the data\nsent should be looped back on local listening sockets.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1\nDefault value:: 1\nApplicable socket types:: ZMQ_RADIO, when using UDP multicast transport\n\n\nZMQ_ROUTER_NOTIFY: Send connect and disconnect notifications\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nEnable connect and disconnect notifications on a ROUTER socket.\nWhen enabled, the socket delivers a zero-length message (with routing-id\nas first frame) when a peer connects or disconnects. It's possible\nto notify both events for a peer by OR-ing the flag values. This option\nonly applies to stream oriented (tcp, ipc) transports.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, ZMQ_NOTIFY_CONNECT, ZMQ_NOTIFY_DISCONNECT, ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT\nDefault value:: 0\nApplicable socket types:: ZMQ_ROUTER\n\n\nZMQ_IN_BATCH_SIZE: Maximal receive batch size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the maximal amount of messages that can be received in a single\n'recv' system call. WARNING: this option should almost never be changed.\nThe default has been chosen to offer the best compromise between latency and\nthroughtput. In the vast majority of cases, changing this option will result in\nworst result if not outright breakages.\n\nCannot be zero.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: messages\nDefault value:: 8192\nApplicable socket types:: All, when using TCP, IPC, PGM or NORM transport.\n\n\nZMQ_OUT_BATCH_SIZE: Maximal send batch size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the maximal amount of messages that can be sent in a single\n'send' system call. WARNING: this option should almost never be changed.\nThe default has been chosen to offer the best compromise between latency and\nthroughtput. In the vast majority of cases, changing this option will result in\nworst result if not outright breakages.\n\nCannot be zero.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: messages\nDefault value:: 8192\nApplicable socket types:: All, when using TCP, IPC, PGM or NORM transport.\n\n\nZMQ_NORM_MODE: NORM Sender Mode\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the NORM sender mode to control the operation of the NORM transport. NORM\nsupports fixed rate operation (0='ZMQ_NORM_FIXED'), congestion control mode \n(1='ZMQ_NORM_CC'), loss-tolerant congestion control (2='ZMQ_NORM_CCL'), explicit\ncongestion notification (ECN)-enabled congestion control (3='ZMQ_NORM_CCE'), and\nECN-only congestion control (4='ZMQ_NORM_CCE_ECNONLY'). The default value is \nTCP-friendly congestion control mode. Fixed rate mode (using datarate set by\n'ZMQ_RATE') offers better performance, but care must be taken to prevent data\nloss.  ECN modes will set one of the ECN Capable Transport bits in the given\n'ZMQ_TOS' if it is not set already.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: 0, 1, 2, 3, 4\nDefault value:: 1 ('ZMQ_NORM_CC')\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_UNICAST_NACK: Set NORM Unicast NACK mode\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nIf set, NORM receiver will send Negative ACKnowledgements (NACKs) back to the\nsender using unicast instead of multicast.  NORM transport endpoints specifying\na unicast address will enable this by default, but it is disabled by default for\nmulticast addresses.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 0 (false)\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_BUFFER_SIZE: Set NORM buffer size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets NORM buffer size for NORM transport sender, receiver, and stream.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: kilobytes\nDefault value:: 2048\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_SEGMENT_SIZE: Set NORM segment size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets NORM sender segment size, which is the maximum message payload size of\nindividual NORM messages (ZMQ messages may be split over multiple NORM\nmessages).  Ideally, this value should fit within the system/network maximum\ntransmission unit (MTU) after accounting for additional NORM message headers\n(up to 48 bytes).\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: bytes\nDefault value:: 1400\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_BLOCK_SIZE: Set NORM block size\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets NORM sender block size, which is the number of segments in a NORM FEC\ncoding block. NORM repair operations take place at block boundaries. Maximum\nvalue is 255, but parity packets ('ZMQ_NORM_NUM_PARITY') are limited to a value\nof (255 - 'ZMQ_NORM_BLOCK_SIZE'). Minimum value is ('ZMQ_NORM_NUM_PARITY' + 1).\nEffective value may be different based on the settings of 'ZMQ_NORM_NUM_PARITY'\nand 'ZMQ_NORM_NUM_AUTOPARITY' if invalid settings are provided.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: >0, <=255\nDefault value:: 16\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_NUM_PARITY: Set number of NORM parity segments\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the maximum number of NORM parity symbol segments that the sender is\nwilling to calculate per FEC coding block for the purpose of reparing lost data.\nMaximum value is 255, but is further limited to a value of\n(255 - 'ZMQ_NORM_BLOCK_SIZE'). Minimum value is 'ZMQ_NORM_NUM_AUTOPARITY'.\nEffective value may be different based on the setting of\n'ZMQ_NORM_NUM_AUTOPARITY' if invalid settings are provided.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: >0, <255\nDefault value:: 4\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_NUM_AUTOPARITY: Set number of proactive NORM parity segments\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSets the number of NORM parity symbol segments that the sender will proactively\nsend at the end of each FEC coding block. By default, no proactive parity\nsegments will be sent; instead, parity segments will only be sent in response to\nrepair requests (NACKs). Maximum value is 255, but is further limited to a \nmaximum value of 'ZMQ_NORM_NUM_PARITY'.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: >=0, <255\nDefault value:: 0\nApplicable socket types:: All, when using NORM transport.\n\n\nZMQ_NORM_PUSH: Enable NORM push mode\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nEnables NORM stream push mode, which alters the behavior of the sender when\nenqueueing new data. By default, NORM will stop accepting new messages while\nwaiting for old data to be transmitted and/or repaired. Enabling push mode\ndiscards the oldest data (which may be pending repair or may never have been\ntransmitted) in favor of accepting new data. This may be useful in cases where\nit is more important to quickly deliver new data instead of reliably delivering\nolder data.\n\nNOTE: in DRAFT state, not yet available in stable releases.\n\n[horizontal]\nOption value type:: int\nOption value unit:: boolean\nDefault value:: 0 (false)\nApplicable socket types:: All, when using NORM transport.\n\n\n== RETURN VALUE\nThe _zmq_setsockopt()_ function shall return zero if successful. Otherwise it\nshall return `-1` and set 'errno' to one of the values defined below.\n\n== ERRORS\n*EINVAL*::\nThe requested option _option_name_ is unknown, or the requested _option_len_ or\n_option_value_ is invalid.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*EINTR*::\nThe operation was interrupted by delivery of a signal.\n\n\n== EXAMPLE\n.Subscribing to messages on a 'ZMQ_SUB' socket\n----\n/* Subscribe to all messages */\nrc = zmq_setsockopt (socket, ZMQ_SUBSCRIBE, \"\", 0);\nassert (rc == 0);\n/* Subscribe to messages prefixed with \"ANIMALS.CATS\" */\nrc = zmq_setsockopt (socket, ZMQ_SUBSCRIBE, \"ANIMALS.CATS\", 12);\n----\n\n.Setting I/O thread affinity\n----\nint64_t affinity;\n/* Incoming connections on TCP port 5555 shall be handled by I/O thread 1 */\naffinity = 1;\nrc = zmq_setsockopt (socket, ZMQ_AFFINITY, &affinity, sizeof (affinity));\nassert (rc);\nrc = zmq_bind (socket, \"tcp://lo:5555\");\nassert (rc);\n/* Incoming connections on TCP port 5556 shall be handled by I/O thread 2 */\naffinity = 2;\nrc = zmq_setsockopt (socket, ZMQ_AFFINITY, &affinity, sizeof (affinity));\nassert (rc);\nrc = zmq_bind (socket, \"tcp://lo:5556\");\nassert (rc);\n----\n\n\n== SEE ALSO\n* xref:zmq_getsockopt.adoc[zmq_getsockopt]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq_plain.adoc[zmq_plain]\n* xref:zmq_curve.adoc[zmq_curve]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_socket.adoc",
    "content": "= zmq_socket(3)\n\n\n== NAME\nzmq_socket - create 0MQ socket\n\n\n== SYNOPSIS\n*void *zmq_socket (void '*context', int 'type');*\n\n\n== DESCRIPTION\nThe 'zmq_socket()' function shall create a 0MQ socket within the specified\n'context' and return an opaque handle to the newly created socket. The 'type'\nargument specifies the socket type, which determines the semantics of\ncommunication over the socket.\n\nThe newly created socket is initially unbound, and not associated with any\nendpoints. In order to establish a message flow a socket must first be\nconnected to at least one endpoint with xref:zmq_connect.adoc[zmq_connect], or at least one\nendpoint must be created for accepting incoming connections with\nxref:zmq_bind.adoc[zmq_bind]\n\n.Key differences to conventional sockets\nGenerally speaking, conventional sockets present a _synchronous_ interface to\neither connection-oriented reliable byte streams (SOCK_STREAM), or\nconnection-less unreliable datagrams (SOCK_DGRAM). In comparison, 0MQ sockets\npresent an abstraction of an asynchronous _message queue_, with the exact\nqueueing semantics depending on the socket type in use. Where conventional\nsockets transfer streams of bytes or discrete datagrams, 0MQ sockets transfer\ndiscrete _messages_.\n\n0MQ sockets being _asynchronous_ means that the timings of the physical\nconnection setup and tear down, reconnect and effective delivery are transparent\nto the user and organized by 0MQ itself. Further, messages may be _queued_ in\nthe event that a peer is unavailable to receive them.\n\nConventional sockets allow only strict one-to-one (two peers), many-to-one\n(many clients, one server), or in some cases one-to-many (multicast)\nrelationships. With the exception of 'ZMQ_PAIR' and 'ZMQ_CHANNEL', 0MQ sockets may be connected\n*to multiple endpoints* using _zmq_connect()_, while simultaneously accepting\nincoming connections *from multiple endpoints* bound to the socket using\n_zmq_bind()_, thus allowing many-to-many relationships.\n\n.Thread safety\n0MQ has both thread safe socket type and _not_ thread safe socket types.\nApplications MUST NOT use a _not_ thread safe socket\nfrom multiple threads under any circumstances. Doing so results in undefined\nbehaviour.\n\nFollowing are the thread safe sockets:\n* ZMQ_CLIENT\n* ZMQ_SERVER\n* ZMQ_DISH\n* ZMQ_RADIO\n* ZMQ_SCATTER\n* ZMQ_GATHER\n* ZMQ_PEER\n* ZMQ_CHANNEL\n\n.Socket types\nThe following sections present the socket types defined by 0MQ, grouped by the\ngeneral _messaging pattern_ which is built from related socket types.\n\n\nClient-server pattern\n~~~~~~~~~~~~~~~~~~~~~\n\nThe client-server pattern is used to allow a single 'ZMQ_SERVER' _server_ talk\nto one or more 'ZMQ_CLIENT' _clients_. The client always starts the conversation,\nafter which either peer can send messages asynchronously, to the other.\n\nThe client-server pattern is formally defined by http://rfc.zeromq.org/spec:41.\n\nNOTE: Server-client is still in draft phase.\n\nZMQ_CLIENT\n^^^^^^^^^^\nA 'ZMQ_CLIENT' socket talks to a 'ZMQ_SERVER' socket. Either peer can connect,\nthough the usual and recommended model is to bind the 'ZMQ_SERVER' and connect\nthe 'ZMQ_CLIENT'.\n\nIf the 'ZMQ_CLIENT' socket has established a connection, xref:zmq_send.adoc[zmq_send]\nwill accept messages, queue them, and send them as rapidly as the network\nallows. The outgoing buffer limit is defined by the high water mark for the\nsocket. If the outgoing buffer is full, or, for connection-oriented transports,\nif the ZMQ_IMMEDIATE option is set and there is no connected peer,\nxref:zmq_send.adoc[zmq_send] will block.\nThe 'ZMQ_CLIENT' socket will not drop messages.\n\nWhen a 'ZMQ_CLIENT' socket is connected to multiple 'ZMQ_SERVER' sockets,\noutgoing messages are distributed between connected peers on a round-robin\nbasis. Likewise, the 'ZMQ_CLIENT' socket receives messages fairly from each\nconnected peer. This usage is sensible only for stateless protocols.\n\n'ZMQ_CLIENT' sockets are threadsafe and can be used from multiple threads\nat the same time. Note that replies from a 'ZMQ_SERVER' socket will go to\nthe first client thread that calls xref:zmq_msg_recv.adoc[zmq_msg_recv] If you need to get\nreplies back to the originating thread, use one 'ZMQ_CLIENT' socket per\nthread.\n\nNOTE: 'ZMQ_CLIENT' sockets are threadsafe. They do not accept the ZMQ_SNDMORE\noption on sends not ZMQ_RCVMORE on receives. This limits them to single part\ndata. The intention is to extend the API to allow scatter/gather of multi-part\ndata.\n\n[horizontal]\n.Summary of ZMQ_CLIENT characteristics\nCompatible peer sockets:: 'ZMQ_SERVER'\nDirection:: Bidirectional\nSend/receive pattern:: Unrestricted\nOutgoing routing strategy:: Round-robin\nIncoming routing strategy:: Fair-queued\nAction in mute state:: Block\n\n\nZMQ_SERVER\n^^^^^^^^^^\nA 'ZMQ_SERVER' socket talks to a set of 'ZMQ_CLIENT' sockets. A 'ZMQ_SERVER'\nsocket can only reply to an incoming message: the 'ZMQ_CLIENT' peer must\nalways initiate a conversation.\n\nEach received message has a 'routing_id' that is a 32-bit unsigned integer.\nThe application can fetch this with xref:zmq_msg_routing_id.adoc[zmq_msg_routing_id] To send\na message to a given 'ZMQ_CLIENT' peer the application must set the peer's\n'routing_id' on the message, using xref:zmq_msg_set_routing_id.adoc[zmq_msg_set_routing_id]\n\nIf the 'routing_id' is not specified, or does not refer to a connected client\npeer, the send call will fail with EHOSTUNREACH. If the outgoing buffer for\nthe client peer is full, the send call shall block, unless ZMQ_DONTWAIT is\nused in the send, in which case it shall fail with EAGAIN. The 'ZMQ_SERVER'\nsocket shall not drop messages in any case.\n\nNOTE: 'ZMQ_SERVER' sockets are threadsafe. They do not accept the ZMQ_SNDMORE\noption on sends not ZMQ_RCVMORE on receives. This limits them to single part\ndata. The intention is to extend the API to allow scatter/gather of multi-part\ndata.\n\n[horizontal]\n.Summary of ZMQ_SERVER characteristics\nCompatible peer sockets:: 'ZMQ_CLIENT'\nDirection:: Bidirectional\nSend/receive pattern:: Unrestricted\nOutgoing routing strategy:: See text\nIncoming routing strategy:: Fair-queued\nAction in mute state:: Return EAGAIN\n\n\nRadio-dish pattern\n~~~~~~~~~~~~~~~~~~\n\nThe radio-dish pattern is used for one-to-many distribution of data from\na single _publisher_ to multiple _subscribers_ in a fan out fashion.\n\nRadio-dish is using groups (vs Pub-sub topics), Dish sockets can join a group\nand each message sent by Radio sockets belong to a group.\n\nGroups are null terminated strings limited to 16 chars length (including null).\nThe intention is to increase the length to 40 chars (including null).\nThe encoding of groups shall be UTF8.\n\nGroups are matched using exact matching (vs prefix matching of PubSub).\n\nNOTE: Radio-dish is still in draft phase.\n\nZMQ_RADIO\n^^^^^^^^^\nA socket of type 'ZMQ_RADIO' is used by a _publisher_ to distribute data.\nEach message belong to a group, a group is specified with xref:zmq_msg_set_group.adoc[zmq_msg_set_group]\nMessages are distributed to all members of a group.\nThe xref:zmq_recv.adoc[zmq_recv] function is not implemented for this socket type.\n\nWhen a 'ZMQ_RADIO' socket enters the 'mute' state due to having reached the\nhigh water mark for a _subscriber_, then any messages that would be sent to the\n_subscriber_ in question shall instead be dropped until the mute state\nends. The _zmq_send()_ function shall never block for this socket type.\n\nNOTE: 'ZMQ_RADIO' sockets are threadsafe. They do not accept the ZMQ_SNDMORE\noption on sends. This limits them to single part data.\n\n[horizontal]\n.Summary of ZMQ_RADIO characteristics\nCompatible peer sockets:: 'ZMQ_DISH'\nDirection:: Unidirectional\nSend/receive pattern:: Send only\nIncoming routing strategy:: N/A\nOutgoing routing strategy:: Fan out\nAction in mute state:: Drop\n\n\nZMQ_DISH\n^^^^^^^^\nA socket of type 'ZMQ_DISH' is used by a _subscriber_ to subscribe to groups\ndistributed by a _radio_. Initially a 'ZMQ_DISH' socket is not subscribed to\nany groups, use xref:zmq_join.adoc[zmq_join] to\njoin a group.\nTo get the group the message belong to call xref:zmq_msg_group.adoc[zmq_msg_group]\nThe _zmq_send()_ function is not implemented for this socket type.\n\nNOTE: 'ZMQ_DISH' sockets are threadsafe. They do not accept ZMQ_RCVMORE on receives.\nThis limits them to single part data.\n\n[horizontal]\n.Summary of ZMQ_DISH characteristics\nCompatible peer sockets:: 'ZMQ_RADIO'\nDirection:: Unidirectional\nSend/receive pattern:: Receive only\nIncoming routing strategy:: Fair-queued\nOutgoing routing strategy:: N/A\n\n\nPublish-subscribe pattern\n~~~~~~~~~~~~~~~~~~~~~~~~~\nThe publish-subscribe pattern is used for one-to-many distribution of data from\na single _publisher_ to multiple _subscribers_ in a fan out fashion.\n\nThe publish-subscribe pattern is formally defined by http://rfc.zeromq.org/spec:29.\n\nZMQ_PUB\n^^^^^^^\nA socket of type 'ZMQ_PUB' is used by a _publisher_ to distribute data.\nMessages sent are distributed in a fan out fashion to all connected peers.\nThe xref:zmq_recv.adoc[zmq_recv] function is not implemented for this socket type.\n\nWhen a 'ZMQ_PUB' socket enters the 'mute' state due to having reached the\nhigh water mark for a _subscriber_, then any messages that would be sent to the\n_subscriber_ in question shall instead be dropped until the mute state\nends. The _zmq_send()_ function shall never block for this socket type.\n\n[horizontal]\n.Summary of ZMQ_PUB characteristics\nCompatible peer sockets:: 'ZMQ_SUB', 'ZMQ_XSUB'\nDirection:: Unidirectional\nSend/receive pattern:: Send only\nIncoming routing strategy:: N/A\nOutgoing routing strategy:: Fan out\nAction in mute state:: Drop\n\n\nZMQ_SUB\n^^^^^^^\nA socket of type 'ZMQ_SUB' is used by a _subscriber_ to subscribe to data\ndistributed by a _publisher_. Initially a 'ZMQ_SUB' socket is not subscribed to\nany messages, use the 'ZMQ_SUBSCRIBE' option of xref:zmq_setsockopt.adoc[zmq_setsockopt] to\nspecify which messages to subscribe to. The _zmq_send()_ function is not\nimplemented for this socket type.\n\n[horizontal]\n.Summary of ZMQ_SUB characteristics\nCompatible peer sockets:: 'ZMQ_PUB', 'ZMQ_XPUB'\nDirection:: Unidirectional\nSend/receive pattern:: Receive only\nIncoming routing strategy:: Fair-queued\nOutgoing routing strategy:: N/A\n\n\nZMQ_XPUB\n^^^^^^^^\nSame as ZMQ_PUB except that you can receive subscriptions from the peers\nin form of incoming messages. Subscription message is a byte 1 (for\nsubscriptions) or byte 0 (for unsubscriptions) followed by the subscription\nbody. Messages without a sub/unsub prefix are also received, but have no\neffect on subscription status.\n\n[horizontal]\n.Summary of ZMQ_XPUB characteristics\nCompatible peer sockets:: 'ZMQ_SUB', 'ZMQ_XSUB'\nDirection:: Unidirectional\nSend/receive pattern:: Send messages, receive subscriptions\nIncoming routing strategy:: N/A\nOutgoing routing strategy:: Fan out\nAction in mute state:: Drop\n\n\nZMQ_XSUB\n^^^^^^^^\nSame as ZMQ_SUB except that you subscribe by sending subscription messages to\nthe socket. Subscription message is a byte 1 (for subscriptions) or byte 0\n(for unsubscriptions) followed by the subscription body. Messages without a\nsub/unsub prefix may also be sent, but have no effect on subscription status.\n\n[horizontal]\n.Summary of ZMQ_XSUB characteristics\nCompatible peer sockets:: 'ZMQ_PUB', 'ZMQ_XPUB'\nDirection:: Unidirectional\nSend/receive pattern:: Receive messages, send subscriptions\nIncoming routing strategy:: Fair-queued\nOutgoing routing strategy:: N/A\nAction in mute state:: Drop\n\n\nPipeline pattern\n~~~~~~~~~~~~~~~~\nThe pipeline pattern is used for distributing data to _nodes_ arranged in\na pipeline. Data always flows down the pipeline, and each stage of the pipeline\nis connected to at least one _node_. When a pipeline stage is connected to\nmultiple _nodes_ data is round-robined among all connected _nodes_.\n\nThe pipeline pattern is formally defined by http://rfc.zeromq.org/spec:30.\n\nZMQ_PUSH\n^^^^^^^^\nA socket of type 'ZMQ_PUSH' is used by a pipeline _node_ to send messages\nto downstream pipeline _nodes_. Messages are round-robined to all connected\ndownstream _nodes_. The _zmq_recv()_ function is not implemented for this\nsocket type.\n\nWhen a 'ZMQ_PUSH' socket enters the 'mute' state due to having reached the\nhigh water mark for all downstream _nodes_, or, for connection-oriented transports,\nif the ZMQ_IMMEDIATE option is set and there are no downstream _nodes_ at all,\nthen any xref:zmq_send.adoc[zmq_send] operations on the socket shall block until the mute\nstate ends or at least one downstream _node_ becomes available for sending;\nmessages are not discarded.\n\n[horizontal]\n.Summary of ZMQ_PUSH characteristics\nCompatible peer sockets:: 'ZMQ_PULL'\nDirection:: Unidirectional\nSend/receive pattern:: Send only\nIncoming routing strategy:: N/A\nOutgoing routing strategy:: Round-robin\nAction in mute state:: Block\n\n\nZMQ_PULL\n^^^^^^^^\nA socket of type 'ZMQ_PULL' is used by a pipeline _node_ to receive messages\nfrom upstream pipeline _nodes_. Messages are fair-queued from among all\nconnected upstream _nodes_. The _zmq_send()_ function is not implemented for\nthis socket type.\n\n[horizontal]\n.Summary of ZMQ_PULL characteristics\nCompatible peer sockets:: 'ZMQ_PUSH'\nDirection:: Unidirectional\nSend/receive pattern:: Receive only\nIncoming routing strategy:: Fair-queued\nOutgoing routing strategy:: N/A\nAction in mute state:: Block\n\nScatter-gather pattern\n~~~~~~~~~~~~~~~~~~~~~~\nThe scatter-gather pattern is the thread-safe version of the pipeline pattern.\nThe scatter-gather pattern is used for distributing data to _nodes_ arranged in\na pipeline. Data always flows down the pipeline, and each stage of the pipeline\nis connected to at least one _node_. When a pipeline stage is connected to\nmultiple _nodes_ data is round-robined among all connected _nodes_.\n\nZMQ_SCATTER\n^^^^^^^^^^^\nA socket of type 'ZMQ_SCATTER' is used by a scatter-gather _node_ to send messages\nto downstream scatter-gather _nodes_. Messages are round-robined to all connected\ndownstream _nodes_. The _zmq_recv()_ function is not implemented for this\nsocket type.\n\nWhen a 'ZMQ_SCATTER' socket enters the 'mute' state due to having reached the\nhigh water mark for all downstream _nodes_, or, for connection-oriented transports,\nif the ZMQ_IMMEDIATE option is set and there are no downstream _nodes_ at all,\nthen any xref:zmq_send.adoc[zmq_send] operations on the socket shall block until the mute\nstate ends or at least one downstream _node_ becomes available for sending;\nmessages are not discarded.\n\nNOTE: 'ZMQ_SCATTER' sockets are threadsafe. They do not accept ZMQ_RCVMORE on receives.\nThis limits them to single part data.\n\n[horizontal]\n.Summary of ZMQ_SCATTER characteristics\nCompatible peer sockets:: 'ZMQ_SCATTER'\nDirection:: Unidirectional\nSend/receive pattern:: Send only\nIncoming routing strategy:: N/A\nOutgoing routing strategy:: Round-robin\nAction in mute state:: Block\n\n\nZMQ_GATHER\n^^^^^^^^^^\nA socket of type 'ZMQ_GATHER' is used by a scatter-gather _node_ to receive messages\nfrom upstream scatter-gather _nodes_. Messages are fair-queued from among all\nconnected upstream _nodes_. The _zmq_send()_ function is not implemented for\nthis socket type.\n\nNOTE: 'ZMQ_GATHER' sockets are threadsafe. They do not accept ZMQ_RCVMORE on receives.\nThis limits them to single part data.\n\n[horizontal]\n.Summary of ZMQ_GATHER characteristics\nCompatible peer sockets:: 'ZMQ_GATHER'\nDirection:: Unidirectional\nSend/receive pattern:: Receive only\nIncoming routing strategy:: Fair-queued\nOutgoing routing strategy:: N/A\nAction in mute state:: Block\n\n\nExclusive pair pattern\n~~~~~~~~~~~~~~~~~~~~~~\nThe exclusive pair pattern is used to connect a peer to precisely one other\npeer. This pattern is used for inter-thread communication across the inproc\ntransport.\n\nThe exclusive pair pattern is formally defined by http://rfc.zeromq.org/spec:31.\n\nZMQ_PAIR\n^^^^^^^^\nA socket of type 'ZMQ_PAIR' can only be connected to a single peer at any one\ntime.  No message routing or filtering is performed on messages sent over a\n'ZMQ_PAIR' socket.\n\nWhen a 'ZMQ_PAIR' socket enters the 'mute' state due to having reached the\nhigh water mark for the connected peer, or, for connection-oriented transports,\nif the ZMQ_IMMEDIATE option is set and there is no connected peer, then\nany xref:zmq_send.adoc[zmq_send] operations on the socket shall block until the peer\nbecomes available for sending; messages are not discarded.\n\nWhile 'ZMQ_PAIR' sockets can be used over transports other than xref:zmq_inproc.adoc[zmq_inproc],\ntheir inability to auto-reconnect coupled with the fact new incoming connections will\nbe terminated while any previous connections (including ones in a closing state)\nexist makes them unsuitable for TCP in most cases.\n\nNOTE: 'ZMQ_PAIR' sockets are designed for inter-thread communication across\nthe xref:zmq_inproc.adoc[zmq_inproc] transport and do not implement functionality such\nas auto-reconnection.\n\n[horizontal]\n.Summary of ZMQ_PAIR characteristics\nCompatible peer sockets:: 'ZMQ_PAIR'\nDirection:: Bidirectional\nSend/receive pattern:: Unrestricted\nIncoming routing strategy:: N/A\nOutgoing routing strategy:: N/A\nAction in mute state:: Block\n\n\nPeer-to-peer pattern\n~~~~~~~~~~~~~~~~~~~~\n\nThe peer-to-peer pattern is used to connect a peer to multiple peers.\nPeer can both connect and bind and mix both of them with the same socket.\nThe peer-to-peer pattern is useful to build peer-to-peer networks (e.g zyre, bitcoin, torrent)\nwhere a peer can both accept connections from other peers or connect to them.\n\nNOTE: Peer-to-peer is still in draft phase.\n\nZMQ_PEER\n^^^^^^^^\nA 'ZMQ_PEER' socket talks to a set of 'ZMQ_PEER' sockets.\n\nTo connect and fetch the 'routing_id' of the peer use xref:zmq_connect_peer.adoc[zmq_connect_peer]\nand to disconnect a specific peer by its 'routing_id' use xref:zmq_disconnect_peer.adoc[zmq_disconnect_peer].\n\nEach received message has a 'routing_id' that is a 32-bit unsigned integer.\nThe application can fetch this with xref:zmq_msg_routing_id.adoc[zmq_msg_routing_id]\n\nTo send a message to a given 'ZMQ_PEER' peer the application must set the peer's\n'routing_id' on the message, using xref:zmq_msg_set_routing_id.adoc[zmq_msg_set_routing_id]\n\nIf the 'routing_id' is not specified, or does not refer to a connected client\npeer, the send call will fail with EHOSTUNREACH. If the outgoing buffer for\nthe peer is full, the send call shall block, unless ZMQ_DONTWAIT is\nused in the send, in which case it shall fail with EAGAIN. The 'ZMQ_PEER'\nsocket shall not drop messages in any case.\n\nNOTE: 'ZMQ_PEER' sockets are threadsafe. They do not accept the ZMQ_SNDMORE\noption on sends not ZMQ_RCVMORE on receives. This limits them to single part\ndata.\n\n[horizontal]\n.Summary of ZMQ_PEER characteristics\nCompatible peer sockets:: 'ZMQ_PEER'\nDirection:: Bidirectional\nSend/receive pattern:: Unrestricted\nOutgoing routing strategy:: See text\nIncoming routing strategy:: Fair-queued\nAction in mute state:: Return EAGAIN\n\nChannel pattern\n~~~~~~~~~~~~~~~\nThe channel pattern is the thread-safe version of the exclusive pair pattern.\nThe channel pattern is used to connect a peer to precisely one other\npeer. This pattern is used for inter-thread communication across the inproc\ntransport.\n\nNOTE: Channel is still in draft phase.\n\nZMQ_CHANNEL\n^^^^^^^^^^^\nA socket of type 'ZMQ_CHANNEL' can only be connected to a single peer at any one\ntime.  No message routing or filtering is performed on messages sent over a\n'ZMQ_CHANNEL' socket.\n\nWhen a 'ZMQ_CHANNEL' socket enters the 'mute' state due to having reached the\nhigh water mark for the connected peer, or, for connection-oriented transports,\nif the ZMQ_IMMEDIATE option is set and there is no connected peer, then\nany xref:zmq_send.adoc[zmq_send] operations on the socket shall block until the peer\nbecomes available for sending; messages are not discarded.\n\nWhile 'ZMQ_CHANNEL' sockets can be used over transports other than xref:zmq_inproc.adoc[zmq_inproc],\ntheir inability to auto-reconnect coupled with the fact new incoming connections will\nbe terminated while any previous connections (including ones in a closing state)\nexist makes them unsuitable for TCP in most cases.\n\nNOTE: 'ZMQ_CHANNEL' sockets are designed for inter-thread communication across\nthe xref:zmq_inproc.adoc[zmq_inproc] transport and do not implement functionality such\nas auto-reconnection.\n\nNOTE: 'ZMQ_CHANNEL' sockets are threadsafe. They do not accept ZMQ_RCVMORE on receives.\nThis limits them to single part data.\n\n[horizontal]\n.Summary of ZMQ_CHANNEL characteristics\nCompatible peer sockets:: 'ZMQ_CHANNEL'\nDirection:: Bidirectional\nSend/receive pattern:: Unrestricted\nIncoming routing strategy:: N/A\nOutgoing routing strategy:: N/A\nAction in mute state:: Block\n\nNative Pattern\n~~~~~~~~~~~~~~\nThe native pattern is used for communicating with TCP peers and allows\nasynchronous requests and replies in either direction.\n\n\nZMQ_STREAM\n^^^^^^^^^^\nA socket of type 'ZMQ_STREAM' is used to send and receive TCP data from a\nnon-0MQ peer, when using the tcp:// transport. A 'ZMQ_STREAM' socket can\nact as client and/or server, sending and/or receiving TCP data asynchronously.\n\nWhen receiving TCP data, a 'ZMQ_STREAM' socket shall prepend a message part\ncontaining the _routing id_ of the originating peer to the message before passing\nit to the application. Messages received are fair-queued from among all\nconnected peers.\n\nWhen sending TCP data, a 'ZMQ_STREAM' socket shall remove the first part of the\nmessage and use it to determine the _routing id_ of the peer the message shall be\nrouted to, and unroutable messages shall cause an EHOSTUNREACH or EAGAIN error.\n\nTo open a connection to a server, use the zmq_connect call, and then fetch the\nsocket routing id using the zmq_getsockopt call with the ZMQ_ROUTING_ID option.\n\nTo close a specific connection, send the routing id frame followed by a\nzero-length message (see EXAMPLE section).\n\nWhen a connection is made, a zero-length message will be received by the\napplication.  Similarly, when the peer disconnects (or the connection is lost),\na zero-length message will be received by the application.\n\nYou must send one routing id frame followed by one data frame. The ZMQ_SNDMORE\nflag is required for routing id frames but is ignored on data frames.\n\n[horizontal]\n.Summary of ZMQ_STREAM characteristics\nCompatible peer sockets:: none.\nDirection:: Bidirectional\nSend/receive pattern:: Unrestricted\nOutgoing routing strategy:: See text\nIncoming routing strategy:: Fair-queued\nAction in mute state:: EAGAIN\n\n\nRequest-reply pattern\n~~~~~~~~~~~~~~~~~~~~~\nThe request-reply pattern is used for sending requests from a ZMQ_REQ _client_\nto one or more ZMQ_REP _services_, and receiving subsequent replies to each\nrequest sent.\n\nThe request-reply pattern is formally defined by http://rfc.zeromq.org/spec:28.\n\nZMQ_REQ\n^^^^^^^\nA socket of type 'ZMQ_REQ' is used by a _client_ to send requests to and\nreceive replies from a _service_. This socket type allows only an alternating\nsequence of _zmq_send(request)_ and subsequent _zmq_recv(reply)_ calls. Each\nrequest sent is round-robined among all _services_, and each reply received is\nmatched with the last issued request.\n\nFor connection-oriented transports, If the ZMQ_IMMEDIATE option is set and there\nis no service available, then any send operation on the socket shall block until\nat least one _service_ becomes available. The REQ socket shall not discard messages.\n\n[horizontal]\n.Summary of ZMQ_REQ characteristics\nCompatible peer sockets:: 'ZMQ_REP', 'ZMQ_ROUTER'\nDirection:: Bidirectional\nSend/receive pattern:: Send, Receive, Send, Receive, ...\nOutgoing routing strategy:: Round-robin\nIncoming routing strategy:: Last peer\nAction in mute state:: Block\n\n\nZMQ_REP\n^^^^^^^\nA socket of type 'ZMQ_REP' is used by a _service_ to receive requests from and\nsend replies to a _client_. This socket type allows only an alternating\nsequence of _zmq_recv(request)_ and subsequent _zmq_send(reply)_ calls. Each\nrequest received is fair-queued from among all _clients_, and each reply sent\nis routed to the _client_ that issued the last request. If the original\nrequester does not exist any more the reply is silently discarded.\n\n[horizontal]\n.Summary of ZMQ_REP characteristics\nCompatible peer sockets:: 'ZMQ_REQ', 'ZMQ_DEALER'\nDirection:: Bidirectional\nSend/receive pattern:: Receive, Send, Receive, Send, ...\nIncoming routing strategy:: Fair-queued\nOutgoing routing strategy:: Last peer\n\n\nZMQ_DEALER\n^^^^^^^^^^\nA socket of type 'ZMQ_DEALER' is an advanced pattern used for extending\nrequest/reply sockets. Each message sent is round-robined among all connected\npeers, and each message received is fair-queued from all connected peers.\n\nWhen a 'ZMQ_DEALER' socket enters the 'mute' state due to having reached the\nhigh water mark for all peers, or, for connection-oriented transports, if the\nZMQ_IMMEDIATE option is set and there are no peers at all, then any\nxref:zmq_send.adoc[zmq_send] operations on the socket shall block until the mute state\nends or at least one peer becomes available for sending; messages are not discarded.\n\nWhen a 'ZMQ_DEALER' socket is connected to a 'ZMQ_REP' socket each message sent\nmust consist of an empty message part, the _delimiter_, followed by one or more\n_body parts_.\n\n[horizontal]\n.Summary of ZMQ_DEALER characteristics\nCompatible peer sockets:: 'ZMQ_ROUTER', 'ZMQ_REP', 'ZMQ_DEALER'\nDirection:: Bidirectional\nSend/receive pattern:: Unrestricted\nOutgoing routing strategy:: Round-robin\nIncoming routing strategy:: Fair-queued\nAction in mute state:: Block\n\n\nZMQ_ROUTER\n^^^^^^^^^^\nA socket of type 'ZMQ_ROUTER' is an advanced socket type used for extending\nrequest/reply sockets. When receiving messages a 'ZMQ_ROUTER' socket shall\nprepend a message part containing the _routing id_ of the originating peer to the\nmessage before passing it to the application. Messages received are fair-queued\nfrom among all connected peers. When sending messages a 'ZMQ_ROUTER' socket shall\nremove the first part of the message and use it to determine the _routing id _ of\nthe peer the message shall be routed to. If the peer does not exist anymore, or\nhas never existed, the message shall be silently discarded. However, if\n'ZMQ_ROUTER_MANDATORY' socket option is set to '1', the socket shall fail\nwith EHOSTUNREACH in both cases.\n\nWhen a 'ZMQ_ROUTER' socket enters the 'mute' state due to having reached the\nhigh water mark for all peers, then any messages sent to the socket shall be dropped\nuntil the mute state ends. Likewise, any messages routed to a peer for which\nthe individual high water mark has been reached shall also be dropped. If,\n'ZMQ_ROUTER_MANDATORY' is set to '1', the socket shall block or return EAGAIN in\nboth cases.\n\nWhen a 'ZMQ_ROUTER' socket has 'ZMQ_ROUTER_MANDATORY' flag set to '1', the\nsocket shall generate 'ZMQ_POLLIN' events upon reception of messages from one\nor more peers. Likewise, the socket shall generate 'ZMQ_POLLOUT' events when\nat least one message can be sent to one or more peers.\n\nWhen a 'ZMQ_REQ' socket is connected to a 'ZMQ_ROUTER' socket, in addition to the\n_routing id_ of the originating peer each message received shall contain an empty\n_delimiter_ message part. Hence, the entire structure of each received message\nas seen by the application becomes: one or more _routing id_ parts, _delimiter_\npart, one or more _body parts_. When sending replies to a 'ZMQ_REQ' socket the\napplication must include the _delimiter_ part.\n\n[horizontal]\n.Summary of ZMQ_ROUTER characteristics\nCompatible peer sockets:: 'ZMQ_DEALER', 'ZMQ_REQ', 'ZMQ_ROUTER'\nDirection:: Bidirectional\nSend/receive pattern:: Unrestricted\nOutgoing routing strategy:: See text\nIncoming routing strategy:: Fair-queued\nAction in mute state:: Drop (see text)\n\n\n== RETURN VALUE\nThe _zmq_socket()_ function shall return an opaque handle to the newly created\nsocket if successful. Otherwise, it shall return NULL and set 'errno' to one of\nthe values defined below.\n\n\n== ERRORS\n*EINVAL*::\nThe requested socket 'type' is invalid.\n*EFAULT*::\nThe provided 'context' is invalid.\n*EMFILE*::\nThe limit on the total number of open 0MQ sockets has been reached.\n*ETERM*::\nThe context specified was shutdown or terminated.\n\n== EXAMPLE\n.Creating a simple HTTP server using ZMQ_STREAM\n----\nvoid *ctx = zmq_ctx_new ();\nassert (ctx);\n/* Create ZMQ_STREAM socket */\nvoid *socket = zmq_socket (ctx, ZMQ_STREAM);\nassert (socket);\nint rc = zmq_bind (socket, \"tcp://*:8080\");\nassert (rc == 0);\n/* Data structure to hold the ZMQ_STREAM routing id */\nuint8_t routing_id [256];\nsize_t routing_id_size = 256;\n/* Data structure to hold the ZMQ_STREAM received data */\nuint8_t raw [256];\nsize_t raw_size = 256;\nwhile (1) {\n\t/*  Get HTTP request; routing id frame and then request */\n\trouting_id_size = zmq_recv (socket, routing_id, 256, 0);\n\tassert (routing_id_size > 0);\n\tdo {\n\t\traw_size = zmq_recv (socket, raw, 256, 0);\n\t\tassert (raw_size >= 0);\n\t} while (raw_size == 256);\n\t/* Prepares the response */\n\tchar http_response [] =\n\t\t\"HTTP/1.0 200 OK\\r\\n\"\n\t\t\"Content-Type: text/plain\\r\\n\"\n\t\t\"\\r\\n\"\n\t\t\"Hello, World!\";\n\t/* Sends the routing id frame followed by the response */\n\tzmq_send (socket, routing_id, routing_id_size, ZMQ_SNDMORE);\n\tzmq_send (socket, http_response, strlen (http_response), 0);\n\t/* Closes the connection by sending the routing id frame followed by a zero response */\n\tzmq_send (socket, routing_id, routing_id_size, ZMQ_SNDMORE);\n\tzmq_send (socket, 0, 0, 0);\n}\nzmq_close (socket);\nzmq_ctx_destroy (ctx);\n----\n\n\n== SEE ALSO\n* xref:zmq_init.adoc[zmq_init]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_send.adoc[zmq_send]\n* xref:zmq_recv.adoc[zmq_recv]\n* xref:zmq_inproc.adoc[zmq_inproc]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_socket_monitor.adoc",
    "content": "= zmq_socket_monitor(3)\n\n\n== NAME\n\nzmq_socket_monitor - monitor socket events\n\n\n== SYNOPSIS\n*int zmq_socket_monitor (void '*socket', char '*endpoint', int 'events');*\n\n\n== DESCRIPTION\nThe _zmq_socket_monitor()_ method lets an application thread track\nsocket events (like connects) on a ZeroMQ socket. Each call to this\nmethod creates a 'ZMQ_PAIR' socket and binds that to the specified\ninproc:// 'endpoint'. To collect the socket events, you must create\nyour own 'ZMQ_PAIR' socket, and connect that to the endpoint.\n\nNote that there is also a DRAFT function xref:zmq_socket_monitor_versioned.adoc[zmq_socket_monitor_versioned],\nwhich allows to subscribe to events that provide more information.\nCalling zmq_socket_monitor is equivalent to calling 'zmq_socket_monitor_versioned'\nwith the 'event_version' parameter set to 1, with the exception of error cases.\n\nThe 'events' argument is a bitmask of the socket events you wish to\nmonitor, see 'Supported events' below. To monitor all events, use the\nevent value ZMQ_EVENT_ALL. NOTE: as new events are added, the catch-all\nvalue will start returning them. An application that relies on a strict\nand fixed sequence of events must not use ZMQ_EVENT_ALL in order to\nguarantee compatibility with future versions.\n\nEach event is sent as two frames. The first frame contains an event\nnumber (16 bits), and an event value (32 bits) that provides additional\ndata according to the event number. The second frame contains a string\nthat specifies the affected endpoint.\n\n----\nThe _zmq_socket_monitor()_ method supports only connection-oriented\ntransports, that is, TCP, IPC, and TIPC.\n----\n\nSupported events\n----------------\n\nZMQ_EVENT_CONNECTED\n~~~~~~~~~~~~~~~~~~~\nThe socket has successfully connected to a remote peer. The event value\nis the file descriptor (FD) of the underlying network socket. Warning:\nthere is no guarantee that the FD is still valid by the time your code\nreceives this event.\n\nZMQ_EVENT_CONNECT_DELAYED\n~~~~~~~~~~~~~~~~~~~~~~~~~\nA connect request on the socket is pending. The event value is unspecified.\n\nZMQ_EVENT_CONNECT_RETRIED\n~~~~~~~~~~~~~~~~~~~~~~~~~\nA connect request failed, and is now being retried. The event value is the\nreconnect interval in milliseconds. Note that the reconnect interval is\nrecalculated at each retry.\n\nZMQ_EVENT_LISTENING\n~~~~~~~~~~~~~~~~~~~\nThe socket was successfully bound to a network interface. The event value\nis the FD of the underlying network socket. Warning: there is no guarantee\nthat the FD is still valid by the time your code receives this event.\n\nZMQ_EVENT_BIND_FAILED\n~~~~~~~~~~~~~~~~~~~~~\nThe socket could not bind to a given interface. The event value is the\nerrno generated by the system bind call.\n\nZMQ_EVENT_ACCEPTED\n~~~~~~~~~~~~~~~~~~\nThe socket has accepted a connection from a remote peer. The event value is\nthe FD of the underlying network socket. Warning: there is no guarantee that\nthe FD is still valid by the time your code receives this event.\n\nZMQ_EVENT_ACCEPT_FAILED\n~~~~~~~~~~~~~~~~~~~~~~~\nThe socket has rejected a connection from a remote peer. The event value is\nthe errno generated by the accept call.\n\nZMQ_EVENT_CLOSED\n~~~~~~~~~~~~~~~~\nThe socket was closed. The event value is the FD of the (now closed) network\nsocket.\n\nZMQ_EVENT_CLOSE_FAILED\n~~~~~~~~~~~~~~~~~~~~~~\nThe socket close failed. The event value is the errno returned by the system\ncall. Note that this event occurs only on IPC transports.\n\nZMQ_EVENT_DISCONNECTED\n~~~~~~~~~~~~~~~~~~~~~~\nThe socket was disconnected unexpectedly. The event value is the FD of the\nunderlying network socket. Warning: this socket will be closed.\n\nZMQ_EVENT_MONITOR_STOPPED\n~~~~~~~~~~~~~~~~~~~~~~~~~\nMonitoring on this socket ended.\n\nZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nUnspecified error during handshake.\nThe event value is an errno.\n\nZMQ_EVENT_HANDSHAKE_SUCCEEDED\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe ZMTP security mechanism handshake succeeded.\nThe event value is unspecified.\n\nZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe ZMTP security mechanism handshake failed due to some mechanism protocol\nerror, either between the ZMTP mechanism peers, or between the mechanism\nserver and the ZAP handler. This indicates a configuration or implementation\nerror in either peer resp. the ZAP handler.\nThe event value is one of the ZMQ_PROTOCOL_ERROR_* values:\nZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED\nZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND\nZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE\nZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME\nZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA\nZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC\nZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH\nZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED\nZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY\nZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID\nZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION\nZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE\nZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA\n\nZMQ_EVENT_HANDSHAKE_FAILED_AUTH\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe ZMTP security mechanism handshake failed due to an authentication failure.\nThe event value is the status code returned by the ZAP handler (i.e. 300,\n400 or 500).\n\n\n\n== RETURN VALUE\nThe _zmq_socket_monitor()_ function returns a value of 0 or greater if\nsuccessful. Otherwise it returns `-1` and sets 'errno' to one of the values\ndefined below.\n\n\n== ERRORS\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n\n*EPROTONOSUPPORT*::\nThe requested 'transport' protocol is not supported. Monitor sockets are\nrequired to use the inproc:// transport.\n\n*EINVAL*::\nThe endpoint supplied is invalid.\n\n== EXAMPLE\n.Monitoring client and server sockets\n----\n//  Read one event off the monitor socket; return value and address\n//  by reference, if not null, and event number by value. Returns -1\n//  in case of error.\n\nstatic int\nget_monitor_event (void *monitor, int *value, char **address)\n{\n    //  First frame in message contains event number and value\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    if (zmq_msg_recv (&msg, monitor, 0) == -1)\n        return -1;              //  Interrupted, presumably\n    assert (zmq_msg_more (&msg));\n\n    uint8_t *data = (uint8_t *) zmq_msg_data (&msg);\n    uint16_t event = *(uint16_t *) (data);\n    if (value)\n        *value = *(uint32_t *) (data + 2);\n\n    //  Second frame in message contains event address\n    zmq_msg_init (&msg);\n    if (zmq_msg_recv (&msg, monitor, 0) == -1)\n        return -1;              //  Interrupted, presumably\n    assert (!zmq_msg_more (&msg));\n\n    if (address) {\n        uint8_t *data = (uint8_t *) zmq_msg_data (&msg);\n        size_t size = zmq_msg_size (&msg);\n        *address = (char *) malloc (size + 1);\n        memcpy (*address, data, size);\n        (*address)[size] = 0;\n    }\n    return event;\n}\n\nint main (void)\n{\n    void *ctx = zmq_ctx_new ();\n    assert (ctx);\n\n    //  We'll monitor these two sockets\n    void *client = zmq_socket (ctx, ZMQ_DEALER);\n    assert (client);\n    void *server = zmq_socket (ctx, ZMQ_DEALER);\n    assert (server);\n\n    //  Socket monitoring only works over inproc://\n    int rc = zmq_socket_monitor (client, \"tcp://127.0.0.1:9999\", 0);\n    assert (rc == -1);\n    assert (zmq_errno () == EPROTONOSUPPORT);\n\n    //  Monitor all events on client and server sockets\n    rc = zmq_socket_monitor (client, \"inproc://monitor-client\", ZMQ_EVENT_ALL);\n    assert (rc == 0);\n    rc = zmq_socket_monitor (server, \"inproc://monitor-server\", ZMQ_EVENT_ALL);\n    assert (rc == 0);\n\n    //  Create two sockets for collecting monitor events\n    void *client_mon = zmq_socket (ctx, ZMQ_PAIR);\n    assert (client_mon);\n    void *server_mon = zmq_socket (ctx, ZMQ_PAIR);\n    assert (server_mon);\n\n    //  Connect these to the inproc endpoints so they'll get events\n    rc = zmq_connect (client_mon, \"inproc://monitor-client\");\n    assert (rc == 0);\n    rc = zmq_connect (server_mon, \"inproc://monitor-server\");\n    assert (rc == 0);\n\n    //  Now do a basic ping test\n    rc = zmq_bind (server, \"tcp://127.0.0.1:9998\");\n    assert (rc == 0);\n    rc = zmq_connect (client, \"tcp://127.0.0.1:9998\");\n    assert (rc == 0);\n    bounce (client, server);\n\n    //  Close client and server\n    close_zero_linger (client);\n    close_zero_linger (server);\n\n    //  Now collect and check events from both sockets\n    int event = get_monitor_event (client_mon, NULL, NULL);\n    if (event == ZMQ_EVENT_CONNECT_DELAYED)\n        event = get_monitor_event (client_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_CONNECTED);\n    event = get_monitor_event (client_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n    event = get_monitor_event (client_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_MONITOR_STOPPED);\n\n    //  This is the flow of server events\n    event = get_monitor_event (server_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_LISTENING);\n    event = get_monitor_event (server_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_ACCEPTED);\n    event = get_monitor_event (server_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n    event = get_monitor_event (server_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_CLOSED);\n    event = get_monitor_event (server_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_MONITOR_STOPPED);\n\n    //  Close down the sockets\n    close_zero_linger (client_mon);\n    close_zero_linger (server_mon);\n    zmq_ctx_term (ctx);\n\n    return 0 ;\n}\n----\n\n\n== SEE ALSO\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_socket_monitor_versioned.adoc",
    "content": "= zmq_socket_monitor_versioned(3)\n\n\n== NAME\n\nzmq_socket_monitor_versioned - monitor socket events\n\n\n== SYNOPSIS\n*int zmq_socket_monitor_versioned (void '*socket', char '*endpoint', uint64_t 'events', int 'event_version', int 'type');*\n\n*int zmq_socket_monitor_pipes_stats (void '*socket');*\n\n\n== DESCRIPTION\nThe _zmq_socket_monitor_versioned()_ method lets an application thread track\nsocket events (like connects) on a ZeroMQ socket. Each call to this\nmethod creates a 'ZMQ_PAIR' socket and binds that to the specified\ninproc:// 'endpoint'. To collect the socket events, you must create\nyour own 'ZMQ_PAIR' socket, and connect that to the endpoint.\n\nThe 'events' argument is a bitmask of the socket events you wish to\nmonitor, see 'Supported events' below. To monitor all events for a version, use\nthe event value ZMQ_EVENT_ALL_V<version>, e.g. ZMQ_EVENT_ALL_V1. For non-DRAFT event\nversions, this value will not change in the future, so new event types will only be\nadded in new versions (note that this is a change over zmq_socket_monitor and the\nunversioned ZMQ_EVENT_ALL).\n\nNote that event_version 2 is currently in DRAFT mode. The protocol may be\nchanged at any time for event_versions in DRAFT.\n\nZMQ_CURRENT_EVENT_VERSION and ZMQ_CURRENT_EVENT_VERSION_DRAFT are always defined\nto the most recent stable or DRAFT event version, which are currently 1 resp. 2\n\nThis page describes the protocol for 'event_version' 2 only. For the protocol\nused with 'event_version' 1, please refer to xref:zmq_socket_monitor.adoc[zmq_socket_monitor]\n\nEach event is sent in multiple frames. The first frame contains an event\nnumber (64 bits). The number and content of further frames depend on this\nevent number.\n\nUnless it is specified differently, the second frame contains the number of\nvalue frames that will follow it as a 64 bits integer. The third frame to N-th\nframes contain an event value (64 bits) that provides additional data according\nto the event number. Each event type might have a different number of values.\nThe second-to-last and last frames contain strings that specifies the affected\nconnection or endpoint. The former frame contains a string denoting the local\nendpoint, while the latter frame contains a string denoting the remote endpoint.\nEither of these may be empty, depending on the event type and whether the\nconnection uses a bound or connected local endpoint.\n\nNote that the format of the second and further frames, and also the number of\nframes, may be different for events added in the future.\n\nThe 'type' argument is used to specify the type of the monitoring socket.\nSupported types are 'ZMQ_PAIR', 'ZMQ_PUB' and 'ZMQ_PUSH'. Note that consumers\nof the events will have to be compatible with the socket type, for instance a\nmonitoring socket of type 'ZMQ_PUB' will require consumers of type 'ZMQ_SUB'.\nIn the case that the monitoring socket type is of 'ZMQ_PUB', the multipart\nmessage topic is the event number, thus consumers should subscribe to the\nevents they want to receive.\n\nThe _zmq_socket_monitor_pipes_stats()_ method triggers an event of type\nZMQ_EVENT_PIPES_STATS for each connected peer of the monitored socket.\nNOTE: _zmq_socket_monitor_pipes_stats()_ is in DRAFT state.\n\n----\nMonitoring events are only generated by some transports: At the moment these\nare SOCKS, TCP, IPC, and TIPC. Note that it is not an error to call\n'zmq_socket_monitor_versioned' on a socket that is connected or bound to some\nother transport, as this may not be known at the time\n'zmq_socket_monitor_versioned' is called. Also, a socket can be connected/bound\nto multiple endpoints using different transports.\n\n----\n\nSupported events (v1)\n----------------\n\nZMQ_EVENT_CONNECTED\n~~~~~~~~~~~~~~~~~~~\nThe socket has successfully connected to a remote peer. The event value\nis the file descriptor (FD) of the underlying network socket. Warning:\nthere is no guarantee that the FD is still valid by the time your code\nreceives this event.\n\nZMQ_EVENT_CONNECT_DELAYED\n~~~~~~~~~~~~~~~~~~~~~~~~~\nA connect request on the socket is pending. The event value is unspecified.\n\nZMQ_EVENT_CONNECT_RETRIED\n~~~~~~~~~~~~~~~~~~~~~~~~~\nA connect request failed, and is now being retried. The event value is the\nreconnect interval in milliseconds. Note that the reconnect interval is\nrecalculated for each retry.\n\nZMQ_EVENT_LISTENING\n~~~~~~~~~~~~~~~~~~~\nThe socket was successfully bound to a network interface. The event value\nis the FD of the underlying network socket. Warning: there is no guarantee\nthat the FD is still valid by the time your code receives this event.\n\nZMQ_EVENT_BIND_FAILED\n~~~~~~~~~~~~~~~~~~~~~\nThe socket could not bind to a given interface. The event value is the\nerrno generated by the system bind call.\n\nZMQ_EVENT_ACCEPTED\n~~~~~~~~~~~~~~~~~~\nThe socket has accepted a connection from a remote peer. The event value is\nthe FD of the underlying network socket. Warning: there is no guarantee that\nthe FD is still valid by the time your code receives this event.\n\nZMQ_EVENT_ACCEPT_FAILED\n~~~~~~~~~~~~~~~~~~~~~~~\nThe socket has rejected a connection from a remote peer. The event value is\nthe errno generated by the accept call.\n\nZMQ_EVENT_CLOSED\n~~~~~~~~~~~~~~~~\nThe socket was closed. The event value is the FD of the (now closed) network\nsocket.\n\nZMQ_EVENT_CLOSE_FAILED\n~~~~~~~~~~~~~~~~~~~~~~\nThe socket close failed. The event value is the errno returned by the system\ncall. Note that this event occurs only on IPC transports.\n\nZMQ_EVENT_DISCONNECTED\n~~~~~~~~~~~~~~~~~~~~~~\nThe socket was disconnected unexpectedly. The event value is the FD of the\nunderlying network socket. Warning: this socket will be closed.\n\nZMQ_EVENT_MONITOR_STOPPED\n~~~~~~~~~~~~~~~~~~~~~~~~~\nMonitoring on this socket ended.\n\nZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nUnspecified error during handshake.\nThe event value is an errno.\n\nZMQ_EVENT_HANDSHAKE_SUCCEEDED\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe ZMTP security mechanism handshake succeeded.\nThe event value is unspecified.\n\nZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe ZMTP security mechanism handshake failed due to some mechanism protocol \nerror, either between the ZMTP mechanism peers, or between the mechanism \nserver and the ZAP handler. This indicates a configuration or implementation \nerror in either peer resp. the ZAP handler.\nThe event value is one of the ZMQ_PROTOCOL_ERROR_* values:\nZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED\nZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND\nZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE\nZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY\nZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME\nZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA\nZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC\nZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH\nZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED\nZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY\nZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID\nZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION\nZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE\nZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA\n\nZMQ_EVENT_HANDSHAKE_FAILED_AUTH\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe ZMTP security mechanism handshake failed due to an authentication failure.\nThe event value is the status code returned by the ZAP handler (i.e. 300, \n400 or 500).\n\n----\n\nSupported events (v2)\n----------------\n\nZMQ_EVENT_PIPES_STATS\n~~~~~~~~~~~~~~~~~~~~~\nThis event provides two values, the number of messages in each of the two\nqueues associated with the returned endpoint (respectively egress and ingress).\nThis event only triggers after calling the function\n_zmq_socket_monitor_pipes_stats()_.\nNOTE: this measurement is asynchronous, so by the time the message is received\nthe internal state might have already changed.\nNOTE: when the monitored socket and the monitor are not used in a poll, the\nevent might not be delivered until an API has been called on the monitored\nsocket, like zmq_getsockopt for example (the option is irrelevant).\nNOTE: in DRAFT state, not yet available in stable releases.\n\n\n\n== RETURN VALUE\nThe _zmq_socket_monitor()_ and _zmq_socket_monitor_pipes_stats()_ functions\nreturn a value of 0 or greater if successful. Otherwise they return `-1` and\nset 'errno' to one of the values defined below.\n\n\nERRORS - _zmq_socket_monitor()_\n-------------------------------\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n\n*EPROTONOSUPPORT*::\nThe transport protocol of the monitor 'endpoint' is not supported. Monitor\nsockets are required to use the inproc:// transport.\n\n*EINVAL*::\nThe monitor 'endpoint' supplied does not exist or the specified socket 'type'\nis not supported.\n\n\nERRORS - _zmq_socket_monitor_pipes_stats()_\n-------------------------------------------\n*ENOTSOCK*::\nThe 'socket' parameter was not a valid 0MQ socket.\n\n*EINVAL*::\nThe socket did not have monitoring enabled.\n\n*EAGAIN*::\nThe monitored socket did not have any connections to monitor yet.\n\n== EXAMPLE\n.Monitoring client and server sockets\n----\n//  Read one event off the monitor socket; return values and addresses\n//  by reference, if not null, and event number by value. Returns -1\n//  in case of error.\n\nstatic uint64_t\nget_monitor_event (void *monitor, uint64_t **value, char **local_address, char **remote_address)\n{\n    //  First frame in message contains event number\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    if (zmq_msg_recv (&msg, monitor, 0) == -1)\n        return -1;              //  Interrupted, presumably\n    assert (zmq_msg_more (&msg));\n\n    uint64_t event;\n    memcpy (&event, zmq_msg_data (&msg), sizeof (event));\n    zmq_msg_close (&msg);\n\n    //  Second frame in message contains the number of values\n    zmq_msg_init (&msg);\n    if (zmq_msg_recv (&msg, monitor, 0) == -1)\n        return -1;              //  Interrupted, presumably\n    assert (zmq_msg_more (&msg));\n\n    uint64_t value_count;\n    memcpy (&value_count, zmq_msg_data (&msg), sizeof (value_count));\n    zmq_msg_close (&msg);\n\n    if (value) {\n        *value = (uint64_t *) malloc (value_count * sizeof (uint64_t));\n        assert (*value);\n    }\n\n    for (uint64_t i = 0; i < value_count; ++i) {\n        //  Subsequent frames in message contain event values\n        zmq_msg_init (&msg);\n        if (zmq_msg_recv (&msg, monitor, 0) == -1)\n            return -1;              //  Interrupted, presumably\n        assert (zmq_msg_more (&msg));\n\n        if (value && *value)\n            memcpy (&(*value)[i], zmq_msg_data (&msg), sizeof (uint64_t));\n        zmq_msg_close (&msg);\n    }\n\n    //  Second-to-last frame in message contains local address\n    zmq_msg_init (&msg);\n    if (zmq_msg_recv (&msg, monitor, 0) == -1)\n        return -1;              //  Interrupted, presumably\n    assert (zmq_msg_more (&msg));\n\n    if (local_address_) {\n        uint8_t *data = (uint8_t *) zmq_msg_data (&msg);\n        size_t size = zmq_msg_size (&msg);\n        *local_address_ = (char *) malloc (size + 1);\n        memcpy (*local_address_, data, size);\n        (*local_address_)[size] = 0;\n    }\n    zmq_msg_close (&msg);\n\n    //  Last frame in message contains remote address\n    zmq_msg_init (&msg);\n    if (zmq_msg_recv (&msg, monitor, 0) == -1)\n        return -1;              //  Interrupted, presumably\n    assert (!zmq_msg_more (&msg));\n\n    if (remote_address_) {\n        uint8_t *data = (uint8_t *) zmq_msg_data (&msg);\n        size_t size = zmq_msg_size (&msg);\n        *remote_address_ = (char *) malloc (size + 1);\n        memcpy (*remote_address_, data, size);\n        (*remote_address_)[size] = 0;\n    }\n    zmq_msg_close (&msg);\n\n    return event;\n}\n\nint main (void)\n{\n    void *ctx = zmq_ctx_new ();\n    assert (ctx);\n\n    //  We'll monitor these two sockets\n    void *client = zmq_socket (ctx, ZMQ_DEALER);\n    assert (client);\n    void *server = zmq_socket (ctx, ZMQ_DEALER);\n    assert (server);\n\n    //  Socket monitoring only works over inproc://\n    int rc = zmq_socket_monitor_versioned (client, \"tcp://127.0.0.1:9999\", 0, 2);\n    assert (rc == -1);\n    assert (zmq_errno () == EPROTONOSUPPORT);\n\n    //  Monitor all events on client and server sockets\n    rc = zmq_socket_monitor_versioned (client, \"inproc://monitor-client\", ZMQ_EVENT_ALL, 2);\n    assert (rc == 0);\n    rc = zmq_socket_monitor_versioned (server, \"inproc://monitor-server\", ZMQ_EVENT_ALL, 2);\n    assert (rc == 0);\n\n    //  Create two sockets for collecting monitor events\n    void *client_mon = zmq_socket (ctx, ZMQ_PAIR);\n    assert (client_mon);\n    void *server_mon = zmq_socket (ctx, ZMQ_PAIR);\n    assert (server_mon);\n\n    //  Connect these to the inproc endpoints so they'll get events\n    rc = zmq_connect (client_mon, \"inproc://monitor-client\");\n    assert (rc == 0);\n    rc = zmq_connect (server_mon, \"inproc://monitor-server\");\n    assert (rc == 0);\n\n    //  Now do a basic ping test\n    rc = zmq_bind (server, \"tcp://127.0.0.1:9998\");\n    assert (rc == 0);\n    rc = zmq_connect (client, \"tcp://127.0.0.1:9998\");\n    assert (rc == 0);\n    bounce (client, server);\n\n    //  Close client and server\n    close_zero_linger (client);\n    close_zero_linger (server);\n\n    //  Now collect and check events from both sockets\n    int event = get_monitor_event (client_mon, NULL, NULL);\n    if (event == ZMQ_EVENT_CONNECT_DELAYED)\n        event = get_monitor_event (client_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_CONNECTED);\n    event = get_monitor_event (client_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_MONITOR_STOPPED);\n\n    //  This is the flow of server events\n    event = get_monitor_event (server_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_LISTENING);\n    event = get_monitor_event (server_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_ACCEPTED);\n    event = get_monitor_event (server_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_CLOSED);\n    event = get_monitor_event (server_mon, NULL, NULL);\n    assert (event == ZMQ_EVENT_MONITOR_STOPPED);\n\n    //  Close down the sockets\n    close_zero_linger (client_mon);\n    close_zero_linger (server_mon);\n    zmq_ctx_term (ctx);\n\n    return 0 ;\n}\n----\n\n\n== SEE ALSO\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_strerror.adoc",
    "content": "= zmq_strerror(3)\n\n\n== NAME\nzmq_strerror - get 0MQ error message string\n\n\n== SYNOPSIS\n*const char *zmq_strerror (int 'errnum');*\n\n\n== DESCRIPTION\nThe _zmq_strerror()_ function shall return a pointer to an error message string\ncorresponding to the error number specified by the 'errnum' argument. As 0MQ\ndefines additional error numbers over and above those defined by the operating\nsystem, applications should use _zmq_strerror()_ in preference to the standard\n_strerror()_ function.\n\n\n== RETURN VALUE\nThe _zmq_strerror()_ function shall return a pointer to an error message\nstring.\n\n\n== ERRORS\nNo errors are defined.\n\n\n== EXAMPLE\n.Displaying an error message when a 0MQ context cannot be initialised\n----\nvoid *ctx = zmq_init (1, 1, 0);\nif (!ctx) {\n    printf (\"Error occurred during zmq_init(): %s\\n\", zmq_strerror (errno));\n    abort ();\n}\n----\n\n\n== SEE ALSO\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n\n"
  },
  {
    "path": "doc/zmq_tcp.adoc",
    "content": "= zmq_tcp(7)\n\n\n== NAME\nzmq_tcp - 0MQ unicast transport using TCP\n\n\n== SYNOPSIS\nTCP is an ubiquitous, reliable, unicast transport. When connecting distributed\napplications over a network with 0MQ, using the TCP transport will likely be\nyour first choice.\n\n\n== ADDRESSING\nA 0MQ endpoint is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to connect to.\n\nFor the TCP transport, the transport is `tcp`, and the meaning of the\n'address' part is defined below.\n\n\nAssigning a local address to a socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen assigning a local address to a socket using _zmq_bind()_ with the 'tcp'\ntransport, the 'endpoint' shall be interpreted as an 'interface' followed by a\ncolon and the TCP port number to use.\n\nAn 'interface' may be specified by either of the following:\n\n* The wild-card `*`, meaning all available interfaces.\n* The primary IPv4 or IPv6 address assigned to the interface, in its numeric\n  representation.\n* The non-portable interface name as defined by the operating system.\n\nThe TCP port number may be specified by:\n\n* A numeric value, usually above 1024 on POSIX systems.\n* The wild-card `*`, meaning a system-assigned ephemeral port.\n\nWhen using ephemeral ports, the caller should retrieve the actual assigned\nport using the ZMQ_LAST_ENDPOINT socket option. See xref:zmq_getsockopt.adoc[zmq_getsockopt]\nfor details.\n\nUnbinding wild-card address from a socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen wild-card `*` 'endpoint' was used in _zmq_bind()_, the caller should use\nreal 'endpoint' obtained from the ZMQ_LAST_ENDPOINT socket option to unbind \nthis 'endpoint' from a socket using _zmq_unbind()_.\n\nConnecting a socket\n~~~~~~~~~~~~~~~~~~~\nWhen connecting a socket to a peer address using _zmq_connect()_ with the 'tcp'\ntransport, the 'endpoint' shall be interpreted as a 'peer address' followed by\na colon and the TCP port number to use.\nYou can optionally specify a 'source_endpoint' which will be used as the source\naddress for your connection; tcp://'source_endpoint';'endpoint', see the\n'interface' description above for details.\n\nA 'peer address' may be specified by either of the following:\n\n* The DNS name of the peer.\n* The IPv4 or IPv6 address of the peer, in its numeric representation.\n\nNote: A description of the ZeroMQ Message Transport Protocol (ZMTP) which is \nused by the TCP transport can be found at <http://rfc.zeromq.org/spec:23>\n\n\n== HWM\n\nFor the TCP transport, the high water mark (HWM) mechanism works in conjunction\nwith the TCP socket buffers handled at OS level.\nDepending on the OS and several other factors the size of such TCP buffers will\nbe different. Moreover TCP buffers provided by the OS will accommodate a varying\nnumber of messages depending on the size of messages (unlike ZMQ HWM settings\nthe TCP socket buffers are measured in bytes and not messages).\n\nThis may result in apparently inexplicable behaviors: e.g., you may expect that\nsetting ZMQ_SNDHWM to 100 on a socket using TCP transport will have the effect\nof blocking the transmission of the 101-th message if the receiver is slow.\nThis is very unlikely when using TCP transport since OS TCP buffers will typically\nprovide enough buffering to allow you sending much more than 100 messages.\n\nOf course if the receiver is slow, transmitting on a TCP ZMQ socket will eventually trigger\nthe \"mute state\" of the socket; simply don't rely on the exact HWM value.\n\nObviously the same considerations apply for the receive HWM (see ZMQ_RCVHWM).\n\n\n\n== EXAMPLES\n.Assigning a local address to a socket\n----\n//  TCP port 5555 on all available interfaces\nrc = zmq_bind(socket, \"tcp://*:5555\");\nassert (rc == 0);\n//  TCP port 5555 on the local loop-back interface on all platforms\nrc = zmq_bind(socket, \"tcp://127.0.0.1:5555\");\nassert (rc == 0);\n//  TCP port 5555 on the first Ethernet network interface on Linux\nrc = zmq_bind(socket, \"tcp://eth0:5555\");\nassert (rc == 0);\n----\n\n.Connecting a socket\n----\n//  Connecting using an IP address\nrc = zmq_connect(socket, \"tcp://192.168.1.1:5555\");\nassert (rc == 0);\n//  Connecting using a DNS name\nrc = zmq_connect(socket, \"tcp://server1:5555\");\nassert (rc == 0);\n//  Connecting using a DNS name and bind to eth1\nrc = zmq_connect(socket, \"tcp://eth1:0;server1:5555\");\nassert (rc == 0);\n//  Connecting using a IP address and bind to an IP address\nrc = zmq_connect(socket, \"tcp://192.168.1.17:5555;192.168.1.1:5555\");\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_pgm.adoc[zmq_pgm]\n* xref:zmq_ipc.adoc[zmq_ipc]\n* xref:zmq_inproc.adoc[zmq_inproc]\n* xref:zmq_vmci.adoc[zmq_vmci]\n* xref:zmq_vsock.adoc[zmq_vsock]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_timers.adoc",
    "content": "= zmq_timers(3)\n\n\n== NAME\nzmq_timers - helper functions for cross-platform timers callbacks\n\n\n== SYNOPSIS\n\n*typedef void(zmq_timer_fn) (int 'timer_id', void *'arg');*\n\n*void *zmq_timers_new (void);*\n\n*int zmq_timers_destroy (void **'timers_p');*\n\n*int zmq_timers_add (void *'timers', size_t 'interval', zmq_timer_fn 'handler', void *'arg');*\n\n*int zmq_timers_cancel (void *'timers', int 'timer_id');*\n\n*int zmq_timers_set_interval (void *'timers', int 'timer_id', size_t 'interval');*\n\n*int zmq_timers_reset (void *'timers', int 'timer_id');*\n\n*long zmq_timers_timeout (void *'timers');*\n\n*int zmq_timers_execute (void *'timers');*\n\n\n== DESCRIPTION\nThe _zmq_timers_*_ functions provide cross-platform access to timers callbacks.\nOnce a timer has been registered, it will repeat at the specified interval until\nit gets manually cancelled. To run the callbacks, _zmq_timers_execute_ must be\nran.\n\n_zmq_timers_new_ and _zmq_timers_destroy_ manage the lifetime of a timer\ninstance. _zmq_timers_new_ creates and returns a new timer instance, while\n_zmq_timers_destroy_ destroys it. A pointer to a valid timer must be passed\nas the _timers_p_ argument of _zmq_timers_destroy_. In particular,\n_zmq_timers_destroy_ may not be called multiple times for the same timer\ninstance. _zmq_timers_destroy_ sets the passed pointer to NULL in case of a\nsuccessful execution.\n\n_zmq_timers_add_ and _zmq_timers_cancel_ manage the timers registered.\n\n_zmq_timers_add_ registers a new _timer_ with a given instance. _timers_ must\npoint to a valid _timers_ object. The _interval_ parameter specifies the\nexpiration of the timer in milliseconds. _handler_ and _arg_ specify the callback\nthat will be invoked on expiration and the optional parameter that will be passed\nthrough. The callback must be a valid function implementing the _zmq_timer_fn_\nprototype. An ID will be returned that can be used to modify or cancel the timer.\n\n_zmq_timers_cancel_ will cancel the timer associated with _timer_id_ from the\ninstance _timers_.\n\n_zmq_timers_set_interval_ will set the expiration of the timer associated with\n_timer_id_ from the instance _timers_ to _interval_ milliseconds into the future.\n\n_zmq_timers_reset_ will restart the timer associated with _timer_id_ from the\ninstance _timers_.\n\n_zmq_timers_timeout_ will return the time left in milliseconds until the next\ntimer registered with _timers_ expires.\n\n_zmq_timers_execute_ will run callbacks of all expired timers from the instance\n_timers_.\n\n\n== THREAD SAFETY\nLike most other 0MQ objects, timers are not thread-safe. All operations must\nbe called from the same thread. Otherwise, behaviour is undefined.\n\n\n== RETURN VALUE\n_zmq_timers_new_ always returns a valid pointer to a poller.\n\nAll functions that return an int, return -1 in case of a failure. In that case,\nzmq_errno() can be used to query the type of the error as described below.\n\n_zmq_timers_timeout_ returns the time left in milliseconds until the next\ntimer registered with _timers_ expires, or -1 if there are no timers left.\n\nAll other functions return 0 in case of a successful execution.\n\n\n== ERRORS\nOn _zmq_timers_destroy_, _zmq_poller_cancel_, _zmq_timers_set_interval_,\n_zmq_timers_reset_, zmq_timers_timeout_, and _zmq_timers_execute_:\n*EFAULT*::\n_timers_ did not point to a valid timer. Note that passing an\ninvalid pointer (e.g. pointer to deallocated memory) may cause undefined\nbehaviour (e.g. an access violation).\n\nOn _zmq_timers_add_:\n*EFAULT*::\n_timers_ did not point to a valid timer or _handler_ did not point to a valid\nfunction.\n\nOn _zmq_poller_cancel_, _zmq_timers_set_interval_ and zmq_timers_timeout_:\n*EINVAL*::\n_timer_id_ did not exist or was already cancelled.\n\n\n== EXAMPLE\n.Add one timer with a simple callback that changes a boolean.\n----\n    void handler (int timer_id_, void *arg_)\n    {\n        (void) timer_id_; //  Stop 'unused' compiler warnings\n        *((bool *) arg_) = true;\n    }\n\n    ...\n\n    void *timers = zmq_timers_new ();\n    assert (timers);\n\n    bool timer_invoked = false;\n\n    const unsigned long full_timeout = 100;\n\n    int timer_id =\n      zmq_timers_add (timers, full_timeout, handler, &timer_invoked);\n    assert (timer_id);\n\n    //  Timer should not have been invoked yet\n    int rc = zmq_timers_execute (timers);\n    assert (rc == 0);\n\n    //  Wait half the time and check again\n    long timeout = zmq_timers_timeout (timers);\n    assert (rc != -1);\n    msleep (timeout / 2);\n    rc = zmq_timers_execute (timers);\n    assert (rc == 0);\n\n    // Wait until the end\n    rc = msleep (zmq_timers_timeout (timers));\n    assert (rc == 0);\n\n    // The handler will be executed\n    rc = zmq_timers_execute (timers);\n    assert (rc == 0);\n    assert (timer_invoked);\n\n    rc = zmq_timers_destroy (&timers);\n    assert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_tipc.adoc",
    "content": "= zmq_tipc(7)\n\n\n== NAME\nzmq_tipc - 0MQ unicast transport using TIPC\n\n\n== SYNOPSIS\nTIPC is a cluster IPC protocol with a location transparent addressing scheme.\n\n\n== ADDRESSING\nA 0MQ endpoint is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to connect to.\n\nFor the TIPC transport, the transport is `tipc`, and the meaning of the\n'address' part is defined below.\n\n\nAssigning a port name to a socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen assigning a port name to a socket using _zmq_bind()_ with the 'tipc'\ntransport, the 'endpoint' is defined in the form:\n{type, lower, upper}\n\n* Type is the numerical (u32) ID of your service.\n* Lower and Upper specify a range for your service.\n\nPublishing the same service with overlapping lower/upper ID's will\ncause connection requests to be distributed over these in a round-robin\nmanner.\n\n\nConnecting a socket\n~~~~~~~~~~~~~~~~~~~\nWhen connecting a socket to a peer address using _zmq_connect()_ with the 'tipc'\ntransport, the 'endpoint' shall be interpreted as a service ID, followed by a \ncomma and the instance ID.\n\nThe instance ID must be within the lower/upper range of a published port name\nfor the endpoint to be valid.\n\n== EXAMPLES\n.Assigning a local address to a socket\n----\n//  Publish TIPC service ID 5555\nrc = zmq_bind(socket, \"tipc://{5555,0,0}\");\nassert (rc == 0);\n//  Publish TIPC service ID 5555 with a service range of 0-100\nrc = zmq_bind(socket, \"tipc://{5555,0,100}\");\nassert (rc == 0);\n----\n\n.Connecting a socket\n----\n//  Connect to service 5555 instance id 50\nrc = zmq_connect(socket, \"tipc://{5555,50}\");\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_tcp.adoc[zmq_tcp]\n* xref:zmq_pgm.adoc[zmq_pgm]\n* xref:zmq_ipc.adoc[zmq_ipc]\n* xref:zmq_inproc.adoc[zmq_inproc]\n* xref:zmq_vmci.adoc[zmq_vmci]\n* xref:zmq_vsock.adoc[zmq_vsock]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_udp.adoc",
    "content": "= zmq_udp(7)\n\n\n== NAME\nzmq_udp - 0MQ UDP multicast and unicast transport\n\n\n== SYNOPSIS\nUDP is unreliable protocol transport of data over IP networks.\nUDP support both unicast and multicast communication.\n\n\n== DESCRIPTION\nUDP transport can only be used with the 'ZMQ_RADIO' and\n'ZMQ_DISH' socket types.\n\n== ADDRESSING\nA 0MQ endpoint is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to connect to.\n\nFor the UDP transport, the transport is `udp`.\nThe meaning of the 'address' part is defined below.\n\nBinding a socket\n----------------\nWith 'udp' we can only bind the 'ZMQ_DISH' socket type.\nWhen binding a socket using _zmq_bind()_ with the 'udp'\ntransport the 'endpoint' shall be interpreted as an 'interface' followed by a\ncolon and the UDP port number to use.\n\nAn 'interface' may be specified by either of the following:\n\n* The wild-card `*`, meaning all available interfaces.\n* The name of the network interface (i.e. eth0, lo, wlan0 etc...)\n* The primary address assigned to the interface, in its numeric representation.\n* Multicast address in its numeric representation the socket should join.\n\nThe UDP port number may be specified a numeric value, usually above\n1024 on POSIX systems.\n\nConnecting a socket\n-------------------\nWith 'udp' we can only connect the 'ZMQ_RADIO' socket type.\nWhen connecting a socket to a peer address using _zmq_connect()_ with the 'udp'\ntransport, the 'endpoint' shall be interpreted as a 'peer address' followed by\na colon and the UDP port number to use.\n\nA 'peer address' may be specified by either of the following:\n\n* The IPv4 or IPv6 address of the peer, in its numeric representation\n  or using its hostname.\n* Multicast address in its numeric representation.\n\n== EXAMPLES\n.Binding a socket\n----\n//  Unicast - UDP port 5555 on all available interfaces\nrc = zmq_bind(dish, \"udp://*:5555\");\nassert (rc == 0);\n//  Unicast - UDP port 5555 on the local loop-back interface\nrc = zmq_bind(dish, \"udp://127.0.0.1:5555\");\nassert (rc == 0);\n//  Unicast - UDP port 5555 on interface eth1\nrc = zmq_bind(dish, \"udp://eth1:5555\");\nassert (rc == 0);\n//  Multicast - UDP port 5555 on a Multicast address\nrc = zmq_bind(dish, \"udp://239.0.0.1:5555\");\nassert (rc == 0);\n//  Same as above but joining only on interface eth0\nrc = zmq_bind(dish, \"udp://eth0;239.0.0.1:5555\");\nassert (rc == 0);\n//  Same as above using IPv6 multicast\nrc = zmq_bind(dish, \"udp://eth0;[ff02::1]:5555\");\nassert (rc == 0);\n----\n\n\n.Connecting a socket\n----\n//  Connecting using an Unicast IP address\nrc = zmq_connect(radio, \"udp://192.168.1.1:5555\");\nassert (rc == 0);\n//  Connecting using a Multicast address\nrc = zmq_connect(socket, \"udp://239.0.0.1:5555);\nassert (rc == 0);\n//  Connecting using a Multicast address using local interface wlan0\nrc = zmq_connect(socket, \"udp://wlan0;239.0.0.1:5555);\nassert (rc == 0);\n//  Connecting to IPv6 multicast\nrc = zmq_connect(socket, \"udp://[ff02::1]:5555);\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_setsockopt.adoc[zmq_setsockopt]\n* xref:zmq_tcp.adoc[zmq_tcp]\n* xref:zmq_ipc.adoc[zmq_ipc]\n* xref:zmq_inproc.adoc[zmq_inproc]\n* xref:zmq_vmci.adoc[zmq_vmci]\n* xref:zmq_vsock.adoc[zmq_vsock]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_unbind.adoc",
    "content": "= zmq_unbind(3)\n\n\n== NAME\nzmq_unbind - Stop accepting connections on a socket\n\n\n== SYNOPSIS\nint zmq_unbind (void '*socket', const char '*endpoint');\n\n\n== DESCRIPTION\nThe _zmq_unbind()_ function shall unbind a socket specified\nby the 'socket' argument from the endpoint specified by the 'endpoint'\nargument. \n\nAdditionally the incoming message queue associated with the endpoint will be\ndiscarded. This means that after unbinding an endpoint it is possible to\nreceived messages originating from that same endpoint if they were already\npresent in the incoming message queue before unbinding.\n\nThe 'endpoint' argument is as described in xref:zmq_bind.adoc[zmq_bind]\n\nUnbinding wild-card address from a socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen wild-card `*` 'endpoint' (described in xref:zmq_tcp.adoc[zmq_tcp],\nxref:zmq_ipc.adoc[zmq_ipc], xref:zmq_udp.adoc[zmq_udp],\nxref:zmq_vmci.adoc[zmq_vmci] and xref:zmq_vsock.adoc[zmq_vsock]) was used in\n_zmq_bind()_, the caller should use real 'endpoint' obtained from the \nZMQ_LAST_ENDPOINT socket option to unbind this 'endpoint' from a socket.\n\n== RETURN VALUE\nThe _zmq_unbind()_ function shall return zero if successful. Otherwise it\nshall return `-1` and set 'errno' to one of the values defined below.\n\n== ERRORS\n*EINVAL*::\nThe endpoint supplied is invalid.\n*ETERM*::\nThe 0MQ 'context' associated with the specified 'socket' was terminated.\n*ENOTSOCK*::\nThe provided 'socket' was invalid.\n*ENOENT*::\nThe endpoint supplied was not previously bound.\n\n\n== EXAMPLES\n.Unbind a subscriber socket from a TCP transport\n----\n/* Create a ZMQ_SUB socket */\nvoid *socket = zmq_socket (context, ZMQ_SUB);\nassert (socket);\n/* Connect it to the host server001, port 5555 using a TCP transport */\nrc = zmq_bind (socket, \"tcp://127.0.0.1:5555\");\nassert (rc == 0);\n/* Disconnect from the previously connected endpoint */\nrc = zmq_unbind (socket, \"tcp://127.0.0.1:5555\");\nassert (rc == 0);\n----\n\n.Unbind wild-card `*` binded socket\n----\n/* Create a ZMQ_SUB socket */\nvoid *socket = zmq_socket (context, ZMQ_SUB);\nassert (socket);\n/* Bind it to the system-assigned ephemeral port using a TCP transport */\nrc = zmq_bind (socket, \"tcp://127.0.0.1:*\");\nassert (rc == 0);\n/* Obtain real endpoint */\nconst size_t buf_size = 32;\nchar buf[buf_size];\nrc = zmq_getsockopt (socket, ZMQ_LAST_ENDPOINT, buf, (size_t *)&buf_size);\nassert (rc == 0);\n/* Unbind socket by real endpoint */\nrc = zmq_unbind (socket, buf);\nassert (rc == 0);\n----\n\n== NOTE\n\nNote that while the implementation is similar to _zmq_disconnect()_, the\nsemantics are different and the two functions should not be used\ninterchangeably. Bound sockets should be unbound, and connected sockets should\nbe disconnected.\n\n== SEE ALSO\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_socket.adoc[zmq_socket]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_version.adoc",
    "content": "= zmq_version(3)\n\n\n== NAME\nzmq_version - report 0MQ library version\n\n\n== SYNOPSIS\n*void zmq_version (int '*major', int '*minor', int '*patch');*\n\n\n== DESCRIPTION\nThe _zmq_version()_ function shall fill in the integer variables pointed to by\nthe 'major', 'minor' and 'patch' arguments with the major, minor and patch level\ncomponents of the 0MQ library version.\n\nThis functionality is intended for applications or language bindings\ndynamically linking to the 0MQ library that wish to determine the actual\nversion of the 0MQ library they are using.\n\n\n== RETURN VALUE\nThere is no return value.\n\n\n== ERRORS\nNo errors are defined.\n\n\n== EXAMPLE\n.Printing out the version of the 0MQ library\n----\nint major, minor, patch;\nzmq_version (&major, &minor, &patch);\nprintf (\"Current 0MQ version is %d.%d.%d\\n\", major, minor, patch);\n----\n\n\n== SEE ALSO\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_vmci.adoc",
    "content": "= zmq_vmci(7)\n\n\n== NAME\nzmq_vmci - 0MQ transport over virtual machine communications interface (VMCI) sockets\n\n\n== SYNOPSIS\nThe VMCI transport passes messages between VMware virtual machines running on the same host,\nbetween virtual machine and the host and within virtual machines (inter-process transport like ipc).\n\nNOTE: Communication between a virtual machine and the host is not supported on Mac OS X 10.9 and above.\n\n\n== ADDRESSING\nA 0MQ endpoint is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to connect to.\n\nFor the VMCI transport, the transport is `vmci`, and the meaning of\nthe 'address' part is defined below.\n\n\nBinding a socket\n~~~~~~~~~~~~~~~~\nWhen binding a 'socket' to a local address using _zmq_bind()_ with the 'vmci'\ntransport, the 'endpoint' shall be interpreted as an 'interface' followed by a\ncolon and the TCP port number to use.\n\nAn 'interface' may be specified by either of the following:\n\n* The wild-card `*`, meaning all available interfaces.\n* An integer returned by `VMCISock_GetLocalCID` or `@` (ZeroMQ will call VMCISock_GetLocalCID internally).\n\nThe port may be specified by:\n\n* A numeric value, usually above 1024 on POSIX systems.\n* The wild-card `*`, meaning a system-assigned ephemeral port.\n\nUnbinding wild-card address from a socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen wild-card `*` 'endpoint' was used in _zmq_bind()_, the caller should use\nreal 'endpoint' obtained from the ZMQ_LAST_ENDPOINT socket option to unbind\nthis 'endpoint' from a socket using _zmq_unbind()_.\n\nConnecting a socket\n~~~~~~~~~~~~~~~~~~~\nWhen connecting a socket to a peer address using _zmq_connect()_ with the 'vmci'\ntransport, the 'endpoint' shall be interpreted as a 'peer address' followed by\na colon and the port number to use.\n\nA 'peer address' must be a CID of the peer.\n\n\n== EXAMPLES\n.Assigning a local address to a socket\n----\n//  VMCI port 5555 on all available interfaces\nrc = zmq_bind(socket, \"vmci://*:5555\");\nassert (rc == 0);\n//  VMCI port 5555 on the local loop-back interface on all platforms\ncid = VMCISock_GetLocalCID();\nsprintf(endpoint, \"vmci://%d:5555\", cid);\nrc = zmq_bind(socket, endpoint);\nassert (rc == 0);\n----\n\n.Connecting a socket\n----\n//  Connecting using a CID\nsprintf(endpoint, \"vmci://%d:5555\", cid);\nrc = zmq_connect(socket, endpoint);\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_inproc.adoc[zmq_inproc]\n* xref:zmq_tcp.adoc[zmq_tcp]\n* xref:zmq_pgm.adoc[zmq_pgm]\n* xref:zmq_vmci.adoc[zmq_vmci]\n* xref:zmq_getsockopt.adoc[zmq_getsockopt]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_vsock.adoc",
    "content": "= zmq_vsock(7)\n\n\n== NAME\nzmq_vsock - 0MQ transport over Linux VSOCK (AF_VSOCK)\n\n\n== SYNOPSIS\nThe AF_VSOCK address family facilitates communication between virtual machines and the host they are running on.\nThis address family is used by guest agents and hypervisor services that need a communications channel that is independent of virtual machine network configuration.\n\nNOTE: AF_VSOCK is only supported on linux, <https://man7.org/linux/man-pages/man7/vsock.7.html>\n\n\n== ADDRESSING\nA 0MQ endpoint is a string consisting of a 'transport'`://` followed by an\n'address'. The 'transport' specifies the underlying protocol to use. The\n'address' specifies the transport-specific address to connect to.\n\nFor the VSOCK transport, the transport is `vsock`, and the meaning of\nthe 'address' part is defined below.\n\n\nBinding a socket\n~~~~~~~~~~~~~~~~\nWhen binding a 'socket' to a local address using _zmq_bind()_ with the 'vsock'\ntransport, the 'endpoint' shall be interpreted as an 'interface' followed by a\ncolon and the port number to use.\n\nAn 'interface' may be specified by either of the following:\n\n* The wild-card `*`, meaning all available interfaces.\n* An integer returned by `VMADDR_CID_LOCAL` or `@`.\n\nThe port may be specified by:\n\n* A numeric value, usually above 1024 on POSIX systems.\n* The wild-card `*`, meaning a system-assigned ephemeral port.\n\nUnbinding wild-card address from a socket\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhen wild-card `*` 'endpoint' was used in _zmq_bind()_, the caller should use\nreal 'endpoint' obtained from the ZMQ_LAST_ENDPOINT socket option to unbind\nthis 'endpoint' from a socket using _zmq_unbind()_.\n\nConnecting a socket\n~~~~~~~~~~~~~~~~~~~\nWhen connecting a socket to a peer address using _zmq_connect()_ with the 'vsock'\ntransport, the 'endpoint' shall be interpreted as a 'peer address' followed by\na colon and the port number to use.\n\nA 'peer address' must be a CID of the peer.\n\n\n== EXAMPLES\n.Assigning a local address to a socket\n----\n//  VSOCK port 5555 on all available interfaces\nrc = zmq_bind(socket, \"vsock://*:5555\");\nassert (rc == 0);\n//  VSOCK port 5555 on the local loop-back interface on all platforms\ncid = VMADDR_CID_LOCAL;\nsprintf(endpoint, \"vsock://%d:5555\", cid);\nrc = zmq_bind(socket, endpoint);\nassert (rc == 0);\n----\n\n.Connecting a socket\n----\n//  Connecting using a CID\nsprintf(endpoint, \"vsock://%d:5555\", cid);\nrc = zmq_connect(socket, endpoint);\nassert (rc == 0);\n----\n\n\n== SEE ALSO\n* xref:zmq_bind.adoc[zmq_bind]\n* xref:zmq_connect.adoc[zmq_connect]\n* xref:zmq_inproc.adoc[zmq_inproc]\n* xref:zmq_tcp.adoc[zmq_tcp]\n* xref:zmq_pgm.adoc[zmq_pgm]\n* xref:zmq_vsock.adoc[zmq_vsock]\n* xref:zmq_getsockopt.adoc[zmq_getsockopt]\n* xref:zmq.adoc[zmq]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_z85_decode.adoc",
    "content": "= zmq_z85_decode(3)\n\n\n== NAME\nzmq_z85_decode - decode a binary key from Z85 printable text\n\n\n== SYNOPSIS\n*uint8_t *zmq_z85_decode (uint8_t *dest, const char *string);*\n\n\n== DESCRIPTION\nThe _zmq_z85_decode()_ function shall decode 'string' into 'dest'.\nThe length of 'string' shall be divisible by 5. 'dest' must be large\nenough for the decoded value (0.8 x strlen (string)). \n\nThe encoding shall follow the ZMQ RFC 32 specification.\n\n\n== RETURN VALUE\nThe _zmq_z85_decode()_ function shall return 'dest' if successful, else it\nshall return NULL.\n\n\n== EXAMPLE\n.Decoding a CURVE key\n----\nconst char decoded [] = \"rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7\";\nuint8_t public_key [32];\nzmq_z85_decode (public_key, decoded);\n----\n\n\n== SEE ALSO\n* xref:zmq_z85_encode.adoc[zmq_z85_encode]\n* xref:zmq_curve_keypair.adoc[zmq_curve_keypair]\n* xref:zmq_curve_public.adoc[zmq_curve_public]\n* xref:zmq_curve.adoc[zmq_curve]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "doc/zmq_z85_encode.adoc",
    "content": "= zmq_z85_encode(3)\n\n\n== NAME\nzmq_z85_encode - encode a binary key as Z85 printable text\n\n\n== SYNOPSIS\n*char *zmq_z85_encode (char *dest, const uint8_t *data, size_t size);*\n\n\n== DESCRIPTION\nThe _zmq_z85_encode()_ function shall encode the binary block specified \nby 'data' and 'size' into a string in 'dest'. The size of the binary block\nmust be divisible by 4. The 'dest' must have sufficient space for size * 1.25 \nplus 1 for a null terminator. A 32-byte CURVE key is encoded as 40 ASCII \ncharacters plus a null terminator.\n\nThe encoding shall follow the ZMQ RFC 32 specification.\n\n\n== RETURN VALUE\nThe _zmq_z85_encode()_ function shall return 'dest' if successful, else it\nshall return NULL.\n\n\n== EXAMPLE\n.Encoding a CURVE key\n----\n#include <sodium.h>\nuint8_t public_key [32];\nuint8_t secret_key [32];\nint rc = crypto_box_keypair (public_key, secret_key);\nassert (rc == 0);\nchar encoded [41];\nzmq_z85_encode (encoded, public_key, 32);\nputs (encoded);\n----\n\n\n== SEE ALSO\n* xref:zmq_z85_decode.adoc[zmq_z85_decode]\n* xref:zmq_curve_keypair.adoc[zmq_curve_keypair]\n* xref:zmq_curve_public.adoc[zmq_curve_public]\n* xref:zmq_curve.adoc[zmq_curve]\n\n\n== AUTHORS\nThis page was written by the 0MQ community. To make a change please\nread the 0MQ Contribution Policy at <https://zeromq.org/how-to-contribute/>.\n"
  },
  {
    "path": "external/sha1/license.txt",
    "content": "Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n       notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n       notice, this list of conditions and the following disclaimer in the\n       documentation and/or other materials provided with the distribution.\n3. Neither the name of the project nor the names of its contributors\n       may be used to endorse or promote products derived from this software\n       without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.      IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\nOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n"
  },
  {
    "path": "external/sha1/sha1.c",
    "content": "/*\n * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *\t  notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *\t  notice, this list of conditions and the following disclaimer in the\n *\t  documentation and/or other materials provided with the distribution.\n * 3. Neither the name of the project nor the names of its contributors\n *\t  may be used to endorse or promote products derived from this software\n *\t  without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.\tIN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)\n * based on: http://www.itl.nist.gov/fipspubs/fip180-1.htm\n * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>\n */\n\n#include \"sha1.h\"\n#include <string.h>\n\n\n/* constant table */\nstatic uint32_t _K[] = {0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6};\n\n#define K(t)\t_K[(t) / 20]\n\n#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d)))\n#define F1(b, c, d) (((b) ^ (c)) ^ (d))\n#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))\n#define F3(b, c, d) (((b) ^ (c)) ^ (d))\n\n#define S(n, x)\t\t(((x) << (n)) | ((x) >> (32 - (n))))\n\n#define H(n)\t(ctxt->h.b32[(n)])\n#define COUNT\t(ctxt->count)\n#define BCOUNT\t(ctxt->c.b64[0] / 8)\n#define W(n)\t(ctxt->m.b32[(n)])\n\n#define PUTBYTE(x) \\\ndo { \\\n\tctxt->m.b8[(COUNT % 64)] = (x);\t\t\\\n\tCOUNT++;\t\t\t\t\\\n\tCOUNT %= 64;\t\t\t\t\\\n\tctxt->c.b64[0] += 8;\t\t\t\\\n\tif (COUNT % 64 == 0)\t\t\t\\\n\t\tsha1_step(ctxt);\t\t\\\n} while (0)\n\n#define PUTPAD(x) \\\ndo { \\\n\tctxt->m.b8[(COUNT % 64)] = (x);\t\t\\\n\tCOUNT++;\t\t\t\t\\\n\tCOUNT %= 64;\t\t\t\t\\\n\tif (COUNT % 64 == 0)\t\t\t\\\n\t\tsha1_step(ctxt);\t\t\\\n} while (0)\n\nstatic void sha1_step(struct sha1_ctxt *);\n\nstatic void\nsha1_step(struct sha1_ctxt * ctxt)\n{\n\tuint32_t\t\ta,\n\t\t\t\tb,\n\t\t\t\tc,\n\t\t\t\td,\n\t\t\t\te;\n\tsize_t\t\tt,\n\t\t\t\ts;\n\tuint32_t\t\ttmp;\n\n#ifndef WORDS_BIGENDIAN\n\tstruct sha1_ctxt tctxt;\n\n\tmemmove(&tctxt.m.b8[0], &ctxt->m.b8[0], 64);\n\tctxt->m.b8[0] = tctxt.m.b8[3];\n\tctxt->m.b8[1] = tctxt.m.b8[2];\n\tctxt->m.b8[2] = tctxt.m.b8[1];\n\tctxt->m.b8[3] = tctxt.m.b8[0];\n\tctxt->m.b8[4] = tctxt.m.b8[7];\n\tctxt->m.b8[5] = tctxt.m.b8[6];\n\tctxt->m.b8[6] = tctxt.m.b8[5];\n\tctxt->m.b8[7] = tctxt.m.b8[4];\n\tctxt->m.b8[8] = tctxt.m.b8[11];\n\tctxt->m.b8[9] = tctxt.m.b8[10];\n\tctxt->m.b8[10] = tctxt.m.b8[9];\n\tctxt->m.b8[11] = tctxt.m.b8[8];\n\tctxt->m.b8[12] = tctxt.m.b8[15];\n\tctxt->m.b8[13] = tctxt.m.b8[14];\n\tctxt->m.b8[14] = tctxt.m.b8[13];\n\tctxt->m.b8[15] = tctxt.m.b8[12];\n\tctxt->m.b8[16] = tctxt.m.b8[19];\n\tctxt->m.b8[17] = tctxt.m.b8[18];\n\tctxt->m.b8[18] = tctxt.m.b8[17];\n\tctxt->m.b8[19] = tctxt.m.b8[16];\n\tctxt->m.b8[20] = tctxt.m.b8[23];\n\tctxt->m.b8[21] = tctxt.m.b8[22];\n\tctxt->m.b8[22] = tctxt.m.b8[21];\n\tctxt->m.b8[23] = tctxt.m.b8[20];\n\tctxt->m.b8[24] = tctxt.m.b8[27];\n\tctxt->m.b8[25] = tctxt.m.b8[26];\n\tctxt->m.b8[26] = tctxt.m.b8[25];\n\tctxt->m.b8[27] = tctxt.m.b8[24];\n\tctxt->m.b8[28] = tctxt.m.b8[31];\n\tctxt->m.b8[29] = tctxt.m.b8[30];\n\tctxt->m.b8[30] = tctxt.m.b8[29];\n\tctxt->m.b8[31] = tctxt.m.b8[28];\n\tctxt->m.b8[32] = tctxt.m.b8[35];\n\tctxt->m.b8[33] = tctxt.m.b8[34];\n\tctxt->m.b8[34] = tctxt.m.b8[33];\n\tctxt->m.b8[35] = tctxt.m.b8[32];\n\tctxt->m.b8[36] = tctxt.m.b8[39];\n\tctxt->m.b8[37] = tctxt.m.b8[38];\n\tctxt->m.b8[38] = tctxt.m.b8[37];\n\tctxt->m.b8[39] = tctxt.m.b8[36];\n\tctxt->m.b8[40] = tctxt.m.b8[43];\n\tctxt->m.b8[41] = tctxt.m.b8[42];\n\tctxt->m.b8[42] = tctxt.m.b8[41];\n\tctxt->m.b8[43] = tctxt.m.b8[40];\n\tctxt->m.b8[44] = tctxt.m.b8[47];\n\tctxt->m.b8[45] = tctxt.m.b8[46];\n\tctxt->m.b8[46] = tctxt.m.b8[45];\n\tctxt->m.b8[47] = tctxt.m.b8[44];\n\tctxt->m.b8[48] = tctxt.m.b8[51];\n\tctxt->m.b8[49] = tctxt.m.b8[50];\n\tctxt->m.b8[50] = tctxt.m.b8[49];\n\tctxt->m.b8[51] = tctxt.m.b8[48];\n\tctxt->m.b8[52] = tctxt.m.b8[55];\n\tctxt->m.b8[53] = tctxt.m.b8[54];\n\tctxt->m.b8[54] = tctxt.m.b8[53];\n\tctxt->m.b8[55] = tctxt.m.b8[52];\n\tctxt->m.b8[56] = tctxt.m.b8[59];\n\tctxt->m.b8[57] = tctxt.m.b8[58];\n\tctxt->m.b8[58] = tctxt.m.b8[57];\n\tctxt->m.b8[59] = tctxt.m.b8[56];\n\tctxt->m.b8[60] = tctxt.m.b8[63];\n\tctxt->m.b8[61] = tctxt.m.b8[62];\n\tctxt->m.b8[62] = tctxt.m.b8[61];\n\tctxt->m.b8[63] = tctxt.m.b8[60];\n#endif\n\n\ta = H(0);\n\tb = H(1);\n\tc = H(2);\n\td = H(3);\n\te = H(4);\n\n\tfor (t = 0; t < 20; t++)\n\t{\n\t\ts = t & 0x0f;\n\t\tif (t >= 16)\n\t\t\tW(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s));\n\t\ttmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t);\n\t\te = d;\n\t\td = c;\n\t\tc = S(30, b);\n\t\tb = a;\n\t\ta = tmp;\n\t}\n\tfor (t = 20; t < 40; t++)\n\t{\n\t\ts = t & 0x0f;\n\t\tW(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s));\n\t\ttmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t);\n\t\te = d;\n\t\td = c;\n\t\tc = S(30, b);\n\t\tb = a;\n\t\ta = tmp;\n\t}\n\tfor (t = 40; t < 60; t++)\n\t{\n\t\ts = t & 0x0f;\n\t\tW(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s));\n\t\ttmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t);\n\t\te = d;\n\t\td = c;\n\t\tc = S(30, b);\n\t\tb = a;\n\t\ta = tmp;\n\t}\n\tfor (t = 60; t < 80; t++)\n\t{\n\t\ts = t & 0x0f;\n\t\tW(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s));\n\t\ttmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t);\n\t\te = d;\n\t\td = c;\n\t\tc = S(30, b);\n\t\tb = a;\n\t\ta = tmp;\n\t}\n\n\tH(0) = H(0) + a;\n\tH(1) = H(1) + b;\n\tH(2) = H(2) + c;\n\tH(3) = H(3) + d;\n\tH(4) = H(4) + e;\n\n\tmemset(&ctxt->m.b8[0], 0, 64);\n}\n\n/*------------------------------------------------------------*/\n\nvoid\nsha1_init(struct sha1_ctxt * ctxt)\n{\n\tmemset(ctxt, 0, sizeof(struct sha1_ctxt));\n\tH(0) = 0x67452301;\n\tH(1) = 0xefcdab89;\n\tH(2) = 0x98badcfe;\n\tH(3) = 0x10325476;\n\tH(4) = 0xc3d2e1f0;\n}\n\nvoid\nsha1_pad(struct sha1_ctxt * ctxt)\n{\n\tsize_t\t\tpadlen;\t\t\t/* pad length in bytes */\n\tsize_t\t\tpadstart;\n\n\tPUTPAD(0x80);\n\n\tpadstart = COUNT % 64;\n\tpadlen = 64 - padstart;\n\tif (padlen < 8)\n\t{\n\t\tmemset(&ctxt->m.b8[padstart], 0, padlen);\n\t\tCOUNT += (uint8_t) padlen;\n\t\tCOUNT %= 64;\n\t\tsha1_step(ctxt);\n\t\tpadstart = COUNT % 64;\t/* should be 0 */\n\t\tpadlen = 64 - padstart; /* should be 64 */\n\t}\n\tmemset(&ctxt->m.b8[padstart], 0, padlen - 8);\n    COUNT += ((uint8_t) padlen - 8);\n\tCOUNT %= 64;\n#ifdef WORDS_BIGENDIAN\n\tPUTPAD(ctxt->c.b8[0]);\n\tPUTPAD(ctxt->c.b8[1]);\n\tPUTPAD(ctxt->c.b8[2]);\n\tPUTPAD(ctxt->c.b8[3]);\n\tPUTPAD(ctxt->c.b8[4]);\n\tPUTPAD(ctxt->c.b8[5]);\n\tPUTPAD(ctxt->c.b8[6]);\n\tPUTPAD(ctxt->c.b8[7]);\n#else\n\tPUTPAD(ctxt->c.b8[7]);\n\tPUTPAD(ctxt->c.b8[6]);\n\tPUTPAD(ctxt->c.b8[5]);\n\tPUTPAD(ctxt->c.b8[4]);\n\tPUTPAD(ctxt->c.b8[3]);\n\tPUTPAD(ctxt->c.b8[2]);\n\tPUTPAD(ctxt->c.b8[1]);\n\tPUTPAD(ctxt->c.b8[0]);\n#endif\n}\n\nvoid\nsha1_loop(struct sha1_ctxt * ctxt, const uint8_t *input0, size_t len)\n{\n\tconst uint8_t *input;\n\tsize_t\t\tgaplen;\n\tsize_t\t\tgapstart;\n\tsize_t\t\toff;\n\tsize_t\t\tcopysiz;\n\n\tinput = (const uint8_t *) input0;\n\toff = 0;\n\n\twhile (off < len)\n\t{\n\t\tgapstart = COUNT % 64;\n\t\tgaplen = 64 - gapstart;\n\n\t\tcopysiz = (gaplen < len - off) ? gaplen : len - off;\n\t\tmemmove(&ctxt->m.b8[gapstart], &input[off], copysiz);\n\t\tCOUNT += (uint8_t) copysiz;\n\t\tCOUNT %= 64;\n\t\tctxt->c.b64[0] += copysiz * 8;\n\t\tif (COUNT % 64 == 0)\n\t\t\tsha1_step(ctxt);\n\t\toff += copysiz;\n\t}\n}\n\nvoid\nsha1_result(struct sha1_ctxt * ctxt, uint8_t *digest0)\n{\n\tuint8_t\t   *digest;\n\n\tdigest = (uint8_t *) digest0;\n\tsha1_pad(ctxt);\n#ifdef WORDS_BIGENDIAN\n\tmemmove(digest, &ctxt->h.b8[0], 20);\n#else\n\tdigest[0] = ctxt->h.b8[3];\n\tdigest[1] = ctxt->h.b8[2];\n\tdigest[2] = ctxt->h.b8[1];\n\tdigest[3] = ctxt->h.b8[0];\n\tdigest[4] = ctxt->h.b8[7];\n\tdigest[5] = ctxt->h.b8[6];\n\tdigest[6] = ctxt->h.b8[5];\n\tdigest[7] = ctxt->h.b8[4];\n\tdigest[8] = ctxt->h.b8[11];\n\tdigest[9] = ctxt->h.b8[10];\n\tdigest[10] = ctxt->h.b8[9];\n\tdigest[11] = ctxt->h.b8[8];\n\tdigest[12] = ctxt->h.b8[15];\n\tdigest[13] = ctxt->h.b8[14];\n\tdigest[14] = ctxt->h.b8[13];\n\tdigest[15] = ctxt->h.b8[12];\n\tdigest[16] = ctxt->h.b8[19];\n\tdigest[17] = ctxt->h.b8[18];\n\tdigest[18] = ctxt->h.b8[17];\n\tdigest[19] = ctxt->h.b8[16];\n#endif\n}"
  },
  {
    "path": "external/sha1/sha1.h",
    "content": "/*\tcontrib/pgcrypto/sha1.h */\n/*\t   $KAME: sha1.h,v 1.4 2000/02/22 14:01:18 itojun Exp $    */\n\n/*\n * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *\t  notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *\t  notice, this list of conditions and the following disclaimer in the\n *\t  documentation and/or other materials provided with the distribution.\n * 3. Neither the name of the project nor the names of its contributors\n *\t  may be used to endorse or promote products derived from this software\n *\t  without specific prior written permission.\n *\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.\tIN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n/*\n * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)\n * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * based on: http://www.itl.nist.gov/fipspubs/fip180-1.htm\n * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>\n */\n\n#ifndef _NETINET6_SHA1_H_\n#define _NETINET6_SHA1_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdlib.h>\n#include \"../../src/stdint.hpp\"\n\nstruct sha1_ctxt\n{\n\tunion\n\t{\n\t\tuint8_t\tb8[20];\n\t\tuint32_t b32[5];\n\t} h;\n\tunion\n\t{\n\t\tuint8_t b8[8];\n\t\tuint64_t b64[1];\n\t} c;\n\tunion\n\t{\n\t\tuint8_t b8[64];\n\t\tuint32_t b32[16];\n\t} m;\n\tuint8_t count;\n};\n\nvoid sha1_init(struct sha1_ctxt *);\nvoid sha1_pad(struct sha1_ctxt *);\nvoid sha1_loop(struct sha1_ctxt *, const uint8_t *, size_t);\nvoid sha1_result(struct sha1_ctxt *, uint8_t *);\n\n//  Compatibility with OpenSSL API\n#define SHA_DIGEST_LENGTH 20\ntypedef struct sha1_ctxt SHA_CTX;\n\n#define SHA1_Init(x)            sha1_init((x))\n#define SHA1_Update(x, y, z)    sha1_loop((x), (y), (z))\n#define SHA1_Final(x, y)        sha1_result((y), (x))\n\n#define SHA1_RESULTLEN\t(160/8)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif   /* _NETINET6_SHA1_H_ */\n"
  },
  {
    "path": "external/unity/license.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) <year> 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "external/unity/unity.c",
    "content": "/* =========================================================================\n    Unity Project - A Test Framework for C\n    Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams\n    [Released under MIT License. Please refer to license.txt for details]\n============================================================================ */\n\n#define UNITY_INCLUDE_SETUP_STUBS\n#include \"unity.h\"\n#include <stddef.h>\n\n/* If omitted from header, declare overrideable prototypes here so they're ready for use */\n#ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION\nvoid UNITY_OUTPUT_CHAR(int);\n#endif\n\n/* Helpful macros for us to use here in Assert functions */\n#define UNITY_FAIL_AND_BAIL   { Unity.CurrentTestFailed  = 1; TEST_ABORT(); }\n#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; TEST_ABORT(); }\n#define RETURN_IF_FAIL_OR_IGNORE if (Unity.CurrentTestFailed || Unity.CurrentTestIgnored) return\n\nstruct UNITY_STORAGE_T Unity;\n\n#ifdef UNITY_OUTPUT_COLOR\nstatic const char UnityStrOk[]                     = \"\\033[42mOK\\033[00m\";\nstatic const char UnityStrPass[]                   = \"\\033[42mPASS\\033[00m\";\nstatic const char UnityStrFail[]                   = \"\\033[41mFAIL\\033[00m\";\nstatic const char UnityStrIgnore[]                 = \"\\033[43mIGNORE\\033[00m\";\n#else\nstatic const char UnityStrOk[]                     = \"OK\";\nstatic const char UnityStrPass[]                   = \"PASS\";\nstatic const char UnityStrFail[]                   = \"FAIL\";\nstatic const char UnityStrIgnore[]                 = \"IGNORE\";\n#endif\nstatic const char UnityStrNull[]                   = \"NULL\";\nstatic const char UnityStrSpacer[]                 = \". \";\nstatic const char UnityStrExpected[]               = \" Expected \";\nstatic const char UnityStrWas[]                    = \" Was \";\nstatic const char UnityStrGt[]                     = \" to be greater than \";\nstatic const char UnityStrLt[]                     = \" to be less than \";\nstatic const char UnityStrOrEqual[]                = \"or equal to \";\nstatic const char UnityStrElement[]                = \" Element \";\nstatic const char UnityStrByte[]                   = \" Byte \";\nstatic const char UnityStrMemory[]                 = \" Memory Mismatch.\";\nstatic const char UnityStrDelta[]                  = \" Values Not Within Delta \";\nstatic const char UnityStrPointless[]              = \" You Asked Me To Compare Nothing, Which Was Pointless.\";\nstatic const char UnityStrNullPointerForExpected[] = \" Expected pointer to be NULL\";\nstatic const char UnityStrNullPointerForActual[]   = \" Actual pointer was NULL\";\n#ifndef UNITY_EXCLUDE_FLOAT\nstatic const char UnityStrNot[]                    = \"Not \";\nstatic const char UnityStrInf[]                    = \"Infinity\";\nstatic const char UnityStrNegInf[]                 = \"Negative Infinity\";\nstatic const char UnityStrNaN[]                    = \"NaN\";\nstatic const char UnityStrDet[]                    = \"Determinate\";\nstatic const char UnityStrInvalidFloatTrait[]      = \"Invalid Float Trait\";\n#endif\nconst char UnityStrErrFloat[]                      = \"Unity Floating Point Disabled\";\nconst char UnityStrErrDouble[]                     = \"Unity Double Precision Disabled\";\nconst char UnityStrErr64[]                         = \"Unity 64-bit Support Disabled\";\nstatic const char UnityStrBreaker[]                = \"-----------------------\";\nstatic const char UnityStrResultsTests[]           = \" Tests \";\nstatic const char UnityStrResultsFailures[]        = \" Failures \";\nstatic const char UnityStrResultsIgnored[]         = \" Ignored \";\nstatic const char UnityStrDetail1Name[]            = UNITY_DETAIL1_NAME \" \";\nstatic const char UnityStrDetail2Name[]            = \" \" UNITY_DETAIL2_NAME \" \";\n\n/*-----------------------------------------------\n * Pretty Printers & Test Result Output Handlers\n *-----------------------------------------------*/\n\nvoid UnityPrint(const char* string)\n{\n    const char* pch = string;\n\n    if (pch != NULL)\n    {\n        while (*pch)\n        {\n            /* printable characters plus CR & LF are printed */\n            if ((*pch <= 126) && (*pch >= 32))\n            {\n                UNITY_OUTPUT_CHAR(*pch);\n            }\n            /* write escaped carriage returns */\n            else if (*pch == 13)\n            {\n                UNITY_OUTPUT_CHAR('\\\\');\n                UNITY_OUTPUT_CHAR('r');\n            }\n            /* write escaped line feeds */\n            else if (*pch == 10)\n            {\n                UNITY_OUTPUT_CHAR('\\\\');\n                UNITY_OUTPUT_CHAR('n');\n            }\n#ifdef UNITY_OUTPUT_COLOR\n            /* print ANSI escape code */\n            else if (*pch == 27 && *(pch + 1) == '[')\n            {\n                while (*pch && *pch != 'm')\n                {\n                    UNITY_OUTPUT_CHAR(*pch);\n                    pch++;\n                }\n                UNITY_OUTPUT_CHAR('m');\n            }\n#endif\n            /* unprintable characters are shown as codes */\n            else\n            {\n                UNITY_OUTPUT_CHAR('\\\\');\n                UNITY_OUTPUT_CHAR('x');\n                UnityPrintNumberHex((UNITY_UINT)*pch, 2);\n            }\n            pch++;\n        }\n    }\n}\n\nvoid UnityPrintLen(const char* string, const UNITY_UINT32 length)\n{\n    const char* pch = string;\n\n    if (pch != NULL)\n    {\n        while (*pch && (UNITY_UINT32)(pch - string) < length)\n        {\n            /* printable characters plus CR & LF are printed */\n            if ((*pch <= 126) && (*pch >= 32))\n            {\n                UNITY_OUTPUT_CHAR(*pch);\n            }\n            /* write escaped carriage returns */\n            else if (*pch == 13)\n            {\n                UNITY_OUTPUT_CHAR('\\\\');\n                UNITY_OUTPUT_CHAR('r');\n            }\n            /* write escaped line feeds */\n            else if (*pch == 10)\n            {\n                UNITY_OUTPUT_CHAR('\\\\');\n                UNITY_OUTPUT_CHAR('n');\n            }\n            /* unprintable characters are shown as codes */\n            else\n            {\n                UNITY_OUTPUT_CHAR('\\\\');\n                UNITY_OUTPUT_CHAR('x');\n                UnityPrintNumberHex((UNITY_UINT)*pch, 2);\n            }\n            pch++;\n        }\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style)\n{\n    if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT)\n    {\n        UnityPrintNumber(number);\n    }\n    else if ((style & UNITY_DISPLAY_RANGE_UINT) == UNITY_DISPLAY_RANGE_UINT)\n    {\n        UnityPrintNumberUnsigned((UNITY_UINT)number);\n    }\n    else\n    {\n        UNITY_OUTPUT_CHAR('0');\n        UNITY_OUTPUT_CHAR('x');\n        UnityPrintNumberHex((UNITY_UINT)number, (char)((style & 0xF) * 2));\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityPrintNumber(const UNITY_INT number_to_print)\n{\n    UNITY_UINT number = (UNITY_UINT)number_to_print;\n\n    if (number_to_print < 0)\n    {\n        /* A negative number, including MIN negative */\n        UNITY_OUTPUT_CHAR('-');\n        number = (UNITY_UINT)(-number_to_print);\n    }\n    UnityPrintNumberUnsigned(number);\n}\n\n/*-----------------------------------------------\n * basically do an itoa using as little ram as possible */\nvoid UnityPrintNumberUnsigned(const UNITY_UINT number)\n{\n    UNITY_UINT divisor = 1;\n\n    /* figure out initial divisor */\n    while (number / divisor > 9)\n    {\n        divisor *= 10;\n    }\n\n    /* now mod and print, then divide divisor */\n    do\n    {\n        UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10)));\n        divisor /= 10;\n    } while (divisor > 0);\n}\n\n/*-----------------------------------------------*/\nvoid UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print)\n{\n    int nibble;\n    char nibbles = nibbles_to_print;\n    if ((unsigned)nibbles > (2 * sizeof(number)))\n        nibbles = 2 * sizeof(number);\n\n    while (nibbles > 0)\n    {\n        nibbles--;\n        nibble = (int)(number >> (nibbles * 4)) & 0x0F;\n        if (nibble <= 9)\n        {\n            UNITY_OUTPUT_CHAR((char)('0' + nibble));\n        }\n        else\n        {\n            UNITY_OUTPUT_CHAR((char)('A' - 10 + nibble));\n        }\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number)\n{\n    UNITY_UINT current_bit = (UNITY_UINT)1 << (UNITY_INT_WIDTH - 1);\n    UNITY_INT32 i;\n\n    for (i = 0; i < UNITY_INT_WIDTH; i++)\n    {\n        if (current_bit & mask)\n        {\n            if (current_bit & number)\n            {\n                UNITY_OUTPUT_CHAR('1');\n            }\n            else\n            {\n                UNITY_OUTPUT_CHAR('0');\n            }\n        }\n        else\n        {\n            UNITY_OUTPUT_CHAR('X');\n        }\n        current_bit = current_bit >> 1;\n    }\n}\n\n/*-----------------------------------------------*/\n#ifndef UNITY_EXCLUDE_FLOAT_PRINT\n/* This function prints a floating-point value in a format similar to\n * printf(\"%.6g\").  It can work with either single- or double-precision,\n * but for simplicity, it prints only 6 significant digits in either case.\n * Printing more than 6 digits accurately is hard (at least in the single-\n * precision case) and isn't attempted here. */\nvoid UnityPrintFloat(const UNITY_DOUBLE input_number)\n{\n    UNITY_DOUBLE number = input_number;\n\n    /* print minus sign (including for negative zero) */\n    if (number < 0.0f || (number == 0.0f && 1.0f / number < 0.0f))\n    {\n        UNITY_OUTPUT_CHAR('-');\n        number = -number;\n    }\n\n    /* handle zero, NaN, and +/- infinity */\n    if (number == 0.0f) UnityPrint(\"0\");\n    else if (isnan(number)) UnityPrint(\"nan\");\n    else if (isinf(number)) UnityPrint(\"inf\");\n    else\n    {\n        int exponent = 0;\n        int decimals, digits;\n        UNITY_INT32 n;\n        char buf[16];\n\n        /* scale up or down by powers of 10 */\n        while (number < 100000.0f / 1e6f)  { number *= 1e6f; exponent -= 6; }\n        while (number < 100000.0f)         { number *= 10.0f; exponent--; }\n        while (number > 1000000.0f * 1e6f) { number /= 1e6f; exponent += 6; }\n        while (number > 1000000.0f)        { number /= 10.0f; exponent++; }\n\n        /* round to nearest integer */\n        n = ((UNITY_INT32)(number + number) + 1) / 2;\n        if (n > 999999)\n        {\n            n = 100000;\n            exponent++;\n        }\n\n        /* determine where to place decimal point */\n        decimals = (exponent <= 0 && exponent >= -9) ? -exponent : 5;\n        exponent += decimals;\n\n        /* truncate trailing zeroes after decimal point */\n        while (decimals > 0 && n % 10 == 0)\n        {\n            n /= 10;\n            decimals--;\n        }\n\n        /* build up buffer in reverse order */\n        digits = 0;\n        while (n != 0 || digits < decimals + 1)\n        {\n            buf[digits++] = (char)('0' + n % 10);\n            n /= 10;\n        }\n        while (digits > 0)\n        {\n            if(digits == decimals) UNITY_OUTPUT_CHAR('.');\n            UNITY_OUTPUT_CHAR(buf[--digits]);\n        }\n\n        /* print exponent if needed */\n        if (exponent != 0)\n        {\n            UNITY_OUTPUT_CHAR('e');\n\n            if(exponent < 0)\n            {\n                UNITY_OUTPUT_CHAR('-');\n                exponent = -exponent;\n            }\n            else\n            {\n                UNITY_OUTPUT_CHAR('+');\n            }\n\n            digits = 0;\n            while (exponent != 0 || digits < 2)\n            {\n                buf[digits++] = (char)('0' + exponent % 10);\n                exponent /= 10;\n            }\n            while (digits > 0)\n            {\n                UNITY_OUTPUT_CHAR(buf[--digits]);\n            }\n        }\n    }\n}\n#endif /* ! UNITY_EXCLUDE_FLOAT_PRINT */\n\n/*-----------------------------------------------*/\nstatic void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line)\n{\n    UnityPrint(file);\n    UNITY_OUTPUT_CHAR(':');\n    UnityPrintNumber((UNITY_INT)line);\n    UNITY_OUTPUT_CHAR(':');\n    UnityPrint(Unity.CurrentTestName);\n    UNITY_OUTPUT_CHAR(':');\n}\n\n/*-----------------------------------------------*/\nstatic void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line)\n{\n    UnityTestResultsBegin(Unity.TestFile, line);\n    UnityPrint(UnityStrFail);\n    UNITY_OUTPUT_CHAR(':');\n}\n\n/*-----------------------------------------------*/\nvoid UnityConcludeTest(void)\n{\n    if (Unity.CurrentTestIgnored)\n    {\n        Unity.TestIgnores++;\n    }\n    else if (!Unity.CurrentTestFailed)\n    {\n        UnityTestResultsBegin(Unity.TestFile, Unity.CurrentTestLineNumber);\n        UnityPrint(UnityStrPass);\n    }\n    else\n    {\n        Unity.TestFailures++;\n    }\n\n    Unity.CurrentTestFailed = 0;\n    Unity.CurrentTestIgnored = 0;\n    UNITY_PRINT_EOL();\n    UNITY_FLUSH_CALL();\n}\n\n/*-----------------------------------------------*/\nstatic void UnityAddMsgIfSpecified(const char* msg)\n{\n    if (msg)\n    {\n        UnityPrint(UnityStrSpacer);\n#ifndef UNITY_EXCLUDE_DETAILS\n        if (Unity.CurrentDetail1)\n        {\n            UnityPrint(UnityStrDetail1Name);\n            UnityPrint(Unity.CurrentDetail1);\n            if (Unity.CurrentDetail2)\n            {\n                UnityPrint(UnityStrDetail2Name);\n                UnityPrint(Unity.CurrentDetail2);\n            }\n            UnityPrint(UnityStrSpacer);\n        }\n#endif\n        UnityPrint(msg);\n    }\n}\n\n/*-----------------------------------------------*/\nstatic void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual)\n{\n    UnityPrint(UnityStrExpected);\n    if (expected != NULL)\n    {\n        UNITY_OUTPUT_CHAR('\\'');\n        UnityPrint(expected);\n        UNITY_OUTPUT_CHAR('\\'');\n    }\n    else\n    {\n        UnityPrint(UnityStrNull);\n    }\n    UnityPrint(UnityStrWas);\n    if (actual != NULL)\n    {\n        UNITY_OUTPUT_CHAR('\\'');\n        UnityPrint(actual);\n        UNITY_OUTPUT_CHAR('\\'');\n    }\n    else\n    {\n        UnityPrint(UnityStrNull);\n    }\n}\n\n/*-----------------------------------------------*/\nstatic void UnityPrintExpectedAndActualStringsLen(const char* expected,\n                                                  const char* actual,\n                                                  const UNITY_UINT32 length)\n{\n    UnityPrint(UnityStrExpected);\n    if (expected != NULL)\n    {\n        UNITY_OUTPUT_CHAR('\\'');\n        UnityPrintLen(expected, length);\n        UNITY_OUTPUT_CHAR('\\'');\n    }\n    else\n    {\n        UnityPrint(UnityStrNull);\n    }\n    UnityPrint(UnityStrWas);\n    if (actual != NULL)\n    {\n        UNITY_OUTPUT_CHAR('\\'');\n        UnityPrintLen(actual, length);\n        UNITY_OUTPUT_CHAR('\\'');\n    }\n    else\n    {\n        UnityPrint(UnityStrNull);\n    }\n}\n\n/*-----------------------------------------------\n * Assertion & Control Helpers\n *-----------------------------------------------*/\n\nstatic int UnityIsOneArrayNull(UNITY_INTERNAL_PTR expected,\n                               UNITY_INTERNAL_PTR actual,\n                               const UNITY_LINE_TYPE lineNumber,\n                               const char* msg)\n{\n    if (expected == actual) return 0; /* Both are NULL or same pointer */\n\n    /* print and return true if just expected is NULL */\n    if (expected == NULL)\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UnityPrint(UnityStrNullPointerForExpected);\n        UnityAddMsgIfSpecified(msg);\n        return 1;\n    }\n\n    /* print and return true if just actual is NULL */\n    if (actual == NULL)\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UnityPrint(UnityStrNullPointerForActual);\n        UnityAddMsgIfSpecified(msg);\n        return 1;\n    }\n\n    return 0; /* return false if neither is NULL */\n}\n\n/*-----------------------------------------------\n * Assertion Functions\n *-----------------------------------------------*/\n\nvoid UnityAssertBits(const UNITY_INT mask,\n                     const UNITY_INT expected,\n                     const UNITY_INT actual,\n                     const char* msg,\n                     const UNITY_LINE_TYPE lineNumber)\n{\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    if ((mask & expected) != (mask & actual))\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UnityPrint(UnityStrExpected);\n        UnityPrintMask((UNITY_UINT)mask, (UNITY_UINT)expected);\n        UnityPrint(UnityStrWas);\n        UnityPrintMask((UNITY_UINT)mask, (UNITY_UINT)actual);\n        UnityAddMsgIfSpecified(msg);\n        UNITY_FAIL_AND_BAIL;\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityAssertEqualNumber(const UNITY_INT expected,\n                            const UNITY_INT actual,\n                            const char* msg,\n                            const UNITY_LINE_TYPE lineNumber,\n                            const UNITY_DISPLAY_STYLE_T style)\n{\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    if (expected != actual)\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UnityPrint(UnityStrExpected);\n        UnityPrintNumberByStyle(expected, style);\n        UnityPrint(UnityStrWas);\n        UnityPrintNumberByStyle(actual, style);\n        UnityAddMsgIfSpecified(msg);\n        UNITY_FAIL_AND_BAIL;\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold,\n                                           const UNITY_INT actual,\n                                           const UNITY_COMPARISON_T compare,\n                                           const char *msg,\n                                           const UNITY_LINE_TYPE lineNumber,\n                                           const UNITY_DISPLAY_STYLE_T style)\n{\n    int failed = 0;\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    if (threshold == actual && compare & UNITY_EQUAL_TO) return;\n    if (threshold == actual) failed = 1;\n\n    if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT)\n    {\n        if (actual > threshold && compare & UNITY_SMALLER_THAN) failed = 1;\n        if (actual < threshold && compare & UNITY_GREATER_THAN) failed = 1;\n    }\n    else /* UINT or HEX */\n    {\n        if ((UNITY_UINT)actual > (UNITY_UINT)threshold && compare & UNITY_SMALLER_THAN) failed = 1;\n        if ((UNITY_UINT)actual < (UNITY_UINT)threshold && compare & UNITY_GREATER_THAN) failed = 1;\n    }\n\n    if (failed)\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UnityPrint(UnityStrExpected);\n        UnityPrintNumberByStyle(actual, style);\n        if (compare & UNITY_GREATER_THAN) UnityPrint(UnityStrGt);\n        if (compare & UNITY_SMALLER_THAN) UnityPrint(UnityStrLt);\n        if (compare & UNITY_EQUAL_TO)     UnityPrint(UnityStrOrEqual);\n        UnityPrintNumberByStyle(threshold, style);\n        UnityAddMsgIfSpecified(msg);\n        UNITY_FAIL_AND_BAIL;\n    }\n}\n\n#define UnityPrintPointlessAndBail()       \\\n{                                          \\\n    UnityTestResultsFailBegin(lineNumber); \\\n    UnityPrint(UnityStrPointless);         \\\n    UnityAddMsgIfSpecified(msg);           \\\n    UNITY_FAIL_AND_BAIL; }\n\n/*-----------------------------------------------*/\nvoid UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected,\n                              UNITY_INTERNAL_PTR actual,\n                              const UNITY_UINT32 num_elements,\n                              const char* msg,\n                              const UNITY_LINE_TYPE lineNumber,\n                              const UNITY_DISPLAY_STYLE_T style,\n                              const UNITY_FLAGS_T flags)\n{\n    UNITY_UINT32 elements = num_elements;\n    unsigned int length   = style & 0xF;\n\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    if (num_elements == 0)\n    {\n        UnityPrintPointlessAndBail();\n    }\n\n    if (expected == actual) return; /* Both are NULL or same pointer */\n    if (UnityIsOneArrayNull(expected, actual, lineNumber, msg))\n        UNITY_FAIL_AND_BAIL;\n\n    while ((elements > 0) && elements--)\n    {\n        UNITY_INT expect_val;\n        UNITY_INT actual_val;\n        switch (length)\n        {\n            case 1:\n                expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected;\n                actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual;\n                break;\n            case 2:\n                expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected;\n                actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual;\n                break;\n#ifdef UNITY_SUPPORT_64\n            case 8:\n                expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)expected;\n                actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)actual;\n                break;\n#endif\n            default: /* length 4 bytes */\n                expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected;\n                actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual;\n                length = 4;\n                break;\n        }\n\n        if (expect_val != actual_val)\n        {\n            if (style & UNITY_DISPLAY_RANGE_UINT && length < sizeof(expect_val))\n            {   /* For UINT, remove sign extension (padding 1's) from signed type casts above */\n                UNITY_INT mask = 1;\n                mask = (mask << 8 * length) - 1;\n                expect_val &= mask;\n                actual_val &= mask;\n            }\n            UnityTestResultsFailBegin(lineNumber);\n            UnityPrint(UnityStrElement);\n            UnityPrintNumberUnsigned(num_elements - elements - 1);\n            UnityPrint(UnityStrExpected);\n            UnityPrintNumberByStyle(expect_val, style);\n            UnityPrint(UnityStrWas);\n            UnityPrintNumberByStyle(actual_val, style);\n            UnityAddMsgIfSpecified(msg);\n            UNITY_FAIL_AND_BAIL;\n        }\n        if (flags == UNITY_ARRAY_TO_ARRAY)\n        {\n            expected = (UNITY_INTERNAL_PTR)(length + (const char*)expected);\n        }\n        actual   = (UNITY_INTERNAL_PTR)(length + (const char*)actual);\n    }\n}\n\n/*-----------------------------------------------*/\n#ifndef UNITY_EXCLUDE_FLOAT\n/* Wrap this define in a function with variable types as float or double */\n#define UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff)                       \\\n    if (isinf(expected) && isinf(actual) && ((expected < 0) == (actual < 0))) return 1;   \\\n    if (UNITY_NAN_CHECK) return 1;                                                        \\\n    diff = actual - expected;                                                             \\\n    if (diff < 0) diff = -diff;                                                           \\\n    if (delta < 0) delta = -delta;                                                        \\\n    return !(isnan(diff) || isinf(diff) || (diff > delta))\n    /* This first part of this condition will catch any NaN or Infinite values */\n#ifndef UNITY_NAN_NOT_EQUAL_NAN\n  #define UNITY_NAN_CHECK isnan(expected) && isnan(actual)\n#else\n  #define UNITY_NAN_CHECK 0\n#endif\n\n#ifndef UNITY_EXCLUDE_FLOAT_PRINT\n  #define UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual) \\\n  {                                                               \\\n    UnityPrint(UnityStrExpected);                                 \\\n    UnityPrintFloat(expected);                                    \\\n    UnityPrint(UnityStrWas);                                      \\\n    UnityPrintFloat(actual); }\n#else\n  #define UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual) \\\n    UnityPrint(UnityStrDelta)\n#endif /* UNITY_EXCLUDE_FLOAT_PRINT */\n\nstatic int UnityFloatsWithin(UNITY_FLOAT delta, UNITY_FLOAT expected, UNITY_FLOAT actual)\n{\n    UNITY_FLOAT diff;\n    UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff);\n}\n\nvoid UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected,\n                                UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* actual,\n                                const UNITY_UINT32 num_elements,\n                                const char* msg,\n                                const UNITY_LINE_TYPE lineNumber,\n                                const UNITY_FLAGS_T flags)\n{\n    UNITY_UINT32 elements = num_elements;\n    UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_expected = expected;\n    UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_actual = actual;\n\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    if (elements == 0)\n    {\n        UnityPrintPointlessAndBail();\n    }\n\n    if (expected == actual) return; /* Both are NULL or same pointer */\n    if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg))\n        UNITY_FAIL_AND_BAIL;\n\n    while (elements--)\n    {\n        if (!UnityFloatsWithin(*ptr_expected * UNITY_FLOAT_PRECISION, *ptr_expected, *ptr_actual))\n        {\n            UnityTestResultsFailBegin(lineNumber);\n            UnityPrint(UnityStrElement);\n            UnityPrintNumberUnsigned(num_elements - elements - 1);\n            UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)*ptr_expected, (UNITY_DOUBLE)*ptr_actual);\n            UnityAddMsgIfSpecified(msg);\n            UNITY_FAIL_AND_BAIL;\n        }\n        if (flags == UNITY_ARRAY_TO_ARRAY)\n        {\n            ptr_expected++;\n        }\n        ptr_actual++;\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityAssertFloatsWithin(const UNITY_FLOAT delta,\n                             const UNITY_FLOAT expected,\n                             const UNITY_FLOAT actual,\n                             const char* msg,\n                             const UNITY_LINE_TYPE lineNumber)\n{\n    RETURN_IF_FAIL_OR_IGNORE;\n\n\n    if (!UnityFloatsWithin(delta, expected, actual))\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual);\n        UnityAddMsgIfSpecified(msg);\n        UNITY_FAIL_AND_BAIL;\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityAssertFloatSpecial(const UNITY_FLOAT actual,\n                             const char* msg,\n                             const UNITY_LINE_TYPE lineNumber,\n                             const UNITY_FLOAT_TRAIT_T style)\n{\n    const char* trait_names[] = {UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet};\n    UNITY_INT should_be_trait = ((UNITY_INT)style & 1);\n    UNITY_INT is_trait        = !should_be_trait;\n    UNITY_INT trait_index     = (UNITY_INT)(style >> 1);\n\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    switch (style)\n    {\n        case UNITY_FLOAT_IS_INF:\n        case UNITY_FLOAT_IS_NOT_INF:\n            is_trait = isinf(actual) && (actual > 0);\n            break;\n        case UNITY_FLOAT_IS_NEG_INF:\n        case UNITY_FLOAT_IS_NOT_NEG_INF:\n            is_trait = isinf(actual) && (actual < 0);\n            break;\n\n        case UNITY_FLOAT_IS_NAN:\n        case UNITY_FLOAT_IS_NOT_NAN:\n            is_trait = isnan(actual) ? 1 : 0;\n            break;\n\n        case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */\n        case UNITY_FLOAT_IS_NOT_DET:\n            is_trait = !isinf(actual) && !isnan(actual);\n            break;\n\n        default:\n            trait_index = 0;\n            trait_names[0] = UnityStrInvalidFloatTrait;\n            break;\n    }\n\n    if (is_trait != should_be_trait)\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UnityPrint(UnityStrExpected);\n        if (!should_be_trait)\n            UnityPrint(UnityStrNot);\n        UnityPrint(trait_names[trait_index]);\n        UnityPrint(UnityStrWas);\n#ifndef UNITY_EXCLUDE_FLOAT_PRINT\n        UnityPrintFloat((UNITY_DOUBLE)actual);\n#else\n        if (should_be_trait)\n            UnityPrint(UnityStrNot);\n        UnityPrint(trait_names[trait_index]);\n#endif\n        UnityAddMsgIfSpecified(msg);\n        UNITY_FAIL_AND_BAIL;\n    }\n}\n\n#endif /* not UNITY_EXCLUDE_FLOAT */\n\n/*-----------------------------------------------*/\n#ifndef UNITY_EXCLUDE_DOUBLE\nstatic int UnityDoublesWithin(UNITY_DOUBLE delta, UNITY_DOUBLE expected, UNITY_DOUBLE actual)\n{\n    UNITY_DOUBLE diff;\n    UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff);\n}\n\nvoid UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected,\n                                 UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual,\n                                 const UNITY_UINT32 num_elements,\n                                 const char* msg,\n                                 const UNITY_LINE_TYPE lineNumber,\n                                 const UNITY_FLAGS_T flags)\n{\n    UNITY_UINT32 elements = num_elements;\n    UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_expected = expected;\n    UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_actual = actual;\n\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    if (elements == 0)\n    {\n        UnityPrintPointlessAndBail();\n    }\n\n    if (expected == actual) return; /* Both are NULL or same pointer */\n    if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg))\n        UNITY_FAIL_AND_BAIL;\n\n    while (elements--)\n    {\n        if (!UnityDoublesWithin(*ptr_expected * UNITY_DOUBLE_PRECISION, *ptr_expected, *ptr_actual))\n        {\n            UnityTestResultsFailBegin(lineNumber);\n            UnityPrint(UnityStrElement);\n            UnityPrintNumberUnsigned(num_elements - elements - 1);\n            UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(*ptr_expected, *ptr_actual);\n            UnityAddMsgIfSpecified(msg);\n            UNITY_FAIL_AND_BAIL;\n        }\n        if (flags == UNITY_ARRAY_TO_ARRAY)\n        {\n            ptr_expected++;\n        }\n        ptr_actual++;\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityAssertDoublesWithin(const UNITY_DOUBLE delta,\n                              const UNITY_DOUBLE expected,\n                              const UNITY_DOUBLE actual,\n                              const char* msg,\n                              const UNITY_LINE_TYPE lineNumber)\n{\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    if (!UnityDoublesWithin(delta, expected, actual))\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual);\n        UnityAddMsgIfSpecified(msg);\n        UNITY_FAIL_AND_BAIL;\n    }\n}\n\n/*-----------------------------------------------*/\n\nvoid UnityAssertDoubleSpecial(const UNITY_DOUBLE actual,\n                              const char* msg,\n                              const UNITY_LINE_TYPE lineNumber,\n                              const UNITY_FLOAT_TRAIT_T style)\n{\n    const char* trait_names[] = {UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet};\n    UNITY_INT should_be_trait = ((UNITY_INT)style & 1);\n    UNITY_INT is_trait        = !should_be_trait;\n    UNITY_INT trait_index     = (UNITY_INT)(style >> 1);\n\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    switch (style)\n    {\n        case UNITY_FLOAT_IS_INF:\n        case UNITY_FLOAT_IS_NOT_INF:\n            is_trait = isinf(actual) && (actual > 0);\n            break;\n        case UNITY_FLOAT_IS_NEG_INF:\n        case UNITY_FLOAT_IS_NOT_NEG_INF:\n            is_trait = isinf(actual) && (actual < 0);\n            break;\n\n        case UNITY_FLOAT_IS_NAN:\n        case UNITY_FLOAT_IS_NOT_NAN:\n            is_trait = isnan(actual) ? 1 : 0;\n            break;\n\n        case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */\n        case UNITY_FLOAT_IS_NOT_DET:\n            is_trait = !isinf(actual) && !isnan(actual);\n            break;\n\n        default:\n            trait_index = 0;\n            trait_names[0] = UnityStrInvalidFloatTrait;\n            break;\n    }\n\n    if (is_trait != should_be_trait)\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UnityPrint(UnityStrExpected);\n        if (!should_be_trait)\n            UnityPrint(UnityStrNot);\n        UnityPrint(trait_names[trait_index]);\n        UnityPrint(UnityStrWas);\n#ifndef UNITY_EXCLUDE_FLOAT_PRINT\n        UnityPrintFloat(actual);\n#else\n        if (should_be_trait)\n            UnityPrint(UnityStrNot);\n        UnityPrint(trait_names[trait_index]);\n#endif\n        UnityAddMsgIfSpecified(msg);\n        UNITY_FAIL_AND_BAIL;\n    }\n}\n\n#endif /* not UNITY_EXCLUDE_DOUBLE */\n\n/*-----------------------------------------------*/\nvoid UnityAssertNumbersWithin(const UNITY_UINT delta,\n                              const UNITY_INT expected,\n                              const UNITY_INT actual,\n                              const char* msg,\n                              const UNITY_LINE_TYPE lineNumber,\n                              const UNITY_DISPLAY_STYLE_T style)\n{\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT)\n    {\n        if (actual > expected)\n          Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(actual - expected) > delta);\n        else\n            Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(expected - actual) > delta);\n    }\n    else\n    {\n        if ((UNITY_UINT)actual > (UNITY_UINT)expected)\n            Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(actual - expected) > delta);\n        else\n            Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(expected - actual) > delta);\n    }\n\n    if (Unity.CurrentTestFailed)\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UnityPrint(UnityStrDelta);\n        UnityPrintNumberByStyle((UNITY_INT)delta, style);\n        UnityPrint(UnityStrExpected);\n        UnityPrintNumberByStyle(expected, style);\n        UnityPrint(UnityStrWas);\n        UnityPrintNumberByStyle(actual, style);\n        UnityAddMsgIfSpecified(msg);\n        UNITY_FAIL_AND_BAIL;\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityAssertEqualString(const char* expected,\n                            const char* actual,\n                            const char* msg,\n                            const UNITY_LINE_TYPE lineNumber)\n{\n    UNITY_UINT32 i;\n\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    /* if both pointers not null compare the strings */\n    if (expected && actual)\n    {\n        for (i = 0; expected[i] || actual[i]; i++)\n        {\n            if (expected[i] != actual[i])\n            {\n                Unity.CurrentTestFailed = 1;\n                break;\n            }\n        }\n    }\n    else\n    { /* handle case of one pointers being null (if both null, test should pass) */\n        if (expected != actual)\n        {\n            Unity.CurrentTestFailed = 1;\n        }\n    }\n\n    if (Unity.CurrentTestFailed)\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UnityPrintExpectedAndActualStrings(expected, actual);\n        UnityAddMsgIfSpecified(msg);\n        UNITY_FAIL_AND_BAIL;\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityAssertEqualStringLen(const char* expected,\n                               const char* actual,\n                               const UNITY_UINT32 length,\n                               const char* msg,\n                               const UNITY_LINE_TYPE lineNumber)\n{\n    UNITY_UINT32 i;\n\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    /* if both pointers not null compare the strings */\n    if (expected && actual)\n    {\n        for (i = 0; (i < length) && (expected[i] || actual[i]); i++)\n        {\n            if (expected[i] != actual[i])\n            {\n                Unity.CurrentTestFailed = 1;\n                break;\n            }\n        }\n    }\n    else\n    { /* handle case of one pointers being null (if both null, test should pass) */\n        if (expected != actual)\n        {\n            Unity.CurrentTestFailed = 1;\n        }\n    }\n\n    if (Unity.CurrentTestFailed)\n    {\n        UnityTestResultsFailBegin(lineNumber);\n        UnityPrintExpectedAndActualStringsLen(expected, actual, length);\n        UnityAddMsgIfSpecified(msg);\n        UNITY_FAIL_AND_BAIL;\n    }\n}\n\n/*-----------------------------------------------*/\nvoid UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected,\n                                 const char** actual,\n                                 const UNITY_UINT32 num_elements,\n                                 const char* msg,\n                                 const UNITY_LINE_TYPE lineNumber,\n                                 const UNITY_FLAGS_T flags)\n{\n    UNITY_UINT32 i = 0;\n    UNITY_UINT32 j = 0;\n    const char* expd = NULL;\n    const char* act = NULL;\n\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    /* if no elements, it's an error */\n    if (num_elements == 0)\n    {\n        UnityPrintPointlessAndBail();\n    }\n\n    if ((const void*)expected == (const void*)actual)\n    {\n        return; /* Both are NULL or same pointer */\n    }\n\n    if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg))\n    {\n        UNITY_FAIL_AND_BAIL;\n    }\n\n    if (flags != UNITY_ARRAY_TO_ARRAY)\n    {\n        expd = (const char*)expected;\n    }\n\n    do\n    {\n        act = actual[j];\n        if (flags == UNITY_ARRAY_TO_ARRAY)\n        {\n            expd = ((const char* const*)expected)[j];\n        }\n\n        /* if both pointers not null compare the strings */\n        if (expd && act)\n        {\n            for (i = 0; expd[i] || act[i]; i++)\n            {\n                if (expd[i] != act[i])\n                {\n                    Unity.CurrentTestFailed = 1;\n                    break;\n                }\n            }\n        }\n        else\n        { /* handle case of one pointers being null (if both null, test should pass) */\n            if (expd != act)\n            {\n                Unity.CurrentTestFailed = 1;\n            }\n        }\n\n        if (Unity.CurrentTestFailed)\n        {\n            UnityTestResultsFailBegin(lineNumber);\n            if (num_elements > 1)\n            {\n                UnityPrint(UnityStrElement);\n                UnityPrintNumberUnsigned(j);\n            }\n            UnityPrintExpectedAndActualStrings(expd, act);\n            UnityAddMsgIfSpecified(msg);\n            UNITY_FAIL_AND_BAIL;\n        }\n    } while (++j < num_elements);\n}\n\n/*-----------------------------------------------*/\nvoid UnityAssertEqualMemory(UNITY_INTERNAL_PTR expected,\n                            UNITY_INTERNAL_PTR actual,\n                            const UNITY_UINT32 length,\n                            const UNITY_UINT32 num_elements,\n                            const char* msg,\n                            const UNITY_LINE_TYPE lineNumber,\n                            const UNITY_FLAGS_T flags)\n{\n    UNITY_PTR_ATTRIBUTE const unsigned char* ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected;\n    UNITY_PTR_ATTRIBUTE const unsigned char* ptr_act = (UNITY_PTR_ATTRIBUTE const unsigned char*)actual;\n    UNITY_UINT32 elements = num_elements;\n    UNITY_UINT32 bytes;\n\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    if ((elements == 0) || (length == 0))\n    {\n        UnityPrintPointlessAndBail();\n    }\n\n    if (expected == actual) return; /* Both are NULL or same pointer */\n    if (UnityIsOneArrayNull(expected, actual, lineNumber, msg))\n        UNITY_FAIL_AND_BAIL;\n\n    while (elements--)\n    {\n        bytes = length;\n        while (bytes--)\n        {\n            if (*ptr_exp != *ptr_act)\n            {\n                UnityTestResultsFailBegin(lineNumber);\n                UnityPrint(UnityStrMemory);\n                if (num_elements > 1)\n                {\n                    UnityPrint(UnityStrElement);\n                    UnityPrintNumberUnsigned(num_elements - elements - 1);\n                }\n                UnityPrint(UnityStrByte);\n                UnityPrintNumberUnsigned(length - bytes - 1);\n                UnityPrint(UnityStrExpected);\n                UnityPrintNumberByStyle(*ptr_exp, UNITY_DISPLAY_STYLE_HEX8);\n                UnityPrint(UnityStrWas);\n                UnityPrintNumberByStyle(*ptr_act, UNITY_DISPLAY_STYLE_HEX8);\n                UnityAddMsgIfSpecified(msg);\n                UNITY_FAIL_AND_BAIL;\n            }\n            ptr_exp++;\n            ptr_act++;\n        }\n        if (flags == UNITY_ARRAY_TO_VAL)\n        {\n            ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected;\n        }\n    }\n}\n\n/*-----------------------------------------------*/\n\nstatic union\n{\n    UNITY_INT8 i8;\n    UNITY_INT16 i16;\n    UNITY_INT32 i32;\n#ifdef UNITY_SUPPORT_64\n    UNITY_INT64 i64;\n#endif\n#ifndef UNITY_EXCLUDE_FLOAT\n    float f;\n#endif\n#ifndef UNITY_EXCLUDE_DOUBLE\n    double d;\n#endif\n} UnityQuickCompare;\n\nUNITY_INTERNAL_PTR UnityNumToPtr(const UNITY_INT num, const UNITY_UINT8 size)\n{\n    switch(size)\n    {\n        case 1:\n          UnityQuickCompare.i8 = (UNITY_INT8)num;\n          return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i8);\n\n        case 2:\n          UnityQuickCompare.i16 = (UNITY_INT16)num;\n          return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i16);\n\n#ifdef UNITY_SUPPORT_64\n        case 8:\n          UnityQuickCompare.i64 = (UNITY_INT64)num;\n          return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i64);\n#endif\n        default: /* 4 bytes */\n          UnityQuickCompare.i32 = (UNITY_INT32)num;\n          return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i32);\n    }\n}\n\n#ifndef UNITY_EXCLUDE_FLOAT\nUNITY_INTERNAL_PTR UnityFloatToPtr(const float num)\n{\n    UnityQuickCompare.f = num;\n    return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.f);\n}\n#endif\n\n#ifndef UNITY_EXCLUDE_DOUBLE\nUNITY_INTERNAL_PTR UnityDoubleToPtr(const double num)\n{\n    UnityQuickCompare.d = num;\n    return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.d);\n}\n#endif\n\n/*-----------------------------------------------\n * Control Functions\n *-----------------------------------------------*/\n\nvoid UnityFail(const char* msg, const UNITY_LINE_TYPE line)\n{\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    UnityTestResultsBegin(Unity.TestFile, line);\n    UnityPrint(UnityStrFail);\n    if (msg != NULL)\n    {\n        UNITY_OUTPUT_CHAR(':');\n\n#ifndef UNITY_EXCLUDE_DETAILS\n        if (Unity.CurrentDetail1)\n        {\n            UnityPrint(UnityStrDetail1Name);\n            UnityPrint(Unity.CurrentDetail1);\n            if (Unity.CurrentDetail2)\n            {\n                UnityPrint(UnityStrDetail2Name);\n                UnityPrint(Unity.CurrentDetail2);\n            }\n            UnityPrint(UnityStrSpacer);\n        }\n#endif\n        if (msg[0] != ' ')\n        {\n            UNITY_OUTPUT_CHAR(' ');\n        }\n        UnityPrint(msg);\n    }\n\n    UNITY_FAIL_AND_BAIL;\n}\n\n/*-----------------------------------------------*/\nvoid UnityIgnore(const char* msg, const UNITY_LINE_TYPE line)\n{\n    RETURN_IF_FAIL_OR_IGNORE;\n\n    UnityTestResultsBegin(Unity.TestFile, line);\n    UnityPrint(UnityStrIgnore);\n    if (msg != NULL)\n    {\n        UNITY_OUTPUT_CHAR(':');\n        UNITY_OUTPUT_CHAR(' ');\n        UnityPrint(msg);\n    }\n    UNITY_IGNORE_AND_BAIL;\n}\n\n/*-----------------------------------------------*/\nvoid UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum)\n{\n    Unity.CurrentTestName = FuncName;\n    Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum;\n    Unity.NumberOfTests++;\n    UNITY_CLR_DETAILS();\n    if (TEST_PROTECT())\n    {\n        setUp();\n        Func();\n    }\n    if (TEST_PROTECT())\n    {\n        tearDown();\n    }\n    UnityConcludeTest();\n}\n\n/*-----------------------------------------------*/\nvoid UnityBegin(const char* filename)\n{\n    Unity.TestFile = filename;\n    Unity.CurrentTestName = NULL;\n    Unity.CurrentTestLineNumber = 0;\n    Unity.NumberOfTests = 0;\n    Unity.TestFailures = 0;\n    Unity.TestIgnores = 0;\n    Unity.CurrentTestFailed = 0;\n    Unity.CurrentTestIgnored = 0;\n\n    UNITY_CLR_DETAILS();\n    UNITY_OUTPUT_START();\n}\n\n/*-----------------------------------------------*/\nint UnityEnd(void)\n{\n    UNITY_PRINT_EOL();\n    UnityPrint(UnityStrBreaker);\n    UNITY_PRINT_EOL();\n    UnityPrintNumber((UNITY_INT)(Unity.NumberOfTests));\n    UnityPrint(UnityStrResultsTests);\n    UnityPrintNumber((UNITY_INT)(Unity.TestFailures));\n    UnityPrint(UnityStrResultsFailures);\n    UnityPrintNumber((UNITY_INT)(Unity.TestIgnores));\n    UnityPrint(UnityStrResultsIgnored);\n    UNITY_PRINT_EOL();\n    if (Unity.TestFailures == 0U)\n    {\n        UnityPrint(UnityStrOk);\n    }\n    else\n    {\n        UnityPrint(UnityStrFail);\n#ifdef UNITY_DIFFERENTIATE_FINAL_FAIL\n        UNITY_OUTPUT_CHAR('E'); UNITY_OUTPUT_CHAR('D');\n#endif\n    }\n    UNITY_PRINT_EOL();\n    UNITY_FLUSH_CALL();\n    UNITY_OUTPUT_COMPLETE();\n    return (int)(Unity.TestFailures);\n}\n\n/*-----------------------------------------------\n * Command Line Argument Support\n *-----------------------------------------------*/\n#ifdef UNITY_USE_COMMAND_LINE_ARGS\n\nchar* UnityOptionIncludeNamed = NULL;\nchar* UnityOptionExcludeNamed = NULL;\nint UnityVerbosity            = 1;\n\nint UnityParseOptions(int argc, char** argv)\n{\n    UnityOptionIncludeNamed = NULL;\n    UnityOptionExcludeNamed = NULL;\n\n    for (int i = 1; i < argc; i++)\n    {\n        if (argv[i][0] == '-')\n        {\n            switch (argv[i][1])\n            {\n                case 'l': /* list tests */\n                    return -1;\n                case 'n': /* include tests with name including this string */\n                case 'f': /* an alias for -n */\n                    if (argv[i][2] == '=')\n                        UnityOptionIncludeNamed = &argv[i][3];\n                    else if (++i < argc)\n                        UnityOptionIncludeNamed = argv[i];\n                    else\n                    {\n                        UnityPrint(\"ERROR: No Test String to Include Matches For\");\n                        UNITY_PRINT_EOL();\n                        return 1;\n                    }\n                    break;\n                case 'q': /* quiet */\n                    UnityVerbosity = 0;\n                    break;\n                case 'v': /* verbose */\n                    UnityVerbosity = 2;\n                    break;\n                case 'x': /* exclude tests with name including this string */\n                    if (argv[i][2] == '=')\n                        UnityOptionExcludeNamed = &argv[i][3];\n                    else if (++i < argc)\n                        UnityOptionExcludeNamed = argv[i];\n                    else\n                    {\n                        UnityPrint(\"ERROR: No Test String to Exclude Matches For\");\n                        UNITY_PRINT_EOL();\n                        return 1;\n                    }\n                    break;\n                default:\n                    UnityPrint(\"ERROR: Unknown Option \");\n                    UNITY_OUTPUT_CHAR(argv[i][1]);\n                    UNITY_PRINT_EOL();\n                    return 1;\n            }\n        }\n    }\n\n    return 0;\n}\n\nint IsStringInBiggerString(const char* longstring, const char* shortstring)\n{\n    const char* lptr = longstring;\n    const char* sptr = shortstring;\n    const char* lnext = lptr;\n\n    if (*sptr == '*')\n        return 1;\n\n    while (*lptr)\n    {\n        lnext = lptr + 1;\n\n        /* If they current bytes match, go on to the next bytes */\n        while (*lptr && *sptr && (*lptr == *sptr))\n        {\n            lptr++;\n            sptr++;\n\n            /* We're done if we match the entire string or up to a wildcard */\n            if (*sptr == '*')\n                return 1;\n            if (*sptr == ',')\n                return 1;\n            if (*sptr == '\"')\n                return 1;\n            if (*sptr == '\\'')\n                return 1;\n            if (*sptr == ':')\n                return 2;\n            if (*sptr == 0)\n                return 1;\n        }\n\n        /* Otherwise we start in the long pointer 1 character further and try again */\n        lptr = lnext;\n        sptr = shortstring;\n    }\n    return 0;\n}\n\nint UnityStringArgumentMatches(const char* str)\n{\n    int retval;\n    const char* ptr1;\n    const char* ptr2;\n    const char* ptrf;\n\n    /* Go through the options and get the substrings for matching one at a time */\n    ptr1 = str;\n    while (ptr1[0] != 0)\n    {\n        if ((ptr1[0] == '\"') || (ptr1[0] == '\\''))\n            ptr1++;\n\n        /* look for the start of the next partial */\n        ptr2 = ptr1;\n        ptrf = 0;\n        do\n        {\n            ptr2++;\n            if ((ptr2[0] == ':') && (ptr2[1] != 0) && (ptr2[0] != '\\'') && (ptr2[0] != '\"') && (ptr2[0] != ','))\n                ptrf = &ptr2[1];\n        } while ((ptr2[0] != 0) && (ptr2[0] != '\\'') && (ptr2[0] != '\"') && (ptr2[0] != ','));\n        while ((ptr2[0] != 0) && ((ptr2[0] == ':') || (ptr2[0] == '\\'') || (ptr2[0] == '\"') || (ptr2[0] == ',')))\n            ptr2++;\n\n        /* done if complete filename match */\n        retval = IsStringInBiggerString(Unity.TestFile, ptr1);\n        if (retval == 1)\n            return retval;\n\n        /* done if testname match after filename partial match */\n        if ((retval == 2) && (ptrf != 0))\n        {\n            if (IsStringInBiggerString(Unity.CurrentTestName, ptrf))\n                return 1;\n        }\n\n        /* done if complete testname match */\n        if (IsStringInBiggerString(Unity.CurrentTestName, ptr1) == 1)\n            return 1;\n\n        ptr1 = ptr2;\n    }\n\n    /* we couldn't find a match for any substrings */\n    return 0;\n}\n\nint UnityTestMatches(void)\n{\n    /* Check if this test name matches the included test pattern */\n    int retval;\n    if (UnityOptionIncludeNamed)\n    {\n        retval = UnityStringArgumentMatches(UnityOptionIncludeNamed);\n    }\n    else\n        retval = 1;\n\n    /* Check if this test name matches the excluded test pattern */\n    if (UnityOptionExcludeNamed)\n    {\n        if (UnityStringArgumentMatches(UnityOptionExcludeNamed))\n            retval = 0;\n    }\n    return retval;\n}\n\n#endif /* UNITY_USE_COMMAND_LINE_ARGS */\n/*-----------------------------------------------*/\n"
  },
  {
    "path": "external/unity/unity.h",
    "content": "/* ==========================================\n    Unity Project - A Test Framework for C\n    Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams\n    [Released under MIT License. Please refer to license.txt for details]\n========================================== */\n\n#ifndef UNITY_FRAMEWORK_H\n#define UNITY_FRAMEWORK_H\n#define UNITY\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n#include \"unity_internals.h\"\n\n/*-------------------------------------------------------\n * Test Setup / Teardown\n *-------------------------------------------------------*/\n\n/* These functions are intended to be called before and after each test. */\nvoid setUp(void);\nvoid tearDown(void);\n\n/* These functions are intended to be called at the beginning and end of an\n * entire test suite.  suiteTearDown() is passed the number of tests that\n * failed, and its return value becomes the exit code of main(). */\nvoid suiteSetUp(void);\nint suiteTearDown(int num_failures);\n\n/* If the compiler supports it, the following block provides stub\n * implementations of the above functions as weak symbols.  Note that on\n * some platforms (MinGW for example), weak function implementations need\n * to be in the same translation unit they are called from.  This can be\n * achieved by defining UNITY_INCLUDE_SETUP_STUBS before including unity.h. */\n#ifdef UNITY_INCLUDE_SETUP_STUBS\n  #ifdef UNITY_WEAK_ATTRIBUTE\n    UNITY_WEAK_ATTRIBUTE void setUp(void) { }\n    UNITY_WEAK_ATTRIBUTE void tearDown(void) { }\n    UNITY_WEAK_ATTRIBUTE void suiteSetUp(void) { }\n    UNITY_WEAK_ATTRIBUTE int suiteTearDown(int num_failures) { return num_failures; }\n  #elif defined(UNITY_WEAK_PRAGMA)\n    #pragma weak setUp\n    void setUp(void) { }\n    #pragma weak tearDown\n    void tearDown(void) { }\n    #pragma weak suiteSetUp\n    void suiteSetUp(void) { }\n    #pragma weak suiteTearDown\n    int suiteTearDown(int num_failures) { return num_failures; }\n  #endif\n#endif\n\n/*-------------------------------------------------------\n * Configuration Options\n *-------------------------------------------------------\n * All options described below should be passed as a compiler flag to all files using Unity. If you must add #defines, place them BEFORE the #include above.\n\n * Integers/longs/pointers\n *     - Unity attempts to automatically discover your integer sizes\n *       - define UNITY_EXCLUDE_STDINT_H to stop attempting to look in <stdint.h>\n *       - define UNITY_EXCLUDE_LIMITS_H to stop attempting to look in <limits.h>\n *     - If you cannot use the automatic methods above, you can force Unity by using these options:\n *       - define UNITY_SUPPORT_64\n *       - set UNITY_INT_WIDTH\n *       - set UNITY_LONG_WIDTH\n *       - set UNITY_POINTER_WIDTH\n\n * Floats\n *     - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons\n *     - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT\n *     - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats\n *     - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons\n *     - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default)\n *     - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE\n *     - define UNITY_DOUBLE_TYPE to specify something other than double\n *     - define UNITY_EXCLUDE_FLOAT_PRINT to trim binary size, won't print floating point values in errors\n\n * Output\n *     - by default, Unity prints to standard out with putchar.  define UNITY_OUTPUT_CHAR(a) with a different function if desired\n *     - define UNITY_DIFFERENTIATE_FINAL_FAIL to print FAILED (vs. FAIL) at test end summary - for automated search for failure\n\n * Optimization\n *     - by default, line numbers are stored in unsigned shorts.  Define UNITY_LINE_TYPE with a different type if your files are huge\n *     - by default, test and failure counters are unsigned shorts.  Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests.\n\n * Test Cases\n *     - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script\n\n * Parameterized Tests\n *     - you'll want to create a define of TEST_CASE(...) which basically evaluates to nothing\n\n * Tests with Arguments\n *     - you'll want to define UNITY_USE_COMMAND_LINE_ARGS if you have the test runner passing arguments to Unity\n\n *-------------------------------------------------------\n * Basic Fail and Ignore\n *-------------------------------------------------------*/\n\n#define TEST_FAIL_MESSAGE(message)                                                                 UNITY_TEST_FAIL(__LINE__, (message))\n#define TEST_FAIL()                                                                                UNITY_TEST_FAIL(__LINE__, NULL)\n#define TEST_IGNORE_MESSAGE(message)                                                               UNITY_TEST_IGNORE(__LINE__, (message))\n#define TEST_IGNORE()                                                                              UNITY_TEST_IGNORE(__LINE__, NULL)\n#define TEST_ONLY()\n\n/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails.\n * This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */\n#define TEST_PASS()                                                                                TEST_ABORT()\n\n/* This macro does nothing, but it is useful for build tools (like Ceedling) to make use of this to figure out\n * which files should be linked to in order to perform a test. Use it like TEST_FILE(\"sandwiches.c\") */\n#define TEST_FILE(a)\n\n/*-------------------------------------------------------\n * Test Asserts (simple)\n *-------------------------------------------------------*/\n\n/* Boolean */\n#define TEST_ASSERT(condition)                                                                     UNITY_TEST_ASSERT(       (condition), __LINE__, \" Expression Evaluated To FALSE\")\n#define TEST_ASSERT_TRUE(condition)                                                                UNITY_TEST_ASSERT(       (condition), __LINE__, \" Expected TRUE Was FALSE\")\n#define TEST_ASSERT_UNLESS(condition)                                                              UNITY_TEST_ASSERT(      !(condition), __LINE__, \" Expression Evaluated To TRUE\")\n#define TEST_ASSERT_FALSE(condition)                                                               UNITY_TEST_ASSERT(      !(condition), __LINE__, \" Expected FALSE Was TRUE\")\n#define TEST_ASSERT_NULL(pointer)                                                                  UNITY_TEST_ASSERT_NULL(    (pointer), __LINE__, \" Expected NULL\")\n#define TEST_ASSERT_NOT_NULL(pointer)                                                              UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, \" Expected Non-NULL\")\n\n/* Integers (of all sizes) */\n#define TEST_ASSERT_EQUAL_INT(expected, actual)                                                    UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_INT8(expected, actual)                                                   UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_INT16(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_INT32(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_INT64(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL(expected, actual)                                                        UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_NOT_EQUAL(expected, actual)                                                    UNITY_TEST_ASSERT(((expected) !=  (actual)), __LINE__, \" Expected Not-Equal\")\n#define TEST_ASSERT_EQUAL_UINT(expected, actual)                                                   UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_UINT8(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_UINT16(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_UINT32(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_UINT64(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_HEX(expected, actual)                                                    UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_HEX8(expected, actual)                                                   UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_HEX16(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_HEX32(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_HEX64(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_BITS(mask, expected, actual)                                                   UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_BITS_HIGH(mask, actual)                                                        UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(-1), (actual), __LINE__, NULL)\n#define TEST_ASSERT_BITS_LOW(mask, actual)                                                         UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(0), (actual), __LINE__, NULL)\n#define TEST_ASSERT_BIT_HIGH(bit, actual)                                                          UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, NULL)\n#define TEST_ASSERT_BIT_LOW(bit, actual)                                                           UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, NULL)\n\n/* Integer Greater Than/ Less Than (of all sizes) */\n#define TEST_ASSERT_GREATER_THAN(threshold, actual)                                                UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_INT(threshold, actual)                                            UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_INT8(threshold, actual)                                           UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_INT16(threshold, actual)                                          UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_INT32(threshold, actual)                                          UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_INT64(threshold, actual)                                          UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_UINT(threshold, actual)                                           UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual)                                          UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual)                                         UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual)                                         UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual)                                         UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual)                                           UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual)                                          UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual)                                          UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual)                                          UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, NULL)\n\n#define TEST_ASSERT_LESS_THAN(threshold, actual)                                                   UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_INT(threshold, actual)                                               UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_INT8(threshold, actual)                                              UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_INT16(threshold, actual)                                             UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_INT32(threshold, actual)                                             UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_INT64(threshold, actual)                                             UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_UINT(threshold, actual)                                              UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_UINT8(threshold, actual)                                             UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_UINT16(threshold, actual)                                            UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_UINT32(threshold, actual)                                            UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual)                                            UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual)                                              UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_HEX16(threshold, actual)                                             UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_HEX32(threshold, actual)                                             UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_THAN_HEX64(threshold, actual)                                             UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, NULL)\n\n#define TEST_ASSERT_GREATER_OR_EQUAL(threshold, actual)                                            UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual)                                        UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual)                                       UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual)                                      UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual)                                      UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual)                                      UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual)                                       UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual)                                      UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual)                                     UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual)                                     UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual)                                     UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual)                                       UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual)                                      UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual)                                      UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual)                                      UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL)\n\n#define TEST_ASSERT_LESS_OR_EQUAL(threshold, actual)                                               UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_INT(threshold, actual)                                           UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_INT8(threshold, actual)                                          UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_INT16(threshold, actual)                                         UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_INT32(threshold, actual)                                         UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_INT64(threshold, actual)                                         UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_UINT(threshold, actual)                                          UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_UINT8(threshold, actual)                                         UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_UINT16(threshold, actual)                                        UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_UINT32(threshold, actual)                                        UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_UINT64(threshold, actual)                                        UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_HEX8(threshold, actual)                                          UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_HEX16(threshold, actual)                                         UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_HEX32(threshold, actual)                                         UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL)\n#define TEST_ASSERT_LESS_OR_EQUAL_HEX64(threshold, actual)                                         UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL)\n\n/* Integer Ranges (of all sizes) */\n#define TEST_ASSERT_INT_WITHIN(delta, expected, actual)                                            UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_INT8_WITHIN(delta, expected, actual)                                           UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_INT16_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_INT32_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_INT64_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual)                                           UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_UINT8_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual)                                         UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual)                                         UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual)                                         UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual)                                            UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual)                                           UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n\n/* Structs and Strings */\n#define TEST_ASSERT_EQUAL_PTR(expected, actual)                                                    UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_STRING(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len)                                        UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len)                                            UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, NULL)\n\n/* Arrays */\n#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements)                        UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL)\n\n/* Arrays Compared To Single Value */\n#define TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements)                                 UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_INT16((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_INT32((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_INT64((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_UINT8((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_HEX(expected, actual, num_elements)                                 UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_HEX64((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements)                                 UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements)                         UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, NULL)\n\n/* Floating Point (If Enabled) */\n#define TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_FLOAT(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_FLOAT_IS_INF(actual)                                                           UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, NULL)\n#define TEST_ASSERT_FLOAT_IS_NEG_INF(actual)                                                       UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, NULL)\n#define TEST_ASSERT_FLOAT_IS_NAN(actual)                                                           UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, NULL)\n#define TEST_ASSERT_FLOAT_IS_DETERMINATE(actual)                                                   UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, NULL)\n#define TEST_ASSERT_FLOAT_IS_NOT_INF(actual)                                                       UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, NULL)\n#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual)                                                   UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, NULL)\n#define TEST_ASSERT_FLOAT_IS_NOT_NAN(actual)                                                       UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, NULL)\n#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual)                                               UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, NULL)\n\n/* Double (If Enabled) */\n#define TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual)                                         UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_DOUBLE(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, NULL)\n#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE((expected), (actual), (num_elements), __LINE__, NULL)\n#define TEST_ASSERT_DOUBLE_IS_INF(actual)                                                          UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, NULL)\n#define TEST_ASSERT_DOUBLE_IS_NEG_INF(actual)                                                      UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, NULL)\n#define TEST_ASSERT_DOUBLE_IS_NAN(actual)                                                          UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, NULL)\n#define TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual)                                                  UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, NULL)\n#define TEST_ASSERT_DOUBLE_IS_NOT_INF(actual)                                                      UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, NULL)\n#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual)                                                  UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, NULL)\n#define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual)                                                      UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, NULL)\n#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual)                                              UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, NULL)\n\n/*-------------------------------------------------------\n * Test Asserts (with additional messages)\n *-------------------------------------------------------*/\n\n/* Boolean */\n#define TEST_ASSERT_MESSAGE(condition, message)                                                    UNITY_TEST_ASSERT(       (condition), __LINE__, (message))\n#define TEST_ASSERT_TRUE_MESSAGE(condition, message)                                               UNITY_TEST_ASSERT(       (condition), __LINE__, (message))\n#define TEST_ASSERT_UNLESS_MESSAGE(condition, message)                                             UNITY_TEST_ASSERT(      !(condition), __LINE__, (message))\n#define TEST_ASSERT_FALSE_MESSAGE(condition, message)                                              UNITY_TEST_ASSERT(      !(condition), __LINE__, (message))\n#define TEST_ASSERT_NULL_MESSAGE(pointer, message)                                                 UNITY_TEST_ASSERT_NULL(    (pointer), __LINE__, (message))\n#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message)                                             UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message))\n\n/* Integers (of all sizes) */\n#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message)                                   UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message)                                  UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message)                                       UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message)                                   UNITY_TEST_ASSERT(((expected) !=  (actual)), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message)                                  UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message)                                   UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message)                                  UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message)                                  UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message)                                       UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(-1), (actual), __LINE__, (message))\n#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message)                                        UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(0), (actual), __LINE__, (message))\n#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message)                                         UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, (message))\n#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message)                                          UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, (message))\n\n/* Integer Greater Than/ Less Than (of all sizes) */\n#define TEST_ASSERT_GREATER_THAN_MESSAGE(threshold, actual, message)                               UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(threshold, actual, message)                           UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_INT8_MESSAGE(threshold, actual, message)                          UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_INT16_MESSAGE(threshold, actual, message)                         UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_INT32_MESSAGE(threshold, actual, message)                         UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_INT64_MESSAGE(threshold, actual, message)                         UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_UINT_MESSAGE(threshold, actual, message)                          UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_UINT8_MESSAGE(threshold, actual, message)                         UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_UINT16_MESSAGE(threshold, actual, message)                        UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(threshold, actual, message)                        UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_UINT64_MESSAGE(threshold, actual, message)                        UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_HEX8_MESSAGE(threshold, actual, message)                          UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_HEX16_MESSAGE(threshold, actual, message)                         UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_HEX32_MESSAGE(threshold, actual, message)                         UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_THAN_HEX64_MESSAGE(threshold, actual, message)                         UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, (message))\n\n#define TEST_ASSERT_LESS_THAN_MESSAGE(threshold, actual, message)                                  UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_INT_MESSAGE(threshold, actual, message)                              UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_INT8_MESSAGE(threshold, actual, message)                             UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_INT16_MESSAGE(threshold, actual, message)                            UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_INT32_MESSAGE(threshold, actual, message)                            UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_INT64_MESSAGE(threshold, actual, message)                            UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_UINT_MESSAGE(threshold, actual, message)                             UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_UINT8_MESSAGE(threshold, actual, message)                            UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_UINT16_MESSAGE(threshold, actual, message)                           UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_UINT32_MESSAGE(threshold, actual, message)                           UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_UINT64_MESSAGE(threshold, actual, message)                           UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_HEX8_MESSAGE(threshold, actual, message)                             UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_HEX16_MESSAGE(threshold, actual, message)                            UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_HEX32_MESSAGE(threshold, actual, message)                            UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_THAN_HEX64_MESSAGE(threshold, actual, message)                            UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message))\n\n#define TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(threshold, actual, message)                           UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(threshold, actual, message)                       UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_INT8_MESSAGE(threshold, actual, message)                      UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_INT16_MESSAGE(threshold, actual, message)                     UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_INT32_MESSAGE(threshold, actual, message)                     UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_INT64_MESSAGE(threshold, actual, message)                     UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_UINT_MESSAGE(threshold, actual, message)                      UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message)                     UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message)                    UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message)                    UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message)                    UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message)                      UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message)                     UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message)                     UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message)                     UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message))\n\n#define TEST_ASSERT_LESS_OR_EQUAL_MESSAGE(threshold, actual, message)                              UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_INT_MESSAGE(threshold, actual, message)                          UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_INT8_MESSAGE(threshold, actual, message)                         UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_INT16_MESSAGE(threshold, actual, message)                        UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_INT32_MESSAGE(threshold, actual, message)                        UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_INT64_MESSAGE(threshold, actual, message)                        UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_UINT_MESSAGE(threshold, actual, message)                         UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message)                        UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message)                       UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message)                       UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message)                       UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message)                         UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message)                        UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message)                        UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message))\n#define TEST_ASSERT_LESS_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message)                        UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message))\n\n/* Integer Ranges (of all sizes) */\n#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message)                           UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message)                          UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_INT16_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_INT32_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_INT64_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message)                          UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_UINT8_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message)                        UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message)                        UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message)                        UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message)                           UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message)                          UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, (message))\n\n/* Structs and Strings */\n#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message)                                   UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message)                       UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message)                           UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, (message))\n\n/* Arrays */\n#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE(expected, actual, len, num_elements, message)       UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, (message))\n\n/* Arrays Compared To Single Value*/\n#define TEST_ASSERT_EACH_EQUAL_INT_MESSAGE(expected, actual, num_elements, message)                UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_INT8_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_INT16_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_INT16((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_INT32_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_INT32((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_INT64_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_INT64((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_UINT_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_UINT8_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_UINT8((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_UINT32_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_UINT64_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE(expected, actual, num_elements, message)                UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_HEX8_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_HEX16_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_HEX64_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_HEX64((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_PTR_MESSAGE(expected, actual, num_elements, message)                UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_STRING_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_MEMORY_MESSAGE(expected, actual, len, num_elements, message)        UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, (message))\n\n/* Floating Point (If Enabled) */\n#define TEST_ASSERT_FLOAT_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_FLOAT_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_FLOAT_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_FLOAT_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_FLOAT_IS_INF_MESSAGE(actual, message)                                          UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, (message))\n#define TEST_ASSERT_FLOAT_IS_NEG_INF_MESSAGE(actual, message)                                      UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, (message))\n#define TEST_ASSERT_FLOAT_IS_NAN_MESSAGE(actual, message)                                          UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, (message))\n#define TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(actual, message)                                  UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, (message))\n#define TEST_ASSERT_FLOAT_IS_NOT_INF_MESSAGE(actual, message)                                      UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, (message))\n#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF_MESSAGE(actual, message)                                  UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, (message))\n#define TEST_ASSERT_FLOAT_IS_NOT_NAN_MESSAGE(actual, message)                                      UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, (message))\n#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE_MESSAGE(actual, message)                              UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, (message))\n\n/* Double (If Enabled) */\n#define TEST_ASSERT_DOUBLE_WITHIN_MESSAGE(delta, expected, actual, message)                        UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_DOUBLE_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, (message))\n#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_EACH_EQUAL_DOUBLE_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE((expected), (actual), (num_elements), __LINE__, (message))\n#define TEST_ASSERT_DOUBLE_IS_INF_MESSAGE(actual, message)                                         UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, (message))\n#define TEST_ASSERT_DOUBLE_IS_NEG_INF_MESSAGE(actual, message)                                     UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, (message))\n#define TEST_ASSERT_DOUBLE_IS_NAN_MESSAGE(actual, message)                                         UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, (message))\n#define TEST_ASSERT_DOUBLE_IS_DETERMINATE_MESSAGE(actual, message)                                 UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, (message))\n#define TEST_ASSERT_DOUBLE_IS_NOT_INF_MESSAGE(actual, message)                                     UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, (message))\n#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF_MESSAGE(actual, message)                                 UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, (message))\n#define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message)                                     UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message))\n#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message)                             UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message))\n\n/* end of UNITY_FRAMEWORK_H */\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "external/unity/unity_internals.h",
    "content": "/* ==========================================\n    Unity Project - A Test Framework for C\n    Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams\n    [Released under MIT License. Please refer to license.txt for details]\n========================================== */\n\n#ifndef UNITY_INTERNALS_H\n#define UNITY_INTERNALS_H\n\n#ifdef UNITY_INCLUDE_CONFIG_H\n#include \"unity_config.h\"\n#endif\n\n#ifndef UNITY_EXCLUDE_SETJMP_H\n#include <setjmp.h>\n#endif\n\n#ifndef UNITY_EXCLUDE_MATH_H\n#include <math.h>\n#endif\n\n/* Unity Attempts to Auto-Detect Integer Types\n * Attempt 1: UINT_MAX, ULONG_MAX in <limits.h>, or default to 32 bits\n * Attempt 2: UINTPTR_MAX in <stdint.h>, or default to same size as long\n * The user may override any of these derived constants:\n * UNITY_INT_WIDTH, UNITY_LONG_WIDTH, UNITY_POINTER_WIDTH */\n#ifndef UNITY_EXCLUDE_STDINT_H\n#include <stdint.h>\n#endif\n\n#ifndef UNITY_EXCLUDE_LIMITS_H\n#include <limits.h>\n#endif\n\n/*-------------------------------------------------------\n * Guess Widths If Not Specified\n *-------------------------------------------------------*/\n\n/* Determine the size of an int, if not already specified.\n * We cannot use sizeof(int), because it is not yet defined\n * at this stage in the translation of the C program.\n * Therefore, infer it from UINT_MAX if possible. */\n#ifndef UNITY_INT_WIDTH\n  #ifdef UINT_MAX\n    #if (UINT_MAX == 0xFFFF)\n      #define UNITY_INT_WIDTH (16)\n    #elif (UINT_MAX == 0xFFFFFFFF)\n      #define UNITY_INT_WIDTH (32)\n    #elif (UINT_MAX == 0xFFFFFFFFFFFFFFFF)\n      #define UNITY_INT_WIDTH (64)\n    #endif\n  #else /* Set to default */\n    #define UNITY_INT_WIDTH (32)\n  #endif /* UINT_MAX */\n#endif\n\n/* Determine the size of a long, if not already specified. */\n#ifndef UNITY_LONG_WIDTH\n  #ifdef ULONG_MAX\n    #if (ULONG_MAX == 0xFFFF)\n      #define UNITY_LONG_WIDTH (16)\n    #elif (ULONG_MAX == 0xFFFFFFFF)\n      #define UNITY_LONG_WIDTH (32)\n    #elif (ULONG_MAX == 0xFFFFFFFFFFFFFFFF)\n      #define UNITY_LONG_WIDTH (64)\n    #endif\n  #else /* Set to default */\n    #define UNITY_LONG_WIDTH (32)\n  #endif /* ULONG_MAX */\n#endif\n\n/* Determine the size of a pointer, if not already specified. */\n#ifndef UNITY_POINTER_WIDTH\n  #ifdef UINTPTR_MAX\n    #if (UINTPTR_MAX <= 0xFFFF)\n      #define UNITY_POINTER_WIDTH (16)\n    #elif (UINTPTR_MAX <= 0xFFFFFFFF)\n      #define UNITY_POINTER_WIDTH (32)\n    #elif (UINTPTR_MAX <= 0xFFFFFFFFFFFFFFFF)\n      #define UNITY_POINTER_WIDTH (64)\n    #endif\n  #else /* Set to default */\n    #define UNITY_POINTER_WIDTH UNITY_LONG_WIDTH\n  #endif /* UINTPTR_MAX */\n#endif\n\n/*-------------------------------------------------------\n * Int Support (Define types based on detected sizes)\n *-------------------------------------------------------*/\n\n#if (UNITY_INT_WIDTH == 32)\n    typedef unsigned char   UNITY_UINT8;\n    typedef unsigned short  UNITY_UINT16;\n    typedef unsigned int    UNITY_UINT32;\n    typedef signed char     UNITY_INT8;\n    typedef signed short    UNITY_INT16;\n    typedef signed int      UNITY_INT32;\n#elif (UNITY_INT_WIDTH == 16)\n    typedef unsigned char   UNITY_UINT8;\n    typedef unsigned int    UNITY_UINT16;\n    typedef unsigned long   UNITY_UINT32;\n    typedef signed char     UNITY_INT8;\n    typedef signed int      UNITY_INT16;\n    typedef signed long     UNITY_INT32;\n#else\n    #error Invalid UNITY_INT_WIDTH specified! (16 or 32 are supported)\n#endif\n\n/*-------------------------------------------------------\n * 64-bit Support\n *-------------------------------------------------------*/\n\n#ifndef UNITY_SUPPORT_64\n  #if UNITY_LONG_WIDTH == 64 || UNITY_POINTER_WIDTH == 64\n    #define UNITY_SUPPORT_64\n  #endif\n#endif\n\n#ifndef UNITY_SUPPORT_64\n    /* No 64-bit Support */\n    typedef UNITY_UINT32 UNITY_UINT;\n    typedef UNITY_INT32 UNITY_INT;\n#else\n\n    /* 64-bit Support */\n  #if (UNITY_LONG_WIDTH == 32)\n    typedef unsigned long long UNITY_UINT64;\n    typedef signed long long   UNITY_INT64;\n  #elif (UNITY_LONG_WIDTH == 64)\n    typedef unsigned long      UNITY_UINT64;\n    typedef signed long        UNITY_INT64;\n  #else\n    #error Invalid UNITY_LONG_WIDTH specified! (32 or 64 are supported)\n  #endif\n    typedef UNITY_UINT64 UNITY_UINT;\n    typedef UNITY_INT64 UNITY_INT;\n\n#endif\n\n/*-------------------------------------------------------\n * Pointer Support\n *-------------------------------------------------------*/\n\n#if (UNITY_POINTER_WIDTH == 32)\n#define UNITY_PTR_TO_INT UNITY_INT32\n#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32\n#elif (UNITY_POINTER_WIDTH == 64)\n#define UNITY_PTR_TO_INT UNITY_INT64\n#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64\n#elif (UNITY_POINTER_WIDTH == 16)\n#define UNITY_PTR_TO_INT UNITY_INT16\n#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16\n#else\n    #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported)\n#endif\n\n#ifndef UNITY_PTR_ATTRIBUTE\n#define UNITY_PTR_ATTRIBUTE\n#endif\n\n#ifndef UNITY_INTERNAL_PTR\n#define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const void*\n#endif\n\n/*-------------------------------------------------------\n * Float Support\n *-------------------------------------------------------*/\n\n#ifdef UNITY_EXCLUDE_FLOAT\n\n/* No Floating Point Support */\n#ifndef UNITY_EXCLUDE_DOUBLE\n#define UNITY_EXCLUDE_DOUBLE /* Remove double when excluding float support */\n#endif\n#ifndef UNITY_EXCLUDE_FLOAT_PRINT\n#define UNITY_EXCLUDE_FLOAT_PRINT\n#endif\n\n#else\n\n/* Floating Point Support */\n#ifndef UNITY_FLOAT_PRECISION\n#define UNITY_FLOAT_PRECISION (0.00001f)\n#endif\n#ifndef UNITY_FLOAT_TYPE\n#define UNITY_FLOAT_TYPE float\n#endif\ntypedef UNITY_FLOAT_TYPE UNITY_FLOAT;\n\n/* isinf & isnan macros should be provided by math.h */\n#ifndef isinf\n/* The value of Inf - Inf is NaN */\n#define isinf(n) (isnan((n) - (n)) && !isnan(n))\n#endif\n\n#ifndef isnan\n/* NaN is the only floating point value that does NOT equal itself.\n * Therefore if n != n, then it is NaN. */\n#define isnan(n) ((n != n) ? 1 : 0)\n#endif\n\n#endif\n\n/*-------------------------------------------------------\n * Double Float Support\n *-------------------------------------------------------*/\n\n/* unlike float, we DON'T include by default */\n#if defined(UNITY_EXCLUDE_DOUBLE) || !defined(UNITY_INCLUDE_DOUBLE)\n\n  /* No Floating Point Support */\n  #ifndef UNITY_EXCLUDE_DOUBLE\n  #define UNITY_EXCLUDE_DOUBLE\n  #else\n    #undef UNITY_INCLUDE_DOUBLE\n  #endif\n\n  #ifndef UNITY_EXCLUDE_FLOAT\n    #ifndef UNITY_DOUBLE_TYPE\n    #define UNITY_DOUBLE_TYPE double\n    #endif\n  typedef UNITY_FLOAT UNITY_DOUBLE;\n  /* For parameter in UnityPrintFloat(UNITY_DOUBLE), which aliases to double or float */\n  #endif\n\n#else\n\n  /* Double Floating Point Support */\n  #ifndef UNITY_DOUBLE_PRECISION\n  #define UNITY_DOUBLE_PRECISION (1e-12)\n  #endif\n\n  #ifndef UNITY_DOUBLE_TYPE\n  #define UNITY_DOUBLE_TYPE double\n  #endif\n  typedef UNITY_DOUBLE_TYPE UNITY_DOUBLE;\n\n#endif\n\n/*-------------------------------------------------------\n * Output Method: stdout (DEFAULT)\n *-------------------------------------------------------*/\n#ifndef UNITY_OUTPUT_CHAR\n/* Default to using putchar, which is defined in stdio.h */\n#include <stdio.h>\n#define UNITY_OUTPUT_CHAR(a) (void)putchar(a)\n#else\n  /* If defined as something else, make sure we declare it here so it's ready for use */\n  #ifdef UNITY_OUTPUT_CHAR_HEADER_DECLARATION\nextern void UNITY_OUTPUT_CHAR_HEADER_DECLARATION;\n  #endif\n#endif\n\n#ifndef UNITY_OUTPUT_FLUSH\n#ifdef UNITY_USE_FLUSH_STDOUT\n/* We want to use the stdout flush utility */\n#include <stdio.h>\n#define UNITY_OUTPUT_FLUSH() (void)fflush(stdout)\n#else\n/* We've specified nothing, therefore flush should just be ignored */\n#define UNITY_OUTPUT_FLUSH()\n#endif\n#else\n/* We've defined flush as something else, so make sure we declare it here so it's ready for use */\n#ifdef UNITY_OUTPUT_FLUSH_HEADER_DECLARATION\nextern void UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION;\n#endif\n#endif\n\n#ifndef UNITY_OUTPUT_FLUSH\n#define UNITY_FLUSH_CALL()\n#else\n#define UNITY_FLUSH_CALL() UNITY_OUTPUT_FLUSH()\n#endif\n\n#ifndef UNITY_PRINT_EOL\n#define UNITY_PRINT_EOL()    UNITY_OUTPUT_CHAR('\\n')\n#endif\n\n#ifndef UNITY_OUTPUT_START\n#define UNITY_OUTPUT_START()\n#endif\n\n#ifndef UNITY_OUTPUT_COMPLETE\n#define UNITY_OUTPUT_COMPLETE()\n#endif\n\n/*-------------------------------------------------------\n * Footprint\n *-------------------------------------------------------*/\n\n#ifndef UNITY_LINE_TYPE\n#define UNITY_LINE_TYPE UNITY_UINT\n#endif\n\n#ifndef UNITY_COUNTER_TYPE\n#define UNITY_COUNTER_TYPE UNITY_UINT\n#endif\n\n/*-------------------------------------------------------\n * Language Features Available\n *-------------------------------------------------------*/\n#if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA)\n#   if defined(__GNUC__) || defined(__ghs__) /* __GNUC__ includes clang */\n#       if !(defined(__WIN32__) && defined(__clang__)) && !defined(__TMS470__)\n#           define UNITY_WEAK_ATTRIBUTE __attribute__((weak))\n#       endif\n#   endif\n#endif\n\n#ifdef UNITY_NO_WEAK\n#   undef UNITY_WEAK_ATTRIBUTE\n#   undef UNITY_WEAK_PRAGMA\n#endif\n\n\n/*-------------------------------------------------------\n * Internal Structs Needed\n *-------------------------------------------------------*/\n\ntypedef void (*UnityTestFunction)(void);\n\n#define UNITY_DISPLAY_RANGE_INT  (0x10)\n#define UNITY_DISPLAY_RANGE_UINT (0x20)\n#define UNITY_DISPLAY_RANGE_HEX  (0x40)\n\ntypedef enum\n{\nUNITY_DISPLAY_STYLE_INT = sizeof(int)+ UNITY_DISPLAY_RANGE_INT,\n    UNITY_DISPLAY_STYLE_INT8     = 1 + UNITY_DISPLAY_RANGE_INT,\n    UNITY_DISPLAY_STYLE_INT16    = 2 + UNITY_DISPLAY_RANGE_INT,\n    UNITY_DISPLAY_STYLE_INT32    = 4 + UNITY_DISPLAY_RANGE_INT,\n#ifdef UNITY_SUPPORT_64\n    UNITY_DISPLAY_STYLE_INT64    = 8 + UNITY_DISPLAY_RANGE_INT,\n#endif\n\nUNITY_DISPLAY_STYLE_UINT = sizeof(unsigned) + UNITY_DISPLAY_RANGE_UINT,\n    UNITY_DISPLAY_STYLE_UINT8    = 1 + UNITY_DISPLAY_RANGE_UINT,\n    UNITY_DISPLAY_STYLE_UINT16   = 2 + UNITY_DISPLAY_RANGE_UINT,\n    UNITY_DISPLAY_STYLE_UINT32   = 4 + UNITY_DISPLAY_RANGE_UINT,\n#ifdef UNITY_SUPPORT_64\n    UNITY_DISPLAY_STYLE_UINT64   = 8 + UNITY_DISPLAY_RANGE_UINT,\n#endif\n\n    UNITY_DISPLAY_STYLE_HEX8     = 1 + UNITY_DISPLAY_RANGE_HEX,\n    UNITY_DISPLAY_STYLE_HEX16    = 2 + UNITY_DISPLAY_RANGE_HEX,\n    UNITY_DISPLAY_STYLE_HEX32    = 4 + UNITY_DISPLAY_RANGE_HEX,\n#ifdef UNITY_SUPPORT_64\n    UNITY_DISPLAY_STYLE_HEX64    = 8 + UNITY_DISPLAY_RANGE_HEX,\n#endif\n\n    UNITY_DISPLAY_STYLE_UNKNOWN\n} UNITY_DISPLAY_STYLE_T;\n\ntypedef enum\n{\n    UNITY_EQUAL_TO         = 1,\n    UNITY_GREATER_THAN     = 2,\n    UNITY_GREATER_OR_EQUAL = 2 + UNITY_EQUAL_TO,\n    UNITY_SMALLER_THAN     = 4,\n    UNITY_SMALLER_OR_EQUAL = 4 + UNITY_EQUAL_TO\n} UNITY_COMPARISON_T;\n\n#ifndef UNITY_EXCLUDE_FLOAT\ntypedef enum UNITY_FLOAT_TRAIT\n{\n    UNITY_FLOAT_IS_NOT_INF       = 0,\n    UNITY_FLOAT_IS_INF,\n    UNITY_FLOAT_IS_NOT_NEG_INF,\n    UNITY_FLOAT_IS_NEG_INF,\n    UNITY_FLOAT_IS_NOT_NAN,\n    UNITY_FLOAT_IS_NAN,\n    UNITY_FLOAT_IS_NOT_DET,\n    UNITY_FLOAT_IS_DET,\n    UNITY_FLOAT_INVALID_TRAIT\n} UNITY_FLOAT_TRAIT_T;\n#endif\n\ntypedef enum\n{\n    UNITY_ARRAY_TO_VAL = 0,\n    UNITY_ARRAY_TO_ARRAY\n} UNITY_FLAGS_T;\n\nstruct UNITY_STORAGE_T\n{\n    const char* TestFile;\n    const char* CurrentTestName;\n#ifndef UNITY_EXCLUDE_DETAILS\n    const char* CurrentDetail1;\n    const char* CurrentDetail2;\n#endif\n    UNITY_LINE_TYPE CurrentTestLineNumber;\n    UNITY_COUNTER_TYPE NumberOfTests;\n    UNITY_COUNTER_TYPE TestFailures;\n    UNITY_COUNTER_TYPE TestIgnores;\n    UNITY_COUNTER_TYPE CurrentTestFailed;\n    UNITY_COUNTER_TYPE CurrentTestIgnored;\n#ifndef UNITY_EXCLUDE_SETJMP_H\n    jmp_buf AbortFrame;\n#endif\n};\n\nextern struct UNITY_STORAGE_T Unity;\n\n/*-------------------------------------------------------\n * Test Suite Management\n *-------------------------------------------------------*/\n\nvoid UnityBegin(const char* filename);\nint  UnityEnd(void);\nvoid UnityConcludeTest(void);\nvoid UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum);\n\n/*-------------------------------------------------------\n * Details Support\n *-------------------------------------------------------*/\n\n#ifdef UNITY_EXCLUDE_DETAILS\n#define UNITY_CLR_DETAILS()\n#define UNITY_SET_DETAIL(d1)\n#define UNITY_SET_DETAILS(d1,d2)\n#else\n#define UNITY_CLR_DETAILS()      { Unity.CurrentDetail1 = 0;   Unity.CurrentDetail2 = 0;  }\n#define UNITY_SET_DETAIL(d1)     { Unity.CurrentDetail1 = d1;  Unity.CurrentDetail2 = 0;  }\n#define UNITY_SET_DETAILS(d1,d2) { Unity.CurrentDetail1 = d1;  Unity.CurrentDetail2 = d2; }\n\n#ifndef UNITY_DETAIL1_NAME\n#define UNITY_DETAIL1_NAME \"Function\"\n#endif\n\n#ifndef UNITY_DETAIL2_NAME\n#define UNITY_DETAIL2_NAME \"Argument\"\n#endif\n#endif\n\n/*-------------------------------------------------------\n * Test Output\n *-------------------------------------------------------*/\n\nvoid UnityPrint(const char* string);\nvoid UnityPrintLen(const char* string, const UNITY_UINT32 length);\nvoid UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number);\nvoid UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style);\nvoid UnityPrintNumber(const UNITY_INT number);\nvoid UnityPrintNumberUnsigned(const UNITY_UINT number);\nvoid UnityPrintNumberHex(const UNITY_UINT number, const char nibbles);\n\n#ifndef UNITY_EXCLUDE_FLOAT_PRINT\nvoid UnityPrintFloat(const UNITY_DOUBLE input_number);\n#endif\n\n/*-------------------------------------------------------\n * Test Assertion Functions\n *-------------------------------------------------------\n *  Use the macros below this section instead of calling\n *  these directly. The macros have a consistent naming\n *  convention and will pull in file and line information\n *  for you. */\n\nvoid UnityAssertEqualNumber(const UNITY_INT expected,\n                            const UNITY_INT actual,\n                            const char* msg,\n                            const UNITY_LINE_TYPE lineNumber,\n                            const UNITY_DISPLAY_STYLE_T style);\n\nvoid UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold,\n                                           const UNITY_INT actual,\n                                           const UNITY_COMPARISON_T compare,\n                                           const char *msg,\n                                           const UNITY_LINE_TYPE lineNumber,\n                                           const UNITY_DISPLAY_STYLE_T style);\n\nvoid UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected,\n                              UNITY_INTERNAL_PTR actual,\n                              const UNITY_UINT32 num_elements,\n                              const char* msg,\n                              const UNITY_LINE_TYPE lineNumber,\n                              const UNITY_DISPLAY_STYLE_T style,\n                              const UNITY_FLAGS_T flags);\n\nvoid UnityAssertBits(const UNITY_INT mask,\n                     const UNITY_INT expected,\n                     const UNITY_INT actual,\n                     const char* msg,\n                     const UNITY_LINE_TYPE lineNumber);\n\nvoid UnityAssertEqualString(const char* expected,\n                            const char* actual,\n                            const char* msg,\n                            const UNITY_LINE_TYPE lineNumber);\n\nvoid UnityAssertEqualStringLen(const char* expected,\n                            const char* actual,\n                            const UNITY_UINT32 length,\n                            const char* msg,\n                            const UNITY_LINE_TYPE lineNumber);\n\nvoid UnityAssertEqualStringArray( UNITY_INTERNAL_PTR expected,\n                                  const char** actual,\n                                  const UNITY_UINT32 num_elements,\n                                  const char* msg,\n                                  const UNITY_LINE_TYPE lineNumber,\n                                  const UNITY_FLAGS_T flags);\n\nvoid UnityAssertEqualMemory( UNITY_INTERNAL_PTR expected,\n                             UNITY_INTERNAL_PTR actual,\n                             const UNITY_UINT32 length,\n                             const UNITY_UINT32 num_elements,\n                             const char* msg,\n                             const UNITY_LINE_TYPE lineNumber,\n                             const UNITY_FLAGS_T flags);\n\nvoid UnityAssertNumbersWithin(const UNITY_UINT delta,\n                              const UNITY_INT expected,\n                              const UNITY_INT actual,\n                              const char* msg,\n                              const UNITY_LINE_TYPE lineNumber,\n                              const UNITY_DISPLAY_STYLE_T style);\n\nvoid UnityFail(const char* message, const UNITY_LINE_TYPE line);\n\nvoid UnityIgnore(const char* message, const UNITY_LINE_TYPE line);\n\n#ifndef UNITY_EXCLUDE_FLOAT\nvoid UnityAssertFloatsWithin(const UNITY_FLOAT delta,\n                             const UNITY_FLOAT expected,\n                             const UNITY_FLOAT actual,\n                             const char* msg,\n                             const UNITY_LINE_TYPE lineNumber);\n\nvoid UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected,\n                                UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* actual,\n                                const UNITY_UINT32 num_elements,\n                                const char* msg,\n                                const UNITY_LINE_TYPE lineNumber,\n                                const UNITY_FLAGS_T flags);\n\nvoid UnityAssertFloatSpecial(const UNITY_FLOAT actual,\n                             const char* msg,\n                             const UNITY_LINE_TYPE lineNumber,\n                             const UNITY_FLOAT_TRAIT_T style);\n#endif\n\n#ifndef UNITY_EXCLUDE_DOUBLE\nvoid UnityAssertDoublesWithin(const UNITY_DOUBLE delta,\n                              const UNITY_DOUBLE expected,\n                              const UNITY_DOUBLE actual,\n                              const char* msg,\n                              const UNITY_LINE_TYPE lineNumber);\n\nvoid UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected,\n                                 UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual,\n                                 const UNITY_UINT32 num_elements,\n                                 const char* msg,\n                                 const UNITY_LINE_TYPE lineNumber,\n                                 const UNITY_FLAGS_T flags);\n\nvoid UnityAssertDoubleSpecial(const UNITY_DOUBLE actual,\n                              const char* msg,\n                              const UNITY_LINE_TYPE lineNumber,\n                              const UNITY_FLOAT_TRAIT_T style);\n#endif\n\n/*-------------------------------------------------------\n * Helpers\n *-------------------------------------------------------*/\n\nUNITY_INTERNAL_PTR UnityNumToPtr(const UNITY_INT num, const UNITY_UINT8 size);\n#ifndef UNITY_EXCLUDE_FLOAT\nUNITY_INTERNAL_PTR UnityFloatToPtr(const float num);\n#endif\n#ifndef UNITY_EXCLUDE_DOUBLE\nUNITY_INTERNAL_PTR UnityDoubleToPtr(const double num);\n#endif\n\n/*-------------------------------------------------------\n * Error Strings We Might Need\n *-------------------------------------------------------*/\n\nextern const char UnityStrErrFloat[];\nextern const char UnityStrErrDouble[];\nextern const char UnityStrErr64[];\n\n/*-------------------------------------------------------\n * Test Running Macros\n *-------------------------------------------------------*/\n\n#ifndef UNITY_EXCLUDE_SETJMP_H\n#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0)\n#define TEST_ABORT() longjmp(Unity.AbortFrame, 1)\n#else\n#define TEST_PROTECT() 1\n#define TEST_ABORT() return\n#endif\n\n/* This tricky series of macros gives us an optional line argument to treat it as RUN_TEST(func, num=__LINE__) */\n#ifndef RUN_TEST\n#ifdef __STDC_VERSION__\n#if __STDC_VERSION__ >= 199901L\n#define RUN_TEST(...) UnityDefaultTestRun(RUN_TEST_FIRST(__VA_ARGS__), RUN_TEST_SECOND(__VA_ARGS__))\n#define RUN_TEST_FIRST(...) RUN_TEST_FIRST_HELPER(__VA_ARGS__, throwaway)\n#define RUN_TEST_FIRST_HELPER(first, ...) (first), #first\n#define RUN_TEST_SECOND(...) RUN_TEST_SECOND_HELPER(__VA_ARGS__, __LINE__, throwaway)\n#define RUN_TEST_SECOND_HELPER(first, second, ...) (second)\n#endif\n#endif\n#endif\n\n/* If we can't do the tricky version, we'll just have to require them to always include the line number */\n#ifndef RUN_TEST\n#ifdef CMOCK\n#define RUN_TEST(func, num) UnityDefaultTestRun(func, #func, num)\n#else\n#define RUN_TEST(func) UnityDefaultTestRun(func, #func, __LINE__)\n#endif\n#endif\n\n#define TEST_LINE_NUM (Unity.CurrentTestLineNumber)\n#define TEST_IS_IGNORED (Unity.CurrentTestIgnored)\n#define UNITY_NEW_TEST(a) \\\n    Unity.CurrentTestName = (a); \\\n    Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)(__LINE__); \\\n    Unity.NumberOfTests++;\n\n#ifndef UNITY_BEGIN\n#define UNITY_BEGIN() UnityBegin(__FILE__)\n#endif\n\n#ifndef UNITY_END\n#define UNITY_END() UnityEnd()\n#endif\n\n/*-----------------------------------------------\n * Command Line Argument Support\n *-----------------------------------------------*/\n\n#ifdef UNITY_USE_COMMAND_LINE_ARGS\nint UnityParseOptions(int argc, char** argv);\nint UnityTestMatches(void);\n#endif\n\n/*-------------------------------------------------------\n * Basic Fail and Ignore\n *-------------------------------------------------------*/\n\n#define UNITY_TEST_FAIL(line, message)   UnityFail(   (message), (UNITY_LINE_TYPE)(line))\n#define UNITY_TEST_IGNORE(line, message) UnityIgnore( (message), (UNITY_LINE_TYPE)(line))\n\n/*-------------------------------------------------------\n * Test Asserts\n *-------------------------------------------------------*/\n\n#define UNITY_TEST_ASSERT(condition, line, message)                                              if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));}\n#define UNITY_TEST_ASSERT_NULL(pointer, line, message)                                           UNITY_TEST_ASSERT(((pointer) == NULL),  (UNITY_LINE_TYPE)(line), (message))\n#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message)                                       UNITY_TEST_ASSERT(((pointer) != NULL),  (UNITY_LINE_TYPE)(line), (message))\n\n#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message)                             UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)\n#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message)                            UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)\n#define UNITY_TEST_ASSERT_EQUAL_INT16(expected, actual, line, message)                           UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)\n#define UNITY_TEST_ASSERT_EQUAL_INT32(expected, actual, line, message)                           UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)\n#define UNITY_TEST_ASSERT_EQUAL_UINT(expected, actual, line, message)                            UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)\n#define UNITY_TEST_ASSERT_EQUAL_UINT8(expected, actual, line, message)                           UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)\n#define UNITY_TEST_ASSERT_EQUAL_UINT16(expected, actual, line, message)                          UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)\n#define UNITY_TEST_ASSERT_EQUAL_UINT32(expected, actual, line, message)                          UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)\n#define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message)                            UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)\n#define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message)                           UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)\n#define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message)                           UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)\n#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message)                            UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line))\n\n#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message)                     UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold),              (UNITY_INT)(actual),              UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)\n#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message)                    UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)\n#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)\n#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)\n#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message)                    UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold),              (UNITY_INT)(actual),              UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)\n#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)\n#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message)                  UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)\n#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message)                  UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)\n#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message)                    UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)\n#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)\n#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)\n\n#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message)                     UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold),              (UNITY_INT)(actual),              UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message)                    UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message)                    UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold),              (UNITY_INT)(actual),              UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message)                  UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message)                  UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message)                    UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)\n\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual, line, message)                 UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold),              (UNITY_INT)(actual),              UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual, line, message)                UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual, line, message)                UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold),              (UNITY_INT)(actual),              UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual, line, message)              UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual, line, message)              UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual, line, message)                UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)\n\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT(threshold, actual, line, message)                 UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold),              (UNITY_INT)(actual),              UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8(threshold, actual, line, message)                UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT(threshold, actual, line, message)                UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold),              (UNITY_INT)(actual),              UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16(threshold, actual, line, message)              UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32(threshold, actual, line, message)              UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8(threshold, actual, line, message)                UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)\n\n#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message)                     UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)\n#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message)                    UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)\n#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)\n#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)\n#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message)                    UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)\n#define UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)\n#define UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, line, message)                  UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)\n#define UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, line, message)                  UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)\n#define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message)                    UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)\n#define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)\n#define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)\n\n#define UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, line, message)                             UnityAssertEqualNumber((UNITY_PTR_TO_INT)(expected), (UNITY_PTR_TO_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER)\n#define UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, line, message)                          UnityAssertEqualString((const char*)(expected), (const char*)(actual), (message), (UNITY_LINE_TYPE)(line))\n#define UNITY_TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len, line, message)                 UnityAssertEqualStringLen((const char*)(expected), (const char*)(actual), (UNITY_UINT32)(len), (message), (UNITY_LINE_TYPE)(line))\n#define UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, line, message)                     UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), 1, (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY)\n\n#define UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT,     UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8,    UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16,   UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32,   UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT,    UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8,   UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16,  UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32,  UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8,    UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16,   UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32,   UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualStringArray((UNITY_INTERNAL_PTR)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY)\n\n#define UNITY_TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements, line, message)          UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)              expected, sizeof(int)),  (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT,     UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8  )expected, 1),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8,    UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )expected, 2),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16,   UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )expected, 4),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32,   UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)              expected, sizeof(unsigned int)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT,    UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT8 )expected, 1),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8,   UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT16)expected, 2),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16,  UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT32)expected, 4),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32,  UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8  )expected, 1),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8,    UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )expected, 2),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16,   UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )expected, 4),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32,   UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements, line, message)          UnityAssertEqualIntArray(UnityNumToPtr((UNITY_PTR_TO_INT)       expected, sizeof(int*)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements, line, message)       UnityAssertEqualStringArray((UNITY_INTERNAL_PTR)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements, line, message)  UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL)\n\n#ifdef UNITY_SUPPORT_64\n#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message)                           UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)\n#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message)                          UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)\n#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message)                           UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)\n#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64,  UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64,  UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64,  UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64,  UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)\n#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message)                  UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)\n#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)\n#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN,     (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)\n#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message)                  UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN,     (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)\n#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN,     (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message)              UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN,     (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message)                  UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN,     (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message)                   UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN,     (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message)              UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message)               UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)\n#else\n#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message)                          UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message)       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message)      UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message)       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message)                  UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message)                  UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message)               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message)              UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message)               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message)                  UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message)               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message)              UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message)               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)\n#endif\n\n#ifdef UNITY_EXCLUDE_FLOAT\n#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message)       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements, line, message)        UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message)                                    UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message)                                UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message)                                    UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message)                            UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message)                                UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message)                            UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message)                                UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message)                        UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)\n#else\n#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message)                   UnityAssertFloatsWithin((UNITY_FLOAT)(delta), (UNITY_FLOAT)(expected), (UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line))\n#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message)                           UNITY_TEST_ASSERT_FLOAT_WITHIN((UNITY_FLOAT)(expected) * (UNITY_FLOAT)UNITY_FLOAT_PRECISION, (UNITY_FLOAT)(expected), (UNITY_FLOAT)(actual), (UNITY_LINE_TYPE)(line), (message))\n#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualFloatArray((UNITY_FLOAT*)(expected), (UNITY_FLOAT*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements, line, message)        UnityAssertEqualFloatArray(UnityFloatToPtr(expected), (UNITY_FLOAT*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message)                                    UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message)                                UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message)                                    UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN)\n#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message)                            UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message)                                UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message)                            UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message)                                UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN)\n#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message)                        UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET)\n#endif\n\n#ifdef UNITY_EXCLUDE_DOUBLE\n#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message)                  UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message)                          UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message)      UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements, line, message)       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message)                                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message)                               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message)                                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message)                               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message)                               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message)                       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)\n#else\n#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message)                  UnityAssertDoublesWithin((UNITY_DOUBLE)(delta), (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)line)\n#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message)                          UNITY_TEST_ASSERT_DOUBLE_WITHIN((UNITY_DOUBLE)(expected) * (UNITY_DOUBLE)UNITY_DOUBLE_PRECISION, (UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual, (UNITY_LINE_TYPE)(line), message)\n#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualDoubleArray((UNITY_DOUBLE*)(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_ARRAY_TO_ARRAY)\n#define UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements, line, message)       UnityAssertEqualDoubleArray(UnityDoubleToPtr(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_ARRAY_TO_VAL)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message)                                   UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message)                               UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message)                                   UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message)                           UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message)                               UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message)                           UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message)                               UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN)\n#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message)                       UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET)\n#endif\n\n/* End of UNITY_INTERNALS_H */\n#endif\n"
  },
  {
    "path": "external/unity/version.txt",
    "content": "https://github.com/ThrowTheSwitch/Unity/commit/b4aca70fd9e0ddf0afbdafb1b826f5edcfc1049b\n"
  },
  {
    "path": "external/wepoll/README.md",
    "content": "# wepoll - epoll for windows\n\n[![][ci status badge]][ci status link]\n\nThis library implements the [epoll][man epoll] API for Windows\napplications. It is fast and scalable, and it closely resembles the API\nand behavior of Linux' epoll.\n\n## Rationale\n\nUnlike Linux, OS X, and many other operating systems, Windows doesn't\nhave a good API for receiving socket state notifications. It only\nsupports the `select` and `WSAPoll` APIs, but they\n[don't scale][select scale] and suffer from\n[other issues][wsapoll broken].\n\nUsing I/O completion ports isn't always practical when software is\ndesigned to be cross-platform. Wepoll offers an alternative that is\nmuch closer to a drop-in replacement for software that was designed\nto run on Linux.\n\n## Features\n\n* Can poll 100000s of sockets efficiently.\n* Fully thread-safe.\n* Multiple threads can poll the same epoll port.\n* Sockets can be added to multiple epoll sets.\n* All epoll events (`EPOLLIN`, `EPOLLOUT`, `EPOLLPRI`, `EPOLLRDHUP`)\n  are supported.\n* Level-triggered and one-shot (`EPOLLONESTHOT`) modes are supported\n* Trivial to embed: you need [only two files][dist].\n\n## Limitations\n\n* Only works with sockets.\n* Edge-triggered (`EPOLLET`) mode isn't supported.\n\n## How to use\n\nThe library is [distributed][dist] as a single source file\n([wepoll.c][wepoll.c]) and a single header file ([wepoll.h][wepoll.h]).<br>\nCompile the .c file as part of your project, and include the header wherever\nneeded.\n\n## Compatibility\n\n* Requires Windows Vista or higher.\n* Can be compiled with recent versions of MSVC, Clang, and GCC.\n\n## API\n\n### General remarks\n\n* The epoll port is a `HANDLE`, not a file descriptor.\n* All functions set both `errno` and `GetLastError()` on failure.\n* For more extensive documentation, see the [epoll(7) man page][man epoll],\n  and the per-function man pages that are linked below.\n\n### epoll_create/epoll_create1\n\n```c\nHANDLE epoll_create(int size);\nHANDLE epoll_create1(int flags);\n```\n\n* Create a new epoll instance (port).\n* `size` is ignored but most be greater than zero.\n* `flags` must be zero as there are no supported flags.\n* Returns `NULL` on failure.\n* [Linux man page][man epoll_create]\n\n### epoll_close\n\n```c\nint epoll_close(HANDLE ephnd);\n```\n\n* Close an epoll port.\n* Do not attempt to close the epoll port with `close()`,\n  `CloseHandle()` or `closesocket()`.\n\n### epoll_ctl\n\n```c\nint epoll_ctl(HANDLE ephnd,\n              int op,\n              SOCKET sock,\n              struct epoll_event* event);\n```\n\n* Control which socket events are monitored by an epoll port.\n* `ephnd` must be a HANDLE created by\n  [`epoll_create()`](#epoll_createepoll_create1) or\n  [`epoll_create1()`](#epoll_createepoll_create1).\n* `op` must be one of `EPOLL_CTL_ADD`, `EPOLL_CTL_MOD`, `EPOLL_CTL_DEL`.\n* `sock` must be a valid socket created by [`socket()`][msdn socket],\n  [`WSASocket()`][msdn wsasocket], or [`accept()`][msdn accept].\n* `event` should be a pointer to a [`struct epoll_event`](#struct-epoll_event).<br>\n  If `op` is `EPOLL_CTL_DEL` then the `event` parameter is ignored, and it\n  may be `NULL`.\n* Returns 0 on success, -1 on failure.\n* It is recommended to always explicitly remove a socket from its epoll\n  set using `EPOLL_CTL_DEL` *before* closing it.<br>\n  As on Linux, closed sockets are automatically removed from the epoll set, but\n  wepoll may not be able to detect that a socket was closed until the next call\n  to [`epoll_wait()`](#epoll_wait).\n* [Linux man page][man epoll_ctl]\n\n### epoll_wait\n\n```c\nint epoll_wait(HANDLE ephnd,\n               struct epoll_event* events,\n               int maxevents,\n               int timeout);\n```\n\n* Receive socket events from an epoll port.\n* `events` should point to a caller-allocated array of\n  [`epoll_event`](#struct-epoll_event) structs, which will receive the\n  reported events.\n* `maxevents` is the maximum number of events that will be written to the\n  `events` array, and must be greater than zero.\n* `timeout` specifies whether to block when no events are immediately available.\n  - `<0` block indefinitely\n  - `0`  report any events that are already waiting, but don't block\n  - `≥1` block for at most N milliseconds\n* Return value:\n  - `-1` an error occurred\n  - `0`  timed out without any events to report\n  - `≥1` the number of events stored in the `events` buffer\n* [Linux man page][man epoll_wait]\n\n### struct epoll_event\n\n```c\ntypedef union epoll_data {\n  void* ptr;\n  int fd;\n  uint32_t u32;\n  uint64_t u64;\n  SOCKET sock;        /* Windows specific */\n  HANDLE hnd;         /* Windows specific */\n} epoll_data_t;\n```\n\n```c\nstruct epoll_event {\n  uint32_t events;    /* Epoll events and flags */\n  epoll_data_t data;  /* User data variable */\n};\n```\n\n* The `events` field is a bit mask containing the events being\n  monitored/reported, and optional flags.<br>\n  Flags are accepted by [`epoll_ctl()`](#epoll_ctl), but they are not reported\n  back by [`epoll_wait()`](#epoll_wait).\n* The `data` field can be used to associate application-specific information\n  with a socket; its value will be returned unmodified by\n  [`epoll_wait()`](#epoll_wait).\n* [Linux man page][man epoll_ctl]\n\n| Event         | Description                                                          |\n|---------------|----------------------------------------------------------------------|\n| `EPOLLIN`     | incoming data available, or incoming connection ready to be accepted |\n| `EPOLLOUT`    | ready to send data, or outgoing connection successfully established  |\n| `EPOLLRDHUP`  | remote peer initiated graceful socket shutdown                       |\n| `EPOLLPRI`    | out-of-band data available for reading                               |\n| `EPOLLERR`    | socket error<sup>1</sup>                                             |\n| `EPOLLHUP`    | socket hang-up<sup>1</sup>                                           |\n| `EPOLLRDNORM` | same as `EPOLLIN`                                                    |\n| `EPOLLRDBAND` | same as `EPOLLPRI`                                                   |\n| `EPOLLWRNORM` | same as `EPOLLOUT`                                                   |\n| `EPOLLWRBAND` | same as `EPOLLOUT`                                                   |\n| `EPOLLMSG`    | never reported                                                       |\n\n| Flag             | Description               |\n|------------------|---------------------------|\n| `EPOLLONESHOT`   | report event(s) only once |\n| `EPOLLET`        | not supported by wepoll   |\n| `EPOLLEXCLUSIVE` | not supported by wepoll   |\n| `EPOLLWAKEUP`    | not supported by wepoll   |\n\n<sup>1</sup>: the `EPOLLERR` and `EPOLLHUP` events may always be reported by\n[`epoll_wait()`](#epoll_wait), regardless of the event mask that was passed to\n[`epoll_ctl()`](#epoll_ctl).\n\n\n[ci status badge]:  https://ci.appveyor.com/api/projects/status/github/piscisaureus/wepoll?branch=master&svg=true\n[ci status link]:   https://ci.appveyor.com/project/piscisaureus/wepoll/branch/master\n[dist]:             https://github.com/piscisaureus/wepoll/tree/dist\n[man epoll]:        http://man7.org/linux/man-pages/man7/epoll.7.html\n[man epoll_create]: http://man7.org/linux/man-pages/man2/epoll_create.2.html\n[man epoll_ctl]:    http://man7.org/linux/man-pages/man2/epoll_ctl.2.html\n[man epoll_wait]:   http://man7.org/linux/man-pages/man2/epoll_wait.2.html\n[msdn accept]:      https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx\n[msdn socket]:      https://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx\n[msdn wsasocket]:   https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx\n[select scale]:     https://daniel.haxx.se/docs/poll-vs-select.html\n[wsapoll broken]:   https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/\n[wepoll.c]:         https://github.com/piscisaureus/wepoll/blob/dist/wepoll.c\n[wepoll.h]:         https://github.com/piscisaureus/wepoll/blob/dist/wepoll.h\n"
  },
  {
    "path": "external/wepoll/license.txt",
    "content": "wepoll - epoll for Windows\nhttps://github.com/piscisaureus/wepoll\n\nCopyright 2012-2020, Bert Belder <bertbelder@gmail.com>\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n  * Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n  * Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in the\n    documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "external/wepoll/version.txt",
    "content": "https://github.com/piscisaureus/wepoll/tree/v1.5.8\n"
  },
  {
    "path": "external/wepoll/wepoll.c",
    "content": "/*\n * wepoll - epoll for Windows\n * https://github.com/piscisaureus/wepoll\n *\n * Copyright 2012-2020, Bert Belder <bertbelder@gmail.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *   * Redistributions of source code must retain the above copyright\n *     notice, this list of conditions and the following disclaimer.\n *\n *   * Redistributions in binary form must reproduce the above copyright\n *     notice, this list of conditions and the following disclaimer in the\n *     documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef WEPOLL_EXPORT\n#define WEPOLL_EXPORT\n#endif\n\n#include <stdint.h>\n\nenum EPOLL_EVENTS {\n  EPOLLIN      = (int) (1U <<  0),\n  EPOLLPRI     = (int) (1U <<  1),\n  EPOLLOUT     = (int) (1U <<  2),\n  EPOLLERR     = (int) (1U <<  3),\n  EPOLLHUP     = (int) (1U <<  4),\n  EPOLLRDNORM  = (int) (1U <<  6),\n  EPOLLRDBAND  = (int) (1U <<  7),\n  EPOLLWRNORM  = (int) (1U <<  8),\n  EPOLLWRBAND  = (int) (1U <<  9),\n  EPOLLMSG     = (int) (1U << 10), /* Never reported. */\n  EPOLLRDHUP   = (int) (1U << 13),\n  EPOLLONESHOT = (int) (1U << 31)\n};\n\n#define EPOLLIN      (1U <<  0)\n#define EPOLLPRI     (1U <<  1)\n#define EPOLLOUT     (1U <<  2)\n#define EPOLLERR     (1U <<  3)\n#define EPOLLHUP     (1U <<  4)\n#define EPOLLRDNORM  (1U <<  6)\n#define EPOLLRDBAND  (1U <<  7)\n#define EPOLLWRNORM  (1U <<  8)\n#define EPOLLWRBAND  (1U <<  9)\n#define EPOLLMSG     (1U << 10)\n#define EPOLLRDHUP   (1U << 13)\n#define EPOLLONESHOT (1U << 31)\n\n#define EPOLL_CTL_ADD 1\n#define EPOLL_CTL_MOD 2\n#define EPOLL_CTL_DEL 3\n\ntypedef void* HANDLE;\ntypedef uintptr_t SOCKET;\n\ntypedef union epoll_data {\n  void* ptr;\n  int fd;\n  uint32_t u32;\n  uint64_t u64;\n  SOCKET sock; /* Windows specific */\n  HANDLE hnd;  /* Windows specific */\n} epoll_data_t;\n\nstruct epoll_event {\n  uint32_t events;   /* Epoll events and flags */\n  epoll_data_t data; /* User data variable */\n};\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nWEPOLL_EXPORT HANDLE epoll_create(int size);\nWEPOLL_EXPORT HANDLE epoll_create1(int flags);\n\nWEPOLL_EXPORT int epoll_close(HANDLE ephnd);\n\nWEPOLL_EXPORT int epoll_ctl(HANDLE ephnd,\n                            int op,\n                            SOCKET sock,\n                            struct epoll_event* event);\n\nWEPOLL_EXPORT int epoll_wait(HANDLE ephnd,\n                             struct epoll_event* events,\n                             int maxevents,\n                             int timeout);\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#include <assert.h>\n\n#include <stdlib.h>\n\n#define WEPOLL_INTERNAL static\n#define WEPOLL_INTERNAL_EXTERN static\n\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wnonportable-system-include-path\"\n#pragma clang diagnostic ignored \"-Wreserved-id-macro\"\n#elif defined(_MSC_VER)\n#pragma warning(push, 1)\n#endif\n\n#undef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n\n#undef _WIN32_WINNT\n#define _WIN32_WINNT 0x0600\n\n#include <winsock2.h>\n#include <ws2tcpip.h>\n#include <windows.h>\n\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#elif defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n\nWEPOLL_INTERNAL int nt_global_init(void);\n\ntypedef LONG NTSTATUS;\ntypedef NTSTATUS* PNTSTATUS;\n\n#ifndef NT_SUCCESS\n#define NT_SUCCESS(status) (((NTSTATUS)(status)) >= 0)\n#endif\n\n#ifndef STATUS_SUCCESS\n#define STATUS_SUCCESS ((NTSTATUS) 0x00000000L)\n#endif\n\n#ifndef STATUS_PENDING\n#define STATUS_PENDING ((NTSTATUS) 0x00000103L)\n#endif\n\n#ifndef STATUS_CANCELLED\n#define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L)\n#endif\n\n#ifndef STATUS_NOT_FOUND\n#define STATUS_NOT_FOUND ((NTSTATUS) 0xC0000225L)\n#endif\n\ntypedef struct _IO_STATUS_BLOCK {\n  NTSTATUS Status;\n  ULONG_PTR Information;\n} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;\n\ntypedef VOID(NTAPI* PIO_APC_ROUTINE)(PVOID ApcContext,\n                                     PIO_STATUS_BLOCK IoStatusBlock,\n                                     ULONG Reserved);\n\ntypedef struct _UNICODE_STRING {\n  USHORT Length;\n  USHORT MaximumLength;\n  PWSTR Buffer;\n} UNICODE_STRING, *PUNICODE_STRING;\n\n#define RTL_CONSTANT_STRING(s) \\\n  { sizeof(s) - sizeof((s)[0]), sizeof(s), s }\n\ntypedef struct _OBJECT_ATTRIBUTES {\n  ULONG Length;\n  HANDLE RootDirectory;\n  PUNICODE_STRING ObjectName;\n  ULONG Attributes;\n  PVOID SecurityDescriptor;\n  PVOID SecurityQualityOfService;\n} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;\n\n#define RTL_CONSTANT_OBJECT_ATTRIBUTES(ObjectName, Attributes) \\\n  { sizeof(OBJECT_ATTRIBUTES), NULL, ObjectName, Attributes, NULL, NULL }\n\n#ifndef FILE_OPEN\n#define FILE_OPEN 0x00000001UL\n#endif\n\n#define KEYEDEVENT_WAIT 0x00000001UL\n#define KEYEDEVENT_WAKE 0x00000002UL\n#define KEYEDEVENT_ALL_ACCESS \\\n  (STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE)\n\n#define NT_NTDLL_IMPORT_LIST(X)           \\\n  X(NTSTATUS,                             \\\n    NTAPI,                                \\\n    NtCancelIoFileEx,                     \\\n    (HANDLE FileHandle,                   \\\n     PIO_STATUS_BLOCK IoRequestToCancel,  \\\n     PIO_STATUS_BLOCK IoStatusBlock))     \\\n                                          \\\n  X(NTSTATUS,                             \\\n    NTAPI,                                \\\n    NtCreateFile,                         \\\n    (PHANDLE FileHandle,                  \\\n     ACCESS_MASK DesiredAccess,           \\\n     POBJECT_ATTRIBUTES ObjectAttributes, \\\n     PIO_STATUS_BLOCK IoStatusBlock,      \\\n     PLARGE_INTEGER AllocationSize,       \\\n     ULONG FileAttributes,                \\\n     ULONG ShareAccess,                   \\\n     ULONG CreateDisposition,             \\\n     ULONG CreateOptions,                 \\\n     PVOID EaBuffer,                      \\\n     ULONG EaLength))                     \\\n                                          \\\n  X(NTSTATUS,                             \\\n    NTAPI,                                \\\n    NtCreateKeyedEvent,                   \\\n    (PHANDLE KeyedEventHandle,            \\\n     ACCESS_MASK DesiredAccess,           \\\n     POBJECT_ATTRIBUTES ObjectAttributes, \\\n     ULONG Flags))                        \\\n                                          \\\n  X(NTSTATUS,                             \\\n    NTAPI,                                \\\n    NtDeviceIoControlFile,                \\\n    (HANDLE FileHandle,                   \\\n     HANDLE Event,                        \\\n     PIO_APC_ROUTINE ApcRoutine,          \\\n     PVOID ApcContext,                    \\\n     PIO_STATUS_BLOCK IoStatusBlock,      \\\n     ULONG IoControlCode,                 \\\n     PVOID InputBuffer,                   \\\n     ULONG InputBufferLength,             \\\n     PVOID OutputBuffer,                  \\\n     ULONG OutputBufferLength))           \\\n                                          \\\n  X(NTSTATUS,                             \\\n    NTAPI,                                \\\n    NtReleaseKeyedEvent,                  \\\n    (HANDLE KeyedEventHandle,             \\\n     PVOID KeyValue,                      \\\n     BOOLEAN Alertable,                   \\\n     PLARGE_INTEGER Timeout))             \\\n                                          \\\n  X(NTSTATUS,                             \\\n    NTAPI,                                \\\n    NtWaitForKeyedEvent,                  \\\n    (HANDLE KeyedEventHandle,             \\\n     PVOID KeyValue,                      \\\n     BOOLEAN Alertable,                   \\\n     PLARGE_INTEGER Timeout))             \\\n                                          \\\n  X(ULONG, WINAPI, RtlNtStatusToDosError, (NTSTATUS Status))\n\n#define X(return_type, attributes, name, parameters) \\\n  WEPOLL_INTERNAL_EXTERN return_type(attributes* name) parameters;\nNT_NTDLL_IMPORT_LIST(X)\n#undef X\n\n#define AFD_POLL_RECEIVE           0x0001\n#define AFD_POLL_RECEIVE_EXPEDITED 0x0002\n#define AFD_POLL_SEND              0x0004\n#define AFD_POLL_DISCONNECT        0x0008\n#define AFD_POLL_ABORT             0x0010\n#define AFD_POLL_LOCAL_CLOSE       0x0020\n#define AFD_POLL_ACCEPT            0x0080\n#define AFD_POLL_CONNECT_FAIL      0x0100\n\ntypedef struct _AFD_POLL_HANDLE_INFO {\n  HANDLE Handle;\n  ULONG Events;\n  NTSTATUS Status;\n} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO;\n\ntypedef struct _AFD_POLL_INFO {\n  LARGE_INTEGER Timeout;\n  ULONG NumberOfHandles;\n  ULONG Exclusive;\n  AFD_POLL_HANDLE_INFO Handles[1];\n} AFD_POLL_INFO, *PAFD_POLL_INFO;\n\nWEPOLL_INTERNAL int afd_create_device_handle(HANDLE iocp_handle,\n                                             HANDLE* afd_device_handle_out);\n\nWEPOLL_INTERNAL int afd_poll(HANDLE afd_device_handle,\n                             AFD_POLL_INFO* poll_info,\n                             IO_STATUS_BLOCK* io_status_block);\nWEPOLL_INTERNAL int afd_cancel_poll(HANDLE afd_device_handle,\n                                    IO_STATUS_BLOCK* io_status_block);\n\n#define return_map_error(value) \\\n  do {                          \\\n    err_map_win_error();        \\\n    return (value);             \\\n  } while (0)\n\n#define return_set_error(value, error) \\\n  do {                                 \\\n    err_set_win_error(error);          \\\n    return (value);                    \\\n  } while (0)\n\nWEPOLL_INTERNAL void err_map_win_error(void);\nWEPOLL_INTERNAL void err_set_win_error(DWORD error);\nWEPOLL_INTERNAL int err_check_handle(HANDLE handle);\n\n#define IOCTL_AFD_POLL 0x00012024\n\nstatic UNICODE_STRING afd__device_name =\n    RTL_CONSTANT_STRING(L\"\\\\Device\\\\Afd\\\\Wepoll\");\n\nstatic OBJECT_ATTRIBUTES afd__device_attributes =\n    RTL_CONSTANT_OBJECT_ATTRIBUTES(&afd__device_name, 0);\n\nint afd_create_device_handle(HANDLE iocp_handle,\n                             HANDLE* afd_device_handle_out) {\n  HANDLE afd_device_handle;\n  IO_STATUS_BLOCK iosb;\n  NTSTATUS status;\n\n  /* By opening \\Device\\Afd without specifying any extended attributes, we'll\n   * get a handle that lets us talk to the AFD driver, but that doesn't have an\n   * associated endpoint (so it's not a socket). */\n  status = NtCreateFile(&afd_device_handle,\n                        SYNCHRONIZE,\n                        &afd__device_attributes,\n                        &iosb,\n                        NULL,\n                        0,\n                        FILE_SHARE_READ | FILE_SHARE_WRITE,\n                        FILE_OPEN,\n                        0,\n                        NULL,\n                        0);\n  if (status != STATUS_SUCCESS)\n    return_set_error(-1, RtlNtStatusToDosError(status));\n\n  if (CreateIoCompletionPort(afd_device_handle, iocp_handle, 0, 0) == NULL)\n    goto error;\n\n  if (!SetFileCompletionNotificationModes(afd_device_handle,\n                                          FILE_SKIP_SET_EVENT_ON_HANDLE))\n    goto error;\n\n  *afd_device_handle_out = afd_device_handle;\n  return 0;\n\nerror:\n  CloseHandle(afd_device_handle);\n  return_map_error(-1);\n}\n\nint afd_poll(HANDLE afd_device_handle,\n             AFD_POLL_INFO* poll_info,\n             IO_STATUS_BLOCK* io_status_block) {\n  NTSTATUS status;\n\n  /* Blocking operation is not supported. */\n  assert(io_status_block != NULL);\n\n  io_status_block->Status = STATUS_PENDING;\n  status = NtDeviceIoControlFile(afd_device_handle,\n                                 NULL,\n                                 NULL,\n                                 io_status_block,\n                                 io_status_block,\n                                 IOCTL_AFD_POLL,\n                                 poll_info,\n                                 sizeof *poll_info,\n                                 poll_info,\n                                 sizeof *poll_info);\n\n  if (status == STATUS_SUCCESS)\n    return 0;\n  else if (status == STATUS_PENDING)\n    return_set_error(-1, ERROR_IO_PENDING);\n  else\n    return_set_error(-1, RtlNtStatusToDosError(status));\n}\n\nint afd_cancel_poll(HANDLE afd_device_handle,\n                    IO_STATUS_BLOCK* io_status_block) {\n  NTSTATUS cancel_status;\n  IO_STATUS_BLOCK cancel_iosb;\n\n  /* If the poll operation has already completed or has been cancelled earlier,\n   * there's nothing left for us to do. */\n  if (io_status_block->Status != STATUS_PENDING)\n    return 0;\n\n  cancel_status =\n      NtCancelIoFileEx(afd_device_handle, io_status_block, &cancel_iosb);\n\n  /* NtCancelIoFileEx() may return STATUS_NOT_FOUND if the operation completed\n   * just before calling NtCancelIoFileEx(). This is not an error. */\n  if (cancel_status == STATUS_SUCCESS || cancel_status == STATUS_NOT_FOUND)\n    return 0;\n  else\n    return_set_error(-1, RtlNtStatusToDosError(cancel_status));\n}\n\nWEPOLL_INTERNAL int epoll_global_init(void);\n\nWEPOLL_INTERNAL int init(void);\n\ntypedef struct port_state port_state_t;\ntypedef struct queue queue_t;\ntypedef struct sock_state sock_state_t;\ntypedef struct ts_tree_node ts_tree_node_t;\n\nWEPOLL_INTERNAL port_state_t* port_new(HANDLE* iocp_handle_out);\nWEPOLL_INTERNAL int port_close(port_state_t* port_state);\nWEPOLL_INTERNAL int port_delete(port_state_t* port_state);\n\nWEPOLL_INTERNAL int port_wait(port_state_t* port_state,\n                              struct epoll_event* events,\n                              int maxevents,\n                              int timeout);\n\nWEPOLL_INTERNAL int port_ctl(port_state_t* port_state,\n                             int op,\n                             SOCKET sock,\n                             struct epoll_event* ev);\n\nWEPOLL_INTERNAL int port_register_socket(port_state_t* port_state,\n                                         sock_state_t* sock_state,\n                                         SOCKET socket);\nWEPOLL_INTERNAL void port_unregister_socket(port_state_t* port_state,\n                                            sock_state_t* sock_state);\nWEPOLL_INTERNAL sock_state_t* port_find_socket(port_state_t* port_state,\n                                               SOCKET socket);\n\nWEPOLL_INTERNAL void port_request_socket_update(port_state_t* port_state,\n                                                sock_state_t* sock_state);\nWEPOLL_INTERNAL void port_cancel_socket_update(port_state_t* port_state,\n                                               sock_state_t* sock_state);\n\nWEPOLL_INTERNAL void port_add_deleted_socket(port_state_t* port_state,\n                                             sock_state_t* sock_state);\nWEPOLL_INTERNAL void port_remove_deleted_socket(port_state_t* port_state,\n                                                sock_state_t* sock_state);\n\nWEPOLL_INTERNAL HANDLE port_get_iocp_handle(port_state_t* port_state);\nWEPOLL_INTERNAL queue_t* port_get_poll_group_queue(port_state_t* port_state);\n\nWEPOLL_INTERNAL port_state_t* port_state_from_handle_tree_node(\n    ts_tree_node_t* tree_node);\nWEPOLL_INTERNAL ts_tree_node_t* port_state_to_handle_tree_node(\n    port_state_t* port_state);\n\n/* The reflock is a special kind of lock that normally prevents a chunk of\n * memory from being freed, but does allow the chunk of memory to eventually be\n * released in a coordinated fashion.\n *\n * Under normal operation, threads increase and decrease the reference count,\n * which are wait-free operations.\n *\n * Exactly once during the reflock's lifecycle, a thread holding a reference to\n * the lock may \"destroy\" the lock; this operation blocks until all other\n * threads holding a reference to the lock have dereferenced it. After\n * \"destroy\" returns, the calling thread may assume that no other threads have\n * a reference to the lock.\n *\n * Attemmpting to lock or destroy a lock after reflock_unref_and_destroy() has\n * been called is invalid and results in undefined behavior. Therefore the user\n * should use another lock to guarantee that this can't happen.\n */\n\ntypedef struct reflock {\n  volatile long state; /* 32-bit Interlocked APIs operate on `long` values. */\n} reflock_t;\n\nWEPOLL_INTERNAL int reflock_global_init(void);\n\nWEPOLL_INTERNAL void reflock_init(reflock_t* reflock);\nWEPOLL_INTERNAL void reflock_ref(reflock_t* reflock);\nWEPOLL_INTERNAL void reflock_unref(reflock_t* reflock);\nWEPOLL_INTERNAL void reflock_unref_and_destroy(reflock_t* reflock);\n\n#include <stdbool.h>\n\n/* N.b.: the tree functions do not set errno or LastError when they fail. Each\n * of the API functions has at most one failure mode. It is up to the caller to\n * set an appropriate error code when necessary. */\n\ntypedef struct tree tree_t;\ntypedef struct tree_node tree_node_t;\n\ntypedef struct tree {\n  tree_node_t* root;\n} tree_t;\n\ntypedef struct tree_node {\n  tree_node_t* left;\n  tree_node_t* right;\n  tree_node_t* parent;\n  uintptr_t key;\n  bool red;\n} tree_node_t;\n\nWEPOLL_INTERNAL void tree_init(tree_t* tree);\nWEPOLL_INTERNAL void tree_node_init(tree_node_t* node);\n\nWEPOLL_INTERNAL int tree_add(tree_t* tree, tree_node_t* node, uintptr_t key);\nWEPOLL_INTERNAL void tree_del(tree_t* tree, tree_node_t* node);\n\nWEPOLL_INTERNAL tree_node_t* tree_find(const tree_t* tree, uintptr_t key);\nWEPOLL_INTERNAL tree_node_t* tree_root(const tree_t* tree);\n\ntypedef struct ts_tree {\n  tree_t tree;\n  SRWLOCK lock;\n} ts_tree_t;\n\ntypedef struct ts_tree_node {\n  tree_node_t tree_node;\n  reflock_t reflock;\n} ts_tree_node_t;\n\nWEPOLL_INTERNAL void ts_tree_init(ts_tree_t* rtl);\nWEPOLL_INTERNAL void ts_tree_node_init(ts_tree_node_t* node);\n\nWEPOLL_INTERNAL int ts_tree_add(ts_tree_t* ts_tree,\n                                ts_tree_node_t* node,\n                                uintptr_t key);\n\nWEPOLL_INTERNAL ts_tree_node_t* ts_tree_del_and_ref(ts_tree_t* ts_tree,\n                                                    uintptr_t key);\nWEPOLL_INTERNAL ts_tree_node_t* ts_tree_find_and_ref(ts_tree_t* ts_tree,\n                                                     uintptr_t key);\n\nWEPOLL_INTERNAL void ts_tree_node_unref(ts_tree_node_t* node);\nWEPOLL_INTERNAL void ts_tree_node_unref_and_destroy(ts_tree_node_t* node);\n\nstatic ts_tree_t epoll__handle_tree;\n\nint epoll_global_init(void) {\n  ts_tree_init(&epoll__handle_tree);\n  return 0;\n}\n\nstatic HANDLE epoll__create(void) {\n  port_state_t* port_state;\n  HANDLE ephnd;\n  ts_tree_node_t* tree_node;\n\n  if (init() < 0)\n    return NULL;\n\n  port_state = port_new(&ephnd);\n  if (port_state == NULL)\n    return NULL;\n\n  tree_node = port_state_to_handle_tree_node(port_state);\n  if (ts_tree_add(&epoll__handle_tree, tree_node, (uintptr_t) ephnd) < 0) {\n    /* This should never happen. */\n    port_delete(port_state);\n    return_set_error(NULL, ERROR_ALREADY_EXISTS);\n  }\n\n  return ephnd;\n}\n\nHANDLE epoll_create(int size) {\n  if (size <= 0)\n    return_set_error(NULL, ERROR_INVALID_PARAMETER);\n\n  return epoll__create();\n}\n\nHANDLE epoll_create1(int flags) {\n  if (flags != 0)\n    return_set_error(NULL, ERROR_INVALID_PARAMETER);\n\n  return epoll__create();\n}\n\nint epoll_close(HANDLE ephnd) {\n  ts_tree_node_t* tree_node;\n  port_state_t* port_state;\n\n  if (init() < 0)\n    return -1;\n\n  tree_node = ts_tree_del_and_ref(&epoll__handle_tree, (uintptr_t) ephnd);\n  if (tree_node == NULL) {\n    err_set_win_error(ERROR_INVALID_PARAMETER);\n    goto err;\n  }\n\n  port_state = port_state_from_handle_tree_node(tree_node);\n  port_close(port_state);\n\n  ts_tree_node_unref_and_destroy(tree_node);\n\n  return port_delete(port_state);\n\nerr:\n  err_check_handle(ephnd);\n  return -1;\n}\n\nint epoll_ctl(HANDLE ephnd, int op, SOCKET sock, struct epoll_event* ev) {\n  ts_tree_node_t* tree_node;\n  port_state_t* port_state;\n  int r;\n\n  if (init() < 0)\n    return -1;\n\n  tree_node = ts_tree_find_and_ref(&epoll__handle_tree, (uintptr_t) ephnd);\n  if (tree_node == NULL) {\n    err_set_win_error(ERROR_INVALID_PARAMETER);\n    goto err;\n  }\n\n  port_state = port_state_from_handle_tree_node(tree_node);\n  r = port_ctl(port_state, op, sock, ev);\n\n  ts_tree_node_unref(tree_node);\n\n  if (r < 0)\n    goto err;\n\n  return 0;\n\nerr:\n  /* On Linux, in the case of epoll_ctl(), EBADF takes priority over other\n   * errors. Wepoll mimics this behavior. */\n  err_check_handle(ephnd);\n  err_check_handle((HANDLE) sock);\n  return -1;\n}\n\nint epoll_wait(HANDLE ephnd,\n               struct epoll_event* events,\n               int maxevents,\n               int timeout) {\n  ts_tree_node_t* tree_node;\n  port_state_t* port_state;\n  int num_events;\n\n  if (maxevents <= 0)\n    return_set_error(-1, ERROR_INVALID_PARAMETER);\n\n  if (init() < 0)\n    return -1;\n\n  tree_node = ts_tree_find_and_ref(&epoll__handle_tree, (uintptr_t) ephnd);\n  if (tree_node == NULL) {\n    err_set_win_error(ERROR_INVALID_PARAMETER);\n    goto err;\n  }\n\n  port_state = port_state_from_handle_tree_node(tree_node);\n  num_events = port_wait(port_state, events, maxevents, timeout);\n\n  ts_tree_node_unref(tree_node);\n\n  if (num_events < 0)\n    goto err;\n\n  return num_events;\n\nerr:\n  err_check_handle(ephnd);\n  return -1;\n}\n\n#include <errno.h>\n\n#define ERR__ERRNO_MAPPINGS(X)               \\\n  X(ERROR_ACCESS_DENIED, EACCES)             \\\n  X(ERROR_ALREADY_EXISTS, EEXIST)            \\\n  X(ERROR_BAD_COMMAND, EACCES)               \\\n  X(ERROR_BAD_EXE_FORMAT, ENOEXEC)           \\\n  X(ERROR_BAD_LENGTH, EACCES)                \\\n  X(ERROR_BAD_NETPATH, ENOENT)               \\\n  X(ERROR_BAD_NET_NAME, ENOENT)              \\\n  X(ERROR_BAD_NET_RESP, ENETDOWN)            \\\n  X(ERROR_BAD_PATHNAME, ENOENT)              \\\n  X(ERROR_BROKEN_PIPE, EPIPE)                \\\n  X(ERROR_CANNOT_MAKE, EACCES)               \\\n  X(ERROR_COMMITMENT_LIMIT, ENOMEM)          \\\n  X(ERROR_CONNECTION_ABORTED, ECONNABORTED)  \\\n  X(ERROR_CONNECTION_ACTIVE, EISCONN)        \\\n  X(ERROR_CONNECTION_REFUSED, ECONNREFUSED)  \\\n  X(ERROR_CRC, EACCES)                       \\\n  X(ERROR_DIR_NOT_EMPTY, ENOTEMPTY)          \\\n  X(ERROR_DISK_FULL, ENOSPC)                 \\\n  X(ERROR_DUP_NAME, EADDRINUSE)              \\\n  X(ERROR_FILENAME_EXCED_RANGE, ENOENT)      \\\n  X(ERROR_FILE_NOT_FOUND, ENOENT)            \\\n  X(ERROR_GEN_FAILURE, EACCES)               \\\n  X(ERROR_GRACEFUL_DISCONNECT, EPIPE)        \\\n  X(ERROR_HOST_DOWN, EHOSTUNREACH)           \\\n  X(ERROR_HOST_UNREACHABLE, EHOSTUNREACH)    \\\n  X(ERROR_INSUFFICIENT_BUFFER, EFAULT)       \\\n  X(ERROR_INVALID_ADDRESS, EADDRNOTAVAIL)    \\\n  X(ERROR_INVALID_FUNCTION, EINVAL)          \\\n  X(ERROR_INVALID_HANDLE, EBADF)             \\\n  X(ERROR_INVALID_NETNAME, EADDRNOTAVAIL)    \\\n  X(ERROR_INVALID_PARAMETER, EINVAL)         \\\n  X(ERROR_INVALID_USER_BUFFER, EMSGSIZE)     \\\n  X(ERROR_IO_PENDING, EINPROGRESS)           \\\n  X(ERROR_LOCK_VIOLATION, EACCES)            \\\n  X(ERROR_MORE_DATA, EMSGSIZE)               \\\n  X(ERROR_NETNAME_DELETED, ECONNABORTED)     \\\n  X(ERROR_NETWORK_ACCESS_DENIED, EACCES)     \\\n  X(ERROR_NETWORK_BUSY, ENETDOWN)            \\\n  X(ERROR_NETWORK_UNREACHABLE, ENETUNREACH)  \\\n  X(ERROR_NOACCESS, EFAULT)                  \\\n  X(ERROR_NONPAGED_SYSTEM_RESOURCES, ENOMEM) \\\n  X(ERROR_NOT_ENOUGH_MEMORY, ENOMEM)         \\\n  X(ERROR_NOT_ENOUGH_QUOTA, ENOMEM)          \\\n  X(ERROR_NOT_FOUND, ENOENT)                 \\\n  X(ERROR_NOT_LOCKED, EACCES)                \\\n  X(ERROR_NOT_READY, EACCES)                 \\\n  X(ERROR_NOT_SAME_DEVICE, EXDEV)            \\\n  X(ERROR_NOT_SUPPORTED, ENOTSUP)            \\\n  X(ERROR_NO_MORE_FILES, ENOENT)             \\\n  X(ERROR_NO_SYSTEM_RESOURCES, ENOMEM)       \\\n  X(ERROR_OPERATION_ABORTED, EINTR)          \\\n  X(ERROR_OUT_OF_PAPER, EACCES)              \\\n  X(ERROR_PAGED_SYSTEM_RESOURCES, ENOMEM)    \\\n  X(ERROR_PAGEFILE_QUOTA, ENOMEM)            \\\n  X(ERROR_PATH_NOT_FOUND, ENOENT)            \\\n  X(ERROR_PIPE_NOT_CONNECTED, EPIPE)         \\\n  X(ERROR_PORT_UNREACHABLE, ECONNRESET)      \\\n  X(ERROR_PROTOCOL_UNREACHABLE, ENETUNREACH) \\\n  X(ERROR_REM_NOT_LIST, ECONNREFUSED)        \\\n  X(ERROR_REQUEST_ABORTED, EINTR)            \\\n  X(ERROR_REQ_NOT_ACCEP, EWOULDBLOCK)        \\\n  X(ERROR_SECTOR_NOT_FOUND, EACCES)          \\\n  X(ERROR_SEM_TIMEOUT, ETIMEDOUT)            \\\n  X(ERROR_SHARING_VIOLATION, EACCES)         \\\n  X(ERROR_TOO_MANY_NAMES, ENOMEM)            \\\n  X(ERROR_TOO_MANY_OPEN_FILES, EMFILE)       \\\n  X(ERROR_UNEXP_NET_ERR, ECONNABORTED)       \\\n  X(ERROR_WAIT_NO_CHILDREN, ECHILD)          \\\n  X(ERROR_WORKING_SET_QUOTA, ENOMEM)         \\\n  X(ERROR_WRITE_PROTECT, EACCES)             \\\n  X(ERROR_WRONG_DISK, EACCES)                \\\n  X(WSAEACCES, EACCES)                       \\\n  X(WSAEADDRINUSE, EADDRINUSE)               \\\n  X(WSAEADDRNOTAVAIL, EADDRNOTAVAIL)         \\\n  X(WSAEAFNOSUPPORT, EAFNOSUPPORT)           \\\n  X(WSAECONNABORTED, ECONNABORTED)           \\\n  X(WSAECONNREFUSED, ECONNREFUSED)           \\\n  X(WSAECONNRESET, ECONNRESET)               \\\n  X(WSAEDISCON, EPIPE)                       \\\n  X(WSAEFAULT, EFAULT)                       \\\n  X(WSAEHOSTDOWN, EHOSTUNREACH)              \\\n  X(WSAEHOSTUNREACH, EHOSTUNREACH)           \\\n  X(WSAEINPROGRESS, EBUSY)                   \\\n  X(WSAEINTR, EINTR)                         \\\n  X(WSAEINVAL, EINVAL)                       \\\n  X(WSAEISCONN, EISCONN)                     \\\n  X(WSAEMSGSIZE, EMSGSIZE)                   \\\n  X(WSAENETDOWN, ENETDOWN)                   \\\n  X(WSAENETRESET, EHOSTUNREACH)              \\\n  X(WSAENETUNREACH, ENETUNREACH)             \\\n  X(WSAENOBUFS, ENOMEM)                      \\\n  X(WSAENOTCONN, ENOTCONN)                   \\\n  X(WSAENOTSOCK, ENOTSOCK)                   \\\n  X(WSAEOPNOTSUPP, EOPNOTSUPP)               \\\n  X(WSAEPROCLIM, ENOMEM)                     \\\n  X(WSAESHUTDOWN, EPIPE)                     \\\n  X(WSAETIMEDOUT, ETIMEDOUT)                 \\\n  X(WSAEWOULDBLOCK, EWOULDBLOCK)             \\\n  X(WSANOTINITIALISED, ENETDOWN)             \\\n  X(WSASYSNOTREADY, ENETDOWN)                \\\n  X(WSAVERNOTSUPPORTED, ENOSYS)\n\nstatic errno_t err__map_win_error_to_errno(DWORD error) {\n  switch (error) {\n#define X(error_sym, errno_sym) \\\n  case error_sym:               \\\n    return errno_sym;\n    ERR__ERRNO_MAPPINGS(X)\n#undef X\n  }\n  return EINVAL;\n}\n\nvoid err_map_win_error(void) {\n  errno = err__map_win_error_to_errno(GetLastError());\n}\n\nvoid err_set_win_error(DWORD error) {\n  SetLastError(error);\n  errno = err__map_win_error_to_errno(error);\n}\n\nint err_check_handle(HANDLE handle) {\n  DWORD flags;\n\n  /* GetHandleInformation() succeeds when passed INVALID_HANDLE_VALUE, so check\n   * for this condition explicitly. */\n  if (handle == INVALID_HANDLE_VALUE)\n    return_set_error(-1, ERROR_INVALID_HANDLE);\n\n  if (!GetHandleInformation(handle, &flags))\n    return_map_error(-1);\n\n  return 0;\n}\n\n#include <stddef.h>\n\n#define array_count(a) (sizeof(a) / (sizeof((a)[0])))\n\n#define container_of(ptr, type, member) \\\n  ((type*) ((uintptr_t) (ptr) - offsetof(type, member)))\n\n#define unused_var(v) ((void) (v))\n\n/* Polyfill `inline` for older versions of msvc (up to Visual Studio 2013) */\n#if defined(_MSC_VER) && _MSC_VER < 1900\n#define inline __inline\n#endif\n\nWEPOLL_INTERNAL int ws_global_init(void);\nWEPOLL_INTERNAL SOCKET ws_get_base_socket(SOCKET socket);\n\nstatic bool init__done = false;\nstatic INIT_ONCE init__once = INIT_ONCE_STATIC_INIT;\n\nstatic BOOL CALLBACK init__once_callback(INIT_ONCE* once,\n                                         void* parameter,\n                                         void** context) {\n  unused_var(once);\n  unused_var(parameter);\n  unused_var(context);\n\n  /* N.b. that initialization order matters here. */\n  if (ws_global_init() < 0 || nt_global_init() < 0 ||\n      reflock_global_init() < 0 || epoll_global_init() < 0)\n    return FALSE;\n\n  init__done = true;\n  return TRUE;\n}\n\nint init(void) {\n  if (!init__done &&\n      !InitOnceExecuteOnce(&init__once, init__once_callback, NULL, NULL))\n    /* `InitOnceExecuteOnce()` itself is infallible, and it doesn't set any\n     * error code when the once-callback returns FALSE. We return -1 here to\n     * indicate that global initialization failed; the failing init function is\n     * resposible for setting `errno` and calling `SetLastError()`. */\n    return -1;\n\n  return 0;\n}\n\n/* Set up a workaround for the following problem:\n *   FARPROC addr = GetProcAddress(...);\n *   MY_FUNC func = (MY_FUNC) addr;          <-- GCC 8 warning/error.\n *   MY_FUNC func = (MY_FUNC) (void*) addr;  <-- MSVC  warning/error.\n * To compile cleanly with either compiler, do casts with this \"bridge\" type:\n *   MY_FUNC func = (MY_FUNC) (nt__fn_ptr_cast_t) addr; */\n#ifdef __GNUC__\ntypedef void* nt__fn_ptr_cast_t;\n#else\ntypedef FARPROC nt__fn_ptr_cast_t;\n#endif\n\n#define X(return_type, attributes, name, parameters) \\\n  WEPOLL_INTERNAL return_type(attributes* name) parameters = NULL;\nNT_NTDLL_IMPORT_LIST(X)\n#undef X\n\nint nt_global_init(void) {\n  HMODULE ntdll;\n  FARPROC fn_ptr;\n\n  ntdll = GetModuleHandleW(L\"ntdll.dll\");\n  if (ntdll == NULL)\n    return -1;\n\n#define X(return_type, attributes, name, parameters) \\\n  fn_ptr = GetProcAddress(ntdll, #name);             \\\n  if (fn_ptr == NULL)                                \\\n    return -1;                                       \\\n  name = (return_type(attributes*) parameters)(nt__fn_ptr_cast_t) fn_ptr;\n  NT_NTDLL_IMPORT_LIST(X)\n#undef X\n\n  return 0;\n}\n\n#include <string.h>\n\ntypedef struct poll_group poll_group_t;\n\ntypedef struct queue_node queue_node_t;\n\nWEPOLL_INTERNAL poll_group_t* poll_group_acquire(port_state_t* port);\nWEPOLL_INTERNAL void poll_group_release(poll_group_t* poll_group);\n\nWEPOLL_INTERNAL void poll_group_delete(poll_group_t* poll_group);\n\nWEPOLL_INTERNAL poll_group_t* poll_group_from_queue_node(\n    queue_node_t* queue_node);\nWEPOLL_INTERNAL HANDLE\n    poll_group_get_afd_device_handle(poll_group_t* poll_group);\n\ntypedef struct queue_node {\n  queue_node_t* prev;\n  queue_node_t* next;\n} queue_node_t;\n\ntypedef struct queue {\n  queue_node_t head;\n} queue_t;\n\nWEPOLL_INTERNAL void queue_init(queue_t* queue);\nWEPOLL_INTERNAL void queue_node_init(queue_node_t* node);\n\nWEPOLL_INTERNAL queue_node_t* queue_first(const queue_t* queue);\nWEPOLL_INTERNAL queue_node_t* queue_last(const queue_t* queue);\n\nWEPOLL_INTERNAL void queue_prepend(queue_t* queue, queue_node_t* node);\nWEPOLL_INTERNAL void queue_append(queue_t* queue, queue_node_t* node);\nWEPOLL_INTERNAL void queue_move_to_start(queue_t* queue, queue_node_t* node);\nWEPOLL_INTERNAL void queue_move_to_end(queue_t* queue, queue_node_t* node);\nWEPOLL_INTERNAL void queue_remove(queue_node_t* node);\n\nWEPOLL_INTERNAL bool queue_is_empty(const queue_t* queue);\nWEPOLL_INTERNAL bool queue_is_enqueued(const queue_node_t* node);\n\n#define POLL_GROUP__MAX_GROUP_SIZE 32\n\ntypedef struct poll_group {\n  port_state_t* port_state;\n  queue_node_t queue_node;\n  HANDLE afd_device_handle;\n  size_t group_size;\n} poll_group_t;\n\nstatic poll_group_t* poll_group__new(port_state_t* port_state) {\n  HANDLE iocp_handle = port_get_iocp_handle(port_state);\n  queue_t* poll_group_queue = port_get_poll_group_queue(port_state);\n\n  poll_group_t* poll_group = malloc(sizeof *poll_group);\n  if (poll_group == NULL)\n    return_set_error(NULL, ERROR_NOT_ENOUGH_MEMORY);\n\n  memset(poll_group, 0, sizeof *poll_group);\n\n  queue_node_init(&poll_group->queue_node);\n  poll_group->port_state = port_state;\n\n  if (afd_create_device_handle(iocp_handle, &poll_group->afd_device_handle) <\n      0) {\n    free(poll_group);\n    return NULL;\n  }\n\n  queue_append(poll_group_queue, &poll_group->queue_node);\n\n  return poll_group;\n}\n\nvoid poll_group_delete(poll_group_t* poll_group) {\n  assert(poll_group->group_size == 0);\n  CloseHandle(poll_group->afd_device_handle);\n  queue_remove(&poll_group->queue_node);\n  free(poll_group);\n}\n\npoll_group_t* poll_group_from_queue_node(queue_node_t* queue_node) {\n  return container_of(queue_node, poll_group_t, queue_node);\n}\n\nHANDLE poll_group_get_afd_device_handle(poll_group_t* poll_group) {\n  return poll_group->afd_device_handle;\n}\n\npoll_group_t* poll_group_acquire(port_state_t* port_state) {\n  queue_t* poll_group_queue = port_get_poll_group_queue(port_state);\n  poll_group_t* poll_group =\n      !queue_is_empty(poll_group_queue)\n          ? container_of(\n                queue_last(poll_group_queue), poll_group_t, queue_node)\n          : NULL;\n\n  if (poll_group == NULL ||\n      poll_group->group_size >= POLL_GROUP__MAX_GROUP_SIZE)\n    poll_group = poll_group__new(port_state);\n  if (poll_group == NULL)\n    return NULL;\n\n  if (++poll_group->group_size == POLL_GROUP__MAX_GROUP_SIZE)\n    queue_move_to_start(poll_group_queue, &poll_group->queue_node);\n\n  return poll_group;\n}\n\nvoid poll_group_release(poll_group_t* poll_group) {\n  port_state_t* port_state = poll_group->port_state;\n  queue_t* poll_group_queue = port_get_poll_group_queue(port_state);\n\n  poll_group->group_size--;\n  assert(poll_group->group_size < POLL_GROUP__MAX_GROUP_SIZE);\n\n  queue_move_to_end(poll_group_queue, &poll_group->queue_node);\n\n  /* Poll groups are currently only freed when the epoll port is closed. */\n}\n\nWEPOLL_INTERNAL sock_state_t* sock_new(port_state_t* port_state,\n                                       SOCKET socket);\nWEPOLL_INTERNAL void sock_delete(port_state_t* port_state,\n                                 sock_state_t* sock_state);\nWEPOLL_INTERNAL void sock_force_delete(port_state_t* port_state,\n                                       sock_state_t* sock_state);\n\nWEPOLL_INTERNAL int sock_set_event(port_state_t* port_state,\n                                   sock_state_t* sock_state,\n                                   const struct epoll_event* ev);\n\nWEPOLL_INTERNAL int sock_update(port_state_t* port_state,\n                                sock_state_t* sock_state);\nWEPOLL_INTERNAL int sock_feed_event(port_state_t* port_state,\n                                    IO_STATUS_BLOCK* io_status_block,\n                                    struct epoll_event* ev);\n\nWEPOLL_INTERNAL sock_state_t* sock_state_from_queue_node(\n    queue_node_t* queue_node);\nWEPOLL_INTERNAL queue_node_t* sock_state_to_queue_node(\n    sock_state_t* sock_state);\nWEPOLL_INTERNAL sock_state_t* sock_state_from_tree_node(\n    tree_node_t* tree_node);\nWEPOLL_INTERNAL tree_node_t* sock_state_to_tree_node(sock_state_t* sock_state);\n\n#define PORT__MAX_ON_STACK_COMPLETIONS 256\n\ntypedef struct port_state {\n  HANDLE iocp_handle;\n  tree_t sock_tree;\n  queue_t sock_update_queue;\n  queue_t sock_deleted_queue;\n  queue_t poll_group_queue;\n  ts_tree_node_t handle_tree_node;\n  CRITICAL_SECTION lock;\n  size_t active_poll_count;\n} port_state_t;\n\nstatic inline port_state_t* port__alloc(void) {\n  port_state_t* port_state = malloc(sizeof *port_state);\n  if (port_state == NULL)\n    return_set_error(NULL, ERROR_NOT_ENOUGH_MEMORY);\n\n  return port_state;\n}\n\nstatic inline void port__free(port_state_t* port) {\n  assert(port != NULL);\n  free(port);\n}\n\nstatic inline HANDLE port__create_iocp(void) {\n  HANDLE iocp_handle =\n      CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);\n  if (iocp_handle == NULL)\n    return_map_error(NULL);\n\n  return iocp_handle;\n}\n\nport_state_t* port_new(HANDLE* iocp_handle_out) {\n  port_state_t* port_state;\n  HANDLE iocp_handle;\n\n  port_state = port__alloc();\n  if (port_state == NULL)\n    goto err1;\n\n  iocp_handle = port__create_iocp();\n  if (iocp_handle == NULL)\n    goto err2;\n\n  memset(port_state, 0, sizeof *port_state);\n\n  port_state->iocp_handle = iocp_handle;\n  tree_init(&port_state->sock_tree);\n  queue_init(&port_state->sock_update_queue);\n  queue_init(&port_state->sock_deleted_queue);\n  queue_init(&port_state->poll_group_queue);\n  ts_tree_node_init(&port_state->handle_tree_node);\n  InitializeCriticalSection(&port_state->lock);\n\n  *iocp_handle_out = iocp_handle;\n  return port_state;\n\nerr2:\n  port__free(port_state);\nerr1:\n  return NULL;\n}\n\nstatic inline int port__close_iocp(port_state_t* port_state) {\n  HANDLE iocp_handle = port_state->iocp_handle;\n  port_state->iocp_handle = NULL;\n\n  if (!CloseHandle(iocp_handle))\n    return_map_error(-1);\n\n  return 0;\n}\n\nint port_close(port_state_t* port_state) {\n  int result;\n\n  EnterCriticalSection(&port_state->lock);\n  result = port__close_iocp(port_state);\n  LeaveCriticalSection(&port_state->lock);\n\n  return result;\n}\n\nint port_delete(port_state_t* port_state) {\n  tree_node_t* tree_node;\n  queue_node_t* queue_node;\n\n  /* At this point the IOCP port should have been closed. */\n  assert(port_state->iocp_handle == NULL);\n\n  while ((tree_node = tree_root(&port_state->sock_tree)) != NULL) {\n    sock_state_t* sock_state = sock_state_from_tree_node(tree_node);\n    sock_force_delete(port_state, sock_state);\n  }\n\n  while ((queue_node = queue_first(&port_state->sock_deleted_queue)) != NULL) {\n    sock_state_t* sock_state = sock_state_from_queue_node(queue_node);\n    sock_force_delete(port_state, sock_state);\n  }\n\n  while ((queue_node = queue_first(&port_state->poll_group_queue)) != NULL) {\n    poll_group_t* poll_group = poll_group_from_queue_node(queue_node);\n    poll_group_delete(poll_group);\n  }\n\n  assert(queue_is_empty(&port_state->sock_update_queue));\n\n  DeleteCriticalSection(&port_state->lock);\n\n  port__free(port_state);\n\n  return 0;\n}\n\nstatic int port__update_events(port_state_t* port_state) {\n  queue_t* sock_update_queue = &port_state->sock_update_queue;\n\n  /* Walk the queue, submitting new poll requests for every socket that needs\n   * it. */\n  while (!queue_is_empty(sock_update_queue)) {\n    queue_node_t* queue_node = queue_first(sock_update_queue);\n    sock_state_t* sock_state = sock_state_from_queue_node(queue_node);\n\n    if (sock_update(port_state, sock_state) < 0)\n      return -1;\n\n    /* sock_update() removes the socket from the update queue. */\n  }\n\n  return 0;\n}\n\nstatic inline void port__update_events_if_polling(port_state_t* port_state) {\n  if (port_state->active_poll_count > 0)\n    port__update_events(port_state);\n}\n\nstatic inline int port__feed_events(port_state_t* port_state,\n                                    struct epoll_event* epoll_events,\n                                    OVERLAPPED_ENTRY* iocp_events,\n                                    DWORD iocp_event_count) {\n  int epoll_event_count = 0;\n  DWORD i;\n\n  for (i = 0; i < iocp_event_count; i++) {\n    IO_STATUS_BLOCK* io_status_block =\n        (IO_STATUS_BLOCK*) iocp_events[i].lpOverlapped;\n    struct epoll_event* ev = &epoll_events[epoll_event_count];\n\n    epoll_event_count += sock_feed_event(port_state, io_status_block, ev);\n  }\n\n  return epoll_event_count;\n}\n\nstatic inline int port__poll(port_state_t* port_state,\n                             struct epoll_event* epoll_events,\n                             OVERLAPPED_ENTRY* iocp_events,\n                             DWORD maxevents,\n                             DWORD timeout) {\n  DWORD completion_count;\n\n  if (port__update_events(port_state) < 0)\n    return -1;\n\n  port_state->active_poll_count++;\n\n  LeaveCriticalSection(&port_state->lock);\n\n  BOOL r = GetQueuedCompletionStatusEx(port_state->iocp_handle,\n                                       iocp_events,\n                                       maxevents,\n                                       &completion_count,\n                                       timeout,\n                                       FALSE);\n\n  EnterCriticalSection(&port_state->lock);\n\n  port_state->active_poll_count--;\n\n  if (!r)\n    return_map_error(-1);\n\n  return port__feed_events(\n      port_state, epoll_events, iocp_events, completion_count);\n}\n\nint port_wait(port_state_t* port_state,\n              struct epoll_event* events,\n              int maxevents,\n              int timeout) {\n  OVERLAPPED_ENTRY stack_iocp_events[PORT__MAX_ON_STACK_COMPLETIONS];\n  OVERLAPPED_ENTRY* iocp_events;\n  uint64_t due = 0;\n  DWORD gqcs_timeout;\n  int result;\n\n  /* Check whether `maxevents` is in range. */\n  if (maxevents <= 0)\n    return_set_error(-1, ERROR_INVALID_PARAMETER);\n\n  /* Decide whether the IOCP completion list can live on the stack, or allocate\n   * memory for it on the heap. */\n  if ((size_t) maxevents <= array_count(stack_iocp_events)) {\n    iocp_events = stack_iocp_events;\n  } else if ((iocp_events =\n                  malloc((size_t) maxevents * sizeof *iocp_events)) == NULL) {\n    iocp_events = stack_iocp_events;\n    maxevents = array_count(stack_iocp_events);\n  }\n\n  /* Compute the timeout for GetQueuedCompletionStatus, and the wait end\n   * time, if the user specified a timeout other than zero or infinite. */\n  if (timeout > 0) {\n    due = GetTickCount64() + (uint64_t) timeout;\n    gqcs_timeout = (DWORD) timeout;\n  } else if (timeout == 0) {\n    gqcs_timeout = 0;\n  } else {\n    gqcs_timeout = INFINITE;\n  }\n\n  EnterCriticalSection(&port_state->lock);\n\n  /* Dequeue completion packets until either at least one interesting event\n   * has been discovered, or the timeout is reached. */\n  for (;;) {\n    uint64_t now;\n\n    result = port__poll(\n        port_state, events, iocp_events, (DWORD) maxevents, gqcs_timeout);\n    if (result < 0 || result > 0)\n      break; /* Result, error, or time-out. */\n\n    if (timeout < 0)\n      continue; /* When timeout is negative, never time out. */\n\n    /* Update time. */\n    now = GetTickCount64();\n\n    /* Do not allow the due time to be in the past. */\n    if (now >= due) {\n      SetLastError(WAIT_TIMEOUT);\n      break;\n    }\n\n    /* Recompute time-out argument for GetQueuedCompletionStatus. */\n    gqcs_timeout = (DWORD)(due - now);\n  }\n\n  port__update_events_if_polling(port_state);\n\n  LeaveCriticalSection(&port_state->lock);\n\n  if (iocp_events != stack_iocp_events)\n    free(iocp_events);\n\n  if (result >= 0)\n    return result;\n  else if (GetLastError() == WAIT_TIMEOUT)\n    return 0;\n  else\n    return -1;\n}\n\nstatic inline int port__ctl_add(port_state_t* port_state,\n                                SOCKET sock,\n                                struct epoll_event* ev) {\n  sock_state_t* sock_state = sock_new(port_state, sock);\n  if (sock_state == NULL)\n    return -1;\n\n  if (sock_set_event(port_state, sock_state, ev) < 0) {\n    sock_delete(port_state, sock_state);\n    return -1;\n  }\n\n  port__update_events_if_polling(port_state);\n\n  return 0;\n}\n\nstatic inline int port__ctl_mod(port_state_t* port_state,\n                                SOCKET sock,\n                                struct epoll_event* ev) {\n  sock_state_t* sock_state = port_find_socket(port_state, sock);\n  if (sock_state == NULL)\n    return -1;\n\n  if (sock_set_event(port_state, sock_state, ev) < 0)\n    return -1;\n\n  port__update_events_if_polling(port_state);\n\n  return 0;\n}\n\nstatic inline int port__ctl_del(port_state_t* port_state, SOCKET sock) {\n  sock_state_t* sock_state = port_find_socket(port_state, sock);\n  if (sock_state == NULL)\n    return -1;\n\n  sock_delete(port_state, sock_state);\n\n  return 0;\n}\n\nstatic inline int port__ctl_op(port_state_t* port_state,\n                               int op,\n                               SOCKET sock,\n                               struct epoll_event* ev) {\n  switch (op) {\n    case EPOLL_CTL_ADD:\n      return port__ctl_add(port_state, sock, ev);\n    case EPOLL_CTL_MOD:\n      return port__ctl_mod(port_state, sock, ev);\n    case EPOLL_CTL_DEL:\n      return port__ctl_del(port_state, sock);\n    default:\n      return_set_error(-1, ERROR_INVALID_PARAMETER);\n  }\n}\n\nint port_ctl(port_state_t* port_state,\n             int op,\n             SOCKET sock,\n             struct epoll_event* ev) {\n  int result;\n\n  EnterCriticalSection(&port_state->lock);\n  result = port__ctl_op(port_state, op, sock, ev);\n  LeaveCriticalSection(&port_state->lock);\n\n  return result;\n}\n\nint port_register_socket(port_state_t* port_state,\n                         sock_state_t* sock_state,\n                         SOCKET socket) {\n  if (tree_add(&port_state->sock_tree,\n               sock_state_to_tree_node(sock_state),\n               socket) < 0)\n    return_set_error(-1, ERROR_ALREADY_EXISTS);\n  return 0;\n}\n\nvoid port_unregister_socket(port_state_t* port_state,\n                            sock_state_t* sock_state) {\n  tree_del(&port_state->sock_tree, sock_state_to_tree_node(sock_state));\n}\n\nsock_state_t* port_find_socket(port_state_t* port_state, SOCKET socket) {\n  tree_node_t* tree_node = tree_find(&port_state->sock_tree, socket);\n  if (tree_node == NULL)\n    return_set_error(NULL, ERROR_NOT_FOUND);\n  return sock_state_from_tree_node(tree_node);\n}\n\nvoid port_request_socket_update(port_state_t* port_state,\n                                sock_state_t* sock_state) {\n  if (queue_is_enqueued(sock_state_to_queue_node(sock_state)))\n    return;\n  queue_append(&port_state->sock_update_queue,\n               sock_state_to_queue_node(sock_state));\n}\n\nvoid port_cancel_socket_update(port_state_t* port_state,\n                               sock_state_t* sock_state) {\n  unused_var(port_state);\n  if (!queue_is_enqueued(sock_state_to_queue_node(sock_state)))\n    return;\n  queue_remove(sock_state_to_queue_node(sock_state));\n}\n\nvoid port_add_deleted_socket(port_state_t* port_state,\n                             sock_state_t* sock_state) {\n  if (queue_is_enqueued(sock_state_to_queue_node(sock_state)))\n    return;\n  queue_append(&port_state->sock_deleted_queue,\n               sock_state_to_queue_node(sock_state));\n}\n\nvoid port_remove_deleted_socket(port_state_t* port_state,\n                                sock_state_t* sock_state) {\n  unused_var(port_state);\n  if (!queue_is_enqueued(sock_state_to_queue_node(sock_state)))\n    return;\n  queue_remove(sock_state_to_queue_node(sock_state));\n}\n\nHANDLE port_get_iocp_handle(port_state_t* port_state) {\n  assert(port_state->iocp_handle != NULL);\n  return port_state->iocp_handle;\n}\n\nqueue_t* port_get_poll_group_queue(port_state_t* port_state) {\n  return &port_state->poll_group_queue;\n}\n\nport_state_t* port_state_from_handle_tree_node(ts_tree_node_t* tree_node) {\n  return container_of(tree_node, port_state_t, handle_tree_node);\n}\n\nts_tree_node_t* port_state_to_handle_tree_node(port_state_t* port_state) {\n  return &port_state->handle_tree_node;\n}\n\nvoid queue_init(queue_t* queue) {\n  queue_node_init(&queue->head);\n}\n\nvoid queue_node_init(queue_node_t* node) {\n  node->prev = node;\n  node->next = node;\n}\n\nstatic inline void queue__detach_node(queue_node_t* node) {\n  node->prev->next = node->next;\n  node->next->prev = node->prev;\n}\n\nqueue_node_t* queue_first(const queue_t* queue) {\n  return !queue_is_empty(queue) ? queue->head.next : NULL;\n}\n\nqueue_node_t* queue_last(const queue_t* queue) {\n  return !queue_is_empty(queue) ? queue->head.prev : NULL;\n}\n\nvoid queue_prepend(queue_t* queue, queue_node_t* node) {\n  node->next = queue->head.next;\n  node->prev = &queue->head;\n  node->next->prev = node;\n  queue->head.next = node;\n}\n\nvoid queue_append(queue_t* queue, queue_node_t* node) {\n  node->next = &queue->head;\n  node->prev = queue->head.prev;\n  node->prev->next = node;\n  queue->head.prev = node;\n}\n\nvoid queue_move_to_start(queue_t* queue, queue_node_t* node) {\n  queue__detach_node(node);\n  queue_prepend(queue, node);\n}\n\nvoid queue_move_to_end(queue_t* queue, queue_node_t* node) {\n  queue__detach_node(node);\n  queue_append(queue, node);\n}\n\nvoid queue_remove(queue_node_t* node) {\n  queue__detach_node(node);\n  queue_node_init(node);\n}\n\nbool queue_is_empty(const queue_t* queue) {\n  return !queue_is_enqueued(&queue->head);\n}\n\nbool queue_is_enqueued(const queue_node_t* node) {\n  return node->prev != node;\n}\n\n#define REFLOCK__REF          ((long) 0x00000001UL)\n#define REFLOCK__REF_MASK     ((long) 0x0fffffffUL)\n#define REFLOCK__DESTROY      ((long) 0x10000000UL)\n#define REFLOCK__DESTROY_MASK ((long) 0xf0000000UL)\n#define REFLOCK__POISON       ((long) 0x300dead0UL)\n\nstatic HANDLE reflock__keyed_event = NULL;\n\nint reflock_global_init(void) {\n  NTSTATUS status = NtCreateKeyedEvent(\n      &reflock__keyed_event, KEYEDEVENT_ALL_ACCESS, NULL, 0);\n  if (status != STATUS_SUCCESS)\n    return_set_error(-1, RtlNtStatusToDosError(status));\n  return 0;\n}\n\nvoid reflock_init(reflock_t* reflock) {\n  reflock->state = 0;\n}\n\nstatic void reflock__signal_event(void* address) {\n  NTSTATUS status =\n      NtReleaseKeyedEvent(reflock__keyed_event, address, FALSE, NULL);\n  if (status != STATUS_SUCCESS)\n    abort();\n}\n\nstatic void reflock__await_event(void* address) {\n  NTSTATUS status =\n      NtWaitForKeyedEvent(reflock__keyed_event, address, FALSE, NULL);\n  if (status != STATUS_SUCCESS)\n    abort();\n}\n\nvoid reflock_ref(reflock_t* reflock) {\n  long state = InterlockedAdd(&reflock->state, REFLOCK__REF);\n\n  /* Verify that the counter didn't overflow and the lock isn't destroyed. */\n  assert((state & REFLOCK__DESTROY_MASK) == 0);\n  unused_var(state);\n}\n\nvoid reflock_unref(reflock_t* reflock) {\n  long state = InterlockedAdd(&reflock->state, -REFLOCK__REF);\n\n  /* Verify that the lock was referenced and not already destroyed. */\n  assert((state & REFLOCK__DESTROY_MASK & ~REFLOCK__DESTROY) == 0);\n\n  if (state == REFLOCK__DESTROY)\n    reflock__signal_event(reflock);\n}\n\nvoid reflock_unref_and_destroy(reflock_t* reflock) {\n  long state =\n      InterlockedAdd(&reflock->state, REFLOCK__DESTROY - REFLOCK__REF);\n  long ref_count = state & REFLOCK__REF_MASK;\n\n  /* Verify that the lock was referenced and not already destroyed. */\n  assert((state & REFLOCK__DESTROY_MASK) == REFLOCK__DESTROY);\n\n  if (ref_count != 0)\n    reflock__await_event(reflock);\n\n  state = InterlockedExchange(&reflock->state, REFLOCK__POISON);\n  assert(state == REFLOCK__DESTROY);\n}\n\n#define SOCK__KNOWN_EPOLL_EVENTS                                       \\\n  (EPOLLIN | EPOLLPRI | EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLRDNORM | \\\n   EPOLLRDBAND | EPOLLWRNORM | EPOLLWRBAND | EPOLLMSG | EPOLLRDHUP)\n\ntypedef enum sock__poll_status {\n  SOCK__POLL_IDLE = 0,\n  SOCK__POLL_PENDING,\n  SOCK__POLL_CANCELLED\n} sock__poll_status_t;\n\ntypedef struct sock_state {\n  IO_STATUS_BLOCK io_status_block;\n  AFD_POLL_INFO poll_info;\n  queue_node_t queue_node;\n  tree_node_t tree_node;\n  poll_group_t* poll_group;\n  SOCKET base_socket;\n  epoll_data_t user_data;\n  uint32_t user_events;\n  uint32_t pending_events;\n  sock__poll_status_t poll_status;\n  bool delete_pending;\n} sock_state_t;\n\nstatic inline sock_state_t* sock__alloc(void) {\n  sock_state_t* sock_state = malloc(sizeof *sock_state);\n  if (sock_state == NULL)\n    return_set_error(NULL, ERROR_NOT_ENOUGH_MEMORY);\n  return sock_state;\n}\n\nstatic inline void sock__free(sock_state_t* sock_state) {\n  assert(sock_state != NULL);\n  free(sock_state);\n}\n\nstatic inline int sock__cancel_poll(sock_state_t* sock_state) {\n  assert(sock_state->poll_status == SOCK__POLL_PENDING);\n\n  if (afd_cancel_poll(poll_group_get_afd_device_handle(sock_state->poll_group),\n                      &sock_state->io_status_block) < 0)\n    return -1;\n\n  sock_state->poll_status = SOCK__POLL_CANCELLED;\n  sock_state->pending_events = 0;\n  return 0;\n}\n\nsock_state_t* sock_new(port_state_t* port_state, SOCKET socket) {\n  SOCKET base_socket;\n  poll_group_t* poll_group;\n  sock_state_t* sock_state;\n\n  if (socket == 0 || socket == INVALID_SOCKET)\n    return_set_error(NULL, ERROR_INVALID_HANDLE);\n\n  base_socket = ws_get_base_socket(socket);\n  if (base_socket == INVALID_SOCKET)\n    return NULL;\n\n  poll_group = poll_group_acquire(port_state);\n  if (poll_group == NULL)\n    return NULL;\n\n  sock_state = sock__alloc();\n  if (sock_state == NULL)\n    goto err1;\n\n  memset(sock_state, 0, sizeof *sock_state);\n\n  sock_state->base_socket = base_socket;\n  sock_state->poll_group = poll_group;\n\n  tree_node_init(&sock_state->tree_node);\n  queue_node_init(&sock_state->queue_node);\n\n  if (port_register_socket(port_state, sock_state, socket) < 0)\n    goto err2;\n\n  return sock_state;\n\nerr2:\n  sock__free(sock_state);\nerr1:\n  poll_group_release(poll_group);\n\n  return NULL;\n}\n\nstatic int sock__delete(port_state_t* port_state,\n                        sock_state_t* sock_state,\n                        bool force) {\n  if (!sock_state->delete_pending) {\n    if (sock_state->poll_status == SOCK__POLL_PENDING)\n      sock__cancel_poll(sock_state);\n\n    port_cancel_socket_update(port_state, sock_state);\n    port_unregister_socket(port_state, sock_state);\n\n    sock_state->delete_pending = true;\n  }\n\n  /* If the poll request still needs to complete, the sock_state object can't\n   * be free()d yet. `sock_feed_event()` or `port_close()` will take care\n   * of this later. */\n  if (force || sock_state->poll_status == SOCK__POLL_IDLE) {\n    /* Free the sock_state now. */\n    port_remove_deleted_socket(port_state, sock_state);\n    poll_group_release(sock_state->poll_group);\n    sock__free(sock_state);\n  } else {\n    /* Free the socket later. */\n    port_add_deleted_socket(port_state, sock_state);\n  }\n\n  return 0;\n}\n\nvoid sock_delete(port_state_t* port_state, sock_state_t* sock_state) {\n  sock__delete(port_state, sock_state, false);\n}\n\nvoid sock_force_delete(port_state_t* port_state, sock_state_t* sock_state) {\n  sock__delete(port_state, sock_state, true);\n}\n\nint sock_set_event(port_state_t* port_state,\n                   sock_state_t* sock_state,\n                   const struct epoll_event* ev) {\n  /* EPOLLERR and EPOLLHUP are always reported, even when not requested by the\n   * caller. However they are disabled after a event has been reported for a\n   * socket for which the EPOLLONESHOT flag was set. */\n  uint32_t events = ev->events | EPOLLERR | EPOLLHUP;\n\n  sock_state->user_events = events;\n  sock_state->user_data = ev->data;\n\n  if ((events & SOCK__KNOWN_EPOLL_EVENTS & ~sock_state->pending_events) != 0)\n    port_request_socket_update(port_state, sock_state);\n\n  return 0;\n}\n\nstatic inline DWORD sock__epoll_events_to_afd_events(uint32_t epoll_events) {\n  /* Always monitor for AFD_POLL_LOCAL_CLOSE, which is triggered when the\n   * socket is closed with closesocket() or CloseHandle(). */\n  DWORD afd_events = AFD_POLL_LOCAL_CLOSE;\n\n  if (epoll_events & (EPOLLIN | EPOLLRDNORM))\n    afd_events |= AFD_POLL_RECEIVE | AFD_POLL_ACCEPT;\n  if (epoll_events & (EPOLLPRI | EPOLLRDBAND))\n    afd_events |= AFD_POLL_RECEIVE_EXPEDITED;\n  if (epoll_events & (EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND))\n    afd_events |= AFD_POLL_SEND;\n  if (epoll_events & (EPOLLIN | EPOLLRDNORM | EPOLLRDHUP))\n    afd_events |= AFD_POLL_DISCONNECT;\n  if (epoll_events & EPOLLHUP)\n    afd_events |= AFD_POLL_ABORT;\n  if (epoll_events & EPOLLERR)\n    afd_events |= AFD_POLL_CONNECT_FAIL;\n\n  return afd_events;\n}\n\nstatic inline uint32_t sock__afd_events_to_epoll_events(DWORD afd_events) {\n  uint32_t epoll_events = 0;\n\n  if (afd_events & (AFD_POLL_RECEIVE | AFD_POLL_ACCEPT))\n    epoll_events |= EPOLLIN | EPOLLRDNORM;\n  if (afd_events & AFD_POLL_RECEIVE_EXPEDITED)\n    epoll_events |= EPOLLPRI | EPOLLRDBAND;\n  if (afd_events & AFD_POLL_SEND)\n    epoll_events |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;\n  if (afd_events & AFD_POLL_DISCONNECT)\n    epoll_events |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;\n  if (afd_events & AFD_POLL_ABORT)\n    epoll_events |= EPOLLHUP;\n  if (afd_events & AFD_POLL_CONNECT_FAIL)\n    /* Linux reports all these events after connect() has failed. */\n    epoll_events |=\n        EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLRDNORM | EPOLLWRNORM | EPOLLRDHUP;\n\n  return epoll_events;\n}\n\nint sock_update(port_state_t* port_state, sock_state_t* sock_state) {\n  assert(!sock_state->delete_pending);\n\n  if ((sock_state->poll_status == SOCK__POLL_PENDING) &&\n      (sock_state->user_events & SOCK__KNOWN_EPOLL_EVENTS &\n       ~sock_state->pending_events) == 0) {\n    /* All the events the user is interested in are already being monitored by\n     * the pending poll operation. It might spuriously complete because of an\n     * event that we're no longer interested in; when that happens we'll submit\n     * a new poll operation with the updated event mask. */\n\n  } else if (sock_state->poll_status == SOCK__POLL_PENDING) {\n    /* A poll operation is already pending, but it's not monitoring for all the\n     * events that the user is interested in. Therefore, cancel the pending\n     * poll operation; when we receive it's completion package, a new poll\n     * operation will be submitted with the correct event mask. */\n    if (sock__cancel_poll(sock_state) < 0)\n      return -1;\n\n  } else if (sock_state->poll_status == SOCK__POLL_CANCELLED) {\n    /* The poll operation has already been cancelled, we're still waiting for\n     * it to return. For now, there's nothing that needs to be done. */\n\n  } else if (sock_state->poll_status == SOCK__POLL_IDLE) {\n    /* No poll operation is pending; start one. */\n    sock_state->poll_info.Exclusive = FALSE;\n    sock_state->poll_info.NumberOfHandles = 1;\n    sock_state->poll_info.Timeout.QuadPart = INT64_MAX;\n    sock_state->poll_info.Handles[0].Handle = (HANDLE) sock_state->base_socket;\n    sock_state->poll_info.Handles[0].Status = 0;\n    sock_state->poll_info.Handles[0].Events =\n        sock__epoll_events_to_afd_events(sock_state->user_events);\n\n    if (afd_poll(poll_group_get_afd_device_handle(sock_state->poll_group),\n                 &sock_state->poll_info,\n                 &sock_state->io_status_block) < 0) {\n      switch (GetLastError()) {\n        case ERROR_IO_PENDING:\n          /* Overlapped poll operation in progress; this is expected. */\n          break;\n        case ERROR_INVALID_HANDLE:\n          /* Socket closed; it'll be dropped from the epoll set. */\n          return sock__delete(port_state, sock_state, false);\n        default:\n          /* Other errors are propagated to the caller. */\n          return_map_error(-1);\n      }\n    }\n\n    /* The poll request was successfully submitted. */\n    sock_state->poll_status = SOCK__POLL_PENDING;\n    sock_state->pending_events = sock_state->user_events;\n\n  } else {\n    /* Unreachable. */\n    assert(false);\n  }\n\n  port_cancel_socket_update(port_state, sock_state);\n  return 0;\n}\n\nint sock_feed_event(port_state_t* port_state,\n                    IO_STATUS_BLOCK* io_status_block,\n                    struct epoll_event* ev) {\n  sock_state_t* sock_state =\n      container_of(io_status_block, sock_state_t, io_status_block);\n  AFD_POLL_INFO* poll_info = &sock_state->poll_info;\n  uint32_t epoll_events = 0;\n\n  sock_state->poll_status = SOCK__POLL_IDLE;\n  sock_state->pending_events = 0;\n\n  if (sock_state->delete_pending) {\n    /* Socket has been deleted earlier and can now be freed. */\n    return sock__delete(port_state, sock_state, false);\n\n  } else if (io_status_block->Status == STATUS_CANCELLED) {\n    /* The poll request was cancelled by CancelIoEx. */\n\n  } else if (!NT_SUCCESS(io_status_block->Status)) {\n    /* The overlapped request itself failed in an unexpected way. */\n    epoll_events = EPOLLERR;\n\n  } else if (poll_info->NumberOfHandles < 1) {\n    /* This poll operation succeeded but didn't report any socket events. */\n\n  } else if (poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {\n    /* The poll operation reported that the socket was closed. */\n    return sock__delete(port_state, sock_state, false);\n\n  } else {\n    /* Events related to our socket were reported. */\n    epoll_events =\n        sock__afd_events_to_epoll_events(poll_info->Handles[0].Events);\n  }\n\n  /* Requeue the socket so a new poll request will be submitted. */\n  port_request_socket_update(port_state, sock_state);\n\n  /* Filter out events that the user didn't ask for. */\n  epoll_events &= sock_state->user_events;\n\n  /* Return if there are no epoll events to report. */\n  if (epoll_events == 0)\n    return 0;\n\n  /* If the the socket has the EPOLLONESHOT flag set, unmonitor all events,\n   * even EPOLLERR and EPOLLHUP. But always keep looking for closed sockets. */\n  if (sock_state->user_events & EPOLLONESHOT)\n    sock_state->user_events = 0;\n\n  ev->data = sock_state->user_data;\n  ev->events = epoll_events;\n  return 1;\n}\n\nsock_state_t* sock_state_from_queue_node(queue_node_t* queue_node) {\n  return container_of(queue_node, sock_state_t, queue_node);\n}\n\nqueue_node_t* sock_state_to_queue_node(sock_state_t* sock_state) {\n  return &sock_state->queue_node;\n}\n\nsock_state_t* sock_state_from_tree_node(tree_node_t* tree_node) {\n  return container_of(tree_node, sock_state_t, tree_node);\n}\n\ntree_node_t* sock_state_to_tree_node(sock_state_t* sock_state) {\n  return &sock_state->tree_node;\n}\n\nvoid ts_tree_init(ts_tree_t* ts_tree) {\n  tree_init(&ts_tree->tree);\n  InitializeSRWLock(&ts_tree->lock);\n}\n\nvoid ts_tree_node_init(ts_tree_node_t* node) {\n  tree_node_init(&node->tree_node);\n  reflock_init(&node->reflock);\n}\n\nint ts_tree_add(ts_tree_t* ts_tree, ts_tree_node_t* node, uintptr_t key) {\n  int r;\n\n  AcquireSRWLockExclusive(&ts_tree->lock);\n  r = tree_add(&ts_tree->tree, &node->tree_node, key);\n  ReleaseSRWLockExclusive(&ts_tree->lock);\n\n  return r;\n}\n\nstatic inline ts_tree_node_t* ts_tree__find_node(ts_tree_t* ts_tree,\n                                                 uintptr_t key) {\n  tree_node_t* tree_node = tree_find(&ts_tree->tree, key);\n  if (tree_node == NULL)\n    return NULL;\n\n  return container_of(tree_node, ts_tree_node_t, tree_node);\n}\n\nts_tree_node_t* ts_tree_del_and_ref(ts_tree_t* ts_tree, uintptr_t key) {\n  ts_tree_node_t* ts_tree_node;\n\n  AcquireSRWLockExclusive(&ts_tree->lock);\n\n  ts_tree_node = ts_tree__find_node(ts_tree, key);\n  if (ts_tree_node != NULL) {\n    tree_del(&ts_tree->tree, &ts_tree_node->tree_node);\n    reflock_ref(&ts_tree_node->reflock);\n  }\n\n  ReleaseSRWLockExclusive(&ts_tree->lock);\n\n  return ts_tree_node;\n}\n\nts_tree_node_t* ts_tree_find_and_ref(ts_tree_t* ts_tree, uintptr_t key) {\n  ts_tree_node_t* ts_tree_node;\n\n  AcquireSRWLockShared(&ts_tree->lock);\n\n  ts_tree_node = ts_tree__find_node(ts_tree, key);\n  if (ts_tree_node != NULL)\n    reflock_ref(&ts_tree_node->reflock);\n\n  ReleaseSRWLockShared(&ts_tree->lock);\n\n  return ts_tree_node;\n}\n\nvoid ts_tree_node_unref(ts_tree_node_t* node) {\n  reflock_unref(&node->reflock);\n}\n\nvoid ts_tree_node_unref_and_destroy(ts_tree_node_t* node) {\n  reflock_unref_and_destroy(&node->reflock);\n}\n\nvoid tree_init(tree_t* tree) {\n  memset(tree, 0, sizeof *tree);\n}\n\nvoid tree_node_init(tree_node_t* node) {\n  memset(node, 0, sizeof *node);\n}\n\n#define TREE__ROTATE(cis, trans)   \\\n  tree_node_t* p = node;           \\\n  tree_node_t* q = node->trans;    \\\n  tree_node_t* parent = p->parent; \\\n                                   \\\n  if (parent) {                    \\\n    if (parent->left == p)         \\\n      parent->left = q;            \\\n    else                           \\\n      parent->right = q;           \\\n  } else {                         \\\n    tree->root = q;                \\\n  }                                \\\n                                   \\\n  q->parent = parent;              \\\n  p->parent = q;                   \\\n  p->trans = q->cis;               \\\n  if (p->trans)                    \\\n    p->trans->parent = p;          \\\n  q->cis = p;\n\nstatic inline void tree__rotate_left(tree_t* tree, tree_node_t* node) {\n  TREE__ROTATE(left, right)\n}\n\nstatic inline void tree__rotate_right(tree_t* tree, tree_node_t* node) {\n  TREE__ROTATE(right, left)\n}\n\n#define TREE__INSERT_OR_DESCEND(side) \\\n  if (parent->side) {                 \\\n    parent = parent->side;            \\\n  } else {                            \\\n    parent->side = node;              \\\n    break;                            \\\n  }\n\n#define TREE__REBALANCE_AFTER_INSERT(cis, trans) \\\n  tree_node_t* grandparent = parent->parent;     \\\n  tree_node_t* uncle = grandparent->trans;       \\\n                                                 \\\n  if (uncle && uncle->red) {                     \\\n    parent->red = uncle->red = false;            \\\n    grandparent->red = true;                     \\\n    node = grandparent;                          \\\n  } else {                                       \\\n    if (node == parent->trans) {                 \\\n      tree__rotate_##cis(tree, parent);          \\\n      node = parent;                             \\\n      parent = node->parent;                     \\\n    }                                            \\\n    parent->red = false;                         \\\n    grandparent->red = true;                     \\\n    tree__rotate_##trans(tree, grandparent);     \\\n  }\n\nint tree_add(tree_t* tree, tree_node_t* node, uintptr_t key) {\n  tree_node_t* parent;\n\n  parent = tree->root;\n  if (parent) {\n    for (;;) {\n      if (key < parent->key) {\n        TREE__INSERT_OR_DESCEND(left)\n      } else if (key > parent->key) {\n        TREE__INSERT_OR_DESCEND(right)\n      } else {\n        return -1;\n      }\n    }\n  } else {\n    tree->root = node;\n  }\n\n  node->key = key;\n  node->left = node->right = NULL;\n  node->parent = parent;\n  node->red = true;\n\n  for (; parent && parent->red; parent = node->parent) {\n    if (parent == parent->parent->left) {\n      TREE__REBALANCE_AFTER_INSERT(left, right)\n    } else {\n      TREE__REBALANCE_AFTER_INSERT(right, left)\n    }\n  }\n  tree->root->red = false;\n\n  return 0;\n}\n\n#define TREE__REBALANCE_AFTER_REMOVE(cis, trans)   \\\n  tree_node_t* sibling = parent->trans;            \\\n                                                   \\\n  if (sibling->red) {                              \\\n    sibling->red = false;                          \\\n    parent->red = true;                            \\\n    tree__rotate_##cis(tree, parent);              \\\n    sibling = parent->trans;                       \\\n  }                                                \\\n  if ((sibling->left && sibling->left->red) ||     \\\n      (sibling->right && sibling->right->red)) {   \\\n    if (!sibling->trans || !sibling->trans->red) { \\\n      sibling->cis->red = false;                   \\\n      sibling->red = true;                         \\\n      tree__rotate_##trans(tree, sibling);         \\\n      sibling = parent->trans;                     \\\n    }                                              \\\n    sibling->red = parent->red;                    \\\n    parent->red = sibling->trans->red = false;     \\\n    tree__rotate_##cis(tree, parent);              \\\n    node = tree->root;                             \\\n    break;                                         \\\n  }                                                \\\n  sibling->red = true;\n\nvoid tree_del(tree_t* tree, tree_node_t* node) {\n  tree_node_t* parent = node->parent;\n  tree_node_t* left = node->left;\n  tree_node_t* right = node->right;\n  tree_node_t* next;\n  bool red;\n\n  if (!left) {\n    next = right;\n  } else if (!right) {\n    next = left;\n  } else {\n    next = right;\n    while (next->left)\n      next = next->left;\n  }\n\n  if (parent) {\n    if (parent->left == node)\n      parent->left = next;\n    else\n      parent->right = next;\n  } else {\n    tree->root = next;\n  }\n\n  if (left && right) {\n    red = next->red;\n    next->red = node->red;\n    next->left = left;\n    left->parent = next;\n    if (next != right) {\n      parent = next->parent;\n      next->parent = node->parent;\n      node = next->right;\n      parent->left = node;\n      next->right = right;\n      right->parent = next;\n    } else {\n      next->parent = parent;\n      parent = next;\n      node = next->right;\n    }\n  } else {\n    red = node->red;\n    node = next;\n  }\n\n  if (node)\n    node->parent = parent;\n  if (red)\n    return;\n  if (node && node->red) {\n    node->red = false;\n    return;\n  }\n\n  do {\n    if (node == tree->root)\n      break;\n    if (node == parent->left) {\n      TREE__REBALANCE_AFTER_REMOVE(left, right)\n    } else {\n      TREE__REBALANCE_AFTER_REMOVE(right, left)\n    }\n    node = parent;\n    parent = parent->parent;\n  } while (!node->red);\n\n  if (node)\n    node->red = false;\n}\n\ntree_node_t* tree_find(const tree_t* tree, uintptr_t key) {\n  tree_node_t* node = tree->root;\n  while (node) {\n    if (key < node->key)\n      node = node->left;\n    else if (key > node->key)\n      node = node->right;\n    else\n      return node;\n  }\n  return NULL;\n}\n\ntree_node_t* tree_root(const tree_t* tree) {\n  return tree->root;\n}\n\n#ifndef SIO_BSP_HANDLE_POLL\n#define SIO_BSP_HANDLE_POLL 0x4800001D\n#endif\n\n#ifndef SIO_BASE_HANDLE\n#define SIO_BASE_HANDLE 0x48000022\n#endif\n\nint ws_global_init(void) {\n  int r;\n  WSADATA wsa_data;\n\n  r = WSAStartup(MAKEWORD(2, 2), &wsa_data);\n  if (r != 0)\n    return_set_error(-1, (DWORD) r);\n\n  return 0;\n}\n\nstatic inline SOCKET ws__ioctl_get_bsp_socket(SOCKET socket, DWORD ioctl) {\n  SOCKET bsp_socket;\n  DWORD bytes;\n\n  if (WSAIoctl(socket,\n               ioctl,\n               NULL,\n               0,\n               &bsp_socket,\n               sizeof bsp_socket,\n               &bytes,\n               NULL,\n               NULL) != SOCKET_ERROR)\n    return bsp_socket;\n  else\n    return INVALID_SOCKET;\n}\n\nSOCKET ws_get_base_socket(SOCKET socket) {\n  SOCKET base_socket;\n  DWORD error;\n\n  for (;;) {\n    base_socket = ws__ioctl_get_bsp_socket(socket, SIO_BASE_HANDLE);\n    if (base_socket != INVALID_SOCKET)\n      return base_socket;\n\n    error = GetLastError();\n    if (error == WSAENOTSOCK)\n      return_set_error(INVALID_SOCKET, error);\n\n    /* Even though Microsoft documentation clearly states that LSPs should\n     * never intercept the `SIO_BASE_HANDLE` ioctl [1], Komodia based LSPs do\n     * so anyway, breaking it, with the apparent intention of preventing LSP\n     * bypass [2]. Fortunately they don't handle `SIO_BSP_HANDLE_POLL`, which\n     * will at least let us obtain the socket associated with the next winsock\n     * protocol chain entry. If this succeeds, loop around and call\n     * `SIO_BASE_HANDLE` again with the returned BSP socket, to make sure that\n     * we unwrap all layers and retrieve the actual base socket.\n     *  [1] https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls\n     *  [2] https://www.komodia.com/newwiki/index.php?title=Komodia%27s_Redirector_bug_fixes#Version_2.2.2.6\n     */\n    base_socket = ws__ioctl_get_bsp_socket(socket, SIO_BSP_HANDLE_POLL);\n    if (base_socket != INVALID_SOCKET && base_socket != socket)\n      socket = base_socket;\n    else\n      return_set_error(INVALID_SOCKET, error);\n  }\n}\n"
  },
  {
    "path": "external/wepoll/wepoll.h",
    "content": "/*\n * wepoll - epoll for Windows\n * https://github.com/piscisaureus/wepoll\n *\n * Copyright 2012-2020, Bert Belder <bertbelder@gmail.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *   * Redistributions of source code must retain the above copyright\n *     notice, this list of conditions and the following disclaimer.\n *\n *   * Redistributions in binary form must reproduce the above copyright\n *     notice, this list of conditions and the following disclaimer in the\n *     documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef WEPOLL_H_\n#define WEPOLL_H_\n\n#ifndef WEPOLL_EXPORT\n#define WEPOLL_EXPORT\n#endif\n\n#include <stdint.h>\n\nenum EPOLL_EVENTS {\n  EPOLLIN      = (int) (1U <<  0),\n  EPOLLPRI     = (int) (1U <<  1),\n  EPOLLOUT     = (int) (1U <<  2),\n  EPOLLERR     = (int) (1U <<  3),\n  EPOLLHUP     = (int) (1U <<  4),\n  EPOLLRDNORM  = (int) (1U <<  6),\n  EPOLLRDBAND  = (int) (1U <<  7),\n  EPOLLWRNORM  = (int) (1U <<  8),\n  EPOLLWRBAND  = (int) (1U <<  9),\n  EPOLLMSG     = (int) (1U << 10), /* Never reported. */\n  EPOLLRDHUP   = (int) (1U << 13),\n  EPOLLONESHOT = (int) (1U << 31)\n};\n\n#define EPOLLIN      (1U <<  0)\n#define EPOLLPRI     (1U <<  1)\n#define EPOLLOUT     (1U <<  2)\n#define EPOLLERR     (1U <<  3)\n#define EPOLLHUP     (1U <<  4)\n#define EPOLLRDNORM  (1U <<  6)\n#define EPOLLRDBAND  (1U <<  7)\n#define EPOLLWRNORM  (1U <<  8)\n#define EPOLLWRBAND  (1U <<  9)\n#define EPOLLMSG     (1U << 10)\n#define EPOLLRDHUP   (1U << 13)\n#define EPOLLONESHOT (1U << 31)\n\n#define EPOLL_CTL_ADD 1\n#define EPOLL_CTL_MOD 2\n#define EPOLL_CTL_DEL 3\n\ntypedef void* HANDLE;\ntypedef uintptr_t SOCKET;\n\ntypedef union epoll_data {\n  void* ptr;\n  int fd;\n  uint32_t u32;\n  uint64_t u64;\n  SOCKET sock; /* Windows specific */\n  HANDLE hnd;  /* Windows specific */\n} epoll_data_t;\n\nstruct epoll_event {\n  uint32_t events;   /* Epoll events and flags */\n  epoll_data_t data; /* User data variable */\n};\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nWEPOLL_EXPORT HANDLE epoll_create(int size);\nWEPOLL_EXPORT HANDLE epoll_create1(int flags);\n\nWEPOLL_EXPORT int epoll_close(HANDLE ephnd);\n\nWEPOLL_EXPORT int epoll_ctl(HANDLE ephnd,\n                            int op,\n                            SOCKET sock,\n                            struct epoll_event* event);\n\nWEPOLL_EXPORT int epoll_wait(HANDLE ephnd,\n                             struct epoll_event* events,\n                             int maxevents,\n                             int timeout);\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /* WEPOLL_H_ */\n"
  },
  {
    "path": "include/zmq.h",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n/*  *************************************************************************\n    NOTE to contributors. This file comprises the principal public contract\n    for ZeroMQ API users. Any change to this file supplied in a stable\n    release SHOULD not break existing applications.\n    In practice this means that the value of constants must not change, and\n    that old values may not be reused for new constants.\n    *************************************************************************\n*/\n\n#ifndef __ZMQ_H_INCLUDED__\n#define __ZMQ_H_INCLUDED__\n\n/*  Version macros for compile-time API version detection                     */\n#define ZMQ_VERSION_MAJOR 4\n#define ZMQ_VERSION_MINOR 3\n#define ZMQ_VERSION_PATCH 6\n\n#define ZMQ_MAKE_VERSION(major, minor, patch)                                  \\\n    ((major) * 10000 + (minor) * 100 + (patch))\n#define ZMQ_VERSION                                                            \\\n    ZMQ_MAKE_VERSION (ZMQ_VERSION_MAJOR, ZMQ_VERSION_MINOR, ZMQ_VERSION_PATCH)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if !defined _WIN32_WCE\n#include <errno.h>\n#endif\n#include <stddef.h>\n#include <stdio.h>\n\n/*  Handle DSO symbol visibility                                             */\n#if defined ZMQ_NO_EXPORT\n#define ZMQ_EXPORT\n#else\n#if defined _WIN32\n#if defined ZMQ_STATIC\n#define ZMQ_EXPORT\n#elif defined DLL_EXPORT\n#define ZMQ_EXPORT __declspec (dllexport)\n#else\n#define ZMQ_EXPORT __declspec (dllimport)\n#endif\n#else\n#if defined __SUNPRO_C || defined __SUNPRO_CC\n#define ZMQ_EXPORT __global\n#elif (defined __GNUC__ && __GNUC__ >= 4) || defined __INTEL_COMPILER\n#define ZMQ_EXPORT __attribute__ ((visibility (\"default\")))\n#else\n#define ZMQ_EXPORT\n#endif\n#endif\n#endif\n\n/*  Define integer types needed for event interface                          */\n#define ZMQ_DEFINED_STDINT 1\n#if defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_OPENVMS\n#include <inttypes.h>\n#elif defined _MSC_VER && _MSC_VER < 1600\n#ifndef uint64_t\ntypedef unsigned __int64 uint64_t;\n#endif\n#ifndef int32_t\ntypedef __int32 int32_t;\n#endif\n#ifndef uint32_t\ntypedef unsigned __int32 uint32_t;\n#endif\n#ifndef uint16_t\ntypedef unsigned __int16 uint16_t;\n#endif\n#ifndef uint8_t\ntypedef unsigned __int8 uint8_t;\n#endif\n#else\n#include <stdint.h>\n#endif\n\n#if !defined _WIN32\n// needed for sigset_t definition in zmq_ppoll\n#include <signal.h>\n#endif\n\n//  32-bit AIX's pollfd struct members are called reqevents and rtnevents so it\n//  defines compatibility macros for them. Need to include that header first to\n//  stop build failures since zmq_pollset_t defines them as events and revents.\n#ifdef ZMQ_HAVE_AIX\n#include <poll.h>\n#endif\n\n\n/******************************************************************************/\n/*  0MQ errors.                                                               */\n/******************************************************************************/\n\n/*  A number random enough not to collide with different errno ranges on      */\n/*  different OSes. The assumption is that error_t is at least 32-bit type.   */\n#define ZMQ_HAUSNUMERO 156384712\n\n/*  On Windows platform some of the standard POSIX errnos are not defined.    */\n#ifndef ENOTSUP\n#define ENOTSUP (ZMQ_HAUSNUMERO + 1)\n#endif\n#ifndef EPROTONOSUPPORT\n#define EPROTONOSUPPORT (ZMQ_HAUSNUMERO + 2)\n#endif\n#ifndef ENOBUFS\n#define ENOBUFS (ZMQ_HAUSNUMERO + 3)\n#endif\n#ifndef ENETDOWN\n#define ENETDOWN (ZMQ_HAUSNUMERO + 4)\n#endif\n#ifndef EADDRINUSE\n#define EADDRINUSE (ZMQ_HAUSNUMERO + 5)\n#endif\n#ifndef EADDRNOTAVAIL\n#define EADDRNOTAVAIL (ZMQ_HAUSNUMERO + 6)\n#endif\n#ifndef ECONNREFUSED\n#define ECONNREFUSED (ZMQ_HAUSNUMERO + 7)\n#endif\n#ifndef EINPROGRESS\n#define EINPROGRESS (ZMQ_HAUSNUMERO + 8)\n#endif\n#ifndef ENOTSOCK\n#define ENOTSOCK (ZMQ_HAUSNUMERO + 9)\n#endif\n#ifndef EMSGSIZE\n#define EMSGSIZE (ZMQ_HAUSNUMERO + 10)\n#endif\n#ifndef EAFNOSUPPORT\n#define EAFNOSUPPORT (ZMQ_HAUSNUMERO + 11)\n#endif\n#ifndef ENETUNREACH\n#define ENETUNREACH (ZMQ_HAUSNUMERO + 12)\n#endif\n#ifndef ECONNABORTED\n#define ECONNABORTED (ZMQ_HAUSNUMERO + 13)\n#endif\n#ifndef ECONNRESET\n#define ECONNRESET (ZMQ_HAUSNUMERO + 14)\n#endif\n#ifndef ENOTCONN\n#define ENOTCONN (ZMQ_HAUSNUMERO + 15)\n#endif\n#ifndef ETIMEDOUT\n#define ETIMEDOUT (ZMQ_HAUSNUMERO + 16)\n#endif\n#ifndef EHOSTUNREACH\n#define EHOSTUNREACH (ZMQ_HAUSNUMERO + 17)\n#endif\n#ifndef ENETRESET\n#define ENETRESET (ZMQ_HAUSNUMERO + 18)\n#endif\n\n/*  Native 0MQ error codes.                                                   */\n#define EFSM (ZMQ_HAUSNUMERO + 51)\n#define ENOCOMPATPROTO (ZMQ_HAUSNUMERO + 52)\n#define ETERM (ZMQ_HAUSNUMERO + 53)\n#define EMTHREAD (ZMQ_HAUSNUMERO + 54)\n\n/*  This function retrieves the errno as it is known to 0MQ library. The goal */\n/*  of this function is to make the code 100% portable, including where 0MQ   */\n/*  compiled with certain CRT library (on Windows) is linked to an            */\n/*  application that uses different CRT library.                              */\nZMQ_EXPORT int zmq_errno (void);\n\n/*  Resolves system errors and 0MQ errors to human-readable string.           */\nZMQ_EXPORT const char *zmq_strerror (int errnum_);\n\n/*  Run-time API version detection                                            */\nZMQ_EXPORT void zmq_version (int *major_, int *minor_, int *patch_);\n\n/******************************************************************************/\n/*  0MQ infrastructure (a.k.a. context) initialisation & termination.         */\n/******************************************************************************/\n\n/*  Context options                                                           */\n#define ZMQ_IO_THREADS 1\n#define ZMQ_MAX_SOCKETS 2\n#define ZMQ_SOCKET_LIMIT 3\n#define ZMQ_THREAD_PRIORITY 3\n#define ZMQ_THREAD_SCHED_POLICY 4\n#define ZMQ_MAX_MSGSZ 5\n#define ZMQ_MSG_T_SIZE 6\n#define ZMQ_THREAD_AFFINITY_CPU_ADD 7\n#define ZMQ_THREAD_AFFINITY_CPU_REMOVE 8\n#define ZMQ_THREAD_NAME_PREFIX 9\n\n/*  Default for new contexts                                                  */\n#define ZMQ_IO_THREADS_DFLT 1\n#define ZMQ_MAX_SOCKETS_DFLT 1023\n#define ZMQ_THREAD_PRIORITY_DFLT -1\n#define ZMQ_THREAD_SCHED_POLICY_DFLT -1\n\nZMQ_EXPORT void *zmq_ctx_new (void);\nZMQ_EXPORT int zmq_ctx_term (void *context_);\nZMQ_EXPORT int zmq_ctx_shutdown (void *context_);\nZMQ_EXPORT int zmq_ctx_set (void *context_, int option_, int optval_);\nZMQ_EXPORT int zmq_ctx_get (void *context_, int option_);\n\n/*  Old (legacy) API                                                          */\nZMQ_EXPORT void *zmq_init (int io_threads_);\nZMQ_EXPORT int zmq_term (void *context_);\nZMQ_EXPORT int zmq_ctx_destroy (void *context_);\n\n\n/******************************************************************************/\n/*  0MQ message definition.                                                   */\n/******************************************************************************/\n\n/* Some architectures, like sparc64 and some variants of aarch64, enforce pointer\n * alignment and raise sigbus on violations. Make sure applications allocate\n * zmq_msg_t on addresses aligned on a pointer-size boundary to avoid this issue.\n */\ntypedef struct zmq_msg_t\n{\n#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))\n    __declspec (align (8)) unsigned char _[64];\n#elif defined(_MSC_VER)                                                        \\\n  && (defined(_M_IX86) || defined(_M_ARM_ARMV7VE) || defined(_M_ARM))\n    __declspec (align (4)) unsigned char _[64];\n#elif defined(__GNUC__) || defined(__INTEL_COMPILER)                           \\\n  || (defined(__SUNPRO_C) && __SUNPRO_C >= 0x590)                              \\\n  || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590)\n    unsigned char _[64] __attribute__ ((aligned (sizeof (void *))));\n#else\n    unsigned char _[64];\n#endif\n} zmq_msg_t;\n\ntypedef void (zmq_free_fn) (void *data_, void *hint_);\n\nZMQ_EXPORT int zmq_msg_init (zmq_msg_t *msg_);\nZMQ_EXPORT int zmq_msg_init_size (zmq_msg_t *msg_, size_t size_);\nZMQ_EXPORT int zmq_msg_init_data (\n  zmq_msg_t *msg_, void *data_, size_t size_, zmq_free_fn *ffn_, void *hint_);\nZMQ_EXPORT int zmq_msg_send (zmq_msg_t *msg_, void *s_, int flags_);\nZMQ_EXPORT int zmq_msg_recv (zmq_msg_t *msg_, void *s_, int flags_);\nZMQ_EXPORT int zmq_msg_close (zmq_msg_t *msg_);\nZMQ_EXPORT int zmq_msg_move (zmq_msg_t *dest_, zmq_msg_t *src_);\nZMQ_EXPORT int zmq_msg_copy (zmq_msg_t *dest_, zmq_msg_t *src_);\nZMQ_EXPORT void *zmq_msg_data (zmq_msg_t *msg_);\nZMQ_EXPORT size_t zmq_msg_size (const zmq_msg_t *msg_);\nZMQ_EXPORT int zmq_msg_more (const zmq_msg_t *msg_);\nZMQ_EXPORT int zmq_msg_get (const zmq_msg_t *msg_, int property_);\nZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg_, int property_, int optval_);\nZMQ_EXPORT const char *zmq_msg_gets (const zmq_msg_t *msg_,\n                                     const char *property_);\n\n/******************************************************************************/\n/*  0MQ socket definition.                                                    */\n/******************************************************************************/\n\n/*  Socket types.                                                             */\n#define ZMQ_PAIR 0\n#define ZMQ_PUB 1\n#define ZMQ_SUB 2\n#define ZMQ_REQ 3\n#define ZMQ_REP 4\n#define ZMQ_DEALER 5\n#define ZMQ_ROUTER 6\n#define ZMQ_PULL 7\n#define ZMQ_PUSH 8\n#define ZMQ_XPUB 9\n#define ZMQ_XSUB 10\n#define ZMQ_STREAM 11\n\n/*  Deprecated aliases                                                        */\n#define ZMQ_XREQ ZMQ_DEALER\n#define ZMQ_XREP ZMQ_ROUTER\n\n/*  Socket options.                                                           */\n#define ZMQ_AFFINITY 4\n#define ZMQ_ROUTING_ID 5\n#define ZMQ_SUBSCRIBE 6\n#define ZMQ_UNSUBSCRIBE 7\n#define ZMQ_RATE 8\n#define ZMQ_RECOVERY_IVL 9\n#define ZMQ_SNDBUF 11\n#define ZMQ_RCVBUF 12\n#define ZMQ_RCVMORE 13\n#define ZMQ_FD 14\n#define ZMQ_EVENTS 15\n#define ZMQ_TYPE 16\n#define ZMQ_LINGER 17\n#define ZMQ_RECONNECT_IVL 18\n#define ZMQ_BACKLOG 19\n#define ZMQ_RECONNECT_IVL_MAX 21\n#define ZMQ_MAXMSGSIZE 22\n#define ZMQ_SNDHWM 23\n#define ZMQ_RCVHWM 24\n#define ZMQ_MULTICAST_HOPS 25\n#define ZMQ_RCVTIMEO 27\n#define ZMQ_SNDTIMEO 28\n#define ZMQ_LAST_ENDPOINT 32\n#define ZMQ_ROUTER_MANDATORY 33\n#define ZMQ_TCP_KEEPALIVE 34\n#define ZMQ_TCP_KEEPALIVE_CNT 35\n#define ZMQ_TCP_KEEPALIVE_IDLE 36\n#define ZMQ_TCP_KEEPALIVE_INTVL 37\n#define ZMQ_IMMEDIATE 39\n#define ZMQ_XPUB_VERBOSE 40\n#define ZMQ_ROUTER_RAW 41\n#define ZMQ_IPV6 42\n#define ZMQ_MECHANISM 43\n#define ZMQ_PLAIN_SERVER 44\n#define ZMQ_PLAIN_USERNAME 45\n#define ZMQ_PLAIN_PASSWORD 46\n#define ZMQ_CURVE_SERVER 47\n#define ZMQ_CURVE_PUBLICKEY 48\n#define ZMQ_CURVE_SECRETKEY 49\n#define ZMQ_CURVE_SERVERKEY 50\n#define ZMQ_PROBE_ROUTER 51\n#define ZMQ_REQ_CORRELATE 52\n#define ZMQ_REQ_RELAXED 53\n#define ZMQ_CONFLATE 54\n#define ZMQ_ZAP_DOMAIN 55\n#define ZMQ_ROUTER_HANDOVER 56\n#define ZMQ_TOS 57\n#define ZMQ_CONNECT_ROUTING_ID 61\n#define ZMQ_GSSAPI_SERVER 62\n#define ZMQ_GSSAPI_PRINCIPAL 63\n#define ZMQ_GSSAPI_SERVICE_PRINCIPAL 64\n#define ZMQ_GSSAPI_PLAINTEXT 65\n#define ZMQ_HANDSHAKE_IVL 66\n#define ZMQ_SOCKS_PROXY 68\n#define ZMQ_XPUB_NODROP 69\n#define ZMQ_BLOCKY 70\n#define ZMQ_XPUB_MANUAL 71\n#define ZMQ_XPUB_WELCOME_MSG 72\n#define ZMQ_STREAM_NOTIFY 73\n#define ZMQ_INVERT_MATCHING 74\n#define ZMQ_HEARTBEAT_IVL 75\n#define ZMQ_HEARTBEAT_TTL 76\n#define ZMQ_HEARTBEAT_TIMEOUT 77\n#define ZMQ_XPUB_VERBOSER 78\n#define ZMQ_CONNECT_TIMEOUT 79\n#define ZMQ_TCP_MAXRT 80\n#define ZMQ_THREAD_SAFE 81\n#define ZMQ_MULTICAST_MAXTPDU 84\n#define ZMQ_VMCI_BUFFER_SIZE 85\n#define ZMQ_VMCI_BUFFER_MIN_SIZE 86\n#define ZMQ_VMCI_BUFFER_MAX_SIZE 87\n#define ZMQ_VMCI_CONNECT_TIMEOUT 88\n#define ZMQ_USE_FD 89\n#define ZMQ_GSSAPI_PRINCIPAL_NAMETYPE 90\n#define ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE 91\n#define ZMQ_BINDTODEVICE 92\n\n/*  Message options                                                           */\n#define ZMQ_MORE 1\n#define ZMQ_SHARED 3\n\n/*  Send/recv options.                                                        */\n#define ZMQ_DONTWAIT 1\n#define ZMQ_SNDMORE 2\n\n/*  Security mechanisms                                                       */\n#define ZMQ_NULL 0\n#define ZMQ_PLAIN 1\n#define ZMQ_CURVE 2\n#define ZMQ_GSSAPI 3\n\n/*  RADIO-DISH protocol                                                       */\n#define ZMQ_GROUP_MAX_LENGTH 255\n\n/*  Deprecated options and aliases                                            */\n#define ZMQ_IDENTITY ZMQ_ROUTING_ID\n#define ZMQ_CONNECT_RID ZMQ_CONNECT_ROUTING_ID\n#define ZMQ_TCP_ACCEPT_FILTER 38\n#define ZMQ_IPC_FILTER_PID 58\n#define ZMQ_IPC_FILTER_UID 59\n#define ZMQ_IPC_FILTER_GID 60\n#define ZMQ_IPV4ONLY 31\n#define ZMQ_DELAY_ATTACH_ON_CONNECT ZMQ_IMMEDIATE\n#define ZMQ_NOBLOCK ZMQ_DONTWAIT\n#define ZMQ_FAIL_UNROUTABLE ZMQ_ROUTER_MANDATORY\n#define ZMQ_ROUTER_BEHAVIOR ZMQ_ROUTER_MANDATORY\n\n/*  Deprecated Message options                                                */\n#define ZMQ_SRCFD 2\n\n/******************************************************************************/\n/*  GSSAPI definitions                                                        */\n/******************************************************************************/\n\n/*  GSSAPI principal name types                                               */\n#define ZMQ_GSSAPI_NT_HOSTBASED 0\n#define ZMQ_GSSAPI_NT_USER_NAME 1\n#define ZMQ_GSSAPI_NT_KRB5_PRINCIPAL 2\n\n/******************************************************************************/\n/*  0MQ socket events and monitoring                                          */\n/******************************************************************************/\n\n/*  Socket transport events (TCP, IPC and TIPC only)                          */\n\n#define ZMQ_EVENT_CONNECTED 0x0001\n#define ZMQ_EVENT_CONNECT_DELAYED 0x0002\n#define ZMQ_EVENT_CONNECT_RETRIED 0x0004\n#define ZMQ_EVENT_LISTENING 0x0008\n#define ZMQ_EVENT_BIND_FAILED 0x0010\n#define ZMQ_EVENT_ACCEPTED 0x0020\n#define ZMQ_EVENT_ACCEPT_FAILED 0x0040\n#define ZMQ_EVENT_CLOSED 0x0080\n#define ZMQ_EVENT_CLOSE_FAILED 0x0100\n#define ZMQ_EVENT_DISCONNECTED 0x0200\n#define ZMQ_EVENT_MONITOR_STOPPED 0x0400\n#define ZMQ_EVENT_ALL 0xFFFF\n/*  Unspecified system errors during handshake. Event value is an errno.      */\n#define ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL 0x0800\n/*  Handshake complete successfully with successful authentication (if        *\n *  enabled). Event value is unused.                                          */\n#define ZMQ_EVENT_HANDSHAKE_SUCCEEDED 0x1000\n/*  Protocol errors between ZMTP peers or between server and ZAP handler.     *\n *  Event value is one of ZMQ_PROTOCOL_ERROR_*                                */\n#define ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL 0x2000\n/*  Failed authentication requests. Event value is the numeric ZAP status     *\n *  code, i.e. 300, 400 or 500.                                               */\n#define ZMQ_EVENT_HANDSHAKE_FAILED_AUTH 0x4000\n#define ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED 0x10000000\n#define ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND 0x10000001\n#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE 0x10000002\n#define ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE 0x10000003\n#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED 0x10000011\n#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE 0x10000012\n#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO 0x10000013\n#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE 0x10000014\n#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR 0x10000015\n#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY 0x10000016\n#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME 0x10000017\n#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA 0x10000018\n// the following two may be due to erroneous configuration of a peer\n#define ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC 0x11000001\n#define ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH 0x11000002\n#define ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED 0x20000000\n#define ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY 0x20000001\n#define ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID 0x20000002\n#define ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION 0x20000003\n#define ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE 0x20000004\n#define ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA 0x20000005\n#define ZMQ_PROTOCOL_ERROR_WS_UNSPECIFIED 0x30000000\n\nZMQ_EXPORT void *zmq_socket (void *, int type_);\nZMQ_EXPORT int zmq_close (void *s_);\nZMQ_EXPORT int\nzmq_setsockopt (void *s_, int option_, const void *optval_, size_t optvallen_);\nZMQ_EXPORT int\nzmq_getsockopt (void *s_, int option_, void *optval_, size_t *optvallen_);\nZMQ_EXPORT int zmq_bind (void *s_, const char *addr_);\nZMQ_EXPORT int zmq_connect (void *s_, const char *addr_);\nZMQ_EXPORT int zmq_unbind (void *s_, const char *addr_);\nZMQ_EXPORT int zmq_disconnect (void *s_, const char *addr_);\nZMQ_EXPORT int zmq_send (void *s_, const void *buf_, size_t len_, int flags_);\nZMQ_EXPORT int\nzmq_send_const (void *s_, const void *buf_, size_t len_, int flags_);\nZMQ_EXPORT int zmq_recv (void *s_, void *buf_, size_t len_, int flags_);\nZMQ_EXPORT int zmq_socket_monitor (void *s_, const char *addr_, int events_);\n\n/******************************************************************************/\n/*  Hide socket fd type; this was before zmq_poller_event_t typedef below     */\n/******************************************************************************/\n\n#if defined _WIN32\n// Windows uses a pointer-sized unsigned integer to store the socket fd.\n#if defined _WIN64\ntypedef unsigned __int64 zmq_fd_t;\n#else\ntypedef unsigned int zmq_fd_t;\n#endif\n#else\ntypedef int zmq_fd_t;\n#endif\n\n/******************************************************************************/\n/*  Deprecated I/O multiplexing. Prefer using zmq_poller API                  */\n/******************************************************************************/\n\n#define ZMQ_POLLIN 1\n#define ZMQ_POLLOUT 2\n#define ZMQ_POLLERR 4\n#define ZMQ_POLLPRI 8\n\ntypedef struct zmq_pollitem_t\n{\n    void *socket;\n    zmq_fd_t fd;\n    short events;\n    short revents;\n} zmq_pollitem_t;\n\n#define ZMQ_POLLITEMS_DFLT 16\n\nZMQ_EXPORT int zmq_poll (zmq_pollitem_t *items_, int nitems_, long timeout_);\n\n/******************************************************************************/\n/*  Message proxying                                                          */\n/******************************************************************************/\n\nZMQ_EXPORT int zmq_proxy (void *frontend_, void *backend_, void *capture_);\nZMQ_EXPORT int zmq_proxy_steerable (void *frontend_,\n                                    void *backend_,\n                                    void *capture_,\n                                    void *control_);\n\n/******************************************************************************/\n/*  Probe library capabilities                                                */\n/******************************************************************************/\n\n#define ZMQ_HAS_CAPABILITIES 1\nZMQ_EXPORT int zmq_has (const char *capability_);\n\n/*  Deprecated aliases */\n#define ZMQ_STREAMER 1\n#define ZMQ_FORWARDER 2\n#define ZMQ_QUEUE 3\n\n/*  Deprecated methods */\nZMQ_EXPORT int zmq_device (int type_, void *frontend_, void *backend_);\nZMQ_EXPORT int zmq_sendmsg (void *s_, zmq_msg_t *msg_, int flags_);\nZMQ_EXPORT int zmq_recvmsg (void *s_, zmq_msg_t *msg_, int flags_);\nstruct iovec;\nZMQ_EXPORT int\nzmq_sendiov (void *s_, struct iovec *iov_, size_t count_, int flags_);\nZMQ_EXPORT int\nzmq_recviov (void *s_, struct iovec *iov_, size_t *count_, int flags_);\n\n/******************************************************************************/\n/*  Encryption functions                                                      */\n/******************************************************************************/\n\n/*  Encode data with Z85 encoding. Returns encoded data                       */\nZMQ_EXPORT char *\nzmq_z85_encode (char *dest_, const uint8_t *data_, size_t size_);\n\n/*  Decode data with Z85 encoding. Returns decoded data                       */\nZMQ_EXPORT uint8_t *zmq_z85_decode (uint8_t *dest_, const char *string_);\n\n/*  Generate z85-encoded public and private keypair with libsodium. */\n/*  Returns 0 on success.                                                     */\nZMQ_EXPORT int zmq_curve_keypair (char *z85_public_key_, char *z85_secret_key_);\n\n/*  Derive the z85-encoded public key from the z85-encoded secret key.        */\n/*  Returns 0 on success.                                                     */\nZMQ_EXPORT int zmq_curve_public (char *z85_public_key_,\n                                 const char *z85_secret_key_);\n\n/******************************************************************************/\n/*  Atomic utility methods                                                    */\n/******************************************************************************/\n\nZMQ_EXPORT void *zmq_atomic_counter_new (void);\nZMQ_EXPORT void zmq_atomic_counter_set (void *counter_, int value_);\nZMQ_EXPORT int zmq_atomic_counter_inc (void *counter_);\nZMQ_EXPORT int zmq_atomic_counter_dec (void *counter_);\nZMQ_EXPORT int zmq_atomic_counter_value (void *counter_);\nZMQ_EXPORT void zmq_atomic_counter_destroy (void **counter_p_);\n\n/******************************************************************************/\n/*  Scheduling timers                                                         */\n/******************************************************************************/\n\n#define ZMQ_HAVE_TIMERS\n\ntypedef void (zmq_timer_fn) (int timer_id, void *arg);\n\nZMQ_EXPORT void *zmq_timers_new (void);\nZMQ_EXPORT int zmq_timers_destroy (void **timers_p);\nZMQ_EXPORT int\nzmq_timers_add (void *timers, size_t interval, zmq_timer_fn handler, void *arg);\nZMQ_EXPORT int zmq_timers_cancel (void *timers, int timer_id);\nZMQ_EXPORT int\nzmq_timers_set_interval (void *timers, int timer_id, size_t interval);\nZMQ_EXPORT int zmq_timers_reset (void *timers, int timer_id);\nZMQ_EXPORT long zmq_timers_timeout (void *timers);\nZMQ_EXPORT int zmq_timers_execute (void *timers);\n\n\n/******************************************************************************/\n/*  These functions are not documented by man pages -- use at your own risk.  */\n/*  If you need these to be part of the formal ZMQ API, then (a) write a man  */\n/*  page, and (b) write a test case in tests.                                 */\n/******************************************************************************/\n\n/*  Helper functions are used by perf tests so that they don't have to care   */\n/*  about minutiae of time-related functions on different OS platforms.       */\n\n/*  Starts the stopwatch. Returns the handle to the watch.                    */\nZMQ_EXPORT void *zmq_stopwatch_start (void);\n\n/*  Returns the number of microseconds elapsed since the stopwatch was        */\n/*  started, but does not stop or deallocate the stopwatch.                   */\nZMQ_EXPORT unsigned long zmq_stopwatch_intermediate (void *watch_);\n\n/*  Stops the stopwatch. Returns the number of microseconds elapsed since     */\n/*  the stopwatch was started, and deallocates that watch.                    */\nZMQ_EXPORT unsigned long zmq_stopwatch_stop (void *watch_);\n\n/*  Sleeps for specified number of seconds.                                   */\nZMQ_EXPORT void zmq_sleep (int seconds_);\n\ntypedef void (zmq_thread_fn) (void *);\n\n/* Start a thread. Returns a handle to the thread.                            */\nZMQ_EXPORT void *zmq_threadstart (zmq_thread_fn *func_, void *arg_);\n\n/* Wait for thread to complete then free up resources.                        */\nZMQ_EXPORT void zmq_threadclose (void *thread_);\n\n\n/******************************************************************************/\n/*  These functions are DRAFT and disabled in stable releases, and subject to */\n/*  change at ANY time until declared stable.                                 */\n/******************************************************************************/\n\n#ifdef ZMQ_BUILD_DRAFT_API\n\n/*  DRAFT Socket types.                                                       */\n#define ZMQ_SERVER 12\n#define ZMQ_CLIENT 13\n#define ZMQ_RADIO 14\n#define ZMQ_DISH 15\n#define ZMQ_GATHER 16\n#define ZMQ_SCATTER 17\n#define ZMQ_DGRAM 18\n#define ZMQ_PEER 19\n#define ZMQ_CHANNEL 20\n\n/*  DRAFT Socket options.                                                     */\n#define ZMQ_ZAP_ENFORCE_DOMAIN 93\n#define ZMQ_LOOPBACK_FASTPATH 94\n#define ZMQ_METADATA 95\n#define ZMQ_MULTICAST_LOOP 96\n#define ZMQ_ROUTER_NOTIFY 97\n#define ZMQ_XPUB_MANUAL_LAST_VALUE 98\n#define ZMQ_SOCKS_USERNAME 99\n#define ZMQ_SOCKS_PASSWORD 100\n#define ZMQ_IN_BATCH_SIZE 101\n#define ZMQ_OUT_BATCH_SIZE 102\n#define ZMQ_WSS_KEY_PEM 103\n#define ZMQ_WSS_CERT_PEM 104\n#define ZMQ_WSS_TRUST_PEM 105\n#define ZMQ_WSS_HOSTNAME 106\n#define ZMQ_WSS_TRUST_SYSTEM 107\n#define ZMQ_ONLY_FIRST_SUBSCRIBE 108\n#define ZMQ_RECONNECT_STOP 109\n#define ZMQ_HELLO_MSG 110\n#define ZMQ_DISCONNECT_MSG 111\n#define ZMQ_PRIORITY 112\n#define ZMQ_BUSY_POLL 113\n#define ZMQ_HICCUP_MSG 114\n#define ZMQ_XSUB_VERBOSE_UNSUBSCRIBE 115\n#define ZMQ_TOPICS_COUNT 116\n#define ZMQ_NORM_MODE 117\n#define ZMQ_NORM_UNICAST_NACK 118\n#define ZMQ_NORM_BUFFER_SIZE 119\n#define ZMQ_NORM_SEGMENT_SIZE 120\n#define ZMQ_NORM_BLOCK_SIZE 121\n#define ZMQ_NORM_NUM_PARITY 122\n#define ZMQ_NORM_NUM_AUTOPARITY 123\n#define ZMQ_NORM_PUSH 124\n\n/*  DRAFT ZMQ_NORM_MODE options                                               */\n#define ZMQ_NORM_FIXED 0\n#define ZMQ_NORM_CC 1\n#define ZMQ_NORM_CCL 2\n#define ZMQ_NORM_CCE 3\n#define ZMQ_NORM_CCE_ECNONLY 4\n\n/*  DRAFT ZMQ_RECONNECT_STOP options                                          */\n#define ZMQ_RECONNECT_STOP_CONN_REFUSED 0x1\n#define ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED 0x2\n#define ZMQ_RECONNECT_STOP_AFTER_DISCONNECT 0x4\n\n/*  DRAFT Context options                                                     */\n#define ZMQ_ZERO_COPY_RECV 10\n\n/*  DRAFT Context methods.                                                    */\nZMQ_EXPORT int zmq_ctx_set_ext (void *context_,\n                                int option_,\n                                const void *optval_,\n                                size_t optvallen_);\nZMQ_EXPORT int zmq_ctx_get_ext (void *context_,\n                                int option_,\n                                void *optval_,\n                                size_t *optvallen_);\n\n/*  DRAFT Socket methods.                                                     */\nZMQ_EXPORT int zmq_join (void *s, const char *group);\nZMQ_EXPORT int zmq_leave (void *s, const char *group);\nZMQ_EXPORT uint32_t zmq_connect_peer (void *s_, const char *addr_);\nZMQ_EXPORT int zmq_disconnect_peer (void *s_, uint32_t routing_id_);\n\n/*  DRAFT Msg methods.                                                        */\nZMQ_EXPORT int zmq_msg_set_routing_id (zmq_msg_t *msg, uint32_t routing_id);\nZMQ_EXPORT uint32_t zmq_msg_routing_id (zmq_msg_t *msg);\nZMQ_EXPORT int zmq_msg_set_group (zmq_msg_t *msg, const char *group);\nZMQ_EXPORT const char *zmq_msg_group (zmq_msg_t *msg);\nZMQ_EXPORT int\nzmq_msg_init_buffer (zmq_msg_t *msg_, const void *buf_, size_t size_);\n\n/*  DRAFT Msg property names.                                                 */\n#define ZMQ_MSG_PROPERTY_ROUTING_ID \"Routing-Id\"\n#define ZMQ_MSG_PROPERTY_SOCKET_TYPE \"Socket-Type\"\n#define ZMQ_MSG_PROPERTY_USER_ID \"User-Id\"\n#define ZMQ_MSG_PROPERTY_PEER_ADDRESS \"Peer-Address\"\n\n/*  Router notify options                                                     */\n#define ZMQ_NOTIFY_CONNECT 1\n#define ZMQ_NOTIFY_DISCONNECT 2\n\n/******************************************************************************/\n/*  Poller polling on sockets,fd and thread-safe sockets                      */\n/******************************************************************************/\n\n#define ZMQ_HAVE_POLLER\n\ntypedef struct zmq_poller_event_t\n{\n    void *socket;\n    zmq_fd_t fd;\n    void *user_data;\n    short events;\n} zmq_poller_event_t;\n\nZMQ_EXPORT void *zmq_poller_new (void);\nZMQ_EXPORT int zmq_poller_destroy (void **poller_p);\nZMQ_EXPORT int zmq_poller_size (void *poller);\nZMQ_EXPORT int\nzmq_poller_add (void *poller, void *socket, void *user_data, short events);\nZMQ_EXPORT int zmq_poller_modify (void *poller, void *socket, short events);\nZMQ_EXPORT int zmq_poller_remove (void *poller, void *socket);\nZMQ_EXPORT int\nzmq_poller_wait (void *poller, zmq_poller_event_t *event, long timeout);\nZMQ_EXPORT int zmq_poller_wait_all (void *poller,\n                                    zmq_poller_event_t *events,\n                                    int n_events,\n                                    long timeout);\nZMQ_EXPORT int zmq_poller_fd (void *poller, zmq_fd_t *fd);\n\nZMQ_EXPORT int\nzmq_poller_add_fd (void *poller, zmq_fd_t fd, void *user_data, short events);\nZMQ_EXPORT int zmq_poller_modify_fd (void *poller, zmq_fd_t fd, short events);\nZMQ_EXPORT int zmq_poller_remove_fd (void *poller, zmq_fd_t fd);\n\nZMQ_EXPORT int zmq_socket_get_peer_state (void *socket,\n                                          const void *routing_id,\n                                          size_t routing_id_size);\n\n/*  DRAFT Socket monitoring events                                            */\n#define ZMQ_EVENT_PIPES_STATS 0x10000\n\n#define ZMQ_CURRENT_EVENT_VERSION 1\n#define ZMQ_CURRENT_EVENT_VERSION_DRAFT 2\n\n#define ZMQ_EVENT_ALL_V1 ZMQ_EVENT_ALL\n#define ZMQ_EVENT_ALL_V2 ZMQ_EVENT_ALL_V1 | ZMQ_EVENT_PIPES_STATS\n\nZMQ_EXPORT int zmq_socket_monitor_versioned (\n  void *s_, const char *addr_, uint64_t events_, int event_version_, int type_);\nZMQ_EXPORT int zmq_socket_monitor_pipes_stats (void *s);\n\n#if !defined _WIN32\nZMQ_EXPORT int zmq_ppoll (zmq_pollitem_t *items_,\n                          int nitems_,\n                          long timeout_,\n                          const sigset_t *sigmask_);\n#else\n// Windows has no sigset_t\nZMQ_EXPORT int zmq_ppoll (zmq_pollitem_t *items_,\n                          int nitems_,\n                          long timeout_,\n                          const void *sigmask_);\n#endif\n\n#endif // ZMQ_BUILD_DRAFT_API\n\n\n#undef ZMQ_EXPORT\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/zmq_utils.h",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n/*  This file is deprecated, and all its functionality provided by zmq.h     */\n/*  Note that -Wpedantic compilation requires GCC to avoid using its custom\n    extensions such as #warning, hence the trick below. Also, pragmas for\n    warnings or other messages are not standard, not portable, and not all\n    compilers even have an equivalent concept.\n    So in the worst case, this include file is treated as silently empty. */\n\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)               \\\n  || defined(_MSC_VER)\n#if defined(__GNUC__) || defined(__GNUG__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic warning \"-Wcpp\"\n#pragma GCC diagnostic ignored \"-Werror\"\n#pragma GCC diagnostic ignored \"-Wall\"\n#endif\n#pragma message(                                                               \\\n  \"Warning: zmq_utils.h is deprecated. All its functionality is provided by zmq.h.\")\n#if defined(__GNUC__) || defined(__GNUG__)\n#pragma GCC diagnostic pop\n#endif\n#endif\n"
  },
  {
    "path": "m4/ax_check_compile_flag.m4",
    "content": "# ===========================================================================\n#   http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])\n#\n# DESCRIPTION\n#\n#   Check whether the given FLAG works with the current language's compiler\n#   or gives an error.  (Warnings, however, are ignored)\n#\n#   ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on\n#   success/failure.\n#\n#   If EXTRA-FLAGS is defined, it is added to the current language's default\n#   flags (e.g. CFLAGS) when the check is done.  The check is thus made with\n#   the flags: \"CFLAGS EXTRA-FLAGS FLAG\".  This can for example be used to\n#   force the compiler to issue an error when a bad flag is given.\n#\n#   INPUT gives an alternative input source to AC_COMPILE_IFELSE.\n#\n#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this\n#   macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.\n#\n# LICENSE\n#\n#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>\n#   Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>\n#\n#   This program is free software: you can redistribute it and/or modify it\n#   under the terms of the GNU General Public License as published by the\n#   Free Software Foundation, either version 3 of the License, or (at your\n#   option) any later version.\n#\n#   This program is distributed in the hope that it will be useful, but\n#   WITHOUT ANY WARRANTY; without even the implied warranty of\n#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General\n#   Public License for more details.\n#\n#   You should have received a copy of the GNU General Public License along\n#   with this program. If not, see <http://www.gnu.org/licenses/>.\n#\n#   As a special exception, the respective Autoconf Macro's copyright owner\n#   gives unlimited permission to copy, distribute and modify the configure\n#   scripts that are the output of Autoconf when processing the Macro. You\n#   need not follow the terms of the GNU General Public License when using\n#   or distributing such scripts, even though portions of the text of the\n#   Macro appear in them. The GNU General Public License (GPL) does govern\n#   all other use of the material that constitutes the Autoconf Macro.\n#\n#   This special exception to the GPL applies to versions of the Autoconf\n#   Macro released by the Autoconf Archive. When you make and distribute a\n#   modified version of the Autoconf Macro, you may extend this special\n#   exception to the GPL to apply to your modified version as well.\n\n#serial 4\n\nAC_DEFUN([AX_CHECK_COMPILE_FLAG],\n[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF\nAS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl\nAC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [\n  ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS\n  _AC_LANG_PREFIX[]FLAGS=\"$[]_AC_LANG_PREFIX[]FLAGS $4 $1\"\n  AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],\n    [AS_VAR_SET(CACHEVAR,[yes])],\n    [AS_VAR_SET(CACHEVAR,[no])])\n  _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])\nAS_VAR_IF(CACHEVAR,yes,\n  [m4_default([$2], :)],\n  [m4_default([$3], :)])\nAS_VAR_POPDEF([CACHEVAR])dnl\n])dnl AX_CHECK_COMPILE_FLAGS\n"
  },
  {
    "path": "m4/ax_check_vscript.m4",
    "content": "# ===========================================================================\n#     https://www.gnu.org/software/autoconf-archive/ax_check_vscript.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_CHECK_VSCRIPT\n#\n# DESCRIPTION\n#\n#   Check whether the linker supports version scripts.  Version scripts are\n#   used when building shared libraries to bind symbols to version nodes\n#   (helping to detect incompatibilities) or to limit the visibility of\n#   non-public symbols.\n#\n#   Output:\n#\n#   If version scripts are supported, VSCRIPT_LDFLAGS will contain the\n#   appropriate flag to pass to the linker.  On GNU systems this would\n#   typically be \"-Wl,--version-script\", and on Solaris it would typically\n#   be \"-Wl,-M\".\n#\n#   Two Automake conditionals are also set:\n#\n#    HAVE_VSCRIPT is true if the linker supports version scripts with\n#    entries that use simple wildcards, like \"local: *\".\n#\n#    HAVE_VSCRIPT_COMPLEX is true if the linker supports version scripts with\n#    pattern matching wildcards, like \"global: Java_*\".\n#\n#   On systems that do not support symbol versioning, such as Mac OS X, both\n#   conditionals will be false.  They will also be false if the user passes\n#   \"--disable-symvers\" on the configure command line.\n#\n#   Example:\n#\n#    configure.ac:\n#\n#     AX_CHECK_VSCRIPT\n#\n#    Makefile.am:\n#\n#     if HAVE_VSCRIPT\n#     libfoo_la_LDFLAGS += $(VSCRIPT_LDFLAGS),@srcdir@/libfoo.map\n#     endif\n#\n#     if HAVE_VSCRIPT_COMPLEX\n#     libbar_la_LDFLAGS += $(VSCRIPT_LDFLAGS),@srcdir@/libbar.map\n#     endif\n#\n# LICENSE\n#\n#   Copyright (c) 2014 Kevin Cernekee <cernekee@gmail.com>\n#\n#   Copying and distribution of this file, with or without modification, are\n#   permitted in any medium without royalty provided the copyright notice\n#   and this notice are preserved. This file is offered as-is, without any\n#   warranty.\n\n#serial 2\n\n# _AX_CHECK_VSCRIPT(flag, global-sym, action-if-link-succeeds, [junk-file=no])\nAC_DEFUN([_AX_CHECK_VSCRIPT], [\n  AC_LANG_PUSH([C])\n  ax_check_vscript_save_flags=\"$LDFLAGS\"\n  echo \"V1 { global: $2; local: *; };\" > conftest.map\n  AS_IF([test x$4 = xyes], [\n    echo \"{\" >> conftest.map\n  ])\n  LDFLAGS=\"$LDFLAGS -Wl,$1,conftest.map\"\n  AC_LINK_IFELSE([AC_LANG_PROGRAM([[int show, hide;]], [])], [$3])\n  LDFLAGS=\"$ax_check_vscript_save_flags\"\n  rm -f conftest.map\n  AC_LANG_POP([C])\n]) dnl _AX_CHECK_VSCRIPT\n\nAC_DEFUN([AX_CHECK_VSCRIPT], [\n\n  AC_ARG_ENABLE([symvers],\n    AS_HELP_STRING([--disable-symvers],\n                   [disable library symbol versioning [default=auto]]),\n    [want_symvers=$enableval],\n    [want_symvers=yes]\n  )\n\n  AS_IF([test x$want_symvers = xyes], [\n\n    dnl First test --version-script and -M with a simple wildcard.\n\n    AC_CACHE_CHECK([linker version script flag], ax_cv_check_vscript_flag, [\n      ax_cv_check_vscript_flag=unsupported\n      _AX_CHECK_VSCRIPT([--version-script], [show], [\n        ax_cv_check_vscript_flag=--version-script\n      ])\n      AS_IF([test x$ax_cv_check_vscript_flag = xunsupported], [\n        _AX_CHECK_VSCRIPT([-M], [show], [ax_cv_check_vscript_flag=-M])\n      ])\n\n      dnl The linker may interpret -M (no argument) as \"produce a load map.\"\n      dnl If \"-M conftest.map\" doesn't fail when conftest.map contains\n      dnl obvious syntax errors, assume this is the case.\n\n      AS_IF([test x$ax_cv_check_vscript_flag != xunsupported], [\n        _AX_CHECK_VSCRIPT([$ax_cv_check_vscript_flag], [show],\n\t                  [ax_cv_check_vscript_flag=unsupported], [yes])\n      ])\n    ])\n\n    dnl If the simple wildcard worked, retest with a complex wildcard.\n\n    AS_IF([test x$ax_cv_check_vscript_flag != xunsupported], [\n      ax_check_vscript_flag=$ax_cv_check_vscript_flag\n      AC_CACHE_CHECK([if version scripts can use complex wildcards],\n                     ax_cv_check_vscript_complex_wildcards, [\n        ax_cv_check_vscript_complex_wildcards=no\n        _AX_CHECK_VSCRIPT([$ax_cv_check_vscript_flag], [sh*], [\n        ax_cv_check_vscript_complex_wildcards=yes])\n      ])\n      ax_check_vscript_complex_wildcards=\"$ax_cv_check_vscript_complex_wildcards\"\n    ], [\n      ax_check_vscript_flag=\n      ax_check_vscript_complex_wildcards=no\n    ])\n  ], [\n    AC_MSG_CHECKING([linker version script flag])\n    AC_MSG_RESULT([disabled])\n\n    ax_check_vscript_flag=\n    ax_check_vscript_complex_wildcards=no\n  ])\n\n  AS_IF([test x$ax_check_vscript_flag != x], [\n    VSCRIPT_LDFLAGS=\"-Wl,$ax_check_vscript_flag\"\n    AC_SUBST([VSCRIPT_LDFLAGS])\n  ])\n\n  AM_CONDITIONAL([HAVE_VSCRIPT],\n    [test x$ax_check_vscript_flag != x])\n  AM_CONDITIONAL([HAVE_VSCRIPT_COMPLEX],\n    [test x$ax_check_vscript_complex_wildcards = xyes])\n\n]) dnl AX_CHECK_VSCRIPT\n"
  },
  {
    "path": "m4/ax_code_coverage.m4",
    "content": "# ===========================================================================\n#     https://www.gnu.org/software/autoconf-archive/ax_code_coverage.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_CODE_COVERAGE()\n#\n# DESCRIPTION\n#\n#   Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS,\n#   CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LIBS which should be included\n#   in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LIBADD variables of every\n#   build target (program or library) which should be built with code\n#   coverage support. Also defines CODE_COVERAGE_RULES which should be\n#   substituted in your Makefile; and $enable_code_coverage which can be\n#   used in subsequent configure output. CODE_COVERAGE_ENABLED is defined\n#   and substituted, and corresponds to the value of the\n#   --enable-code-coverage option, which defaults to being disabled.\n#\n#   Test also for gcov program and create GCOV variable that could be\n#   substituted.\n#\n#   Note that all optimization flags in CFLAGS must be disabled when code\n#   coverage is enabled.\n#\n#   Usage example:\n#\n#   configure.ac:\n#\n#     AX_CODE_COVERAGE\n#\n#   Makefile.am:\n#\n#     @CODE_COVERAGE_RULES@\n#     my_program_LIBS = ... $(CODE_COVERAGE_LIBS) ...\n#     my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ...\n#     my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ...\n#     my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ...\n#\n#   This results in a \"check-code-coverage\" rule being added to any\n#   Makefile.am which includes \"@CODE_COVERAGE_RULES@\" (assuming the module\n#   has been configured with --enable-code-coverage). Running `make\n#   check-code-coverage` in that directory will run the module's test suite\n#   (`make check`) and build a code coverage report detailing the code which\n#   was touched, then print the URI for the report.\n#\n#   In earlier versions of this macro, CODE_COVERAGE_LDFLAGS was defined\n#   instead of CODE_COVERAGE_LIBS. They are both still defined, but use of\n#   CODE_COVERAGE_LIBS is preferred for clarity; CODE_COVERAGE_LDFLAGS is\n#   deprecated. They have the same value.\n#\n#   This code was derived from Makefile.decl in GLib, originally licenced\n#   under LGPLv2.1+.\n#\n# LICENSE\n#\n#   Copyright (c) 2012, 2016 Philip Withnall\n#   Copyright (c) 2012 Xan Lopez\n#   Copyright (c) 2012 Christian Persch\n#   Copyright (c) 2012 Paolo Borelli\n#   Copyright (c) 2012 Dan Winship\n#   Copyright (c) 2015 Bastien ROUCARIES\n#\n#   This library is free software; you can redistribute it and/or modify it\n#   under the terms of the GNU Lesser General Public License as published by\n#   the Free Software Foundation; either version 2.1 of the License, or (at\n#   your option) any later version.\n#\n#   This library is distributed in the hope that it will be useful, but\n#   WITHOUT ANY WARRANTY; without even the implied warranty of\n#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser\n#   General Public License for more details.\n#\n#   You should have received a copy of the GNU Lesser General Public License\n#   along with this program. If not, see <https://www.gnu.org/licenses/>.\n\n#serial 25\n\nAC_DEFUN([AX_CODE_COVERAGE],[\n\tdnl Check for --enable-code-coverage\n\tAC_REQUIRE([AC_PROG_SED])\n\n\t# allow to override gcov location\n\tAC_ARG_WITH([gcov],\n\t  [AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])],\n\t  [_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov],\n\t  [_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov])\n\n\tAC_MSG_CHECKING([whether to build with code coverage support])\n\tAC_ARG_ENABLE([code-coverage],\n\t  AS_HELP_STRING([--enable-code-coverage],\n\t  [Whether to enable code coverage support]),,\n\t  enable_code_coverage=no)\n\n\tAM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes])\n\tAC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage])\n\tAC_MSG_RESULT($enable_code_coverage)\n\n\tAS_IF([ test \"$enable_code_coverage\" = \"yes\" ], [\n\t\t# check for gcov\n\t\tAC_CHECK_TOOL([GCOV],\n\t\t  [$_AX_CODE_COVERAGE_GCOV_PROG_WITH],\n\t\t  [:])\n\t\tAS_IF([test \"X$GCOV\" = \"X:\"],\n\t\t  [AC_MSG_ERROR([gcov is needed to do coverage])])\n\t\tAC_SUBST([GCOV])\n\n\t\tdnl Check if gcc is being used\n\t\tAS_IF([ test \"$GCC\" = \"no\" ], [\n\t\t\tAC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage])\n\t\t])\n\n\t\tAC_CHECK_PROG([LCOV], [lcov], [lcov])\n\t\tAC_CHECK_PROG([GENHTML], [genhtml], [genhtml])\n\n\t\tAS_IF([ test -z \"$LCOV\" ], [\n\t\t\tAC_MSG_ERROR([To enable code coverage reporting you must have lcov installed])\n\t\t])\n\n\t\tAS_IF([ test -z \"$GENHTML\" ], [\n\t\t\tAC_MSG_ERROR([Could not find genhtml from the lcov package])\n\t\t])\n\n\t\tdnl Build the code coverage flags\n\t\tdnl Define CODE_COVERAGE_LDFLAGS for backwards compatibility\n\t\tCODE_COVERAGE_CPPFLAGS=\"-DNDEBUG\"\n\t\tCODE_COVERAGE_CFLAGS=\"-O0 -g -fprofile-arcs -fprofile-update=atomic -ftest-coverage\"\n\t\tCODE_COVERAGE_CXXFLAGS=\"-O0 -g -fprofile-arcs -fprofile-update=atomic -ftest-coverage\"\n\t\tCODE_COVERAGE_LIBS=\"-lgcov\"\n\t\tCODE_COVERAGE_LDFLAGS=\"$CODE_COVERAGE_LIBS\"\n\n\t\tAC_SUBST([CODE_COVERAGE_CPPFLAGS])\n\t\tAC_SUBST([CODE_COVERAGE_CFLAGS])\n\t\tAC_SUBST([CODE_COVERAGE_CXXFLAGS])\n\t\tAC_SUBST([CODE_COVERAGE_LIBS])\n\t\tAC_SUBST([CODE_COVERAGE_LDFLAGS])\n\n\t\t[CODE_COVERAGE_RULES_CHECK='\n\t-$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k check\n\t$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture\n']\n\t\t[CODE_COVERAGE_RULES_CAPTURE='\n\t$(code_coverage_v_lcov_cap)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --capture --output-file \"$(CODE_COVERAGE_OUTPUT_FILE).tmp\" --test-name \"$(call code_coverage_sanitize,$(PACKAGE_NAME)-$(PACKAGE_VERSION))\" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_OPTIONS)\n\t$(code_coverage_v_lcov_ign)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --ignore-errors unused --remove \"$(CODE_COVERAGE_OUTPUT_FILE).tmp\" \"/tmp/*\" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file \"$(CODE_COVERAGE_OUTPUT_FILE)\" $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_RMOPTS)\n\t-@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp\n\t$(code_coverage_v_genhtml)LANG=C $(GENHTML) $(code_coverage_quiet) $(addprefix --prefix ,$(CODE_COVERAGE_DIRECTORY)) --output-directory \"$(CODE_COVERAGE_OUTPUT_DIRECTORY)\" --title \"$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage\" --legend --show-details \"$(CODE_COVERAGE_OUTPUT_FILE)\" $(CODE_COVERAGE_GENHTML_OPTIONS)\n\t@echo \"file://$(abs_builddir)/$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html\"\n']\n\t\t[CODE_COVERAGE_RULES_CLEAN='\nclean: code-coverage-clean\ndistclean: code-coverage-clean\ncode-coverage-clean:\n\t-$(LCOV) --directory $(top_builddir) -z\n\t-rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_DIRECTORY)\n\t-find . \\( -name \"*.gcda\" -o -name \"*.gcno\" -o -name \"*.gcov\" \\) -delete\n']\n\t], [\n\t\t[CODE_COVERAGE_RULES_CHECK='\n\t@echo \"Need to reconfigure with --enable-code-coverage\"\n']\n\t\tCODE_COVERAGE_RULES_CAPTURE=\"$CODE_COVERAGE_RULES_CHECK\"\n\t\tCODE_COVERAGE_RULES_CLEAN=''\n\t])\n\n[CODE_COVERAGE_RULES='\n# Code coverage\n#\n# Optional:\n#  - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting.\n#    Multiple directories may be specified, separated by whitespace.\n#    (Default: $(top_builddir))\n#  - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated\n#    by lcov for code coverage. (Default:\n#    $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info)\n#  - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage\n#    reports to be created. (Default:\n#    $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage)\n#  - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage,\n#    set to 0 to disable it and leave empty to stay with the default.\n#    (Default: empty)\n#  - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov\n#    instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)\n#  - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov\n#    instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)\n#  - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov\n#  - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the\n#    collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)\n#  - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov\n#    instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)\n#  - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering\n#    lcov instance. (Default: empty)\n#  - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov\n#    instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)\n#  - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the\n#    genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)\n#  - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml\n#    instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)\n#  - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore\n#\n# The generated report will be titled using the $(PACKAGE_NAME) and\n# $(PACKAGE_VERSION). In order to add the current git hash to the title,\n# use the git-version-gen script, available online.\n\n# Optional variables\nCODE_COVERAGE_DIRECTORY ?= $(top_builddir)\nCODE_COVERAGE_OUTPUT_FILE ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info\nCODE_COVERAGE_OUTPUT_DIRECTORY ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage\nCODE_COVERAGE_BRANCH_COVERAGE ?=\nCODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\\\n--rc lcov_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE))\nCODE_COVERAGE_LCOV_SHOPTS ?= $(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)\nCODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool \"$(GCOV)\"\nCODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= $(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)\nCODE_COVERAGE_LCOV_OPTIONS ?= $(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)\nCODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?=\nCODE_COVERAGE_LCOV_RMOPTS ?= $(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)\nCODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\\\n$(if $(CODE_COVERAGE_BRANCH_COVERAGE),\\\n--rc genhtml_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE))\nCODE_COVERAGE_GENHTML_OPTIONS ?= $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)\nCODE_COVERAGE_IGNORE_PATTERN ?=\n\nGITIGNOREFILES ?=\nGITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY)\n\ncode_coverage_v_lcov_cap = $(code_coverage_v_lcov_cap_$(V))\ncode_coverage_v_lcov_cap_ = $(code_coverage_v_lcov_cap_$(AM_DEFAULT_VERBOSITY))\ncode_coverage_v_lcov_cap_0 = @echo \"  LCOV   --capture\"\\\n $(CODE_COVERAGE_OUTPUT_FILE);\ncode_coverage_v_lcov_ign = $(code_coverage_v_lcov_ign_$(V))\ncode_coverage_v_lcov_ign_ = $(code_coverage_v_lcov_ign_$(AM_DEFAULT_VERBOSITY))\ncode_coverage_v_lcov_ign_0 = @echo \"  LCOV   --remove /tmp/*\"\\\n $(CODE_COVERAGE_IGNORE_PATTERN);\ncode_coverage_v_genhtml = $(code_coverage_v_genhtml_$(V))\ncode_coverage_v_genhtml_ = $(code_coverage_v_genhtml_$(AM_DEFAULT_VERBOSITY))\ncode_coverage_v_genhtml_0 = @echo \"  GEN   \" $(CODE_COVERAGE_OUTPUT_DIRECTORY);\ncode_coverage_quiet = $(code_coverage_quiet_$(V))\ncode_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY))\ncode_coverage_quiet_0 = --quiet\n\n# sanitizes the test-name: replaces with underscores: dashes and dots\ncode_coverage_sanitize = $(subst -,_,$(subst .,_,$(1)))\n\n# Use recursive makes in order to ignore errors during check\ncheck-code-coverage:'\"$CODE_COVERAGE_RULES_CHECK\"'\n\n# Capture code coverage data\ncode-coverage-capture: code-coverage-capture-hook'\"$CODE_COVERAGE_RULES_CAPTURE\"'\n\n# Hook rule executed before code-coverage-capture, overridable by the user\ncode-coverage-capture-hook:\n\n'\"$CODE_COVERAGE_RULES_CLEAN\"'\n\nA''M_DISTCHECK_CONFIGURE_FLAGS ?=\nA''M_DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage\n\n.PHONY: check-code-coverage code-coverage-capture code-coverage-capture-hook code-coverage-clean\n']\n\n\tAC_SUBST([CODE_COVERAGE_RULES])\n\tm4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])])\n])\n"
  },
  {
    "path": "m4/ax_cxx_compile_stdcxx.m4",
    "content": "# ===========================================================================\n#   http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])\n#\n# DESCRIPTION\n#\n#   Check for baseline language coverage in the compiler for the specified\n#   version of the C++ standard.  If necessary, add switches to CXX and\n#   CXXCPP to enable support.  VERSION may be '11' (for the C++11 standard)\n#   or '14' (for the C++14 standard).\n#\n#   The second argument, if specified, indicates whether you insist on an\n#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.\n#   -std=c++11).  If neither is specified, you get whatever works, with\n#   preference for an extended mode.\n#\n#   The third argument, if specified 'mandatory' or if left unspecified,\n#   indicates that baseline support for the specified C++ standard is\n#   required and that the macro should error out if no mode with that\n#   support is found.  If specified 'optional', then configuration proceeds\n#   regardless, after defining HAVE_CXX${VERSION} if and only if a\n#   supporting mode is found.\n#\n# LICENSE\n#\n#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>\n#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>\n#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>\n#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>\n#   Copyright (c) 2015 Paul Norman <penorman@mac.com>\n#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>\n#\n#   Copying and distribution of this file, with or without modification, are\n#   permitted in any medium without royalty provided the copyright notice\n#   and this notice are preserved.  This file is offered as-is, without any\n#   warranty.\n\n#serial 4\n\ndnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro\ndnl  (serial version number 13).\n\nAC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl\n  m4_if([$1], [11], [],\n        [$1], [14], [],\n        [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],\n        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl\n  m4_if([$2], [], [],\n        [$2], [ext], [],\n        [$2], [noext], [],\n        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl\n  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],\n        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],\n        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],\n        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])\n  AC_LANG_PUSH([C++])dnl\n  ac_success=no\n  AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,\n  ax_cv_cxx_compile_cxx$1,\n  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],\n    [ax_cv_cxx_compile_cxx$1=yes],\n    [ax_cv_cxx_compile_cxx$1=no])])\n  if test x$ax_cv_cxx_compile_cxx$1 = xyes; then\n    ac_success=yes\n  fi\n\n  m4_if([$2], [noext], [], [dnl\n  if test x$ac_success = xno; then\n    for switch in -std=gnu++$1 -std=gnu++0x; do\n      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])\n      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,\n                     $cachevar,\n        [ac_save_CXX=\"$CXX\"\n         CXX=\"$CXX $switch\"\n         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],\n          [eval $cachevar=yes],\n          [eval $cachevar=no])\n         CXX=\"$ac_save_CXX\"])\n      if eval test x\\$$cachevar = xyes; then\n        CXX=\"$CXX $switch\"\n        if test -n \"$CXXCPP\" ; then\n          CXXCPP=\"$CXXCPP $switch\"\n        fi\n        ac_success=yes\n        break\n      fi\n    done\n  fi])\n\n  m4_if([$2], [ext], [], [dnl\n  if test x$ac_success = xno; then\n    dnl HP's aCC needs +std=c++11 according to:\n    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf\n    dnl Cray's crayCC needs \"-h std=c++11\"\n    for switch in -std=c++$1 -std=c++0x +std=c++$1 \"-h std=c++$1\"; do\n      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])\n      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,\n                     $cachevar,\n        [ac_save_CXX=\"$CXX\"\n         CXX=\"$CXX $switch\"\n         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],\n          [eval $cachevar=yes],\n          [eval $cachevar=no])\n         CXX=\"$ac_save_CXX\"])\n      if eval test x\\$$cachevar = xyes; then\n        CXX=\"$CXX $switch\"\n        if test -n \"$CXXCPP\" ; then\n          CXXCPP=\"$CXXCPP $switch\"\n        fi\n        ac_success=yes\n        break\n      fi\n    done\n  fi])\n  AC_LANG_POP([C++])\n  if test x$ax_cxx_compile_cxx$1_required = xtrue; then\n    if test x$ac_success = xno; then\n      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])\n    fi\n  fi\n  if test x$ac_success = xno; then\n    HAVE_CXX$1=0\n    AC_MSG_NOTICE([No compiler with C++$1 support was found])\n  else\n    HAVE_CXX$1=1\n    AC_DEFINE(HAVE_CXX$1,1,\n              [define if the compiler supports basic C++$1 syntax])\n  fi\n  AC_SUBST(HAVE_CXX$1)\n])\n\n\ndnl  Test body for checking C++11 support\n\nm4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],\n  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11\n)\n\n\ndnl  Test body for checking C++14 support\n\nm4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],\n  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11\n  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14\n)\n\n\ndnl  Tests for new features in C++11\n\nm4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[\n\n// If the compiler admits that it is not ready for C++11, why torture it?\n// Hopefully, this will speed up the test.\n\n#ifndef __cplusplus\n\n#error \"This is not a C++ compiler\"\n\n#elif __cplusplus < 201103L\n\n#error \"This is not a C++11 compiler\"\n\n#else\n\nnamespace cxx11\n{\n\n  namespace test_static_assert\n  {\n\n    template <typename T>\n    struct check\n    {\n      static_assert(sizeof(int) <= sizeof(T), \"not big enough\");\n    };\n\n  }\n\n  namespace test_final_override\n  {\n\n    struct Base\n    {\n      virtual void f() {}\n    };\n\n    struct Derived : public Base\n    {\n      virtual void f() override {}\n    };\n\n  }\n\n  namespace test_double_right_angle_brackets\n  {\n\n    template < typename T >\n    struct check {};\n\n    typedef check<void> single_type;\n    typedef check<check<void>> double_type;\n    typedef check<check<check<void>>> triple_type;\n    typedef check<check<check<check<void>>>> quadruple_type;\n\n  }\n\n  namespace test_decltype\n  {\n\n    int\n    f()\n    {\n      int a = 1;\n      decltype(a) b = 2;\n      return a + b;\n    }\n\n  }\n\n  namespace test_type_deduction\n  {\n\n    template < typename T1, typename T2 >\n    struct is_same\n    {\n      static const bool value = false;\n    };\n\n    template < typename T >\n    struct is_same<T, T>\n    {\n      static const bool value = true;\n    };\n\n    template < typename T1, typename T2 >\n    auto\n    add(T1 a1, T2 a2) -> decltype(a1 + a2)\n    {\n      return a1 + a2;\n    }\n\n    int\n    test(const int c, volatile int v)\n    {\n      static_assert(is_same<int, decltype(0)>::value == true, \"\");\n      static_assert(is_same<int, decltype(c)>::value == false, \"\");\n      static_assert(is_same<int, decltype(v)>::value == false, \"\");\n      auto ac = c;\n      auto av = v;\n      auto sumi = ac + av + 'x';\n      auto sumf = ac + av + 1.0;\n      static_assert(is_same<int, decltype(ac)>::value == true, \"\");\n      static_assert(is_same<int, decltype(av)>::value == true, \"\");\n      static_assert(is_same<int, decltype(sumi)>::value == true, \"\");\n      static_assert(is_same<int, decltype(sumf)>::value == false, \"\");\n      static_assert(is_same<int, decltype(add(c, v))>::value == true, \"\");\n      return (sumf > 0.0) ? sumi : add(c, v);\n    }\n\n  }\n\n  namespace test_noexcept\n  {\n\n    int f() { return 0; }\n    int g() noexcept { return 0; }\n\n    static_assert(noexcept(f()) == false, \"\");\n    static_assert(noexcept(g()) == true, \"\");\n\n  }\n\n  namespace test_constexpr\n  {\n\n    template < typename CharT >\n    unsigned long constexpr\n    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept\n    {\n      return *s ? strlen_c_r(s + 1, acc + 1) : acc;\n    }\n\n    template < typename CharT >\n    unsigned long constexpr\n    strlen_c(const CharT *const s) noexcept\n    {\n      return strlen_c_r(s, 0UL);\n    }\n\n    static_assert(strlen_c(\"\") == 0UL, \"\");\n    static_assert(strlen_c(\"1\") == 1UL, \"\");\n    static_assert(strlen_c(\"example\") == 7UL, \"\");\n    static_assert(strlen_c(\"another\\0example\") == 7UL, \"\");\n\n  }\n\n  namespace test_rvalue_references\n  {\n\n    template < int N >\n    struct answer\n    {\n      static constexpr int value = N;\n    };\n\n    answer<1> f(int&)       { return answer<1>(); }\n    answer<2> f(const int&) { return answer<2>(); }\n    answer<3> f(int&&)      { return answer<3>(); }\n\n    void\n    test()\n    {\n      int i = 0;\n      const int c = 0;\n      static_assert(decltype(f(i))::value == 1, \"\");\n      static_assert(decltype(f(c))::value == 2, \"\");\n      static_assert(decltype(f(0))::value == 3, \"\");\n    }\n\n  }\n\n  namespace test_uniform_initialization\n  {\n\n    struct test\n    {\n      static const int zero {};\n      static const int one {1};\n    };\n\n    static_assert(test::zero == 0, \"\");\n    static_assert(test::one == 1, \"\");\n\n  }\n\n  namespace test_lambdas\n  {\n\n    void\n    test1()\n    {\n      auto lambda1 = [](){};\n      auto lambda2 = lambda1;\n      lambda1();\n      lambda2();\n    }\n\n    int\n    test2()\n    {\n      auto a = [](int i, int j){ return i + j; }(1, 2);\n      auto b = []() -> int { return '0'; }();\n      auto c = [=](){ return a + b; }();\n      auto d = [&](){ return c; }();\n      auto e = [a, &b](int x) mutable {\n        const auto identity = [](int y){ return y; };\n        for (auto i = 0; i < a; ++i)\n          a += b--;\n        return x + identity(a + b);\n      }(0);\n      return a + b + c + d + e;\n    }\n\n    int\n    test3()\n    {\n      const auto nullary = [](){ return 0; };\n      const auto unary = [](int x){ return x; };\n      using nullary_t = decltype(nullary);\n      using unary_t = decltype(unary);\n      const auto higher1st = [](nullary_t f){ return f(); };\n      const auto higher2nd = [unary](nullary_t f1){\n        return [unary, f1](unary_t f2){ return f2(unary(f1())); };\n      };\n      return higher1st(nullary) + higher2nd(nullary)(unary);\n    }\n\n  }\n\n  namespace test_variadic_templates\n  {\n\n    template <int...>\n    struct sum;\n\n    template <int N0, int... N1toN>\n    struct sum<N0, N1toN...>\n    {\n      static constexpr auto value = N0 + sum<N1toN...>::value;\n    };\n\n    template <>\n    struct sum<>\n    {\n      static constexpr auto value = 0;\n    };\n\n    static_assert(sum<>::value == 0, \"\");\n    static_assert(sum<1>::value == 1, \"\");\n    static_assert(sum<23>::value == 23, \"\");\n    static_assert(sum<1, 2>::value == 3, \"\");\n    static_assert(sum<5, 5, 11>::value == 21, \"\");\n    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, \"\");\n\n  }\n\n  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae\n  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function\n  // because of this.\n  namespace test_template_alias_sfinae\n  {\n\n    struct foo {};\n\n    template<typename T>\n    using member = typename T::member_type;\n\n    template<typename T>\n    void func(...) {}\n\n    template<typename T>\n    void func(member<T>*) {}\n\n    void test();\n\n    void test() { func<foo>(0); }\n\n  }\n\n}  // namespace cxx11\n\n#endif  // __cplusplus >= 201103L\n\n]])\n\n\ndnl  Tests for new features in C++14\n\nm4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[\n\n// If the compiler admits that it is not ready for C++14, why torture it?\n// Hopefully, this will speed up the test.\n\n#ifndef __cplusplus\n\n#error \"This is not a C++ compiler\"\n\n#elif __cplusplus < 201402L\n\n#error \"This is not a C++14 compiler\"\n\n#else\n\nnamespace cxx14\n{\n\n  namespace test_polymorphic_lambdas\n  {\n\n    int\n    test()\n    {\n      const auto lambda = [](auto&&... args){\n        const auto istiny = [](auto x){\n          return (sizeof(x) == 1UL) ? 1 : 0;\n        };\n        const int aretiny[] = { istiny(args)... };\n        return aretiny[0];\n      };\n      return lambda(1, 1L, 1.0f, '1');\n    }\n\n  }\n\n  namespace test_binary_literals\n  {\n\n    constexpr auto ivii = 0b0000000000101010;\n    static_assert(ivii == 42, \"wrong value\");\n\n  }\n\n  namespace test_generalized_constexpr\n  {\n\n    template < typename CharT >\n    constexpr unsigned long\n    strlen_c(const CharT *const s) noexcept\n    {\n      auto length = 0UL;\n      for (auto p = s; *p; ++p)\n        ++length;\n      return length;\n    }\n\n    static_assert(strlen_c(\"\") == 0UL, \"\");\n    static_assert(strlen_c(\"x\") == 1UL, \"\");\n    static_assert(strlen_c(\"test\") == 4UL, \"\");\n    static_assert(strlen_c(\"another\\0test\") == 7UL, \"\");\n\n  }\n\n  namespace test_lambda_init_capture\n  {\n\n    int\n    test()\n    {\n      auto x = 0;\n      const auto lambda1 = [a = x](int b){ return a + b; };\n      const auto lambda2 = [a = lambda1(x)](){ return a; };\n      return lambda2();\n    }\n\n  }\n\n  namespace test_digit_seperators\n  {\n\n    constexpr auto ten_million = 100'000'000;\n    static_assert(ten_million == 100000000, \"\");\n\n  }\n\n  namespace test_return_type_deduction\n  {\n\n    auto f(int& x) { return x; }\n    decltype(auto) g(int& x) { return x; }\n\n    template < typename T1, typename T2 >\n    struct is_same\n    {\n      static constexpr auto value = false;\n    };\n\n    template < typename T >\n    struct is_same<T, T>\n    {\n      static constexpr auto value = true;\n    };\n\n    int\n    test()\n    {\n      auto x = 0;\n      static_assert(is_same<int, decltype(f(x))>::value, \"\");\n      static_assert(is_same<int&, decltype(g(x))>::value, \"\");\n      return x;\n    }\n\n  }\n\n}  // namespace cxx14\n\n#endif  // __cplusplus >= 201402L\n\n]])\n"
  },
  {
    "path": "m4/ax_cxx_compile_stdcxx_11.m4",
    "content": "# ============================================================================\n#  http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html\n# ============================================================================\n#\n# SYNOPSIS\n#\n#   AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional])\n#\n# DESCRIPTION\n#\n#   Check for baseline language coverage in the compiler for the C++11\n#   standard; if necessary, add switches to CXX and CXXCPP to enable\n#   support.\n#\n#   This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX\n#   macro with the version set to C++11.  The two optional arguments are\n#   forwarded literally as the second and third argument respectively.\n#   Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for\n#   more information.  If you want to use this macro, you also need to\n#   download the ax_cxx_compile_stdcxx.m4 file.\n#\n# LICENSE\n#\n#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>\n#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>\n#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>\n#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>\n#   Copyright (c) 2015 Paul Norman <penorman@mac.com>\n#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>\n#\n#   Copying and distribution of this file, with or without modification, are\n#   permitted in any medium without royalty provided the copyright notice\n#   and this notice are preserved. This file is offered as-is, without any\n#   warranty.\n\n#serial 16\n\nm4_include([m4/ax_cxx_compile_stdcxx.m4])\n\nAC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])])\n"
  },
  {
    "path": "m4/ax_func_posix_memalign.m4",
    "content": "# ===========================================================================\n#  https://www.gnu.org/software/autoconf-archive/ax_func_posix_memalign.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_FUNC_POSIX_MEMALIGN\n#\n# DESCRIPTION\n#\n#   Some versions of posix_memalign (notably glibc 2.2.5) incorrectly apply\n#   their power-of-two check to the size argument, not the alignment\n#   argument. AX_FUNC_POSIX_MEMALIGN defines HAVE_POSIX_MEMALIGN if the\n#   power-of-two check is correctly applied to the alignment argument.\n#\n# LICENSE\n#\n#   Copyright (c) 2008 Scott Pakin <pakin@uiuc.edu>\n#\n#   Copying and distribution of this file, with or without modification, are\n#   permitted in any medium without royalty provided the copyright notice\n#   and this notice are preserved. This file is offered as-is, without any\n#   warranty.\n\n#serial 9\n\nAC_DEFUN([AX_FUNC_POSIX_MEMALIGN],\n[AC_CACHE_CHECK([for working posix_memalign],\n  [ax_cv_func_posix_memalign_works],\n  [AC_RUN_IFELSE([AC_LANG_SOURCE([[\n#include <stdlib.h>\n\nint\nmain ()\n{\n  void *buffer;\n\n  /* Some versions of glibc incorrectly perform the alignment check on\n   * the size word. */\n  exit (posix_memalign (&buffer, sizeof(void *), 123) != 0);\n}\n    ]])],\n    [ax_cv_func_posix_memalign_works=yes],\n    [ax_cv_func_posix_memalign_works=no],\n    [ax_cv_func_posix_memalign_works=no])])\nif test \"$ax_cv_func_posix_memalign_works\" = \"yes\" ; then\n  AC_DEFINE([HAVE_POSIX_MEMALIGN], [1],\n    [Define to 1 if `posix_memalign' works.])\nfi\n])\n"
  },
  {
    "path": "m4/ax_valgrind_check.m4",
    "content": "# ===========================================================================\n#     http://www.gnu.org/software/autoconf-archive/ax_valgrind_check.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_VALGRIND_CHECK()\n#\n# DESCRIPTION\n#\n#   Checks whether Valgrind is present and, if so, allows running `make\n#   check` under a variety of Valgrind tools to check for memory and\n#   threading errors.\n#\n#   Defines VALGRIND_CHECK_RULES which should be substituted in your\n#   Makefile; and $enable_valgrind which can be used in subsequent configure\n#   output. VALGRIND_ENABLED is defined and substituted, and corresponds to\n#   the value of the --enable-valgrind option, which defaults to being\n#   enabled if Valgrind is installed and disabled otherwise.\n#\n#   If unit tests are written using a shell script and automake's\n#   LOG_COMPILER system, the $(VALGRIND) variable can be used within the\n#   shell scripts to enable Valgrind, as described here:\n#\n#     https://www.gnu.org/software/gnulib/manual/html_node/Running-self_002dtests-under-valgrind.html\n#\n#   Usage example:\n#\n#   configure.ac:\n#\n#     AX_VALGRIND_CHECK\n#\n#   Makefile.am:\n#\n#     @VALGRIND_CHECK_RULES@\n#     VALGRIND_SUPPRESSIONS_FILES = my-project.supp\n#     EXTRA_DIST = my-project.supp\n#\n#   This results in a \"check-valgrind\" rule being added to any Makefile.am\n#   which includes \"@VALGRIND_CHECK_RULES@\" (assuming the module has been\n#   configured with --enable-valgrind). Running `make check-valgrind` in\n#   that directory will run the module's test suite (`make check`) once for\n#   each of the available Valgrind tools (out of memcheck, helgrind, drd and\n#   sgcheck), and will output results to test-suite-$toolname.log for each.\n#   The target will succeed if there are zero errors and fail otherwise.\n#\n#   Alternatively, a \"check-valgrind-$TOOL\" rule will be added, for $TOOL in\n#   memcheck, helgrind, drd and sgcheck. These are useful because often only\n#   some of those tools can be ran cleanly on a codebase.\n#\n#   The macro supports running with and without libtool.\n#\n# LICENSE\n#\n#   Copyright (c) 2014, 2015, 2016 Philip Withnall <philip.withnall@collabora.co.uk>\n#\n#   Copying and distribution of this file, with or without modification, are\n#   permitted in any medium without royalty provided the copyright notice\n#   and this notice are preserved.  This file is offered as-is, without any\n#   warranty.\n\n#serial 9\n\nAC_DEFUN([AX_VALGRIND_CHECK],[\n\tdnl Check for --enable-valgrind\n\tAC_ARG_ENABLE([valgrind],\n\t              [AS_HELP_STRING([--enable-valgrind], [Whether to enable Valgrind on the unit tests])],\n\t              [enable_valgrind=$enableval],[enable_valgrind=])\n\n\tAS_IF([test \"$enable_valgrind\" != \"no\"],[\n\t\t# Check for Valgrind.\n\t\tAC_CHECK_PROG([VALGRIND],[valgrind],[valgrind])\n\t\tAS_IF([test \"$VALGRIND\" = \"\"],[\n\t\t\tAS_IF([test \"$enable_valgrind\" = \"yes\"],[\n\t\t\t\tAC_MSG_ERROR([Could not find valgrind; either install it or reconfigure with --disable-valgrind])\n\t\t\t],[\n\t\t\t\tenable_valgrind=no\n\t\t\t])\n\t\t],[\n\t\t\tenable_valgrind=yes\n\t\t])\n\t])\n\n\tAM_CONDITIONAL([VALGRIND_ENABLED],[test \"$enable_valgrind\" = \"yes\"])\n\tAC_SUBST([VALGRIND_ENABLED],[$enable_valgrind])\n\n\t# Check for Valgrind tools we care about.\n\tm4_define([valgrind_tool_list],[[memcheck], [helgrind], [drd], [exp-sgcheck]])\n\n\tAS_IF([test \"$VALGRIND\" != \"\"],[\n\t\tm4_foreach([vgtool],[valgrind_tool_list],[\n\t\t\tm4_define([vgtooln],AS_TR_SH(vgtool))\n\t\t\tm4_define([ax_cv_var],[ax_cv_valgrind_tool_]vgtooln)\n\t\t\tAC_CACHE_CHECK([for Valgrind tool ]vgtool,ax_cv_var,[\n\t\t\t\tax_cv_var=\n\t\t\t\tAS_IF([`$VALGRIND --tool=vgtool --help >/dev/null 2>&1`],[\n\t\t\t\t\tax_cv_var=\"vgtool\"\n\t\t\t\t])\n\t\t\t])\n\n\t\t\tAC_SUBST([VALGRIND_HAVE_TOOL_]vgtooln,[$ax_cv_var])\n\t\t])\n\t])\n\n[VALGRIND_CHECK_RULES='\n# Valgrind check\n#\n# Optional:\n#  - VALGRIND_SUPPRESSIONS_FILES: Space-separated list of Valgrind suppressions\n#    files to load. (Default: empty)\n#  - VALGRIND_FLAGS: General flags to pass to all Valgrind tools.\n#    (Default: --num-callers=30)\n#  - VALGRIND_$toolname_FLAGS: Flags to pass to Valgrind $toolname (one of:\n#    memcheck, helgrind, drd, sgcheck). (Default: various)\n\n# Optional variables\nVALGRIND_SUPPRESSIONS ?= $(addprefix --suppressions=,$(VALGRIND_SUPPRESSIONS_FILES))\nVALGRIND_FLAGS ?= --num-callers=30\nVALGRIND_memcheck_FLAGS ?= --leak-check=full --show-reachable=no\nVALGRIND_helgrind_FLAGS ?= --history-level=approx\nVALGRIND_drd_FLAGS ?=\nVALGRIND_sgcheck_FLAGS ?=\n\n# Internal use\nvalgrind_tools = memcheck helgrind drd sgcheck\nvalgrind_log_files = $(addprefix test-suite-,$(addsuffix .log,$(valgrind_tools)))\n\nvalgrind_memcheck_flags = --tool=memcheck $(VALGRIND_memcheck_FLAGS)\nvalgrind_helgrind_flags = --tool=helgrind $(VALGRIND_helgrind_FLAGS)\nvalgrind_drd_flags = --tool=drd $(VALGRIND_drd_FLAGS)\nvalgrind_sgcheck_flags = --tool=exp-sgcheck $(VALGRIND_sgcheck_FLAGS)\n\nvalgrind_quiet = $(valgrind_quiet_$(V))\nvalgrind_quiet_ = $(valgrind_quiet_$(AM_DEFAULT_VERBOSITY))\nvalgrind_quiet_0 = --quiet\n\n# Support running with and without libtool.\nifneq ($(LIBTOOL),)\nvalgrind_lt = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=execute\nelse\nvalgrind_lt =\nendif\n\n# Use recursive makes in order to ignore errors during check\ncheck-valgrind:\nifeq ($(VALGRIND_ENABLED),yes)\n\t-$(foreach tool,$(valgrind_tools), \\\n\t\t$(if $(VALGRIND_HAVE_TOOL_$(tool))$(VALGRIND_HAVE_TOOL_exp_$(tool)), \\\n\t\t\t$(MAKE) $(AM_MAKEFLAGS) -k check-valgrind-tool VALGRIND_TOOL=$(tool); \\\n\t\t) \\\n\t)\nelse\n\t@echo \"Need to reconfigure with --enable-valgrind\"\nendif\n\n# Valgrind running\nVALGRIND_TESTS_ENVIRONMENT = \\\n\t$(TESTS_ENVIRONMENT) \\\n\tenv VALGRIND=$(VALGRIND) \\\n\tG_SLICE=always-malloc,debug-blocks \\\n\tG_DEBUG=fatal-warnings,fatal-criticals,gc-friendly\n\nVALGRIND_LOG_COMPILER = \\\n\t$(valgrind_lt) \\\n\t$(VALGRIND) $(VALGRIND_SUPPRESSIONS) --error-exitcode=1 $(VALGRIND_FLAGS)\n\ncheck-valgrind-tool:\nifeq ($(VALGRIND_ENABLED),yes)\n\t$(MAKE) check-TESTS \\\n\t\tTESTS_ENVIRONMENT=\"$(VALGRIND_TESTS_ENVIRONMENT)\" \\\n\t\tLOG_COMPILER=\"$(VALGRIND_LOG_COMPILER)\" \\\n\t\tLOG_FLAGS=\"$(valgrind_$(VALGRIND_TOOL)_flags)\" \\\n\t\tTEST_SUITE_LOG=test-suite-$(VALGRIND_TOOL).log\nelse\n\t@echo \"Need to reconfigure with --enable-valgrind\"\nendif\n\ncheck-valgrind-memcheck:\nifeq ($(VALGRIND_ENABLED),yes)\n\t$(MAKE) check-TESTS \\\n\t\tTESTS_ENVIRONMENT=\"$(VALGRIND_TESTS_ENVIRONMENT)\" \\\n\t\tLOG_COMPILER=\"$(VALGRIND_LOG_COMPILER)\" \\\n\t\tLOG_FLAGS=\"$(valgrind_memcheck_flags)\" \\\n\t\tTEST_SUITE_LOG=test-suite-memcheck.log\nelse\n\t@echo \"Need to reconfigure with --enable-valgrind\"\nendif\n\ncheck-valgrind-helgrind:\nifeq ($(VALGRIND_ENABLED),yes)\n\t$(MAKE) check-TESTS \\\n\t\tTESTS_ENVIRONMENT=\"$(VALGRIND_TESTS_ENVIRONMENT)\" \\\n\t\tLOG_COMPILER=\"$(VALGRIND_LOG_COMPILER)\" \\\n\t\tLOG_FLAGS=\"$(valgrind_helgrind_flags)\" \\\n\t\tTEST_SUITE_LOG=test-suite-helgrind.log\nelse\n\t@echo \"Need to reconfigure with --enable-valgrind\"\nendif\n\ncheck-valgrind-drd:\nifeq ($(VALGRIND_ENABLED),yes)\n\t$(MAKE) check-TESTS \\\n\t\tTESTS_ENVIRONMENT=\"$(VALGRIND_TESTS_ENVIRONMENT)\" \\\n\t\tLOG_COMPILER=\"$(VALGRIND_LOG_COMPILER)\" \\\n\t\tLOG_FLAGS=\"$(valgrind_drd_flags)\" \\\n\t\tTEST_SUITE_LOG=test-suite-drd.log\nelse\n\t@echo \"Need to reconfigure with --enable-valgrind\"\nendif\n\ncheck-valgrind-sgcheck:\nifeq ($(VALGRIND_ENABLED),yes)\n\t$(MAKE) check-TESTS \\\n\t\tTESTS_ENVIRONMENT=\"$(VALGRIND_TESTS_ENVIRONMENT)\" \\\n\t\tLOG_COMPILER=\"$(VALGRIND_LOG_COMPILER)\" \\\n\t\tLOG_FLAGS=\"$(valgrind_sgcheck_flags)\" \\\n\t\tTEST_SUITE_LOG=test-suite-sgcheck.log\nelse\n\t@echo \"Need to reconfigure with --enable-valgrind\"\nendif\n\nA''M_DISTCHECK_CONFIGURE_FLAGS ?=\nA''M_DISTCHECK_CONFIGURE_FLAGS += --disable-valgrind\n\nMOSTLYCLEANFILES ?=\nMOSTLYCLEANFILES += $(valgrind_log_files)\n\n.PHONY: check-valgrind check-valgrind-tool\n']\n\n\tAC_SUBST([VALGRIND_CHECK_RULES])\n\tm4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([VALGRIND_CHECK_RULES])])\n])\n"
  },
  {
    "path": "packaging/README",
    "content": "This directory is for packaging tools. Please do not hardcode version\nnumbers into your scripts; you can get them at runtime by calling\nversion.sh, or at configure time if you use autoconf.\n\n"
  },
  {
    "path": "packaging/debian/changelog",
    "content": "zeromq (4.3.6-0.1) UNRELEASED; urgency=low\n\n  * Initial packaging.\n\n -- libzmq Developers <zeromq-dev@lists.zeromq.org>  Wed, 31 Dec 2014 00:00:00 +0000\n"
  },
  {
    "path": "packaging/debian/compat",
    "content": "9\n"
  },
  {
    "path": "packaging/debian/control",
    "content": "Source: zeromq\nSection: libs\nPriority: optional\nMaintainer: libzmq Developers <zeromq-dev@lists.zeromq.org>\nBuild-Depends: debhelper (>= 9),\n dh-autoreconf,\n libkrb5-dev,\n libnorm-dev,\n libpgm-dev,\n libsodium-dev,\n libunwind-dev | libunwind8-dev | libunwind7-dev,\n libnss3-dev,\n libgnutls28-dev | libgnutls-dev,\n libbsd-dev,\n pkg-config,\n asciidoctor,\nStandards-Version: 3.9.8\nHomepage: http://www.zeromq.org/\n\nPackage: libzmq5\nArchitecture: any\nDepends: ${shlibs:Depends}, ${misc:Depends}\nPre-Depends: ${misc:Pre-Depends}\nMulti-Arch: same\nDescription: lightweight messaging kernel (shared library)\n ØMQ is a library which extends the standard socket interfaces with features\n traditionally provided by specialised messaging middleware products.\n .\n ØMQ sockets provide an abstraction of asynchronous message queues, multiple\n messaging patterns, message filtering (subscriptions), seamless access to\n multiple transport protocols and more.\n .\n This package contains the libzmq shared library.\n\nPackage: libzmq3-dev\nArchitecture: any\nSection: libdevel\nDepends: libzmq5 (= ${binary:Version}), ${misc:Depends},\n libkrb5-dev,\n libnorm-dev,\n libpgm-dev,\n libsodium-dev,\n libunwind-dev | libunwind8-dev | libunwind7-dev,\n libnss3-dev,\n libgnutls28-dev | libgnutls-dev,\n libbsd-dev,\nConflicts: libzmq-dev, libzmq5-dev\nReplaces: libzmq5-dev\nProvides: libzmq5-dev\nMulti-Arch: same\nDescription: lightweight messaging kernel (development files)\n ØMQ is a library which extends the standard socket interfaces with features\n traditionally provided by specialised messaging middleware products.\n .\n ØMQ sockets provide an abstraction of asynchronous message queues, multiple\n messaging patterns, message filtering (subscriptions), seamless access to\n multiple transport protocols and more.\n .\n This package contains the ZeroMQ development libraries and header files.\n\nPackage: libzmq5-dbg\nArchitecture: any\nPriority: extra\nSection: debug\nDepends: libzmq5 (= ${binary:Version}), ${misc:Depends}\nMulti-Arch: same\nDescription: lightweight messaging kernel (debugging symbols)\n ØMQ is a library which extends the standard socket interfaces with features\n traditionally provided by specialised messaging middleware products.\n .\n ØMQ sockets provide an abstraction of asynchronous message queues, multiple\n messaging patterns, message filtering (subscriptions), seamless access to\n multiple transport protocols and more.\n .\n This package contains the debugging symbols for the ZeroMQ library.\n"
  },
  {
    "path": "packaging/debian/copyright",
    "content": "Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: ZeroMQ\nSource: http://zeromq.org\n\nFiles: *\nCopyright: 2009-2011, 250bpm s.r.o\n 2007-2013, iMatix Corporation\n 2010-2011, Miru Limited\n 2011, VMware, Inc\n 2007-2023, Other contributors as noted in the AUTHORS file\nLicense:  MPL-2.0\n\nFiles: external/unity/*\nCopyright: 2007-2014 Mike Karlesky\n           2007-2014 Mark VanderVoord\n           2007-2014 Greg Williams\nLicense: MIT\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n .\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n .\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n THE SOFTWARE.\n\nFiles: debian/*\nCopyright: 2014-    , Laszlo Boszormenyi (GCS) <gcs@debian.org>\n 2012-2014, Alessandro Ghedini <ghedo@debian.org>\n 2010-2012, Martin Lucina <martin@lucina.net>\n 2009-2010, Adrian von Bidder <cmot@debian.org>\n 2009-2010, Peter Busser <peter@mirabilix.nl>\n 2012, Alessandro Ghedini <ghedo@debian.org>\nLicense: LGPL-2.0+\n\nLicense: LGPL-2.0+\n This package is free software; you can redistribute it and/or\n modify it under the terms of the GNU Lesser General Public\n License as published by the Free Software Foundation; either\n version 2 of the License, or (at your option) any later version.\n .\n This package is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n Lesser General Public License for more details.\n .\n You should have received a copy of the GNU General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n .\n On Debian systems, the complete text of the GNU Lesser General\n Public License can be found in \"/usr/share/common-licenses/LGPL-2\".\n\nLicense: MPL-2.0\n On Debian systems the full text of the MPL-2.0 can be found in\n /usr/share/common-licenses/MPL-2.0.\n"
  },
  {
    "path": "packaging/debian/libzmq3-dev.install",
    "content": "usr/include/*\nusr/lib/*/libzmq.a\nusr/lib/*/libzmq.so\nusr/lib/*/pkgconfig/libzmq.pc\n"
  },
  {
    "path": "packaging/debian/libzmq3-dev.manpages",
    "content": "debian/tmp/usr/share/man/man3/*\ndebian/tmp/usr/share/man/man7/*\n"
  },
  {
    "path": "packaging/debian/libzmq5.docs",
    "content": "AUTHORS\nNEWS\n"
  },
  {
    "path": "packaging/debian/libzmq5.install",
    "content": "usr/lib/*/libzmq.so.*\n"
  },
  {
    "path": "packaging/debian/rules",
    "content": "#!/usr/bin/make -f\n# -*- makefile -*-\n\n# Uncomment this to turn on verbose mode.\n#export DH_VERBOSE=1\n\nexport DEB_BUILD_MAINT_OPTIONS=hardening=+all\n\nexport TEST_VERBOSE=1\n\nifeq ($(DEB_BUILD_ARCH_OS), kfreebsd)\n\tDO_TEST = no\nendif\n\nDRAFTS=no\n\n# OBS build: add\n#   Macros:\n#   %_with_drafts 1\n# at the BOTTOM of the OBS prjconf\nOBS_BUILD_CFG=/.build/build.dist\nifeq (\"$(wildcard $(OBS_BUILD_CFG))\",\"\")\nBUILDCONFIG=$(shell ls -1 /usr/src/packages/SOURCES/_buildconfig* | head -n 1)\nendif\nifneq (\"$(wildcard $(OBS_BUILD_CFG))\",\"\")\nifneq (\"$(shell grep drafts $(OBS_BUILD_CFG))\",\"\")\nDRAFTS=yes\nendif\nendif\n\n# User build: DEB_BUILD_OPTIONS=drafts dpkg-buildpackage\nifneq (,$(findstring drafts,$(DEB_BUILD_OPTIONS)))\nDRAFTS=yes\nendif\n\n# Workaround for automake < 1.14 bug\n$(shell dpkg --compare-versions `dpkg-query -W -f='$${Version}\\n' automake` lt 1:1.14 && mkdir -p config)\n\noverride_dh_clean:\n\tdh_clean\n\tfind $(CURDIR) -type s -exec rm {} \\;\n\trm -f $(CURDIR)/doc/*.xml $(CURDIR)/doc/*.3 $(CURDIR)/doc/*.7\n\trm -f config.log\n\noverride_dh_auto_configure:\n\tdh_auto_configure -- --with-pgm --with-libsodium --enable-drafts=$(DRAFTS) --with-libgssapi_krb5=yes --with-norm=yes --with-nss=yes --with-tls=yes\n\noverride_dh_auto_test:\nifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))\nifneq ($(DO_TEST), no)\n\tdh_auto_test -- VERBOSE=1\nelse\n\t-dh_auto_test -- VERBOSE=1\nendif\nendif\n\noverride_dh_auto_install:\n\tdh_auto_install\nifneq (\"$(wildcard debian/zmq.hpp)\",\"\")\n\tcp $(CURDIR)/debian/zmq.hpp $(CURDIR)/debian/tmp/usr/include/\nendif\n\noverride_dh_strip:\n\tdh_strip --dbg-package=libzmq5-dbg\n\n%:\n\tdh $@ --with=autoreconf --parallel\n\n.PHONY: override_dh_auto_configure override_dh_strip\n"
  },
  {
    "path": "packaging/debian/source/format",
    "content": "3.0 (quilt)\n"
  },
  {
    "path": "packaging/debian/zeromq.dsc",
    "content": "Format: 3.0 (quilt)\nSource: zeromq\nBinary: libzmq5, libzmq3-dev, libzmq5-dbg\nArchitecture: any\nVersion: 4.3.6-0.1\nMaintainer: libzmq Developers <zeromq-dev@lists.zeromq.org>\nHomepage: http://www.zeromq.org/\nStandards-Version: 3.9.8\nBuild-Depends: debhelper (>= 9), dh-autoreconf, libkrb5-dev, libpgm-dev, libnorm-dev, libsodium-dev, libunwind-dev | libunwind8-dev | libunwind7-dev, libnss3-dev, libgnutls28-dev | libgnutls-dev, libbsd-dev, pkg-config, asciidoctor\nPackage-List:\n libzmq3-dev deb libdevel optional arch=any\n libzmq5 deb libs optional arch=any\n libzmq5-dbg deb debug extra arch=any\nFiles:\n e7adf4b7dbae09b28cfd10d26cd67fac 794853 zeromq.orig.tar.gz\n"
  },
  {
    "path": "packaging/nuget/package.bat",
    "content": "@ECHO OFF\nECHO Started nuget packaging build.\nECHO.\nREM http://www.nuget.org/packages/gsl\ngsl -q -script:package.gsl package.config\nECHO.\nREM http://nuget.codeplex.com/releases\nnuget pack package.nuspec -verbosity detailed\nECHO.\nECHO NOTE: Ignore warnings not applicable to native code: \"Issue: Assembly outside lib folder.\"\nECHO.\nECHO Completed nuget packaging build. The package is in the following folder:\nCD\nPAUSE"
  },
  {
    "path": "packaging/nuget/package.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- These values are populated into the package.gsl templates by package.bat. -->\n<!-- The target attribute controls path and file name only, id controls package naming. -->\n<package id=\"libzmq-vc142\" target=\"libzmq\" version = \"4.2.3.0\" pathversion=\"4_2_3_0\" platformtoolset=\"v142\">\n  <!--<dependency id=\"libsodium_vc120\" version=\"1.0.12.0\" />-->\n</package>"
  },
  {
    "path": "packaging/nuget/package.gsl",
    "content": ".#  Generate NuGet nuspec file (for subsequent packing).\n.#\n.#  This is a code generator built using the iMatix GSL code generation\n.#  language. See https://github.com/zeromq/gsl for details. This script\n.#  is licensed under MIT/X11.\n.#\n.echo \"Generating package.nuspec from template.\"\n.output \"package.nuspec\"\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n#################################################################\n#   GENERATED SOURCE CODE, DO NOT EDIT EXCEPT EXPERIMENTALLY    #\n#################################################################\n-->\n<package xmlns=\"http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd\">\n    <metadata minClientVersion=\"2.5\">\n        <id>$(package.id)</id>\n        <version>$(package.version)</version>\n        <title>$(package.id)</title>\n        <authors>libzmq contributors</authors>\n        <owners>Eric Voskuil</owners>\n        <licenseUrl>https://raw.github.com/zeromq/libzmq/master/LICENSE</licenseUrl>\n        <projectUrl>https://github.com/zeromq/libzmq</projectUrl>\n        <iconUrl>https://avatars1.githubusercontent.com/u/109777?s=32</iconUrl>\n        <requireLicenseAcceptance>true</requireLicenseAcceptance>\n        <developmentDependency>false</developmentDependency>\n        <description>The 0MQ lightweight messaging kernel is a library which extends the standard socket interfaces with features traditionally provided by specialised messaging middleware products. 0MQ sockets provide an abstraction of asynchronous message queues, multiple messaging patterns, message filtering (subscriptions), seamless access to multiple transport protocols and more.</description>\n        <summary>The 0MQ lightweight messaging kernel, packaged for specific Visual Studio compiler.</summary>\n        <releaseNotes>https://raw.github.com/zeromq/libzmq/master/NEWS</releaseNotes>\n        <copyright>MPL-2.0</copyright>\n        <tags>native, libzmq, zmq, 0MQ, messaging, sockets, C++</tags>\n        <dependencies>\n.for dependency\n            <dependency id=\"$(id)\" version=\"$(version)\" />\n.endfor\n        </dependencies>\n    </metadata>\n    <files>\n        <!-- include -->\n        \n        <file src=\"..\\\\..\\\\include\\\\*.h\" target=\"build\\\\native\\\\include\" />\n        <file src=\"..\\\\..\\\\builds\\\\msvc\\\\platform.hpp\" target=\"build\\\\native\\\\include\" />\n\n        <!-- targets -->\n      \n        <file src=\"package.targets\" target=\"build\\\\native\\\\$(package.id).targets\" />\n        <file src=\"package.xml\" target=\"build\\\\native\\\\package.xml\" />\n        \n        <!-- docs -->\n        \n        <!-- Documents (.*) -->\n        <!--<file src=\"..\\\\..\\\\docs\\\\*\" target=\"build\\\\native\\\\docs\" />-->\n        \n        <!-- libraries -->\n\n        <!-- x86 Dynamic libraries (.dll) -->\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Release\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).dll\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-$(package.pathversion).dll\" />\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Debug\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).dll\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-gd-$(package.pathversion).dll\" />\n\n        <!-- x86 Debugging symbols (.pdb) -->\n        <!--<file src=\"..\\\\..\\\\bin\\\\Win32\\\\Release\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).pdb\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-$(package.pathversion).pdb\" />-->\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Debug\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).pdb\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-gd-$(package.pathversion).pdb\" />\n\n        <!-- x86 Import libraries (.imp.lib) -->\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Release\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-$(package.pathversion).imp.lib\" />\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Debug\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-gd-$(package.pathversion).imp.lib\" />\n\n        <!-- x86 Export libraries (.exp) -->\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Release\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).exp\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-$(package.pathversion).exp\" />\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Debug\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).exp\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-gd-$(package.pathversion).exp\" />\n\n        <!-- x86 Static libraries (.lib) -->\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Release\\\\$(package.platformtoolset)\\\\static\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-s-$(package.pathversion).lib\" />\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Debug\\\\$(package.platformtoolset)\\\\static\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-sgd-$(package.pathversion).lib\" />\n\n        <!-- x86 Static link time code generation libraries (.ltcg.lib) -->\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Release\\\\$(package.platformtoolset)\\\\ltcg\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-s-$(package.pathversion).ltcg.lib\" />\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Debug\\\\$(package.platformtoolset)\\\\ltcg\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-sgd-$(package.pathversion).ltcg.lib\" />\n\n        <!-- x64 Dynamic libraries (.dll) -->\n        <file src=\"..\\\\..\\\\bin\\\\x64\\\\Release\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).dll\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-$(package.pathversion).dll\" />\n        <file src=\"..\\\\..\\\\bin\\\\x64\\\\Debug\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).dll\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-gd-$(package.pathversion).dll\" />\n\n        <!-- x64 Debugging symbols (.pdb) -->\n        <!--<file src=\"..\\\\..\\\\bin\\\\x64\\\\Release\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).pdb\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-$(package.pathversion).pdb\" />-->\n        <file src=\"..\\\\..\\\\bin\\\\x64\\\\Debug\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).pdb\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-gd-$(package.pathversion).pdb\" />\n\n        <!-- x64 Import libraries (.imp.lib) -->\n        <file src=\"..\\\\..\\\\bin\\\\x64\\\\Release\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-$(package.pathversion).imp.lib\" />\n        <file src=\"..\\\\..\\\\bin\\\\x64\\\\Debug\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-gd-$(package.pathversion).imp.lib\" />\n\n        <!-- x64 Export libraries (.exp) -->\n        <file src=\"..\\\\..\\\\bin\\\\x64\\\\Release\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).exp\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-$(package.pathversion).exp\" />\n        <file src=\"..\\\\..\\\\bin\\\\x64\\\\Debug\\\\$(package.platformtoolset)\\\\dynamic\\\\$(package.target).exp\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-gd-$(package.pathversion).exp\" />\n\n        <!-- x64 Static libraries (.lib) -->\n        <file src=\"..\\\\..\\\\bin\\\\x64\\\\Release\\\\$(package.platformtoolset)\\\\static\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-s-$(package.pathversion).lib\" />\n        <file src=\"..\\\\..\\\\bin\\\\x64\\\\Debug\\\\$(package.platformtoolset)\\\\static\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-sgd-$(package.pathversion).lib\" />\n\n        <!-- x64 Static link time code generation libraries (.ltcg.lib) -->\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Release\\\\$(package.platformtoolset)\\\\ltcg\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-s-$(package.pathversion).ltcg.lib\" />\n        <file src=\"..\\\\..\\\\bin\\\\Win32\\\\Debug\\\\$(package.platformtoolset)\\\\ltcg\\\\$(package.target).lib\" target=\"build\\\\native\\\\bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-sgd-$(package.pathversion).ltcg.lib\" />\n    </files>\n<!--\n#################################################################\n#   GENERATED SOURCE CODE, DO NOT EDIT EXCEPT EXPERIMENTALLY    #\n#################################################################\n-->\n</package>\n.echo \"Generating package.targets from template.\"\n.output \"package.targets\"\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n#################################################################\n#   GENERATED SOURCE CODE, DO NOT EDIT EXCEPT EXPERIMENTALLY    #\n#################################################################\n-->\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <!-- user interface -->\n  <ItemGroup>\n    <PropertyPageSchema Include=\"$\\(MSBuildThisFileDirectory)package.xml\" />\n  </ItemGroup>\n\n  <!-- general -->\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$\\(MSBuildThisFileDirectory)include\\\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalLibraryDirectories>$\\(MSBuildThisFileDirectory)bin\\\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$\\(Linkage-$(package.target))' == 'static' Or '$\\(Linkage-$(package.target))' == 'ltcg'\">\n    <ClCompile>\n      <PreprocessorDefinitions>ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <!-- static libraries -->\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'Win32' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'static' And $\\(Configuration.IndexOf('Release')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x86-$(package.platformtoolset)-mt-s-$(package.pathversion).lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'Win32' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'static' And $\\(Configuration.IndexOf('Debug')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x86-$(package.platformtoolset)-mt-sgd-$(package.pathversion).lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'x64' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'static' And $\\(Configuration.IndexOf('Release')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x64-$(package.platformtoolset)-mt-s-$(package.pathversion).lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'x64' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'static' And $\\(Configuration.IndexOf('Debug')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x64-$(package.platformtoolset)-mt-sgd-$(package.pathversion).lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- static ltcg libraries -->\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'Win32' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'ltcg' And $\\(Configuration.IndexOf('Release')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x86-$(package.platformtoolset)-mt-s-$(package.pathversion).ltcg.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'Win32' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'ltcg' And $\\(Configuration.IndexOf('Debug')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x86-$(package.platformtoolset)-mt-sgd-$(package.pathversion).ltcg.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'x64' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'ltcg' And $\\(Configuration.IndexOf('Release')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x64-$(package.platformtoolset)-mt-s-$(package.pathversion).ltcg.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'x64' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'ltcg' And $\\(Configuration.IndexOf('Debug')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x64-$(package.platformtoolset)-mt-sgd-$(package.pathversion).ltcg.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  \n  <!-- dynamic import libraries -->\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'Win32' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'dynamic' And $\\(Configuration.IndexOf('Release')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x86-$(package.platformtoolset)-mt-$(package.pathversion).imp.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'Win32' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'dynamic' And $\\(Configuration.IndexOf('Debug')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x86-$(package.platformtoolset)-mt-gd-$(package.pathversion).imp.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'x64' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'dynamic' And $\\(Configuration.IndexOf('Release')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x64-$(package.platformtoolset)-mt-$(package.pathversion).imp.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$\\(Platform)' == 'x64' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'dynamic' And $\\(Configuration.IndexOf('Debug')) != -1\">\n    <Link>\n      <AdditionalDependencies>$(package.target)-x64-$(package.platformtoolset)-mt-gd-$(package.pathversion).imp.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <!-- dynamic libraries with debug symbols -->\n  <Target Name=\"$(package.target)_AfterBuild\" AfterTargets=\"AfterBuild\" />\n  <Target Name=\"$(package.target)_AfterBuild_Win32_$(package.platformtoolset)_Dynamic_Release\"\n          Condition=\"'$\\(Platform)' == 'Win32' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'dynamic' And $\\(Configuration.IndexOf('Release')) != -1\"\n          AfterTargets=\"$(package.target)_AfterBuild\">\n    <Copy SourceFiles=\"$\\(MSBuildThisFileDirectory)bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-$(package.pathversion).dll\" DestinationFiles=\"$\\(TargetDir)$(package.target).dll\" SkipUnchangedFiles=\"true\" />\n    <!--<Copy SourceFiles=\"$\\(MSBuildThisFileDirectory)bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-$(package.pathversion).pdb\" DestinationFiles=\"$\\(TargetDir)$(package.target).pdb\" SkipUnchangedFiles=\"true\" />-->\n  </Target>\n  <Target Name=\"$(package.target)_AfterBuild_Win32_$(package.platformtoolset)_Dynamic_Debug\"\n          Condition=\"'$\\(Platform)' == 'Win32' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'dynamic' And $\\(Configuration.IndexOf('Debug')) != -1\"\n          AfterTargets=\"$(package.target)_AfterBuild\">\n    <Copy SourceFiles=\"$\\(MSBuildThisFileDirectory)bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-gd-$(package.pathversion).dll\" DestinationFiles=\"$\\(TargetDir)$(package.target).dll\" SkipUnchangedFiles=\"true\" />\n    <Copy SourceFiles=\"$\\(MSBuildThisFileDirectory)bin\\\\$(package.target)-x86-$(package.platformtoolset)-mt-gd-$(package.pathversion).pdb\" DestinationFiles=\"$\\(TargetDir)$(package.target).pdb\" SkipUnchangedFiles=\"true\" />\n  </Target>\n  <Target Name=\"$(package.target)_AfterBuild_x64_$(package.platformtoolset)_Dynamic_Release\"\n          Condition=\"'$\\(Platform)' == 'x64' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'dynamic' And $\\(Configuration.IndexOf('Release')) != -1\"\n          AfterTargets=\"$(package.target)_AfterBuild\">\n    <Copy SourceFiles=\"$\\(MSBuildThisFileDirectory)bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-$(package.pathversion).dll\" DestinationFiles=\"$\\(TargetDir)$(package.target).dll\" SkipUnchangedFiles=\"true\" />\n    <!--<Copy SourceFiles=\"$\\(MSBuildThisFileDirectory)bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-$(package.pathversion).pdb\" DestinationFiles=\"$\\(TargetDir)$(package.target).pdb\" SkipUnchangedFiles=\"true\" />-->\n  </Target>\n  <Target Name=\"$(package.target)_AfterBuild_x64_$(package.platformtoolset)_Dynamic_Debug\"\n          Condition=\"'$\\(Platform)' == 'x64' And ('$\\(PlatformToolset)' == '$(package.platformtoolset)' Or '$\\(PlatformToolset)' == 'CTP_Nov2013') And '$\\(Linkage-$(package.target))' == 'dynamic' And $\\(Configuration.IndexOf('Debug')) != -1\"\n          AfterTargets=\"$(package.target)_AfterBuild\">\n    <Copy SourceFiles=\"$\\(MSBuildThisFileDirectory)bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-gd-$(package.pathversion).dll\" DestinationFiles=\"$\\(TargetDir)$(package.target).dll\" SkipUnchangedFiles=\"true\" />\n    <Copy SourceFiles=\"$\\(MSBuildThisFileDirectory)bin\\\\$(package.target)-x64-$(package.platformtoolset)-mt-gd-$(package.pathversion).pdb\" DestinationFiles=\"$\\(TargetDir)$(package.target).pdb\" SkipUnchangedFiles=\"true\" />\n  </Target>\n\n<!--\n#################################################################\n#   GENERATED SOURCE CODE, DO NOT EDIT EXCEPT EXPERIMENTALLY    #\n#################################################################\n-->\n</Project>\n.echo \"Generating package.xml (ui extension) from template.\"\n.output \"package.xml\"\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n#################################################################\n#   GENERATED SOURCE CODE, DO NOT EDIT EXCEPT EXPERIMENTALLY    #\n#################################################################\n-->\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\n  <Rule Name=\"Linkage-$(package.target)-uiextension\" PageTemplate=\"tool\" DisplayName=\"NuGet Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\n    <Rule.Categories>\n      <Category Name=\"$(package.target)\" DisplayName=\"$(package.target)\" />\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\n    </Rule.DataSource>\n    <EnumProperty Name=\"Linkage-$(package.target)\" DisplayName=\"Linkage\" Description=\"How NuGet $(package.target) will be linked into the output of this project\" Category=\"$(package.target)\">\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\n    </EnumProperty>\n  </Rule>\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "packaging/nuget/package.nuspec",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<!--\r\n#################################################################\r\n#   GENERATED SOURCE CODE, DO NOT EDIT EXCEPT EXPERIMENTALLY    #\r\n#################################################################\r\n-->\r\n<package xmlns=\"http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd\">\r\n    <metadata minClientVersion=\"2.5\">\r\n        <id>libzmq-vc142</id>\r\n        <version>4.2.3.0</version>\r\n        <title>libzmq-vc142</title>\r\n        <authors>libzmq contributors</authors>\r\n        <owners>Eric Voskuil</owners>\r\n        <licenseUrl>https://raw.github.com/zeromq/libzmq/master/LICENSE</licenseUrl>\r\n        <projectUrl>https://github.com/zeromq/libzmq</projectUrl>\r\n        <iconUrl>https://avatars1.githubusercontent.com/u/109777?s=32</iconUrl>\r\n        <requireLicenseAcceptance>true</requireLicenseAcceptance>\r\n        <developmentDependency>false</developmentDependency>\r\n        <description>The 0MQ lightweight messaging kernel is a library which extends the standard socket interfaces with features traditionally provided by specialised messaging middleware products. 0MQ sockets provide an abstraction of asynchronous message queues, multiple messaging patterns, message filtering (subscriptions), seamless access to multiple transport protocols and more.</description>\r\n        <summary>The 0MQ lightweight messaging kernel, packaged for specific Visual Studio compiler.</summary>\r\n        <releaseNotes>https://raw.github.com/zeromq/libzmq/master/NEWS</releaseNotes>\r\n        <copyright>MPL-2.0</copyright>\r\n        <tags>native, libzmq, zmq, 0MQ, messaging, sockets, C++</tags>\r\n        <dependencies>\r\n        </dependencies>\r\n    </metadata>\r\n    <files>\r\n        <!-- include -->\r\n\r\n        <file src=\"..\\..\\include\\*.h\" target=\"build\\native\\include\" />\r\n        <file src=\"..\\..\\builds\\msvc\\platform.hpp\" target=\"build\\native\\include\" />\r\n\r\n        <!-- targets -->\r\n\r\n        <file src=\"package.targets\" target=\"build\\native\\libzmq-vc142.targets\" />\r\n        <file src=\"package.xml\" target=\"build\\native\\package.xml\" />\r\n\r\n        <!-- docs -->\r\n\r\n        <!-- Documents (.*) -->\r\n        <!--<file src=\"..\\..\\docs\\*\" target=\"build\\native\\docs\" />-->\r\n\r\n        <!-- libraries -->\r\n\r\n        <!-- x86 Dynamic libraries (.dll) -->\r\n        <file src=\"..\\..\\bin\\Win32\\Release\\v142\\dynamic\\libzmq.dll\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-4_2_3_0.dll\" />\r\n        <file src=\"..\\..\\bin\\Win32\\Debug\\v142\\dynamic\\libzmq.dll\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-gd-4_2_3_0.dll\" />\r\n\r\n        <!-- x86 Debugging symbols (.pdb) -->\r\n        <!--<file src=\"..\\..\\bin\\Win32\\Release\\v142\\dynamic\\libzmq.pdb\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-4_2_3_0.pdb\" />-->\r\n        <file src=\"..\\..\\bin\\Win32\\Debug\\v142\\dynamic\\libzmq.pdb\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-gd-4_2_3_0.pdb\" />\r\n\r\n        <!-- x86 Import libraries (.imp.lib) -->\r\n        <file src=\"..\\..\\bin\\Win32\\Release\\v142\\dynamic\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-4_2_3_0.imp.lib\" />\r\n        <file src=\"..\\..\\bin\\Win32\\Debug\\v142\\dynamic\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-gd-4_2_3_0.imp.lib\" />\r\n\r\n        <!-- x86 Export libraries (.exp) -->\r\n        <file src=\"..\\..\\bin\\Win32\\Release\\v142\\dynamic\\libzmq.exp\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-4_2_3_0.exp\" />\r\n        <file src=\"..\\..\\bin\\Win32\\Debug\\v142\\dynamic\\libzmq.exp\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-gd-4_2_3_0.exp\" />\r\n\r\n        <!-- x86 Static libraries (.lib) -->\r\n        <file src=\"..\\..\\bin\\Win32\\Release\\v142\\static\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-s-4_2_3_0.lib\" />\r\n        <file src=\"..\\..\\bin\\Win32\\Debug\\v142\\static\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-sgd-4_2_3_0.lib\" />\r\n\r\n        <!-- x86 Static link time code generation libraries (.ltcg.lib) -->\r\n        <file src=\"..\\..\\bin\\Win32\\Release\\v142\\ltcg\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-s-4_2_3_0.ltcg.lib\" />\r\n        <file src=\"..\\..\\bin\\Win32\\Debug\\v142\\ltcg\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x86-v142-mt-sgd-4_2_3_0.ltcg.lib\" />\r\n\r\n        <!-- x64 Dynamic libraries (.dll) -->\r\n        <file src=\"..\\..\\bin\\x64\\Release\\v142\\dynamic\\libzmq.dll\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-4_2_3_0.dll\" />\r\n        <file src=\"..\\..\\bin\\x64\\Debug\\v142\\dynamic\\libzmq.dll\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-gd-4_2_3_0.dll\" />\r\n\r\n        <!-- x64 Debugging symbols (.pdb) -->\r\n        <!--<file src=\"..\\..\\bin\\x64\\Release\\v142\\dynamic\\libzmq.pdb\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-4_2_3_0.pdb\" />-->\r\n        <file src=\"..\\..\\bin\\x64\\Debug\\v142\\dynamic\\libzmq.pdb\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-gd-4_2_3_0.pdb\" />\r\n\r\n        <!-- x64 Import libraries (.imp.lib) -->\r\n        <file src=\"..\\..\\bin\\x64\\Release\\v142\\dynamic\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-4_2_3_0.imp.lib\" />\r\n        <file src=\"..\\..\\bin\\x64\\Debug\\v142\\dynamic\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-gd-4_2_3_0.imp.lib\" />\r\n\r\n        <!-- x64 Export libraries (.exp) -->\r\n        <file src=\"..\\..\\bin\\x64\\Release\\v142\\dynamic\\libzmq.exp\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-4_2_3_0.exp\" />\r\n        <file src=\"..\\..\\bin\\x64\\Debug\\v142\\dynamic\\libzmq.exp\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-gd-4_2_3_0.exp\" />\r\n\r\n        <!-- x64 Static libraries (.lib) -->\r\n        <file src=\"..\\..\\bin\\x64\\Release\\v142\\static\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-s-4_2_3_0.lib\" />\r\n        <file src=\"..\\..\\bin\\x64\\Debug\\v142\\static\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-sgd-4_2_3_0.lib\" />\r\n\r\n        <!-- x64 Static link time code generation libraries (.ltcg.lib) -->\r\n        <file src=\"..\\..\\bin\\Win32\\Release\\v142\\ltcg\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-s-4_2_3_0.ltcg.lib\" />\r\n        <file src=\"..\\..\\bin\\Win32\\Debug\\v142\\ltcg\\libzmq.lib\" target=\"build\\native\\bin\\libzmq-x64-v142-mt-sgd-4_2_3_0.ltcg.lib\" />\r\n    </files>\r\n<!--\r\n#################################################################\r\n#   GENERATED SOURCE CODE, DO NOT EDIT EXCEPT EXPERIMENTALLY    #\r\n#################################################################\r\n-->\r\n</package>\r\n"
  },
  {
    "path": "packaging/nuget/package.targets",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<!--\r\n#################################################################\r\n#   GENERATED SOURCE CODE, DO NOT EDIT EXCEPT EXPERIMENTALLY    #\r\n#################################################################\r\n-->\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n\r\n  <!-- user interface -->\r\n  <ItemGroup>\r\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)package.xml\" />\r\n  </ItemGroup>\r\n\r\n  <!-- general -->\r\n  <ItemDefinitionGroup>\r\n    <ClCompile>\r\n      <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)bin\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Linkage-libzmq)' == 'static' Or '$(Linkage-libzmq)' == 'ltcg'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n\r\n  <!-- static libraries -->\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'Win32' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'static' And $(Configuration.IndexOf('Release')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x86-v142-mt-s-4_2_3_0.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'Win32' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'static' And $(Configuration.IndexOf('Debug')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x86-v142-mt-sgd-4_2_3_0.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'x64' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'static' And $(Configuration.IndexOf('Release')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x64-v142-mt-s-4_2_3_0.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'x64' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'static' And $(Configuration.IndexOf('Debug')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x64-v142-mt-sgd-4_2_3_0.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n\r\n  <!-- static ltcg libraries -->\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'Win32' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'ltcg' And $(Configuration.IndexOf('Release')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x86-v142-mt-s-4_2_3_0.ltcg.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'Win32' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'ltcg' And $(Configuration.IndexOf('Debug')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x86-v142-mt-sgd-4_2_3_0.ltcg.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'x64' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'ltcg' And $(Configuration.IndexOf('Release')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x64-v142-mt-s-4_2_3_0.ltcg.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'x64' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'ltcg' And $(Configuration.IndexOf('Debug')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x64-v142-mt-sgd-4_2_3_0.ltcg.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n\r\n  <!-- dynamic import libraries -->\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'Win32' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'dynamic' And $(Configuration.IndexOf('Release')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x86-v142-mt-4_2_3_0.imp.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'Win32' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'dynamic' And $(Configuration.IndexOf('Debug')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x86-v142-mt-gd-4_2_3_0.imp.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'x64' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'dynamic' And $(Configuration.IndexOf('Release')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x64-v142-mt-4_2_3_0.imp.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)' == 'x64' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'dynamic' And $(Configuration.IndexOf('Debug')) != -1\">\r\n    <Link>\r\n      <AdditionalDependencies>libzmq-x64-v142-mt-gd-4_2_3_0.imp.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n\r\n  <!-- dynamic libraries with debug symbols -->\r\n  <Target Name=\"libzmq_AfterBuild\" AfterTargets=\"AfterBuild\" />\r\n  <Target Name=\"libzmq_AfterBuild_Win32_v142_Dynamic_Release\"\r\n          Condition=\"'$(Platform)' == 'Win32' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'dynamic' And $(Configuration.IndexOf('Release')) != -1\"\r\n          AfterTargets=\"libzmq_AfterBuild\">\r\n    <Copy SourceFiles=\"$(MSBuildThisFileDirectory)bin\\libzmq-x86-v142-mt-4_2_3_0.dll\" DestinationFiles=\"$(TargetDir)libzmq.dll\" SkipUnchangedFiles=\"true\" />\r\n    <!--<Copy SourceFiles=\"$(MSBuildThisFileDirectory)bin\\libzmq-x86-v142-mt-4_2_3_0.pdb\" DestinationFiles=\"$(TargetDir)libzmq.pdb\" SkipUnchangedFiles=\"true\" />-->\r\n  </Target>\r\n  <Target Name=\"libzmq_AfterBuild_Win32_v142_Dynamic_Debug\"\r\n          Condition=\"'$(Platform)' == 'Win32' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'dynamic' And $(Configuration.IndexOf('Debug')) != -1\"\r\n          AfterTargets=\"libzmq_AfterBuild\">\r\n    <Copy SourceFiles=\"$(MSBuildThisFileDirectory)bin\\libzmq-x86-v142-mt-gd-4_2_3_0.dll\" DestinationFiles=\"$(TargetDir)libzmq.dll\" SkipUnchangedFiles=\"true\" />\r\n    <Copy SourceFiles=\"$(MSBuildThisFileDirectory)bin\\libzmq-x86-v142-mt-gd-4_2_3_0.pdb\" DestinationFiles=\"$(TargetDir)libzmq.pdb\" SkipUnchangedFiles=\"true\" />\r\n  </Target>\r\n  <Target Name=\"libzmq_AfterBuild_x64_v142_Dynamic_Release\"\r\n          Condition=\"'$(Platform)' == 'x64' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'dynamic' And $(Configuration.IndexOf('Release')) != -1\"\r\n          AfterTargets=\"libzmq_AfterBuild\">\r\n    <Copy SourceFiles=\"$(MSBuildThisFileDirectory)bin\\libzmq-x64-v142-mt-4_2_3_0.dll\" DestinationFiles=\"$(TargetDir)libzmq.dll\" SkipUnchangedFiles=\"true\" />\r\n    <!--<Copy SourceFiles=\"$(MSBuildThisFileDirectory)bin\\libzmq-x64-v142-mt-4_2_3_0.pdb\" DestinationFiles=\"$(TargetDir)libzmq.pdb\" SkipUnchangedFiles=\"true\" />-->\r\n  </Target>\r\n  <Target Name=\"libzmq_AfterBuild_x64_v142_Dynamic_Debug\"\r\n          Condition=\"'$(Platform)' == 'x64' And ('$(PlatformToolset)' == 'v142' Or '$(PlatformToolset)' == 'CTP_Nov2013') And '$(Linkage-libzmq)' == 'dynamic' And $(Configuration.IndexOf('Debug')) != -1\"\r\n          AfterTargets=\"libzmq_AfterBuild\">\r\n    <Copy SourceFiles=\"$(MSBuildThisFileDirectory)bin\\libzmq-x64-v142-mt-gd-4_2_3_0.dll\" DestinationFiles=\"$(TargetDir)libzmq.dll\" SkipUnchangedFiles=\"true\" />\r\n    <Copy SourceFiles=\"$(MSBuildThisFileDirectory)bin\\libzmq-x64-v142-mt-gd-4_2_3_0.pdb\" DestinationFiles=\"$(TargetDir)libzmq.pdb\" SkipUnchangedFiles=\"true\" />\r\n  </Target>\r\n\r\n<!--\r\n#################################################################\r\n#   GENERATED SOURCE CODE, DO NOT EDIT EXCEPT EXPERIMENTALLY    #\r\n#################################################################\r\n-->\r\n</Project>\r\n"
  },
  {
    "path": "packaging/nuget/package.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<!--\r\n#################################################################\r\n#   GENERATED SOURCE CODE, DO NOT EDIT EXCEPT EXPERIMENTALLY    #\r\n#################################################################\r\n-->\r\n<ProjectSchemaDefinitions xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\">\r\n  <Rule Name=\"Linkage-libzmq-uiextension\" PageTemplate=\"tool\" DisplayName=\"NuGet Dependencies\" SwitchPrefix=\"/\" Order=\"1\">\r\n    <Rule.Categories>\r\n      <Category Name=\"libzmq\" DisplayName=\"libzmq\" />\r\n    </Rule.Categories>\r\n    <Rule.DataSource>\r\n      <DataSource Persistence=\"ProjectFile\" ItemType=\"\" />\r\n    </Rule.DataSource>\r\n    <EnumProperty Name=\"Linkage-libzmq\" DisplayName=\"Linkage\" Description=\"How NuGet libzmq will be linked into the output of this project\" Category=\"libzmq\">\r\n      <EnumValue Name=\"\" DisplayName=\"Not linked\" />\r\n      <EnumValue Name=\"dynamic\" DisplayName=\"Dynamic (DLL)\" />\r\n      <EnumValue Name=\"static\" DisplayName=\"Static (LIB)\" />\r\n      <EnumValue Name=\"ltcg\" DisplayName=\"Static using link time compile generation (LTCG)\" />\r\n    </EnumProperty>\r\n  </Rule>\r\n</ProjectSchemaDefinitions>"
  },
  {
    "path": "packaging/obs/_service",
    "content": "<services>\n  <service name=\"tar_scm\">\n    <param name=\"url\">https://github.com/zeromq/libzmq</param>\n    <param name=\"scm\">git</param>\n    <param name=\"revision\">@PARENT_TAG@</param>\n    <param name=\"versionformat\">@PARENT_TAG@+git%cd</param>\n    <param name=\"versionrewrite-pattern\">v(.*)</param>\n    <param name=\"versionrewrite-replacement\">\\1</param>\n    <param name=\"exclude\">.git</param>\n    <param name=\"changesgenerate\">enable</param>\n    <param name=\"filename\">zeromq</param>\n  </service>\n\n  <!-- embed zmq.hpp like Debian and Ubuntu do -->\n  <service name=\"download_url\">\n    <param name=\"protocol\">https</param>\n    <param name=\"host\">github.com</param>\n    <param name=\"path\">zeromq/cppzmq/archive/master.zip</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*master.zip</param>\n    <param name=\"files\">*/zmq.hpp</param>\n    <param name=\"outfilename\">debian.zmq.hpp</param>\n  </service>\n\n  <!-- extract redhat packaging -->\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/redhat/zeromq.spec</param>\n    <param name=\"outfilename\">zeromq.spec</param>\n  </service>\n\n  <!-- extract debian packaging -->\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/zeromq.dsc.obs</param>\n    <param name=\"outfilename\">zeromq.dsc</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/changelog</param>\n    <param name=\"outfilename\">debian.changelog</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/compat</param>\n    <param name=\"outfilename\">debian.compat</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/control</param>\n    <param name=\"outfilename\">debian.control</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/copyright</param>\n    <param name=\"outfilename\">debian.copyright</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/source/format</param>\n    <param name=\"outfilename\">debian.format</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/rules</param>\n    <param name=\"outfilename\">debian.rules</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/libzmq3-dev.install</param>\n    <param name=\"outfilename\">debian.libzmq3-dev.install</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/libzmq3-dev.manpages</param>\n    <param name=\"outfilename\">debian.libzmq3-dev.manpages</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/libzmq5.docs</param>\n    <param name=\"outfilename\">debian.libzmq5.docs</param>\n  </service>\n  <service name=\"extract_file\">\n    <param name=\"archive\">*.tar</param>\n    <param name=\"files\">*/packaging/debian/libzmq5.install</param>\n    <param name=\"outfilename\">debian.libzmq5.install</param>\n  </service>\n\n  <service name=\"set_version\">\n    <param name=\"basename\">zeromq</param>\n  </service>\n\n  <service name=\"recompress\">\n    <param name=\"file\">*.tar</param>\n    <param name=\"compression\">gz</param>\n  </service>\n</services>\n\n"
  },
  {
    "path": "packaging/redhat/zeromq.spec",
    "content": "# To build with draft APIs, use \"--with drafts\" in rpmbuild for local builds or add\n#   Macros:\n#   %_with_drafts 1\n# at the BOTTOM of the OBS prjconf\n%bcond_with drafts\n%if %{with drafts}\n%define DRAFTS yes\n%else\n%define DRAFTS no\n%endif\n%define lib_name libzmq5\nName:          zeromq\nVersion:       4.3.6\nRelease:       1%{?dist}\nSummary:       The ZeroMQ messaging library\nGroup:         Development/Libraries/C and C++\nLicense:       MPL-2.0\nURL:           http://www.zeromq.org/\nSource:        http://download.zeromq.org/%{name}-%{version}.tar.gz\nPrefix:        %{_prefix}\nBuildroot:     %{_tmppath}/%{name}-%{version}-%{release}-root\nBuildRequires:  autoconf automake libtool glib2-devel libbsd-devel\n%if ! (0%{?fedora} > 12 || 0%{?rhel} > 5)\nBuildRequires:  e2fsprogs-devel\nBuildRoot:      %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)\n%endif\n%bcond_with pgm\n%if %{with pgm}\nBuildRequires:  openpgm-devel\n%define PGM yes\n%else\n%define PGM no\n%endif\n%bcond_with libgssapi_krb5\n%if %{with libgssapi_krb5}\nBuildRequires:  krb5-devel\n%define GSSAPI yes\n%else\n%define GSSAPI no\n%endif\n%bcond_with libsodium\n%if %{with libsodium}\nBuildRequires:  libsodium-devel\n%define SODIUM yes\n%else\n%define SODIUM no\n%endif\n%bcond_with nss\n%if %{with nss}\n%if 0%{?suse_version}\nBuildRequires:  mozilla-nss-devel\n%else\nBuildRequires:  nss-devel\n%endif\n%define NSS yes\n%else\n%define NSS no\n%endif\n%bcond_with tls\n%if %{with tls} && ! 0%{?centos_version} < 700\n%if 0%{?suse_version}\nBuildRequires:  libgnutls-devel\n%else\nBuildRequires:  gnutls-devel\n%endif\n%define TLS yes\n%else\n%define TLS no\n%endif\n%if 0%{?rhel_version}\n%if 0%{?rhel_version} >= 800\n# note1: on OBS the RHEL7 target for some reason is unable to find the asciidoctor package, so on RHEL7 docs are not built\n# note2: on RHEL8/Centos8 the asciidoctor package depends from the ruby module; this might require some extra config on the\n#        build farm where this .spec file is used\nBuildRequires:  asciidoctor\n%endif\n%else\n# on non-RHEL targets, listing asciidoctor in BuildRequires works just fine:\nBuildRequires:  rubygem(asciidoctor)\n%endif\nBuildRequires: gcc, make, gcc-c++, libstdc++-devel\nRequires:      libstdc++\n\n%ifarch pentium3 pentium4 athlon i386 i486 i586 i686 x86_64\n%{!?_with_pic: %{!?_without_pic: %define _with_pic --with-pic}}\n%{!?_with_gnu_ld: %{!?_without_gnu_ld: %define _with_gnu_ld --with-gnu_ld}}\n%endif\n\n# We do not want to ship libzmq.la\n%define _unpackaged_files_terminate_build 0\n\n%description\nThe 0MQ lightweight messaging kernel is a library which extends the\nstandard socket interfaces with features traditionally provided by\nspecialised messaging middleware products. 0MQ sockets provide an\nabstraction of asynchronous message queues, multiple messaging\npatterns, message filtering (subscriptions), seamless access to\nmultiple transport protocols and more.\n\n%package -n %{lib_name}\nSummary:   Shared Library for ZeroMQ\nGroup:     Productivity/Networking/Web/Servers\nConflicts: zeromq\n\n%description -n %{lib_name}\nThe 0MQ lightweight messaging kernel is a library which extends the\nstandard socket interfaces with features traditionally provided by\nspecialised messaging middleware products. 0MQ sockets provide an\nabstraction of asynchronous message queues, multiple messaging\npatterns, message filtering (subscriptions), seamless access to\nmultiple transport protocols and more.\n\nThis package contains the ZeroMQ shared library.\n\n%package devel\nSummary:  Development files and static library for the ZeroMQ library\nGroup:    Development/Libraries\nRequires: %{lib_name} = %{version}-%{release}, pkgconfig\n%bcond_with pgm\n%if %{with pgm}\nRequires:  openpgm-devel\n%endif\n%bcond_with libgssapi_krb5\n%if %{with libgssapi_krb5}\nRequires:  krb5-devel\n%endif\n%bcond_with libsodium\n%if %{with libsodium}\nRequires:  libsodium-devel\n%endif\n%bcond_with nss\n%if %{with nss}\n%if 0%{?suse_version}\nRequires:  mozilla-nss-devel\n%else\nRequires:  nss-devel\n%endif\n%endif\n%bcond_with tls\n%if %{with tls} && ! 0%{?centos_version} < 700\n%if 0%{?suse_version}\nRequires:  libgnutls-devel\n%else\nRequires:  gnutls-devel\n%endif\n%endif\n\n%description devel\nThe 0MQ lightweight messaging kernel is a library which extends the\nstandard socket interfaces with features traditionally provided by\nspecialised messaging middleware products. 0MQ sockets provide an\nabstraction of asynchronous message queues, multiple messaging\npatterns, message filtering (subscriptions), seamless access to\nmultiple transport protocols and more.\n\nThis package contains ZeroMQ related development libraries and header files.\n\n%package -n libzmq-tools\nSummary:   ZeroMQ tools\nGroup:     Productivity/Networking/Web/Servers\n\n%description -n libzmq-tools\nThe 0MQ lightweight messaging kernel is a library which extends the\nstandard socket interfaces with features traditionally provided by\nspecialised messaging middleware products. 0MQ sockets provide an\nabstraction of asynchronous message queues, multiple messaging\npatterns, message filtering (subscriptions), seamless access to\nmultiple transport protocols and more.\n\nThis package contains tools such as curve_keygen to use with libzmq.\n\n%prep\n%setup -q\n\n# Sed version number of openpgm into configure\n%global openpgm_pc $(basename %{_libdir}/pkgconfig/openpgm*.pc .pc)\nsed -i \"s/openpgm-[0-9].[0-9]/%{openpgm_pc}/g\" \\\n    configure*\n\n%build\n# Workaround for automake < 1.14 bug\nmkdir -p config\nautoreconf -fi\n%configure --enable-drafts=%{DRAFTS} \\\n    --with-pgm=%{PGM} \\\n    --with-libsodium=%{SODIUM} \\\n    --with-libgssapi_krb5=%{GSSAPI} \\\n    --with-nss=%{NSS} \\\n    --with-tls=%{TLS} \\\n    %{?_with_pic} \\\n    %{?_without_pic} \\\n    %{?_with_gnu_ld} \\\n    %{?_without_gnu_ld}\n\n%{__make} %{?_smp_mflags}\n\n%check\n%{__make} check VERBOSE=1\n\n%install\n[ \"%{buildroot}\" != \"/\" ] && %{__rm} -rf %{buildroot}\n# Install the package to build area\n%makeinstall\n\n%post\n/sbin/ldconfig\n\n%postun\n/sbin/ldconfig\n\n%clean\n[ \"%{buildroot}\" != \"/\" ] && %{__rm} -rf %{buildroot}\n\n%files -n %{lib_name}\n%defattr(-,root,root,-)\n\n# docs in the main package\n%doc AUTHORS LICENSE NEWS\n\n# libraries\n%{_libdir}/libzmq.so.*\n\n%{_mandir}/man7/zmq.7.gz\n\n%files devel\n%defattr(-,root,root,-)\n%{_includedir}/zmq.h\n%{_includedir}/zmq_utils.h\n\n%{_libdir}/libzmq.a\n%{_libdir}/pkgconfig/libzmq.pc\n%{_libdir}/libzmq.so\n\n%{_mandir}/man3/zmq*\n# skip man7/zmq.7.gz\n%{_mandir}/man7/zmq_*\n\n%files -n libzmq-tools\n%defattr(-,root,root,-)\n%if %{with libsodium}\n%{_bindir}/curve_keygen\n%endif\n\n%changelog\n* Fri Oct 4 2019 Luca Boccassi <luca.boccassi@gmail.com>\n- Add macro for optional TLS dependency\n\n* Wed Sep 11 2019 Luca Boccassi <luca.boccassi@gmail.com>\n- Add macro for optional NSS dependency\n\n* Sat Aug 19 2017 Luca Boccassi <luca.boccassi@gmail.com>\n- Fix parsing and usage of conditionals for sodium/pgm/krb5 so that they work\n  in OBS\n- Do not ship libzmq.la anymore, it's not needed and causes overlinking\n\n* Sun Nov 06 2016 Luca Boccassi <luca.boccassi@gmail.com>\n- Add libzmq-tool to package curve_keygen in /usr/bin\n\n* Sun Jul 31 2016 Luca Boccassi <luca.boccassi@gmail.com>\n- Follow RPM standards and rename zeromq to libzmq5\n\n* Sat Oct 25 2014 Phillip Mienk <mienkphi@gmail.com>\n- Add --with/--without libgssapi_krb5 support following J.T.Conklin's pattern\n\n* Sat Oct 18 2014 J.T. Conklin <jtc@acorntoolworks.com>\n- Add --with/--without pgm support\n- Add --with/--without libsodium support\n\n* Tue Jun 10 2014 Tristian Celestin <tristian.celestin@outlook.com> 4.0.4\n- Updated packaged files\n\n* Mon Nov 26 2012 Justin Cook <jhcook@gmail.com> 3.2.2\n- Update packaged files\n\n* Fri Apr 8 2011 Mikko Koppanen <mikko@kuut.io> 3.0.0-1\n- Update dependencies and packaged files\n\n* Sat Apr 10 2010 Mikko Koppanen <mkoppanen@php.net> 2.0.7-1\n- Initial packaging\n"
  },
  {
    "path": "perf/benchmark_radix_tree.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#if __cplusplus >= 201103L\n\n#include \"radix_tree.hpp\"\n#include \"trie.hpp\"\n\n#include <chrono>\n#include <cstddef>\n#include <cstdio>\n#include <random>\n#include <ratio>\n#include <vector>\n\nconst std::size_t nkeys = 10000;\nconst std::size_t nqueries = 1000000;\nconst std::size_t warmup_runs = 10;\nconst std::size_t samples = 10;\nconst std::size_t key_length = 20;\nconst char *chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\nconst int chars_len = 36;\n\ntemplate <class T>\nvoid benchmark_lookup (T &subscriptions_,\n                       std::vector<unsigned char *> &queries_)\n{\n    using namespace std::chrono;\n    std::vector<duration<long, std::nano> > samples_vec;\n    samples_vec.reserve (samples);\n\n    for (std::size_t run = 0; run < warmup_runs; ++run) {\n        for (auto &query : queries_)\n            subscriptions_.check (query, key_length);\n    }\n\n    for (std::size_t run = 0; run < samples; ++run) {\n        duration<long, std::nano> interval (0);\n        for (auto &query : queries_) {\n            auto start = steady_clock::now ();\n            subscriptions_.check (query, key_length);\n            auto end = steady_clock::now ();\n            interval += end - start;\n        }\n        samples_vec.push_back (interval / queries_.size ());\n    }\n\n    std::size_t sum = 0;\n    for (const auto &sample : samples_vec)\n        sum += sample.count ();\n    std::printf (\"Average lookup time = %.1lf ns\\n\",\n                 static_cast<double> (sum) / samples);\n}\n\nint main ()\n{\n    // Generate input set.\n    std::minstd_rand rng (123456789);\n    std::vector<unsigned char *> input_set;\n    std::vector<unsigned char *> queries;\n    input_set.reserve (nkeys);\n    queries.reserve (nqueries);\n\n    for (std::size_t i = 0; i < nkeys; ++i) {\n        unsigned char *key = new unsigned char[key_length];\n        for (std::size_t j = 0; j < key_length; j++)\n            key[j] = static_cast<unsigned char> (chars[rng () % chars_len]);\n        input_set.emplace_back (key);\n    }\n    for (std::size_t i = 0; i < nqueries; ++i)\n        queries.push_back (input_set[rng () % nkeys]);\n\n    // Initialize both data structures.\n    //\n    // Keeping initialization out of the benchmarking function helps\n    // heaptrack detect peak memory consumption of the radix tree.\n    zmq::trie_t trie;\n    zmq::radix_tree_t radix_tree;\n    for (auto &key : input_set) {\n        trie.add (key, key_length);\n        radix_tree.add (key, key_length);\n    }\n\n    // Create a benchmark.\n    std::printf (\"keys = %llu, queries = %llu, key size = %llu\\n\",\n                 static_cast<unsigned long long> (nkeys),\n                 static_cast<unsigned long long> (nqueries),\n                 static_cast<unsigned long long> (key_length));\n    std::puts (\"[trie]\");\n    benchmark_lookup (trie, queries);\n\n    std::puts (\"[radix_tree]\");\n    benchmark_lookup (radix_tree, queries);\n\n    for (auto &op : input_set)\n        delete[] op;\n}\n\n#else\n\nint main ()\n{\n}\n\n#endif\n"
  },
  {
    "path": "perf/generate_csv.sh",
    "content": "#!/bin/bash\n\n#\n# This script assumes that 2 machines are used to generate performance results.\n# First machine is assumed to be the one where this script runs.\n# Second machine is the \"REMOTE_IP_SSH\" machine; we assume to have passwordless SSH access.\n#\n# Usage example:\n#    export REMOTE_IP_SSH=10.0.0.1\n#    export LOCAL_TEST_ENDPOINT=\"tcp://192.168.1.1:1234\"\n#    export REMOTE_TEST_ENDPOINT=\"tcp://192.168.1.2:1234\"\n#    export REMOTE_LIBZMQ_PATH=\"/home/fmontorsi/libzmq/perf\"\n#    ./generate_csv.sh\n#\n\nset -u\n\n# configurable values (via environment variables):\nREMOTE_IP_SSH=${REMOTE_IP_SSH:-127.0.0.1}\nREMOTE_LIBZMQ_PATH=${REMOTE_LIBZMQ_PATH:-/root/libzmq/perf}\nLOCAL_TEST_ENDPOINT=${LOCAL_TEST_ENDPOINT:-tcp://192.168.1.1:1234}\nREMOTE_TEST_ENDPOINT=${REMOTE_TEST_ENDPOINT:-tcp://192.168.1.2:1234}\n\n# constant values:\nMESSAGE_SIZE_LIST=\"8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072\"\nOUTPUT_DIR=\"results\"\nOUTPUT_FILE_PREFIX=\"results.txt\"\nOUTPUT_FILE_CSV_PREFIX=\"results.csv\"\n\n\n# utility functions:\n\nfunction verify_ssh()\n{\n    ssh $REMOTE_IP_SSH \"ls /\" >/dev/null\n    if [ $? -ne 0 ]; then\n        echo \"Cannot connect via SSH passwordless to the REMOTE_IP_SSH $REMOTE_IP_SSH. Please fix the problem and retry.\"\n        exit 2\n    fi\n\n    ssh $REMOTE_IP_SSH \"ls $REMOTE_LIBZMQ_PATH\" >/dev/null\n    if [ $? -ne 0 ]; then\n        echo \"The folder $REMOTE_LIBZMQ_PATH is not valid. Please fix the problem and retry.\"\n        exit 2\n    fi\n\n    echo \"SSH connection to the remote $REMOTE_IP_SSH is working fine.\"\n}\n\nfunction run_remote_perf_util()\n{\n    local MESSAGE_SIZE_BYTES=\"$1\"\n    local REMOTE_PERF_UTIL=\"$2\"\n    local NUM_MESSAGES=\"$3\"\n\n    echo \"Launching on $REMOTE_IP_SSH the utility [$REMOTE_PERF_UTIL] for messages ${MESSAGE_SIZE_BYTES}B long\"\n    ssh $REMOTE_IP_SSH \"$REMOTE_LIBZMQ_PATH/$REMOTE_PERF_UTIL $TEST_ENDPOINT $MESSAGE_SIZE_BYTES $NUM_MESSAGES\" &\n    if [ $? -ne 0 ]; then\n        echo \"Failed to launch remote perf util.\"\n        exit 2\n    fi\n}\n\nfunction generate_output_file()\n{\n    local LOCAL_PERF_UTIL=\"$1\"     # must be the utility generating the TXT output\n    local REMOTE_PERF_UTIL=\"$2\"\n    local OUTPUT_FILE_PREFIX=\"$3\"\n    local NUM_MESSAGES=\"$4\"\n    local CSV_HEADER_LINE=\"$5\"\n\n    # derived values:\n    local OUTPUT_FILE_TXT=\"${OUTPUT_DIR}/${OUTPUT_FILE_PREFIX}.txt\"         # useful just for human-friendly debugging\n    local OUTPUT_FILE_CSV=\"${OUTPUT_DIR}/${OUTPUT_FILE_PREFIX}.csv\"     # actually used to later produce graphs\n    local MESSAGE_SIZE_ARRAY=($MESSAGE_SIZE_LIST)\n\n    echo \"Killing still-running ZMQ performance utils, if any\"\n    pkill $LOCAL_PERF_UTIL                       # in case it's running from a previous test\n    if [ ! -z \"$REMOTE_PERF_UTIL\" ]; then\n        ssh $REMOTE_IP_SSH \"pkill $REMOTE_PERF_UTIL\"     # in case it's running from a previous test\n    fi\n\n    echo \"Resetting output file $OUTPUT_FILE_TXT and $OUTPUT_FILE_CSV\"\n    mkdir -p ${OUTPUT_DIR}\n    > $OUTPUT_FILE_TXT\n    echo \"$CSV_HEADER_LINE\" > $OUTPUT_FILE_CSV\n\n    for MESSAGE_SIZE in ${MESSAGE_SIZE_ARRAY[@]}; do\n        echo \"Launching locally the utility [$LOCAL_PERF_UTIL] for messages ${MESSAGE_SIZE}B long\"\n        ./$LOCAL_PERF_UTIL $TEST_ENDPOINT $MESSAGE_SIZE $NUM_MESSAGES >${OUTPUT_FILE_TXT}-${MESSAGE_SIZE} &\n\n        if [ ! -z \"$REMOTE_PERF_UTIL\" ]; then\n            run_remote_perf_util $MESSAGE_SIZE $REMOTE_PERF_UTIL $NUM_MESSAGES\n        fi\n        wait\n\n        # produce the complete human-readable output file:\n        cat ${OUTPUT_FILE_TXT}-${MESSAGE_SIZE} >>${OUTPUT_FILE_TXT}\n\n        # produce a machine-friendly file for later plotting:\n        local DATALINE=\"$(cat ${OUTPUT_FILE_TXT}-${MESSAGE_SIZE} | grep -o '[0-9.]*' | tr '\\n' ',')\"\n        echo ${DATALINE::-1} >>$OUTPUT_FILE_CSV\n        rm -f ${OUTPUT_FILE_TXT}-${MESSAGE_SIZE}\n    done\n\n    echo \"All measurements completed and saved into $OUTPUT_FILE_TXT and $OUTPUT_FILE_CSV\"\n}\n\n\n\n# main:\n\nverify_ssh\n\nTHROUGHPUT_CSV_HEADER_LINE=\"# message_size,message_count,PPS[msg/s],throughput[Mb/s]\"\n\n# PUSH/PULL TCP throughput CSV file:\nTEST_ENDPOINT=\"$LOCAL_TEST_ENDPOINT\"\ngenerate_output_file \"local_thr\" \"remote_thr\" \\\n    \"pushpull_tcp_thr_results\" \\\n    \"1000000\" \\\n    \"$THROUGHPUT_CSV_HEADER_LINE\"\n\n# PUSH/PULL INPROC throughput CSV file:\n# NOTE: in this case there is no remote utility to run and no ENDPOINT to provide:\nTEST_ENDPOINT=\"\"  # inproc does not require any endpoint\ngenerate_output_file \"inproc_thr\" \"\" \\\n    \"pushpull_inproc_thr_results\" \\\n    \"10000000\" \\\n    \"$THROUGHPUT_CSV_HEADER_LINE\"\n\n# PUB/SUB proxy INPROC throughput CSV file:\n# NOTE: in this case there is no remote utility to run and no ENDPOINT to provide:\nTEST_ENDPOINT=\"\" # inproc does\tnot require any\tendpoint\ngenerate_output_file \"proxy_thr\" \"\" \\\n    \"pubsubproxy_inproc_thr_results\" \\\n    \"10000000\" \\\n    \"$THROUGHPUT_CSV_HEADER_LINE\"\n\n\n# REQ/REP TCP latency CSV file:\n# NOTE: in this case it's the remote_lat utility that prints out the data, so we swap the local/remote arguments to the bash func:\nTEST_ENDPOINT=\"$REMOTE_TEST_ENDPOINT\"\ngenerate_output_file \"remote_lat\" \"local_lat\" \\\n    \"reqrep_tcp_lat_results\" \\\n    \"10000\" \\\n    \"# message_size,message_count,latency[us]\"\n"
  },
  {
    "path": "perf/generate_graphs.py",
    "content": "#!/usr/bin/python3\n\n#\n# This script assumes that the set of CSV files produced by \"generate_csv.sh\" is provided as input\n# and that locally there is the \"results\" folder.\n#\n\n# results for TCP:\nINPUT_FILE_PUSHPULL_TCP_THROUGHPUT=\"results/pushpull_tcp_thr_results.csv\"\nINPUT_FILE_REQREP_TCP_LATENCY=\"results/reqrep_tcp_lat_results.csv\"\nTCP_LINK_GPBS=100\n\n# results for INPROC:\nINPUT_FILE_PUSHPULL_INPROC_THROUGHPUT=\"results/pushpull_inproc_thr_results.csv\"\nINPUT_FILE_PUBSUBPROXY_INPROC_THROUGHPUT=\"results/pubsubproxy_inproc_thr_results.csv\"\n\n\n# dependencies\n#\n# pip3 install matplotlib\n#\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\n# functions\n\ndef plot_throughput(csv_filename, title, is_tcp=False):\n    message_size_bytes, message_count, pps, mbps = np.loadtxt(csv_filename, delimiter=',', unpack=True)\n\n    fig, ax1 = plt.subplots()\n\n    # PPS axis\n    color = 'tab:red'\n    ax1.set_xlabel('Message size [B]')\n    ax1.set_ylabel('PPS [Mmsg/s]', color=color)\n    ax1.semilogx(message_size_bytes, pps / 1e6, label='PPS [Mmsg/s]', marker='x', color=color)\n    ax1.tick_params(axis='y', labelcolor=color)\n\n    # GBPS axis\n    color = 'tab:blue'\n    ax2 = ax1.twinx()  # instantiate a second axes that shares the same x-axis\n    ax2.set_ylabel('Throughput [Gb/s]', color=color)\n    ax2.semilogx(message_size_bytes, mbps / 1e3, label='Throughput [Gb/s]', marker='o')\n    if is_tcp:\n        ax2.set_yticks(np.arange(0, TCP_LINK_GPBS + 1, TCP_LINK_GPBS/10)) \n    ax2.tick_params(axis='y', labelcolor=color)\n    ax2.grid(True)\n    \n    plt.title(title)\n    fig.tight_layout()  # otherwise the right y-label is slightly clippe\n    plt.savefig(csv_filename.replace('.csv', '.png'))\n    plt.show()\n\ndef plot_latency(csv_filename, title):\n    message_size_bytes, message_count, lat = np.loadtxt(csv_filename, delimiter=',', unpack=True)\n    plt.semilogx(message_size_bytes, lat, label='Latency [us]', marker='o')\n    \n    plt.xlabel('Message size [B]')\n    plt.ylabel('Latency [us]')\n    plt.grid(True)\n    plt.title(title)\n    plt.savefig(csv_filename.replace('.csv', '.png'))\n    plt.show()\n\n\n# main\n\nplot_throughput(INPUT_FILE_PUSHPULL_TCP_THROUGHPUT, 'ZeroMQ PUSH/PULL socket throughput, TCP transport', is_tcp=True)\nplot_throughput(INPUT_FILE_PUSHPULL_INPROC_THROUGHPUT, 'ZeroMQ PUSH/PULL socket throughput, INPROC transport')\nplot_throughput(INPUT_FILE_PUBSUBPROXY_INPROC_THROUGHPUT, 'ZeroMQ PUB/SUB PROXY socket throughput, INPROC transport')\nplot_latency(INPUT_FILE_REQREP_TCP_LATENCY, 'ZeroMQ REQ/REP socket latency, TCP transport')\n"
  },
  {
    "path": "perf/inproc_lat.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../include/zmq.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"platform.hpp\"\n\n#if defined ZMQ_HAVE_WINDOWS\n#include <windows.h>\n#include <process.h>\n#else\n#include <pthread.h>\n#endif\n\nstatic size_t message_size;\nstatic int roundtrip_count;\n\n#if defined ZMQ_HAVE_WINDOWS\nstatic unsigned int __stdcall worker (void *ctx_)\n#else\nstatic void *worker (void *ctx_)\n#endif\n{\n    void *s;\n    int rc;\n    int i;\n    zmq_msg_t msg;\n\n    s = zmq_socket (ctx_, ZMQ_REP);\n    if (!s) {\n        printf (\"error in zmq_socket: %s\\n\", zmq_strerror (errno));\n        exit (1);\n    }\n\n    rc = zmq_connect (s, \"inproc://lat_test\");\n    if (rc != 0) {\n        printf (\"error in zmq_connect: %s\\n\", zmq_strerror (errno));\n        exit (1);\n    }\n\n    rc = zmq_msg_init (&msg);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_init: %s\\n\", zmq_strerror (errno));\n        exit (1);\n    }\n\n    for (i = 0; i != roundtrip_count; i++) {\n        rc = zmq_recvmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_recvmsg: %s\\n\", zmq_strerror (errno));\n            exit (1);\n        }\n        rc = zmq_sendmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_sendmsg: %s\\n\", zmq_strerror (errno));\n            exit (1);\n        }\n    }\n\n    rc = zmq_msg_close (&msg);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_close: %s\\n\", zmq_strerror (errno));\n        exit (1);\n    }\n\n    rc = zmq_close (s);\n    if (rc != 0) {\n        printf (\"error in zmq_close: %s\\n\", zmq_strerror (errno));\n        exit (1);\n    }\n\n#if defined ZMQ_HAVE_WINDOWS\n    return 0;\n#else\n    return NULL;\n#endif\n}\n\nint main (int argc, char *argv[])\n{\n#if defined ZMQ_HAVE_WINDOWS\n    HANDLE local_thread;\n#else\n    pthread_t local_thread;\n#endif\n    void *ctx;\n    void *s;\n    int rc;\n    int i;\n    zmq_msg_t msg;\n    void *watch;\n    unsigned long elapsed;\n    double latency;\n\n    if (argc != 3) {\n        printf (\"usage: inproc_lat <message-size> <roundtrip-count>\\n\");\n        return 1;\n    }\n\n    message_size = atoi (argv[1]);\n    roundtrip_count = atoi (argv[2]);\n\n    ctx = zmq_init (1);\n    if (!ctx) {\n        printf (\"error in zmq_init: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    s = zmq_socket (ctx, ZMQ_REQ);\n    if (!s) {\n        printf (\"error in zmq_socket: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_bind (s, \"inproc://lat_test\");\n    if (rc != 0) {\n        printf (\"error in zmq_bind: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n#if defined ZMQ_HAVE_WINDOWS\n    local_thread = (HANDLE) _beginthreadex (NULL, 0, worker, ctx, 0, NULL);\n    if (local_thread == 0) {\n        printf (\"error in _beginthreadex\\n\");\n        return -1;\n    }\n#else\n    rc = pthread_create (&local_thread, NULL, worker, ctx);\n    if (rc != 0) {\n        printf (\"error in pthread_create: %s\\n\", zmq_strerror (rc));\n        return -1;\n    }\n#endif\n\n    rc = zmq_msg_init_size (&msg, message_size);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_init_size: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n    memset (zmq_msg_data (&msg), 0, message_size);\n\n    printf (\"message size: %d [B]\\n\", (int) message_size);\n    printf (\"roundtrip count: %d\\n\", (int) roundtrip_count);\n\n    watch = zmq_stopwatch_start ();\n\n    for (i = 0; i != roundtrip_count; i++) {\n        rc = zmq_sendmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_sendmsg: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n        rc = zmq_recvmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_recvmsg: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n        if (zmq_msg_size (&msg) != message_size) {\n            printf (\"message of incorrect size received\\n\");\n            return -1;\n        }\n    }\n\n    elapsed = zmq_stopwatch_stop (watch);\n\n    rc = zmq_msg_close (&msg);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    latency = (double) elapsed / (roundtrip_count * 2);\n\n#if defined ZMQ_HAVE_WINDOWS\n    DWORD rc2 = WaitForSingleObject (local_thread, INFINITE);\n    if (rc2 == WAIT_FAILED) {\n        printf (\"error in WaitForSingleObject\\n\");\n        return -1;\n    }\n    BOOL rc3 = CloseHandle (local_thread);\n    if (rc3 == 0) {\n        printf (\"error in CloseHandle\\n\");\n        return -1;\n    }\n#else\n    rc = pthread_join (local_thread, NULL);\n    if (rc != 0) {\n        printf (\"error in pthread_join: %s\\n\", zmq_strerror (rc));\n        return -1;\n    }\n#endif\n\n    printf (\"average latency: %.3f [us]\\n\", (double) latency);\n\n    rc = zmq_close (s);\n    if (rc != 0) {\n        printf (\"error in zmq_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_ctx_term (ctx);\n    if (rc != 0) {\n        printf (\"error in zmq_ctx_term: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "perf/inproc_thr.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../include/zmq.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"platform.hpp\"\n\n#if defined ZMQ_HAVE_WINDOWS\n#include <windows.h>\n#include <process.h>\n#else\n#include <pthread.h>\n#endif\n\nstatic int message_count;\nstatic size_t message_size;\n\n#if defined ZMQ_HAVE_WINDOWS\nstatic unsigned int __stdcall worker (void *ctx_)\n#else\nstatic void *worker (void *ctx_)\n#endif\n{\n    void *s;\n    int rc;\n    int i;\n    zmq_msg_t msg;\n\n    s = zmq_socket (ctx_, ZMQ_PUSH);\n    if (!s) {\n        printf (\"error in zmq_socket: %s\\n\", zmq_strerror (errno));\n        exit (1);\n    }\n\n    rc = zmq_connect (s, \"inproc://thr_test\");\n    if (rc != 0) {\n        printf (\"error in zmq_connect: %s\\n\", zmq_strerror (errno));\n        exit (1);\n    }\n\n    for (i = 0; i != message_count; i++) {\n        rc = zmq_msg_init_size (&msg, message_size);\n        if (rc != 0) {\n            printf (\"error in zmq_msg_init_size: %s\\n\", zmq_strerror (errno));\n            exit (1);\n        }\n#if defined ZMQ_MAKE_VALGRIND_HAPPY\n        memset (zmq_msg_data (&msg), 0, message_size);\n#endif\n\n        rc = zmq_sendmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_sendmsg: %s\\n\", zmq_strerror (errno));\n            exit (1);\n        }\n        rc = zmq_msg_close (&msg);\n        if (rc != 0) {\n            printf (\"error in zmq_msg_close: %s\\n\", zmq_strerror (errno));\n            exit (1);\n        }\n    }\n\n    rc = zmq_close (s);\n    if (rc != 0) {\n        printf (\"error in zmq_close: %s\\n\", zmq_strerror (errno));\n        exit (1);\n    }\n\n#if defined ZMQ_HAVE_WINDOWS\n    return 0;\n#else\n    return NULL;\n#endif\n}\n\nint main (int argc, char *argv[])\n{\n#if defined ZMQ_HAVE_WINDOWS\n    HANDLE local_thread;\n#else\n    pthread_t local_thread;\n#endif\n    void *ctx;\n    void *s;\n    int rc;\n    int i;\n    zmq_msg_t msg;\n    void *watch;\n    unsigned long elapsed;\n    unsigned long throughput;\n    double megabits;\n\n    if (argc != 3) {\n        printf (\"usage: inproc_thr <message-size> <message-count>\\n\");\n        return 1;\n    }\n\n    message_size = atoi (argv[1]);\n    message_count = atoi (argv[2]);\n\n    ctx = zmq_init (1);\n    if (!ctx) {\n        printf (\"error in zmq_init: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    s = zmq_socket (ctx, ZMQ_PULL);\n    if (!s) {\n        printf (\"error in zmq_socket: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_bind (s, \"inproc://thr_test\");\n    if (rc != 0) {\n        printf (\"error in zmq_bind: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n#if defined ZMQ_HAVE_WINDOWS\n    local_thread = (HANDLE) _beginthreadex (NULL, 0, worker, ctx, 0, NULL);\n    if (local_thread == 0) {\n        printf (\"error in _beginthreadex\\n\");\n        return -1;\n    }\n#else\n    rc = pthread_create (&local_thread, NULL, worker, ctx);\n    if (rc != 0) {\n        printf (\"error in pthread_create: %s\\n\", zmq_strerror (rc));\n        return -1;\n    }\n#endif\n\n    rc = zmq_msg_init (&msg);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_init: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    printf (\"message size: %d [B]\\n\", (int) message_size);\n    printf (\"message count: %d\\n\", (int) message_count);\n\n    rc = zmq_recvmsg (s, &msg, 0);\n    if (rc < 0) {\n        printf (\"error in zmq_recvmsg: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n    if (zmq_msg_size (&msg) != message_size) {\n        printf (\"message of incorrect size received\\n\");\n        return -1;\n    }\n\n    watch = zmq_stopwatch_start ();\n\n    for (i = 0; i != message_count - 1; i++) {\n        rc = zmq_recvmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_recvmsg: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n        if (zmq_msg_size (&msg) != message_size) {\n            printf (\"message of incorrect size received\\n\");\n            return -1;\n        }\n    }\n\n    elapsed = zmq_stopwatch_stop (watch);\n    if (elapsed == 0)\n        elapsed = 1;\n\n    rc = zmq_msg_close (&msg);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n#if defined ZMQ_HAVE_WINDOWS\n    DWORD rc2 = WaitForSingleObject (local_thread, INFINITE);\n    if (rc2 == WAIT_FAILED) {\n        printf (\"error in WaitForSingleObject\\n\");\n        return -1;\n    }\n    BOOL rc3 = CloseHandle (local_thread);\n    if (rc3 == 0) {\n        printf (\"error in CloseHandle\\n\");\n        return -1;\n    }\n#else\n    rc = pthread_join (local_thread, NULL);\n    if (rc != 0) {\n        printf (\"error in pthread_join: %s\\n\", zmq_strerror (rc));\n        return -1;\n    }\n#endif\n\n    rc = zmq_close (s);\n    if (rc != 0) {\n        printf (\"error in zmq_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_ctx_term (ctx);\n    if (rc != 0) {\n        printf (\"error in zmq_ctx_term: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    throughput =\n      (unsigned long) ((double) message_count / (double) elapsed * 1000000);\n    megabits = (double) (throughput * message_size * 8) / 1000000;\n\n    printf (\"mean throughput: %d [msg/s]\\n\", (int) throughput);\n    printf (\"mean throughput: %.3f [Mb/s]\\n\", (double) megabits);\n\n    return 0;\n}\n"
  },
  {
    "path": "perf/local_lat.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../include/zmq.h\"\n#include <stdio.h>\n#include <stdlib.h>\n\nint main (int argc, char *argv[])\n{\n    const char *bind_to;\n    int roundtrip_count;\n    size_t message_size;\n    void *ctx;\n    void *s;\n    int rc;\n    int i;\n    zmq_msg_t msg;\n\n    if (argc != 4) {\n        printf (\"usage: local_lat <bind-to> <message-size> \"\n                \"<roundtrip-count>\\n\");\n        return 1;\n    }\n    bind_to = argv[1];\n    message_size = atoi (argv[2]);\n    roundtrip_count = atoi (argv[3]);\n\n    ctx = zmq_init (1);\n    if (!ctx) {\n        printf (\"error in zmq_init: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    s = zmq_socket (ctx, ZMQ_REP);\n    if (!s) {\n        printf (\"error in zmq_socket: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_bind (s, bind_to);\n    if (rc != 0) {\n        printf (\"error in zmq_bind: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_msg_init (&msg);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_init: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    for (i = 0; i != roundtrip_count; i++) {\n        rc = zmq_recvmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_recvmsg: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n        if (zmq_msg_size (&msg) != message_size) {\n            printf (\"message of incorrect size received\\n\");\n            return -1;\n        }\n        rc = zmq_sendmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_sendmsg: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n    }\n\n    rc = zmq_msg_close (&msg);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    zmq_sleep (1);\n\n    rc = zmq_close (s);\n    if (rc != 0) {\n        printf (\"error in zmq_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_ctx_term (ctx);\n    if (rc != 0) {\n        printf (\"error in zmq_ctx_term: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "perf/local_thr.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../include/zmq.h\"\n#include <stdio.h>\n#include <stdlib.h>\n\n// keys are arbitrary but must match remote_lat.cpp\nconst char server_prvkey[] = \"{X}#>t#jRGaQ}gMhv=30r(Mw+87YGs+5%kh=i@f8\";\n\nint main (int argc, char *argv[])\n{\n    const char *bind_to;\n    int message_count;\n    size_t message_size;\n    void *ctx;\n    void *s;\n    int rc;\n    int i;\n    zmq_msg_t msg;\n    void *watch;\n    unsigned long elapsed;\n    double throughput;\n    double megabits;\n    int curve = 0;\n\n    if (argc != 4 && argc != 5) {\n        printf (\"usage: local_thr <bind-to> <message-size> <message-count> \"\n                \"[<enable_curve>]\\n\");\n        return 1;\n    }\n    bind_to = argv[1];\n    message_size = atoi (argv[2]);\n    message_count = atoi (argv[3]);\n    if (argc >= 5 && atoi (argv[4])) {\n        curve = 1;\n    }\n\n    ctx = zmq_init (1);\n    if (!ctx) {\n        printf (\"error in zmq_init: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    s = zmq_socket (ctx, ZMQ_PULL);\n    if (!s) {\n        printf (\"error in zmq_socket: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    //  Add your socket options here.\n    //  For example ZMQ_RATE, ZMQ_RECOVERY_IVL and ZMQ_MCAST_LOOP for PGM.\n    if (curve) {\n        rc = zmq_setsockopt (s, ZMQ_CURVE_SECRETKEY, server_prvkey,\n                             sizeof (server_prvkey));\n        if (rc != 0) {\n            printf (\"error in zmq_setsockoopt: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n        int server = 1;\n        rc = zmq_setsockopt (s, ZMQ_CURVE_SERVER, &server, sizeof (int));\n        if (rc != 0) {\n            printf (\"error in zmq_setsockoopt: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n    }\n\n    rc = zmq_bind (s, bind_to);\n    if (rc != 0) {\n        printf (\"error in zmq_bind: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_msg_init (&msg);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_init: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_recvmsg (s, &msg, 0);\n    if (rc < 0) {\n        printf (\"error in zmq_recvmsg: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n    if (zmq_msg_size (&msg) != message_size) {\n        printf (\"message of incorrect size received\\n\");\n        return -1;\n    }\n\n    watch = zmq_stopwatch_start ();\n\n    for (i = 0; i != message_count - 1; i++) {\n        rc = zmq_recvmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_recvmsg: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n        if (zmq_msg_size (&msg) != message_size) {\n            printf (\"message of incorrect size received\\n\");\n            return -1;\n        }\n    }\n\n    elapsed = zmq_stopwatch_stop (watch);\n    if (elapsed == 0)\n        elapsed = 1;\n\n    rc = zmq_msg_close (&msg);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    throughput = ((double) message_count / (double) elapsed * 1000000);\n    megabits = ((double) throughput * message_size * 8) / 1000000;\n\n    printf (\"message size: %d [B]\\n\", (int) message_size);\n    printf (\"message count: %d\\n\", (int) message_count);\n    printf (\"mean throughput: %d [msg/s]\\n\", (int) throughput);\n    printf (\"mean throughput: %.3f [Mb/s]\\n\", (double) megabits);\n\n    rc = zmq_close (s);\n    if (rc != 0) {\n        printf (\"error in zmq_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_ctx_term (ctx);\n    if (rc != 0) {\n        printf (\"error in zmq_ctx_term: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "perf/proxy_thr.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n#include \"../include/zmq.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <time.h>\n#include <stdarg.h>\n#include <string.h>\n#include <string>\n\n#include \"platform.hpp\"\n\n#if defined ZMQ_HAVE_WINDOWS\n#include <windows.h>\n#include <process.h>\n#else\n#include <pthread.h>\n#include <unistd.h>\n#endif\n\n\n/*\n   Asynchronous proxy benchmark using ZMQ_XPUB_NODROP.\n\n   Topology:\n\n     XPUB                      SUB\n      |                         |\n      +-----> XSUB -> XPUB -----/\n      |       ^^^^^^^^^^^^\n     XPUB      ZMQ proxy\n\n   All connections use \"inproc\" transport. The two XPUB sockets start\n   flooding the proxy. The throughput is computed using the bytes received\n   in the SUB socket.\n*/\n\n\n#define HWM 10000\n\n#ifndef ARRAY_SIZE\n#define ARRAY_SIZE(x) (sizeof (x) / sizeof (*x))\n#endif\n\n#define TEST_ASSERT_SUCCESS_ERRNO(expr)                                        \\\n    test_assert_success_message_errno_helper (expr, NULL, #expr)\n\n// This macro is used to avoid-variable warning. If used with an expression,\n// the sizeof is not evaluated to avoid polluting the assembly code.\n#ifdef NDEBUG\n#define ASSERT_EXPR_SAFE(x)                                                    \\\n    do {                                                                       \\\n        (void) sizeof (x);                                                     \\\n    } while (0)\n#else\n#define ASSERT_EXPR_SAFE(x) assert (x)\n#endif\n\n\nstatic uint64_t message_count = 0;\nstatic size_t message_size = 0;\n\n\ntypedef struct\n{\n    void *context;\n    int thread_idx;\n    const char *frontend_endpoint[4];\n    const char *backend_endpoint[4];\n    const char *control_endpoint;\n} proxy_hwm_cfg_t;\n\n\nint test_assert_success_message_errno_helper (int rc_,\n                                              const char *msg_,\n                                              const char *expr_)\n{\n    if (rc_ == -1) {\n        char buffer[512];\n        buffer[sizeof (buffer) - 1] =\n          0; //  to ensure defined behavior with VC++ <= 2013\n        printf (\"%s failed%s%s%s, errno = %i (%s)\", expr_,\n                msg_ ? \" (additional info: \" : \"\", msg_ ? msg_ : \"\",\n                msg_ ? \")\" : \"\", zmq_errno (), zmq_strerror (zmq_errno ()));\n        exit (1);\n    }\n    return rc_;\n}\n\nstatic void set_hwm (void *skt)\n{\n    int hwm = HWM;\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (skt, ZMQ_SNDHWM, &hwm, sizeof (hwm)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (skt, ZMQ_RCVHWM, &hwm, sizeof (hwm)));\n}\n\nstatic void publisher_thread_main (void *pvoid)\n{\n    const proxy_hwm_cfg_t *cfg = (proxy_hwm_cfg_t *) pvoid;\n    const int idx = cfg->thread_idx;\n    int optval;\n    int rc;\n\n    void *pubsocket = zmq_socket (cfg->context, ZMQ_XPUB);\n    assert (pubsocket);\n\n    set_hwm (pubsocket);\n\n    optval = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pubsocket, ZMQ_XPUB_NODROP, &optval, sizeof (optval)));\n\n    optval = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pubsocket, ZMQ_SNDTIMEO, &optval, sizeof (optval)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (pubsocket, cfg->frontend_endpoint[idx]));\n\n    //  Wait before starting TX operations till 1 subscriber has subscribed\n    //  (in this test there's 1 subscriber only)\n    char buffer[32] = {};\n    rc = TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_recv (pubsocket, buffer, sizeof (buffer), 0));\n    if (rc != 1) {\n        printf (\"invalid response length: expected 1, received %d\", rc);\n        exit (1);\n    }\n    if (buffer[0] != 1) {\n        printf (\"invalid response value: expected 1, received %d\",\n                (int) buffer[0]);\n        exit (1);\n    }\n\n    zmq_msg_t msg_orig;\n    rc = zmq_msg_init_size (&msg_orig, message_size);\n    assert (rc == 0);\n    memset (zmq_msg_data (&msg_orig), 'A', zmq_msg_size (&msg_orig));\n\n    uint64_t send_count = 0;\n    while (send_count < message_count) {\n        zmq_msg_t msg;\n        zmq_msg_init (&msg);\n        rc = zmq_msg_copy (&msg, &msg_orig);\n        assert (rc == 0);\n\n        //  Send the message to the socket\n        rc = zmq_msg_send (&msg, pubsocket, 0);\n        if (rc != -1) {\n            send_count++;\n        } else {\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n        }\n    }\n\n    zmq_close (pubsocket);\n    //printf (\"publisher thread ended\\n\");\n}\n\nstatic void subscriber_thread_main (void *pvoid)\n{\n    const proxy_hwm_cfg_t *cfg = (proxy_hwm_cfg_t *) pvoid;\n    const int idx = cfg->thread_idx;\n\n    void *subsocket = zmq_socket (cfg->context, ZMQ_SUB);\n    assert (subsocket);\n\n    set_hwm (subsocket);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (subsocket, ZMQ_SUBSCRIBE, 0, 0));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (subsocket, cfg->backend_endpoint[idx]));\n\n    //  Receive message_count messages\n    uint64_t rxsuccess = 0;\n    bool success = true;\n    while (success) {\n        zmq_msg_t msg;\n        int rc = zmq_msg_init (&msg);\n        assert (rc == 0);\n\n        rc = zmq_msg_recv (&msg, subsocket, 0);\n        if (rc != -1) {\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n            rxsuccess++;\n        }\n\n        if (rxsuccess == message_count)\n            break;\n    }\n\n    //  Cleanup\n\n    zmq_close (subsocket);\n    //printf (\"subscriber thread ended\\n\");\n}\n\nstatic void proxy_thread_main (void *pvoid)\n{\n    const proxy_hwm_cfg_t *cfg = (proxy_hwm_cfg_t *) pvoid;\n    int rc;\n\n    //  FRONTEND SUB\n\n    void *frontend_xsub = zmq_socket (\n      cfg->context,\n      ZMQ_XSUB); // the frontend is the one exposed to internal threads (INPROC)\n    assert (frontend_xsub);\n\n    set_hwm (frontend_xsub);\n\n    //  Bind FRONTEND\n    for (unsigned int i = 0; i < ARRAY_SIZE (cfg->frontend_endpoint); i++) {\n        const char *ep = cfg->frontend_endpoint[i];\n        if (ep != NULL) {\n            assert (strlen (ep) > 5);\n            rc = zmq_bind (frontend_xsub, ep);\n            ASSERT_EXPR_SAFE (rc == 0);\n        }\n    }\n\n    //  BACKEND PUB\n\n    void *backend_xpub = zmq_socket (\n      cfg->context,\n      ZMQ_XPUB); //  the backend is the one exposed to the external world (TCP)\n    assert (backend_xpub);\n\n    int optval = 1;\n    rc =\n      zmq_setsockopt (backend_xpub, ZMQ_XPUB_NODROP, &optval, sizeof (optval));\n    ASSERT_EXPR_SAFE (rc == 0);\n\n    set_hwm (backend_xpub);\n\n    //  Bind BACKEND\n    for (unsigned int i = 0; i < ARRAY_SIZE (cfg->backend_endpoint); i++) {\n        const char *ep = cfg->backend_endpoint[i];\n        if (ep != NULL) {\n            assert (strlen (ep) > 5);\n            rc = zmq_bind (backend_xpub, ep);\n            ASSERT_EXPR_SAFE (rc == 0);\n        }\n    }\n\n    //  CONTROL REP\n\n    void *control_rep = zmq_socket (\n      cfg->context,\n      ZMQ_REP); //  This one is used by the proxy to receive&reply to commands\n    assert (control_rep);\n\n    //  Bind CONTROL\n    rc = zmq_bind (control_rep, cfg->control_endpoint);\n    ASSERT_EXPR_SAFE (rc == 0);\n\n    //  Start proxying!\n\n    zmq_proxy_steerable (frontend_xsub, backend_xpub, NULL, control_rep);\n\n    zmq_close (frontend_xsub);\n    zmq_close (backend_xpub);\n    zmq_close (control_rep);\n    //printf (\"proxy thread ended\\n\");\n}\n\nvoid terminate_proxy (const proxy_hwm_cfg_t *cfg)\n{\n    //  CONTROL REQ\n\n    void *control_req = zmq_socket (\n      cfg->context,\n      ZMQ_REQ); //  This one can be used to send command to the proxy\n    assert (control_req);\n\n    //  Connect CONTROL-REQ: a socket to which send commands\n    int rc = zmq_connect (control_req, cfg->control_endpoint);\n    ASSERT_EXPR_SAFE (rc == 0);\n\n    //  Ask the proxy to exit: the subscriber has received all messages\n\n    rc = zmq_send (control_req, \"TERMINATE\", 9, 0);\n    ASSERT_EXPR_SAFE (rc == 9);\n\n    zmq_close (control_req);\n}\n\n//  The main thread simply starts some publishers, a proxy,\n//  and a subscriber. Finish when all packets are received.\n\nint main (int argc, char *argv[])\n{\n    if (argc != 3) {\n        printf (\"usage: proxy_thr <message-size> <message-count>\\n\");\n        return 1;\n    }\n\n    message_size = atoi (argv[1]);\n    message_count = atoi (argv[2]);\n    printf (\"message size: %d [B]\\n\", (int) message_size);\n    printf (\"message count: %d\\n\", (int) message_count);\n\n    void *context = zmq_ctx_new ();\n    assert (context);\n\n    int rv = zmq_ctx_set (context, ZMQ_IO_THREADS, 4);\n    ASSERT_EXPR_SAFE (rv == 0);\n\n    //  START ALL SECONDARY THREADS\n\n    const char *pub1 = \"inproc://perf_pub1\";\n    const char *pub2 = \"inproc://perf_pub2\";\n    const char *sub1 = \"inproc://perf_backend\";\n\n    proxy_hwm_cfg_t cfg_global = {};\n    cfg_global.context = context;\n    cfg_global.frontend_endpoint[0] = pub1;\n    cfg_global.frontend_endpoint[1] = pub2;\n    cfg_global.backend_endpoint[0] = sub1;\n    cfg_global.control_endpoint = \"inproc://ctrl\";\n\n    //  Proxy\n    proxy_hwm_cfg_t cfg_proxy = cfg_global;\n    void *proxy = zmq_threadstart (&proxy_thread_main, (void *) &cfg_proxy);\n    assert (proxy != 0);\n\n    //  Subscriber 1\n    proxy_hwm_cfg_t cfg_sub1 = cfg_global;\n    cfg_sub1.thread_idx = 0;\n    void *subscriber =\n      zmq_threadstart (&subscriber_thread_main, (void *) &cfg_sub1);\n    assert (subscriber != 0);\n\n    //  Start measuring\n    void *watch = zmq_stopwatch_start ();\n\n    //  Publisher 1\n    proxy_hwm_cfg_t cfg_pub1 = cfg_global;\n    cfg_pub1.thread_idx = 0;\n    void *publisher1 =\n      zmq_threadstart (&publisher_thread_main, (void *) &cfg_pub1);\n    assert (publisher1 != 0);\n\n    //  Publisher 2\n    proxy_hwm_cfg_t cfg_pub2 = cfg_global;\n    cfg_pub2.thread_idx = 1;\n    void *publisher2 =\n      zmq_threadstart (&publisher_thread_main, (void *) &cfg_pub2);\n    assert (publisher2 != 0);\n\n    //  Wait for all packets to be received\n    zmq_threadclose (subscriber);\n\n    //  Stop measuring\n    unsigned long elapsed = zmq_stopwatch_stop (watch);\n    if (elapsed == 0)\n        elapsed = 1;\n\n    unsigned long throughput =\n      (unsigned long) ((double) message_count / (double) elapsed * 1000000);\n    double megabits = (double) (throughput * message_size * 8) / 1000000;\n\n    printf (\"mean throughput: %d [msg/s]\\n\", (int) throughput);\n    printf (\"mean throughput: %.3f [Mb/s]\\n\", (double) megabits);\n\n    //  Wait for the end of publishers...\n    zmq_threadclose (publisher1);\n    zmq_threadclose (publisher2);\n\n    //  ... then close the proxy\n    terminate_proxy (&cfg_proxy);\n    zmq_threadclose (proxy);\n\n    int rc = zmq_ctx_term (context);\n    ASSERT_EXPR_SAFE (rc == 0);\n\n    return 0;\n}\n"
  },
  {
    "path": "perf/remote_lat.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../include/zmq.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nint main (int argc, char *argv[])\n{\n    const char *connect_to;\n    int roundtrip_count;\n    size_t message_size;\n    void *ctx;\n    void *s;\n    int rc;\n    int i;\n    zmq_msg_t msg;\n    void *watch;\n    unsigned long elapsed;\n    double latency;\n\n    if (argc != 4) {\n        printf (\"usage: remote_lat <connect-to> <message-size> \"\n                \"<roundtrip-count>\\n\");\n        return 1;\n    }\n    connect_to = argv[1];\n    message_size = atoi (argv[2]);\n    roundtrip_count = atoi (argv[3]);\n\n    ctx = zmq_init (1);\n    if (!ctx) {\n        printf (\"error in zmq_init: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    s = zmq_socket (ctx, ZMQ_REQ);\n    if (!s) {\n        printf (\"error in zmq_socket: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_connect (s, connect_to);\n    if (rc != 0) {\n        printf (\"error in zmq_connect: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_msg_init_size (&msg, message_size);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_init_size: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n    memset (zmq_msg_data (&msg), 0, message_size);\n\n    watch = zmq_stopwatch_start ();\n\n    for (i = 0; i != roundtrip_count; i++) {\n        rc = zmq_sendmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_sendmsg: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n        rc = zmq_recvmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_recvmsg: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n        if (zmq_msg_size (&msg) != message_size) {\n            printf (\"message of incorrect size received\\n\");\n            return -1;\n        }\n    }\n\n    elapsed = zmq_stopwatch_stop (watch);\n\n    rc = zmq_msg_close (&msg);\n    if (rc != 0) {\n        printf (\"error in zmq_msg_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    latency = (double) elapsed / (roundtrip_count * 2);\n\n    printf (\"message size: %d [B]\\n\", (int) message_size);\n    printf (\"roundtrip count: %d\\n\", (int) roundtrip_count);\n    printf (\"average latency: %.3f [us]\\n\", (double) latency);\n\n    rc = zmq_close (s);\n    if (rc != 0) {\n        printf (\"error in zmq_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_ctx_term (ctx);\n    if (rc != 0) {\n        printf (\"error in zmq_ctx_term: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "perf/remote_thr.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../include/zmq.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n// keys are arbitrary but must match local_lat.cpp\nconst char server_pubkey[] = \"DX4nh=yUn{-9ugra0X3Src4SU-4xTgqxcYY.+<SH\";\nconst char client_pubkey[] = \"<n^oA}I:66W+*ds3tAmi1+KJzv-}k&fC2aA5Bj0K\";\nconst char client_prvkey[] = \"9R9bV}[6z6DC-%$!jTVTKvWc=LEL{4i4gzUe$@Zx\";\n\nint main (int argc, char *argv[])\n{\n    const char *connect_to;\n    int message_count;\n    int message_size;\n    void *ctx;\n    void *s;\n    int rc;\n    int i;\n    zmq_msg_t msg;\n    int curve = 0;\n\n    if (argc != 4 && argc != 5) {\n        printf (\"usage: remote_thr <connect-to> <message-size> \"\n                \"<message-count> [<enable_curve>]\\n\");\n        return 1;\n    }\n    connect_to = argv[1];\n    message_size = atoi (argv[2]);\n    message_count = atoi (argv[3]);\n    if (argc >= 5 && atoi (argv[4])) {\n        curve = 1;\n    }\n\n    ctx = zmq_init (1);\n    if (!ctx) {\n        printf (\"error in zmq_init: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    s = zmq_socket (ctx, ZMQ_PUSH);\n    if (!s) {\n        printf (\"error in zmq_socket: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    //  Add your socket options here.\n    //  For example ZMQ_RATE, ZMQ_RECOVERY_IVL and ZMQ_MCAST_LOOP for PGM.\n    if (curve) {\n        rc = zmq_setsockopt (s, ZMQ_CURVE_SECRETKEY, client_prvkey,\n                             sizeof (client_prvkey));\n        if (rc != 0) {\n            printf (\"error in zmq_setsockoopt: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n\n        rc = zmq_setsockopt (s, ZMQ_CURVE_PUBLICKEY, client_pubkey,\n                             sizeof (client_pubkey));\n        if (rc != 0) {\n            printf (\"error in zmq_setsockoopt: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n\n        rc = zmq_setsockopt (s, ZMQ_CURVE_SERVERKEY, server_pubkey,\n                             sizeof (server_pubkey));\n        if (rc != 0) {\n            printf (\"error in zmq_setsockoopt: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n    }\n\n    rc = zmq_connect (s, connect_to);\n    if (rc != 0) {\n        printf (\"error in zmq_connect: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    for (i = 0; i != message_count; i++) {\n        rc = zmq_msg_init_size (&msg, message_size);\n        if (rc != 0) {\n            printf (\"error in zmq_msg_init_size: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n        rc = zmq_sendmsg (s, &msg, 0);\n        if (rc < 0) {\n            printf (\"error in zmq_sendmsg: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n        rc = zmq_msg_close (&msg);\n        if (rc != 0) {\n            printf (\"error in zmq_msg_close: %s\\n\", zmq_strerror (errno));\n            return -1;\n        }\n    }\n\n    rc = zmq_close (s);\n    if (rc != 0) {\n        printf (\"error in zmq_close: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    rc = zmq_ctx_term (ctx);\n    if (rc != 0) {\n        printf (\"error in zmq_ctx_term: %s\\n\", zmq_strerror (errno));\n        return -1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "src/address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"address.hpp\"\n#include \"ctx.hpp\"\n#include \"err.hpp\"\n#include \"tcp_address.hpp\"\n#include \"udp_address.hpp\"\n#include \"ipc_address.hpp\"\n#include \"tipc_address.hpp\"\n#include \"ws_address.hpp\"\n\n#if defined ZMQ_HAVE_VSOCK\n// fix header conflict with VMCI\n#define sockaddr_vm linux_sockaddr_vm\n#define VMADDR_PORT_ANY LINUX_VMADDR_PORT_ANY\n#define VMADDR_CID_ANY LINUX_VMADDR_CID_ANY\n#include \"vsock_address.hpp\"\n#undef sockaddr_vm\n#undef VMADDR_CID_ANY\n#undef VMADDR_PORT_ANY\n#endif\n\n#if defined ZMQ_HAVE_VMCI\n#include \"vmci_address.hpp\"\n#endif\n\n#include <string>\n#include <sstream>\n\nzmq::address_t::address_t (const std::string &protocol_,\n                           const std::string &address_,\n                           ctx_t *parent_) :\n    protocol (protocol_), address (address_), parent (parent_)\n{\n    resolved.dummy = NULL;\n}\n\nzmq::address_t::~address_t ()\n{\n    if (protocol == protocol_name::tcp) {\n        LIBZMQ_DELETE (resolved.tcp_addr);\n    } else if (protocol == protocol_name::udp) {\n        LIBZMQ_DELETE (resolved.udp_addr);\n    }\n#ifdef ZMQ_HAVE_WS\n    else if (protocol == protocol_name::ws) {\n        LIBZMQ_DELETE (resolved.ws_addr);\n    }\n#endif\n\n#ifdef ZMQ_HAVE_WSS\n    else if (protocol == protocol_name::wss) {\n        LIBZMQ_DELETE (resolved.ws_addr);\n    }\n#endif\n\n#if defined ZMQ_HAVE_IPC\n    else if (protocol == protocol_name::ipc) {\n        LIBZMQ_DELETE (resolved.ipc_addr);\n    }\n#endif\n#if defined ZMQ_HAVE_TIPC\n    else if (protocol == protocol_name::tipc) {\n        LIBZMQ_DELETE (resolved.tipc_addr);\n    }\n#endif\n#if defined ZMQ_HAVE_VMCI\n    else if (protocol == protocol_name::vmci) {\n        LIBZMQ_DELETE (resolved.vmci_addr);\n    }\n#endif\n#if defined ZMQ_HAVE_VSOCK\n    else if (protocol == protocol_name::vsock) {\n        LIBZMQ_DELETE (resolved.vsock_addr);\n    }\n#endif\n}\n\nint zmq::address_t::to_string (std::string &addr_) const\n{\n    if (protocol == protocol_name::tcp && resolved.tcp_addr)\n        return resolved.tcp_addr->to_string (addr_);\n    if (protocol == protocol_name::udp && resolved.udp_addr)\n        return resolved.udp_addr->to_string (addr_);\n#ifdef ZMQ_HAVE_WS\n    if (protocol == protocol_name::ws && resolved.ws_addr)\n        return resolved.ws_addr->to_string (addr_);\n#endif\n#ifdef ZMQ_HAVE_WSS\n    if (protocol == protocol_name::wss && resolved.ws_addr)\n        return resolved.ws_addr->to_string (addr_);\n#endif\n#if defined ZMQ_HAVE_IPC\n    if (protocol == protocol_name::ipc && resolved.ipc_addr)\n        return resolved.ipc_addr->to_string (addr_);\n#endif\n#if defined ZMQ_HAVE_TIPC\n    if (protocol == protocol_name::tipc && resolved.tipc_addr)\n        return resolved.tipc_addr->to_string (addr_);\n#endif\n#if defined ZMQ_HAVE_VMCI\n    if (protocol == protocol_name::vmci && resolved.vmci_addr)\n        return resolved.vmci_addr->to_string (addr_);\n#endif\n#if defined ZMQ_HAVE_VSOCK\n    if (protocol == protocol_name::vsock && resolved.vsock_addr)\n        return resolved.vsock_addr->to_string (addr_);\n#endif\n\n    if (!protocol.empty () && !address.empty ()) {\n        std::stringstream s;\n        s << protocol << \"://\" << address;\n        addr_ = s.str ();\n        return 0;\n    }\n    addr_.clear ();\n    return -1;\n}\n\nzmq::zmq_socklen_t zmq::get_socket_address (fd_t fd_,\n                                            socket_end_t socket_end_,\n                                            sockaddr_storage *ss_)\n{\n    zmq_socklen_t sl = static_cast<zmq_socklen_t> (sizeof (*ss_));\n\n    const int rc =\n      socket_end_ == socket_end_local\n        ? getsockname (fd_, reinterpret_cast<struct sockaddr *> (ss_), &sl)\n        : getpeername (fd_, reinterpret_cast<struct sockaddr *> (ss_), &sl);\n\n    return rc != 0 ? 0 : sl;\n}\n"
  },
  {
    "path": "src/address.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_ADDRESS_HPP_INCLUDED__\n#define __ZMQ_ADDRESS_HPP_INCLUDED__\n\n#include \"fd.hpp\"\n\n#include <string>\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <sys/socket.h>\n#else\n#include <ws2tcpip.h>\n#endif\n\nnamespace zmq\n{\nclass ctx_t;\nclass tcp_address_t;\nclass udp_address_t;\nclass ws_address_t;\n#ifdef ZMQ_HAVE_WSS\nclass wss_address_t;\n#endif\n#if defined ZMQ_HAVE_IPC\nclass ipc_address_t;\n#endif\n#if defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_VXWORKS\nclass tipc_address_t;\n#endif\n#if defined ZMQ_HAVE_VMCI\nclass vmci_address_t;\n#endif\n#if defined ZMQ_HAVE_VSOCK\nclass vsock_address_t;\n#endif\n\nnamespace protocol_name\n{\nstatic const char inproc[] = \"inproc\";\nstatic const char tcp[] = \"tcp\";\nstatic const char udp[] = \"udp\";\n#ifdef ZMQ_HAVE_OPENPGM\nstatic const char pgm[] = \"pgm\";\nstatic const char epgm[] = \"epgm\";\n#endif\n#ifdef ZMQ_HAVE_NORM\nstatic const char norm[] = \"norm\";\n#endif\n#ifdef ZMQ_HAVE_WS\nstatic const char ws[] = \"ws\";\n#endif\n#ifdef ZMQ_HAVE_WSS\nstatic const char wss[] = \"wss\";\n#endif\n#if defined ZMQ_HAVE_IPC\nstatic const char ipc[] = \"ipc\";\n#endif\n#if defined ZMQ_HAVE_TIPC\nstatic const char tipc[] = \"tipc\";\n#endif\n#if defined ZMQ_HAVE_VMCI\nstatic const char vmci[] = \"vmci\";\n#endif\n#if defined ZMQ_HAVE_VSOCK\nstatic const char vsock[] = \"vsock\";\n#endif\n}\n\nstruct address_t\n{\n    address_t (const std::string &protocol_,\n               const std::string &address_,\n               ctx_t *parent_);\n\n    ~address_t ();\n\n    const std::string protocol;\n    const std::string address;\n    ctx_t *const parent;\n\n    //  Protocol specific resolved address\n    //  All members must be pointers to allow for consistent initialization\n    union\n    {\n        void *dummy;\n        tcp_address_t *tcp_addr;\n        udp_address_t *udp_addr;\n#ifdef ZMQ_HAVE_WS\n        ws_address_t *ws_addr;\n#endif\n#ifdef ZMQ_HAVE_WSS\n        wss_address_t *wss_addr;\n#endif\n#if defined ZMQ_HAVE_IPC\n        ipc_address_t *ipc_addr;\n#endif\n#if defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_VXWORKS\n        tipc_address_t *tipc_addr;\n#endif\n#if defined ZMQ_HAVE_VMCI\n        vmci_address_t *vmci_addr;\n#endif\n#if defined ZMQ_HAVE_VSOCK\n        vsock_address_t *vsock_addr;\n#endif\n    } resolved;\n\n    int to_string (std::string &addr_) const;\n};\n\n#if defined(ZMQ_HAVE_HPUX) || defined(ZMQ_HAVE_VXWORKS)                        \\\n  || defined(ZMQ_HAVE_WINDOWS)\ntypedef int zmq_socklen_t;\n#else\ntypedef socklen_t zmq_socklen_t;\n#endif\n\nenum socket_end_t\n{\n    socket_end_local,\n    socket_end_remote\n};\n\nzmq_socklen_t\nget_socket_address (fd_t fd_, socket_end_t socket_end_, sockaddr_storage *ss_);\n\ntemplate <typename T>\nstd::string get_socket_name (fd_t fd_, socket_end_t socket_end_)\n{\n    struct sockaddr_storage ss;\n    const zmq_socklen_t sl = get_socket_address (fd_, socket_end_, &ss);\n    if (sl == 0) {\n        return std::string ();\n    }\n\n    const T addr (reinterpret_cast<struct sockaddr *> (&ss), sl);\n    std::string address_string;\n    addr.to_string (address_string);\n    return address_string;\n}\n}\n\n#endif\n"
  },
  {
    "path": "src/array.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_ARRAY_INCLUDED__\n#define __ZMQ_ARRAY_INCLUDED__\n\n#include <vector>\n#include <algorithm>\n\n#include \"macros.hpp\"\n\nnamespace zmq\n{\n//  Implementation of fast arrays with O(1) access, insertion and\n//  removal. The array stores pointers rather than objects.\n//  O(1) is achieved by making items inheriting from\n//  array_item_t<ID> class which internally stores the position\n//  in the array.\n//  The ID template argument is used to differentiate among arrays\n//  and thus let an object be stored in different arrays.\n\n//  Base class for objects stored in the array. If you want to store\n//  same object in multiple arrays, each of those arrays has to have\n//  different ID. The item itself has to be derived from instantiations of\n//  array_item_t template for all relevant IDs.\n\ntemplate <int ID = 0> class array_item_t\n{\n  public:\n    array_item_t () : _array_index (-1) {}\n\n    //  The destructor doesn't have to be virtual. It is made virtual\n    //  just to keep ICC and code checking tools from complaining.\n    virtual ~array_item_t () ZMQ_DEFAULT;\n\n    void set_array_index (int index_) { _array_index = index_; }\n\n    int get_array_index () const { return _array_index; }\n\n  private:\n    int _array_index;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (array_item_t)\n};\n\n\ntemplate <typename T, int ID = 0> class array_t\n{\n  private:\n    typedef array_item_t<ID> item_t;\n\n  public:\n    typedef typename std::vector<T *>::size_type size_type;\n\n    array_t () ZMQ_DEFAULT;\n\n    size_type size () { return _items.size (); }\n\n    bool empty () { return _items.empty (); }\n\n    T *&operator[] (size_type index_) { return _items[index_]; }\n\n    void push_back (T *item_)\n    {\n        if (item_)\n            static_cast<item_t *> (item_)->set_array_index (\n              static_cast<int> (_items.size ()));\n        _items.push_back (item_);\n    }\n\n    void erase (T *item_)\n    {\n        erase (static_cast<item_t *> (item_)->get_array_index ());\n    }\n\n    void erase (size_type index_)\n    {\n        if (_items.empty ())\n            return;\n        static_cast<item_t *> (_items.back ())\n          ->set_array_index (static_cast<int> (index_));\n\n        _items[index_] = _items.back ();\n        _items.pop_back ();\n    }\n\n    void swap (size_type index1_, size_type index2_)\n    {\n        if (_items[index1_])\n            static_cast<item_t *> (_items[index1_])\n              ->set_array_index (static_cast<int> (index2_));\n        if (_items[index2_])\n            static_cast<item_t *> (_items[index2_])\n              ->set_array_index (static_cast<int> (index1_));\n        std::swap (_items[index1_], _items[index2_]);\n    }\n\n    void clear () { _items.clear (); }\n\n    static size_type index (T *item_)\n    {\n        return static_cast<size_type> (\n          static_cast<item_t *> (item_)->get_array_index ());\n    }\n\n  private:\n    typedef std::vector<T *> items_t;\n    items_t _items;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (array_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/atomic_counter.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__\n#define __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__\n\n#include \"stdint.hpp\"\n#include \"macros.hpp\"\n\n#if defined ZMQ_FORCE_MUTEXES\n#define ZMQ_ATOMIC_COUNTER_MUTEX\n#elif (defined __cplusplus && __cplusplus >= 201103L)                          \\\n  || (defined _MSC_VER && _MSC_VER >= 1900)\n#define ZMQ_ATOMIC_COUNTER_CXX11\n#elif defined ZMQ_HAVE_ATOMIC_INTRINSICS\n#define ZMQ_ATOMIC_COUNTER_INTRINSIC\n#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__\n#define ZMQ_ATOMIC_COUNTER_X86\n#elif defined __ARM_ARCH_7A__ && defined __GNUC__\n#define ZMQ_ATOMIC_COUNTER_ARM\n#elif defined ZMQ_HAVE_WINDOWS\n#define ZMQ_ATOMIC_COUNTER_WINDOWS\n#elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD                     \\\n       || defined ZMQ_HAVE_GNU)\n#define ZMQ_ATOMIC_COUNTER_ATOMIC_H\n#elif defined __tile__\n#define ZMQ_ATOMIC_COUNTER_TILE\n#else\n#define ZMQ_ATOMIC_COUNTER_MUTEX\n#endif\n\n#if defined ZMQ_ATOMIC_COUNTER_MUTEX\n#include \"mutex.hpp\"\n#elif defined ZMQ_ATOMIC_COUNTER_CXX11\n#include <atomic>\n#elif defined ZMQ_ATOMIC_COUNTER_WINDOWS\n#include \"windows.hpp\"\n#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H\n#include <atomic.h>\n#elif defined ZMQ_ATOMIC_COUNTER_TILE\n#include <arch/atomic.h>\n#endif\n\nnamespace zmq\n{\n//  This class represents an integer that can be incremented/decremented\n//  in atomic fashion.\n//\n//  In zmq::shared_message_memory_allocator a buffer with an atomic_counter_t\n//  at the start is allocated. If the class does not align to pointer size,\n//  access to pointers in structures in the buffer will cause SIGBUS on\n//  architectures that do not allow mis-aligned pointers (eg: SPARC).\n//  Force the compiler to align to pointer size, which will cause the object\n//  to grow from 4 bytes to 8 bytes on 64 bit architectures (when not using\n//  mutexes).\n\n#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))\nclass __declspec (align (8)) atomic_counter_t\n#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_ARM_ARMV7VE))\nclass __declspec (align (4)) atomic_counter_t\n#else\nclass atomic_counter_t\n#endif\n{\n  public:\n    typedef uint32_t integer_t;\n\n    atomic_counter_t (integer_t value_ = 0) ZMQ_NOEXCEPT : _value (value_) {}\n\n    //  Set counter _value (not thread-safe).\n    void set (integer_t value_) ZMQ_NOEXCEPT { _value = value_; }\n\n    //  Atomic addition. Returns the old _value.\n    integer_t add (integer_t increment_) ZMQ_NOEXCEPT\n    {\n        integer_t old_value;\n\n#if defined ZMQ_ATOMIC_COUNTER_WINDOWS\n        old_value = InterlockedExchangeAdd ((LONG *) &_value, increment_);\n#elif defined ZMQ_ATOMIC_COUNTER_INTRINSIC\n        old_value = __atomic_fetch_add (&_value, increment_, __ATOMIC_ACQ_REL);\n#elif defined ZMQ_ATOMIC_COUNTER_CXX11\n        old_value = _value.fetch_add (increment_, std::memory_order_acq_rel);\n#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H\n        integer_t new_value = atomic_add_32_nv (&_value, increment_);\n        old_value = new_value - increment_;\n#elif defined ZMQ_ATOMIC_COUNTER_TILE\n        old_value = arch_atomic_add (&_value, increment_);\n#elif defined ZMQ_ATOMIC_COUNTER_X86\n        __asm__ volatile (\"lock; xadd %0, %1 \\n\\t\"\n                          : \"=r\"(old_value), \"=m\"(_value)\n                          : \"0\"(increment_), \"m\"(_value)\n                          : \"cc\", \"memory\");\n#elif defined ZMQ_ATOMIC_COUNTER_ARM\n        integer_t flag, tmp;\n        __asm__ volatile (\"       dmb     sy\\n\\t\"\n                          \"1:     ldrex   %0, [%5]\\n\\t\"\n                          \"       add     %2, %0, %4\\n\\t\"\n                          \"       strex   %1, %2, [%5]\\n\\t\"\n                          \"       teq     %1, #0\\n\\t\"\n                          \"       bne     1b\\n\\t\"\n                          \"       dmb     sy\\n\\t\"\n                          : \"=&r\"(old_value), \"=&r\"(flag), \"=&r\"(tmp),\n                            \"+Qo\"(_value)\n                          : \"Ir\"(increment_), \"r\"(&_value)\n                          : \"cc\");\n#elif defined ZMQ_ATOMIC_COUNTER_MUTEX\n        sync.lock ();\n        old_value = _value;\n        _value += increment_;\n        sync.unlock ();\n#else\n#error atomic_counter is not implemented for this platform\n#endif\n        return old_value;\n    }\n\n    //  Atomic subtraction. Returns false if the counter drops to zero.\n    bool sub (integer_t decrement_) ZMQ_NOEXCEPT\n    {\n#if defined ZMQ_ATOMIC_COUNTER_WINDOWS\n        LONG delta = -((LONG) decrement_);\n        integer_t old = InterlockedExchangeAdd ((LONG *) &_value, delta);\n        return old - decrement_ != 0;\n#elif defined ZMQ_ATOMIC_COUNTER_INTRINSIC\n        integer_t nv =\n          __atomic_sub_fetch (&_value, decrement_, __ATOMIC_ACQ_REL);\n        return nv != 0;\n#elif defined ZMQ_ATOMIC_COUNTER_CXX11\n        const integer_t old =\n          _value.fetch_sub (decrement_, std::memory_order_acq_rel);\n        return old - decrement_ != 0;\n#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H\n        int32_t delta = -((int32_t) decrement_);\n        integer_t nv = atomic_add_32_nv (&_value, delta);\n        return nv != 0;\n#elif defined ZMQ_ATOMIC_COUNTER_TILE\n        int32_t delta = -((int32_t) decrement_);\n        integer_t nv = arch_atomic_add (&_value, delta);\n        return nv != 0;\n#elif defined ZMQ_ATOMIC_COUNTER_X86\n        integer_t oldval = -decrement_;\n        volatile integer_t *val = &_value;\n        __asm__ volatile (\"lock; xaddl %0,%1\"\n                          : \"=r\"(oldval), \"=m\"(*val)\n                          : \"0\"(oldval), \"m\"(*val)\n                          : \"cc\", \"memory\");\n        return oldval != decrement_;\n#elif defined ZMQ_ATOMIC_COUNTER_ARM\n        integer_t old_value, flag, tmp;\n        __asm__ volatile (\"       dmb     sy\\n\\t\"\n                          \"1:     ldrex   %0, [%5]\\n\\t\"\n                          \"       sub     %2, %0, %4\\n\\t\"\n                          \"       strex   %1, %2, [%5]\\n\\t\"\n                          \"       teq     %1, #0\\n\\t\"\n                          \"       bne     1b\\n\\t\"\n                          \"       dmb     sy\\n\\t\"\n                          : \"=&r\"(old_value), \"=&r\"(flag), \"=&r\"(tmp),\n                            \"+Qo\"(_value)\n                          : \"Ir\"(decrement_), \"r\"(&_value)\n                          : \"cc\");\n        return old_value - decrement_ != 0;\n#elif defined ZMQ_ATOMIC_COUNTER_MUTEX\n        sync.lock ();\n        _value -= decrement_;\n        bool result = _value ? true : false;\n        sync.unlock ();\n        return result;\n#else\n#error atomic_counter is not implemented for this platform\n#endif\n    }\n\n    integer_t get () const ZMQ_NOEXCEPT { return _value; }\n\n  private:\n#if defined ZMQ_ATOMIC_COUNTER_CXX11\n    std::atomic<integer_t> _value;\n#else\n    volatile integer_t _value;\n#endif\n\n#if defined ZMQ_ATOMIC_COUNTER_MUTEX\n    mutex_t sync;\n#endif\n\n#if !defined ZMQ_ATOMIC_COUNTER_CXX11\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (atomic_counter_t)\n#endif\n#if defined(__GNUC__) || defined(__INTEL_COMPILER)                             \\\n  || (defined(__SUNPRO_C) && __SUNPRO_C >= 0x590)                              \\\n  || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590)\n} __attribute__ ((aligned (sizeof (void *))));\n#else\n};\n#endif\n}\n\n//  Remove macros local to this file.\n#undef ZMQ_ATOMIC_COUNTER_MUTEX\n#undef ZMQ_ATOMIC_COUNTER_INTRINSIC\n#undef ZMQ_ATOMIC_COUNTER_CXX11\n#undef ZMQ_ATOMIC_COUNTER_X86\n#undef ZMQ_ATOMIC_COUNTER_ARM\n#undef ZMQ_ATOMIC_COUNTER_WINDOWS\n#undef ZMQ_ATOMIC_COUNTER_ATOMIC_H\n#undef ZMQ_ATOMIC_COUNTER_TILE\n\n#endif\n"
  },
  {
    "path": "src/atomic_ptr.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_ATOMIC_PTR_HPP_INCLUDED__\n#define __ZMQ_ATOMIC_PTR_HPP_INCLUDED__\n\n#include \"macros.hpp\"\n\n#if defined ZMQ_FORCE_MUTEXES\n#define ZMQ_ATOMIC_PTR_MUTEX\n#elif (defined __cplusplus && __cplusplus >= 201103L)                          \\\n  || (defined _MSC_VER && _MSC_VER >= 1900)\n#define ZMQ_ATOMIC_PTR_CXX11\n#elif defined ZMQ_HAVE_ATOMIC_INTRINSICS\n#define ZMQ_ATOMIC_PTR_INTRINSIC\n#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__\n#define ZMQ_ATOMIC_PTR_X86\n#elif defined __ARM_ARCH_7A__ && defined __GNUC__\n#define ZMQ_ATOMIC_PTR_ARM\n#elif defined __tile__\n#define ZMQ_ATOMIC_PTR_TILE\n#elif defined ZMQ_HAVE_WINDOWS\n#define ZMQ_ATOMIC_PTR_WINDOWS\n#elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD                     \\\n       || defined ZMQ_HAVE_GNU)\n#define ZMQ_ATOMIC_PTR_ATOMIC_H\n#else\n#define ZMQ_ATOMIC_PTR_MUTEX\n#endif\n\n#if defined ZMQ_ATOMIC_PTR_MUTEX\n#include \"mutex.hpp\"\n#elif defined ZMQ_ATOMIC_PTR_CXX11\n#include <atomic>\n#elif defined ZMQ_ATOMIC_PTR_WINDOWS\n#include \"windows.hpp\"\n#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H\n#include <atomic.h>\n#elif defined ZMQ_ATOMIC_PTR_TILE\n#include <arch/atomic.h>\n#endif\n\nnamespace zmq\n{\n#if !defined ZMQ_ATOMIC_PTR_CXX11\ninline void *atomic_xchg_ptr (void **ptr_,\n                              void *const val_\n#if defined ZMQ_ATOMIC_PTR_MUTEX\n                              ,\n                              mutex_t &_sync\n#endif\n                              ) ZMQ_NOEXCEPT\n{\n#if defined ZMQ_ATOMIC_PTR_WINDOWS\n    return InterlockedExchangePointer ((PVOID *) ptr_, val_);\n#elif defined ZMQ_ATOMIC_PTR_INTRINSIC\n    return __atomic_exchange_n (ptr_, val_, __ATOMIC_ACQ_REL);\n#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H\n    return atomic_swap_ptr (ptr_, val_);\n#elif defined ZMQ_ATOMIC_PTR_TILE\n    return arch_atomic_exchange (ptr_, val_);\n#elif defined ZMQ_ATOMIC_PTR_X86\n    void *old;\n    __asm__ volatile (\"lock; xchg %0, %2\"\n                      : \"=r\"(old), \"=m\"(*ptr_)\n                      : \"m\"(*ptr_), \"0\"(val_));\n    return old;\n#elif defined ZMQ_ATOMIC_PTR_ARM\n    void *old;\n    unsigned int flag;\n    __asm__ volatile (\"       dmb     sy\\n\\t\"\n                      \"1:     ldrex   %1, [%3]\\n\\t\"\n                      \"       strex   %0, %4, [%3]\\n\\t\"\n                      \"       teq     %0, #0\\n\\t\"\n                      \"       bne     1b\\n\\t\"\n                      \"       dmb     sy\\n\\t\"\n                      : \"=&r\"(flag), \"=&r\"(old), \"+Qo\"(*ptr_)\n                      : \"r\"(ptr_), \"r\"(val_)\n                      : \"cc\");\n    return old;\n#elif defined ZMQ_ATOMIC_PTR_MUTEX\n    _sync.lock ();\n    void *old = *ptr_;\n    *ptr_ = val_;\n    _sync.unlock ();\n    return old;\n#else\n#error atomic_ptr is not implemented for this platform\n#endif\n}\n\ninline void *atomic_cas (void *volatile *ptr_,\n                         void *cmp_,\n                         void *val_\n#if defined ZMQ_ATOMIC_PTR_MUTEX\n                         ,\n                         mutex_t &_sync\n#endif\n                         ) ZMQ_NOEXCEPT\n{\n#if defined ZMQ_ATOMIC_PTR_WINDOWS\n    return InterlockedCompareExchangePointer ((volatile PVOID *) ptr_, val_,\n                                              cmp_);\n#elif defined ZMQ_ATOMIC_PTR_INTRINSIC\n    void *old = cmp_;\n    __atomic_compare_exchange_n (ptr_, &old, val_, false, __ATOMIC_RELEASE,\n                                 __ATOMIC_ACQUIRE);\n    return old;\n#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H\n    return atomic_cas_ptr (ptr_, cmp_, val_);\n#elif defined ZMQ_ATOMIC_PTR_TILE\n    return arch_atomic_val_compare_and_exchange (ptr_, cmp_, val_);\n#elif defined ZMQ_ATOMIC_PTR_X86\n    void *old;\n    __asm__ volatile (\"lock; cmpxchg %2, %3\"\n                      : \"=a\"(old), \"=m\"(*ptr_)\n                      : \"r\"(val_), \"m\"(*ptr_), \"0\"(cmp_)\n                      : \"cc\");\n    return old;\n#elif defined ZMQ_ATOMIC_PTR_ARM\n    void *old;\n    unsigned int flag;\n    __asm__ volatile (\"       dmb     sy\\n\\t\"\n                      \"1:     ldrex   %1, [%3]\\n\\t\"\n                      \"       mov     %0, #0\\n\\t\"\n                      \"       teq     %1, %4\\n\\t\"\n                      \"       it      eq\\n\\t\"\n                      \"       strexeq %0, %5, [%3]\\n\\t\"\n                      \"       teq     %0, #0\\n\\t\"\n                      \"       bne     1b\\n\\t\"\n                      \"       dmb     sy\\n\\t\"\n                      : \"=&r\"(flag), \"=&r\"(old), \"+Qo\"(*ptr_)\n                      : \"r\"(ptr_), \"r\"(cmp_), \"r\"(val_)\n                      : \"cc\");\n    return old;\n#elif defined ZMQ_ATOMIC_PTR_MUTEX\n    _sync.lock ();\n    void *old = *ptr_;\n    if (*ptr_ == cmp_)\n        *ptr_ = val_;\n    _sync.unlock ();\n    return old;\n#else\n#error atomic_ptr is not implemented for this platform\n#endif\n}\n#endif\n\n//  This class encapsulates several atomic operations on pointers.\n\ntemplate <typename T> class atomic_ptr_t\n{\n  public:\n    //  Initialise atomic pointer\n    atomic_ptr_t () ZMQ_NOEXCEPT { _ptr = NULL; }\n\n    //  Set value of atomic pointer in a non-threadsafe way\n    //  Use this function only when you are sure that at most one\n    //  thread is accessing the pointer at the moment.\n    void set (T *ptr_) ZMQ_NOEXCEPT { _ptr = ptr_; }\n\n    //  Perform atomic 'exchange pointers' operation. Pointer is set\n    //  to the 'val_' value. Old value is returned.\n    T *xchg (T *val_) ZMQ_NOEXCEPT\n    {\n#if defined ZMQ_ATOMIC_PTR_CXX11\n        return _ptr.exchange (val_, std::memory_order_acq_rel);\n#else\n        return (T *) atomic_xchg_ptr ((void **) &_ptr, val_\n#if defined ZMQ_ATOMIC_PTR_MUTEX\n                                      ,\n                                      _sync\n#endif\n        );\n#endif\n    }\n\n    //  Perform atomic 'compare and swap' operation on the pointer.\n    //  The pointer is compared to 'cmp' argument and if they are\n    //  equal, its value is set to 'val_'. Old value of the pointer\n    //  is returned.\n    T *cas (T *cmp_, T *val_) ZMQ_NOEXCEPT\n    {\n#if defined ZMQ_ATOMIC_PTR_CXX11\n        _ptr.compare_exchange_strong (cmp_, val_, std::memory_order_acq_rel);\n        return cmp_;\n#else\n        return (T *) atomic_cas ((void **) &_ptr, cmp_, val_\n#if defined ZMQ_ATOMIC_PTR_MUTEX\n                                 ,\n                                 _sync\n#endif\n        );\n#endif\n    }\n\n  private:\n#if defined ZMQ_ATOMIC_PTR_CXX11\n    std::atomic<T *> _ptr;\n#else\n    volatile T *_ptr;\n#endif\n\n#if defined ZMQ_ATOMIC_PTR_MUTEX\n    mutex_t _sync;\n#endif\n\n#if !defined ZMQ_ATOMIC_PTR_CXX11\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (atomic_ptr_t)\n#endif\n};\n\nstruct atomic_value_t\n{\n    atomic_value_t (const int value_) ZMQ_NOEXCEPT : _value (value_) {}\n\n    atomic_value_t (const atomic_value_t &src_) ZMQ_NOEXCEPT\n        : _value (src_.load ())\n    {\n    }\n\n    void store (const int value_) ZMQ_NOEXCEPT\n    {\n#if defined ZMQ_ATOMIC_PTR_CXX11\n        _value.store (value_, std::memory_order_release);\n#else\n        atomic_xchg_ptr ((void **) &_value, (void *) (ptrdiff_t) value_\n#if defined ZMQ_ATOMIC_PTR_MUTEX\n                         ,\n                         _sync\n#endif\n        );\n#endif\n    }\n\n    int load () const ZMQ_NOEXCEPT\n    {\n#if defined ZMQ_ATOMIC_PTR_CXX11\n        return _value.load (std::memory_order_acquire);\n#else\n        return (int) (ptrdiff_t) atomic_cas ((void **) &_value, 0, 0\n#if defined ZMQ_ATOMIC_PTR_MUTEX\n                                             ,\n#if defined __SUNPRO_CC\n                                             const_cast<mutex_t &> (_sync)\n#else\n                                             _sync\n#endif\n#endif\n        );\n#endif\n    }\n\n  private:\n#if defined ZMQ_ATOMIC_PTR_CXX11\n    std::atomic<int> _value;\n#else\n    volatile ptrdiff_t _value;\n#endif\n\n#if defined ZMQ_ATOMIC_PTR_MUTEX\n    mutable mutex_t _sync;\n#endif\n\n  private:\n    atomic_value_t &operator= (const atomic_value_t &src_);\n};\n}\n\n//  Remove macros local to this file.\n#undef ZMQ_ATOMIC_PTR_MUTEX\n#undef ZMQ_ATOMIC_PTR_INTRINSIC\n#undef ZMQ_ATOMIC_PTR_CXX11\n#undef ZMQ_ATOMIC_PTR_X86\n#undef ZMQ_ATOMIC_PTR_ARM\n#undef ZMQ_ATOMIC_PTR_TILE\n#undef ZMQ_ATOMIC_PTR_WINDOWS\n#undef ZMQ_ATOMIC_PTR_ATOMIC_H\n\n#endif\n"
  },
  {
    "path": "src/blob.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_BLOB_HPP_INCLUDED__\n#define __ZMQ_BLOB_HPP_INCLUDED__\n\n#include \"macros.hpp\"\n#include \"err.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n#include <algorithm>\n#include <ios>\n\n#if __cplusplus >= 201103L || defined(_MSC_VER) && _MSC_VER > 1700\n#define ZMQ_HAS_MOVE_SEMANTICS\n#define ZMQ_MAP_INSERT_OR_EMPLACE(k, v) emplace (k, v)\n#define ZMQ_PUSH_OR_EMPLACE_BACK emplace_back\n#define ZMQ_MOVE(x) std::move (x)\n#else\n#if defined __SUNPRO_CC\ntemplate <typename K, typename V>\nstd::pair<const K, V> make_pair_fix_const (const K &k, const V &v)\n{\n    return std::pair<const K, V> (k, v);\n}\n\n#define ZMQ_MAP_INSERT_OR_EMPLACE(k, v) insert (make_pair_fix_const (k, v))\n#else\n#define ZMQ_MAP_INSERT_OR_EMPLACE(k, v) insert (std::make_pair (k, v))\n#endif\n\n#define ZMQ_PUSH_OR_EMPLACE_BACK push_back\n#define ZMQ_MOVE(x) (x)\n#endif\n\nnamespace zmq\n{\nstruct reference_tag_t\n{\n};\n\n//  Object to hold dynamically allocated opaque binary data.\n//  On modern compilers, it will be movable but not copyable. Copies\n//  must be explicitly created by set_deep_copy.\n//  On older compilers, it is copyable for syntactical reasons.\nstruct blob_t\n{\n    //  Creates an empty blob_t.\n    blob_t () : _data (0), _size (0), _owned (true) {}\n\n    //  Creates a blob_t of a given size, with uninitialized content.\n    explicit blob_t (const size_t size_) :\n        _data (static_cast<unsigned char *> (malloc (size_))),\n        _size (size_),\n        _owned (true)\n    {\n        alloc_assert (!_size || _data);\n    }\n\n    //  Creates a blob_t of a given size, an initializes content by copying\n    // from another buffer.\n    blob_t (const unsigned char *const data_, const size_t size_) :\n        _data (static_cast<unsigned char *> (malloc (size_))),\n        _size (size_),\n        _owned (true)\n    {\n        alloc_assert (!size_ || _data);\n        if (size_ && _data) {\n            memcpy (_data, data_, size_);\n        }\n    }\n\n    //  Creates a blob_t for temporary use that only references a\n    //  pre-allocated block of data.\n    //  Use with caution and ensure that the blob_t will not outlive\n    //  the referenced data.\n    blob_t (unsigned char *const data_, const size_t size_, reference_tag_t) :\n        _data (data_), _size (size_), _owned (false)\n    {\n    }\n\n    //  Returns the size of the blob_t.\n    size_t size () const { return _size; }\n\n    //  Returns a pointer to the data of the blob_t.\n    const unsigned char *data () const { return _data; }\n\n    //  Returns a pointer to the data of the blob_t.\n    unsigned char *data () { return _data; }\n\n    //  Defines an order relationship on blob_t.\n    bool operator< (blob_t const &other_) const\n    {\n        const int cmpres =\n          memcmp (_data, other_._data, std::min (_size, other_._size));\n        return cmpres < 0 || (cmpres == 0 && _size < other_._size);\n    }\n\n    //  Sets a blob_t to a deep copy of another blob_t.\n    void set_deep_copy (blob_t const &other_)\n    {\n        clear ();\n        _data = static_cast<unsigned char *> (malloc (other_._size));\n        alloc_assert (!other_._size || _data);\n        _size = other_._size;\n        _owned = true;\n        if (_size && _data) {\n            memcpy (_data, other_._data, _size);\n        }\n    }\n\n    //  Sets a blob_t to a copy of a given buffer.\n    void set (const unsigned char *const data_, const size_t size_)\n    {\n        clear ();\n        _data = static_cast<unsigned char *> (malloc (size_));\n        alloc_assert (!size_ || _data);\n        _size = size_;\n        _owned = true;\n        if (size_ && _data) {\n            memcpy (_data, data_, size_);\n        }\n    }\n\n    //  Empties a blob_t.\n    void clear ()\n    {\n        if (_owned) {\n            free (_data);\n        }\n        _data = 0;\n        _size = 0;\n    }\n\n    ~blob_t ()\n    {\n        if (_owned) {\n            free (_data);\n        }\n    }\n\n#ifdef ZMQ_HAS_MOVE_SEMANTICS\n    blob_t (const blob_t &) = delete;\n    blob_t &operator= (const blob_t &) = delete;\n\n    blob_t (blob_t &&other_) ZMQ_NOEXCEPT : _data (other_._data),\n                                            _size (other_._size),\n                                            _owned (other_._owned)\n    {\n        other_._owned = false;\n    }\n    blob_t &operator= (blob_t &&other_) ZMQ_NOEXCEPT\n    {\n        if (this != &other_) {\n            clear ();\n            _data = other_._data;\n            _size = other_._size;\n            _owned = other_._owned;\n            other_._owned = false;\n        }\n        return *this;\n    }\n#else\n    blob_t (const blob_t &other) : _owned (false) { set_deep_copy (other); }\n    blob_t &operator= (const blob_t &other)\n    {\n        if (this != &other) {\n            clear ();\n            set_deep_copy (other);\n        }\n        return *this;\n    }\n#endif\n\n  private:\n    unsigned char *_data;\n    size_t _size;\n    bool _owned;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/channel.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"channel.hpp\"\n#include \"err.hpp\"\n#include \"pipe.hpp\"\n#include \"msg.hpp\"\n\nzmq::channel_t::channel_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_, true), _pipe (NULL)\n{\n    options.type = ZMQ_CHANNEL;\n}\n\nzmq::channel_t::~channel_t ()\n{\n    zmq_assert (!_pipe);\n}\n\nvoid zmq::channel_t::xattach_pipe (pipe_t *pipe_,\n                                   bool subscribe_to_all_,\n                                   bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_ != NULL);\n\n    //  ZMQ_PAIR socket can only be connected to a single peer.\n    //  The socket rejects any further connection requests.\n    if (_pipe == NULL)\n        _pipe = pipe_;\n    else\n        pipe_->terminate (false);\n}\n\nvoid zmq::channel_t::xpipe_terminated (pipe_t *pipe_)\n{\n    if (pipe_ == _pipe)\n        _pipe = NULL;\n}\n\nvoid zmq::channel_t::xread_activated (pipe_t *)\n{\n    //  There's just one pipe. No lists of active and inactive pipes.\n    //  There's nothing to do here.\n}\n\nvoid zmq::channel_t::xwrite_activated (pipe_t *)\n{\n    //  There's just one pipe. No lists of active and inactive pipes.\n    //  There's nothing to do here.\n}\n\nint zmq::channel_t::xsend (msg_t *msg_)\n{\n    //  CHANNEL sockets do not allow multipart data (ZMQ_SNDMORE)\n    if (msg_->flags () & msg_t::more) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    if (!_pipe || !_pipe->write (msg_)) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    _pipe->flush ();\n\n    //  Detach the original message from the data buffer.\n    const int rc = msg_->init ();\n    errno_assert (rc == 0);\n\n    return 0;\n}\n\nint zmq::channel_t::xrecv (msg_t *msg_)\n{\n    //  Deallocate old content of the message.\n    int rc = msg_->close ();\n    errno_assert (rc == 0);\n\n    if (!_pipe) {\n        //  Initialise the output parameter to be a 0-byte message.\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n\n        errno = EAGAIN;\n        return -1;\n    }\n\n    // Drop any messages with more flag\n    bool read = _pipe->read (msg_);\n    while (read && msg_->flags () & msg_t::more) {\n        // drop all frames of the current multi-frame message\n        read = _pipe->read (msg_);\n        while (read && msg_->flags () & msg_t::more)\n            read = _pipe->read (msg_);\n\n        // get the new message\n        if (read)\n            read = _pipe->read (msg_);\n    }\n\n    if (!read) {\n        //  Initialise the output parameter to be a 0-byte message.\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n\n        errno = EAGAIN;\n        return -1;\n    }\n\n    return 0;\n}\n\nbool zmq::channel_t::xhas_in ()\n{\n    if (!_pipe)\n        return false;\n\n    return _pipe->check_read ();\n}\n\nbool zmq::channel_t::xhas_out ()\n{\n    if (!_pipe)\n        return false;\n\n    return _pipe->check_write ();\n}\n"
  },
  {
    "path": "src/channel.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_CHANNEL_HPP_INCLUDED__\n#define __ZMQ_CHANNEL_HPP_INCLUDED__\n\n#include \"blob.hpp\"\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass pipe_t;\nclass io_thread_t;\n\nclass channel_t ZMQ_FINAL : public socket_base_t\n{\n  public:\n    channel_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~channel_t ();\n\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xsend (zmq::msg_t *msg_);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    bool xhas_out ();\n    void xread_activated (zmq::pipe_t *pipe_);\n    void xwrite_activated (zmq::pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n\n  private:\n    zmq::pipe_t *_pipe;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (channel_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/client.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"client.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n\nzmq::client_t::client_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_, true)\n{\n    options.type = ZMQ_CLIENT;\n    options.can_send_hello_msg = true;\n    options.can_recv_hiccup_msg = true;\n}\n\nzmq::client_t::~client_t ()\n{\n}\n\nvoid zmq::client_t::xattach_pipe (pipe_t *pipe_,\n                                  bool subscribe_to_all_,\n                                  bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_);\n\n    _fq.attach (pipe_);\n    _lb.attach (pipe_);\n}\n\nint zmq::client_t::xsend (msg_t *msg_)\n{\n    //  CLIENT sockets do not allow multipart data (ZMQ_SNDMORE)\n    if (msg_->flags () & msg_t::more) {\n        errno = EINVAL;\n        return -1;\n    }\n    return _lb.sendpipe (msg_, NULL);\n}\n\nint zmq::client_t::xrecv (msg_t *msg_)\n{\n    int rc = _fq.recvpipe (msg_, NULL);\n\n    // Drop any messages with more flag\n    while (rc == 0 && msg_->flags () & msg_t::more) {\n        // drop all frames of the current multi-frame message\n        rc = _fq.recvpipe (msg_, NULL);\n\n        while (rc == 0 && msg_->flags () & msg_t::more)\n            rc = _fq.recvpipe (msg_, NULL);\n\n        // get the new message\n        if (rc == 0)\n            rc = _fq.recvpipe (msg_, NULL);\n    }\n\n    return rc;\n}\n\nbool zmq::client_t::xhas_in ()\n{\n    return _fq.has_in ();\n}\n\nbool zmq::client_t::xhas_out ()\n{\n    return _lb.has_out ();\n}\n\nvoid zmq::client_t::xread_activated (pipe_t *pipe_)\n{\n    _fq.activated (pipe_);\n}\n\nvoid zmq::client_t::xwrite_activated (pipe_t *pipe_)\n{\n    _lb.activated (pipe_);\n}\n\nvoid zmq::client_t::xpipe_terminated (pipe_t *pipe_)\n{\n    _fq.pipe_terminated (pipe_);\n    _lb.pipe_terminated (pipe_);\n}\n"
  },
  {
    "path": "src/client.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_CLIENT_HPP_INCLUDED__\n#define __ZMQ_CLIENT_HPP_INCLUDED__\n\n#include \"socket_base.hpp\"\n#include \"fq.hpp\"\n#include \"lb.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass pipe_t;\nclass io_thread_t;\n\nclass client_t ZMQ_FINAL : public socket_base_t\n{\n  public:\n    client_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~client_t ();\n\n  protected:\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xsend (zmq::msg_t *msg_);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    bool xhas_out ();\n    void xread_activated (zmq::pipe_t *pipe_);\n    void xwrite_activated (zmq::pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n\n  private:\n    //  Messages are fair-queued from inbound pipes. And load-balanced to\n    //  the outbound pipes.\n    fq_t _fq;\n    lb_t _lb;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (client_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/clock.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"clock.hpp\"\n#include \"likely.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"mutex.hpp\"\n\n#include <stddef.h>\n\n#if defined _MSC_VER\n#if defined _WIN32_WCE\n#include <cmnintrin.h>\n#else\n#include <intrin.h>\n#if defined(_M_ARM) || defined(_M_ARM64)\n#include <arm_neon.h>\n#endif\n#endif\n#endif\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <sys/time.h>\n#endif\n\n#if defined HAVE_CLOCK_GETTIME || defined HAVE_GETHRTIME\n#include <time.h>\n#endif\n\n#if defined ZMQ_HAVE_VXWORKS\n#include \"timers.h\"\n#endif\n\n#if defined ZMQ_HAVE_OSX\nint alt_clock_gettime (int clock_id, timespec *ts)\n{\n    clock_serv_t cclock;\n    mach_timespec_t mts;\n    host_get_clock_service (mach_host_self (), clock_id, &cclock);\n    clock_get_time (cclock, &mts);\n    mach_port_deallocate (mach_task_self (), cclock);\n    ts->tv_sec = mts.tv_sec;\n    ts->tv_nsec = mts.tv_nsec;\n    return 0;\n}\n#endif\n\n#ifdef ZMQ_HAVE_WINDOWS\ntypedef ULONGLONG (*f_compatible_get_tick_count64) ();\n\nstatic zmq::mutex_t compatible_get_tick_count64_mutex;\n\nULONGLONG compatible_get_tick_count64 ()\n{\n#ifdef ZMQ_HAVE_WINDOWS_UWP\n    const ULONGLONG result = ::GetTickCount64 ();\n    return result;\n#else\n    zmq::scoped_lock_t locker (compatible_get_tick_count64_mutex);\n\n    static DWORD s_wrap = 0;\n    static DWORD s_last_tick = 0;\n    const DWORD current_tick = ::GetTickCount ();\n\n    if (current_tick < s_last_tick)\n        ++s_wrap;\n\n    s_last_tick = current_tick;\n    const ULONGLONG result = (static_cast<ULONGLONG> (s_wrap) << 32)\n                             + static_cast<ULONGLONG> (current_tick);\n\n    return result;\n#endif\n}\n\nf_compatible_get_tick_count64 init_compatible_get_tick_count64 ()\n{\n    f_compatible_get_tick_count64 func = NULL;\n#if !defined ZMQ_HAVE_WINDOWS_UWP\n\n    const HMODULE module = ::LoadLibraryA (\"Kernel32.dll\");\n    if (module != NULL)\n        func = reinterpret_cast<f_compatible_get_tick_count64> (\n          ::GetProcAddress (module, \"GetTickCount64\"));\n#endif\n    if (func == NULL)\n        func = compatible_get_tick_count64;\n\n#if !defined ZMQ_HAVE_WINDOWS_UWP\n    if (module != NULL)\n        ::FreeLibrary (module);\n#endif\n\n    return func;\n}\n\nstatic f_compatible_get_tick_count64 my_get_tick_count64 =\n  init_compatible_get_tick_count64 ();\n#endif\n\n#ifndef ZMQ_HAVE_WINDOWS\nconst uint64_t usecs_per_msec = 1000;\nconst uint64_t nsecs_per_usec = 1000;\n#endif\nconst uint64_t usecs_per_sec = 1000000;\n\nzmq::clock_t::clock_t () :\n    _last_tsc (rdtsc ()),\n#ifdef ZMQ_HAVE_WINDOWS\n    _last_time (static_cast<uint64_t> ((*my_get_tick_count64) ()))\n#else\n    _last_time (now_us () / usecs_per_msec)\n#endif\n{\n}\n\nuint64_t zmq::clock_t::now_us ()\n{\n#if defined ZMQ_HAVE_WINDOWS\n\n    //  Get the high resolution counter's accuracy.\n    //  While QueryPerformanceFrequency only needs to be called once, since its\n    //  value does not change during runtime, we query it here since this is a\n    //  static function. It might make sense to cache it, though.\n    LARGE_INTEGER ticks_per_second;\n    QueryPerformanceFrequency (&ticks_per_second);\n\n    //  What time is it?\n    LARGE_INTEGER tick;\n    QueryPerformanceCounter (&tick);\n\n    //  Convert the tick number into the number of seconds\n    //  since the system was started.\n    const double ticks_div =\n      static_cast<double> (ticks_per_second.QuadPart) / usecs_per_sec;\n    return static_cast<uint64_t> (tick.QuadPart / ticks_div);\n\n#elif defined HAVE_CLOCK_GETTIME                                               \\\n  && (defined CLOCK_MONOTONIC || defined ZMQ_HAVE_VXWORKS)\n\n    //  Use POSIX clock_gettime function to get precise monotonic time.\n    struct timespec tv;\n\n#if defined ZMQ_HAVE_OSX                                                       \\\n  && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12\n    int rc = alt_clock_gettime (SYSTEM_CLOCK, &tv);\n#else\n    int rc = clock_gettime (CLOCK_MONOTONIC, &tv);\n#endif\n    // Fix case where system has clock_gettime but CLOCK_MONOTONIC is not supported.\n    // This should be a configuration check, but I looked into it and writing an\n    // AC_FUNC_CLOCK_MONOTONIC seems beyond my powers.\n    if (rc != 0) {\n#ifndef ZMQ_HAVE_VXWORKS\n        //  Use POSIX gettimeofday function to get precise time.\n        struct timeval tv;\n        int rc = gettimeofday (&tv, NULL);\n        errno_assert (rc == 0);\n        return tv.tv_sec * usecs_per_sec + tv.tv_usec;\n#endif\n    }\n    return tv.tv_sec * usecs_per_sec + tv.tv_nsec / nsecs_per_usec;\n\n#elif defined HAVE_GETHRTIME\n\n    return gethrtime () / nsecs_per_usec;\n\n#else\n\n    LIBZMQ_UNUSED (nsecs_per_usec);\n    //  Use POSIX gettimeofday function to get precise time.\n    struct timeval tv;\n    int rc = gettimeofday (&tv, NULL);\n    errno_assert (rc == 0);\n    return tv.tv_sec * usecs_per_sec + tv.tv_usec;\n\n#endif\n}\n\nuint64_t zmq::clock_t::now_ms ()\n{\n    const uint64_t tsc = rdtsc ();\n\n    //  If TSC is not supported, get precise time and chop off the microseconds.\n    if (!tsc) {\n#ifdef ZMQ_HAVE_WINDOWS\n        // Under Windows, now_us is not so reliable since QueryPerformanceCounter\n        // does not guarantee that it will use a hardware that offers a monotonic timer.\n        // So, lets use GetTickCount when GetTickCount64 is not available with an workaround\n        // to its 32 bit limitation.\n        return static_cast<uint64_t> ((*my_get_tick_count64) ());\n#else\n        return now_us () / usecs_per_msec;\n#endif\n    }\n\n    //  If TSC haven't jumped back (in case of migration to a different\n    //  CPU core) and if not too much time elapsed since last measurement,\n    //  we can return cached time value.\n    if (likely (tsc - _last_tsc <= (clock_precision / 2) && tsc >= _last_tsc))\n        return _last_time;\n\n    _last_tsc = tsc;\n#ifdef ZMQ_HAVE_WINDOWS\n    _last_time = static_cast<uint64_t> ((*my_get_tick_count64) ());\n#else\n    _last_time = now_us () / usecs_per_msec;\n#endif\n    return _last_time;\n}\n\nuint64_t zmq::clock_t::rdtsc ()\n{\n#if (defined _MSC_VER && (defined _M_IX86 || defined _M_X64))\n    return __rdtsc ();\n#elif defined(_MSC_VER) && defined(_M_ARM)   // NC => added for windows ARM\n    return __rdpmccntr64 ();\n#elif defined(_MSC_VER) && defined(_M_ARM64) // NC => added for windows ARM64\n    const int64_t pmccntr_el0 = (((3 & 1) << 14) |  // op0\n                                 ((3 & 7) << 11) |  // op1\n                                 ((9 & 15) << 7) |  // crn\n                                 ((13 & 15) << 3) | // crm\n                                 ((0 & 7) << 0));   // op2\n    return _ReadStatusReg (pmccntr_el0);\n#elif (defined(_WIN32) && defined(__GNUC__) && defined(__aarch64__))\n    uint64_t val;\n    __asm__ volatile (\"mrs %0, pmccntr_el0\" : \"=r\"(val));\n    return val;\n#elif (defined __GNUC__ && (defined __i386__ || defined __x86_64__))\n    uint32_t low, high;\n    __asm__ volatile (\"rdtsc\" : \"=a\"(low), \"=d\"(high));\n    return static_cast<uint64_t> (high) << 32 | low;\n#elif (defined __SUNPRO_CC && (__SUNPRO_CC >= 0x5100)                          \\\n       && (defined __i386 || defined __amd64 || defined __x86_64))\n    union\n    {\n        uint64_t u64val;\n        uint32_t u32val[2];\n    } tsc;\n    asm (\"rdtsc\" : \"=a\"(tsc.u32val[0]), \"=d\"(tsc.u32val[1]));\n    return tsc.u64val;\n#elif defined(__s390__)\n    uint64_t tsc;\n    asm (\"\\tstck\\t%0\\n\" : \"=Q\"(tsc) : : \"cc\");\n    return tsc;\n#else\n    struct timespec ts;\n#if defined ZMQ_HAVE_OSX                                                       \\\n  && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12\n    alt_clock_gettime (SYSTEM_CLOCK, &ts);\n#else\n    clock_gettime (CLOCK_MONOTONIC, &ts);\n#endif\n    return static_cast<uint64_t> (ts.tv_sec) * nsecs_per_usec * usecs_per_sec\n           + ts.tv_nsec;\n#endif\n}\n"
  },
  {
    "path": "src/clock.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_CLOCK_HPP_INCLUDED__\n#define __ZMQ_CLOCK_HPP_INCLUDED__\n\n#include \"macros.hpp\"\n#include \"stdint.hpp\"\n\n#if defined ZMQ_HAVE_OSX\n// TODO this is not required in this file, but condition_variable.hpp includes\n// clock.hpp to get these definitions\n#ifndef CLOCK_REALTIME\n#define CLOCK_REALTIME 0\n#endif\n#ifndef HAVE_CLOCK_GETTIME\n#define HAVE_CLOCK_GETTIME\n#endif\n\n#include <mach/clock.h>\n#include <mach/mach.h>\n#include <time.h>\n#include <sys/time.h>\n#endif\n\nnamespace zmq\n{\nclass clock_t\n{\n  public:\n    clock_t ();\n\n    //  CPU's timestamp counter. Returns 0 if it's not available.\n    static uint64_t rdtsc ();\n\n    //  High precision timestamp.\n    static uint64_t now_us ();\n\n    //  Low precision timestamp. In tight loops generating it can be\n    //  10 to 100 times faster than the high precision timestamp.\n    uint64_t now_ms ();\n\n  private:\n    //  TSC timestamp of when last time measurement was made.\n    uint64_t _last_tsc;\n\n    //  Physical time corresponding to the TSC above (in milliseconds).\n    uint64_t _last_time;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (clock_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/command.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_COMMAND_HPP_INCLUDED__\n#define __ZMQ_COMMAND_HPP_INCLUDED__\n\n#include <string>\n#include \"stdint.hpp\"\n#include \"endpoint.hpp\"\n#include \"platform.hpp\"\n\nnamespace zmq\n{\nclass object_t;\nclass own_t;\nstruct i_engine;\nclass pipe_t;\nclass socket_base_t;\n\n//  This structure defines the commands that can be sent between threads.\n\nstruct command_t\n{\n    //  Object to process the command.\n    zmq::object_t *destination;\n\n    enum type_t\n    {\n        stop,\n        plug,\n        own,\n        attach,\n        bind,\n        activate_read,\n        activate_write,\n        hiccup,\n        pipe_term,\n        pipe_term_ack,\n        pipe_hwm,\n        term_req,\n        term,\n        term_ack,\n        term_endpoint,\n        reap,\n        reaped,\n        inproc_connected,\n        conn_failed,\n        pipe_peer_stats,\n        pipe_stats_publish,\n        done\n    } type;\n\n    union args_t\n    {\n        //  Sent to I/O thread to let it know that it should\n        //  terminate itself.\n        struct\n        {\n        } stop;\n\n        //  Sent to I/O object to make it register with its I/O thread.\n        struct\n        {\n        } plug;\n\n        //  Sent to socket to let it know about the newly created object.\n        struct\n        {\n            zmq::own_t *object;\n        } own;\n\n        //  Attach the engine to the session. If engine is NULL, it informs\n        //  session that the connection have failed.\n        struct\n        {\n            struct i_engine *engine;\n        } attach;\n\n        //  Sent from session to socket to establish pipe(s) between them.\n        //  Caller have used inc_seqnum beforehand sending the command.\n        struct\n        {\n            zmq::pipe_t *pipe;\n        } bind;\n\n        //  Sent by pipe writer to inform dormant pipe reader that there\n        //  are messages in the pipe.\n        struct\n        {\n        } activate_read;\n\n        //  Sent by pipe reader to inform pipe writer about how many\n        //  messages it has read so far.\n        struct\n        {\n            uint64_t msgs_read;\n        } activate_write;\n\n        //  Sent by pipe reader to writer after creating a new inpipe.\n        //  The parameter is actually of type pipe_t::upipe_t, however,\n        //  its definition is private so we'll have to do with void*.\n        struct\n        {\n            void *pipe;\n        } hiccup;\n\n        //  Sent by pipe reader to pipe writer to ask it to terminate\n        //  its end of the pipe.\n        struct\n        {\n        } pipe_term;\n\n        //  Pipe writer acknowledges pipe_term command.\n        struct\n        {\n        } pipe_term_ack;\n\n        //  Sent by one of pipe to another part for modify hwm\n        struct\n        {\n            int inhwm;\n            int outhwm;\n        } pipe_hwm;\n\n        //  Sent by I/O object ot the socket to request the shutdown of\n        //  the I/O object.\n        struct\n        {\n            zmq::own_t *object;\n        } term_req;\n\n        //  Sent by socket to I/O object to start its shutdown.\n        struct\n        {\n            int linger;\n        } term;\n\n        //  Sent by I/O object to the socket to acknowledge it has\n        //  shut down.\n        struct\n        {\n        } term_ack;\n\n        //  Sent by session_base (I/O thread) to socket (application thread)\n        //  to ask to disconnect the endpoint.\n        struct\n        {\n            std::string *endpoint;\n        } term_endpoint;\n\n        //  Transfers the ownership of the closed socket\n        //  to the reaper thread.\n        struct\n        {\n            zmq::socket_base_t *socket;\n        } reap;\n\n        //  Closed socket notifies the reaper that it's already deallocated.\n        struct\n        {\n        } reaped;\n\n        //  Send application-side pipe count and ask to send monitor event\n        struct\n        {\n            uint64_t queue_count;\n            zmq::own_t *socket_base;\n            endpoint_uri_pair_t *endpoint_pair;\n        } pipe_peer_stats;\n\n        //  Collate application thread and I/O thread pipe counts and endpoints\n        //  and send as event\n        struct\n        {\n            uint64_t outbound_queue_count;\n            uint64_t inbound_queue_count;\n            endpoint_uri_pair_t *endpoint_pair;\n        } pipe_stats_publish;\n\n        //  Sent by reaper thread to the term thread when all the sockets\n        //  are successfully deallocated.\n        struct\n        {\n        } done;\n\n    } args;\n#ifdef _MSC_VER\n};\n#else\n}\n#ifdef HAVE_POSIX_MEMALIGN\n__attribute__ ((aligned (ZMQ_CACHELINE_SIZE)))\n#endif\n;\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "src/compat.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_COMPAT_HPP_INCLUDED__\n#define __ZMQ_COMPAT_HPP_INCLUDED__\n\n#include \"precompiled.hpp\"\n#include <string.h>\n\n#ifdef ZMQ_HAVE_WINDOWS\n#define strcasecmp _stricmp\n#define strtok_r strtok_s\n#else\n#ifndef ZMQ_HAVE_STRLCPY\n#ifdef ZMQ_HAVE_LIBBSD\n#include <bsd/string.h>\n#else\nstatic inline size_t\nstrlcpy (char *dest_, const char *src_, const size_t dest_size_)\n{\n    size_t remain = dest_size_;\n    for (; remain && *src_; --remain, ++src_, ++dest_) {\n        *dest_ = *src_;\n    }\n    return dest_size_ - remain;\n}\n#endif\n#endif\ntemplate <size_t size>\nstatic inline int strcpy_s (char (&dest_)[size], const char *const src_)\n{\n    const size_t res = strlcpy (dest_, src_, size);\n    return res >= size ? ERANGE : 0;\n}\n#endif\n\n#ifndef HAVE_STRNLEN\nstatic inline size_t strnlen (const char *s, size_t len)\n{\n    for (size_t i = 0; i < len; i++) {\n        if (s[i] == '\\0')\n            return i + 1;\n    }\n\n    return len;\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/condition_variable.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_CONDITON_VARIABLE_HPP_INCLUDED__\n#define __ZMQ_CONDITON_VARIABLE_HPP_INCLUDED__\n\n#include \"err.hpp\"\n#include \"mutex.hpp\"\n\n//  Condition variable class encapsulates OS mutex in a platform-independent way.\n\n#if defined(ZMQ_USE_CV_IMPL_NONE)\n\nnamespace zmq\n{\nclass condition_variable_t\n{\n  public:\n    inline condition_variable_t () { zmq_assert (false); }\n\n    inline int wait (mutex_t *mutex_, int timeout_)\n    {\n        zmq_assert (false);\n        return -1;\n    }\n\n    inline void broadcast () { zmq_assert (false); }\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)\n};\n}\n\n#elif defined(ZMQ_USE_CV_IMPL_WIN32API)\n\n#include \"windows.hpp\"\n\nnamespace zmq\n{\nclass condition_variable_t\n{\n  public:\n    inline condition_variable_t () { InitializeConditionVariable (&_cv); }\n\n    inline int wait (mutex_t *mutex_, int timeout_)\n    {\n        int rc = SleepConditionVariableCS (&_cv, mutex_->get_cs (), timeout_);\n\n        if (rc != 0)\n            return 0;\n\n        rc = GetLastError ();\n\n        if (rc != ERROR_TIMEOUT)\n            win_assert (rc);\n\n        errno = EAGAIN;\n        return -1;\n    }\n\n    inline void broadcast () { WakeAllConditionVariable (&_cv); }\n\n  private:\n    CONDITION_VARIABLE _cv;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)\n};\n}\n\n#elif defined(ZMQ_USE_CV_IMPL_STL11)\n\n#include <condition_variable>\n\nnamespace zmq\n{\nclass condition_variable_t\n{\n  public:\n    condition_variable_t () ZMQ_DEFAULT;\n\n    int wait (mutex_t *mutex_, int timeout_)\n    {\n        // this assumes that the mutex mutex_ has been locked by the caller\n        int res = 0;\n        if (timeout_ == -1) {\n            _cv.wait (\n              *mutex_); // unlock mtx and wait cv.notify_all(), lock mtx after cv.notify_all()\n        } else if (_cv.wait_for (*mutex_, std::chrono::milliseconds (timeout_))\n                   == std::cv_status::timeout) {\n            // time expired\n            errno = EAGAIN;\n            res = -1;\n        }\n        return res;\n    }\n\n    void broadcast ()\n    {\n        // this assumes that the mutex associated with _cv has been locked by the caller\n        _cv.notify_all ();\n    }\n\n  private:\n    std::condition_variable_any _cv;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)\n};\n}\n\n#elif defined(ZMQ_USE_CV_IMPL_VXWORKS)\n\n#include <sysLib.h>\n\nnamespace zmq\n{\nclass condition_variable_t\n{\n  public:\n    inline condition_variable_t () ZMQ_DEFAULT;\n\n    inline ~condition_variable_t ()\n    {\n        scoped_lock_t l (_listenersMutex);\n        for (size_t i = 0; i < _listeners.size (); i++) {\n            semDelete (_listeners[i]);\n        }\n    }\n\n    inline int wait (mutex_t *mutex_, int timeout_)\n    {\n        //Atomically releases lock, blocks the current executing thread,\n        //and adds it to the list of threads waiting on *this. The thread\n        //will be unblocked when broadcast() is executed.\n        //It may also be unblocked spuriously. When unblocked, regardless\n        //of the reason, lock is reacquired and wait exits.\n\n        SEM_ID sem = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);\n        {\n            scoped_lock_t l (_listenersMutex);\n            _listeners.push_back (sem);\n        }\n        mutex_->unlock ();\n\n        int rc;\n        if (timeout_ < 0)\n            rc = semTake (sem, WAIT_FOREVER);\n        else {\n            int ticksPerSec = sysClkRateGet ();\n            int timeoutTicks = (timeout_ * ticksPerSec) / 1000 + 1;\n            rc = semTake (sem, timeoutTicks);\n        }\n\n        {\n            scoped_lock_t l (_listenersMutex);\n            // remove sem from listeners\n            for (size_t i = 0; i < _listeners.size (); i++) {\n                if (_listeners[i] == sem) {\n                    _listeners.erase (_listeners.begin () + i);\n                    break;\n                }\n            }\n            semDelete (sem);\n        }\n        mutex_->lock ();\n\n        if (rc == 0)\n            return 0;\n\n        if (rc == S_objLib_OBJ_TIMEOUT) {\n            errno = EAGAIN;\n            return -1;\n        }\n\n        return -1;\n    }\n\n    inline void broadcast ()\n    {\n        scoped_lock_t l (_listenersMutex);\n        for (size_t i = 0; i < _listeners.size (); i++) {\n            semGive (_listeners[i]);\n        }\n    }\n\n  private:\n    mutex_t _listenersMutex;\n    std::vector<SEM_ID> _listeners;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)\n};\n}\n\n#elif defined(ZMQ_USE_CV_IMPL_PTHREADS)\n\n#include <pthread.h>\n\n#if defined(__ANDROID_API__) && __ANDROID_API__ < 21\n#define ANDROID_LEGACY\nextern \"C\" int pthread_cond_timedwait_monotonic_np (pthread_cond_t *,\n                                                    pthread_mutex_t *,\n                                                    const struct timespec *);\n#endif\n\nnamespace zmq\n{\nclass condition_variable_t\n{\n  public:\n    inline condition_variable_t ()\n    {\n        pthread_condattr_t attr;\n        pthread_condattr_init (&attr);\n#if !defined(ZMQ_HAVE_OSX) && !defined(ANDROID_LEGACY)\n        pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);\n#endif\n        int rc = pthread_cond_init (&_cond, &attr);\n        posix_assert (rc);\n    }\n\n    inline ~condition_variable_t ()\n    {\n        int rc = pthread_cond_destroy (&_cond);\n        posix_assert (rc);\n    }\n\n    inline int wait (mutex_t *mutex_, int timeout_)\n    {\n        int rc;\n\n        if (timeout_ != -1) {\n            struct timespec timeout;\n\n#ifdef ZMQ_HAVE_OSX\n            timeout.tv_sec = 0;\n            timeout.tv_nsec = 0;\n#else\n            rc = clock_gettime (CLOCK_MONOTONIC, &timeout);\n            posix_assert (rc);\n#endif\n\n            timeout.tv_sec += timeout_ / 1000;\n            timeout.tv_nsec += (timeout_ % 1000) * 1000000;\n\n            if (timeout.tv_nsec >= 1000000000) {\n                timeout.tv_sec++;\n                timeout.tv_nsec -= 1000000000;\n            }\n#ifdef ZMQ_HAVE_OSX\n            rc = pthread_cond_timedwait_relative_np (\n              &_cond, mutex_->get_mutex (), &timeout);\n#elif defined(ANDROID_LEGACY)\n            rc = pthread_cond_timedwait_monotonic_np (\n              &_cond, mutex_->get_mutex (), &timeout);\n#else\n            rc =\n              pthread_cond_timedwait (&_cond, mutex_->get_mutex (), &timeout);\n#endif\n        } else\n            rc = pthread_cond_wait (&_cond, mutex_->get_mutex ());\n\n        if (rc == 0)\n            return 0;\n\n        if (rc == ETIMEDOUT) {\n            errno = EAGAIN;\n            return -1;\n        }\n\n        posix_assert (rc);\n        return -1;\n    }\n\n    inline void broadcast ()\n    {\n        int rc = pthread_cond_broadcast (&_cond);\n        posix_assert (rc);\n    }\n\n  private:\n    pthread_cond_t _cond;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/config.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_CONFIG_HPP_INCLUDED__\n#define __ZMQ_CONFIG_HPP_INCLUDED__\n\nnamespace zmq\n{\n//  Compile-time settings.\n\nenum\n{\n    //  Number of new messages in message pipe needed to trigger new memory\n    //  allocation. Setting this parameter to 256 decreases the impact of\n    //  memory allocation by approximately 99.6%\n    message_pipe_granularity = 256,\n\n    //  Commands in pipe per allocation event.\n    command_pipe_granularity = 16,\n\n    //  Determines how often does socket poll for new commands when it\n    //  still has unprocessed messages to handle. Thus, if it is set to 100,\n    //  socket will process 100 inbound messages before doing the poll.\n    //  If there are no unprocessed messages available, poll is done\n    //  immediately. Decreasing the value trades overall latency for more\n    //  real-time behaviour (less latency peaks).\n    inbound_poll_rate = 100,\n\n    //  Maximal delta between high and low watermark.\n    max_wm_delta = 1024,\n\n    //  Maximum number of events the I/O thread can process in one go.\n    max_io_events = 256,\n\n    //  Maximal batch size of packets forwarded by a ZMQ proxy.\n    //  Increasing this value improves throughput at the expense of\n    //  latency and fairness.\n    proxy_burst_size = 1000,\n\n    //  Maximal delay to process command in API thread (in CPU ticks).\n    //  3,000,000 ticks equals to 1 - 2 milliseconds on current CPUs.\n    //  Note that delay is only applied when there is continuous stream of\n    //  messages to process. If not so, commands are processed immediately.\n    max_command_delay = 3000000,\n\n    //  Low-precision clock precision in CPU ticks. 1ms. Value of 1000000\n    //  should be OK for CPU frequencies above 1GHz. If should work\n    //  reasonably well for CPU frequencies above 500MHz. For lower CPU\n    //  frequencies you may consider lowering this value to get best\n    //  possible latencies.\n    clock_precision = 1000000,\n\n    //  On some OSes the signaler has to be emulated using a TCP\n    //  connection. In such cases following port is used.\n    //  If 0, it lets the OS choose a free port without requiring use of a\n    //  global mutex. The original implementation of a Windows signaler\n    //  socket used port 5905 instead of letting the OS choose a free port.\n    //  https://github.com/zeromq/libzmq/issues/1542\n    signaler_port = 0\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ctx.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#ifndef ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#endif\n\n#include <limits>\n#include <climits>\n#include <new>\n#include <sstream>\n#include <string.h>\n\n#include \"ctx.hpp\"\n#include \"socket_base.hpp\"\n#include \"io_thread.hpp\"\n#include \"reaper.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n#include \"random.hpp\"\n\n#ifdef ZMQ_HAVE_VMCI\n#include <vmci_sockets.h>\n#endif\n\n#ifdef ZMQ_HAVE_VSOCK\n#include <sys/socket.h>\n#endif\n\n#ifdef ZMQ_USE_NSS\n#include <nss.h>\n#endif\n\n#ifdef ZMQ_USE_GNUTLS\n#include <gnutls/gnutls.h>\n#endif\n\n#define ZMQ_CTX_TAG_VALUE_GOOD 0xabadcafe\n#define ZMQ_CTX_TAG_VALUE_BAD 0xdeadbeef\n\nstatic int clipped_maxsocket (int max_requested_)\n{\n    if (max_requested_ >= zmq::poller_t::max_fds ()\n        && zmq::poller_t::max_fds () != -1)\n        // -1 because we need room for the reaper mailbox.\n        max_requested_ = zmq::poller_t::max_fds () - 1;\n\n    return max_requested_;\n}\n\nzmq::ctx_t::ctx_t () :\n    _tag (ZMQ_CTX_TAG_VALUE_GOOD),\n    _starting (true),\n    _terminating (false),\n    _reaper (NULL),\n    _max_sockets (clipped_maxsocket (ZMQ_MAX_SOCKETS_DFLT)),\n    _max_msgsz (INT_MAX),\n    _io_thread_count (ZMQ_IO_THREADS_DFLT),\n    _blocky (true),\n    _ipv6 (false),\n    _zero_copy (true)\n{\n#ifdef HAVE_FORK\n    _pid = getpid ();\n#endif\n#ifdef ZMQ_HAVE_VMCI\n    _vmci_fd = -1;\n    _vmci_family = -1;\n#endif\n\n    //  Initialise crypto library, if needed.\n    zmq::random_open ();\n\n#ifdef ZMQ_USE_NSS\n    NSS_NoDB_Init (NULL);\n#endif\n\n#ifdef ZMQ_USE_GNUTLS\n    gnutls_global_init ();\n#endif\n}\n\nbool zmq::ctx_t::check_tag () const\n{\n    return _tag == ZMQ_CTX_TAG_VALUE_GOOD;\n}\n\nzmq::ctx_t::~ctx_t ()\n{\n    //  Check that there are no remaining _sockets.\n    zmq_assert (_sockets.empty ());\n\n    //  Ask I/O threads to terminate. If stop signal wasn't sent to I/O\n    //  thread subsequent invocation of destructor would hang-up.\n    const io_threads_t::size_type io_threads_size = _io_threads.size ();\n    for (io_threads_t::size_type i = 0; i != io_threads_size; i++) {\n        _io_threads[i]->stop ();\n    }\n\n    //  Wait till I/O threads actually terminate.\n    for (io_threads_t::size_type i = 0; i != io_threads_size; i++) {\n        LIBZMQ_DELETE (_io_threads[i]);\n    }\n\n    //  Deallocate the reaper thread object.\n    LIBZMQ_DELETE (_reaper);\n\n    //  The mailboxes in _slots themselves were deallocated with their\n    //  corresponding io_thread/socket objects.\n\n    //  De-initialise crypto library, if needed.\n    zmq::random_close ();\n\n#ifdef ZMQ_USE_NSS\n    NSS_Shutdown ();\n#endif\n\n#ifdef ZMQ_USE_GNUTLS\n    gnutls_global_deinit ();\n#endif\n\n    //  Remove the tag, so that the object is considered dead.\n    _tag = ZMQ_CTX_TAG_VALUE_BAD;\n}\n\nbool zmq::ctx_t::valid () const\n{\n    return _term_mailbox.valid ();\n}\n\nint zmq::ctx_t::terminate ()\n{\n    _slot_sync.lock ();\n\n    const bool save_terminating = _terminating;\n    _terminating = false;\n\n    // Connect up any pending inproc connections, otherwise we will hang\n    pending_connections_t copy = _pending_connections;\n    for (pending_connections_t::iterator p = copy.begin (), end = copy.end ();\n         p != end; ++p) {\n        zmq::socket_base_t *s = create_socket (ZMQ_PAIR);\n        // create_socket might fail eg: out of memory/sockets limit reached\n        zmq_assert (s);\n        s->bind (p->first.c_str ());\n        s->close ();\n    }\n    _terminating = save_terminating;\n\n    if (!_starting) {\n#ifdef HAVE_FORK\n        if (_pid != getpid ()) {\n            // we are a forked child process. Close all file descriptors\n            // inherited from the parent.\n            for (sockets_t::size_type i = 0, size = _sockets.size (); i != size;\n                 i++) {\n                _sockets[i]->get_mailbox ()->forked ();\n            }\n            _term_mailbox.forked ();\n        }\n#endif\n\n        //  Check whether termination was already underway, but interrupted and now\n        //  restarted.\n        const bool restarted = _terminating;\n        _terminating = true;\n\n        //  First attempt to terminate the context.\n        if (!restarted) {\n            //  First send stop command to sockets so that any blocking calls\n            //  can be interrupted. If there are no sockets we can ask reaper\n            //  thread to stop.\n            for (sockets_t::size_type i = 0, size = _sockets.size (); i != size;\n                 i++) {\n                _sockets[i]->stop ();\n            }\n            if (_sockets.empty ())\n                _reaper->stop ();\n        }\n        _slot_sync.unlock ();\n\n        //  Wait till reaper thread closes all the sockets.\n        command_t cmd;\n        const int rc = _term_mailbox.recv (&cmd, -1);\n        if (rc == -1 && errno == EINTR)\n            return -1;\n        errno_assert (rc == 0);\n        zmq_assert (cmd.type == command_t::done);\n        _slot_sync.lock ();\n        zmq_assert (_sockets.empty ());\n    }\n    _slot_sync.unlock ();\n\n#ifdef ZMQ_HAVE_VMCI\n    _vmci_sync.lock ();\n\n    VMCISock_ReleaseAFValueFd (_vmci_fd);\n    _vmci_family = -1;\n    _vmci_fd = -1;\n\n    _vmci_sync.unlock ();\n#endif\n\n    //  Deallocate the resources.\n    delete this;\n\n    return 0;\n}\n\nint zmq::ctx_t::shutdown ()\n{\n    scoped_lock_t locker (_slot_sync);\n\n    if (!_terminating) {\n        _terminating = true;\n\n        if (!_starting) {\n            //  Send stop command to sockets so that any blocking calls\n            //  can be interrupted. If there are no sockets we can ask reaper\n            //  thread to stop.\n            for (sockets_t::size_type i = 0, size = _sockets.size (); i != size;\n                 i++) {\n                _sockets[i]->stop ();\n            }\n            if (_sockets.empty ())\n                _reaper->stop ();\n        }\n    }\n\n    return 0;\n}\n\nint zmq::ctx_t::set (int option_, const void *optval_, size_t optvallen_)\n{\n    const bool is_int = (optvallen_ == sizeof (int));\n    int value = 0;\n    if (is_int)\n        memcpy (&value, optval_, sizeof (int));\n\n    switch (option_) {\n        case ZMQ_MAX_SOCKETS:\n            if (is_int && value >= 1 && value == clipped_maxsocket (value)) {\n                scoped_lock_t locker (_opt_sync);\n                _max_sockets = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_IO_THREADS:\n            if (is_int && value >= 0) {\n                scoped_lock_t locker (_opt_sync);\n                _io_thread_count = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_IPV6:\n            if (is_int && value >= 0) {\n                scoped_lock_t locker (_opt_sync);\n                _ipv6 = (value != 0);\n                return 0;\n            }\n            break;\n\n        case ZMQ_BLOCKY:\n            if (is_int && value >= 0) {\n                scoped_lock_t locker (_opt_sync);\n                _blocky = (value != 0);\n                return 0;\n            }\n            break;\n\n        case ZMQ_MAX_MSGSZ:\n            if (is_int && value >= 0) {\n                scoped_lock_t locker (_opt_sync);\n                _max_msgsz = value < INT_MAX ? value : INT_MAX;\n                return 0;\n            }\n            break;\n\n        case ZMQ_ZERO_COPY_RECV:\n            if (is_int && value >= 0) {\n                scoped_lock_t locker (_opt_sync);\n                _zero_copy = (value != 0);\n                return 0;\n            }\n            break;\n\n        default: {\n            return thread_ctx_t::set (option_, optval_, optvallen_);\n        }\n    }\n\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::ctx_t::get (int option_, void *optval_, const size_t *optvallen_)\n{\n    const bool is_int = (*optvallen_ == sizeof (int));\n    int *value = static_cast<int *> (optval_);\n\n    switch (option_) {\n        case ZMQ_MAX_SOCKETS:\n            if (is_int) {\n                scoped_lock_t locker (_opt_sync);\n                *value = _max_sockets;\n                return 0;\n            }\n            break;\n\n        case ZMQ_SOCKET_LIMIT:\n            if (is_int) {\n                *value = clipped_maxsocket (65535);\n                return 0;\n            }\n            break;\n\n        case ZMQ_IO_THREADS:\n            if (is_int) {\n                scoped_lock_t locker (_opt_sync);\n                *value = _io_thread_count;\n                return 0;\n            }\n            break;\n\n        case ZMQ_IPV6:\n            if (is_int) {\n                scoped_lock_t locker (_opt_sync);\n                *value = _ipv6;\n                return 0;\n            }\n            break;\n\n        case ZMQ_BLOCKY:\n            if (is_int) {\n                scoped_lock_t locker (_opt_sync);\n                *value = _blocky;\n                return 0;\n            }\n            break;\n\n        case ZMQ_MAX_MSGSZ:\n            if (is_int) {\n                scoped_lock_t locker (_opt_sync);\n                *value = _max_msgsz;\n                return 0;\n            }\n            break;\n\n        case ZMQ_MSG_T_SIZE:\n            if (is_int) {\n                scoped_lock_t locker (_opt_sync);\n                *value = sizeof (zmq_msg_t);\n                return 0;\n            }\n            break;\n\n        case ZMQ_ZERO_COPY_RECV:\n            if (is_int) {\n                scoped_lock_t locker (_opt_sync);\n                *value = _zero_copy;\n                return 0;\n            }\n            break;\n\n        default: {\n            return thread_ctx_t::get (option_, optval_, optvallen_);\n        }\n    }\n\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::ctx_t::get (int option_)\n{\n    int optval = 0;\n    size_t optvallen = sizeof (int);\n\n    if (get (option_, &optval, &optvallen) == 0)\n        return optval;\n\n    errno = EINVAL;\n    return -1;\n}\n\nbool zmq::ctx_t::start ()\n{\n    //  Initialise the array of mailboxes. Additional two slots are for\n    //  zmq_ctx_term thread and reaper thread.\n    _opt_sync.lock ();\n    const int term_and_reaper_threads_count = 2;\n    const int mazmq = _max_sockets;\n    const int ios = _io_thread_count;\n    _opt_sync.unlock ();\n    const int slot_count = mazmq + ios + term_and_reaper_threads_count;\n    try {\n        _slots.reserve (slot_count);\n        _empty_slots.reserve (slot_count - term_and_reaper_threads_count);\n    }\n    catch (const std::bad_alloc &) {\n        errno = ENOMEM;\n        return false;\n    }\n    _slots.resize (term_and_reaper_threads_count);\n\n    //  Initialise the infrastructure for zmq_ctx_term thread.\n    _slots[term_tid] = &_term_mailbox;\n\n    //  Create the reaper thread.\n    _reaper = new (std::nothrow) reaper_t (this, reaper_tid);\n    if (!_reaper) {\n        errno = ENOMEM;\n        goto fail_cleanup_slots;\n    }\n    if (!_reaper->get_mailbox ()->valid ())\n        goto fail_cleanup_reaper;\n    _slots[reaper_tid] = _reaper->get_mailbox ();\n    _reaper->start ();\n\n    //  Create I/O thread objects and launch them.\n    _slots.resize (slot_count, NULL);\n\n    for (int i = term_and_reaper_threads_count;\n         i != ios + term_and_reaper_threads_count; i++) {\n        io_thread_t *io_thread = new (std::nothrow) io_thread_t (this, i);\n        if (!io_thread) {\n            errno = ENOMEM;\n            goto fail_cleanup_reaper;\n        }\n        if (!io_thread->get_mailbox ()->valid ()) {\n            delete io_thread;\n            goto fail_cleanup_reaper;\n        }\n        _io_threads.push_back (io_thread);\n        _slots[i] = io_thread->get_mailbox ();\n        io_thread->start ();\n    }\n\n    //  In the unused part of the slot array, create a list of empty slots.\n    for (int32_t i = static_cast<int32_t> (_slots.size ()) - 1;\n         i >= static_cast<int32_t> (ios) + term_and_reaper_threads_count; i--) {\n        _empty_slots.push_back (i);\n    }\n\n    _starting = false;\n    return true;\n\nfail_cleanup_reaper:\n    _reaper->stop ();\n    delete _reaper;\n    _reaper = NULL;\n\nfail_cleanup_slots:\n    _slots.clear ();\n    return false;\n}\n\nzmq::socket_base_t *zmq::ctx_t::create_socket (int type_)\n{\n    scoped_lock_t locker (_slot_sync);\n\n    //  Once zmq_ctx_term() or zmq_ctx_shutdown() was called, we can't create\n    //  new sockets.\n    if (_terminating) {\n        errno = ETERM;\n        return NULL;\n    }\n\n    if (unlikely (_starting)) {\n        if (!start ())\n            return NULL;\n    }\n\n    //  If max_sockets limit was reached, return error.\n    if (_empty_slots.empty ()) {\n        errno = EMFILE;\n        return NULL;\n    }\n\n    //  Choose a slot for the socket.\n    const uint32_t slot = _empty_slots.back ();\n    _empty_slots.pop_back ();\n\n    //  Generate new unique socket ID.\n    const int sid = (static_cast<int> (max_socket_id.add (1))) + 1;\n\n    //  Create the socket and register its mailbox.\n    socket_base_t *s = socket_base_t::create (type_, this, slot, sid);\n    if (!s) {\n        _empty_slots.push_back (slot);\n        return NULL;\n    }\n    _sockets.push_back (s);\n    _slots[slot] = s->get_mailbox ();\n\n    return s;\n}\n\nvoid zmq::ctx_t::destroy_socket (class socket_base_t *socket_)\n{\n    scoped_lock_t locker (_slot_sync);\n\n    //  Free the associated thread slot.\n    const uint32_t tid = socket_->get_tid ();\n    _empty_slots.push_back (tid);\n    _slots[tid] = NULL;\n\n    //  Remove the socket from the list of sockets.\n    _sockets.erase (socket_);\n\n    //  If zmq_ctx_term() was already called and there are no more socket\n    //  we can ask reaper thread to terminate.\n    if (_terminating && _sockets.empty ())\n        _reaper->stop ();\n}\n\nzmq::object_t *zmq::ctx_t::get_reaper () const\n{\n    return _reaper;\n}\n\nzmq::thread_ctx_t::thread_ctx_t () :\n    _thread_priority (ZMQ_THREAD_PRIORITY_DFLT),\n    _thread_sched_policy (ZMQ_THREAD_SCHED_POLICY_DFLT)\n{\n}\n\nvoid zmq::thread_ctx_t::start_thread (thread_t &thread_,\n                                      thread_fn *tfn_,\n                                      void *arg_,\n                                      const char *name_) const\n{\n    thread_.setSchedulingParameters (_thread_priority, _thread_sched_policy,\n                                     _thread_affinity_cpus);\n\n    char namebuf[16] = \"\";\n    snprintf (namebuf, sizeof (namebuf), \"%s%sZMQbg%s%s\",\n              _thread_name_prefix.empty () ? \"\" : _thread_name_prefix.c_str (),\n              _thread_name_prefix.empty () ? \"\" : \"/\", name_ ? \"/\" : \"\",\n              name_ ? name_ : \"\");\n    thread_.start (tfn_, arg_, namebuf);\n}\n\nint zmq::thread_ctx_t::set (int option_, const void *optval_, size_t optvallen_)\n{\n    const bool is_int = (optvallen_ == sizeof (int));\n    int value = 0;\n    if (is_int)\n        memcpy (&value, optval_, sizeof (int));\n\n    switch (option_) {\n        case ZMQ_THREAD_SCHED_POLICY:\n            if (is_int && value >= 0) {\n                scoped_lock_t locker (_opt_sync);\n                _thread_sched_policy = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_THREAD_AFFINITY_CPU_ADD:\n            if (is_int && value >= 0) {\n                scoped_lock_t locker (_opt_sync);\n                _thread_affinity_cpus.insert (value);\n                return 0;\n            }\n            break;\n\n        case ZMQ_THREAD_AFFINITY_CPU_REMOVE:\n            if (is_int && value >= 0) {\n                scoped_lock_t locker (_opt_sync);\n                if (0 == _thread_affinity_cpus.erase (value)) {\n                    errno = EINVAL;\n                    return -1;\n                }\n                return 0;\n            }\n            break;\n\n        case ZMQ_THREAD_PRIORITY:\n            if (is_int && value >= 0) {\n                scoped_lock_t locker (_opt_sync);\n                _thread_priority = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_THREAD_NAME_PREFIX:\n            // start_thread() allows max 16 chars for thread name\n            if (is_int) {\n                std::ostringstream s;\n                s << value;\n                scoped_lock_t locker (_opt_sync);\n                _thread_name_prefix = s.str ();\n                return 0;\n            } else if (optvallen_ > 0 && optvallen_ <= 16) {\n                scoped_lock_t locker (_opt_sync);\n                _thread_name_prefix.assign (static_cast<const char *> (optval_),\n                                            optvallen_);\n                return 0;\n            }\n            break;\n    }\n\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::thread_ctx_t::get (int option_,\n                            void *optval_,\n                            const size_t *optvallen_)\n{\n    const bool is_int = (*optvallen_ == sizeof (int));\n    int *value = static_cast<int *> (optval_);\n\n    switch (option_) {\n        case ZMQ_THREAD_SCHED_POLICY:\n            if (is_int) {\n                scoped_lock_t locker (_opt_sync);\n                *value = _thread_sched_policy;\n                return 0;\n            }\n            break;\n\n        case ZMQ_THREAD_NAME_PREFIX:\n            if (is_int) {\n                scoped_lock_t locker (_opt_sync);\n                *value = atoi (_thread_name_prefix.c_str ());\n                return 0;\n            } else if (*optvallen_ >= _thread_name_prefix.size ()) {\n                scoped_lock_t locker (_opt_sync);\n                memcpy (optval_, _thread_name_prefix.data (),\n                        _thread_name_prefix.size ());\n                return 0;\n            }\n            break;\n    }\n\n    errno = EINVAL;\n    return -1;\n}\n\nvoid zmq::ctx_t::send_command (uint32_t tid_, const command_t &command_)\n{\n    _slots[tid_]->send (command_);\n}\n\nzmq::io_thread_t *zmq::ctx_t::choose_io_thread (uint64_t affinity_)\n{\n    if (_io_threads.empty ())\n        return NULL;\n\n    //  Find the I/O thread with minimum load.\n    int min_load = -1;\n    io_thread_t *selected_io_thread = NULL;\n    for (io_threads_t::size_type i = 0, size = _io_threads.size (); i != size;\n         i++) {\n        if (!affinity_ || (affinity_ & (uint64_t (1) << i))) {\n            const int load = _io_threads[i]->get_load ();\n            if (selected_io_thread == NULL || load < min_load) {\n                min_load = load;\n                selected_io_thread = _io_threads[i];\n            }\n        }\n    }\n    return selected_io_thread;\n}\n\nint zmq::ctx_t::register_endpoint (const char *addr_,\n                                   const endpoint_t &endpoint_)\n{\n    scoped_lock_t locker (_endpoints_sync);\n\n    const bool inserted =\n      _endpoints.ZMQ_MAP_INSERT_OR_EMPLACE (std::string (addr_), endpoint_)\n        .second;\n    if (!inserted) {\n        errno = EADDRINUSE;\n        return -1;\n    }\n    return 0;\n}\n\nint zmq::ctx_t::unregister_endpoint (const std::string &addr_,\n                                     const socket_base_t *const socket_)\n{\n    scoped_lock_t locker (_endpoints_sync);\n\n    const endpoints_t::iterator it = _endpoints.find (addr_);\n    if (it == _endpoints.end () || it->second.socket != socket_) {\n        errno = ENOENT;\n        return -1;\n    }\n\n    //  Remove endpoint.\n    _endpoints.erase (it);\n\n    return 0;\n}\n\nvoid zmq::ctx_t::unregister_endpoints (const socket_base_t *const socket_)\n{\n    scoped_lock_t locker (_endpoints_sync);\n\n    for (endpoints_t::iterator it = _endpoints.begin (),\n                               end = _endpoints.end ();\n         it != end;) {\n        if (it->second.socket == socket_)\n#if __cplusplus >= 201103L || (defined _MSC_VER && _MSC_VER >= 1700)\n            it = _endpoints.erase (it);\n#else\n            _endpoints.erase (it++);\n#endif\n        else\n            ++it;\n    }\n}\n\nzmq::endpoint_t zmq::ctx_t::find_endpoint (const char *addr_)\n{\n    scoped_lock_t locker (_endpoints_sync);\n\n    endpoints_t::iterator it = _endpoints.find (addr_);\n    if (it == _endpoints.end ()) {\n        errno = ECONNREFUSED;\n        endpoint_t empty = {NULL, options_t ()};\n        return empty;\n    }\n    endpoint_t endpoint = it->second;\n\n    //  Increment the command sequence number of the peer so that it won't\n    //  get deallocated until \"bind\" command is issued by the caller.\n    //  The subsequent 'bind' has to be called with inc_seqnum parameter\n    //  set to false, so that the seqnum isn't incremented twice.\n    endpoint.socket->inc_seqnum ();\n\n    return endpoint;\n}\n\nvoid zmq::ctx_t::pend_connection (const std::string &addr_,\n                                  const endpoint_t &endpoint_,\n                                  pipe_t **pipes_)\n{\n    scoped_lock_t locker (_endpoints_sync);\n\n    const pending_connection_t pending_connection = {endpoint_, pipes_[0],\n                                                     pipes_[1]};\n\n    const endpoints_t::iterator it = _endpoints.find (addr_);\n    if (it == _endpoints.end ()) {\n        //  Still no bind.\n        endpoint_.socket->inc_seqnum ();\n        _pending_connections.ZMQ_MAP_INSERT_OR_EMPLACE (addr_,\n                                                        pending_connection);\n    } else {\n        //  Bind has happened in the mean time, connect directly\n        connect_inproc_sockets (it->second.socket, it->second.options,\n                                pending_connection, connect_side);\n    }\n}\n\nvoid zmq::ctx_t::connect_pending (const char *addr_,\n                                  zmq::socket_base_t *bind_socket_)\n{\n    scoped_lock_t locker (_endpoints_sync);\n\n    const std::pair<pending_connections_t::iterator,\n                    pending_connections_t::iterator>\n      pending = _pending_connections.equal_range (addr_);\n    for (pending_connections_t::iterator p = pending.first; p != pending.second;\n         ++p)\n        connect_inproc_sockets (bind_socket_, _endpoints[addr_].options,\n                                p->second, bind_side);\n\n    _pending_connections.erase (pending.first, pending.second);\n}\n\nvoid zmq::ctx_t::connect_inproc_sockets (\n  zmq::socket_base_t *bind_socket_,\n  const options_t &bind_options_,\n  const pending_connection_t &pending_connection_,\n  side side_)\n{\n    bind_socket_->inc_seqnum ();\n    pending_connection_.bind_pipe->set_tid (bind_socket_->get_tid ());\n\n    if (!bind_options_.recv_routing_id) {\n        msg_t msg;\n        const bool ok = pending_connection_.bind_pipe->read (&msg);\n        zmq_assert (ok);\n        const int rc = msg.close ();\n        errno_assert (rc == 0);\n    }\n\n    if (!get_effective_conflate_option (pending_connection_.endpoint.options)) {\n        pending_connection_.connect_pipe->set_hwms_boost (bind_options_.sndhwm,\n                                                          bind_options_.rcvhwm);\n        pending_connection_.bind_pipe->set_hwms_boost (\n          pending_connection_.endpoint.options.sndhwm,\n          pending_connection_.endpoint.options.rcvhwm);\n\n        pending_connection_.connect_pipe->set_hwms (\n          pending_connection_.endpoint.options.rcvhwm,\n          pending_connection_.endpoint.options.sndhwm);\n        pending_connection_.bind_pipe->set_hwms (bind_options_.rcvhwm,\n                                                 bind_options_.sndhwm);\n    } else {\n        pending_connection_.connect_pipe->set_hwms (-1, -1);\n        pending_connection_.bind_pipe->set_hwms (-1, -1);\n    }\n\n#ifdef ZMQ_BUILD_DRAFT_API\n    if (bind_options_.can_recv_disconnect_msg\n        && !bind_options_.disconnect_msg.empty ())\n        pending_connection_.connect_pipe->set_disconnect_msg (\n          bind_options_.disconnect_msg);\n#endif\n\n    if (side_ == bind_side) {\n        command_t cmd;\n        cmd.type = command_t::bind;\n        cmd.args.bind.pipe = pending_connection_.bind_pipe;\n        bind_socket_->process_command (cmd);\n        bind_socket_->send_inproc_connected (\n          pending_connection_.endpoint.socket);\n    } else\n        pending_connection_.connect_pipe->send_bind (\n          bind_socket_, pending_connection_.bind_pipe, false);\n\n    // When a ctx is terminated all pending inproc connection will be\n    // connected, but the socket will already be closed and the pipe will be\n    // in waiting_for_delimiter state, which means no more writes can be done\n    // and the routing id write fails and causes an assert. Check if the socket\n    // is open before sending.\n    if (pending_connection_.endpoint.options.recv_routing_id\n        && pending_connection_.endpoint.socket->check_tag ()) {\n        send_routing_id (pending_connection_.bind_pipe, bind_options_);\n    }\n\n#ifdef ZMQ_BUILD_DRAFT_API\n    //  If set, send the hello msg of the bind socket to the pending connection.\n    if (bind_options_.can_send_hello_msg\n        && bind_options_.hello_msg.size () > 0) {\n        send_hello_msg (pending_connection_.bind_pipe, bind_options_);\n    }\n#endif\n}\n\n#ifdef ZMQ_HAVE_VMCI\n\nint zmq::ctx_t::get_vmci_socket_family ()\n{\n    zmq::scoped_lock_t locker (_vmci_sync);\n\n    if (_vmci_fd == -1) {\n        _vmci_family = VMCISock_GetAFValueFd (&_vmci_fd);\n\n        if (_vmci_fd != -1) {\n#ifdef FD_CLOEXEC\n            int rc = fcntl (_vmci_fd, F_SETFD, FD_CLOEXEC);\n            errno_assert (rc != -1);\n#endif\n        }\n    }\n\n    return _vmci_family;\n}\n\n#endif\n\n#ifdef ZMQ_HAVE_VSOCK\n\nint zmq::ctx_t::get_vsock_socket_family ()\n{\n    return AF_VSOCK;\n}\n\n#endif\n\n//  The last used socket ID, or 0 if no socket was used so far. Note that this\n//  is a global variable. Thus, even sockets created in different contexts have\n//  unique IDs.\nzmq::atomic_counter_t zmq::ctx_t::max_socket_id;\n"
  },
  {
    "path": "src/ctx.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_CTX_HPP_INCLUDED__\n#define __ZMQ_CTX_HPP_INCLUDED__\n\n#include <map>\n#include <vector>\n#include <string>\n#include <stdarg.h>\n\n#include \"mailbox.hpp\"\n#include \"array.hpp\"\n#include \"config.hpp\"\n#include \"mutex.hpp\"\n#include \"stdint.hpp\"\n#include \"options.hpp\"\n#include \"atomic_counter.hpp\"\n#include \"thread.hpp\"\n\nnamespace zmq\n{\nclass object_t;\nclass io_thread_t;\nclass socket_base_t;\nclass reaper_t;\nclass pipe_t;\n\n//  Information associated with inproc endpoint. Note that endpoint options\n//  are registered as well so that the peer can access them without a need\n//  for synchronisation, handshaking or similar.\nstruct endpoint_t\n{\n    socket_base_t *socket;\n    options_t options;\n};\n\nclass thread_ctx_t\n{\n  public:\n    thread_ctx_t ();\n\n    //  Start a new thread with proper scheduling parameters.\n    void start_thread (thread_t &thread_,\n                       thread_fn *tfn_,\n                       void *arg_,\n                       const char *name_ = NULL) const;\n\n    int set (int option_, const void *optval_, size_t optvallen_);\n    int get (int option_, void *optval_, const size_t *optvallen_);\n\n  protected:\n    //  Synchronisation of access to context options.\n    mutex_t _opt_sync;\n\n  private:\n    //  Thread parameters.\n    int _thread_priority;\n    int _thread_sched_policy;\n    std::set<int> _thread_affinity_cpus;\n    std::string _thread_name_prefix;\n};\n\n//  Context object encapsulates all the global state associated with\n//  the library.\n\nclass ctx_t ZMQ_FINAL : public thread_ctx_t\n{\n  public:\n    //  Create the context object.\n    ctx_t ();\n\n    //  Returns false if object is not a context.\n    bool check_tag () const;\n\n    //  This function is called when user invokes zmq_ctx_term. If there are\n    //  no more sockets open it'll cause all the infrastructure to be shut\n    //  down. If there are open sockets still, the deallocation happens\n    //  after the last one is closed.\n    int terminate ();\n\n    // This function starts the terminate process by unblocking any blocking\n    // operations currently in progress and stopping any more socket activity\n    // (except zmq_close).\n    // This function is non-blocking.\n    // terminate must still be called afterwards.\n    // This function is optional, terminate will unblock any current\n    // operations as well.\n    int shutdown ();\n\n    //  Set and get context properties.\n    int set (int option_, const void *optval_, size_t optvallen_);\n    int get (int option_, void *optval_, const size_t *optvallen_);\n    int get (int option_);\n\n    //  Create and destroy a socket.\n    zmq::socket_base_t *create_socket (int type_);\n    void destroy_socket (zmq::socket_base_t *socket_);\n\n    //  Send command to the destination thread.\n    void send_command (uint32_t tid_, const command_t &command_);\n\n    //  Returns the I/O thread that is the least busy at the moment.\n    //  Affinity specifies which I/O threads are eligible (0 = all).\n    //  Returns NULL if no I/O thread is available.\n    zmq::io_thread_t *choose_io_thread (uint64_t affinity_);\n\n    //  Returns reaper thread object.\n    zmq::object_t *get_reaper () const;\n\n    //  Management of inproc endpoints.\n    int register_endpoint (const char *addr_, const endpoint_t &endpoint_);\n    int unregister_endpoint (const std::string &addr_,\n                             const socket_base_t *socket_);\n    void unregister_endpoints (const zmq::socket_base_t *socket_);\n    endpoint_t find_endpoint (const char *addr_);\n    void pend_connection (const std::string &addr_,\n                          const endpoint_t &endpoint_,\n                          pipe_t **pipes_);\n    void connect_pending (const char *addr_, zmq::socket_base_t *bind_socket_);\n\n#ifdef ZMQ_HAVE_VMCI\n    // Return family for the VMCI socket or -1 if it's not available.\n    int get_vmci_socket_family ();\n#endif\n#ifdef ZMQ_HAVE_VSOCK\n    // Return family for the AF_VSOCK socket or -1 if it's not available.\n    int get_vsock_socket_family ();\n#endif\n\n    enum\n    {\n        term_tid = 0,\n        reaper_tid = 1\n    };\n\n    ~ctx_t ();\n\n    bool valid () const;\n\n  private:\n    bool start ();\n\n    struct pending_connection_t\n    {\n        endpoint_t endpoint;\n        pipe_t *connect_pipe;\n        pipe_t *bind_pipe;\n    };\n\n    //  Used to check whether the object is a context.\n    uint32_t _tag;\n\n    //  Sockets belonging to this context. We need the list so that\n    //  we can notify the sockets when zmq_ctx_term() is called.\n    //  The sockets will return ETERM then.\n    typedef array_t<socket_base_t> sockets_t;\n    sockets_t _sockets;\n\n    //  List of unused thread slots.\n    typedef std::vector<uint32_t> empty_slots_t;\n    empty_slots_t _empty_slots;\n\n    //  If true, zmq_init has been called but no socket has been created\n    //  yet. Launching of I/O threads is delayed.\n    bool _starting;\n\n    //  If true, zmq_ctx_term was already called.\n    bool _terminating;\n\n    //  Synchronisation of accesses to global slot-related data:\n    //  sockets, empty_slots, terminating. It also synchronises\n    //  access to zombie sockets as such (as opposed to slots) and provides\n    //  a memory barrier to ensure that all CPU cores see the same data.\n    mutex_t _slot_sync;\n\n    //  The reaper thread.\n    zmq::reaper_t *_reaper;\n\n    //  I/O threads.\n    typedef std::vector<zmq::io_thread_t *> io_threads_t;\n    io_threads_t _io_threads;\n\n    //  Array of pointers to mailboxes for both application and I/O threads.\n    std::vector<i_mailbox *> _slots;\n\n    //  Mailbox for zmq_ctx_term thread.\n    mailbox_t _term_mailbox;\n\n    //  List of inproc endpoints within this context.\n    typedef std::map<std::string, endpoint_t> endpoints_t;\n    endpoints_t _endpoints;\n\n    // List of inproc connection endpoints pending a bind\n    typedef std::multimap<std::string, pending_connection_t>\n      pending_connections_t;\n    pending_connections_t _pending_connections;\n\n    //  Synchronisation of access to the list of inproc endpoints.\n    mutex_t _endpoints_sync;\n\n    //  Maximum socket ID.\n    static atomic_counter_t max_socket_id;\n\n    //  Maximum number of sockets that can be opened at the same time.\n    int _max_sockets;\n\n    //  Maximum allowed message size\n    int _max_msgsz;\n\n    //  Number of I/O threads to launch.\n    int _io_thread_count;\n\n    //  Does context wait (possibly forever) on termination?\n    bool _blocky;\n\n    //  Is IPv6 enabled on this context?\n    bool _ipv6;\n\n    // Should we use zero copy message decoding in this context?\n    bool _zero_copy;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (ctx_t)\n\n#ifdef HAVE_FORK\n    // the process that created this context. Used to detect forking.\n    pid_t _pid;\n#endif\n    enum side\n    {\n        connect_side,\n        bind_side\n    };\n\n    static void\n    connect_inproc_sockets (zmq::socket_base_t *bind_socket_,\n                            const options_t &bind_options_,\n                            const pending_connection_t &pending_connection_,\n                            side side_);\n\n#ifdef ZMQ_HAVE_VMCI\n    int _vmci_fd;\n    int _vmci_family;\n    mutex_t _vmci_sync;\n#endif\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/curve_client.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n\n#ifdef ZMQ_HAVE_CURVE\n\n#include \"msg.hpp\"\n#include \"session_base.hpp\"\n#include \"err.hpp\"\n#include \"curve_client.hpp\"\n#include \"wire.hpp\"\n#include \"curve_client_tools.hpp\"\n#include \"secure_allocator.hpp\"\n\nzmq::curve_client_t::curve_client_t (session_base_t *session_,\n                                     const options_t &options_,\n                                     const bool downgrade_sub_) :\n    mechanism_base_t (session_, options_),\n    curve_mechanism_base_t (session_,\n                            options_,\n                            \"CurveZMQMESSAGEC\",\n                            \"CurveZMQMESSAGES\",\n                            downgrade_sub_),\n    _state (send_hello),\n    _tools (options_.curve_public_key,\n            options_.curve_secret_key,\n            options_.curve_server_key)\n{\n}\n\nzmq::curve_client_t::~curve_client_t ()\n{\n}\n\nint zmq::curve_client_t::next_handshake_command (msg_t *msg_)\n{\n    int rc = 0;\n\n    switch (_state) {\n        case send_hello:\n            rc = produce_hello (msg_);\n            if (rc == 0)\n                _state = expect_welcome;\n            break;\n        case send_initiate:\n            rc = produce_initiate (msg_);\n            if (rc == 0)\n                _state = expect_ready;\n            break;\n        default:\n            errno = EAGAIN;\n            rc = -1;\n    }\n    return rc;\n}\n\nint zmq::curve_client_t::process_handshake_command (msg_t *msg_)\n{\n    const unsigned char *msg_data =\n      static_cast<unsigned char *> (msg_->data ());\n    const size_t msg_size = msg_->size ();\n\n    int rc = 0;\n    if (curve_client_tools_t::is_handshake_command_welcome (msg_data, msg_size))\n        rc = process_welcome (msg_data, msg_size);\n    else if (curve_client_tools_t::is_handshake_command_ready (msg_data,\n                                                               msg_size))\n        rc = process_ready (msg_data, msg_size);\n    else if (curve_client_tools_t::is_handshake_command_error (msg_data,\n                                                               msg_size))\n        rc = process_error (msg_data, msg_size);\n    else {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        rc = -1;\n    }\n\n    if (rc == 0) {\n        rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n    }\n\n    return rc;\n}\n\nint zmq::curve_client_t::encode (msg_t *msg_)\n{\n    zmq_assert (_state == connected);\n    return curve_mechanism_base_t::encode (msg_);\n}\n\nint zmq::curve_client_t::decode (msg_t *msg_)\n{\n    zmq_assert (_state == connected);\n    return curve_mechanism_base_t::decode (msg_);\n}\n\nzmq::mechanism_t::status_t zmq::curve_client_t::status () const\n{\n    if (_state == connected)\n        return mechanism_t::ready;\n    if (_state == error_received)\n        return mechanism_t::error;\n\n    return mechanism_t::handshaking;\n}\n\nint zmq::curve_client_t::produce_hello (msg_t *msg_)\n{\n    int rc = msg_->init_size (200);\n    errno_assert (rc == 0);\n\n    rc = _tools.produce_hello (msg_->data (), get_and_inc_nonce ());\n    if (rc == -1) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n\n        // TODO this is somewhat inconsistent: we call init_size, but we may\n        // not close msg_; i.e. we assume that msg_ is initialized but empty\n        // (if it were non-empty, calling init_size might cause a leak!)\n\n        // msg_->close ();\n        return -1;\n    }\n\n    return 0;\n}\n\nint zmq::curve_client_t::process_welcome (const uint8_t *msg_data_,\n                                          size_t msg_size_)\n{\n    const int rc = _tools.process_welcome (msg_data_, msg_size_,\n                                           get_writable_precom_buffer ());\n\n    if (rc == -1) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n\n        errno = EPROTO;\n        return -1;\n    }\n\n    _state = send_initiate;\n\n    return 0;\n}\n\nint zmq::curve_client_t::produce_initiate (msg_t *msg_)\n{\n    const size_t metadata_length = basic_properties_len ();\n    std::vector<unsigned char, secure_allocator_t<unsigned char> >\n      metadata_plaintext (metadata_length);\n\n    add_basic_properties (&metadata_plaintext[0], metadata_length);\n\n    const size_t msg_size =\n      113 + 128 + crypto_box_BOXZEROBYTES + metadata_length;\n    int rc = msg_->init_size (msg_size);\n    errno_assert (rc == 0);\n\n    rc = _tools.produce_initiate (msg_->data (), msg_size, get_and_inc_nonce (),\n                                  &metadata_plaintext[0], metadata_length);\n\n    if (-1 == rc) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n\n        // TODO see comment in produce_hello\n        return -1;\n    }\n\n    return 0;\n}\n\nint zmq::curve_client_t::process_ready (const uint8_t *msg_data_,\n                                        size_t msg_size_)\n{\n    if (msg_size_ < 30) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY);\n        errno = EPROTO;\n        return -1;\n    }\n\n    const size_t clen = (msg_size_ - 14) + crypto_box_BOXZEROBYTES;\n\n    uint8_t ready_nonce[crypto_box_NONCEBYTES];\n    std::vector<uint8_t, secure_allocator_t<uint8_t> > ready_plaintext (\n      crypto_box_ZEROBYTES + clen);\n    std::vector<uint8_t> ready_box (crypto_box_BOXZEROBYTES + 16 + clen);\n\n    std::fill (ready_box.begin (), ready_box.begin () + crypto_box_BOXZEROBYTES,\n               0);\n    memcpy (&ready_box[crypto_box_BOXZEROBYTES], msg_data_ + 14,\n            clen - crypto_box_BOXZEROBYTES);\n\n    memcpy (ready_nonce, \"CurveZMQREADY---\", 16);\n    memcpy (ready_nonce + 16, msg_data_ + 6, 8);\n    set_peer_nonce (get_uint64 (msg_data_ + 6));\n\n    int rc = crypto_box_open_afternm (&ready_plaintext[0], &ready_box[0], clen,\n                                      ready_nonce, get_precom_buffer ());\n\n    if (rc != 0) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n        errno = EPROTO;\n        return -1;\n    }\n\n    rc = parse_metadata (&ready_plaintext[crypto_box_ZEROBYTES],\n                         clen - crypto_box_ZEROBYTES);\n\n    if (rc == 0)\n        _state = connected;\n    else {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA);\n        errno = EPROTO;\n    }\n\n    return rc;\n}\n\nint zmq::curve_client_t::process_error (const uint8_t *msg_data_,\n                                        size_t msg_size_)\n{\n    if (_state != expect_welcome && _state != expect_ready) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n    if (msg_size_ < 7) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);\n        errno = EPROTO;\n        return -1;\n    }\n    const size_t error_reason_len = static_cast<size_t> (msg_data_[6]);\n    if (error_reason_len > msg_size_ - 7) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);\n        errno = EPROTO;\n        return -1;\n    }\n    const char *error_reason = reinterpret_cast<const char *> (msg_data_) + 7;\n    handle_error_reason (error_reason, error_reason_len);\n    _state = error_received;\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "src/curve_client.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_CURVE_CLIENT_HPP_INCLUDED__\n#define __ZMQ_CURVE_CLIENT_HPP_INCLUDED__\n\n#ifdef ZMQ_HAVE_CURVE\n\n#include \"curve_mechanism_base.hpp\"\n#include \"options.hpp\"\n#include \"curve_client_tools.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\nclass session_base_t;\n\nclass curve_client_t ZMQ_FINAL : public curve_mechanism_base_t\n{\n  public:\n    curve_client_t (session_base_t *session_,\n                    const options_t &options_,\n                    const bool downgrade_sub_);\n    ~curve_client_t () ZMQ_FINAL;\n\n    // mechanism implementation\n    int next_handshake_command (msg_t *msg_) ZMQ_FINAL;\n    int process_handshake_command (msg_t *msg_) ZMQ_FINAL;\n    int encode (msg_t *msg_) ZMQ_FINAL;\n    int decode (msg_t *msg_) ZMQ_FINAL;\n    status_t status () const ZMQ_FINAL;\n\n  private:\n    enum state_t\n    {\n        send_hello,\n        expect_welcome,\n        send_initiate,\n        expect_ready,\n        error_received,\n        connected\n    };\n\n    //  Current FSM state\n    state_t _state;\n\n    //  CURVE protocol tools\n    curve_client_tools_t _tools;\n\n    int produce_hello (msg_t *msg_);\n    int process_welcome (const uint8_t *msg_data_, size_t msg_size_);\n    int produce_initiate (msg_t *msg_);\n    int process_ready (const uint8_t *msg_data_, size_t msg_size_);\n    int process_error (const uint8_t *msg_data_, size_t msg_size_);\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/curve_client_tools.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_CURVE_CLIENT_TOOLS_HPP_INCLUDED__\n#define __ZMQ_CURVE_CLIENT_TOOLS_HPP_INCLUDED__\n\n#ifdef ZMQ_HAVE_CURVE\n\n#if defined(ZMQ_USE_LIBSODIUM)\n#include \"sodium.h\"\n#endif\n\n#if crypto_box_NONCEBYTES != 24 || crypto_box_PUBLICKEYBYTES != 32             \\\n  || crypto_box_SECRETKEYBYTES != 32 || crypto_box_ZEROBYTES != 32             \\\n  || crypto_box_BOXZEROBYTES != 16\n#error \"CURVE library not built properly\"\n#endif\n\n#include \"wire.hpp\"\n#include \"err.hpp\"\n#include \"secure_allocator.hpp\"\n\n#include <vector>\n\nnamespace zmq\n{\nstruct curve_client_tools_t\n{\n    static int produce_hello (void *data_,\n                              const uint8_t *server_key_,\n                              const uint64_t cn_nonce_,\n                              const uint8_t *cn_public_,\n                              const uint8_t *cn_secret_)\n    {\n        uint8_t hello_nonce[crypto_box_NONCEBYTES];\n        std::vector<uint8_t, secure_allocator_t<uint8_t> > hello_plaintext (\n          crypto_box_ZEROBYTES + 64, 0);\n        uint8_t hello_box[crypto_box_BOXZEROBYTES + 80];\n\n        //  Prepare the full nonce\n        memcpy (hello_nonce, \"CurveZMQHELLO---\", 16);\n        put_uint64 (hello_nonce + 16, cn_nonce_);\n\n        //  Create Box [64 * %x0](C'->S)\n        const int rc =\n          crypto_box (hello_box, &hello_plaintext[0], hello_plaintext.size (),\n                      hello_nonce, server_key_, cn_secret_);\n        if (rc == -1)\n            return -1;\n\n        uint8_t *hello = static_cast<uint8_t *> (data_);\n\n        memcpy (hello, \"\\x05HELLO\", 6);\n        //  CurveZMQ major and minor version numbers\n        memcpy (hello + 6, \"\\1\\0\", 2);\n        //  Anti-amplification padding\n        memset (hello + 8, 0, 72);\n        //  Client public connection key\n        memcpy (hello + 80, cn_public_, crypto_box_PUBLICKEYBYTES);\n        //  Short nonce, prefixed by \"CurveZMQHELLO---\"\n        memcpy (hello + 112, hello_nonce + 16, 8);\n        //  Signature, Box [64 * %x0](C'->S)\n        memcpy (hello + 120, hello_box + crypto_box_BOXZEROBYTES, 80);\n\n        return 0;\n    }\n\n    static int process_welcome (const uint8_t *msg_data_,\n                                size_t msg_size_,\n                                const uint8_t *server_key_,\n                                const uint8_t *cn_secret_,\n                                uint8_t *cn_server_,\n                                uint8_t *cn_cookie_,\n                                uint8_t *cn_precom_)\n    {\n        if (msg_size_ != 168) {\n            errno = EPROTO;\n            return -1;\n        }\n\n        uint8_t welcome_nonce[crypto_box_NONCEBYTES];\n        std::vector<uint8_t, secure_allocator_t<uint8_t> > welcome_plaintext (\n          crypto_box_ZEROBYTES + 128);\n        uint8_t welcome_box[crypto_box_BOXZEROBYTES + 144];\n\n        //  Open Box [S' + cookie](C'->S)\n        memset (welcome_box, 0, crypto_box_BOXZEROBYTES);\n        memcpy (welcome_box + crypto_box_BOXZEROBYTES, msg_data_ + 24, 144);\n\n        memcpy (welcome_nonce, \"WELCOME-\", 8);\n        memcpy (welcome_nonce + 8, msg_data_ + 8, 16);\n\n        int rc = crypto_box_open (&welcome_plaintext[0], welcome_box,\n                                  sizeof welcome_box, welcome_nonce,\n                                  server_key_, cn_secret_);\n        if (rc != 0) {\n            errno = EPROTO;\n            return -1;\n        }\n\n        memcpy (cn_server_, &welcome_plaintext[crypto_box_ZEROBYTES], 32);\n        memcpy (cn_cookie_, &welcome_plaintext[crypto_box_ZEROBYTES + 32],\n                16 + 80);\n\n        //  Message independent precomputation\n        rc = crypto_box_beforenm (cn_precom_, cn_server_, cn_secret_);\n        zmq_assert (rc == 0);\n\n        return 0;\n    }\n\n    static int produce_initiate (void *data_,\n                                 size_t size_,\n                                 const uint64_t cn_nonce_,\n                                 const uint8_t *server_key_,\n                                 const uint8_t *public_key_,\n                                 const uint8_t *secret_key_,\n                                 const uint8_t *cn_public_,\n                                 const uint8_t *cn_secret_,\n                                 const uint8_t *cn_server_,\n                                 const uint8_t *cn_cookie_,\n                                 const uint8_t *metadata_plaintext_,\n                                 const size_t metadata_length_)\n    {\n        uint8_t vouch_nonce[crypto_box_NONCEBYTES];\n        std::vector<uint8_t, secure_allocator_t<uint8_t> > vouch_plaintext (\n          crypto_box_ZEROBYTES + 64);\n        uint8_t vouch_box[crypto_box_BOXZEROBYTES + 80];\n\n        //  Create vouch = Box [C',S](C->S')\n        std::fill (vouch_plaintext.begin (),\n                   vouch_plaintext.begin () + crypto_box_ZEROBYTES, 0);\n        memcpy (&vouch_plaintext[crypto_box_ZEROBYTES], cn_public_, 32);\n        memcpy (&vouch_plaintext[crypto_box_ZEROBYTES + 32], server_key_, 32);\n\n        memset (vouch_nonce, 0, crypto_box_NONCEBYTES);\n        memcpy (vouch_nonce, \"VOUCH---\", 8);\n        randombytes (vouch_nonce + 8, 16);\n\n        int rc =\n          crypto_box (vouch_box, &vouch_plaintext[0], vouch_plaintext.size (),\n                      vouch_nonce, cn_server_, secret_key_);\n        if (rc == -1)\n            return -1;\n\n        uint8_t initiate_nonce[crypto_box_NONCEBYTES];\n        std::vector<uint8_t> initiate_box (crypto_box_BOXZEROBYTES + 144\n                                           + metadata_length_);\n        std::vector<uint8_t, secure_allocator_t<uint8_t> > initiate_plaintext (\n          crypto_box_ZEROBYTES + 128 + metadata_length_);\n\n        //  Create Box [C + vouch + metadata](C'->S')\n        std::fill (initiate_plaintext.begin (),\n                   initiate_plaintext.begin () + crypto_box_ZEROBYTES, 0);\n\n        //  False positives due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578\n#if __GNUC__ >= 11\n#pragma GCC diagnostic ignored \"-Warray-bounds\"\n#pragma GCC diagnostic ignored \"-Wstringop-overflow=\"\n#endif\n        memcpy (&initiate_plaintext[crypto_box_ZEROBYTES], public_key_, 32);\n        memcpy (&initiate_plaintext[crypto_box_ZEROBYTES + 32], vouch_nonce + 8,\n                16);\n        memcpy (&initiate_plaintext[crypto_box_ZEROBYTES + 48],\n                vouch_box + crypto_box_BOXZEROBYTES, 80);\n        if (metadata_length_) {\n            memcpy (&initiate_plaintext[crypto_box_ZEROBYTES + 48 + 80],\n                    metadata_plaintext_, metadata_length_);\n        }\n#if __GNUC__ >= 11\n#pragma GCC diagnostic pop\n#pragma GCC diagnostic pop\n#endif\n\n        memcpy (initiate_nonce, \"CurveZMQINITIATE\", 16);\n        put_uint64 (initiate_nonce + 16, cn_nonce_);\n\n        rc = crypto_box (&initiate_box[0], &initiate_plaintext[0],\n                         crypto_box_ZEROBYTES + 128 + metadata_length_,\n                         initiate_nonce, cn_server_, cn_secret_);\n\n        if (rc == -1)\n            return -1;\n\n        uint8_t *initiate = static_cast<uint8_t *> (data_);\n\n        zmq_assert (size_\n                    == 113 + 128 + crypto_box_BOXZEROBYTES + metadata_length_);\n\n        memcpy (initiate, \"\\x08INITIATE\", 9);\n        //  Cookie provided by the server in the WELCOME command\n        memcpy (initiate + 9, cn_cookie_, 96);\n        //  Short nonce, prefixed by \"CurveZMQINITIATE\"\n        memcpy (initiate + 105, initiate_nonce + 16, 8);\n        //  Box [C + vouch + metadata](C'->S')\n        memcpy (initiate + 113, &initiate_box[crypto_box_BOXZEROBYTES],\n                128 + metadata_length_ + crypto_box_BOXZEROBYTES);\n\n        return 0;\n    }\n\n    static bool is_handshake_command_welcome (const uint8_t *msg_data_,\n                                              const size_t msg_size_)\n    {\n        return is_handshake_command (msg_data_, msg_size_, \"\\7WELCOME\");\n    }\n\n    static bool is_handshake_command_ready (const uint8_t *msg_data_,\n                                            const size_t msg_size_)\n    {\n        return is_handshake_command (msg_data_, msg_size_, \"\\5READY\");\n    }\n\n    static bool is_handshake_command_error (const uint8_t *msg_data_,\n                                            const size_t msg_size_)\n    {\n        return is_handshake_command (msg_data_, msg_size_, \"\\5ERROR\");\n    }\n\n    //  non-static functions\n    curve_client_tools_t (\n      const uint8_t (&curve_public_key_)[crypto_box_PUBLICKEYBYTES],\n      const uint8_t (&curve_secret_key_)[crypto_box_SECRETKEYBYTES],\n      const uint8_t (&curve_server_key_)[crypto_box_PUBLICKEYBYTES])\n    {\n        int rc;\n        memcpy (public_key, curve_public_key_, crypto_box_PUBLICKEYBYTES);\n        memcpy (secret_key, curve_secret_key_, crypto_box_SECRETKEYBYTES);\n        memcpy (server_key, curve_server_key_, crypto_box_PUBLICKEYBYTES);\n\n        //  Generate short-term key pair\n        memset (cn_secret, 0, crypto_box_SECRETKEYBYTES);\n        memset (cn_public, 0, crypto_box_PUBLICKEYBYTES);\n        rc = crypto_box_keypair (cn_public, cn_secret);\n        zmq_assert (rc == 0);\n    }\n\n    int produce_hello (void *data_, const uint64_t cn_nonce_) const\n    {\n        return produce_hello (data_, server_key, cn_nonce_, cn_public,\n                              cn_secret);\n    }\n\n    int process_welcome (const uint8_t *msg_data_,\n                         size_t msg_size_,\n                         uint8_t *cn_precom_)\n    {\n        return process_welcome (msg_data_, msg_size_, server_key, cn_secret,\n                                cn_server, cn_cookie, cn_precom_);\n    }\n\n    int produce_initiate (void *data_,\n                          size_t size_,\n                          const uint64_t cn_nonce_,\n                          const uint8_t *metadata_plaintext_,\n                          const size_t metadata_length_) const\n    {\n        return produce_initiate (data_, size_, cn_nonce_, server_key,\n                                 public_key, secret_key, cn_public, cn_secret,\n                                 cn_server, cn_cookie, metadata_plaintext_,\n                                 metadata_length_);\n    }\n\n    //  Our public key (C)\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n\n    //  Our secret key (c)\n    uint8_t secret_key[crypto_box_SECRETKEYBYTES];\n\n    //  Our short-term public key (C')\n    uint8_t cn_public[crypto_box_PUBLICKEYBYTES];\n\n    //  Our short-term secret key (c')\n    uint8_t cn_secret[crypto_box_SECRETKEYBYTES];\n\n    //  Server's public key (S)\n    uint8_t server_key[crypto_box_PUBLICKEYBYTES];\n\n    //  Server's short-term public key (S')\n    uint8_t cn_server[crypto_box_PUBLICKEYBYTES];\n\n    //  Cookie received from server\n    uint8_t cn_cookie[16 + 80];\n\n  private:\n    template <size_t N>\n    static bool is_handshake_command (const uint8_t *msg_data_,\n                                      const size_t msg_size_,\n                                      const char (&prefix_)[N])\n    {\n        return msg_size_ >= (N - 1) && !memcmp (msg_data_, prefix_, N - 1);\n    }\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/curve_mechanism_base.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n\n#include \"precompiled.hpp\"\n#include \"curve_mechanism_base.hpp\"\n#include \"msg.hpp\"\n#include \"wire.hpp\"\n#include \"session_base.hpp\"\n\n#ifdef ZMQ_HAVE_CURVE\n\n#ifdef ZMQ_USE_LIBSODIUM\n//  libsodium added crypto_box_easy_afternm and crypto_box_open_easy_afternm with\n//  https: //github.com/jedisct1/libsodium/commit/aaf5fbf2e53a33b18d8ea9bdf2c6f73d7acc8c3e\n#if SODIUM_LIBRARY_VERSION_MAJOR > 7                                           \\\n  || (SODIUM_LIBRARY_VERSION_MAJOR == 7 && SODIUM_LIBRARY_VERSION_MINOR >= 4)\n#define ZMQ_HAVE_CRYPTO_BOX_EASY_FNS 1\n#endif\n#endif\n\nzmq::curve_mechanism_base_t::curve_mechanism_base_t (\n  session_base_t *session_,\n  const options_t &options_,\n  const char *encode_nonce_prefix_,\n  const char *decode_nonce_prefix_,\n  const bool downgrade_sub_) :\n    mechanism_base_t (session_, options_),\n    curve_encoding_t (\n      encode_nonce_prefix_, decode_nonce_prefix_, downgrade_sub_)\n{\n}\n\nint zmq::curve_mechanism_base_t::encode (msg_t *msg_)\n{\n    return curve_encoding_t::encode (msg_);\n}\n\nint zmq::curve_mechanism_base_t::decode (msg_t *msg_)\n{\n    int rc = check_basic_command_structure (msg_);\n    if (rc == -1)\n        return -1;\n\n    int error_event_code;\n    rc = curve_encoding_t::decode (msg_, &error_event_code);\n    if (-1 == rc) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), error_event_code);\n    }\n\n    return rc;\n}\n\nzmq::curve_encoding_t::curve_encoding_t (const char *encode_nonce_prefix_,\n                                         const char *decode_nonce_prefix_,\n                                         const bool downgrade_sub_) :\n    _encode_nonce_prefix (encode_nonce_prefix_),\n    _decode_nonce_prefix (decode_nonce_prefix_),\n    _cn_nonce (1),\n    _cn_peer_nonce (1),\n    _downgrade_sub (downgrade_sub_)\n{\n}\n\n//  Right now, we only transport the lower two bit flags of zmq::msg_t, so they\n//  are binary identical, and we can just use a bitmask to select them. If we\n//  happened to add more flags, this might change.\nstatic const uint8_t flag_mask = zmq::msg_t::more | zmq::msg_t::command;\nstatic const size_t flags_len = 1;\nstatic const size_t nonce_prefix_len = 16;\nstatic const char message_command[] = \"\\x07MESSAGE\";\nstatic const size_t message_command_len = sizeof (message_command) - 1;\nstatic const size_t message_header_len =\n  message_command_len + sizeof (zmq::curve_encoding_t::nonce_t);\n\n#ifndef ZMQ_USE_LIBSODIUM\nstatic const size_t crypto_box_MACBYTES = 16;\n#endif\n\nint zmq::curve_encoding_t::check_validity (msg_t *msg_, int *error_event_code_)\n{\n    const size_t size = msg_->size ();\n    const uint8_t *const message = static_cast<uint8_t *> (msg_->data ());\n\n    if (size < message_command_len\n        || 0 != memcmp (message, message_command, message_command_len)) {\n        *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND;\n        errno = EPROTO;\n        return -1;\n    }\n\n    if (size < message_header_len + crypto_box_MACBYTES + flags_len) {\n        *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE;\n        errno = EPROTO;\n        return -1;\n    }\n\n    {\n        const uint64_t nonce = get_uint64 (message + message_command_len);\n        if (nonce <= _cn_peer_nonce) {\n            *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE;\n            errno = EPROTO;\n            return -1;\n        }\n        set_peer_nonce (nonce);\n    }\n\n    return 0;\n}\n\nint zmq::curve_encoding_t::encode (msg_t *msg_)\n{\n    size_t sub_cancel_len = 0;\n    uint8_t message_nonce[crypto_box_NONCEBYTES];\n    memcpy (message_nonce, _encode_nonce_prefix, nonce_prefix_len);\n    put_uint64 (message_nonce + nonce_prefix_len, get_and_inc_nonce ());\n\n    if (msg_->is_subscribe () || msg_->is_cancel ()) {\n        if (_downgrade_sub)\n            sub_cancel_len = 1;\n        else\n            sub_cancel_len = msg_->is_cancel ()\n                               ? zmq::msg_t::cancel_cmd_name_size\n                               : zmq::msg_t::sub_cmd_name_size;\n    }\n\n#ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS\n    const size_t mlen = flags_len + sub_cancel_len + msg_->size ();\n    std::vector<uint8_t> message_plaintext (mlen);\n#else\n    const size_t mlen =\n      crypto_box_ZEROBYTES + flags_len + sub_cancel_len + msg_->size ();\n    std::vector<uint8_t> message_plaintext_with_zerobytes (mlen);\n    uint8_t *const message_plaintext =\n      &message_plaintext_with_zerobytes[crypto_box_ZEROBYTES];\n\n    std::fill (message_plaintext_with_zerobytes.begin (),\n               message_plaintext_with_zerobytes.begin () + crypto_box_ZEROBYTES,\n               0);\n#endif\n\n    const uint8_t flags = msg_->flags () & flag_mask;\n    message_plaintext[0] = flags;\n\n    // For backward compatibility subscribe/cancel command messages are not stored with\n    // the message flags, and are encoded in the encoder, so that messages for < 3.0 peers\n    // can be encoded in the \"old\" 0/1 way rather than as commands.\n    if (sub_cancel_len == 1)\n        message_plaintext[flags_len] = msg_->is_subscribe () ? 1 : 0;\n    else if (sub_cancel_len == zmq::msg_t::sub_cmd_name_size) {\n        message_plaintext[0] |= zmq::msg_t::command;\n        memcpy (&message_plaintext[flags_len], zmq::sub_cmd_name,\n                zmq::msg_t::sub_cmd_name_size);\n    } else if (sub_cancel_len == zmq::msg_t::cancel_cmd_name_size) {\n        message_plaintext[0] |= zmq::msg_t::command;\n        memcpy (&message_plaintext[flags_len], zmq::cancel_cmd_name,\n                zmq::msg_t::cancel_cmd_name_size);\n    }\n\n    // this is copying the data from insecure memory, so there is no point in\n    // using secure_allocator_t for message_plaintext\n    if (msg_->size () > 0)\n        memcpy (&message_plaintext[flags_len + sub_cancel_len], msg_->data (),\n                msg_->size ());\n\n#ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS\n    msg_t msg_box;\n    int rc =\n      msg_box.init_size (message_header_len + mlen + crypto_box_MACBYTES);\n    zmq_assert (rc == 0);\n\n    rc = crypto_box_easy_afternm (\n      static_cast<uint8_t *> (msg_box.data ()) + message_header_len,\n      &message_plaintext[0], mlen, message_nonce, _cn_precom);\n    zmq_assert (rc == 0);\n\n    msg_->move (msg_box);\n\n    uint8_t *const message = static_cast<uint8_t *> (msg_->data ());\n#else\n    std::vector<uint8_t> message_box (mlen);\n\n    int rc =\n      crypto_box_afternm (&message_box[0], &message_plaintext_with_zerobytes[0],\n                          mlen, message_nonce, _cn_precom);\n    zmq_assert (rc == 0);\n\n    rc = msg_->close ();\n    zmq_assert (rc == 0);\n\n    rc = msg_->init_size (16 + mlen - crypto_box_BOXZEROBYTES);\n    zmq_assert (rc == 0);\n\n    uint8_t *const message = static_cast<uint8_t *> (msg_->data ());\n\n    memcpy (message + message_header_len, &message_box[crypto_box_BOXZEROBYTES],\n            mlen - crypto_box_BOXZEROBYTES);\n#endif\n\n    memcpy (message, message_command, message_command_len);\n    memcpy (message + message_command_len, message_nonce + nonce_prefix_len,\n            sizeof (nonce_t));\n\n    return 0;\n}\n\nint zmq::curve_encoding_t::decode (msg_t *msg_, int *error_event_code_)\n{\n    int rc = check_validity (msg_, error_event_code_);\n    if (0 != rc) {\n        return rc;\n    }\n\n    uint8_t *const message = static_cast<uint8_t *> (msg_->data ());\n\n    uint8_t message_nonce[crypto_box_NONCEBYTES];\n    memcpy (message_nonce, _decode_nonce_prefix, nonce_prefix_len);\n    memcpy (message_nonce + nonce_prefix_len, message + message_command_len,\n            sizeof (nonce_t));\n\n#ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS\n    const size_t clen = msg_->size () - message_header_len;\n\n    uint8_t *const message_plaintext = message + message_header_len;\n\n    rc = crypto_box_open_easy_afternm (message_plaintext,\n                                       message + message_header_len, clen,\n                                       message_nonce, _cn_precom);\n#else\n    const size_t clen =\n      crypto_box_BOXZEROBYTES + msg_->size () - message_header_len;\n\n    std::vector<uint8_t> message_plaintext_with_zerobytes (clen);\n    std::vector<uint8_t> message_box (clen);\n\n    std::fill (message_box.begin (),\n               message_box.begin () + crypto_box_BOXZEROBYTES, 0);\n    memcpy (&message_box[crypto_box_BOXZEROBYTES], message + message_header_len,\n            msg_->size () - message_header_len);\n\n    rc = crypto_box_open_afternm (&message_plaintext_with_zerobytes[0],\n                                  &message_box[0], clen, message_nonce,\n                                  _cn_precom);\n\n    const uint8_t *const message_plaintext =\n      &message_plaintext_with_zerobytes[crypto_box_ZEROBYTES];\n#endif\n\n    if (rc == 0) {\n        const uint8_t flags = message_plaintext[0];\n\n#ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS\n        const size_t plaintext_size = clen - flags_len - crypto_box_MACBYTES;\n\n        if (plaintext_size > 0) {\n            memmove (msg_->data (), &message_plaintext[flags_len],\n                     plaintext_size);\n        }\n\n        msg_->shrink (plaintext_size);\n#else\n        rc = msg_->close ();\n        zmq_assert (rc == 0);\n\n        rc = msg_->init_size (clen - flags_len - crypto_box_ZEROBYTES);\n        zmq_assert (rc == 0);\n\n        // this is copying the data to insecure memory, so there is no point in\n        // using secure_allocator_t for message_plaintext\n        if (msg_->size () > 0) {\n            memcpy (msg_->data (), &message_plaintext[flags_len],\n                    msg_->size ());\n        }\n#endif\n\n        msg_->set_flags (flags & flag_mask);\n    } else {\n        // CURVE I : connection key used for MESSAGE is wrong\n        *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC;\n        errno = EPROTO;\n    }\n\n    return rc;\n}\n\n#endif\n"
  },
  {
    "path": "src/curve_mechanism_base.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_CURVE_MECHANISM_BASE_HPP_INCLUDED__\n#define __ZMQ_CURVE_MECHANISM_BASE_HPP_INCLUDED__\n\n#ifdef ZMQ_HAVE_CURVE\n\n#if defined(ZMQ_USE_LIBSODIUM)\n#include \"sodium.h\"\n#endif\n\n#if crypto_box_NONCEBYTES != 24 || crypto_box_PUBLICKEYBYTES != 32             \\\n  || crypto_box_SECRETKEYBYTES != 32 || crypto_box_ZEROBYTES != 32             \\\n  || crypto_box_BOXZEROBYTES != 16 || crypto_secretbox_NONCEBYTES != 24        \\\n  || crypto_secretbox_ZEROBYTES != 32 || crypto_secretbox_BOXZEROBYTES != 16\n#error \"CURVE library not built properly\"\n#endif\n\n#include \"mechanism_base.hpp\"\n#include \"options.hpp\"\n\n#include <memory>\n\nnamespace zmq\n{\nclass curve_encoding_t\n{\n  public:\n    curve_encoding_t (const char *encode_nonce_prefix_,\n                      const char *decode_nonce_prefix_,\n                      const bool downgrade_sub_);\n\n    int encode (msg_t *msg_);\n    int decode (msg_t *msg_, int *error_event_code_);\n\n    uint8_t *get_writable_precom_buffer () { return _cn_precom; }\n    const uint8_t *get_precom_buffer () const { return _cn_precom; }\n\n    typedef uint64_t nonce_t;\n\n    nonce_t get_and_inc_nonce () { return _cn_nonce++; }\n    void set_peer_nonce (nonce_t peer_nonce_) { _cn_peer_nonce = peer_nonce_; };\n\n  private:\n    int check_validity (msg_t *msg_, int *error_event_code_);\n\n    const char *_encode_nonce_prefix;\n    const char *_decode_nonce_prefix;\n\n    nonce_t _cn_nonce;\n    nonce_t _cn_peer_nonce;\n\n    //  Intermediary buffer used to speed up boxing and unboxing.\n    uint8_t _cn_precom[crypto_box_BEFORENMBYTES];\n\n    const bool _downgrade_sub;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (curve_encoding_t)\n};\n\nclass curve_mechanism_base_t : public virtual mechanism_base_t,\n                               public curve_encoding_t\n{\n  public:\n    curve_mechanism_base_t (session_base_t *session_,\n                            const options_t &options_,\n                            const char *encode_nonce_prefix_,\n                            const char *decode_nonce_prefix_,\n                            const bool downgrade_sub_);\n\n    // mechanism implementation\n    int encode (msg_t *msg_) ZMQ_OVERRIDE;\n    int decode (msg_t *msg_) ZMQ_OVERRIDE;\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/curve_server.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n\n#ifdef ZMQ_HAVE_CURVE\n\n#include \"msg.hpp\"\n#include \"session_base.hpp\"\n#include \"err.hpp\"\n#include \"curve_server.hpp\"\n#include \"wire.hpp\"\n#include \"secure_allocator.hpp\"\n\nzmq::curve_server_t::curve_server_t (session_base_t *session_,\n                                     const std::string &peer_address_,\n                                     const options_t &options_,\n                                     const bool downgrade_sub_) :\n    mechanism_base_t (session_, options_),\n    zap_client_common_handshake_t (\n      session_, peer_address_, options_, sending_ready),\n    curve_mechanism_base_t (session_,\n                            options_,\n                            \"CurveZMQMESSAGES\",\n                            \"CurveZMQMESSAGEC\",\n                            downgrade_sub_)\n{\n    int rc;\n    //  Fetch our secret key from socket options\n    memcpy (_secret_key, options_.curve_secret_key, crypto_box_SECRETKEYBYTES);\n\n    //  Generate short-term key pair\n    memset (_cn_secret, 0, crypto_box_SECRETKEYBYTES);\n    memset (_cn_public, 0, crypto_box_PUBLICKEYBYTES);\n    rc = crypto_box_keypair (_cn_public, _cn_secret);\n    zmq_assert (rc == 0);\n}\n\nzmq::curve_server_t::~curve_server_t ()\n{\n}\n\nint zmq::curve_server_t::next_handshake_command (msg_t *msg_)\n{\n    int rc = 0;\n\n    switch (state) {\n        case sending_welcome:\n            rc = produce_welcome (msg_);\n            if (rc == 0)\n                state = waiting_for_initiate;\n            break;\n        case sending_ready:\n            rc = produce_ready (msg_);\n            if (rc == 0)\n                state = ready;\n            break;\n        case sending_error:\n            rc = produce_error (msg_);\n            if (rc == 0)\n                state = error_sent;\n            break;\n        default:\n            errno = EAGAIN;\n            rc = -1;\n            break;\n    }\n    return rc;\n}\n\nint zmq::curve_server_t::process_handshake_command (msg_t *msg_)\n{\n    int rc = 0;\n\n    switch (state) {\n        case waiting_for_hello:\n            rc = process_hello (msg_);\n            break;\n        case waiting_for_initiate:\n            rc = process_initiate (msg_);\n            break;\n        default:\n            // TODO I think this is not a case reachable with a misbehaving\n            // client. It is not an \"invalid handshake command\", but would be\n            // trying to process a handshake command in an invalid state,\n            // which is purely under control of this peer.\n            // Therefore, it should be changed to zmq_assert (false);\n\n            // CURVE I: invalid handshake command\n            session->get_socket ()->event_handshake_failed_protocol (\n              session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED);\n            errno = EPROTO;\n            rc = -1;\n            break;\n    }\n    if (rc == 0) {\n        rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n    }\n    return rc;\n}\n\nint zmq::curve_server_t::encode (msg_t *msg_)\n{\n    zmq_assert (state == ready);\n    return curve_mechanism_base_t::encode (msg_);\n}\n\nint zmq::curve_server_t::decode (msg_t *msg_)\n{\n    zmq_assert (state == ready);\n    return curve_mechanism_base_t::decode (msg_);\n}\n\nint zmq::curve_server_t::process_hello (msg_t *msg_)\n{\n    int rc = check_basic_command_structure (msg_);\n    if (rc == -1)\n        return -1;\n\n    const size_t size = msg_->size ();\n    const uint8_t *const hello = static_cast<uint8_t *> (msg_->data ());\n\n    if (size < 6 || memcmp (hello, \"\\x05HELLO\", 6)) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n\n    if (size != 200) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);\n        errno = EPROTO;\n        return -1;\n    }\n\n    const uint8_t major = hello[6];\n    const uint8_t minor = hello[7];\n\n    if (major != 1 || minor != 0) {\n        // CURVE I: client HELLO has unknown version number\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);\n        errno = EPROTO;\n        return -1;\n    }\n\n    //  Save client's short-term public key (C')\n    memcpy (_cn_client, hello + 80, 32);\n\n    uint8_t hello_nonce[crypto_box_NONCEBYTES];\n    std::vector<uint8_t, secure_allocator_t<uint8_t> > hello_plaintext (\n      crypto_box_ZEROBYTES + 64);\n    uint8_t hello_box[crypto_box_BOXZEROBYTES + 80];\n\n    memcpy (hello_nonce, \"CurveZMQHELLO---\", 16);\n    memcpy (hello_nonce + 16, hello + 112, 8);\n    set_peer_nonce (get_uint64 (hello + 112));\n\n    memset (hello_box, 0, crypto_box_BOXZEROBYTES);\n    memcpy (hello_box + crypto_box_BOXZEROBYTES, hello + 120, 80);\n\n    //  Open Box [64 * %x0](C'->S)\n    rc = crypto_box_open (&hello_plaintext[0], hello_box, sizeof hello_box,\n                          hello_nonce, _cn_client, _secret_key);\n    if (rc != 0) {\n        // CURVE I: cannot open client HELLO -- wrong server key?\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n        errno = EPROTO;\n        return -1;\n    }\n\n    state = sending_welcome;\n    return rc;\n}\n\nint zmq::curve_server_t::produce_welcome (msg_t *msg_)\n{\n    uint8_t cookie_nonce[crypto_secretbox_NONCEBYTES];\n    std::vector<uint8_t, secure_allocator_t<uint8_t> > cookie_plaintext (\n      crypto_secretbox_ZEROBYTES + 64);\n    uint8_t cookie_ciphertext[crypto_secretbox_BOXZEROBYTES + 80];\n\n    //  Create full nonce for encryption\n    //  8-byte prefix plus 16-byte random nonce\n    memset (cookie_nonce, 0, crypto_secretbox_NONCEBYTES);\n    memcpy (cookie_nonce, \"COOKIE--\", 8);\n    randombytes (cookie_nonce + 8, 16);\n\n    //  Generate cookie = Box [C' + s'](t)\n    std::fill (cookie_plaintext.begin (),\n               cookie_plaintext.begin () + crypto_secretbox_ZEROBYTES, 0);\n    memcpy (&cookie_plaintext[crypto_secretbox_ZEROBYTES], _cn_client, 32);\n    memcpy (&cookie_plaintext[crypto_secretbox_ZEROBYTES + 32], _cn_secret, 32);\n\n    //  Generate fresh cookie key\n    memset (_cookie_key, 0, crypto_secretbox_KEYBYTES);\n    randombytes (_cookie_key, crypto_secretbox_KEYBYTES);\n\n    //  Encrypt using symmetric cookie key\n    int rc =\n      crypto_secretbox (cookie_ciphertext, &cookie_plaintext[0],\n                        cookie_plaintext.size (), cookie_nonce, _cookie_key);\n    zmq_assert (rc == 0);\n\n    uint8_t welcome_nonce[crypto_box_NONCEBYTES];\n    std::vector<uint8_t, secure_allocator_t<uint8_t> > welcome_plaintext (\n      crypto_box_ZEROBYTES + 128);\n    uint8_t welcome_ciphertext[crypto_box_BOXZEROBYTES + 144];\n\n    //  Create full nonce for encryption\n    //  8-byte prefix plus 16-byte random nonce\n    memset (welcome_nonce, 0, crypto_box_NONCEBYTES);\n    memcpy (welcome_nonce, \"WELCOME-\", 8);\n    randombytes (welcome_nonce + 8, crypto_box_NONCEBYTES - 8);\n\n    //  Create 144-byte Box [S' + cookie](S->C')\n    std::fill (welcome_plaintext.begin (),\n               welcome_plaintext.begin () + crypto_box_ZEROBYTES, 0);\n    memcpy (&welcome_plaintext[crypto_box_ZEROBYTES], _cn_public, 32);\n    memcpy (&welcome_plaintext[crypto_box_ZEROBYTES + 32], cookie_nonce + 8,\n            16);\n    memcpy (&welcome_plaintext[crypto_box_ZEROBYTES + 48],\n            cookie_ciphertext + crypto_secretbox_BOXZEROBYTES, 80);\n\n    rc = crypto_box (welcome_ciphertext, &welcome_plaintext[0],\n                     welcome_plaintext.size (), welcome_nonce, _cn_client,\n                     _secret_key);\n\n    //  TODO I think we should change this back to zmq_assert (rc == 0);\n    //  as it was before https://github.com/zeromq/libzmq/pull/1832\n    //  The reason given there was that secret_key might be 0ed.\n    //  But if it were, we would never get this far, since we could\n    //  not have opened the client's hello box with a 0ed key.\n\n    if (rc == -1)\n        return -1;\n\n    rc = msg_->init_size (168);\n    errno_assert (rc == 0);\n\n    uint8_t *const welcome = static_cast<uint8_t *> (msg_->data ());\n    memcpy (welcome, \"\\x07WELCOME\", 8);\n    memcpy (welcome + 8, welcome_nonce + 8, 16);\n    memcpy (welcome + 24, welcome_ciphertext + crypto_box_BOXZEROBYTES, 144);\n\n    return 0;\n}\n\nint zmq::curve_server_t::process_initiate (msg_t *msg_)\n{\n    int rc = check_basic_command_structure (msg_);\n    if (rc == -1)\n        return -1;\n\n    const size_t size = msg_->size ();\n    const uint8_t *initiate = static_cast<uint8_t *> (msg_->data ());\n\n    if (size < 9 || memcmp (initiate, \"\\x08INITIATE\", 9)) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n\n    if (size < 257) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);\n        errno = EPROTO;\n        return -1;\n    }\n\n    uint8_t cookie_nonce[crypto_secretbox_NONCEBYTES];\n    uint8_t cookie_plaintext[crypto_secretbox_ZEROBYTES + 64];\n    uint8_t cookie_box[crypto_secretbox_BOXZEROBYTES + 80];\n\n    //  Open Box [C' + s'](t)\n    memset (cookie_box, 0, crypto_secretbox_BOXZEROBYTES);\n    memcpy (cookie_box + crypto_secretbox_BOXZEROBYTES, initiate + 25, 80);\n\n    memcpy (cookie_nonce, \"COOKIE--\", 8);\n    memcpy (cookie_nonce + 8, initiate + 9, 16);\n\n    rc = crypto_secretbox_open (cookie_plaintext, cookie_box, sizeof cookie_box,\n                                cookie_nonce, _cookie_key);\n    if (rc != 0) {\n        // CURVE I: cannot open client INITIATE cookie\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n        errno = EPROTO;\n        return -1;\n    }\n\n    //  Check cookie plain text is as expected [C' + s']\n    if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, _cn_client, 32)\n        || memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32,\n                   _cn_secret, 32)) {\n        // TODO this case is very hard to test, as it would require a modified\n        //  client that knows the server's secret temporary cookie key\n\n        // CURVE I: client INITIATE cookie is not valid\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n        errno = EPROTO;\n        return -1;\n    }\n\n    const size_t clen = (size - 113) + crypto_box_BOXZEROBYTES;\n\n    uint8_t initiate_nonce[crypto_box_NONCEBYTES];\n    std::vector<uint8_t, secure_allocator_t<uint8_t> > initiate_plaintext (\n      crypto_box_ZEROBYTES + clen);\n    std::vector<uint8_t> initiate_box (crypto_box_BOXZEROBYTES + clen);\n\n    //  Open Box [C + vouch + metadata](C'->S')\n    std::fill (initiate_box.begin (),\n               initiate_box.begin () + crypto_box_BOXZEROBYTES, 0);\n    memcpy (&initiate_box[crypto_box_BOXZEROBYTES], initiate + 113,\n            clen - crypto_box_BOXZEROBYTES);\n\n    memcpy (initiate_nonce, \"CurveZMQINITIATE\", 16);\n    memcpy (initiate_nonce + 16, initiate + 105, 8);\n    set_peer_nonce (get_uint64 (initiate + 105));\n\n    const uint8_t *client_key = &initiate_plaintext[crypto_box_ZEROBYTES];\n\n    rc = crypto_box_open (&initiate_plaintext[0], &initiate_box[0], clen,\n                          initiate_nonce, _cn_client, _cn_secret);\n    if (rc != 0) {\n        // CURVE I: cannot open client INITIATE\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n        errno = EPROTO;\n        return -1;\n    }\n\n    uint8_t vouch_nonce[crypto_box_NONCEBYTES];\n    std::vector<uint8_t, secure_allocator_t<uint8_t> > vouch_plaintext (\n      crypto_box_ZEROBYTES + 64);\n    uint8_t vouch_box[crypto_box_BOXZEROBYTES + 80];\n\n    //  Open Box Box [C',S](C->S') and check contents\n    memset (vouch_box, 0, crypto_box_BOXZEROBYTES);\n    memcpy (vouch_box + crypto_box_BOXZEROBYTES,\n            &initiate_plaintext[crypto_box_ZEROBYTES + 48], 80);\n\n    memset (vouch_nonce, 0, crypto_box_NONCEBYTES);\n    memcpy (vouch_nonce, \"VOUCH---\", 8);\n    memcpy (vouch_nonce + 8, &initiate_plaintext[crypto_box_ZEROBYTES + 32],\n            16);\n\n    rc = crypto_box_open (&vouch_plaintext[0], vouch_box, sizeof vouch_box,\n                          vouch_nonce, client_key, _cn_secret);\n    if (rc != 0) {\n        // CURVE I: cannot open client INITIATE vouch\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n        errno = EPROTO;\n        return -1;\n    }\n\n    //  What we decrypted must be the client's short-term public key\n    if (memcmp (&vouch_plaintext[crypto_box_ZEROBYTES], _cn_client, 32)) {\n        // TODO this case is very hard to test, as it would require a modified\n        //  client that knows the server's secret short-term key\n\n        // CURVE I: invalid handshake from client (public key)\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE);\n        errno = EPROTO;\n        return -1;\n    }\n\n    //  Precompute connection secret from client key\n    rc = crypto_box_beforenm (get_writable_precom_buffer (), _cn_client,\n                              _cn_secret);\n    zmq_assert (rc == 0);\n\n    //  Given this is a backward-incompatible change, it's behind a socket\n    //  option disabled by default.\n    if (zap_required () || !options.zap_enforce_domain) {\n        //  Use ZAP protocol (RFC 27) to authenticate the user.\n        rc = session->zap_connect ();\n        if (rc == 0) {\n            send_zap_request (client_key);\n            state = waiting_for_zap_reply;\n\n            //  TODO actually, it is quite unlikely that we can read the ZAP\n            //  reply already, but removing this has some strange side-effect\n            //  (probably because the pipe's in_active flag is true until a read\n            //  is attempted)\n            if (-1 == receive_and_process_zap_reply ())\n                return -1;\n        } else if (!options.zap_enforce_domain) {\n            //  This supports the Stonehouse pattern (encryption without\n            //  authentication) in legacy mode (domain set but no handler).\n            state = sending_ready;\n        } else {\n            session->get_socket ()->event_handshake_failed_no_detail (\n              session->get_endpoint (), EFAULT);\n            return -1;\n        }\n    } else {\n        //  This supports the Stonehouse pattern (encryption without authentication).\n        state = sending_ready;\n    }\n\n    return parse_metadata (&initiate_plaintext[crypto_box_ZEROBYTES + 128],\n                           clen - crypto_box_ZEROBYTES - 128);\n}\n\nint zmq::curve_server_t::produce_ready (msg_t *msg_)\n{\n    const size_t metadata_length = basic_properties_len ();\n    uint8_t ready_nonce[crypto_box_NONCEBYTES];\n\n    std::vector<uint8_t, secure_allocator_t<uint8_t> > ready_plaintext (\n      crypto_box_ZEROBYTES + metadata_length);\n\n    //  Create Box [metadata](S'->C')\n    std::fill (ready_plaintext.begin (),\n               ready_plaintext.begin () + crypto_box_ZEROBYTES, 0);\n    uint8_t *ptr = &ready_plaintext[crypto_box_ZEROBYTES];\n\n    ptr += add_basic_properties (ptr, metadata_length);\n    const size_t mlen = ptr - &ready_plaintext[0];\n\n    memcpy (ready_nonce, \"CurveZMQREADY---\", 16);\n    put_uint64 (ready_nonce + 16, get_and_inc_nonce ());\n\n    std::vector<uint8_t> ready_box (crypto_box_BOXZEROBYTES + 16\n                                    + metadata_length);\n\n    int rc = crypto_box_afternm (&ready_box[0], &ready_plaintext[0], mlen,\n                                 ready_nonce, get_precom_buffer ());\n    zmq_assert (rc == 0);\n\n    rc = msg_->init_size (14 + mlen - crypto_box_BOXZEROBYTES);\n    errno_assert (rc == 0);\n\n    uint8_t *ready = static_cast<uint8_t *> (msg_->data ());\n\n    memcpy (ready, \"\\x05READY\", 6);\n    //  Short nonce, prefixed by \"CurveZMQREADY---\"\n    memcpy (ready + 6, ready_nonce + 16, 8);\n    //  Box [metadata](S'->C')\n    memcpy (ready + 14, &ready_box[crypto_box_BOXZEROBYTES],\n            mlen - crypto_box_BOXZEROBYTES);\n\n    return 0;\n}\n\nint zmq::curve_server_t::produce_error (msg_t *msg_) const\n{\n    const size_t expected_status_code_length = 3;\n    zmq_assert (status_code.length () == 3);\n    const int rc = msg_->init_size (6 + 1 + expected_status_code_length);\n    zmq_assert (rc == 0);\n    char *msg_data = static_cast<char *> (msg_->data ());\n    memcpy (msg_data, \"\\5ERROR\", 6);\n    msg_data[6] = expected_status_code_length;\n    memcpy (msg_data + 7, status_code.c_str (), expected_status_code_length);\n    return 0;\n}\n\nvoid zmq::curve_server_t::send_zap_request (const uint8_t *key_)\n{\n    zap_client_t::send_zap_request (\"CURVE\", 5, key_,\n                                    crypto_box_PUBLICKEYBYTES);\n}\n\n#endif\n"
  },
  {
    "path": "src/curve_server.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_CURVE_SERVER_HPP_INCLUDED__\n#define __ZMQ_CURVE_SERVER_HPP_INCLUDED__\n\n#ifdef ZMQ_HAVE_CURVE\n\n#include \"curve_mechanism_base.hpp\"\n#include \"options.hpp\"\n#include \"zap_client.hpp\"\n\nnamespace zmq\n{\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4250)\n#endif\nclass curve_server_t ZMQ_FINAL : public zap_client_common_handshake_t,\n                                 public curve_mechanism_base_t\n{\n  public:\n    curve_server_t (session_base_t *session_,\n                    const std::string &peer_address_,\n                    const options_t &options_,\n                    const bool downgrade_sub_);\n    ~curve_server_t ();\n\n    // mechanism implementation\n    int next_handshake_command (msg_t *msg_);\n    int process_handshake_command (msg_t *msg_);\n    int encode (msg_t *msg_);\n    int decode (msg_t *msg_);\n\n  private:\n    //  Our secret key (s)\n    uint8_t _secret_key[crypto_box_SECRETKEYBYTES];\n\n    //  Our short-term public key (S')\n    uint8_t _cn_public[crypto_box_PUBLICKEYBYTES];\n\n    //  Our short-term secret key (s')\n    uint8_t _cn_secret[crypto_box_SECRETKEYBYTES];\n\n    //  Client's short-term public key (C')\n    uint8_t _cn_client[crypto_box_PUBLICKEYBYTES];\n\n    //  Key used to produce cookie\n    uint8_t _cookie_key[crypto_secretbox_KEYBYTES];\n\n    int process_hello (msg_t *msg_);\n    int produce_welcome (msg_t *msg_);\n    int process_initiate (msg_t *msg_);\n    int produce_ready (msg_t *msg_);\n    int produce_error (msg_t *msg_) const;\n\n    void send_zap_request (const uint8_t *key_);\n};\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/dbuffer.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_DBUFFER_HPP_INCLUDED__\n#define __ZMQ_DBUFFER_HPP_INCLUDED__\n\n#include <stdlib.h>\n#include <stddef.h>\n#include <algorithm>\n\n#include \"mutex.hpp\"\n#include \"msg.hpp\"\n\nnamespace zmq\n{\n//  dbuffer is a single-producer single-consumer double-buffer\n//  implementation.\n//\n//  The producer writes to a back buffer and then tries to swap\n//  pointers between the back and front buffers. If it fails,\n//  due to the consumer reading from the front buffer, it just\n//  gives up, which is ok since writes are many and redundant.\n//\n//  The reader simply reads from the front buffer.\n//\n//  has_msg keeps track of whether there has been a not yet read\n//  value written, it is used by ypipe_conflate to mimic ypipe\n//  functionality regarding a reader being asleep\n\ntemplate <typename T> class dbuffer_t;\n\ntemplate <> class dbuffer_t<msg_t>\n{\n  public:\n    dbuffer_t () : _back (&_storage[0]), _front (&_storage[1]), _has_msg (false)\n    {\n        _back->init ();\n        _front->init ();\n    }\n\n    ~dbuffer_t ()\n    {\n        _back->close ();\n        _front->close ();\n    }\n\n    void write (const msg_t &value_)\n    {\n        zmq_assert (value_.check ());\n        *_back = value_;\n\n        zmq_assert (_back->check ());\n\n        if (_sync.try_lock ()) {\n            _front->move (*_back);\n            _has_msg = true;\n\n            _sync.unlock ();\n        }\n    }\n\n    bool read (msg_t *value_)\n    {\n        if (!value_)\n            return false;\n\n        {\n            scoped_lock_t lock (_sync);\n            if (!_has_msg)\n                return false;\n\n            zmq_assert (_front->check ());\n\n            *value_ = *_front;\n            _front->init (); // avoid double free\n\n            _has_msg = false;\n            return true;\n        }\n    }\n\n\n    bool check_read ()\n    {\n        scoped_lock_t lock (_sync);\n\n        return _has_msg;\n    }\n\n    bool probe (bool (*fn_) (const msg_t &))\n    {\n        scoped_lock_t lock (_sync);\n        return (*fn_) (*_front);\n    }\n\n\n  private:\n    msg_t _storage[2];\n    msg_t *_back, *_front;\n\n    mutex_t _sync;\n    bool _has_msg;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (dbuffer_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/dealer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"dealer.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n\nzmq::dealer_t::dealer_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_), _probe_router (false)\n{\n    options.type = ZMQ_DEALER;\n    options.can_send_hello_msg = true;\n    options.can_recv_hiccup_msg = true;\n}\n\nzmq::dealer_t::~dealer_t ()\n{\n}\n\nvoid zmq::dealer_t::xattach_pipe (pipe_t *pipe_,\n                                  bool subscribe_to_all_,\n                                  bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_);\n\n    if (_probe_router) {\n        msg_t probe_msg;\n        int rc = probe_msg.init ();\n        errno_assert (rc == 0);\n\n        rc = pipe_->write (&probe_msg);\n        // zmq_assert (rc) is not applicable here, since it is not a bug.\n        LIBZMQ_UNUSED (rc);\n\n        pipe_->flush ();\n\n        rc = probe_msg.close ();\n        errno_assert (rc == 0);\n    }\n\n    _fq.attach (pipe_);\n    _lb.attach (pipe_);\n}\n\nint zmq::dealer_t::xsetsockopt (int option_,\n                                const void *optval_,\n                                size_t optvallen_)\n{\n    const bool is_int = (optvallen_ == sizeof (int));\n    int value = 0;\n    if (is_int)\n        memcpy (&value, optval_, sizeof (int));\n\n    switch (option_) {\n        case ZMQ_PROBE_ROUTER:\n            if (is_int && value >= 0) {\n                _probe_router = (value != 0);\n                return 0;\n            }\n            break;\n\n        default:\n            break;\n    }\n\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::dealer_t::xsend (msg_t *msg_)\n{\n    return sendpipe (msg_, NULL);\n}\n\nint zmq::dealer_t::xrecv (msg_t *msg_)\n{\n    return recvpipe (msg_, NULL);\n}\n\nbool zmq::dealer_t::xhas_in ()\n{\n    return _fq.has_in ();\n}\n\nbool zmq::dealer_t::xhas_out ()\n{\n    return _lb.has_out ();\n}\n\nvoid zmq::dealer_t::xread_activated (pipe_t *pipe_)\n{\n    _fq.activated (pipe_);\n}\n\nvoid zmq::dealer_t::xwrite_activated (pipe_t *pipe_)\n{\n    _lb.activated (pipe_);\n}\n\nvoid zmq::dealer_t::xpipe_terminated (pipe_t *pipe_)\n{\n    _fq.pipe_terminated (pipe_);\n    _lb.pipe_terminated (pipe_);\n}\n\nint zmq::dealer_t::sendpipe (msg_t *msg_, pipe_t **pipe_)\n{\n    return _lb.sendpipe (msg_, pipe_);\n}\n\nint zmq::dealer_t::recvpipe (msg_t *msg_, pipe_t **pipe_)\n{\n    return _fq.recvpipe (msg_, pipe_);\n}\n"
  },
  {
    "path": "src/dealer.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_DEALER_HPP_INCLUDED__\n#define __ZMQ_DEALER_HPP_INCLUDED__\n\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n#include \"fq.hpp\"\n#include \"lb.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass pipe_t;\nclass io_thread_t;\nclass socket_base_t;\n\nclass dealer_t : public socket_base_t\n{\n  public:\n    dealer_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~dealer_t () ZMQ_OVERRIDE;\n\n  protected:\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_) ZMQ_FINAL;\n    int xsetsockopt (int option_,\n                     const void *optval_,\n                     size_t optvallen_) ZMQ_OVERRIDE;\n    int xsend (zmq::msg_t *msg_) ZMQ_OVERRIDE;\n    int xrecv (zmq::msg_t *msg_) ZMQ_OVERRIDE;\n    bool xhas_in () ZMQ_OVERRIDE;\n    bool xhas_out () ZMQ_OVERRIDE;\n    void xread_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    void xwrite_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    void xpipe_terminated (zmq::pipe_t *pipe_) ZMQ_OVERRIDE;\n\n    //  Send and recv - knowing which pipe was used.\n    int sendpipe (zmq::msg_t *msg_, zmq::pipe_t **pipe_);\n    int recvpipe (zmq::msg_t *msg_, zmq::pipe_t **pipe_);\n\n  private:\n    //  Messages are fair-queued from inbound pipes. And load-balanced to\n    //  the outbound pipes.\n    fq_t _fq;\n    lb_t _lb;\n\n    // if true, send an empty message to every connected router peer\n    bool _probe_router;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (dealer_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/decoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_DECODER_HPP_INCLUDED__\n#define __ZMQ_DECODER_HPP_INCLUDED__\n\n#include <algorithm>\n#include <cstddef>\n#include <cstring>\n\n#include \"decoder_allocators.hpp\"\n#include \"err.hpp\"\n#include \"i_decoder.hpp\"\n#include \"stdint.hpp\"\n\nnamespace zmq\n{\n//  Helper base class for decoders that know the amount of data to read\n//  in advance at any moment. Knowing the amount in advance is a property\n//  of the protocol used. 0MQ framing protocol is based size-prefixed\n//  paradigm, which qualifies it to be parsed by this class.\n//  On the other hand, XML-based transports (like XMPP or SOAP) don't allow\n//  for knowing the size of data to read in advance and should use different\n//  decoding algorithms.\n//\n//  This class implements the state machine that parses the incoming buffer.\n//  Derived class should implement individual state machine actions.\n//\n//  Buffer management is done by an allocator policy.\ntemplate <typename T, typename A = c_single_allocator>\nclass decoder_base_t : public i_decoder\n{\n  public:\n    explicit decoder_base_t (const size_t buf_size_) :\n        _next (NULL), _read_pos (NULL), _to_read (0), _allocator (buf_size_)\n    {\n        _buf = _allocator.allocate ();\n    }\n\n    ~decoder_base_t () ZMQ_OVERRIDE { _allocator.deallocate (); }\n\n    //  Returns a buffer to be filled with binary data.\n    void get_buffer (unsigned char **data_, std::size_t *size_) ZMQ_FINAL\n    {\n        _buf = _allocator.allocate ();\n\n        //  If we are expected to read large message, we'll opt for zero-\n        //  copy, i.e. we'll ask caller to fill the data directly to the\n        //  message. Note that subsequent read(s) are non-blocking, thus\n        //  each single read reads at most SO_RCVBUF bytes at once not\n        //  depending on how large is the chunk returned from here.\n        //  As a consequence, large messages being received won't block\n        //  other engines running in the same I/O thread for excessive\n        //  amounts of time.\n        if (_to_read >= _allocator.size ()) {\n            *data_ = _read_pos;\n            *size_ = _to_read;\n            return;\n        }\n\n        *data_ = _buf;\n        *size_ = _allocator.size ();\n    }\n\n    //  Processes the data in the buffer previously allocated using\n    //  get_buffer function. size_ argument specifies number of bytes\n    //  actually filled into the buffer. Function returns 1 when the\n    //  whole message was decoded or 0 when more data is required.\n    //  On error, -1 is returned and errno set accordingly.\n    //  Number of bytes processed is returned in bytes_used_.\n    int decode (const unsigned char *data_,\n                std::size_t size_,\n                std::size_t &bytes_used_) ZMQ_FINAL\n    {\n        bytes_used_ = 0;\n\n        //  In case of zero-copy simply adjust the pointers, no copying\n        //  is required. Also, run the state machine in case all the data\n        //  were processed.\n        if (data_ == _read_pos) {\n            zmq_assert (size_ <= _to_read);\n            _read_pos += size_;\n            _to_read -= size_;\n            bytes_used_ = size_;\n\n            while (!_to_read) {\n                const int rc =\n                  (static_cast<T *> (this)->*_next) (data_ + bytes_used_);\n                if (rc != 0)\n                    return rc;\n            }\n            return 0;\n        }\n\n        while (bytes_used_ < size_) {\n            //  Copy the data from buffer to the message.\n            const size_t to_copy = std::min (_to_read, size_ - bytes_used_);\n            // Only copy when destination address is different from the\n            // current address in the buffer.\n            if (_read_pos != data_ + bytes_used_) {\n                memcpy (_read_pos, data_ + bytes_used_, to_copy);\n            }\n\n            _read_pos += to_copy;\n            _to_read -= to_copy;\n            bytes_used_ += to_copy;\n            //  Try to get more space in the message to fill in.\n            //  If none is available, return.\n            while (_to_read == 0) {\n                // pass current address in the buffer\n                const int rc =\n                  (static_cast<T *> (this)->*_next) (data_ + bytes_used_);\n                if (rc != 0)\n                    return rc;\n            }\n        }\n\n        return 0;\n    }\n\n    void resize_buffer (std::size_t new_size_) ZMQ_FINAL\n    {\n        _allocator.resize (new_size_);\n    }\n\n  protected:\n    //  Prototype of state machine action. Action should return false if\n    //  it is unable to push the data to the system.\n    typedef int (T::*step_t) (unsigned char const *);\n\n    //  This function should be called from derived class to read data\n    //  from the buffer and schedule next state machine action.\n    void next_step (void *read_pos_, std::size_t to_read_, step_t next_)\n    {\n        _read_pos = static_cast<unsigned char *> (read_pos_);\n        _to_read = to_read_;\n        _next = next_;\n    }\n\n    A &get_allocator () { return _allocator; }\n\n  private:\n    //  Next step. If set to NULL, it means that associated data stream\n    //  is dead. Note that there can be still data in the process in such\n    //  case.\n    step_t _next;\n\n    //  Where to store the read data.\n    unsigned char *_read_pos;\n\n    //  How much data to read before taking next step.\n    std::size_t _to_read;\n\n    //  The duffer for data to decode.\n    A _allocator;\n    unsigned char *_buf;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (decoder_base_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/decoder_allocators.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"decoder_allocators.hpp\"\n\n#include \"msg.hpp\"\n\nzmq::shared_message_memory_allocator::shared_message_memory_allocator (\n  std::size_t bufsize_) :\n    _buf (NULL),\n    _buf_size (0),\n    _max_size (bufsize_),\n    _msg_content (NULL),\n    _max_counters ((_max_size + msg_t::max_vsm_size - 1) / msg_t::max_vsm_size)\n{\n}\n\nzmq::shared_message_memory_allocator::shared_message_memory_allocator (\n  std::size_t bufsize_, std::size_t max_messages_) :\n    _buf (NULL),\n    _buf_size (0),\n    _max_size (bufsize_),\n    _msg_content (NULL),\n    _max_counters (max_messages_)\n{\n}\n\nzmq::shared_message_memory_allocator::~shared_message_memory_allocator ()\n{\n    deallocate ();\n}\n\nunsigned char *zmq::shared_message_memory_allocator::allocate ()\n{\n    if (_buf) {\n        // release reference count to couple lifetime to messages\n        zmq::atomic_counter_t *c =\n          reinterpret_cast<zmq::atomic_counter_t *> (_buf);\n\n        // if refcnt drops to 0, there are no message using the buffer\n        // because either all messages have been closed or only vsm-messages\n        // were created\n        if (c->sub (1)) {\n            // buffer is still in use as message data. \"Release\" it and create a new one\n            // release pointer because we are going to create a new buffer\n            release ();\n        }\n    }\n\n    // if buf != NULL it is not used by any message so we can re-use it for the next run\n    if (!_buf) {\n        // allocate memory for reference counters together with reception buffer\n        std::size_t const allocationsize =\n          _max_size + sizeof (zmq::atomic_counter_t)\n          + _max_counters * sizeof (zmq::msg_t::content_t);\n\n        _buf = static_cast<unsigned char *> (std::malloc (allocationsize));\n        alloc_assert (_buf);\n\n        new (_buf) atomic_counter_t (1);\n    } else {\n        // release reference count to couple lifetime to messages\n        zmq::atomic_counter_t *c =\n          reinterpret_cast<zmq::atomic_counter_t *> (_buf);\n        c->set (1);\n    }\n\n    _buf_size = _max_size;\n    _msg_content = reinterpret_cast<zmq::msg_t::content_t *> (\n      _buf + sizeof (atomic_counter_t) + _max_size);\n    return _buf + sizeof (zmq::atomic_counter_t);\n}\n\nvoid zmq::shared_message_memory_allocator::deallocate ()\n{\n    zmq::atomic_counter_t *c = reinterpret_cast<zmq::atomic_counter_t *> (_buf);\n    if (_buf && !c->sub (1)) {\n        c->~atomic_counter_t ();\n        std::free (_buf);\n    }\n    clear ();\n}\n\nunsigned char *zmq::shared_message_memory_allocator::release ()\n{\n    unsigned char *b = _buf;\n    clear ();\n    return b;\n}\n\nvoid zmq::shared_message_memory_allocator::clear ()\n{\n    _buf = NULL;\n    _buf_size = 0;\n    _msg_content = NULL;\n}\n\nvoid zmq::shared_message_memory_allocator::inc_ref ()\n{\n    (reinterpret_cast<zmq::atomic_counter_t *> (_buf))->add (1);\n}\n\nvoid zmq::shared_message_memory_allocator::call_dec_ref (void *, void *hint_)\n{\n    zmq_assert (hint_);\n    unsigned char *buf = static_cast<unsigned char *> (hint_);\n    zmq::atomic_counter_t *c = reinterpret_cast<zmq::atomic_counter_t *> (buf);\n\n    if (!c->sub (1)) {\n        c->~atomic_counter_t ();\n        std::free (buf);\n        buf = NULL;\n    }\n}\n\n\nstd::size_t zmq::shared_message_memory_allocator::size () const\n{\n    return _buf_size;\n}\n\nunsigned char *zmq::shared_message_memory_allocator::data ()\n{\n    return _buf + sizeof (zmq::atomic_counter_t);\n}\n"
  },
  {
    "path": "src/decoder_allocators.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_DECODER_ALLOCATORS_HPP_INCLUDED__\n#define __ZMQ_DECODER_ALLOCATORS_HPP_INCLUDED__\n\n#include <cstddef>\n#include <cstdlib>\n\n#include \"atomic_counter.hpp\"\n#include \"msg.hpp\"\n#include \"err.hpp\"\n\nnamespace zmq\n{\n// Static buffer policy.\nclass c_single_allocator\n{\n  public:\n    explicit c_single_allocator (std::size_t bufsize_) :\n        _buf_size (bufsize_),\n        _buf (static_cast<unsigned char *> (std::malloc (_buf_size)))\n    {\n        alloc_assert (_buf);\n    }\n\n    ~c_single_allocator () { std::free (_buf); }\n\n    unsigned char *allocate () { return _buf; }\n\n    void deallocate () {}\n\n    std::size_t size () const { return _buf_size; }\n\n    //  This buffer is fixed, size must not be changed\n    void resize (std::size_t new_size_) { LIBZMQ_UNUSED (new_size_); }\n\n  private:\n    std::size_t _buf_size;\n    unsigned char *_buf;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (c_single_allocator)\n};\n\n// This allocator allocates a reference counted buffer which is used by v2_decoder_t\n// to use zero-copy msg::init_data to create messages with memory from this buffer as\n// data storage.\n//\n// The buffer is allocated with a reference count of 1 to make sure that is is alive while\n// decoding messages. Otherwise, it is possible that e.g. the first message increases the count\n// from zero to one, gets passed to the user application, processed in the user thread and deleted\n// which would then deallocate the buffer. The drawback is that the buffer may be allocated longer\n// than necessary because it is only deleted when allocate is called the next time.\nclass shared_message_memory_allocator\n{\n  public:\n    explicit shared_message_memory_allocator (std::size_t bufsize_);\n\n    // Create an allocator for a maximum number of messages\n    shared_message_memory_allocator (std::size_t bufsize_,\n                                     std::size_t max_messages_);\n\n    ~shared_message_memory_allocator ();\n\n    // Allocate a new buffer\n    //\n    // This releases the current buffer to be bound to the lifetime of the messages\n    // created on this buffer.\n    unsigned char *allocate ();\n\n    // force deallocation of buffer.\n    void deallocate ();\n\n    // Give up ownership of the buffer. The buffer's lifetime is now coupled to\n    // the messages constructed on top of it.\n    unsigned char *release ();\n\n    void inc_ref ();\n\n    static void call_dec_ref (void *, void *hint_);\n\n    std::size_t size () const;\n\n    // Return pointer to the first message data byte.\n    unsigned char *data ();\n\n    // Return pointer to the first byte of the buffer.\n    unsigned char *buffer () { return _buf; }\n\n    void resize (std::size_t new_size_) { _buf_size = new_size_; }\n\n    zmq::msg_t::content_t *provide_content () { return _msg_content; }\n\n    void advance_content () { _msg_content++; }\n\n  private:\n    void clear ();\n\n    unsigned char *_buf;\n    std::size_t _buf_size;\n    const std::size_t _max_size;\n    zmq::msg_t::content_t *_msg_content;\n    std::size_t _max_counters;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/devpoll.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"devpoll.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_DEVPOLL\n\n#include <sys/devpoll.h>\n#include <sys/time.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/ioctl.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <limits.h>\n#include <algorithm>\n\n#include \"devpoll.hpp\"\n#include \"err.hpp\"\n#include \"config.hpp\"\n#include \"i_poll_events.hpp\"\n\nzmq::devpoll_t::devpoll_t (const zmq::thread_ctx_t &ctx_) :\n    worker_poller_base_t (ctx_)\n{\n    devpoll_fd = open (\"/dev/poll\", O_RDWR);\n    errno_assert (devpoll_fd != -1);\n}\n\nzmq::devpoll_t::~devpoll_t ()\n{\n    //  Wait till the worker thread exits.\n    stop_worker ();\n\n    close (devpoll_fd);\n}\n\nvoid zmq::devpoll_t::devpoll_ctl (fd_t fd_, short events_)\n{\n    struct pollfd pfd = {fd_, events_, 0};\n    ssize_t rc = write (devpoll_fd, &pfd, sizeof pfd);\n    zmq_assert (rc == sizeof pfd);\n}\n\nzmq::devpoll_t::handle_t zmq::devpoll_t::add_fd (fd_t fd_,\n                                                 i_poll_events *reactor_)\n{\n    check_thread ();\n    //  If the file descriptor table is too small expand it.\n    fd_table_t::size_type sz = fd_table.size ();\n    if (sz <= (fd_table_t::size_type) fd_) {\n        fd_table.resize (fd_ + 1);\n        while (sz != (fd_table_t::size_type) (fd_ + 1)) {\n            fd_table[sz].valid = false;\n            ++sz;\n        }\n    }\n\n    zmq_assert (!fd_table[fd_].valid);\n\n    fd_table[fd_].events = 0;\n    fd_table[fd_].reactor = reactor_;\n    fd_table[fd_].valid = true;\n    fd_table[fd_].accepted = false;\n\n    devpoll_ctl (fd_, 0);\n    pending_list.push_back (fd_);\n\n    //  Increase the load metric of the thread.\n    adjust_load (1);\n\n    return fd_;\n}\n\nvoid zmq::devpoll_t::rm_fd (handle_t handle_)\n{\n    check_thread ();\n    zmq_assert (fd_table[handle_].valid);\n\n    devpoll_ctl (handle_, POLLREMOVE);\n    fd_table[handle_].valid = false;\n\n    //  Decrease the load metric of the thread.\n    adjust_load (-1);\n}\n\nvoid zmq::devpoll_t::set_pollin (handle_t handle_)\n{\n    check_thread ();\n    devpoll_ctl (handle_, POLLREMOVE);\n    fd_table[handle_].events |= POLLIN;\n    devpoll_ctl (handle_, fd_table[handle_].events);\n}\n\nvoid zmq::devpoll_t::reset_pollin (handle_t handle_)\n{\n    check_thread ();\n    devpoll_ctl (handle_, POLLREMOVE);\n    fd_table[handle_].events &= ~((short) POLLIN);\n    devpoll_ctl (handle_, fd_table[handle_].events);\n}\n\nvoid zmq::devpoll_t::set_pollout (handle_t handle_)\n{\n    check_thread ();\n    devpoll_ctl (handle_, POLLREMOVE);\n    fd_table[handle_].events |= POLLOUT;\n    devpoll_ctl (handle_, fd_table[handle_].events);\n}\n\nvoid zmq::devpoll_t::reset_pollout (handle_t handle_)\n{\n    check_thread ();\n    devpoll_ctl (handle_, POLLREMOVE);\n    fd_table[handle_].events &= ~((short) POLLOUT);\n    devpoll_ctl (handle_, fd_table[handle_].events);\n}\n\nvoid zmq::devpoll_t::stop ()\n{\n    check_thread ();\n}\n\nint zmq::devpoll_t::max_fds ()\n{\n    return -1;\n}\n\nvoid zmq::devpoll_t::loop ()\n{\n    while (true) {\n        struct pollfd ev_buf[max_io_events];\n        struct dvpoll poll_req;\n\n        for (pending_list_t::size_type i = 0; i < pending_list.size (); i++)\n            fd_table[pending_list[i]].accepted = true;\n        pending_list.clear ();\n\n        //  Execute any due timers.\n        int timeout = (int) execute_timers ();\n\n        if (get_load () == 0) {\n            if (timeout == 0)\n                break;\n\n            // TODO sleep for timeout\n            continue;\n        }\n\n        //  Wait for events.\n        //  On Solaris, we can retrieve no more then (OPEN_MAX - 1) events.\n        poll_req.dp_fds = &ev_buf[0];\n#if defined ZMQ_HAVE_SOLARIS\n        poll_req.dp_nfds = std::min ((int) max_io_events, OPEN_MAX - 1);\n#else\n        poll_req.dp_nfds = max_io_events;\n#endif\n        poll_req.dp_timeout = timeout ? timeout : -1;\n        int n = ioctl (devpoll_fd, DP_POLL, &poll_req);\n        if (n == -1 && errno == EINTR)\n            continue;\n        errno_assert (n != -1);\n\n        for (int i = 0; i < n; i++) {\n            fd_entry_t *fd_ptr = &fd_table[ev_buf[i].fd];\n            if (!fd_ptr->valid || !fd_ptr->accepted)\n                continue;\n            if (ev_buf[i].revents & (POLLERR | POLLHUP))\n                fd_ptr->reactor->in_event ();\n            if (!fd_ptr->valid || !fd_ptr->accepted)\n                continue;\n            if (ev_buf[i].revents & POLLOUT)\n                fd_ptr->reactor->out_event ();\n            if (!fd_ptr->valid || !fd_ptr->accepted)\n                continue;\n            if (ev_buf[i].revents & POLLIN)\n                fd_ptr->reactor->in_event ();\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/devpoll.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_DEVPOLL_HPP_INCLUDED__\n#define __ZMQ_DEVPOLL_HPP_INCLUDED__\n\n//  poller.hpp decides which polling mechanism to use.\n#include \"poller.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_DEVPOLL\n\n#include <vector>\n\n#include \"ctx.hpp\"\n#include \"fd.hpp\"\n#include \"thread.hpp\"\n#include \"poller_base.hpp\"\n\nnamespace zmq\n{\nstruct i_poll_events;\n\n//  Implements socket polling mechanism using the \"/dev/poll\" interface.\n\nclass devpoll_t ZMQ_FINAL : public worker_poller_base_t\n{\n  public:\n    typedef fd_t handle_t;\n\n    devpoll_t (const thread_ctx_t &ctx_);\n    ~devpoll_t () ZMQ_FINAL;\n\n    //  \"poller\" concept.\n    handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);\n    void rm_fd (handle_t handle_);\n    void set_pollin (handle_t handle_);\n    void reset_pollin (handle_t handle_);\n    void set_pollout (handle_t handle_);\n    void reset_pollout (handle_t handle_);\n    void stop ();\n\n    static int max_fds ();\n\n  private:\n    //  Main event loop.\n    void loop () ZMQ_FINAL;\n\n    //  File descriptor referring to \"/dev/poll\" pseudo-device.\n    fd_t devpoll_fd;\n\n    struct fd_entry_t\n    {\n        short events;\n        zmq::i_poll_events *reactor;\n        bool valid;\n        bool accepted;\n    };\n\n    typedef std::vector<fd_entry_t> fd_table_t;\n    fd_table_t fd_table;\n\n    typedef std::vector<fd_t> pending_list_t;\n    pending_list_t pending_list;\n\n    //  Pollset manipulation function.\n    void devpoll_ctl (fd_t fd_, short events_);\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (devpoll_t)\n};\n\ntypedef devpoll_t poller_t;\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/dgram.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"dgram.hpp\"\n#include \"pipe.hpp\"\n#include \"wire.hpp\"\n#include \"random.hpp\"\n#include \"likely.hpp\"\n#include \"err.hpp\"\n\nzmq::dgram_t::dgram_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_), _pipe (NULL), _more_out (false)\n{\n    options.type = ZMQ_DGRAM;\n    options.raw_socket = true;\n}\n\nzmq::dgram_t::~dgram_t ()\n{\n    zmq_assert (!_pipe);\n}\n\nvoid zmq::dgram_t::xattach_pipe (pipe_t *pipe_,\n                                 bool subscribe_to_all_,\n                                 bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_);\n\n    //  ZMQ_DGRAM socket can only be connected to a single peer.\n    //  The socket rejects any further connection requests.\n    if (_pipe == NULL)\n        _pipe = pipe_;\n    else\n        pipe_->terminate (false);\n}\n\nvoid zmq::dgram_t::xpipe_terminated (pipe_t *pipe_)\n{\n    if (pipe_ == _pipe) {\n        _pipe = NULL;\n    }\n}\n\nvoid zmq::dgram_t::xread_activated (pipe_t *)\n{\n    //  There's just one pipe. No lists of active and inactive pipes.\n    //  There's nothing to do here.\n}\n\nvoid zmq::dgram_t::xwrite_activated (pipe_t *)\n{\n    //  There's just one pipe. No lists of active and inactive pipes.\n    //  There's nothing to do here.\n}\n\nint zmq::dgram_t::xsend (msg_t *msg_)\n{\n    // If there's no out pipe, just drop it.\n    if (!_pipe) {\n        const int rc = msg_->close ();\n        errno_assert (rc == 0);\n        return -1;\n    }\n\n    //  If this is the first part of the message it's the ID of the\n    //  peer to send the message to.\n    if (!_more_out) {\n        if (!(msg_->flags () & msg_t::more)) {\n            errno = EINVAL;\n            return -1;\n        }\n    } else {\n        //  dgram messages are two part only, reject part if more is set\n        if (msg_->flags () & msg_t::more) {\n            errno = EINVAL;\n            return -1;\n        }\n    }\n\n    // Push the message into the pipe.\n    if (!_pipe->write (msg_)) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    if (!(msg_->flags () & msg_t::more))\n        _pipe->flush ();\n\n    // flip the more flag\n    _more_out = !_more_out;\n\n    //  Detach the message from the data buffer.\n    const int rc = msg_->init ();\n    errno_assert (rc == 0);\n\n    return 0;\n}\n\nint zmq::dgram_t::xrecv (msg_t *msg_)\n{\n    //  Deallocate old content of the message.\n    int rc = msg_->close ();\n    errno_assert (rc == 0);\n\n    if (!_pipe || !_pipe->read (msg_)) {\n        //  Initialise the output parameter to be a 0-byte message.\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n\n        errno = EAGAIN;\n        return -1;\n    }\n\n    return 0;\n}\n\nbool zmq::dgram_t::xhas_in ()\n{\n    if (!_pipe)\n        return false;\n\n    return _pipe->check_read ();\n}\n\nbool zmq::dgram_t::xhas_out ()\n{\n    if (!_pipe)\n        return false;\n\n    return _pipe->check_write ();\n}\n"
  },
  {
    "path": "src/dgram.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_DGRAM_HPP_INCLUDED__\n#define __ZMQ_DGRAM_HPP_INCLUDED__\n\n#include \"blob.hpp\"\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass pipe_t;\nclass io_thread_t;\n\nclass dgram_t ZMQ_FINAL : public socket_base_t\n{\n  public:\n    dgram_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~dgram_t ();\n\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xsend (zmq::msg_t *msg_);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    bool xhas_out ();\n    void xread_activated (zmq::pipe_t *pipe_);\n    void xwrite_activated (zmq::pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n\n  private:\n    zmq::pipe_t *_pipe;\n\n    //  If true, more outgoing message parts are expected.\n    bool _more_out;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (dgram_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/dish.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string.h>\n\n#include \"macros.hpp\"\n#include \"dish.hpp\"\n#include \"err.hpp\"\n\nzmq::dish_t::dish_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_, true), _has_message (false)\n{\n    options.type = ZMQ_DISH;\n\n    //  When socket is being closed down we don't want to wait till pending\n    //  subscription commands are sent to the wire.\n    options.linger.store (0);\n\n    const int rc = _message.init ();\n    errno_assert (rc == 0);\n}\n\nzmq::dish_t::~dish_t ()\n{\n    const int rc = _message.close ();\n    errno_assert (rc == 0);\n}\n\nvoid zmq::dish_t::xattach_pipe (pipe_t *pipe_,\n                                bool subscribe_to_all_,\n                                bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_);\n    _fq.attach (pipe_);\n    _dist.attach (pipe_);\n\n    //  Send all the cached subscriptions to the new upstream peer.\n    send_subscriptions (pipe_);\n}\n\nvoid zmq::dish_t::xread_activated (pipe_t *pipe_)\n{\n    _fq.activated (pipe_);\n}\n\nvoid zmq::dish_t::xwrite_activated (pipe_t *pipe_)\n{\n    _dist.activated (pipe_);\n}\n\nvoid zmq::dish_t::xpipe_terminated (pipe_t *pipe_)\n{\n    _fq.pipe_terminated (pipe_);\n    _dist.pipe_terminated (pipe_);\n}\n\nvoid zmq::dish_t::xhiccuped (pipe_t *pipe_)\n{\n    //  Send all the cached subscriptions to the hiccuped pipe.\n    send_subscriptions (pipe_);\n}\n\nint zmq::dish_t::xjoin (const char *group_)\n{\n    const std::string group = std::string (group_);\n\n    if (group.length () > ZMQ_GROUP_MAX_LENGTH) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    //  User cannot join same group twice\n    if (!_subscriptions.insert (group).second) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    msg_t msg;\n    int rc = msg.init_join ();\n    errno_assert (rc == 0);\n\n    rc = msg.set_group (group_);\n    errno_assert (rc == 0);\n\n    int err = 0;\n    rc = _dist.send_to_all (&msg);\n    if (rc != 0)\n        err = errno;\n    const int rc2 = msg.close ();\n    errno_assert (rc2 == 0);\n    if (rc != 0)\n        errno = err;\n    return rc;\n}\n\nint zmq::dish_t::xleave (const char *group_)\n{\n    const std::string group = std::string (group_);\n\n    if (group.length () > ZMQ_GROUP_MAX_LENGTH) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    if (0 == _subscriptions.erase (group)) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    msg_t msg;\n    int rc = msg.init_leave ();\n    errno_assert (rc == 0);\n\n    rc = msg.set_group (group_);\n    errno_assert (rc == 0);\n\n    int err = 0;\n    rc = _dist.send_to_all (&msg);\n    if (rc != 0)\n        err = errno;\n    const int rc2 = msg.close ();\n    errno_assert (rc2 == 0);\n    if (rc != 0)\n        errno = err;\n    return rc;\n}\n\nint zmq::dish_t::xsend (msg_t *msg_)\n{\n    LIBZMQ_UNUSED (msg_);\n    errno = ENOTSUP;\n    return -1;\n}\n\nbool zmq::dish_t::xhas_out ()\n{\n    //  Subscription can be added/removed anytime.\n    return true;\n}\n\nint zmq::dish_t::xrecv (msg_t *msg_)\n{\n    //  If there's already a message prepared by a previous call to zmq_poll,\n    //  return it straight ahead.\n    if (_has_message) {\n        const int rc = msg_->move (_message);\n        errno_assert (rc == 0);\n        _has_message = false;\n        return 0;\n    }\n\n    return xxrecv (msg_);\n}\n\nint zmq::dish_t::xxrecv (msg_t *msg_)\n{\n    do {\n        //  Get a message using fair queueing algorithm.\n        const int rc = _fq.recv (msg_);\n\n        //  If there's no message available, return immediately.\n        //  The same when error occurs.\n        if (rc != 0)\n            return -1;\n\n        //  Skip non matching messages\n    } while (0 == _subscriptions.count (std::string (msg_->group ())));\n\n    //  Found a matching message\n    return 0;\n}\n\nbool zmq::dish_t::xhas_in ()\n{\n    //  If there's already a message prepared by a previous call to zmq_poll,\n    //  return straight ahead.\n    if (_has_message)\n        return true;\n\n    const int rc = xxrecv (&_message);\n    if (rc != 0) {\n        errno_assert (errno == EAGAIN);\n        return false;\n    }\n\n    //  Matching message found\n    _has_message = true;\n    return true;\n}\n\nvoid zmq::dish_t::send_subscriptions (pipe_t *pipe_)\n{\n    for (subscriptions_t::iterator it = _subscriptions.begin (),\n                                   end = _subscriptions.end ();\n         it != end; ++it) {\n        msg_t msg;\n        int rc = msg.init_join ();\n        errno_assert (rc == 0);\n\n        rc = msg.set_group (it->c_str ());\n        errno_assert (rc == 0);\n\n        //  Send it to the pipe.\n        pipe_->write (&msg);\n    }\n\n    pipe_->flush ();\n}\n\nzmq::dish_session_t::dish_session_t (io_thread_t *io_thread_,\n                                     bool connect_,\n                                     socket_base_t *socket_,\n                                     const options_t &options_,\n                                     address_t *addr_) :\n    session_base_t (io_thread_, connect_, socket_, options_, addr_),\n    _state (group)\n{\n}\n\nzmq::dish_session_t::~dish_session_t ()\n{\n}\n\nint zmq::dish_session_t::push_msg (msg_t *msg_)\n{\n    if (_state == group) {\n        if ((msg_->flags () & msg_t::more) != msg_t::more) {\n            errno = EFAULT;\n            return -1;\n        }\n\n        if (msg_->size () > ZMQ_GROUP_MAX_LENGTH) {\n            errno = EFAULT;\n            return -1;\n        }\n\n        _group_msg = *msg_;\n        _state = body;\n\n        const int rc = msg_->init ();\n        errno_assert (rc == 0);\n        return 0;\n    }\n    const char *group_setting = msg_->group ();\n    int rc;\n    if (group_setting[0] != 0)\n        goto has_group;\n\n    //  Set the message group\n    rc = msg_->set_group (static_cast<char *> (_group_msg.data ()),\n                          _group_msg.size ());\n    errno_assert (rc == 0);\n\n    //  We set the group, so we don't need the group_msg anymore\n    rc = _group_msg.close ();\n    errno_assert (rc == 0);\nhas_group:\n    //  Thread safe socket doesn't support multipart messages\n    if ((msg_->flags () & msg_t::more) == msg_t::more) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    //  Push message to dish socket\n    rc = session_base_t::push_msg (msg_);\n\n    if (rc == 0)\n        _state = group;\n\n    return rc;\n}\n\nint zmq::dish_session_t::pull_msg (msg_t *msg_)\n{\n    int rc = session_base_t::pull_msg (msg_);\n\n    if (rc != 0)\n        return rc;\n\n    if (!msg_->is_join () && !msg_->is_leave ())\n        return rc;\n\n    const int group_length = static_cast<int> (strlen (msg_->group ()));\n\n    msg_t command;\n    int offset;\n\n    if (msg_->is_join ()) {\n        rc = command.init_size (group_length + 5);\n        errno_assert (rc == 0);\n        offset = 5;\n        memcpy (command.data (), \"\\4JOIN\", 5);\n    } else {\n        rc = command.init_size (group_length + 6);\n        errno_assert (rc == 0);\n        offset = 6;\n        memcpy (command.data (), \"\\5LEAVE\", 6);\n    }\n\n    command.set_flags (msg_t::command);\n    char *command_data = static_cast<char *> (command.data ());\n\n    //  Copy the group\n    memcpy (command_data + offset, msg_->group (), group_length);\n\n    //  Close the join message\n    rc = msg_->close ();\n    errno_assert (rc == 0);\n\n    *msg_ = command;\n\n    return 0;\n}\n\nvoid zmq::dish_session_t::reset ()\n{\n    session_base_t::reset ();\n    _state = group;\n}\n"
  },
  {
    "path": "src/dish.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_DISH_HPP_INCLUDED__\n#define __ZMQ_DISH_HPP_INCLUDED__\n\n#include <string>\n\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n#include \"dist.hpp\"\n#include \"fq.hpp\"\n#include \"msg.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass pipe_t;\nclass io_thread_t;\n\nclass dish_t ZMQ_FINAL : public socket_base_t\n{\n  public:\n    dish_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~dish_t ();\n\n  protected:\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xsend (zmq::msg_t *msg_);\n    bool xhas_out ();\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    void xread_activated (zmq::pipe_t *pipe_);\n    void xwrite_activated (zmq::pipe_t *pipe_);\n    void xhiccuped (pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n    int xjoin (const char *group_);\n    int xleave (const char *group_);\n\n  private:\n    int xxrecv (zmq::msg_t *msg_);\n\n    //  Send subscriptions to a pipe\n    void send_subscriptions (pipe_t *pipe_);\n\n    //  Fair queueing object for inbound pipes.\n    fq_t _fq;\n\n    //  Object for distributing the subscriptions upstream.\n    dist_t _dist;\n\n    //  The repository of subscriptions.\n    typedef std::set<std::string> subscriptions_t;\n    subscriptions_t _subscriptions;\n\n    //  If true, 'message' contains a matching message to return on the\n    //  next recv call.\n    bool _has_message;\n    msg_t _message;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (dish_t)\n};\n\nclass dish_session_t ZMQ_FINAL : public session_base_t\n{\n  public:\n    dish_session_t (zmq::io_thread_t *io_thread_,\n                    bool connect_,\n                    zmq::socket_base_t *socket_,\n                    const options_t &options_,\n                    address_t *addr_);\n    ~dish_session_t ();\n\n    //  Overrides of the functions from session_base_t.\n    int push_msg (msg_t *msg_);\n    int pull_msg (msg_t *msg_);\n    void reset ();\n\n  private:\n    enum\n    {\n        group,\n        body\n    } _state;\n\n    msg_t _group_msg;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (dish_session_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/dist.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"dist.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n#include \"likely.hpp\"\n\nzmq::dist_t::dist_t () :\n    _matching (0), _active (0), _eligible (0), _more (false)\n{\n}\n\nzmq::dist_t::~dist_t ()\n{\n    zmq_assert (_pipes.empty ());\n}\n\nvoid zmq::dist_t::attach (pipe_t *pipe_)\n{\n    //  If we are in the middle of sending a message, we'll add new pipe\n    //  into the list of eligible pipes. Otherwise we add it to the list\n    //  of active pipes.\n    if (_more) {\n        _pipes.push_back (pipe_);\n        _pipes.swap (_eligible, _pipes.size () - 1);\n        _eligible++;\n    } else {\n        _pipes.push_back (pipe_);\n        _pipes.swap (_active, _pipes.size () - 1);\n        _active++;\n        _eligible++;\n    }\n}\n\nbool zmq::dist_t::has_pipe (pipe_t *pipe_)\n{\n    std::size_t claimed_index = _pipes.index (pipe_);\n\n    // If pipe claims to be outside the available index space it can't be in the distributor.\n    if (claimed_index >= _pipes.size ()) {\n        return false;\n    }\n\n    return _pipes[claimed_index] == pipe_;\n}\n\nvoid zmq::dist_t::match (pipe_t *pipe_)\n{\n    //  If pipe is already matching do nothing.\n    if (_pipes.index (pipe_) < _matching)\n        return;\n\n    //  If the pipe isn't eligible, ignore it.\n    if (_pipes.index (pipe_) >= _eligible)\n        return;\n\n    //  Mark the pipe as matching.\n    _pipes.swap (_pipes.index (pipe_), _matching);\n    _matching++;\n}\n\nvoid zmq::dist_t::reverse_match ()\n{\n    const pipes_t::size_type prev_matching = _matching;\n\n    // Reset matching to 0\n    unmatch ();\n\n    // Mark all matching pipes as not matching and vice-versa.\n    // To do this, push all pipes that are eligible but not\n    // matched - i.e. between \"matching\" and \"eligible\" -\n    // to the beginning of the queue.\n    for (pipes_t::size_type i = prev_matching; i < _eligible; ++i) {\n        _pipes.swap (i, _matching++);\n    }\n}\n\nvoid zmq::dist_t::unmatch ()\n{\n    _matching = 0;\n}\n\nvoid zmq::dist_t::pipe_terminated (pipe_t *pipe_)\n{\n    //  Remove the pipe from the list; adjust number of matching, active and/or\n    //  eligible pipes accordingly.\n    if (_pipes.index (pipe_) < _matching) {\n        _pipes.swap (_pipes.index (pipe_), _matching - 1);\n        _matching--;\n    }\n    if (_pipes.index (pipe_) < _active) {\n        _pipes.swap (_pipes.index (pipe_), _active - 1);\n        _active--;\n    }\n    if (_pipes.index (pipe_) < _eligible) {\n        _pipes.swap (_pipes.index (pipe_), _eligible - 1);\n        _eligible--;\n    }\n\n    _pipes.erase (pipe_);\n}\n\nvoid zmq::dist_t::activated (pipe_t *pipe_)\n{\n    //  Move the pipe from passive to eligible state.\n    if (_eligible < _pipes.size ()) {\n        _pipes.swap (_pipes.index (pipe_), _eligible);\n        _eligible++;\n    }\n\n    //  If there's no message being sent at the moment, move it to\n    //  the active state.\n    if (!_more && _active < _pipes.size ()) {\n        _pipes.swap (_eligible - 1, _active);\n        _active++;\n    }\n}\n\nint zmq::dist_t::send_to_all (msg_t *msg_)\n{\n    _matching = _active;\n    return send_to_matching (msg_);\n}\n\nint zmq::dist_t::send_to_matching (msg_t *msg_)\n{\n    //  Is this end of a multipart message?\n    const bool msg_more = (msg_->flags () & msg_t::more) != 0;\n\n    //  Push the message to matching pipes.\n    distribute (msg_);\n\n    //  If multipart message is fully sent, activate all the eligible pipes.\n    if (!msg_more)\n        _active = _eligible;\n\n    _more = msg_more;\n\n    return 0;\n}\n\nvoid zmq::dist_t::distribute (msg_t *msg_)\n{\n    //  If there are no matching pipes available, simply drop the message.\n    if (_matching == 0) {\n        int rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n        return;\n    }\n\n    if (msg_->is_vsm ()) {\n        for (pipes_t::size_type i = 0; i < _matching;) {\n            if (!write (_pipes[i], msg_)) {\n                //  Use same index again because entry will have been removed.\n            } else {\n                ++i;\n            }\n        }\n        int rc = msg_->init ();\n        errno_assert (rc == 0);\n        return;\n    }\n\n    //  Add matching-1 references to the message. We already hold one reference,\n    //  that's why -1.\n    msg_->add_refs (static_cast<int> (_matching) - 1);\n\n    //  Push copy of the message to each matching pipe.\n    int failed = 0;\n    for (pipes_t::size_type i = 0; i < _matching;) {\n        if (!write (_pipes[i], msg_)) {\n            ++failed;\n            //  Use same index again because entry will have been removed.\n        } else {\n            ++i;\n        }\n    }\n    if (unlikely (failed))\n        msg_->rm_refs (failed);\n\n    //  Detach the original message from the data buffer. Note that we don't\n    //  close the message. That's because we've already used all the references.\n    const int rc = msg_->init ();\n    errno_assert (rc == 0);\n}\n\nbool zmq::dist_t::has_out ()\n{\n    return true;\n}\n\nbool zmq::dist_t::write (pipe_t *pipe_, msg_t *msg_)\n{\n    if (!pipe_->write (msg_)) {\n        _pipes.swap (_pipes.index (pipe_), _matching - 1);\n        _matching--;\n        _pipes.swap (_pipes.index (pipe_), _active - 1);\n        _active--;\n        _pipes.swap (_active, _eligible - 1);\n        _eligible--;\n        return false;\n    }\n    if (!(msg_->flags () & msg_t::more))\n        pipe_->flush ();\n    return true;\n}\n\nbool zmq::dist_t::check_hwm ()\n{\n    for (pipes_t::size_type i = 0; i < _matching; ++i)\n        if (!_pipes[i]->check_hwm ())\n            return false;\n\n    return true;\n}\n"
  },
  {
    "path": "src/dist.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_DIST_HPP_INCLUDED__\n#define __ZMQ_DIST_HPP_INCLUDED__\n\n#include <vector>\n\n#include \"array.hpp\"\n#include \"macros.hpp\"\n\nnamespace zmq\n{\nclass pipe_t;\nclass msg_t;\n\n//  Class manages a set of outbound pipes. It sends each messages to\n//  each of them.\nclass dist_t\n{\n  public:\n    dist_t ();\n    ~dist_t ();\n\n    //  Adds the pipe to the distributor object.\n    void attach (zmq::pipe_t *pipe_);\n\n    //  Checks if this pipe is present in the distributor.\n    bool has_pipe (zmq::pipe_t *pipe_);\n\n    //  Activates pipe that have previously reached high watermark.\n    void activated (zmq::pipe_t *pipe_);\n\n    //  Mark the pipe as matching. Subsequent call to send_to_matching\n    //  will send message also to this pipe.\n    void match (zmq::pipe_t *pipe_);\n\n    //  Marks all pipes that are not matched as matched and vice-versa.\n    void reverse_match ();\n\n    //  Mark all pipes as non-matching.\n    void unmatch ();\n\n    //  Removes the pipe from the distributor object.\n    void pipe_terminated (zmq::pipe_t *pipe_);\n\n    //  Send the message to the matching outbound pipes.\n    int send_to_matching (zmq::msg_t *msg_);\n\n    //  Send the message to all the outbound pipes.\n    int send_to_all (zmq::msg_t *msg_);\n\n    static bool has_out ();\n\n    // check HWM of all pipes matching\n    bool check_hwm ();\n\n  private:\n    //  Write the message to the pipe. Make the pipe inactive if writing\n    //  fails. In such a case false is returned.\n    bool write (zmq::pipe_t *pipe_, zmq::msg_t *msg_);\n\n    //  Put the message to all active pipes.\n    void distribute (zmq::msg_t *msg_);\n\n    //  List of outbound pipes.\n    typedef array_t<zmq::pipe_t, 2> pipes_t;\n    pipes_t _pipes;\n\n    //  Number of all the pipes to send the next message to.\n    pipes_t::size_type _matching;\n\n    //  Number of active pipes. All the active pipes are located at the\n    //  beginning of the pipes array. These are the pipes the messages\n    //  can be sent to at the moment.\n    pipes_t::size_type _active;\n\n    //  Number of pipes eligible for sending messages to. This includes all\n    //  the active pipes plus all the pipes that we can in theory send\n    //  messages to (the HWM is not yet reached), but sending a message\n    //  to them would result in partial message being delivered, ie. message\n    //  with initial parts missing.\n    pipes_t::size_type _eligible;\n\n    //  True if last we are in the middle of a multipart message.\n    bool _more;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (dist_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/encoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_ENCODER_HPP_INCLUDED__\n#define __ZMQ_ENCODER_HPP_INCLUDED__\n\n#if defined(_MSC_VER)\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n#endif\n\n#include <stddef.h>\n#include <string.h>\n#include <stdlib.h>\n#include <algorithm>\n\n#include \"err.hpp\"\n#include \"i_encoder.hpp\"\n#include \"msg.hpp\"\n\nnamespace zmq\n{\n//  Helper base class for encoders. It implements the state machine that\n//  fills the outgoing buffer. Derived classes should implement individual\n//  state machine actions.\n\ntemplate <typename T> class encoder_base_t : public i_encoder\n{\n  public:\n    explicit encoder_base_t (size_t bufsize_) :\n        _write_pos (0),\n        _to_write (0),\n        _next (NULL),\n        _new_msg_flag (false),\n        _buf_size (bufsize_),\n        _buf (static_cast<unsigned char *> (malloc (bufsize_))),\n        _in_progress (NULL)\n    {\n        alloc_assert (_buf);\n    }\n\n    ~encoder_base_t () ZMQ_OVERRIDE { free (_buf); }\n\n    //  The function returns a batch of binary data. The data\n    //  are filled to a supplied buffer. If no buffer is supplied (data_\n    //  points to NULL) decoder object will provide buffer of its own.\n    size_t encode (unsigned char **data_, size_t size_) ZMQ_FINAL\n    {\n        unsigned char *buffer = !*data_ ? _buf : *data_;\n        const size_t buffersize = !*data_ ? _buf_size : size_;\n\n        if (in_progress () == NULL)\n            return 0;\n\n        size_t pos = 0;\n        while (pos < buffersize) {\n            //  If there are no more data to return, run the state machine.\n            //  If there are still no data, return what we already have\n            //  in the buffer.\n            if (!_to_write) {\n                if (_new_msg_flag) {\n                    int rc = _in_progress->close ();\n                    errno_assert (rc == 0);\n                    rc = _in_progress->init ();\n                    errno_assert (rc == 0);\n                    _in_progress = NULL;\n                    break;\n                }\n                (static_cast<T *> (this)->*_next) ();\n            }\n\n            //  If there are no data in the buffer yet and we are able to\n            //  fill whole buffer in a single go, let's use zero-copy.\n            //  There's no disadvantage to it as we cannot stuck multiple\n            //  messages into the buffer anyway. Note that subsequent\n            //  write(s) are non-blocking, thus each single write writes\n            //  at most SO_SNDBUF bytes at once not depending on how large\n            //  is the chunk returned from here.\n            //  As a consequence, large messages being sent won't block\n            //  other engines running in the same I/O thread for excessive\n            //  amounts of time.\n            if (!pos && !*data_ && _to_write >= buffersize) {\n                *data_ = _write_pos;\n                pos = _to_write;\n                _write_pos = NULL;\n                _to_write = 0;\n                return pos;\n            }\n\n            //  Copy data to the buffer. If the buffer is full, return.\n            const size_t to_copy = std::min (_to_write, buffersize - pos);\n            memcpy (buffer + pos, _write_pos, to_copy);\n            pos += to_copy;\n            _write_pos += to_copy;\n            _to_write -= to_copy;\n        }\n\n        *data_ = buffer;\n        return pos;\n    }\n\n    void load_msg (msg_t *msg_) ZMQ_FINAL\n    {\n        zmq_assert (in_progress () == NULL);\n        _in_progress = msg_;\n        (static_cast<T *> (this)->*_next) ();\n    }\n\n  protected:\n    //  Prototype of state machine action.\n    typedef void (T::*step_t) ();\n\n    //  This function should be called from derived class to write the data\n    //  to the buffer and schedule next state machine action.\n    void next_step (void *write_pos_,\n                    size_t to_write_,\n                    step_t next_,\n                    bool new_msg_flag_)\n    {\n        _write_pos = static_cast<unsigned char *> (write_pos_);\n        _to_write = to_write_;\n        _next = next_;\n        _new_msg_flag = new_msg_flag_;\n    }\n\n    msg_t *in_progress () { return _in_progress; }\n\n  private:\n    //  Where to get the data to write from.\n    unsigned char *_write_pos;\n\n    //  How much data to write before next step should be executed.\n    size_t _to_write;\n\n    //  Next step. If set to NULL, it means that associated data stream\n    //  is dead.\n    step_t _next;\n\n    bool _new_msg_flag;\n\n    //  The buffer for encoded data.\n    const size_t _buf_size;\n    unsigned char *const _buf;\n\n    msg_t *_in_progress;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (encoder_base_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/endpoint.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"endpoint.hpp\"\n\nzmq::endpoint_uri_pair_t\nzmq::make_unconnected_connect_endpoint_pair (const std::string &endpoint_)\n{\n    return endpoint_uri_pair_t (std::string (), endpoint_,\n                                endpoint_type_connect);\n}\n\nzmq::endpoint_uri_pair_t\nzmq::make_unconnected_bind_endpoint_pair (const std::string &endpoint_)\n{\n    return endpoint_uri_pair_t (endpoint_, std::string (), endpoint_type_bind);\n}\n"
  },
  {
    "path": "src/endpoint.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_ENDPOINT_HPP_INCLUDED__\n#define __ZMQ_ENDPOINT_HPP_INCLUDED__\n\n#include <string>\n\nnamespace zmq\n{\nenum endpoint_type_t\n{\n    endpoint_type_none,   // a connection-less endpoint\n    endpoint_type_bind,   // a connection-oriented bind endpoint\n    endpoint_type_connect // a connection-oriented connect endpoint\n};\n\nstruct endpoint_uri_pair_t\n{\n    endpoint_uri_pair_t () : local_type (endpoint_type_none) {}\n    endpoint_uri_pair_t (const std::string &local,\n                         const std::string &remote,\n                         endpoint_type_t local_type) :\n        local (local), remote (remote), local_type (local_type)\n    {\n    }\n\n    const std::string &identifier () const\n    {\n        return local_type == endpoint_type_bind ? local : remote;\n    }\n\n    bool clash () const { return local == remote; }\n\n    std::string local, remote;\n    endpoint_type_t local_type;\n};\n\nendpoint_uri_pair_t\nmake_unconnected_connect_endpoint_pair (const std::string &endpoint_);\n\nendpoint_uri_pair_t\nmake_unconnected_bind_endpoint_pair (const std::string &endpoint_);\n}\n\n#endif\n"
  },
  {
    "path": "src/epoll.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_EPOLL\n#include \"epoll.hpp\"\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#endif\n\n#include <stdlib.h>\n#include <string.h>\n#include <signal.h>\n#include <algorithm>\n#include <new>\n\n#include \"macros.hpp\"\n#include \"err.hpp\"\n#include \"config.hpp\"\n#include \"i_poll_events.hpp\"\n\n#ifdef ZMQ_HAVE_WINDOWS\nconst zmq::epoll_t::epoll_fd_t zmq::epoll_t::epoll_retired_fd =\n  INVALID_HANDLE_VALUE;\n#endif\n\nzmq::epoll_t::epoll_t (const zmq::thread_ctx_t &ctx_) :\n    worker_poller_base_t (ctx_)\n{\n#ifdef ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC\n    //  Setting this option result in sane behaviour when exec() functions\n    //  are used. Old sockets are closed and don't block TCP ports, avoid\n    //  leaks, etc.\n    _epoll_fd = epoll_create1 (EPOLL_CLOEXEC);\n#else\n    _epoll_fd = epoll_create (1);\n#endif\n    errno_assert (_epoll_fd != epoll_retired_fd);\n}\n\nzmq::epoll_t::~epoll_t ()\n{\n    //  Wait till the worker thread exits.\n    stop_worker ();\n\n#ifdef ZMQ_HAVE_WINDOWS\n    epoll_close (_epoll_fd);\n#else\n    close (_epoll_fd);\n#endif\n    for (retired_t::iterator it = _retired.begin (), end = _retired.end ();\n         it != end; ++it) {\n        LIBZMQ_DELETE (*it);\n    }\n}\n\nzmq::epoll_t::handle_t zmq::epoll_t::add_fd (fd_t fd_, i_poll_events *events_)\n{\n    check_thread ();\n    poll_entry_t *pe = new (std::nothrow) poll_entry_t;\n    alloc_assert (pe);\n\n    //  The memset is not actually needed. It's here to prevent debugging\n    //  tools to complain about using uninitialised memory.\n    memset (pe, 0, sizeof (poll_entry_t));\n\n    pe->fd = fd_;\n    pe->ev.events = 0;\n    pe->ev.data.ptr = pe;\n    pe->events = events_;\n\n    const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_ADD, fd_, &pe->ev);\n    errno_assert (rc != -1);\n\n    //  Increase the load metric of the thread.\n    adjust_load (1);\n\n    return pe;\n}\n\nvoid zmq::epoll_t::rm_fd (handle_t handle_)\n{\n    check_thread ();\n    poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);\n    const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_DEL, pe->fd, &pe->ev);\n    errno_assert (rc != -1);\n    pe->fd = retired_fd;\n    _retired.push_back (pe);\n\n    //  Decrease the load metric of the thread.\n    adjust_load (-1);\n}\n\nvoid zmq::epoll_t::set_pollin (handle_t handle_)\n{\n    check_thread ();\n    poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);\n    pe->ev.events |= EPOLLIN;\n    const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);\n    errno_assert (rc != -1);\n}\n\nvoid zmq::epoll_t::reset_pollin (handle_t handle_)\n{\n    check_thread ();\n    poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);\n    pe->ev.events &= ~(static_cast<uint32_t> (EPOLLIN));\n    const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);\n    errno_assert (rc != -1);\n}\n\nvoid zmq::epoll_t::set_pollout (handle_t handle_)\n{\n    check_thread ();\n    poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);\n    pe->ev.events |= EPOLLOUT;\n    const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);\n    errno_assert (rc != -1);\n}\n\nvoid zmq::epoll_t::reset_pollout (handle_t handle_)\n{\n    check_thread ();\n    poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);\n    pe->ev.events &= ~(static_cast<uint32_t> (EPOLLOUT));\n    const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);\n    errno_assert (rc != -1);\n}\n\nvoid zmq::epoll_t::stop ()\n{\n    check_thread ();\n}\n\nint zmq::epoll_t::max_fds ()\n{\n    return -1;\n}\n\nvoid zmq::epoll_t::loop ()\n{\n    epoll_event ev_buf[max_io_events];\n\n    while (true) {\n        //  Execute any due timers.\n        const int timeout = static_cast<int> (execute_timers ());\n\n        if (get_load () == 0) {\n            if (timeout == 0)\n                break;\n\n            // TODO sleep for timeout\n            continue;\n        }\n\n        //  Wait for events.\n        const int n = epoll_wait (_epoll_fd, &ev_buf[0], max_io_events,\n                                  timeout ? timeout : -1);\n        if (n == -1) {\n            errno_assert (errno == EINTR);\n            continue;\n        }\n\n        for (int i = 0; i < n; i++) {\n            const poll_entry_t *const pe =\n              static_cast<const poll_entry_t *> (ev_buf[i].data.ptr);\n\n            if (NULL == pe)\n                continue;\n            if (NULL == pe->events)\n                continue;\n            if (pe->fd == retired_fd)\n                continue;\n            if (ev_buf[i].events & (EPOLLERR | EPOLLHUP))\n                pe->events->in_event ();\n            if (pe->fd == retired_fd)\n                continue;\n            if (ev_buf[i].events & EPOLLOUT)\n                pe->events->out_event ();\n            if (pe->fd == retired_fd)\n                continue;\n            if (ev_buf[i].events & EPOLLIN)\n                pe->events->in_event ();\n        }\n\n        //  Destroy retired event sources.\n        for (retired_t::iterator it = _retired.begin (), end = _retired.end ();\n             it != end; ++it) {\n            LIBZMQ_DELETE (*it);\n        }\n        _retired.clear ();\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/epoll.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_EPOLL_HPP_INCLUDED__\n#define __ZMQ_EPOLL_HPP_INCLUDED__\n\n//  poller.hpp decides which polling mechanism to use.\n#include \"poller.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_EPOLL\n\n#include <vector>\n\n#if defined ZMQ_HAVE_WINDOWS\n#include \"../external/wepoll/wepoll.h\"\n#else\n#include <sys/epoll.h>\n#endif\n\n#include \"ctx.hpp\"\n#include \"fd.hpp\"\n#include \"thread.hpp\"\n#include \"poller_base.hpp\"\n#include \"mutex.hpp\"\n\nnamespace zmq\n{\nstruct i_poll_events;\n\n//  This class implements socket polling mechanism using the Linux-specific\n//  epoll mechanism.\n\nclass epoll_t ZMQ_FINAL : public worker_poller_base_t\n{\n  public:\n    typedef void *handle_t;\n\n    epoll_t (const thread_ctx_t &ctx_);\n    ~epoll_t () ZMQ_OVERRIDE;\n\n    //  \"poller\" concept.\n    handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);\n    void rm_fd (handle_t handle_);\n    void set_pollin (handle_t handle_);\n    void reset_pollin (handle_t handle_);\n    void set_pollout (handle_t handle_);\n    void reset_pollout (handle_t handle_);\n    void stop ();\n\n    static int max_fds ();\n\n  private:\n#if defined ZMQ_HAVE_WINDOWS\n    typedef HANDLE epoll_fd_t;\n    static const epoll_fd_t epoll_retired_fd;\n#else\n    typedef fd_t epoll_fd_t;\n    enum\n    {\n        epoll_retired_fd = retired_fd\n    };\n#endif\n\n    //  Main event loop.\n    void loop () ZMQ_OVERRIDE;\n\n    //  Main epoll file descriptor\n    epoll_fd_t _epoll_fd;\n\n    struct poll_entry_t\n    {\n        fd_t fd;\n        epoll_event ev;\n        zmq::i_poll_events *events;\n    };\n\n    //  List of retired event sources.\n    typedef std::vector<poll_entry_t *> retired_t;\n    retired_t _retired;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (epoll_t)\n};\n\ntypedef epoll_t poller_t;\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/err.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"err.hpp\"\n#include \"macros.hpp\"\n\nconst char *zmq::errno_to_string (int errno_)\n{\n    switch (errno_) {\n#if defined ZMQ_HAVE_WINDOWS\n        case ENOTSUP:\n            return \"Not supported\";\n        case EPROTONOSUPPORT:\n            return \"Protocol not supported\";\n        case ENOBUFS:\n            return \"No buffer space available\";\n        case ENETDOWN:\n            return \"Network is down\";\n        case EADDRINUSE:\n            return \"Address in use\";\n        case EADDRNOTAVAIL:\n            return \"Address not available\";\n        case ECONNREFUSED:\n            return \"Connection refused\";\n        case EINPROGRESS:\n            return \"Operation in progress\";\n#endif\n        case EFSM:\n            return \"Operation cannot be accomplished in current state\";\n        case ENOCOMPATPROTO:\n            return \"The protocol is not compatible with the socket type\";\n        case ETERM:\n            return \"Context was terminated\";\n        case EMTHREAD:\n            return \"No thread available\";\n        case EHOSTUNREACH:\n            return \"Host unreachable\";\n        default:\n#if defined _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4996)\n#endif\n            return strerror (errno_);\n#if defined _MSC_VER\n#pragma warning(pop)\n#endif\n    }\n}\n\nvoid zmq::zmq_abort (const char *errmsg_)\n{\n#if defined ZMQ_HAVE_WINDOWS\n\n    //  Raise STATUS_FATAL_APP_EXIT.\n    ULONG_PTR extra_info[1];\n    extra_info[0] = (ULONG_PTR) errmsg_;\n    RaiseException (0x40000015, EXCEPTION_NONCONTINUABLE, 1, extra_info);\n#else\n    LIBZMQ_UNUSED (errmsg_);\n    print_backtrace ();\n    abort ();\n#endif\n}\n\n#ifdef ZMQ_HAVE_WINDOWS\n\nconst char *zmq::wsa_error ()\n{\n    return wsa_error_no (WSAGetLastError (), NULL);\n}\n\nconst char *zmq::wsa_error_no (int no_, const char *wsae_wouldblock_string_)\n{\n    //  TODO:  It seems that list of Windows socket errors is longer than this.\n    //         Investigate whether there's a way to convert it into the string\n    //         automatically (wsaError->HRESULT->string?).\n    switch (no_) {\n        case WSABASEERR:\n            return \"No Error\";\n        case WSAEINTR:\n            return \"Interrupted system call\";\n        case WSAEBADF:\n            return \"Bad file number\";\n        case WSAEACCES:\n            return \"Permission denied\";\n        case WSAEFAULT:\n            return \"Bad address\";\n        case WSAEINVAL:\n            return \"Invalid argument\";\n        case WSAEMFILE:\n            return \"Too many open files\";\n        case WSAEWOULDBLOCK:\n            return wsae_wouldblock_string_;\n        case WSAEINPROGRESS:\n            return \"Operation now in progress\";\n        case WSAEALREADY:\n            return \"Operation already in progress\";\n        case WSAENOTSOCK:\n            return \"Socket operation on non-socket\";\n        case WSAEDESTADDRREQ:\n            return \"Destination address required\";\n        case WSAEMSGSIZE:\n            return \"Message too long\";\n        case WSAEPROTOTYPE:\n            return \"Protocol wrong type for socket\";\n        case WSAENOPROTOOPT:\n            return \"Bas protocol option\";\n        case WSAEPROTONOSUPPORT:\n            return \"Protocol not supported\";\n        case WSAESOCKTNOSUPPORT:\n            return \"Socket type not supported\";\n        case WSAEOPNOTSUPP:\n            return \"Operation not supported on socket\";\n        case WSAEPFNOSUPPORT:\n            return \"Protocol family not supported\";\n        case WSAEAFNOSUPPORT:\n            return \"Address family not supported by protocol family\";\n        case WSAEADDRINUSE:\n            return \"Address already in use\";\n        case WSAEADDRNOTAVAIL:\n            return \"Can't assign requested address\";\n        case WSAENETDOWN:\n            return \"Network is down\";\n        case WSAENETUNREACH:\n            return \"Network is unreachable\";\n        case WSAENETRESET:\n            return \"Net dropped connection or reset\";\n        case WSAECONNABORTED:\n            return \"Software caused connection abort\";\n        case WSAECONNRESET:\n            return \"Connection reset by peer\";\n        case WSAENOBUFS:\n            return \"No buffer space available\";\n        case WSAEISCONN:\n            return \"Socket is already connected\";\n        case WSAENOTCONN:\n            return \"Socket is not connected\";\n        case WSAESHUTDOWN:\n            return \"Can't send after socket shutdown\";\n        case WSAETOOMANYREFS:\n            return \"Too many references can't splice\";\n        case WSAETIMEDOUT:\n            return \"Connection timed out\";\n        case WSAECONNREFUSED:\n            return \"Connection refused\";\n        case WSAELOOP:\n            return \"Too many levels of symbolic links\";\n        case WSAENAMETOOLONG:\n            return \"File name too long\";\n        case WSAEHOSTDOWN:\n            return \"Host is down\";\n        case WSAEHOSTUNREACH:\n            return \"No Route to Host\";\n        case WSAENOTEMPTY:\n            return \"Directory not empty\";\n        case WSAEPROCLIM:\n            return \"Too many processes\";\n        case WSAEUSERS:\n            return \"Too many users\";\n        case WSAEDQUOT:\n            return \"Disc Quota Exceeded\";\n        case WSAESTALE:\n            return \"Stale NFS file handle\";\n        case WSAEREMOTE:\n            return \"Too many levels of remote in path\";\n        case WSASYSNOTREADY:\n            return \"Network SubSystem is unavailable\";\n        case WSAVERNOTSUPPORTED:\n            return \"WINSOCK DLL Version out of range\";\n        case WSANOTINITIALISED:\n            return \"Successful WSASTARTUP not yet performed\";\n        case WSAHOST_NOT_FOUND:\n            return \"Host not found\";\n        case WSATRY_AGAIN:\n            return \"Non-Authoritative Host not found\";\n        case WSANO_RECOVERY:\n            return \"Non-Recoverable errors: FORMERR REFUSED NOTIMP\";\n        case WSANO_DATA:\n            return \"Valid name no data record of requested\";\n        default:\n            return \"error not defined\";\n    }\n}\n\nvoid zmq::win_error (char *buffer_, size_t buffer_size_)\n{\n    const DWORD errcode = GetLastError ();\n#if defined _WIN32_WCE\n    DWORD rc = FormatMessageW (\n      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errcode,\n      MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) buffer_,\n      buffer_size_ / sizeof (wchar_t), NULL);\n#else\n    const DWORD rc = FormatMessageA (\n      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errcode,\n      MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), buffer_,\n      static_cast<DWORD> (buffer_size_), NULL);\n#endif\n    zmq_assert (rc);\n}\n\nint zmq::wsa_error_to_errno (int errcode_)\n{\n    switch (errcode_) {\n            //  10004 - Interrupted system call.\n        case WSAEINTR:\n            return EINTR;\n            //  10009 - File handle is not valid.\n        case WSAEBADF:\n            return EBADF;\n            //  10013 - Permission denied.\n        case WSAEACCES:\n            return EACCES;\n            //  10014 - Bad address.\n        case WSAEFAULT:\n            return EFAULT;\n            //  10022 - Invalid argument.\n        case WSAEINVAL:\n            return EINVAL;\n            //  10024 - Too many open files.\n        case WSAEMFILE:\n            return EMFILE;\n            //  10035 - Operation would block.\n        case WSAEWOULDBLOCK:\n            return EBUSY;\n            //  10036 - Operation now in progress.\n        case WSAEINPROGRESS:\n            return EAGAIN;\n            //  10037 - Operation already in progress.\n        case WSAEALREADY:\n            return EAGAIN;\n            //  10038 - Socket operation on non-socket.\n        case WSAENOTSOCK:\n            return ENOTSOCK;\n            //  10039 - Destination address required.\n        case WSAEDESTADDRREQ:\n            return EFAULT;\n            //  10040 - Message too long.\n        case WSAEMSGSIZE:\n            return EMSGSIZE;\n            //  10041 - Protocol wrong type for socket.\n        case WSAEPROTOTYPE:\n            return EFAULT;\n            //  10042 - Bad protocol option.\n        case WSAENOPROTOOPT:\n            return EINVAL;\n            //  10043 - Protocol not supported.\n        case WSAEPROTONOSUPPORT:\n            return EPROTONOSUPPORT;\n            //  10044 - Socket type not supported.\n        case WSAESOCKTNOSUPPORT:\n            return EFAULT;\n            //  10045 - Operation not supported on socket.\n        case WSAEOPNOTSUPP:\n            return EFAULT;\n            //  10046 - Protocol family not supported.\n        case WSAEPFNOSUPPORT:\n            return EPROTONOSUPPORT;\n            //  10047 - Address family not supported by protocol family.\n        case WSAEAFNOSUPPORT:\n            return EAFNOSUPPORT;\n            //  10048 - Address already in use.\n        case WSAEADDRINUSE:\n            return EADDRINUSE;\n            //  10049 - Cannot assign requested address.\n        case WSAEADDRNOTAVAIL:\n            return EADDRNOTAVAIL;\n            //  10050 - Network is down.\n        case WSAENETDOWN:\n            return ENETDOWN;\n            //  10051 - Network is unreachable.\n        case WSAENETUNREACH:\n            return ENETUNREACH;\n            //  10052 - Network dropped connection on reset.\n        case WSAENETRESET:\n            return ENETRESET;\n            //  10053 - Software caused connection abort.\n        case WSAECONNABORTED:\n            return ECONNABORTED;\n            //  10054 - Connection reset by peer.\n        case WSAECONNRESET:\n            return ECONNRESET;\n            //  10055 - No buffer space available.\n        case WSAENOBUFS:\n            return ENOBUFS;\n            //  10056 - Socket is already connected.\n        case WSAEISCONN:\n            return EFAULT;\n            //  10057 - Socket is not connected.\n        case WSAENOTCONN:\n            return ENOTCONN;\n            //  10058 - Can't send after socket shutdown.\n        case WSAESHUTDOWN:\n            return EFAULT;\n            //  10059 - Too many references can't splice.\n        case WSAETOOMANYREFS:\n            return EFAULT;\n            //  10060 - Connection timed out.\n        case WSAETIMEDOUT:\n            return ETIMEDOUT;\n            //  10061 - Connection refused.\n        case WSAECONNREFUSED:\n            return ECONNREFUSED;\n            //  10062 - Too many levels of symbolic links.\n        case WSAELOOP:\n            return EFAULT;\n            //  10063 - File name too long.\n        case WSAENAMETOOLONG:\n            return EFAULT;\n            //  10064 - Host is down.\n        case WSAEHOSTDOWN:\n            return EAGAIN;\n            //  10065 - No route to host.\n        case WSAEHOSTUNREACH:\n            return EHOSTUNREACH;\n            //  10066 - Directory not empty.\n        case WSAENOTEMPTY:\n            return EFAULT;\n            //  10067 - Too many processes.\n        case WSAEPROCLIM:\n            return EFAULT;\n            //  10068 - Too many users.\n        case WSAEUSERS:\n            return EFAULT;\n            //  10069 - Disc Quota Exceeded.\n        case WSAEDQUOT:\n            return EFAULT;\n            //  10070 - Stale NFS file handle.\n        case WSAESTALE:\n            return EFAULT;\n            //  10071 - Too many levels of remote in path.\n        case WSAEREMOTE:\n            return EFAULT;\n            //  10091 - Network SubSystem is unavailable.\n        case WSASYSNOTREADY:\n            return EFAULT;\n            //  10092 - WINSOCK DLL Version out of range.\n        case WSAVERNOTSUPPORTED:\n            return EFAULT;\n            //  10093 - Successful WSASTARTUP not yet performed.\n        case WSANOTINITIALISED:\n            return EFAULT;\n            //  11001 - Host not found.\n        case WSAHOST_NOT_FOUND:\n            return EFAULT;\n            //  11002 - Non-Authoritative Host not found.\n        case WSATRY_AGAIN:\n            return EFAULT;\n            //  11003 - Non-Recoverable errors: FORMERR REFUSED NOTIMP.\n        case WSANO_RECOVERY:\n            return EFAULT;\n            //  11004 - Valid name no data record of requested.\n        case WSANO_DATA:\n            return EFAULT;\n        default:\n            wsa_assert (false);\n    }\n    //  Not reachable\n    return 0;\n}\n\n#endif\n\n#if defined(HAVE_LIBUNWIND) && !defined(__SUNPRO_CC)\n\n#define UNW_LOCAL_ONLY\n#include <libunwind.h>\n#include <dlfcn.h>\n#include <cxxabi.h>\n#include \"mutex.hpp\"\n\nvoid zmq::print_backtrace (void)\n{\n    static zmq::mutex_t mtx;\n    mtx.lock ();\n    Dl_info dl_info;\n    unw_cursor_t cursor;\n    unw_context_t ctx;\n    unsigned frame_n = 0;\n\n    unw_getcontext (&ctx);\n    unw_init_local (&cursor, &ctx);\n\n    while (unw_step (&cursor) > 0) {\n        unw_word_t offset;\n        unw_proc_info_t p_info;\n        static const char unknown[] = \"?\";\n        const char *file_name;\n        char *demangled_name;\n        char func_name[256] = \"\";\n        void *addr;\n        int rc;\n\n        if (unw_get_proc_info (&cursor, &p_info))\n            break;\n\n        rc = unw_get_proc_name (&cursor, func_name, 256, &offset);\n        if (rc == -UNW_ENOINFO)\n            memcpy (func_name, unknown, sizeof unknown);\n\n        addr = (void *) (p_info.start_ip + offset);\n\n        if (dladdr (addr, &dl_info) && dl_info.dli_fname)\n            file_name = dl_info.dli_fname;\n        else\n            file_name = unknown;\n\n        demangled_name = abi::__cxa_demangle (func_name, NULL, NULL, &rc);\n\n        printf (\"#%u  %p in %s (%s+0x%lx)\\n\", frame_n++, addr, file_name,\n                rc ? func_name : demangled_name, (unsigned long) offset);\n        free (demangled_name);\n    }\n    puts (\"\");\n\n    fflush (stdout);\n    mtx.unlock ();\n}\n\n#else\n\nvoid zmq::print_backtrace ()\n{\n}\n\n#endif\n"
  },
  {
    "path": "src/err.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_ERR_HPP_INCLUDED__\n#define __ZMQ_ERR_HPP_INCLUDED__\n\n#include <assert.h>\n#if defined _WIN32_WCE\n#include \"..\\builds\\msvc\\errno.hpp\"\n#else\n#include <errno.h>\n#endif\n#include <string.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <netdb.h>\n#endif\n\n#include \"likely.hpp\"\n\n//  0MQ-specific error codes are defined in zmq.h\n\n// EPROTO is not used by OpenBSD and maybe other platforms.\n#ifndef EPROTO\n#define EPROTO 0\n#endif\n\nnamespace zmq\n{\nconst char *errno_to_string (int errno_);\n#if defined __clang__\n#if __has_feature(attribute_analyzer_noreturn)\nvoid zmq_abort (const char *errmsg_) __attribute__ ((analyzer_noreturn));\n#else\nvoid zmq_abort (const char *errmsg_);\n#endif\n#elif defined __MSCVER__\n__declspec (noreturn) void zmq_abort (const char *errmsg_);\n#else\nvoid zmq_abort (const char *errmsg_);\n#endif\nvoid print_backtrace ();\n}\n\n#ifdef ZMQ_HAVE_WINDOWS\n\nnamespace zmq\n{\nconst char *wsa_error ();\nconst char *\nwsa_error_no (int no_,\n              const char *wsae_wouldblock_string_ = \"Operation would block\");\nvoid win_error (char *buffer_, size_t buffer_size_);\nint wsa_error_to_errno (int errcode_);\n}\n\n//  Provides convenient way to check WSA-style errors on Windows.\n#define wsa_assert(x)                                                          \\\n    do {                                                                       \\\n        if (unlikely (!(x))) {                                                 \\\n            const char *errstr = zmq::wsa_error ();                            \\\n            if (errstr != NULL) {                                              \\\n                fprintf (stderr, \"Assertion failed: %s [%i] (%s:%d)\\n\",        \\\n                         errstr, WSAGetLastError (), __FILE__, __LINE__);      \\\n                fflush (stderr);                                               \\\n                zmq::zmq_abort (errstr);                                       \\\n            }                                                                  \\\n        }                                                                      \\\n    } while (false)\n\n//  Provides convenient way to assert on WSA-style errors on Windows.\n#define wsa_assert_no(no)                                                      \\\n    do {                                                                       \\\n        const char *errstr = zmq::wsa_error_no (no);                           \\\n        if (errstr != NULL) {                                                  \\\n            fprintf (stderr, \"Assertion failed: %s (%s:%d)\\n\", errstr,         \\\n                     __FILE__, __LINE__);                                      \\\n            fflush (stderr);                                                   \\\n            zmq::zmq_abort (errstr);                                           \\\n        }                                                                      \\\n    } while (false)\n\n// Provides convenient way to check GetLastError-style errors on Windows.\n#define win_assert(x)                                                          \\\n    do {                                                                       \\\n        if (unlikely (!(x))) {                                                 \\\n            char errstr[256];                                                  \\\n            zmq::win_error (errstr, 256);                                      \\\n            fprintf (stderr, \"Assertion failed: %s (%s:%d)\\n\", errstr,         \\\n                     __FILE__, __LINE__);                                      \\\n            fflush (stderr);                                                   \\\n            zmq::zmq_abort (errstr);                                           \\\n        }                                                                      \\\n    } while (false)\n\n#endif\n\n//  This macro works in exactly the same way as the normal assert. It is used\n//  in its stead because standard assert on Win32 in broken - it prints nothing\n//  when used within the scope of JNI library.\n#define zmq_assert(x)                                                          \\\n    do {                                                                       \\\n        if (unlikely (!(x))) {                                                 \\\n            fprintf (stderr, \"Assertion failed: %s (%s:%d)\\n\", #x, __FILE__,   \\\n                     __LINE__);                                                \\\n            fflush (stderr);                                                   \\\n            zmq::zmq_abort (#x);                                               \\\n        }                                                                      \\\n    } while (false)\n\n//  Provides convenient way to check for errno-style errors.\n#define errno_assert(x)                                                        \\\n    do {                                                                       \\\n        if (unlikely (!(x))) {                                                 \\\n            const char *errstr = strerror (errno);                             \\\n            fprintf (stderr, \"%s (%s:%d)\\n\", errstr, __FILE__, __LINE__);      \\\n            fflush (stderr);                                                   \\\n            zmq::zmq_abort (errstr);                                           \\\n        }                                                                      \\\n    } while (false)\n\n//  Provides convenient way to check for POSIX errors.\n#define posix_assert(x)                                                        \\\n    do {                                                                       \\\n        if (unlikely (x)) {                                                    \\\n            const char *errstr = strerror (x);                                 \\\n            fprintf (stderr, \"%s (%s:%d)\\n\", errstr, __FILE__, __LINE__);      \\\n            fflush (stderr);                                                   \\\n            zmq::zmq_abort (errstr);                                           \\\n        }                                                                      \\\n    } while (false)\n\n//  Provides convenient way to check for errors from getaddrinfo.\n#define gai_assert(x)                                                          \\\n    do {                                                                       \\\n        if (unlikely (x)) {                                                    \\\n            const char *errstr = gai_strerror (x);                             \\\n            fprintf (stderr, \"%s (%s:%d)\\n\", errstr, __FILE__, __LINE__);      \\\n            fflush (stderr);                                                   \\\n            zmq::zmq_abort (errstr);                                           \\\n        }                                                                      \\\n    } while (false)\n\n//  Provides convenient way to check whether memory allocation have succeeded.\n#define alloc_assert(x)                                                        \\\n    do {                                                                       \\\n        if (unlikely (!(x))) {                                                 \\\n            fprintf (stderr, \"FATAL ERROR: OUT OF MEMORY (%s:%d)\\n\", __FILE__, \\\n                     __LINE__);                                                \\\n            fflush (stderr);                                                   \\\n            zmq::zmq_abort (\"FATAL ERROR: OUT OF MEMORY\");                     \\\n        }                                                                      \\\n    } while (false)\n\n#endif\n"
  },
  {
    "path": "src/fd.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_FD_HPP_INCLUDED__\n#define __ZMQ_FD_HPP_INCLUDED__\n\n#if defined _WIN32\n#include \"windows.hpp\"\n#endif\n\nnamespace zmq\n{\ntypedef zmq_fd_t fd_t;\n\n#ifdef ZMQ_HAVE_WINDOWS\n#if defined _MSC_VER && _MSC_VER <= 1400\nenum\n{\n    retired_fd = (fd_t) (~0)\n};\n#else\nenum\n#if _MSC_VER >= 1800\n  : fd_t\n#endif\n{\n    retired_fd = INVALID_SOCKET\n};\n#endif\n#else\nenum\n{\n    retired_fd = -1\n};\n#endif\n}\n#endif\n"
  },
  {
    "path": "src/fq.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"fq.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n\nzmq::fq_t::fq_t () : _active (0), _current (0), _more (false)\n{\n}\n\nzmq::fq_t::~fq_t ()\n{\n    zmq_assert (_pipes.empty ());\n}\n\nvoid zmq::fq_t::attach (pipe_t *pipe_)\n{\n    _pipes.push_back (pipe_);\n    _pipes.swap (_active, _pipes.size () - 1);\n    _active++;\n}\n\nvoid zmq::fq_t::pipe_terminated (pipe_t *pipe_)\n{\n    const pipes_t::size_type index = _pipes.index (pipe_);\n\n    //  Remove the pipe from the list; adjust number of active pipes\n    //  accordingly.\n    if (index < _active) {\n        _active--;\n        _pipes.swap (index, _active);\n        if (_current == _active)\n            _current = 0;\n    }\n    _pipes.erase (pipe_);\n}\n\nvoid zmq::fq_t::activated (pipe_t *pipe_)\n{\n    //  Move the pipe to the list of active pipes.\n    _pipes.swap (_pipes.index (pipe_), _active);\n    _active++;\n}\n\nint zmq::fq_t::recv (msg_t *msg_)\n{\n    return recvpipe (msg_, NULL);\n}\n\nint zmq::fq_t::recvpipe (msg_t *msg_, pipe_t **pipe_)\n{\n    //  Deallocate old content of the message.\n    int rc = msg_->close ();\n    errno_assert (rc == 0);\n\n    //  Round-robin over the pipes to get the next message.\n    while (_active > 0) {\n        //  Try to fetch new message. If we've already read part of the message\n        //  subsequent part should be immediately available.\n        const bool fetched = _pipes[_current]->read (msg_);\n\n        //  Note that when message is not fetched, current pipe is deactivated\n        //  and replaced by another active pipe. Thus we don't have to increase\n        //  the 'current' pointer.\n        if (fetched) {\n            if (pipe_)\n                *pipe_ = _pipes[_current];\n            _more = (msg_->flags () & msg_t::more) != 0;\n            if (!_more) {\n                _current = (_current + 1) % _active;\n            }\n            return 0;\n        }\n\n        //  Check the atomicity of the message.\n        //  If we've already received the first part of the message\n        //  we should get the remaining parts without blocking.\n        zmq_assert (!_more);\n\n        _active--;\n        _pipes.swap (_current, _active);\n        if (_current == _active)\n            _current = 0;\n    }\n\n    //  No message is available. Initialise the output parameter\n    //  to be a 0-byte message.\n    rc = msg_->init ();\n    errno_assert (rc == 0);\n    errno = EAGAIN;\n    return -1;\n}\n\nbool zmq::fq_t::has_in ()\n{\n    //  There are subsequent parts of the partly-read message available.\n    if (_more)\n        return true;\n\n    //  Note that messing with current doesn't break the fairness of fair\n    //  queueing algorithm. If there are no messages available current will\n    //  get back to its original value. Otherwise it'll point to the first\n    //  pipe holding messages, skipping only pipes with no messages available.\n    while (_active > 0) {\n        if (_pipes[_current]->check_read ())\n            return true;\n\n        //  Deactivate the pipe.\n        _active--;\n        _pipes.swap (_current, _active);\n        if (_current == _active)\n            _current = 0;\n    }\n\n    return false;\n}\n"
  },
  {
    "path": "src/fq.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_FQ_HPP_INCLUDED__\n#define __ZMQ_FQ_HPP_INCLUDED__\n\n#include \"array.hpp\"\n#include \"blob.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\nclass pipe_t;\n\n//  Class manages a set of inbound pipes. On receive it performs fair\n//  queueing so that senders gone berserk won't cause denial of\n//  service for decent senders.\n\nclass fq_t\n{\n  public:\n    fq_t ();\n    ~fq_t ();\n\n    void attach (pipe_t *pipe_);\n    void activated (pipe_t *pipe_);\n    void pipe_terminated (pipe_t *pipe_);\n\n    int recv (msg_t *msg_);\n    int recvpipe (msg_t *msg_, pipe_t **pipe_);\n    bool has_in ();\n\n  private:\n    //  Inbound pipes.\n    typedef array_t<pipe_t, 1> pipes_t;\n    pipes_t _pipes;\n\n    //  Number of active pipes. All the active pipes are located at the\n    //  beginning of the pipes array.\n    pipes_t::size_type _active;\n\n    //  Index of the next bound pipe to read a message from.\n    pipes_t::size_type _current;\n\n    //  If true, part of a multipart message was already received, but\n    //  there are following parts still waiting in the current pipe.\n    bool _more;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (fq_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/gather.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"gather.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n#include \"pipe.hpp\"\n\nzmq::gather_t::gather_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_, true)\n{\n    options.type = ZMQ_GATHER;\n}\n\nzmq::gather_t::~gather_t ()\n{\n}\n\nvoid zmq::gather_t::xattach_pipe (pipe_t *pipe_,\n                                  bool subscribe_to_all_,\n                                  bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_);\n    _fq.attach (pipe_);\n}\n\nvoid zmq::gather_t::xread_activated (pipe_t *pipe_)\n{\n    _fq.activated (pipe_);\n}\n\nvoid zmq::gather_t::xpipe_terminated (pipe_t *pipe_)\n{\n    _fq.pipe_terminated (pipe_);\n}\n\nint zmq::gather_t::xrecv (msg_t *msg_)\n{\n    int rc = _fq.recvpipe (msg_, NULL);\n\n    // Drop any messages with more flag\n    while (rc == 0 && msg_->flags () & msg_t::more) {\n        // drop all frames of the current multi-frame message\n        rc = _fq.recvpipe (msg_, NULL);\n\n        while (rc == 0 && msg_->flags () & msg_t::more)\n            rc = _fq.recvpipe (msg_, NULL);\n\n        // get the new message\n        if (rc == 0)\n            rc = _fq.recvpipe (msg_, NULL);\n    }\n\n    return rc;\n}\n\nbool zmq::gather_t::xhas_in ()\n{\n    return _fq.has_in ();\n}\n"
  },
  {
    "path": "src/gather.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_GATHER_HPP_INCLUDED__\n#define __ZMQ_GATHER_HPP_INCLUDED__\n\n#include \"socket_base.hpp\"\n#include \"fq.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass pipe_t;\nclass msg_t;\n\nclass gather_t ZMQ_FINAL : public socket_base_t\n{\n  public:\n    gather_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~gather_t ();\n\n  protected:\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    void xread_activated (zmq::pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n\n  private:\n    //  Fair queueing object for inbound pipes.\n    fq_t _fq;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (gather_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/generic_mtrie.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_GENERIC_MTRIE_HPP_INCLUDED__\n#define __ZMQ_GENERIC_MTRIE_HPP_INCLUDED__\n\n#include <stddef.h>\n#include <set>\n\n#include \"macros.hpp\"\n#include \"stdint.hpp\"\n#include \"atomic_counter.hpp\"\n\nnamespace zmq\n{\n//  Multi-trie (prefix tree). Each node in the trie is a set of pointers.\ntemplate <typename T> class generic_mtrie_t\n{\n  public:\n    typedef T value_t;\n    typedef const unsigned char *prefix_t;\n\n    enum rm_result\n    {\n        not_found,\n        last_value_removed,\n        values_remain\n    };\n\n    generic_mtrie_t ();\n    ~generic_mtrie_t ();\n\n    //  Add key to the trie. Returns true iff no entry with the same prefix_\n    //  and size_ existed before.\n    bool add (prefix_t prefix_, size_t size_, value_t *value_);\n\n    //  Remove all entries with a specific value from the trie.\n    //  The call_on_uniq_ flag controls if the callback is invoked\n    //  when there are no entries left on a prefix only (true)\n    //  or on every removal (false). The arg_ argument is passed\n    //  through to the callback function.\n    template <typename Arg>\n    void rm (value_t *value_,\n             void (*func_) (const unsigned char *data_, size_t size_, Arg arg_),\n             Arg arg_,\n             bool call_on_uniq_);\n\n    //  Removes a specific entry from the trie.\n    //  Returns the result of the operation.\n    rm_result rm (prefix_t prefix_, size_t size_, value_t *value_);\n\n    //  Calls a callback function for all matching entries, i.e. any node\n    //  corresponding to data_ or a prefix of it. The arg_ argument\n    //  is passed through to the callback function.\n    template <typename Arg>\n    void match (prefix_t data_,\n                size_t size_,\n                void (*func_) (value_t *value_, Arg arg_),\n                Arg arg_);\n\n    //  Retrieve the number of prefixes stored in this trie (added - removed)\n    //  Note this is a multithread safe function.\n    uint32_t num_prefixes () const { return _num_prefixes.get (); }\n\n  private:\n    bool is_redundant () const;\n\n    typedef std::set<value_t *> pipes_t;\n    pipes_t *_pipes;\n\n    atomic_counter_t _num_prefixes;\n\n    unsigned char _min;\n    unsigned short _count;\n    unsigned short _live_nodes;\n    union _next_t\n    {\n        class generic_mtrie_t<value_t> *node;\n        class generic_mtrie_t<value_t> **table;\n    } _next;\n\n    struct iter\n    {\n        generic_mtrie_t<value_t> *node;\n        generic_mtrie_t<value_t> *next_node;\n        prefix_t prefix;\n        size_t size;\n        unsigned short current_child;\n        unsigned char new_min;\n        unsigned char new_max;\n        bool processed_for_removal;\n    };\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (generic_mtrie_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/generic_mtrie_impl.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_GENERIC_MTRIE_IMPL_HPP_INCLUDED__\n#define __ZMQ_GENERIC_MTRIE_IMPL_HPP_INCLUDED__\n\n\n#include <stdlib.h>\n\n#include <new>\n#include <algorithm>\n#include <list>\n\n#include \"err.hpp\"\n#include \"macros.hpp\"\n#include \"generic_mtrie.hpp\"\n\nnamespace zmq\n{\ntemplate <typename T>\ngeneric_mtrie_t<T>::generic_mtrie_t () :\n    _pipes (0), _num_prefixes (0), _min (0), _count (0), _live_nodes (0)\n{\n}\n\ntemplate <typename T> generic_mtrie_t<T>::~generic_mtrie_t ()\n{\n    LIBZMQ_DELETE (_pipes);\n\n    if (_count == 1) {\n        zmq_assert (_next.node);\n        LIBZMQ_DELETE (_next.node);\n    } else if (_count > 1) {\n        for (unsigned short i = 0; i != _count; ++i) {\n            LIBZMQ_DELETE (_next.table[i]);\n        }\n        free (_next.table);\n    }\n}\n\ntemplate <typename T>\nbool generic_mtrie_t<T>::add (prefix_t prefix_, size_t size_, value_t *pipe_)\n{\n    generic_mtrie_t<value_t> *it = this;\n\n    while (size_) {\n        const unsigned char c = *prefix_;\n\n        if (c < it->_min || c >= it->_min + it->_count) {\n            //  The character is out of range of currently handled\n            //  characters. We have to extend the table.\n            if (!it->_count) {\n                it->_min = c;\n                it->_count = 1;\n                it->_next.node = NULL;\n            } else if (it->_count == 1) {\n                const unsigned char oldc = it->_min;\n                generic_mtrie_t *oldp = it->_next.node;\n                it->_count = (it->_min < c ? c - it->_min : it->_min - c) + 1;\n                it->_next.table = static_cast<generic_mtrie_t **> (\n                  malloc (sizeof (generic_mtrie_t *) * it->_count));\n                alloc_assert (it->_next.table);\n                for (unsigned short i = 0; i != it->_count; ++i)\n                    it->_next.table[i] = 0;\n                it->_min = std::min (it->_min, c);\n                it->_next.table[oldc - it->_min] = oldp;\n            } else if (it->_min < c) {\n                //  The new character is above the current character range.\n                const unsigned short old_count = it->_count;\n                it->_count = c - it->_min + 1;\n                it->_next.table = static_cast<generic_mtrie_t **> (realloc (\n                  it->_next.table, sizeof (generic_mtrie_t *) * it->_count));\n                alloc_assert (it->_next.table);\n                for (unsigned short i = old_count; i != it->_count; i++)\n                    it->_next.table[i] = NULL;\n            } else {\n                //  The new character is below the current character range.\n                const unsigned short old_count = it->_count;\n                it->_count = (it->_min + old_count) - c;\n                it->_next.table = static_cast<generic_mtrie_t **> (realloc (\n                  it->_next.table, sizeof (generic_mtrie_t *) * it->_count));\n                alloc_assert (it->_next.table);\n                memmove (it->_next.table + it->_min - c, it->_next.table,\n                         old_count * sizeof (generic_mtrie_t *));\n                for (unsigned short i = 0; i != it->_min - c; i++)\n                    it->_next.table[i] = NULL;\n                it->_min = c;\n            }\n        }\n\n        //  If next node does not exist, create one.\n        if (it->_count == 1) {\n            if (!it->_next.node) {\n                it->_next.node = new (std::nothrow) generic_mtrie_t;\n                alloc_assert (it->_next.node);\n                ++(it->_live_nodes);\n            }\n\n            ++prefix_;\n            --size_;\n            it = it->_next.node;\n        } else {\n            if (!it->_next.table[c - it->_min]) {\n                it->_next.table[c - it->_min] =\n                  new (std::nothrow) generic_mtrie_t;\n                alloc_assert (it->_next.table[c - it->_min]);\n                ++(it->_live_nodes);\n            }\n\n            ++prefix_;\n            --size_;\n            it = it->_next.table[c - it->_min];\n        }\n    }\n\n    //  We are at the node corresponding to the prefix. We are done.\n    const bool result = !it->_pipes;\n    if (!it->_pipes) {\n        it->_pipes = new (std::nothrow) pipes_t;\n        alloc_assert (it->_pipes);\n\n        _num_prefixes.add (1);\n    }\n    it->_pipes->insert (pipe_);\n\n    return result;\n}\n\ntemplate <typename T>\ntemplate <typename Arg>\nvoid generic_mtrie_t<T>::rm (value_t *pipe_,\n                             void (*func_) (prefix_t data_,\n                                            size_t size_,\n                                            Arg arg_),\n                             Arg arg_,\n                             bool call_on_uniq_)\n{\n    //  This used to be implemented as a non-tail recursive traversal of the trie,\n    //  which means remote clients controlled the depth of the recursion and the\n    //  stack size.\n    //  To simulate the non-tail recursion, with post-recursion changes depending on\n    //  the result of the recursive call, a stack is used to re-visit the same node\n    //  and operate on it again after children have been visited.\n    //  A boolean is used to record whether the node had already been visited and to\n    //  determine if the pre- or post- children visit actions have to be taken.\n    //  In the case of a node with (N > 1) children, the node has to be re-visited\n    //  N times, in the correct order after each child visit.\n    std::list<struct iter> stack;\n    unsigned char *buff = NULL;\n    size_t maxbuffsize = 0;\n    struct iter it = {this, NULL, NULL, 0, 0, 0, 0, false};\n    stack.push_back (it);\n\n    while (!stack.empty ()) {\n        it = stack.back ();\n        stack.pop_back ();\n\n        if (!it.processed_for_removal) {\n            //  Remove the subscription from this node.\n            if (it.node->_pipes && it.node->_pipes->erase (pipe_)) {\n                if (!call_on_uniq_ || it.node->_pipes->empty ()) {\n                    func_ (buff, it.size, arg_);\n                }\n\n                if (it.node->_pipes->empty ()) {\n                    LIBZMQ_DELETE (it.node->_pipes);\n                }\n            }\n\n            //  Adjust the buffer.\n            if (it.size >= maxbuffsize) {\n                maxbuffsize = it.size + 256;\n                buff =\n                  static_cast<unsigned char *> (realloc (buff, maxbuffsize));\n                alloc_assert (buff);\n            }\n\n            switch (it.node->_count) {\n                case 0:\n                    //  If there are no subnodes in the trie, we are done with this node\n                    //  pre-processing.\n                    break;\n                case 1: {\n                    //  If there's one subnode (optimisation).\n\n                    buff[it.size] = it.node->_min;\n                    //  Mark this node as pre-processed and push it, so that the next\n                    //  visit after the operation on the child can do the removals.\n                    it.processed_for_removal = true;\n                    stack.push_back (it);\n                    struct iter next = {it.node->_next.node,\n                                        NULL,\n                                        NULL,\n                                        ++it.size,\n                                        0,\n                                        0,\n                                        0,\n                                        false};\n                    stack.push_back (next);\n                    break;\n                }\n                default: {\n                    //  If there are multiple subnodes.\n                    //  When first visiting this node, initialize the new_min/max parameters\n                    //  which will then be used after each child has been processed, on the\n                    //  post-children iterations.\n                    if (it.current_child == 0) {\n                        //  New min non-null character in the node table after the removal\n                        it.new_min = it.node->_min + it.node->_count - 1;\n                        //  New max non-null character in the node table after the removal\n                        it.new_max = it.node->_min;\n                    }\n\n                    //  Mark this node as pre-processed and push it, so that the next\n                    //  visit after the operation on the child can do the removals.\n                    buff[it.size] = it.node->_min + it.current_child;\n                    it.processed_for_removal = true;\n                    stack.push_back (it);\n                    if (it.node->_next.table[it.current_child]) {\n                        struct iter next = {\n                          it.node->_next.table[it.current_child],\n                          NULL,\n                          NULL,\n                          it.size + 1,\n                          0,\n                          0,\n                          0,\n                          false};\n                        stack.push_back (next);\n                    }\n                }\n            }\n        } else {\n            //  Reset back for the next time, in case this node doesn't get deleted.\n            //  This is done unconditionally, unlike when setting this variable to true.\n            it.processed_for_removal = false;\n\n            switch (it.node->_count) {\n                case 0:\n                    //  If there are no subnodes in the trie, we are done with this node\n                    //  post-processing.\n                    break;\n                case 1:\n                    //  If there's one subnode (optimisation).\n\n                    //  Prune the node if it was made redundant by the removal\n                    if (it.node->_next.node->is_redundant ()) {\n                        LIBZMQ_DELETE (it.node->_next.node);\n                        it.node->_count = 0;\n                        --it.node->_live_nodes;\n                        zmq_assert (it.node->_live_nodes == 0);\n                    }\n                    break;\n                default:\n                    //  If there are multiple subnodes.\n                    {\n                        if (it.node->_next.table[it.current_child]) {\n                            //  Prune redundant nodes from the mtrie\n                            if (it.node->_next.table[it.current_child]\n                                  ->is_redundant ()) {\n                                LIBZMQ_DELETE (\n                                  it.node->_next.table[it.current_child]);\n\n                                zmq_assert (it.node->_live_nodes > 0);\n                                --it.node->_live_nodes;\n                            } else {\n                                //  The node is not redundant, so it's a candidate for being\n                                //  the new min/max node.\n                                //\n                                //  We loop through the node array from left to right, so the\n                                //  first non-null, non-redundant node encountered is the new\n                                //  minimum index. Conversely, the last non-redundant, non-null\n                                //  node encountered is the new maximum index.\n                                if (it.current_child + it.node->_min\n                                    < it.new_min)\n                                    it.new_min =\n                                      it.current_child + it.node->_min;\n                                if (it.current_child + it.node->_min\n                                    > it.new_max)\n                                    it.new_max =\n                                      it.current_child + it.node->_min;\n                            }\n                        }\n\n                        //  If there are more children to visit, push again the current\n                        //  node, so that pre-processing can happen on the next child.\n                        //  If we are done, reset the child index so that the ::rm is\n                        //  fully idempotent.\n                        ++it.current_child;\n                        if (it.current_child >= it.node->_count)\n                            it.current_child = 0;\n                        else {\n                            stack.push_back (it);\n                            continue;\n                        }\n\n                        //  All children have been visited and removed if needed, and\n                        //  all pre- and post-visit operations have been carried.\n                        //  Resize/free the node table if needed.\n                        zmq_assert (it.node->_count > 1);\n\n                        //  Free the node table if it's no longer used.\n                        switch (it.node->_live_nodes) {\n                            case 0:\n                                free (it.node->_next.table);\n                                it.node->_next.table = NULL;\n                                it.node->_count = 0;\n                                break;\n                            case 1:\n                                //  Compact the node table if possible\n\n                                //  If there's only one live node in the table we can\n                                //  switch to using the more compact single-node\n                                //  representation\n                                zmq_assert (it.new_min == it.new_max);\n                                zmq_assert (it.new_min >= it.node->_min);\n                                zmq_assert (it.new_min\n                                            < it.node->_min + it.node->_count);\n                                {\n                                    generic_mtrie_t *node =\n                                      it.node->_next\n                                        .table[it.new_min - it.node->_min];\n                                    zmq_assert (node);\n                                    free (it.node->_next.table);\n                                    it.node->_next.node = node;\n                                }\n                                it.node->_count = 1;\n                                it.node->_min = it.new_min;\n                                break;\n                            default:\n                                if (it.new_min > it.node->_min\n                                    || it.new_max < it.node->_min\n                                                      + it.node->_count - 1) {\n                                    zmq_assert (it.new_max - it.new_min + 1\n                                                > 1);\n\n                                    generic_mtrie_t **old_table =\n                                      it.node->_next.table;\n                                    zmq_assert (it.new_min > it.node->_min\n                                                || it.new_max\n                                                     < it.node->_min\n                                                         + it.node->_count - 1);\n                                    zmq_assert (it.new_min >= it.node->_min);\n                                    zmq_assert (it.new_max\n                                                <= it.node->_min\n                                                     + it.node->_count - 1);\n                                    zmq_assert (it.new_max - it.new_min + 1\n                                                < it.node->_count);\n\n                                    it.node->_count =\n                                      it.new_max - it.new_min + 1;\n                                    it.node->_next.table =\n                                      static_cast<generic_mtrie_t **> (\n                                        malloc (sizeof (generic_mtrie_t *)\n                                                * it.node->_count));\n                                    alloc_assert (it.node->_next.table);\n\n                                    memmove (it.node->_next.table,\n                                             old_table\n                                               + (it.new_min - it.node->_min),\n                                             sizeof (generic_mtrie_t *)\n                                               * it.node->_count);\n                                    free (old_table);\n\n                                    it.node->_min = it.new_min;\n                                }\n                        }\n                    }\n            }\n        }\n    }\n\n    free (buff);\n}\n\ntemplate <typename T>\ntypename generic_mtrie_t<T>::rm_result\ngeneric_mtrie_t<T>::rm (prefix_t prefix_, size_t size_, value_t *pipe_)\n{\n    //  This used to be implemented as a non-tail recursive traversal of the trie,\n    //  which means remote clients controlled the depth of the recursion and the\n    //  stack size.\n    //  To simulate the non-tail recursion, with post-recursion changes depending on\n    //  the result of the recursive call, a stack is used to re-visit the same node\n    //  and operate on it again after children have been visited.\n    //  A boolean is used to record whether the node had already been visited and to\n    //  determine if the pre- or post- children visit actions have to be taken.\n    rm_result ret = not_found;\n    std::list<struct iter> stack;\n    struct iter it = {this, NULL, prefix_, size_, 0, 0, 0, false};\n    stack.push_back (it);\n\n    while (!stack.empty ()) {\n        it = stack.back ();\n        stack.pop_back ();\n\n        if (!it.processed_for_removal) {\n            if (!it.size) {\n                if (!it.node->_pipes) {\n                    ret = not_found;\n                    continue;\n                }\n\n                typename pipes_t::size_type erased =\n                  it.node->_pipes->erase (pipe_);\n                if (it.node->_pipes->empty ()) {\n                    zmq_assert (erased == 1);\n                    LIBZMQ_DELETE (it.node->_pipes);\n                    ret = last_value_removed;\n                    continue;\n                }\n\n                ret = (erased == 1) ? values_remain : not_found;\n                continue;\n            }\n\n            it.current_child = *it.prefix;\n            if (!it.node->_count || it.current_child < it.node->_min\n                || it.current_child >= it.node->_min + it.node->_count) {\n                ret = not_found;\n                continue;\n            }\n\n            it.next_node =\n              it.node->_count == 1\n                ? it.node->_next.node\n                : it.node->_next.table[it.current_child - it.node->_min];\n            if (!it.next_node) {\n                ret = not_found;\n                continue;\n            }\n\n            it.processed_for_removal = true;\n            stack.push_back (it);\n            struct iter next = {\n              it.next_node, NULL, it.prefix + 1, it.size - 1, 0, 0, 0, false};\n            stack.push_back (next);\n        } else {\n            it.processed_for_removal = false;\n\n            if (it.next_node->is_redundant ()) {\n                LIBZMQ_DELETE (it.next_node);\n                zmq_assert (it.node->_count > 0);\n\n                if (it.node->_count == 1) {\n                    it.node->_next.node = NULL;\n                    it.node->_count = 0;\n                    --it.node->_live_nodes;\n                    zmq_assert (it.node->_live_nodes == 0);\n                } else {\n                    it.node->_next.table[it.current_child - it.node->_min] = 0;\n                    zmq_assert (it.node->_live_nodes > 1);\n                    --it.node->_live_nodes;\n\n                    //  Compact the table if possible\n                    if (it.node->_live_nodes == 1) {\n                        //  If there's only one live node in the table we can\n                        //  switch to using the more compact single-node\n                        //  representation\n                        unsigned short i;\n                        for (i = 0; i < it.node->_count; ++i)\n                            if (it.node->_next.table[i])\n                                break;\n\n                        zmq_assert (i < it.node->_count);\n                        it.node->_min += i;\n                        it.node->_count = 1;\n                        generic_mtrie_t *oldp = it.node->_next.table[i];\n                        free (it.node->_next.table);\n                        it.node->_next.table = NULL;\n                        it.node->_next.node = oldp;\n                    } else if (it.current_child == it.node->_min) {\n                        //  We can compact the table \"from the left\"\n                        unsigned short i;\n                        for (i = 1; i < it.node->_count; ++i)\n                            if (it.node->_next.table[i])\n                                break;\n\n                        zmq_assert (i < it.node->_count);\n                        it.node->_min += i;\n                        it.node->_count -= i;\n                        generic_mtrie_t **old_table = it.node->_next.table;\n                        it.node->_next.table =\n                          static_cast<generic_mtrie_t **> (malloc (\n                            sizeof (generic_mtrie_t *) * it.node->_count));\n                        alloc_assert (it.node->_next.table);\n                        memmove (it.node->_next.table, old_table + i,\n                                 sizeof (generic_mtrie_t *) * it.node->_count);\n                        free (old_table);\n                    } else if (it.current_child\n                               == it.node->_min + it.node->_count - 1) {\n                        //  We can compact the table \"from the right\"\n                        unsigned short i;\n                        for (i = 1; i < it.node->_count; ++i)\n                            if (it.node->_next.table[it.node->_count - 1 - i])\n                                break;\n\n                        zmq_assert (i < it.node->_count);\n                        it.node->_count -= i;\n                        generic_mtrie_t **old_table = it.node->_next.table;\n                        it.node->_next.table =\n                          static_cast<generic_mtrie_t **> (malloc (\n                            sizeof (generic_mtrie_t *) * it.node->_count));\n                        alloc_assert (it.node->_next.table);\n                        memmove (it.node->_next.table, old_table,\n                                 sizeof (generic_mtrie_t *) * it.node->_count);\n                        free (old_table);\n                    }\n                }\n            }\n        }\n    }\n\n    if (ret == last_value_removed) {\n        zmq_assert (_num_prefixes.get () > 0);\n        _num_prefixes.sub (1);\n    }\n\n    return ret;\n}\n\ntemplate <typename T>\ntemplate <typename Arg>\nvoid generic_mtrie_t<T>::match (prefix_t data_,\n                                size_t size_,\n                                void (*func_) (value_t *pipe_, Arg arg_),\n                                Arg arg_)\n{\n    for (generic_mtrie_t *current = this; current; data_++, size_--) {\n        //  Signal the pipes attached to this node.\n        if (current->_pipes) {\n            for (typename pipes_t::iterator it = current->_pipes->begin (),\n                                            end = current->_pipes->end ();\n                 it != end; ++it) {\n                func_ (*it, arg_);\n            }\n        }\n\n        //  If we are at the end of the message, there's nothing more to match.\n        if (!size_)\n            break;\n\n        //  If there are no subnodes in the trie, return.\n        if (current->_count == 0)\n            break;\n\n        if (current->_count == 1) {\n            //  If there's one subnode (optimisation).\n            if (data_[0] != current->_min) {\n                break;\n            }\n            current = current->_next.node;\n        } else {\n            //  If there are multiple subnodes.\n            if (data_[0] < current->_min\n                || data_[0] >= current->_min + current->_count) {\n                break;\n            }\n            current = current->_next.table[data_[0] - current->_min];\n        }\n    }\n}\n\ntemplate <typename T> bool generic_mtrie_t<T>::is_redundant () const\n{\n    return !_pipes && _live_nodes == 0;\n}\n}\n\n\n#endif\n"
  },
  {
    "path": "src/gssapi_client.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#ifdef HAVE_LIBGSSAPI_KRB5\n\n#include <string.h>\n#include <string>\n\n#include \"msg.hpp\"\n#include \"session_base.hpp\"\n#include \"err.hpp\"\n#include \"gssapi_client.hpp\"\n#include \"wire.hpp\"\n\nzmq::gssapi_client_t::gssapi_client_t (session_base_t *session_,\n                                       const options_t &options_) :\n    mechanism_base_t (session_, options_),\n    gssapi_mechanism_base_t (session_, options_),\n    state (call_next_init),\n    token_ptr (GSS_C_NO_BUFFER),\n    mechs (),\n    security_context_established (false)\n{\n    const std::string::size_type service_size =\n      options_.gss_service_principal.size ();\n    service_name = static_cast<char *> (malloc (service_size + 1));\n    assert (service_name);\n    memcpy (service_name, options_.gss_service_principal.c_str (),\n            service_size + 1);\n\n    service_name_type = convert_nametype (options_.gss_service_principal_nt);\n    maj_stat = GSS_S_COMPLETE;\n    if (!options_.gss_principal.empty ()) {\n        const std::string::size_type principal_size =\n          options_.gss_principal.size ();\n        principal_name = static_cast<char *> (malloc (principal_size + 1));\n        assert (principal_name);\n        memcpy (principal_name, options_.gss_principal.c_str (),\n                principal_size + 1);\n\n        gss_OID name_type = convert_nametype (options_.gss_principal_nt);\n        if (acquire_credentials (principal_name, &cred, name_type) != 0)\n            maj_stat = GSS_S_FAILURE;\n    }\n\n    mechs.elements = NULL;\n    mechs.count = 0;\n}\n\nzmq::gssapi_client_t::~gssapi_client_t ()\n{\n    if (service_name)\n        free (service_name);\n    if (cred)\n        gss_release_cred (&min_stat, &cred);\n}\n\nint zmq::gssapi_client_t::next_handshake_command (msg_t *msg_)\n{\n    if (state == send_ready) {\n        int rc = produce_ready (msg_);\n        if (rc == 0)\n            state = connected;\n\n        return rc;\n    }\n\n    if (state != call_next_init) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    if (initialize_context () < 0)\n        return -1;\n\n    if (produce_next_token (msg_) < 0)\n        return -1;\n\n    if (maj_stat != GSS_S_CONTINUE_NEEDED && maj_stat != GSS_S_COMPLETE)\n        return -1;\n\n    if (maj_stat == GSS_S_COMPLETE) {\n        security_context_established = true;\n        state = recv_ready;\n    } else\n        state = recv_next_token;\n\n    return 0;\n}\n\nint zmq::gssapi_client_t::process_handshake_command (msg_t *msg_)\n{\n    if (state == recv_ready) {\n        int rc = process_ready (msg_);\n        if (rc == 0)\n            state = send_ready;\n\n        return rc;\n    }\n\n    if (state != recv_next_token) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n\n    if (process_next_token (msg_) < 0)\n        return -1;\n\n    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)\n        return -1;\n\n    state = call_next_init;\n\n    errno_assert (msg_->close () == 0);\n    errno_assert (msg_->init () == 0);\n\n    return 0;\n}\n\nint zmq::gssapi_client_t::encode (msg_t *msg_)\n{\n    zmq_assert (state == connected);\n\n    if (do_encryption)\n        return encode_message (msg_);\n\n    return 0;\n}\n\nint zmq::gssapi_client_t::decode (msg_t *msg_)\n{\n    zmq_assert (state == connected);\n\n    if (do_encryption)\n        return decode_message (msg_);\n\n    return 0;\n}\n\nzmq::mechanism_t::status_t zmq::gssapi_client_t::status () const\n{\n    return state == connected ? mechanism_t::ready : mechanism_t::handshaking;\n}\n\nint zmq::gssapi_client_t::initialize_context ()\n{\n    // principal was specified but credentials could not be acquired\n    if (principal_name != NULL && cred == NULL)\n        return -1;\n\n    // First time through, import service_name into target_name\n    if (target_name == GSS_C_NO_NAME) {\n        send_tok.value = service_name;\n        send_tok.length = strlen (service_name) + 1;\n        OM_uint32 maj = gss_import_name (&min_stat, &send_tok,\n                                         service_name_type, &target_name);\n\n        if (maj != GSS_S_COMPLETE)\n            return -1;\n    }\n\n    maj_stat = gss_init_sec_context (\n      &init_sec_min_stat, cred, &context, target_name, mechs.elements,\n      gss_flags, 0, NULL, token_ptr, NULL, &send_tok, &ret_flags, NULL);\n\n    if (token_ptr != GSS_C_NO_BUFFER)\n        free (recv_tok.value);\n\n    return 0;\n}\n\nint zmq::gssapi_client_t::produce_next_token (msg_t *msg_)\n{\n    if (send_tok.length != 0) { // Server expects another token\n        if (produce_initiate (msg_, send_tok.value, send_tok.length) < 0) {\n            gss_release_buffer (&min_stat, &send_tok);\n            gss_release_name (&min_stat, &target_name);\n            return -1;\n        }\n    }\n    gss_release_buffer (&min_stat, &send_tok);\n\n    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {\n        gss_release_name (&min_stat, &target_name);\n        if (context != GSS_C_NO_CONTEXT)\n            gss_delete_sec_context (&min_stat, &context, GSS_C_NO_BUFFER);\n        return -1;\n    }\n\n    return 0;\n}\n\nint zmq::gssapi_client_t::process_next_token (msg_t *msg_)\n{\n    if (maj_stat == GSS_S_CONTINUE_NEEDED) {\n        if (process_initiate (msg_, &recv_tok.value, recv_tok.length) < 0) {\n            gss_release_name (&min_stat, &target_name);\n            return -1;\n        }\n        token_ptr = &recv_tok;\n    }\n\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "src/gssapi_client.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_GSSAPI_CLIENT_HPP_INCLUDED__\n#define __ZMQ_GSSAPI_CLIENT_HPP_INCLUDED__\n\n#ifdef HAVE_LIBGSSAPI_KRB5\n\n#include \"gssapi_mechanism_base.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\nclass session_base_t;\n\nclass gssapi_client_t ZMQ_FINAL : public gssapi_mechanism_base_t\n{\n  public:\n    gssapi_client_t (session_base_t *session_, const options_t &options_);\n    ~gssapi_client_t () ZMQ_FINAL;\n\n    // mechanism implementation\n    int next_handshake_command (msg_t *msg_) ZMQ_FINAL;\n    int process_handshake_command (msg_t *msg_) ZMQ_FINAL;\n    int encode (msg_t *msg_) ZMQ_FINAL;\n    int decode (msg_t *msg_) ZMQ_FINAL;\n    status_t status () const ZMQ_FINAL;\n\n  private:\n    enum state_t\n    {\n        call_next_init,\n        send_next_token,\n        recv_next_token,\n        send_ready,\n        recv_ready,\n        connected\n    };\n\n    //  Human-readable principal name of the service we are connecting to\n    char *service_name;\n\n    gss_OID service_name_type;\n\n    //  Current FSM state\n    state_t state;\n\n    //  Points to either send_tok or recv_tok\n    //  during context initialization\n    gss_buffer_desc *token_ptr;\n\n    //  The desired underlying mechanism\n    gss_OID_set_desc mechs;\n\n    //  True iff client considers the server authenticated\n    bool security_context_established;\n\n    int initialize_context ();\n    int produce_next_token (msg_t *msg_);\n    int process_next_token (msg_t *msg_);\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/gssapi_mechanism_base.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#ifdef HAVE_LIBGSSAPI_KRB5\n\n#include <string.h>\n#include <string>\n\n#include \"msg.hpp\"\n#include \"session_base.hpp\"\n#include \"err.hpp\"\n#include \"gssapi_mechanism_base.hpp\"\n#include \"wire.hpp\"\n\nzmq::gssapi_mechanism_base_t::gssapi_mechanism_base_t (\n  session_base_t *session_, const options_t &options_) :\n    mechanism_base_t (session_, options_),\n    send_tok (),\n    recv_tok (),\n    /// FIXME remove? in_buf (),\n    target_name (GSS_C_NO_NAME),\n    principal_name (NULL),\n    maj_stat (GSS_S_COMPLETE),\n    min_stat (0),\n    init_sec_min_stat (0),\n    ret_flags (0),\n    gss_flags (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG),\n    cred (GSS_C_NO_CREDENTIAL),\n    context (GSS_C_NO_CONTEXT),\n    do_encryption (!options_.gss_plaintext)\n{\n}\n\nzmq::gssapi_mechanism_base_t::~gssapi_mechanism_base_t ()\n{\n    if (target_name)\n        gss_release_name (&min_stat, &target_name);\n    if (context)\n        gss_delete_sec_context (&min_stat, &context, GSS_C_NO_BUFFER);\n}\n\nint zmq::gssapi_mechanism_base_t::encode_message (msg_t *msg_)\n{\n    // Wrap the token value\n    int state;\n    gss_buffer_desc plaintext;\n    gss_buffer_desc wrapped;\n\n    uint8_t flags = 0;\n    if (msg_->flags () & msg_t::more)\n        flags |= 0x01;\n    if (msg_->flags () & msg_t::command)\n        flags |= 0x02;\n\n    uint8_t *plaintext_buffer =\n      static_cast<uint8_t *> (malloc (msg_->size () + 1));\n    alloc_assert (plaintext_buffer);\n\n    plaintext_buffer[0] = flags;\n    memcpy (plaintext_buffer + 1, msg_->data (), msg_->size ());\n\n    plaintext.value = plaintext_buffer;\n    plaintext.length = msg_->size () + 1;\n\n    maj_stat = gss_wrap (&min_stat, context, 1, GSS_C_QOP_DEFAULT, &plaintext,\n                         &state, &wrapped);\n\n    zmq_assert (maj_stat == GSS_S_COMPLETE);\n    zmq_assert (state);\n\n    // Re-initialize msg_ for wrapped text\n    int rc = msg_->close ();\n    zmq_assert (rc == 0);\n\n    rc = msg_->init_size (8 + 4 + wrapped.length);\n    zmq_assert (rc == 0);\n\n    uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());\n\n    // Add command string\n    memcpy (ptr, \"\\x07MESSAGE\", 8);\n    ptr += 8;\n\n    // Add token length\n    put_uint32 (ptr, static_cast<uint32_t> (wrapped.length));\n    ptr += 4;\n\n    // Add wrapped token value\n    memcpy (ptr, wrapped.value, wrapped.length);\n    ptr += wrapped.length;\n\n    gss_release_buffer (&min_stat, &wrapped);\n\n    return 0;\n}\n\nint zmq::gssapi_mechanism_base_t::decode_message (msg_t *msg_)\n{\n    const uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());\n    size_t bytes_left = msg_->size ();\n\n    int rc = check_basic_command_structure (msg_);\n    if (rc == -1)\n        return rc;\n\n    // Get command string\n    if (bytes_left < 8 || memcmp (ptr, \"\\x07MESSAGE\", 8)) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n    ptr += 8;\n    bytes_left -= 8;\n\n    // Get token length\n    if (bytes_left < 4) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE);\n        errno = EPROTO;\n        return -1;\n    }\n    gss_buffer_desc wrapped;\n    wrapped.length = get_uint32 (ptr);\n    ptr += 4;\n    bytes_left -= 4;\n\n    // Get token value\n    if (bytes_left < wrapped.length) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE);\n        errno = EPROTO;\n        return -1;\n    }\n    // TODO: instead of malloc/memcpy, can we just do: wrapped.value = ptr;\n    const size_t alloc_length = wrapped.length ? wrapped.length : 1;\n    wrapped.value = static_cast<char *> (malloc (alloc_length));\n    alloc_assert (wrapped.value);\n\n    if (wrapped.length) {\n        memcpy (wrapped.value, ptr, wrapped.length);\n        ptr += wrapped.length;\n        bytes_left -= wrapped.length;\n    }\n\n    // Unwrap the token value\n    int state;\n    gss_buffer_desc plaintext;\n    maj_stat = gss_unwrap (&min_stat, context, &wrapped, &plaintext, &state,\n                           (gss_qop_t *) NULL);\n\n    if (maj_stat != GSS_S_COMPLETE) {\n        gss_release_buffer (&min_stat, &plaintext);\n        free (wrapped.value);\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n        errno = EPROTO;\n        return -1;\n    }\n    zmq_assert (state);\n\n    // Re-initialize msg_ for plaintext\n    rc = msg_->close ();\n    zmq_assert (rc == 0);\n\n    rc = msg_->init_size (plaintext.length - 1);\n    zmq_assert (rc == 0);\n\n    const uint8_t flags = static_cast<char *> (plaintext.value)[0];\n    if (flags & 0x01)\n        msg_->set_flags (msg_t::more);\n    if (flags & 0x02)\n        msg_->set_flags (msg_t::command);\n\n    memcpy (msg_->data (), static_cast<char *> (plaintext.value) + 1,\n            plaintext.length - 1);\n\n    gss_release_buffer (&min_stat, &plaintext);\n    free (wrapped.value);\n\n    if (bytes_left > 0) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE);\n        errno = EPROTO;\n        return -1;\n    }\n\n    return 0;\n}\n\nint zmq::gssapi_mechanism_base_t::produce_initiate (msg_t *msg_,\n                                                    void *token_value_,\n                                                    size_t token_length_)\n{\n    zmq_assert (token_value_);\n    zmq_assert (token_length_ <= 0xFFFFFFFFUL);\n\n    const size_t command_size = 9 + 4 + token_length_;\n\n    const int rc = msg_->init_size (command_size);\n    errno_assert (rc == 0);\n\n    uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());\n\n    // Add command string\n    memcpy (ptr, \"\\x08INITIATE\", 9);\n    ptr += 9;\n\n    // Add token length\n    put_uint32 (ptr, static_cast<uint32_t> (token_length_));\n    ptr += 4;\n\n    // Add token value\n    memcpy (ptr, token_value_, token_length_);\n    ptr += token_length_;\n\n    return 0;\n}\n\nint zmq::gssapi_mechanism_base_t::process_initiate (msg_t *msg_,\n                                                    void **token_value_,\n                                                    size_t &token_length_)\n{\n    zmq_assert (token_value_);\n\n    const uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());\n    size_t bytes_left = msg_->size ();\n\n    int rc = check_basic_command_structure (msg_);\n    if (rc == -1)\n        return rc;\n\n    // Get command string\n    if (bytes_left < 9 || memcmp (ptr, \"\\x08INITIATE\", 9)) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n    ptr += 9;\n    bytes_left -= 9;\n\n    // Get token length\n    if (bytes_left < 4) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);\n        errno = EPROTO;\n        return -1;\n    }\n    token_length_ = get_uint32 (ptr);\n    ptr += 4;\n    bytes_left -= 4;\n\n    // Get token value\n    if (bytes_left < token_length_) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);\n        errno = EPROTO;\n        return -1;\n    }\n\n    *token_value_ =\n      static_cast<char *> (malloc (token_length_ ? token_length_ : 1));\n    alloc_assert (*token_value_);\n\n    if (token_length_) {\n        memcpy (*token_value_, ptr, token_length_);\n        ptr += token_length_;\n        bytes_left -= token_length_;\n    }\n\n    if (bytes_left > 0) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);\n        errno = EPROTO;\n        return -1;\n    }\n\n    return 0;\n}\n\nint zmq::gssapi_mechanism_base_t::produce_ready (msg_t *msg_)\n{\n    make_command_with_basic_properties (msg_, \"\\5READY\", 6);\n\n    if (do_encryption)\n        return encode_message (msg_);\n\n    return 0;\n}\n\nint zmq::gssapi_mechanism_base_t::process_ready (msg_t *msg_)\n{\n    if (do_encryption) {\n        const int rc = decode_message (msg_);\n        if (rc != 0)\n            return rc;\n    }\n\n    const unsigned char *ptr = static_cast<unsigned char *> (msg_->data ());\n    size_t bytes_left = msg_->size ();\n\n    int rc = check_basic_command_structure (msg_);\n    if (rc == -1)\n        return rc;\n\n    if (bytes_left < 6 || memcmp (ptr, \"\\x05READY\", 6)) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n    ptr += 6;\n    bytes_left -= 6;\n    rc = parse_metadata (ptr, bytes_left);\n    if (rc == -1)\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA);\n\n    return rc;\n}\n\nconst gss_OID zmq::gssapi_mechanism_base_t::convert_nametype (int zmq_nametype)\n{\n    switch (zmq_nametype) {\n        case ZMQ_GSSAPI_NT_HOSTBASED:\n            return GSS_C_NT_HOSTBASED_SERVICE;\n        case ZMQ_GSSAPI_NT_USER_NAME:\n            return GSS_C_NT_USER_NAME;\n        case ZMQ_GSSAPI_NT_KRB5_PRINCIPAL:\n#ifdef GSS_KRB5_NT_PRINCIPAL_NAME\n            return (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME;\n#else\n            return GSS_C_NT_USER_NAME;\n#endif\n    }\n    return NULL;\n}\n\nint zmq::gssapi_mechanism_base_t::acquire_credentials (char *service_name_,\n                                                       gss_cred_id_t *cred_,\n                                                       gss_OID name_type_)\n{\n    OM_uint32 maj_stat;\n    OM_uint32 min_stat;\n    gss_name_t server_name;\n\n    gss_buffer_desc name_buf;\n    name_buf.value = service_name_;\n    name_buf.length = strlen ((char *) name_buf.value) + 1;\n\n    maj_stat = gss_import_name (&min_stat, &name_buf, name_type_, &server_name);\n\n    if (maj_stat != GSS_S_COMPLETE)\n        return -1;\n\n    maj_stat = gss_acquire_cred (&min_stat, server_name, 0, GSS_C_NO_OID_SET,\n                                 GSS_C_BOTH, cred_, NULL, NULL);\n\n    if (maj_stat != GSS_S_COMPLETE)\n        return -1;\n\n    gss_release_name (&min_stat, &server_name);\n\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "src/gssapi_mechanism_base.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_GSSAPI_MECHANISM_BASE_HPP_INCLUDED__\n#define __ZMQ_GSSAPI_MECHANISM_BASE_HPP_INCLUDED__\n\n#ifdef HAVE_LIBGSSAPI_KRB5\n\n#if HAVE_GSSAPI_GSSAPI_GENERIC_H\n#include <gssapi/gssapi_generic.h>\n#endif\n#include <gssapi/gssapi_krb5.h>\n\n#include \"mechanism_base.hpp\"\n#include \"options.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\n\n/// Commonalities between clients and servers are captured here.\n/// For example, clients and servers both need to produce and\n/// process context-level GSSAPI tokens (via INITIATE commands)\n/// and per-message GSSAPI tokens (via MESSAGE commands).\nclass gssapi_mechanism_base_t : public virtual mechanism_base_t\n{\n  public:\n    gssapi_mechanism_base_t (session_base_t *session_,\n                             const options_t &options_);\n    ~gssapi_mechanism_base_t () ZMQ_OVERRIDE = 0;\n\n  protected:\n    //  Produce a context-level GSSAPI token (INITIATE command)\n    //  during security context initialization.\n    int produce_initiate (msg_t *msg_, void *data_, size_t data_len_);\n\n    //  Process a context-level GSSAPI token (INITIATE command)\n    //  during security context initialization.\n    int process_initiate (msg_t *msg_, void **data_, size_t &data_len_);\n\n    // Produce a metadata ready msg (READY) to conclude handshake\n    int produce_ready (msg_t *msg_);\n\n    // Process a metadata ready msg (READY)\n    int process_ready (msg_t *msg_);\n\n    //  Encode a per-message GSSAPI token (MESSAGE command) using\n    //  the established security context.\n    int encode_message (msg_t *msg_);\n\n    //  Decode a per-message GSSAPI token (MESSAGE command) using\n    //  the  established security context.\n    int decode_message (msg_t *msg_);\n\n    //  Convert ZMQ_GSSAPI_NT values to GSSAPI name_type\n    static const gss_OID convert_nametype (int zmq_name_type_);\n\n    //  Acquire security context credentials from the\n    //  underlying mechanism.\n    static int acquire_credentials (char *principal_name_,\n                                    gss_cred_id_t *cred_,\n                                    gss_OID name_type_);\n\n  protected:\n    //  Opaque GSSAPI token for outgoing data\n    gss_buffer_desc send_tok;\n\n    //  Opaque GSSAPI token for incoming data\n    gss_buffer_desc recv_tok;\n\n    //  Opaque GSSAPI representation of principal\n    gss_name_t target_name;\n\n    //  Human-readable principal name\n    char *principal_name;\n\n    //  Status code returned by GSSAPI functions\n    OM_uint32 maj_stat;\n\n    //  Status code returned by the underlying mechanism\n    OM_uint32 min_stat;\n\n    //  Status code returned by the underlying mechanism\n    //  during context initialization\n    OM_uint32 init_sec_min_stat;\n\n    //  Flags returned by GSSAPI (ignored)\n    OM_uint32 ret_flags;\n\n    //  Flags returned by GSSAPI (ignored)\n    OM_uint32 gss_flags;\n\n    //  Credentials used to establish security context\n    gss_cred_id_t cred;\n\n    //  Opaque GSSAPI representation of the security context\n    gss_ctx_id_t context;\n\n    //  If true, use gss to encrypt messages. If false, only utilize gss for auth.\n    bool do_encryption;\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/gssapi_server.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#ifdef HAVE_LIBGSSAPI_KRB5\n\n#include <string.h>\n#include <string>\n\n#include \"msg.hpp\"\n#include \"session_base.hpp\"\n#include \"err.hpp\"\n#include \"gssapi_server.hpp\"\n#include \"wire.hpp\"\n\n#include <gssapi/gssapi.h>\n\nzmq::gssapi_server_t::gssapi_server_t (session_base_t *session_,\n                                       const std::string &peer_address_,\n                                       const options_t &options_) :\n    mechanism_base_t (session_, options_),\n    gssapi_mechanism_base_t (session_, options_),\n    zap_client_t (session_, peer_address_, options_),\n    session (session_),\n    peer_address (peer_address_),\n    state (recv_next_token),\n    security_context_established (false)\n{\n    maj_stat = GSS_S_CONTINUE_NEEDED;\n    if (!options_.gss_principal.empty ()) {\n        const std::string::size_type principal_size =\n          options_.gss_principal.size ();\n        principal_name = static_cast<char *> (malloc (principal_size + 1));\n        assert (principal_name);\n        memcpy (principal_name, options_.gss_principal.c_str (),\n                principal_size + 1);\n        gss_OID name_type = convert_nametype (options_.gss_principal_nt);\n        if (acquire_credentials (principal_name, &cred, name_type) != 0)\n            maj_stat = GSS_S_FAILURE;\n    }\n}\n\nzmq::gssapi_server_t::~gssapi_server_t ()\n{\n    if (cred)\n        gss_release_cred (&min_stat, &cred);\n\n    if (target_name)\n        gss_release_name (&min_stat, &target_name);\n}\n\nint zmq::gssapi_server_t::next_handshake_command (msg_t *msg_)\n{\n    if (state == send_ready) {\n        int rc = produce_ready (msg_);\n        if (rc == 0)\n            state = recv_ready;\n\n        return rc;\n    }\n\n    if (state != send_next_token) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    if (produce_next_token (msg_) < 0)\n        return -1;\n\n    if (maj_stat != GSS_S_CONTINUE_NEEDED && maj_stat != GSS_S_COMPLETE)\n        return -1;\n\n    if (maj_stat == GSS_S_COMPLETE) {\n        security_context_established = true;\n    }\n\n    state = recv_next_token;\n\n    return 0;\n}\n\nint zmq::gssapi_server_t::process_handshake_command (msg_t *msg_)\n{\n    if (state == recv_ready) {\n        int rc = process_ready (msg_);\n        if (rc == 0)\n            state = connected;\n\n        return rc;\n    }\n\n    if (state != recv_next_token) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n\n    if (security_context_established) {\n        //  Use ZAP protocol (RFC 27) to authenticate the user.\n        //  Note that rc will be -1 only if ZAP is not set up, but if it was\n        //  requested and it does not work properly the program will abort.\n        bool expecting_zap_reply = false;\n        int rc = session->zap_connect ();\n        if (rc == 0) {\n            send_zap_request ();\n            rc = receive_and_process_zap_reply ();\n            if (rc != 0) {\n                if (rc == -1)\n                    return -1;\n                expecting_zap_reply = true;\n            }\n        }\n        state = expecting_zap_reply ? expect_zap_reply : send_ready;\n        return 0;\n    }\n\n    if (process_next_token (msg_) < 0)\n        return -1;\n\n    accept_context ();\n    state = send_next_token;\n\n    errno_assert (msg_->close () == 0);\n    errno_assert (msg_->init () == 0);\n\n    return 0;\n}\n\nvoid zmq::gssapi_server_t::send_zap_request ()\n{\n    gss_buffer_desc principal;\n    gss_display_name (&min_stat, target_name, &principal, NULL);\n    zap_client_t::send_zap_request (\n      \"GSSAPI\", 6, reinterpret_cast<const uint8_t *> (principal.value),\n      principal.length);\n\n    gss_release_buffer (&min_stat, &principal);\n}\n\nint zmq::gssapi_server_t::encode (msg_t *msg_)\n{\n    zmq_assert (state == connected);\n\n    if (do_encryption)\n        return encode_message (msg_);\n\n    return 0;\n}\n\nint zmq::gssapi_server_t::decode (msg_t *msg_)\n{\n    zmq_assert (state == connected);\n\n    if (do_encryption)\n        return decode_message (msg_);\n\n    return 0;\n}\n\nint zmq::gssapi_server_t::zap_msg_available ()\n{\n    if (state != expect_zap_reply) {\n        errno = EFSM;\n        return -1;\n    }\n    const int rc = receive_and_process_zap_reply ();\n    if (rc == 0)\n        state = send_ready;\n    return rc == -1 ? -1 : 0;\n}\n\nzmq::mechanism_t::status_t zmq::gssapi_server_t::status () const\n{\n    return state == connected ? mechanism_t::ready : mechanism_t::handshaking;\n}\n\nint zmq::gssapi_server_t::produce_next_token (msg_t *msg_)\n{\n    if (send_tok.length != 0) { // Client expects another token\n        if (produce_initiate (msg_, send_tok.value, send_tok.length) < 0)\n            return -1;\n        gss_release_buffer (&min_stat, &send_tok);\n    }\n\n    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {\n        gss_release_name (&min_stat, &target_name);\n        if (context != GSS_C_NO_CONTEXT)\n            gss_delete_sec_context (&min_stat, &context, GSS_C_NO_BUFFER);\n        return -1;\n    }\n\n    return 0;\n}\n\nint zmq::gssapi_server_t::process_next_token (msg_t *msg_)\n{\n    if (maj_stat == GSS_S_CONTINUE_NEEDED) {\n        if (process_initiate (msg_, &recv_tok.value, recv_tok.length) < 0) {\n            if (target_name != GSS_C_NO_NAME)\n                gss_release_name (&min_stat, &target_name);\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\nvoid zmq::gssapi_server_t::accept_context ()\n{\n    maj_stat = gss_accept_sec_context (\n      &init_sec_min_stat, &context, cred, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS,\n      &target_name, &doid, &send_tok, &ret_flags, NULL, NULL);\n\n    if (recv_tok.value) {\n        free (recv_tok.value);\n        recv_tok.value = NULL;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/gssapi_server.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_GSSAPI_SERVER_HPP_INCLUDED__\n#define __ZMQ_GSSAPI_SERVER_HPP_INCLUDED__\n\n#ifdef HAVE_LIBGSSAPI_KRB5\n\n#include \"gssapi_mechanism_base.hpp\"\n#include \"zap_client.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\nclass session_base_t;\n\nclass gssapi_server_t ZMQ_FINAL : public gssapi_mechanism_base_t,\n                                  public zap_client_t\n{\n  public:\n    gssapi_server_t (session_base_t *session_,\n                     const std::string &peer_address,\n                     const options_t &options_);\n    ~gssapi_server_t () ZMQ_FINAL;\n\n    // mechanism implementation\n    int next_handshake_command (msg_t *msg_) ZMQ_FINAL;\n    int process_handshake_command (msg_t *msg_) ZMQ_FINAL;\n    int encode (msg_t *msg_) ZMQ_FINAL;\n    int decode (msg_t *msg_) ZMQ_FINAL;\n    int zap_msg_available () ZMQ_FINAL;\n    status_t status () const ZMQ_FINAL;\n\n  private:\n    enum state_t\n    {\n        send_next_token,\n        recv_next_token,\n        expect_zap_reply,\n        send_ready,\n        recv_ready,\n        connected\n    };\n\n    session_base_t *const session;\n\n    const std::string peer_address;\n\n    //  Current FSM state\n    state_t state;\n\n    //  True iff server considers the client authenticated\n    bool security_context_established;\n\n    //  The underlying mechanism type (ignored)\n    gss_OID doid;\n\n    void accept_context ();\n    int produce_next_token (msg_t *msg_);\n    int process_next_token (msg_t *msg_);\n    void send_zap_request ();\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/i_decoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_I_DECODER_HPP_INCLUDED__\n#define __ZMQ_I_DECODER_HPP_INCLUDED__\n\n#include \"macros.hpp\"\n#include \"stdint.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\n\n//  Interface to be implemented by message decoder.\n\nclass i_decoder\n{\n  public:\n    virtual ~i_decoder () ZMQ_DEFAULT;\n\n    virtual void get_buffer (unsigned char **data_, size_t *size_) = 0;\n\n    virtual void resize_buffer (size_t) = 0;\n    //  Decodes data pointed to by data_.\n    //  When a message is decoded, 1 is returned.\n    //  When the decoder needs more data, 0 is returned.\n    //  On error, -1 is returned and errno is set accordingly.\n    virtual int\n    decode (const unsigned char *data_, size_t size_, size_t &processed_) = 0;\n\n    virtual msg_t *msg () = 0;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/i_encoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_I_ENCODER_HPP_INCLUDED__\n#define __ZMQ_I_ENCODER_HPP_INCLUDED__\n\n#include \"macros.hpp\"\n#include \"stdint.hpp\"\n\nnamespace zmq\n{\n//  Forward declaration\nclass msg_t;\n\n//  Interface to be implemented by message encoder.\n\nstruct i_encoder\n{\n    virtual ~i_encoder () ZMQ_DEFAULT;\n\n    //  The function returns a batch of binary data. The data\n    //  are filled to a supplied buffer. If no buffer is supplied (data_\n    //  is NULL) encoder will provide buffer of its own.\n    //  Function returns 0 when a new message is required.\n    virtual size_t encode (unsigned char **data_, size_t size_) = 0;\n\n    //  Load a new message into encoder.\n    virtual void load_msg (msg_t *msg_) = 0;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/i_engine.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_I_ENGINE_HPP_INCLUDED__\n#define __ZMQ_I_ENGINE_HPP_INCLUDED__\n\n#include \"endpoint.hpp\"\n#include \"macros.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\n\n//  Abstract interface to be implemented by various engines.\n\nstruct i_engine\n{\n    enum error_reason_t\n    {\n        protocol_error,\n        connection_error,\n        timeout_error\n    };\n\n    virtual ~i_engine () ZMQ_DEFAULT;\n\n    //  Indicate if the engine has an handshake stage.\n    //  If engine has handshake stage, engine must call session.engine_ready when the handshake is complete.\n    virtual bool has_handshake_stage () = 0;\n\n    //  Plug the engine to the session.\n    virtual void plug (zmq::io_thread_t *io_thread_,\n                       class session_base_t *session_) = 0;\n\n    //  Terminate and deallocate the engine. Note that 'detached'\n    //  events are not fired on termination.\n    virtual void terminate () = 0;\n\n    //  This method is called by the session to signalise that more\n    //  messages can be written to the pipe.\n    //  Returns false if the engine was deleted due to an error.\n    //  TODO it is probably better to change the design such that the engine\n    //  does not delete itself\n    virtual bool restart_input () = 0;\n\n    //  This method is called by the session to signalise that there\n    //  are messages to send available.\n    virtual void restart_output () = 0;\n\n    virtual void zap_msg_available () = 0;\n\n    virtual const endpoint_uri_pair_t &get_endpoint () const = 0;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/i_mailbox.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_I_MAILBOX_HPP_INCLUDED__\n#define __ZMQ_I_MAILBOX_HPP_INCLUDED__\n\n#include \"macros.hpp\"\n#include \"stdint.hpp\"\n\nnamespace zmq\n{\n//  Interface to be implemented by mailbox.\n\nclass i_mailbox\n{\n  public:\n    virtual ~i_mailbox () ZMQ_DEFAULT;\n\n    virtual void send (const command_t &cmd_) = 0;\n    virtual int recv (command_t *cmd_, int timeout_) = 0;\n\n\n#ifdef HAVE_FORK\n    // close the file descriptors in the signaller. This is used in a forked\n    // child process to close the file descriptors so that they do not interfere\n    // with the context in the parent process.\n    virtual void forked () = 0;\n#endif\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/i_poll_events.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_I_POLL_EVENTS_HPP_INCLUDED__\n#define __ZMQ_I_POLL_EVENTS_HPP_INCLUDED__\n\n#include \"macros.hpp\"\n\nnamespace zmq\n{\n// Virtual interface to be exposed by object that want to be notified\n// about events on file descriptors.\n\nstruct i_poll_events\n{\n    virtual ~i_poll_events () ZMQ_DEFAULT;\n\n    // Called by I/O thread when file descriptor is ready for reading.\n    virtual void in_event () = 0;\n\n    // Called by I/O thread when file descriptor is ready for writing.\n    virtual void out_event () = 0;\n\n    // Called when timer expires.\n    virtual void timer_event (int id_) = 0;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/io_object.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"io_object.hpp\"\n#include \"io_thread.hpp\"\n#include \"err.hpp\"\n\nzmq::io_object_t::io_object_t (io_thread_t *io_thread_) : _poller (NULL)\n{\n    if (io_thread_)\n        plug (io_thread_);\n}\n\nzmq::io_object_t::~io_object_t ()\n{\n}\n\nvoid zmq::io_object_t::plug (io_thread_t *io_thread_)\n{\n    zmq_assert (io_thread_);\n    zmq_assert (!_poller);\n\n    //  Retrieve the poller from the thread we are running in.\n    _poller = io_thread_->get_poller ();\n}\n\nvoid zmq::io_object_t::unplug ()\n{\n    zmq_assert (_poller);\n\n    //  Forget about old poller in preparation to be migrated\n    //  to a different I/O thread.\n    _poller = NULL;\n}\n\nzmq::io_object_t::handle_t zmq::io_object_t::add_fd (fd_t fd_)\n{\n    return _poller->add_fd (fd_, this);\n}\n\nvoid zmq::io_object_t::rm_fd (handle_t handle_)\n{\n    _poller->rm_fd (handle_);\n}\n\nvoid zmq::io_object_t::set_pollin (handle_t handle_)\n{\n    _poller->set_pollin (handle_);\n}\n\nvoid zmq::io_object_t::reset_pollin (handle_t handle_)\n{\n    _poller->reset_pollin (handle_);\n}\n\nvoid zmq::io_object_t::set_pollout (handle_t handle_)\n{\n    _poller->set_pollout (handle_);\n}\n\nvoid zmq::io_object_t::reset_pollout (handle_t handle_)\n{\n    _poller->reset_pollout (handle_);\n}\n\nvoid zmq::io_object_t::add_timer (int timeout_, int id_)\n{\n    _poller->add_timer (timeout_, this, id_);\n}\n\nvoid zmq::io_object_t::cancel_timer (int id_)\n{\n    _poller->cancel_timer (this, id_);\n}\n\nvoid zmq::io_object_t::in_event ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::io_object_t::out_event ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::io_object_t::timer_event (int)\n{\n    zmq_assert (false);\n}\n"
  },
  {
    "path": "src/io_object.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_IO_OBJECT_HPP_INCLUDED__\n#define __ZMQ_IO_OBJECT_HPP_INCLUDED__\n\n#include <stddef.h>\n\n#include \"stdint.hpp\"\n#include \"poller.hpp\"\n#include \"i_poll_events.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\n\n//  Simple base class for objects that live in I/O threads.\n//  It makes communication with the poller object easier and\n//  makes defining unneeded event handlers unnecessary.\n\nclass io_object_t : public i_poll_events\n{\n  public:\n    io_object_t (zmq::io_thread_t *io_thread_ = NULL);\n    ~io_object_t () ZMQ_OVERRIDE;\n\n    //  When migrating an object from one I/O thread to another, first\n    //  unplug it, then migrate it, then plug it to the new thread.\n    void plug (zmq::io_thread_t *io_thread_);\n    void unplug ();\n\n  protected:\n    typedef poller_t::handle_t handle_t;\n\n    //  Methods to access underlying poller object.\n    handle_t add_fd (fd_t fd_);\n    void rm_fd (handle_t handle_);\n    void set_pollin (handle_t handle_);\n    void reset_pollin (handle_t handle_);\n    void set_pollout (handle_t handle_);\n    void reset_pollout (handle_t handle_);\n    void add_timer (int timeout_, int id_);\n    void cancel_timer (int id_);\n\n    //  i_poll_events interface implementation.\n    void in_event () ZMQ_OVERRIDE;\n    void out_event () ZMQ_OVERRIDE;\n    void timer_event (int id_) ZMQ_OVERRIDE;\n\n  private:\n    poller_t *_poller;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (io_object_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/io_thread.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include <new>\n\n#include \"macros.hpp\"\n#include \"io_thread.hpp\"\n#include \"err.hpp\"\n#include \"ctx.hpp\"\n\nzmq::io_thread_t::io_thread_t (ctx_t *ctx_, uint32_t tid_) :\n    object_t (ctx_, tid_),\n    _mailbox_handle (static_cast<poller_t::handle_t> (NULL))\n{\n    _poller = new (std::nothrow) poller_t (*ctx_);\n    alloc_assert (_poller);\n\n    if (_mailbox.get_fd () != retired_fd) {\n        _mailbox_handle = _poller->add_fd (_mailbox.get_fd (), this);\n        _poller->set_pollin (_mailbox_handle);\n    }\n}\n\nzmq::io_thread_t::~io_thread_t ()\n{\n    LIBZMQ_DELETE (_poller);\n}\n\nvoid zmq::io_thread_t::start ()\n{\n    char name[16] = \"\";\n    snprintf (name, sizeof (name), \"IO/%u\",\n              get_tid () - zmq::ctx_t::reaper_tid - 1);\n    //  Start the underlying I/O thread.\n    _poller->start (name);\n}\n\nvoid zmq::io_thread_t::stop ()\n{\n    send_stop ();\n}\n\nzmq::mailbox_t *zmq::io_thread_t::get_mailbox ()\n{\n    return &_mailbox;\n}\n\nint zmq::io_thread_t::get_load () const\n{\n    return _poller->get_load ();\n}\n\nvoid zmq::io_thread_t::in_event ()\n{\n    //  TODO: Do we want to limit number of commands I/O thread can\n    //  process in a single go?\n\n    command_t cmd;\n    int rc = _mailbox.recv (&cmd, 0);\n\n    while (rc == 0 || errno == EINTR) {\n        if (rc == 0)\n            cmd.destination->process_command (cmd);\n        rc = _mailbox.recv (&cmd, 0);\n    }\n\n    errno_assert (rc != 0 && errno == EAGAIN);\n}\n\nvoid zmq::io_thread_t::out_event ()\n{\n    //  We are never polling for POLLOUT here. This function is never called.\n    zmq_assert (false);\n}\n\nvoid zmq::io_thread_t::timer_event (int)\n{\n    //  No timers here. This function is never called.\n    zmq_assert (false);\n}\n\nzmq::poller_t *zmq::io_thread_t::get_poller () const\n{\n    zmq_assert (_poller);\n    return _poller;\n}\n\nvoid zmq::io_thread_t::process_stop ()\n{\n    zmq_assert (_mailbox_handle);\n    _poller->rm_fd (_mailbox_handle);\n    _poller->stop ();\n}\n"
  },
  {
    "path": "src/io_thread.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_IO_THREAD_HPP_INCLUDED__\n#define __ZMQ_IO_THREAD_HPP_INCLUDED__\n\n#include \"stdint.hpp\"\n#include \"object.hpp\"\n#include \"poller.hpp\"\n#include \"i_poll_events.hpp\"\n#include \"mailbox.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\n\n//  Generic part of the I/O thread. Polling-mechanism-specific features\n//  are implemented in separate \"polling objects\".\n\nclass io_thread_t ZMQ_FINAL : public object_t, public i_poll_events\n{\n  public:\n    io_thread_t (zmq::ctx_t *ctx_, uint32_t tid_);\n\n    //  Clean-up. If the thread was started, it's necessary to call 'stop'\n    //  before invoking destructor. Otherwise the destructor would hang up.\n    ~io_thread_t ();\n\n    //  Launch the physical thread.\n    void start ();\n\n    //  Ask underlying thread to stop.\n    void stop ();\n\n    //  Returns mailbox associated with this I/O thread.\n    mailbox_t *get_mailbox ();\n\n    //  i_poll_events implementation.\n    void in_event ();\n    void out_event ();\n    void timer_event (int id_);\n\n    //  Used by io_objects to retrieve the associated poller object.\n    poller_t *get_poller () const;\n\n    //  Command handlers.\n    void process_stop ();\n\n    //  Returns load experienced by the I/O thread.\n    int get_load () const;\n\n  private:\n    //  I/O thread accesses incoming commands via this mailbox.\n    mailbox_t _mailbox;\n\n    //  Handle associated with mailbox' file descriptor.\n    poller_t::handle_t _mailbox_handle;\n\n    //  I/O multiplexing is performed using a poller object.\n    poller_t *_poller;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (io_thread_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ip.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"ip.hpp\"\n#include \"err.hpp\"\n#include \"macros.hpp\"\n#include \"config.hpp\"\n#include \"address.hpp\"\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <fcntl.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <sys/stat.h>\n#include <netdb.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <stdlib.h>\n#include <unistd.h>\n\n#include <vector>\n#else\n#include \"tcp.hpp\"\n#ifdef ZMQ_HAVE_IPC\n#include \"ipc_address.hpp\"\n// Don't try ipc if it fails once\nnamespace zmq\n{\nstatic bool try_ipc_first = true;\n}\n#endif\n\n#include <direct.h>\n\n#define rmdir rmdir_utf8\n#define unlink unlink_utf8\n#endif\n\n#if defined ZMQ_HAVE_OPENVMS || defined ZMQ_HAVE_VXWORKS\n#include <ioctl.h>\n#endif\n\n#if defined ZMQ_HAVE_VXWORKS\n#include <unistd.h>\n#include <sockLib.h>\n#include <ioLib.h>\n#endif\n\n#if defined ZMQ_HAVE_EVENTFD\n#include <sys/eventfd.h>\n#endif\n\n#if defined ZMQ_HAVE_OPENPGM\n#ifdef ZMQ_HAVE_WINDOWS\n#define __PGM_WININT_H__\n#endif\n\n#include <pgm/pgm.h>\n#endif\n\n#ifdef __APPLE__\n#include <TargetConditionals.h>\n#endif\n\n#ifndef ZMQ_HAVE_WINDOWS\n// Acceptable temporary directory environment variables\nstatic const char *tmp_env_vars[] = {\n  \"TMPDIR\", \"TEMPDIR\", \"TMP\",\n  0 // Sentinel\n};\n#endif\n\nzmq::fd_t zmq::open_socket (int domain_, int type_, int protocol_)\n{\n    int rc;\n\n    //  Setting this option result in sane behaviour when exec() functions\n    //  are used. Old sockets are closed and don't block TCP ports etc.\n#if defined ZMQ_HAVE_SOCK_CLOEXEC\n    type_ |= SOCK_CLOEXEC;\n#endif\n\n#if defined ZMQ_HAVE_WINDOWS && defined WSA_FLAG_NO_HANDLE_INHERIT\n    // if supported, create socket with WSA_FLAG_NO_HANDLE_INHERIT, such that\n    // the race condition in making it non-inheritable later is avoided\n    const fd_t s = WSASocket (domain_, type_, protocol_, NULL, 0,\n                              WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);\n#else\n    const fd_t s = socket (domain_, type_, protocol_);\n#endif\n    if (s == retired_fd) {\n#ifdef ZMQ_HAVE_WINDOWS\n        errno = wsa_error_to_errno (WSAGetLastError ());\n#endif\n        return retired_fd;\n    }\n\n    make_socket_noninheritable (s);\n\n    //  Socket is not yet connected so EINVAL is not a valid networking error\n    rc = zmq::set_nosigpipe (s);\n    errno_assert (rc == 0);\n\n    return s;\n}\n\nvoid zmq::unblock_socket (fd_t s_)\n{\n#if defined ZMQ_HAVE_WINDOWS\n    u_long nonblock = 1;\n    const int rc = ioctlsocket (s_, FIONBIO, &nonblock);\n    wsa_assert (rc != SOCKET_ERROR);\n#elif defined ZMQ_HAVE_OPENVMS || defined ZMQ_HAVE_VXWORKS\n    int nonblock = 1;\n    int rc = ioctl (s_, FIONBIO, &nonblock);\n    errno_assert (rc != -1);\n#else\n    int flags = fcntl (s_, F_GETFL, 0);\n    if (flags == -1)\n        flags = 0;\n    int rc = fcntl (s_, F_SETFL, flags | O_NONBLOCK);\n    errno_assert (rc != -1);\n#endif\n}\n\nvoid zmq::enable_ipv4_mapping (fd_t s_)\n{\n    LIBZMQ_UNUSED (s_);\n\n#if defined IPV6_V6ONLY && !defined ZMQ_HAVE_OPENBSD                           \\\n  && !defined ZMQ_HAVE_DRAGONFLY\n#ifdef ZMQ_HAVE_WINDOWS\n    DWORD flag = 0;\n#else\n    int flag = 0;\n#endif\n    const int rc = setsockopt (s_, IPPROTO_IPV6, IPV6_V6ONLY,\n                               reinterpret_cast<char *> (&flag), sizeof (flag));\n#ifdef ZMQ_HAVE_WINDOWS\n    wsa_assert (rc != SOCKET_ERROR);\n#else\n    errno_assert (rc == 0);\n#endif\n#endif\n}\n\nint zmq::get_peer_ip_address (fd_t sockfd_, std::string &ip_addr_)\n{\n    struct sockaddr_storage ss;\n\n    const zmq_socklen_t addrlen =\n      get_socket_address (sockfd_, socket_end_remote, &ss);\n\n    if (addrlen == 0) {\n#ifdef ZMQ_HAVE_WINDOWS\n        const int last_error = WSAGetLastError ();\n        wsa_assert (last_error != WSANOTINITIALISED && last_error != WSAEFAULT\n                    && last_error != WSAEINPROGRESS\n                    && last_error != WSAENOTSOCK);\n#elif !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE\n        errno_assert (errno != EBADF && errno != EFAULT && errno != ENOTSOCK);\n#else\n        errno_assert (errno != EFAULT && errno != ENOTSOCK);\n#endif\n        return 0;\n    }\n\n    char host[NI_MAXHOST];\n    const int rc =\n      getnameinfo (reinterpret_cast<struct sockaddr *> (&ss), addrlen, host,\n                   sizeof host, NULL, 0, NI_NUMERICHOST);\n    if (rc != 0)\n        return 0;\n\n    ip_addr_ = host;\n\n    union\n    {\n        struct sockaddr sa;\n        struct sockaddr_storage sa_stor;\n    } u;\n\n    u.sa_stor = ss;\n    return static_cast<int> (u.sa.sa_family);\n}\n\nvoid zmq::set_ip_type_of_service (fd_t s_, int iptos_)\n{\n    int rc = setsockopt (s_, IPPROTO_IP, IP_TOS,\n                         reinterpret_cast<char *> (&iptos_), sizeof (iptos_));\n\n#ifdef ZMQ_HAVE_WINDOWS\n    wsa_assert (rc != SOCKET_ERROR);\n#else\n    errno_assert (rc == 0);\n#endif\n\n    //  Windows and Hurd do not support IPV6_TCLASS\n#if !defined(ZMQ_HAVE_WINDOWS) && defined(IPV6_TCLASS)\n    rc = setsockopt (s_, IPPROTO_IPV6, IPV6_TCLASS,\n                     reinterpret_cast<char *> (&iptos_), sizeof (iptos_));\n\n    //  If IPv6 is not enabled ENOPROTOOPT will be returned on Linux and\n    //  EINVAL on OSX\n    if (rc == -1) {\n        errno_assert (errno == ENOPROTOOPT || errno == EINVAL);\n    }\n#endif\n}\n\nvoid zmq::set_socket_priority (fd_t s_, int priority_)\n{\n#ifdef ZMQ_HAVE_SO_PRIORITY\n    int rc =\n      setsockopt (s_, SOL_SOCKET, SO_PRIORITY,\n                  reinterpret_cast<char *> (&priority_), sizeof (priority_));\n    errno_assert (rc == 0);\n#else\n    LIBZMQ_UNUSED (s_);\n    LIBZMQ_UNUSED (priority_);\n#endif\n}\n\nint zmq::set_nosigpipe (fd_t s_)\n{\n#ifdef SO_NOSIGPIPE\n    //  Make sure that SIGPIPE signal is not generated when writing to a\n    //  connection that was already closed by the peer.\n    //  As per POSIX spec, EINVAL will be returned if the socket was valid but\n    //  the connection has been reset by the peer. Return an error so that the\n    //  socket can be closed and the connection retried if necessary.\n    int set = 1;\n    int rc = setsockopt (s_, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof (int));\n    if (rc != 0 && errno == EINVAL)\n        return -1;\n    errno_assert (rc == 0);\n#else\n    LIBZMQ_UNUSED (s_);\n#endif\n\n    return 0;\n}\n\nint zmq::bind_to_device (fd_t s_, const std::string &bound_device_)\n{\n#ifdef ZMQ_HAVE_SO_BINDTODEVICE\n    int rc = setsockopt (s_, SOL_SOCKET, SO_BINDTODEVICE,\n                         bound_device_.c_str (), bound_device_.length ());\n    if (rc != 0) {\n        assert_success_or_recoverable (s_, rc);\n        return -1;\n    }\n    return 0;\n\n#else\n    LIBZMQ_UNUSED (s_);\n    LIBZMQ_UNUSED (bound_device_);\n\n    errno = ENOTSUP;\n    return -1;\n#endif\n}\n\nbool zmq::initialize_network ()\n{\n#if defined ZMQ_HAVE_OPENPGM\n\n    //  Init PGM transport. Ensure threading and timer are enabled. Find PGM\n    //  protocol ID. Note that if you want to use gettimeofday and sleep for\n    //  openPGM timing, set environment variables PGM_TIMER to \"GTOD\" and\n    //  PGM_SLEEP to \"USLEEP\".\n    pgm_error_t *pgm_error = NULL;\n    const bool ok = pgm_init (&pgm_error);\n    if (ok != TRUE) {\n        //  Invalid parameters don't set pgm_error_t\n        zmq_assert (pgm_error != NULL);\n        if (pgm_error->domain == PGM_ERROR_DOMAIN_TIME\n            && (pgm_error->code == PGM_ERROR_FAILED)) {\n            //  Failed to access RTC or HPET device.\n            pgm_error_free (pgm_error);\n            errno = EINVAL;\n            return false;\n        }\n\n        //  PGM_ERROR_DOMAIN_ENGINE: WSAStartup errors or missing WSARecvMsg.\n        zmq_assert (false);\n    }\n#endif\n\n#ifdef ZMQ_HAVE_WINDOWS\n    //  Initialise Windows sockets. Note that WSAStartup can be called multiple\n    //  times given that WSACleanup will be called for each WSAStartup.\n\n    const WORD version_requested = MAKEWORD (2, 2);\n    WSADATA wsa_data;\n    const int rc = WSAStartup (version_requested, &wsa_data);\n    zmq_assert (rc == 0);\n    zmq_assert (LOBYTE (wsa_data.wVersion) == 2\n                && HIBYTE (wsa_data.wVersion) == 2);\n#endif\n\n    return true;\n}\n\nvoid zmq::shutdown_network ()\n{\n#ifdef ZMQ_HAVE_WINDOWS\n    //  On Windows, uninitialise socket layer.\n    const int rc = WSACleanup ();\n    wsa_assert (rc != SOCKET_ERROR);\n#endif\n\n#if defined ZMQ_HAVE_OPENPGM\n    //  Shut down the OpenPGM library.\n    if (pgm_shutdown () != TRUE)\n        zmq_assert (false);\n#endif\n}\n\n#if defined ZMQ_HAVE_WINDOWS\nstatic void tune_socket (const SOCKET socket_)\n{\n    BOOL tcp_nodelay = 1;\n    const int rc =\n      setsockopt (socket_, IPPROTO_TCP, TCP_NODELAY,\n                  reinterpret_cast<char *> (&tcp_nodelay), sizeof tcp_nodelay);\n    wsa_assert (rc != SOCKET_ERROR);\n\n    zmq::tcp_tune_loopback_fast_path (socket_);\n}\n\nstatic int make_fdpair_tcpip (zmq::fd_t *r_, zmq::fd_t *w_)\n{\n#if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP\n    //  Windows CE does not manage security attributes\n    SECURITY_DESCRIPTOR sd;\n    SECURITY_ATTRIBUTES sa;\n    memset (&sd, 0, sizeof sd);\n    memset (&sa, 0, sizeof sa);\n\n    InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);\n    SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE);\n\n    sa.nLength = sizeof (SECURITY_ATTRIBUTES);\n    sa.lpSecurityDescriptor = &sd;\n#endif\n\n    //  This function has to be in a system-wide critical section so that\n    //  two instances of the library don't accidentally create signaler\n    //  crossing the process boundary.\n    //  We'll use named event object to implement the critical section.\n    //  Note that if the event object already exists, the CreateEvent requests\n    //  EVENT_ALL_ACCESS access right. If this fails, we try to open\n    //  the event object asking for SYNCHRONIZE access only.\n    HANDLE sync = NULL;\n\n    //  Create critical section only if using fixed signaler port\n    //  Use problematic Event implementation for compatibility if using old port 5905.\n    //  Otherwise use Mutex implementation.\n    const int event_signaler_port = 5905;\n\n    if (zmq::signaler_port == event_signaler_port) {\n#if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP\n        sync =\n          CreateEventW (&sa, FALSE, TRUE, L\"Global\\\\zmq-signaler-port-sync\");\n#else\n        sync =\n          CreateEventW (NULL, FALSE, TRUE, L\"Global\\\\zmq-signaler-port-sync\");\n#endif\n        if (sync == NULL && GetLastError () == ERROR_ACCESS_DENIED)\n            sync = OpenEventW (SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE,\n                               L\"Global\\\\zmq-signaler-port-sync\");\n\n        win_assert (sync != NULL);\n    } else if (zmq::signaler_port != 0) {\n        wchar_t mutex_name[MAX_PATH];\n#ifdef __MINGW32__\n        _snwprintf (mutex_name, MAX_PATH, L\"Global\\\\zmq-signaler-port-%d\",\n                    zmq::signaler_port);\n#else\n        swprintf (mutex_name, MAX_PATH, L\"Global\\\\zmq-signaler-port-%d\",\n                  zmq::signaler_port);\n#endif\n\n#if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP\n        sync = CreateMutexW (&sa, FALSE, mutex_name);\n#else\n        sync = CreateMutexW (NULL, FALSE, mutex_name);\n#endif\n        if (sync == NULL && GetLastError () == ERROR_ACCESS_DENIED)\n            sync = OpenMutexW (SYNCHRONIZE, FALSE, mutex_name);\n\n        win_assert (sync != NULL);\n    }\n\n    //  Windows has no 'socketpair' function. CreatePipe is no good as pipe\n    //  handles cannot be polled on. Here we create the socketpair by hand.\n    *w_ = INVALID_SOCKET;\n    *r_ = INVALID_SOCKET;\n\n    //  Create listening socket.\n    SOCKET listener;\n    listener = zmq::open_socket (AF_INET, SOCK_STREAM, 0);\n    wsa_assert (listener != INVALID_SOCKET);\n\n    //  Set SO_REUSEADDR and TCP_NODELAY on listening socket.\n    BOOL so_reuseaddr = 1;\n    int rc = setsockopt (listener, SOL_SOCKET, SO_REUSEADDR,\n                         reinterpret_cast<char *> (&so_reuseaddr),\n                         sizeof so_reuseaddr);\n    wsa_assert (rc != SOCKET_ERROR);\n\n    tune_socket (listener);\n\n    //  Init sockaddr to signaler port.\n    struct sockaddr_in addr;\n    memset (&addr, 0, sizeof addr);\n    addr.sin_family = AF_INET;\n    addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);\n    addr.sin_port = htons (zmq::signaler_port);\n\n    //  Create the writer socket.\n    *w_ = zmq::open_socket (AF_INET, SOCK_STREAM, 0);\n    wsa_assert (*w_ != INVALID_SOCKET);\n\n    if (sync != NULL) {\n        //  Enter the critical section.\n        const DWORD dwrc = WaitForSingleObject (sync, INFINITE);\n        zmq_assert (dwrc == WAIT_OBJECT_0 || dwrc == WAIT_ABANDONED);\n    }\n\n    //  Bind listening socket to signaler port.\n    rc = bind (listener, reinterpret_cast<const struct sockaddr *> (&addr),\n               sizeof addr);\n\n    if (rc != SOCKET_ERROR && zmq::signaler_port == 0) {\n        //  Retrieve ephemeral port number\n        int addrlen = sizeof addr;\n        rc = getsockname (listener, reinterpret_cast<struct sockaddr *> (&addr),\n                          &addrlen);\n    }\n\n    //  Listen for incoming connections.\n    if (rc != SOCKET_ERROR) {\n        rc = listen (listener, 1);\n    }\n\n    //  Connect writer to the listener.\n    if (rc != SOCKET_ERROR) {\n        rc = connect (*w_, reinterpret_cast<struct sockaddr *> (&addr),\n                      sizeof addr);\n    }\n\n    //  Accept connection from writer.\n    if (rc != SOCKET_ERROR) {\n        //  Set TCP_NODELAY on writer socket.\n        tune_socket (*w_);\n\n        *r_ = accept (listener, NULL, NULL);\n    }\n\n    //  Send/receive large chunk to work around TCP slow start\n    //  This code is a workaround for #1608\n    if (*r_ != INVALID_SOCKET) {\n        const size_t dummy_size =\n          1024 * 1024; //  1M to overload default receive buffer\n        unsigned char *dummy =\n          static_cast<unsigned char *> (malloc (dummy_size));\n        wsa_assert (dummy);\n\n        int still_to_send = static_cast<int> (dummy_size);\n        int still_to_recv = static_cast<int> (dummy_size);\n        while (still_to_send || still_to_recv) {\n            int nbytes;\n            if (still_to_send > 0) {\n                nbytes = ::send (\n                  *w_,\n                  reinterpret_cast<char *> (dummy + dummy_size - still_to_send),\n                  still_to_send, 0);\n                wsa_assert (nbytes != SOCKET_ERROR);\n                still_to_send -= nbytes;\n            }\n            nbytes = ::recv (\n              *r_,\n              reinterpret_cast<char *> (dummy + dummy_size - still_to_recv),\n              still_to_recv, 0);\n            wsa_assert (nbytes != SOCKET_ERROR);\n            still_to_recv -= nbytes;\n        }\n        free (dummy);\n    }\n\n    //  Save errno if error occurred in bind/listen/connect/accept.\n    int saved_errno = 0;\n    if (*r_ == INVALID_SOCKET)\n        saved_errno = WSAGetLastError ();\n\n    //  We don't need the listening socket anymore. Close it.\n    rc = closesocket (listener);\n    wsa_assert (rc != SOCKET_ERROR);\n\n    if (sync != NULL) {\n        //  Exit the critical section.\n        BOOL brc;\n        if (zmq::signaler_port == event_signaler_port)\n            brc = SetEvent (sync);\n        else\n            brc = ReleaseMutex (sync);\n        win_assert (brc != 0);\n\n        //  Release the kernel object\n        brc = CloseHandle (sync);\n        win_assert (brc != 0);\n    }\n\n    if (*r_ != INVALID_SOCKET) {\n        zmq::make_socket_noninheritable (*r_);\n        return 0;\n    }\n    //  Cleanup writer if connection failed\n    if (*w_ != INVALID_SOCKET) {\n        rc = closesocket (*w_);\n        wsa_assert (rc != SOCKET_ERROR);\n        *w_ = INVALID_SOCKET;\n    }\n    //  Set errno from saved value\n    errno = zmq::wsa_error_to_errno (saved_errno);\n    return -1;\n}\n#endif\n\nint zmq::make_fdpair (fd_t *r_, fd_t *w_)\n{\n#if defined ZMQ_HAVE_EVENTFD\n    int flags = 0;\n#if defined ZMQ_HAVE_EVENTFD_CLOEXEC\n    //  Setting this option result in sane behaviour when exec() functions\n    //  are used. Old sockets are closed and don't block TCP ports, avoid\n    //  leaks, etc.\n    flags |= EFD_CLOEXEC;\n#endif\n    fd_t fd = eventfd (0, flags);\n    if (fd == -1) {\n        errno_assert (errno == ENFILE || errno == EMFILE);\n        *w_ = *r_ = -1;\n        return -1;\n    }\n    *w_ = *r_ = fd;\n    return 0;\n\n\n#elif defined ZMQ_HAVE_WINDOWS\n#ifdef ZMQ_HAVE_IPC\n    ipc_address_t address;\n    std::string dirname, filename;\n    sockaddr_un lcladdr;\n    socklen_t lcladdr_len = sizeof lcladdr;\n    int rc = 0;\n    int saved_errno = 0;\n    SOCKET listener = INVALID_SOCKET;\n\n    // It appears that a lack of runtime AF_UNIX support\n    // can fail in more than one way.\n    // At least: open_socket can fail or later in bind or even in connect after bind\n    bool ipc_fallback_on_tcpip = true;\n\n    if (!zmq::try_ipc_first) {\n        // a past ipc attempt failed, skip straight to try_tcpip in the future;\n        goto try_tcpip;\n    }\n\n    //  Create a listening socket.\n    listener = open_socket (AF_UNIX, SOCK_STREAM, 0);\n    if (listener == retired_fd) {\n        //  This may happen if the library was built on a system supporting AF_UNIX, but the system running doesn't support it.\n        goto try_tcpip;\n    }\n\n    rc = create_ipc_wildcard_address (dirname, filename);\n    if (rc != 0) {\n        // This may happen if tmpfile creation fails\n        goto error_closelistener;\n    }\n\n    //  Initialise the address structure.\n    rc = address.resolve (filename.c_str ());\n    if (rc != 0) {\n        goto error_closelistener;\n    }\n\n    //  Bind the socket to the file path.\n    rc = bind (listener, const_cast<sockaddr *> (address.addr ()),\n               address.addrlen ());\n    if (rc != 0) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        goto error_closelistener;\n    }\n    // if we got here, ipc should be working,\n    // but there are at least some cases where connect can still fail\n\n    //  Listen for incoming connections.\n    rc = listen (listener, 1);\n    if (rc != 0) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        goto error_closelistener;\n    }\n\n    rc = getsockname (listener, reinterpret_cast<struct sockaddr *> (&lcladdr),\n                      &lcladdr_len);\n    wsa_assert (rc == 0);\n\n    //  Create the client socket.\n    *w_ = open_socket (AF_UNIX, SOCK_STREAM, 0);\n    if (*w_ == retired_fd) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        goto error_closelistener;\n    }\n\n    //  Connect to the remote peer.\n    rc = ::connect (*w_, reinterpret_cast<const struct sockaddr *> (&lcladdr),\n                    lcladdr_len);\n    if (rc != 0) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        goto error_closeclient;\n    }\n    // if we got here, ipc should be working,\n    // so raise any remaining errors\n    ipc_fallback_on_tcpip = false;\n\n    *r_ = accept (listener, NULL, NULL);\n    wsa_assert (*r_ != retired_fd);\n\n    //  Close the listener socket, we don't need it anymore.\n    rc = closesocket (listener);\n    wsa_assert (rc == 0);\n\n    //  Cleanup temporary socket file descriptor\n    if (!filename.empty ()) {\n        rc = ::unlink (filename.c_str ());\n        if ((rc == 0) && !dirname.empty ()) {\n            rc = ::rmdir (dirname.c_str ());\n            dirname.clear ();\n        }\n        filename.clear ();\n    }\n\n    return 0;\n\nerror_closeclient:\n    saved_errno = errno;\n    rc = closesocket (*w_);\n    wsa_assert (rc == 0);\n    *w_ = retired_fd;\n    errno = saved_errno;\n\nerror_closelistener:\n    saved_errno = errno;\n    rc = closesocket (listener);\n    wsa_assert (rc == 0);\n\n    //  Cleanup temporary socket file descriptor\n    if (!filename.empty ()) {\n        rc = ::unlink (filename.c_str ());\n        if ((rc == 0) && !dirname.empty ()) {\n            rc = ::rmdir (dirname.c_str ());\n            dirname.clear ();\n        }\n        filename.clear ();\n    }\n\n    // ipc failed due to lack of AF_UNIX support, fallback on tcpip\n    if (ipc_fallback_on_tcpip) {\n        goto try_tcpip;\n    }\n\n    errno = saved_errno;\n    return -1;\n\ntry_tcpip:\n    // try to fallback to TCP/IP\n    rc = make_fdpair_tcpip (r_, w_);\n    if (rc == 0 && zmq::try_ipc_first) {\n        // ipc didn't work but tcp/ip did; skip ipc in the future\n        zmq::try_ipc_first = false;\n    }\n    return rc;\n#endif // ZMQ_HAVE_IPC\n    return make_fdpair_tcpip (r_, w_);\n#elif defined ZMQ_HAVE_OPENVMS\n\n    //  Whilst OpenVMS supports socketpair - it maps to AF_INET only.  Further,\n    //  it does not set the socket options TCP_NODELAY and TCP_NODELACK which\n    //  can lead to performance problems.\n    //\n    //  The bug will be fixed in V5.6 ECO4 and beyond.  In the meantime, we'll\n    //  create the socket pair manually.\n    struct sockaddr_in lcladdr;\n    memset (&lcladdr, 0, sizeof lcladdr);\n    lcladdr.sin_family = AF_INET;\n    lcladdr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);\n    lcladdr.sin_port = 0;\n\n    int listener = open_socket (AF_INET, SOCK_STREAM, 0);\n    errno_assert (listener != -1);\n\n    int on = 1;\n    int rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on);\n    errno_assert (rc != -1);\n\n    rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELACK, &on, sizeof on);\n    errno_assert (rc != -1);\n\n    rc = bind (listener, (struct sockaddr *) &lcladdr, sizeof lcladdr);\n    errno_assert (rc != -1);\n\n    socklen_t lcladdr_len = sizeof lcladdr;\n\n    rc = getsockname (listener, (struct sockaddr *) &lcladdr, &lcladdr_len);\n    errno_assert (rc != -1);\n\n    rc = listen (listener, 1);\n    errno_assert (rc != -1);\n\n    *w_ = open_socket (AF_INET, SOCK_STREAM, 0);\n    errno_assert (*w_ != -1);\n\n    rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on);\n    errno_assert (rc != -1);\n\n    rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELACK, &on, sizeof on);\n    errno_assert (rc != -1);\n\n    rc = connect (*w_, (struct sockaddr *) &lcladdr, sizeof lcladdr);\n    errno_assert (rc != -1);\n\n    *r_ = accept (listener, NULL, NULL);\n    errno_assert (*r_ != -1);\n\n    close (listener);\n\n    return 0;\n#elif defined ZMQ_HAVE_VXWORKS\n    struct sockaddr_in lcladdr;\n    memset (&lcladdr, 0, sizeof lcladdr);\n    lcladdr.sin_family = AF_INET;\n    lcladdr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);\n    lcladdr.sin_port = 0;\n\n    int listener = open_socket (AF_INET, SOCK_STREAM, 0);\n    errno_assert (listener != -1);\n\n    int on = 1;\n    int rc =\n      setsockopt (listener, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof on);\n    errno_assert (rc != -1);\n\n    rc = bind (listener, (struct sockaddr *) &lcladdr, sizeof lcladdr);\n    errno_assert (rc != -1);\n\n    socklen_t lcladdr_len = sizeof lcladdr;\n\n    rc = getsockname (listener, (struct sockaddr *) &lcladdr,\n                      (int *) &lcladdr_len);\n    errno_assert (rc != -1);\n\n    rc = listen (listener, 1);\n    errno_assert (rc != -1);\n\n    *w_ = open_socket (AF_INET, SOCK_STREAM, 0);\n    errno_assert (*w_ != -1);\n\n    rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof on);\n    errno_assert (rc != -1);\n\n    rc = connect (*w_, (struct sockaddr *) &lcladdr, sizeof lcladdr);\n    errno_assert (rc != -1);\n\n    *r_ = accept (listener, NULL, NULL);\n    errno_assert (*r_ != -1);\n\n    close (listener);\n\n    return 0;\n#else\n    // All other implementations support socketpair()\n    int sv[2];\n    int type = SOCK_STREAM;\n    //  Setting this option result in sane behaviour when exec() functions\n    //  are used. Old sockets are closed and don't block TCP ports, avoid\n    //  leaks, etc.\n#if defined ZMQ_HAVE_SOCK_CLOEXEC\n    type |= SOCK_CLOEXEC;\n#endif\n    int rc = socketpair (AF_UNIX, type, 0, sv);\n    if (rc == -1) {\n        errno_assert (errno == ENFILE || errno == EMFILE);\n        *w_ = *r_ = -1;\n        return -1;\n    } else {\n        make_socket_noninheritable (sv[0]);\n        make_socket_noninheritable (sv[1]);\n\n        *w_ = sv[0];\n        *r_ = sv[1];\n        return 0;\n    }\n#endif\n}\n\nvoid zmq::make_socket_noninheritable (fd_t sock_)\n{\n#if defined ZMQ_HAVE_WINDOWS && !defined _WIN32_WCE                            \\\n  && !defined ZMQ_HAVE_WINDOWS_UWP\n    //  On Windows, preventing sockets to be inherited by child processes.\n    const BOOL brc = SetHandleInformation (reinterpret_cast<HANDLE> (sock_),\n                                           HANDLE_FLAG_INHERIT, 0);\n    win_assert (brc);\n#elif (!defined ZMQ_HAVE_SOCK_CLOEXEC || !defined HAVE_ACCEPT4)                \\\n  && defined FD_CLOEXEC\n    //  If there 's no SOCK_CLOEXEC, let's try the second best option.\n    //  Race condition can cause socket not to be closed (if fork happens\n    //  between accept and this point).\n    const int rc = fcntl (sock_, F_SETFD, FD_CLOEXEC);\n    errno_assert (rc != -1);\n#else\n    LIBZMQ_UNUSED (sock_);\n#endif\n}\n\nvoid zmq::assert_success_or_recoverable (zmq::fd_t s_, int rc_)\n{\n#ifdef ZMQ_HAVE_WINDOWS\n    if (rc_ != SOCKET_ERROR) {\n        return;\n    }\n#else\n    if (rc_ != -1) {\n        return;\n    }\n#endif\n\n    //  Check whether an error occurred\n    int err = 0;\n#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS\n    int len = sizeof err;\n#else\n    socklen_t len = sizeof err;\n#endif\n\n    const int rc = getsockopt (s_, SOL_SOCKET, SO_ERROR,\n                               reinterpret_cast<char *> (&err), &len);\n\n    //  Assert if the error was caused by 0MQ bug.\n    //  Networking problems are OK. No need to assert.\n#ifdef ZMQ_HAVE_WINDOWS\n    zmq_assert (rc == 0);\n    if (err != 0) {\n        wsa_assert (err == WSAECONNREFUSED || err == WSAECONNRESET\n                    || err == WSAECONNABORTED || err == WSAEINTR\n                    || err == WSAETIMEDOUT || err == WSAEHOSTUNREACH\n                    || err == WSAENETUNREACH || err == WSAENETDOWN\n                    || err == WSAENETRESET || err == WSAEACCES\n                    || err == WSAEINVAL || err == WSAEADDRINUSE);\n    }\n#else\n    //  Following code should handle both Berkeley-derived socket\n    //  implementations and Solaris.\n    if (rc == -1)\n        err = errno;\n    if (err != 0) {\n        errno = err;\n        errno_assert (errno == ECONNREFUSED || errno == ECONNRESET\n                      || errno == ECONNABORTED || errno == EINTR\n                      || errno == ETIMEDOUT || errno == EHOSTUNREACH\n                      || errno == ENETUNREACH || errno == ENETDOWN\n                      || errno == ENETRESET || errno == EINVAL);\n    }\n#endif\n}\n\n#ifdef ZMQ_HAVE_IPC\n\n#if defined ZMQ_HAVE_WINDOWS\nchar *widechar_to_utf8 (const wchar_t *widestring)\n{\n    int nch, n;\n    char *utf8 = 0;\n    nch = WideCharToMultiByte (CP_UTF8, 0, widestring, -1, 0, 0, NULL, NULL);\n    if (nch > 0) {\n        utf8 = (char *) malloc ((nch + 1) * sizeof (char));\n        n = WideCharToMultiByte (CP_UTF8, 0, widestring, -1, utf8, nch, NULL,\n                                 NULL);\n        utf8[nch] = 0;\n    }\n    return utf8;\n}\n#endif\n\nint zmq::create_ipc_wildcard_address (std::string &path_, std::string &file_)\n{\n#if defined ZMQ_HAVE_WINDOWS\n    wchar_t buffer[MAX_PATH];\n\n    {\n        const errno_t rc = _wtmpnam_s (buffer);\n        errno_assert (rc == 0);\n    }\n\n    // TODO or use CreateDirectoryA and specify permissions?\n    const int rc = _wmkdir (buffer);\n    if (rc != 0) {\n        return -1;\n    }\n\n    char *tmp = widechar_to_utf8 (buffer);\n    if (tmp == 0) {\n        return -1;\n    }\n\n    path_.assign (tmp);\n    file_ = path_ + \"/socket\";\n\n    free (tmp);\n#else\n    std::string tmp_path;\n\n    // If TMPDIR, TEMPDIR, or TMP are available and are directories, create\n    // the socket directory there.\n    const char **tmp_env = tmp_env_vars;\n    while (tmp_path.empty () && *tmp_env != 0) {\n        const char *const tmpdir = getenv (*tmp_env);\n        struct stat statbuf;\n\n        // Confirm it is actually a directory before trying to use\n        if (tmpdir != 0 && ::stat (tmpdir, &statbuf) == 0\n            && S_ISDIR (statbuf.st_mode)) {\n            tmp_path.assign (tmpdir);\n            if (*(tmp_path.rbegin ()) != '/') {\n                tmp_path.push_back ('/');\n            }\n        }\n\n        // Try the next environment variable\n        ++tmp_env;\n    }\n\n    // Append a directory name\n    tmp_path.append (\"tmpXXXXXX\");\n\n    // We need room for tmp_path + trailing NUL\n    std::vector<char> buffer (tmp_path.length () + 1);\n    memcpy (&buffer[0], tmp_path.c_str (), tmp_path.length () + 1);\n\n#if defined HAVE_MKDTEMP\n    // Create the directory.  POSIX requires that mkdtemp() creates the\n    // directory with 0700 permissions, meaning the only possible race\n    // with socket creation could be the same user.  However, since\n    // each socket is created in a directory created by mkdtemp(), and\n    // mkdtemp() guarantees a unique directory name, there will be no\n    // collision.\n    if (mkdtemp (&buffer[0]) == 0) {\n        return -1;\n    }\n\n    path_.assign (&buffer[0]);\n    file_ = path_ + \"/socket\";\n#else\n    LIBZMQ_UNUSED (path_);\n    int fd = mkstemp (&buffer[0]);\n    if (fd == -1)\n        return -1;\n    ::close (fd);\n\n    file_.assign (&buffer[0]);\n#endif\n#endif\n\n    return 0;\n}\n#endif\n"
  },
  {
    "path": "src/ip.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_IP_HPP_INCLUDED__\n#define __ZMQ_IP_HPP_INCLUDED__\n\n#include <string>\n#include \"fd.hpp\"\n\nnamespace zmq\n{\n//  Same as socket(2), but allows for transparent tweaking the options.\nfd_t open_socket (int domain_, int type_, int protocol_);\n\n//  Sets the socket into non-blocking mode.\nvoid unblock_socket (fd_t s_);\n\n//  Enable IPv4-mapping of addresses in case it is disabled by default.\nvoid enable_ipv4_mapping (fd_t s_);\n\n//  Returns string representation of peer's address.\n//  Socket sockfd_ must be connected. Returns true iff successful.\nint get_peer_ip_address (fd_t sockfd_, std::string &ip_addr_);\n\n// Sets the IP Type-Of-Service for the underlying socket\nvoid set_ip_type_of_service (fd_t s_, int iptos_);\n\n// Sets the protocol-defined priority for the underlying socket\nvoid set_socket_priority (fd_t s_, int priority_);\n\n// Sets the SO_NOSIGPIPE option for the underlying socket.\n// Return 0 on success, -1 if the connection has been closed by the peer\nint set_nosigpipe (fd_t s_);\n\n// Binds the underlying socket to the given device, eg. VRF or interface\nint bind_to_device (fd_t s_, const std::string &bound_device_);\n\n// Initialize network subsystem. May be called multiple times. Each call must be matched by a call to shutdown_network.\nbool initialize_network ();\n\n// Shutdown network subsystem. Must be called once for each call to initialize_network before terminating.\nvoid shutdown_network ();\n\n// Creates a pair of sockets (using signaler_port on OS using TCP sockets).\n// Returns -1 if we could not make the socket pair successfully\nint make_fdpair (fd_t *r_, fd_t *w_);\n\n// Makes a socket non-inheritable to child processes.\n// Asserts on any failure.\nvoid make_socket_noninheritable (fd_t sock_);\n\n//  Asserts that:\n//  - an internal 0MQ error did not occur,\n//  - and, if a socket error occurred, it can be recovered from.\nvoid assert_success_or_recoverable (fd_t s_, int rc_);\n\n#ifdef ZMQ_HAVE_IPC\n// Create an IPC wildcard path address\nint create_ipc_wildcard_address (std::string &path_, std::string &file_);\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "src/ip_resolver.cpp",
    "content": "#include \"precompiled.hpp\"\n#include <string>\n#include <cstring>\n\n#include \"macros.hpp\"\n#include \"stdint.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <sys/types.h>\n#include <arpa/inet.h>\n#include <netinet/tcp.h>\n#include <net/if.h>\n#include <netdb.h>\n#include <ctype.h>\n#include <unistd.h>\n#include <stdlib.h>\n#endif\n\n#include \"ip_resolver.hpp\"\n\nint zmq::ip_addr_t::family () const\n{\n    return generic.sa_family;\n}\n\nbool zmq::ip_addr_t::is_multicast () const\n{\n    if (family () == AF_INET) {\n        //  IPv4 Multicast: address MSBs are 1110\n        //  Range: 224.0.0.0 - 239.255.255.255\n        return IN_MULTICAST (ntohl (ipv4.sin_addr.s_addr));\n    }\n    //  IPv6 Multicast: ff00::/8\n    return IN6_IS_ADDR_MULTICAST (&ipv6.sin6_addr) != 0;\n}\n\nuint16_t zmq::ip_addr_t::port () const\n{\n    if (family () == AF_INET6) {\n        return ntohs (ipv6.sin6_port);\n    }\n    return ntohs (ipv4.sin_port);\n}\n\nconst struct sockaddr *zmq::ip_addr_t::as_sockaddr () const\n{\n    return &generic;\n}\n\nzmq::zmq_socklen_t zmq::ip_addr_t::sockaddr_len () const\n{\n    return static_cast<zmq_socklen_t> (family () == AF_INET6 ? sizeof (ipv6)\n                                                             : sizeof (ipv4));\n}\n\nvoid zmq::ip_addr_t::set_port (uint16_t port_)\n{\n    if (family () == AF_INET6) {\n        ipv6.sin6_port = htons (port_);\n    } else {\n        ipv4.sin_port = htons (port_);\n    }\n}\n\n//  Construct an \"ANY\" address for the given family\nzmq::ip_addr_t zmq::ip_addr_t::any (int family_)\n{\n    ip_addr_t addr;\n\n    if (family_ == AF_INET) {\n        sockaddr_in *ip4_addr = &addr.ipv4;\n        memset (ip4_addr, 0, sizeof (*ip4_addr));\n        ip4_addr->sin_family = AF_INET;\n        ip4_addr->sin_addr.s_addr = htonl (INADDR_ANY);\n    } else if (family_ == AF_INET6) {\n        sockaddr_in6 *ip6_addr = &addr.ipv6;\n\n        memset (ip6_addr, 0, sizeof (*ip6_addr));\n        ip6_addr->sin6_family = AF_INET6;\n#ifdef ZMQ_HAVE_VXWORKS\n        struct in6_addr newaddr = IN6ADDR_ANY_INIT;\n        memcpy (&ip6_addr->sin6_addr, &newaddr, sizeof (in6_addr));\n#else\n        memcpy (&ip6_addr->sin6_addr, &in6addr_any, sizeof (in6addr_any));\n#endif\n    } else {\n        assert (0 == \"unsupported address family\");\n    }\n\n    return addr;\n}\n\nzmq::ip_resolver_options_t::ip_resolver_options_t () :\n    _bindable_wanted (false),\n    _nic_name_allowed (false),\n    _ipv6_wanted (false),\n    _port_expected (false),\n    _dns_allowed (false),\n    _path_allowed (false)\n{\n}\n\nzmq::ip_resolver_options_t &\nzmq::ip_resolver_options_t::bindable (bool bindable_)\n{\n    _bindable_wanted = bindable_;\n\n    return *this;\n}\n\nzmq::ip_resolver_options_t &\nzmq::ip_resolver_options_t::allow_nic_name (bool allow_)\n{\n    _nic_name_allowed = allow_;\n\n    return *this;\n}\n\nzmq::ip_resolver_options_t &zmq::ip_resolver_options_t::ipv6 (bool ipv6_)\n{\n    _ipv6_wanted = ipv6_;\n\n    return *this;\n}\n\n//  If true we expect that the host will be followed by a colon and a port\n//  number or service name\nzmq::ip_resolver_options_t &\nzmq::ip_resolver_options_t::expect_port (bool expect_)\n{\n    _port_expected = expect_;\n\n    return *this;\n}\n\nzmq::ip_resolver_options_t &zmq::ip_resolver_options_t::allow_dns (bool allow_)\n{\n    _dns_allowed = allow_;\n\n    return *this;\n}\n\nzmq::ip_resolver_options_t &zmq::ip_resolver_options_t::allow_path (bool allow_)\n{\n    _path_allowed = allow_;\n\n    return *this;\n}\n\nbool zmq::ip_resolver_options_t::bindable ()\n{\n    return _bindable_wanted;\n}\n\nbool zmq::ip_resolver_options_t::allow_nic_name ()\n{\n    return _nic_name_allowed;\n}\n\nbool zmq::ip_resolver_options_t::ipv6 ()\n{\n    return _ipv6_wanted;\n}\n\nbool zmq::ip_resolver_options_t::expect_port ()\n{\n    return _port_expected;\n}\n\nbool zmq::ip_resolver_options_t::allow_dns ()\n{\n    return _dns_allowed;\n}\n\nbool zmq::ip_resolver_options_t::allow_path ()\n{\n    return _path_allowed;\n}\n\nzmq::ip_resolver_t::ip_resolver_t (ip_resolver_options_t opts_) :\n    _options (opts_)\n{\n}\n\nint zmq::ip_resolver_t::resolve (ip_addr_t *ip_addr_, const char *name_)\n{\n    std::string addr;\n    uint16_t port;\n\n    if (_options.expect_port ()) {\n        //  We expect 'addr:port'. It's important to use str*r*chr to only get\n        //  the latest colon since IPv6 addresses use colons as delemiters.\n        const char *delim = strrchr (name_, ':');\n\n        if (delim == NULL) {\n            errno = EINVAL;\n            return -1;\n        }\n\n        addr = std::string (name_, delim - name_);\n        const std::string port_str = std::string (delim + 1);\n\n        if (port_str == \"*\") {\n            if (_options.bindable ()) {\n                //  Resolve wildcard to 0 to allow autoselection of port\n                port = 0;\n            } else {\n                errno = EINVAL;\n                return -1;\n            }\n        } else if (port_str == \"0\") {\n            //  Using \"0\" for a bind address is equivalent to using \"*\". For a\n            //  connectable address it could be used to connect to port 0.\n            port = 0;\n        } else {\n            //  Parse the port number (0 is not a valid port).\n            port = static_cast<uint16_t> (atoi (port_str.c_str ()));\n            if (port == 0) {\n                errno = EINVAL;\n                return -1;\n            }\n        }\n    } else {\n        addr = std::string (name_);\n        port = 0;\n    }\n\n    // Check if path is allowed in ip address, if allowed it must be truncated\n    if (_options.allow_path ()) {\n        const size_t pos = addr.find ('/');\n        if (pos != std::string::npos)\n            addr = addr.substr (0, pos);\n    }\n\n    //  Trim any square brackets surrounding the address. Used for\n    //  IPv6 addresses to remove the confusion with the port\n    //  delimiter.\n    //  TODO Should we validate that the brackets are present if\n    //  'addr' contains ':' ?\n    const size_t brackets_length = 2;\n    if (addr.size () >= brackets_length && addr[0] == '['\n        && addr[addr.size () - 1] == ']') {\n        addr = addr.substr (1, addr.size () - brackets_length);\n    }\n\n    //  Look for an interface name / zone_id in the address\n    //  Reference: https://tools.ietf.org/html/rfc4007\n    const std::size_t pos = addr.rfind ('%');\n    uint32_t zone_id = 0;\n\n    if (pos != std::string::npos) {\n        std::string if_str = addr.substr (pos + 1);\n        if (if_str.empty ()) {\n            errno = EINVAL;\n            return -1;\n        }\n        addr = addr.substr (0, pos);\n\n        if (isalpha (if_str.at (0))) {\n            zone_id = do_if_nametoindex (if_str.c_str ());\n        } else {\n            zone_id = static_cast<uint32_t> (atoi (if_str.c_str ()));\n        }\n\n        if (zone_id == 0) {\n            errno = EINVAL;\n            return -1;\n        }\n    }\n\n    bool resolved = false;\n    const char *addr_str = addr.c_str ();\n\n    if (_options.bindable () && addr == \"*\") {\n        //  Return an ANY address\n        *ip_addr_ = ip_addr_t::any (_options.ipv6 () ? AF_INET6 : AF_INET);\n        resolved = true;\n    }\n\n    if (!resolved && _options.allow_nic_name ()) {\n        //  Try to resolve the string as a NIC name.\n        const int rc = resolve_nic_name (ip_addr_, addr_str);\n\n        if (rc == 0) {\n            resolved = true;\n        } else if (errno != ENODEV) {\n            return rc;\n        }\n    }\n\n    if (!resolved) {\n        const int rc = resolve_getaddrinfo (ip_addr_, addr_str);\n\n        if (rc != 0) {\n            return rc;\n        }\n        resolved = true;\n    }\n\n    //  Store the port into the structure. We could get 'getaddrinfo' to do it\n    //  for us but since we don't resolve service names it's a bit overkill and\n    //  we'd still have to do it manually when the address is resolved by\n    //  'resolve_nic_name'\n    ip_addr_->set_port (port);\n\n    if (ip_addr_->family () == AF_INET6) {\n        ip_addr_->ipv6.sin6_scope_id = zone_id;\n    }\n\n    assert (resolved == true);\n    return 0;\n}\n\nint zmq::ip_resolver_t::resolve_getaddrinfo (ip_addr_t *ip_addr_,\n                                             const char *addr_)\n{\n#if defined ZMQ_HAVE_OPENVMS && defined __ia64\n    __addrinfo64 *res = NULL;\n    __addrinfo64 req;\n#else\n    addrinfo *res = NULL;\n    addrinfo req;\n#endif\n\n    memset (&req, 0, sizeof (req));\n\n    //  Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for\n    //  IPv4-in-IPv6 addresses.\n    req.ai_family = _options.ipv6 () ? AF_INET6 : AF_INET;\n\n    //  Arbitrary, not used in the output, but avoids duplicate results.\n    req.ai_socktype = SOCK_STREAM;\n\n    req.ai_flags = 0;\n\n    if (_options.bindable ()) {\n        req.ai_flags |= AI_PASSIVE;\n    }\n\n    if (!_options.allow_dns ()) {\n        req.ai_flags |= AI_NUMERICHOST;\n    }\n\n#if defined AI_V4MAPPED\n    //  In this API we only require IPv4-mapped addresses when\n    //  no native IPv6 interfaces are available (~AI_ALL).\n    //  This saves an additional DNS roundtrip for IPv4 addresses.\n    if (req.ai_family == AF_INET6) {\n        req.ai_flags |= AI_V4MAPPED;\n    }\n#endif\n\n    //  Resolve the literal address. Some of the error info is lost in case\n    //  of error, however, there's no way to report EAI errors via errno.\n    int rc = do_getaddrinfo (addr_, NULL, &req, &res);\n\n#if defined AI_V4MAPPED\n    // Some OS do have AI_V4MAPPED defined but it is not supported in getaddrinfo()\n    // returning EAI_BADFLAGS. Detect this and retry\n    if (rc == EAI_BADFLAGS && (req.ai_flags & AI_V4MAPPED)) {\n        req.ai_flags &= ~AI_V4MAPPED;\n        rc = do_getaddrinfo (addr_, NULL, &req, &res);\n    }\n#endif\n\n#if defined ZMQ_HAVE_WINDOWS\n    //  Resolve specific case on Windows platform when using IPv4 address\n    //  with ZMQ_IPv6 socket option.\n    if ((req.ai_family == AF_INET6) && (rc == WSAHOST_NOT_FOUND)) {\n        req.ai_family = AF_INET;\n        rc = do_getaddrinfo (addr_, NULL, &req, &res);\n    }\n#endif\n\n    if (rc) {\n        switch (rc) {\n            case EAI_MEMORY:\n                errno = ENOMEM;\n                break;\n            default:\n                if (_options.bindable ()) {\n                    errno = ENODEV;\n                } else {\n                    errno = EINVAL;\n                }\n                break;\n        }\n        return -1;\n    }\n\n    //  Use the first result.\n    zmq_assert (res != NULL);\n    zmq_assert (static_cast<size_t> (res->ai_addrlen) <= sizeof (*ip_addr_));\n    memcpy (ip_addr_, res->ai_addr, res->ai_addrlen);\n\n    //  Cleanup getaddrinfo after copying the possibly referenced result.\n    do_freeaddrinfo (res);\n\n    return 0;\n}\n\n#ifdef ZMQ_HAVE_SOLARIS\n#include <sys/sockio.h>\n\n//  On Solaris platform, network interface name can be queried by ioctl.\nint zmq::ip_resolver_t::resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_)\n{\n    //  Create a socket.\n    const int fd = open_socket (AF_INET, SOCK_DGRAM, 0);\n    errno_assert (fd != -1);\n\n    //  Retrieve number of interfaces.\n    lifnum ifn;\n    ifn.lifn_family = AF_INET;\n    ifn.lifn_flags = 0;\n    int rc = ioctl (fd, SIOCGLIFNUM, (char *) &ifn);\n    errno_assert (rc != -1);\n\n    //  Allocate memory to get interface names.\n    const size_t ifr_size = sizeof (struct lifreq) * ifn.lifn_count;\n    char *ifr = (char *) malloc (ifr_size);\n    alloc_assert (ifr);\n\n    //  Retrieve interface names.\n    lifconf ifc;\n    ifc.lifc_family = AF_INET;\n    ifc.lifc_flags = 0;\n    ifc.lifc_len = ifr_size;\n    ifc.lifc_buf = ifr;\n    rc = ioctl (fd, SIOCGLIFCONF, (char *) &ifc);\n    errno_assert (rc != -1);\n\n    //  Find the interface with the specified name and AF_INET family.\n    bool found = false;\n    lifreq *ifrp = ifc.lifc_req;\n    for (int n = 0; n < (int) (ifc.lifc_len / sizeof (lifreq)); n++, ifrp++) {\n        if (!strcmp (nic_, ifrp->lifr_name)) {\n            rc = ioctl (fd, SIOCGLIFADDR, (char *) ifrp);\n            errno_assert (rc != -1);\n            if (ifrp->lifr_addr.ss_family == AF_INET) {\n                ip_addr_->ipv4 = *(sockaddr_in *) &ifrp->lifr_addr;\n                found = true;\n                break;\n            }\n        }\n    }\n\n    //  Clean-up.\n    free (ifr);\n    close (fd);\n\n    if (!found) {\n        errno = ENODEV;\n        return -1;\n    }\n    return 0;\n}\n\n#elif defined ZMQ_HAVE_AIX || defined ZMQ_HAVE_HPUX                            \\\n  || defined ZMQ_HAVE_ANDROID || defined ZMQ_HAVE_VXWORKS\n#include <sys/ioctl.h>\n#ifdef ZMQ_HAVE_VXWORKS\n#include <ioLib.h>\n#endif\n\nint zmq::ip_resolver_t::resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_)\n{\n#if defined ZMQ_HAVE_AIX || defined ZMQ_HAVE_HPUX\n    // IPv6 support not implemented for AIX or HP/UX.\n    if (_options.ipv6 ()) {\n        errno = ENODEV;\n        return -1;\n    }\n#endif\n\n    //  Create a socket.\n    const int sd =\n      open_socket (_options.ipv6 () ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);\n    errno_assert (sd != -1);\n\n    struct ifreq ifr;\n\n    //  Copy interface name for ioctl get.\n    strncpy (ifr.ifr_name, nic_, sizeof (ifr.ifr_name));\n\n    //  Fetch interface address.\n    const int rc = ioctl (sd, SIOCGIFADDR, (caddr_t) &ifr, sizeof (ifr));\n\n    //  Clean up.\n    close (sd);\n\n    if (rc == -1) {\n        errno = ENODEV;\n        return -1;\n    }\n\n    const int family = ifr.ifr_addr.sa_family;\n    if (family == (_options.ipv6 () ? AF_INET6 : AF_INET)\n        && !strcmp (nic_, ifr.ifr_name)) {\n        memcpy (ip_addr_, &ifr.ifr_addr,\n                (family == AF_INET) ? sizeof (struct sockaddr_in)\n                                    : sizeof (struct sockaddr_in6));\n    } else {\n        errno = ENODEV;\n        return -1;\n    }\n\n    return 0;\n}\n\n#elif ((defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD                     \\\n        || defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_OPENBSD                    \\\n        || defined ZMQ_HAVE_QNXNTO || defined ZMQ_HAVE_NETBSD                  \\\n        || defined ZMQ_HAVE_DRAGONFLY || defined ZMQ_HAVE_GNU)                 \\\n       && defined ZMQ_HAVE_IFADDRS)\n\n#include <ifaddrs.h>\n\n//  On these platforms, network interface name can be queried\n//  using getifaddrs function.\nint zmq::ip_resolver_t::resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_)\n{\n    //  Get the addresses.\n    ifaddrs *ifa = NULL;\n    int rc = 0;\n    const int max_attempts = 10;\n    const int backoff_msec = 1;\n    for (int i = 0; i < max_attempts; i++) {\n        rc = getifaddrs (&ifa);\n        if (rc == 0 || (rc < 0 && errno != ECONNREFUSED))\n            break;\n        usleep ((backoff_msec << i) * 1000);\n    }\n\n    if (rc != 0 && ((errno == EINVAL) || (errno == EOPNOTSUPP))) {\n        // Windows Subsystem for Linux compatibility\n        errno = ENODEV;\n        return -1;\n    }\n    errno_assert (rc == 0);\n    zmq_assert (ifa != NULL);\n\n    //  Find the corresponding network interface.\n    bool found = false;\n    for (const ifaddrs *ifp = ifa; ifp != NULL; ifp = ifp->ifa_next) {\n        if (ifp->ifa_addr == NULL)\n            continue;\n\n        const int family = ifp->ifa_addr->sa_family;\n        if (family == (_options.ipv6 () ? AF_INET6 : AF_INET)\n            && !strcmp (nic_, ifp->ifa_name)) {\n            memcpy (ip_addr_, ifp->ifa_addr,\n                    (family == AF_INET) ? sizeof (struct sockaddr_in)\n                                        : sizeof (struct sockaddr_in6));\n            found = true;\n            break;\n        }\n    }\n\n    //  Clean-up;\n    freeifaddrs (ifa);\n\n    if (!found) {\n        errno = ENODEV;\n        return -1;\n    }\n    return 0;\n}\n\n#elif (defined ZMQ_HAVE_WINDOWS)\n\n#include <netioapi.h>\n\nint zmq::ip_resolver_t::get_interface_name (unsigned long index_,\n                                            char **dest_) const\n{\n#ifdef ZMQ_HAVE_WINDOWS_UWP\n    char *buffer = (char *) malloc (1024);\n#else\n    char *buffer = static_cast<char *> (malloc (IF_MAX_STRING_SIZE));\n#endif\n    alloc_assert (buffer);\n\n    char *if_name_result = NULL;\n\n#if _WIN32_WINNT > _WIN32_WINNT_WINXP && !defined ZMQ_HAVE_WINDOWS_UWP\n    if_name_result = if_indextoname (index_, buffer);\n#endif\n\n    if (if_name_result == NULL) {\n        free (buffer);\n        return -1;\n    }\n\n    *dest_ = buffer;\n    return 0;\n}\n\nint zmq::ip_resolver_t::wchar_to_utf8 (const WCHAR *src_, char **dest_) const\n{\n    int rc;\n    const int buffer_len =\n      WideCharToMultiByte (CP_UTF8, 0, src_, -1, NULL, 0, NULL, 0);\n\n    char *buffer = static_cast<char *> (malloc (buffer_len));\n    alloc_assert (buffer);\n\n    rc =\n      WideCharToMultiByte (CP_UTF8, 0, src_, -1, buffer, buffer_len, NULL, 0);\n\n    if (rc == 0) {\n        free (buffer);\n        return -1;\n    }\n\n    *dest_ = buffer;\n    return 0;\n}\n\nint zmq::ip_resolver_t::resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_)\n{\n    int rc;\n    bool found = false;\n    const int max_attempts = 10;\n\n    int iterations = 0;\n    IP_ADAPTER_ADDRESSES *addresses;\n    unsigned long out_buf_len = sizeof (IP_ADAPTER_ADDRESSES);\n\n    do {\n        addresses = static_cast<IP_ADAPTER_ADDRESSES *> (malloc (out_buf_len));\n        alloc_assert (addresses);\n\n        rc =\n          GetAdaptersAddresses (AF_UNSPEC,\n                                GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST\n                                  | GAA_FLAG_SKIP_DNS_SERVER,\n                                NULL, addresses, &out_buf_len);\n        if (rc == ERROR_BUFFER_OVERFLOW) {\n            free (addresses);\n            addresses = NULL;\n        } else {\n            break;\n        }\n        iterations++;\n    } while ((rc == ERROR_BUFFER_OVERFLOW) && (iterations < max_attempts));\n\n    if (rc == 0) {\n        for (const IP_ADAPTER_ADDRESSES *current_addresses = addresses;\n             current_addresses; current_addresses = current_addresses->Next) {\n            char *if_name = NULL;\n            char *if_friendly_name = NULL;\n\n            const int str_rc1 =\n              get_interface_name (current_addresses->IfIndex, &if_name);\n            const int str_rc2 = wchar_to_utf8 (current_addresses->FriendlyName,\n                                               &if_friendly_name);\n\n            //  Find a network adapter by its \"name\" or \"friendly name\"\n            if (((str_rc1 == 0) && (!strcmp (nic_, if_name)))\n                || ((str_rc2 == 0) && (!strcmp (nic_, if_friendly_name)))) {\n                //  Iterate over all unicast addresses bound to the current network interface\n                for (const IP_ADAPTER_UNICAST_ADDRESS *current_unicast_address =\n                       current_addresses->FirstUnicastAddress;\n                     current_unicast_address;\n                     current_unicast_address = current_unicast_address->Next) {\n                    const ADDRESS_FAMILY family =\n                      current_unicast_address->Address.lpSockaddr->sa_family;\n\n                    if (family == (_options.ipv6 () ? AF_INET6 : AF_INET)) {\n                        memcpy (\n                          ip_addr_, current_unicast_address->Address.lpSockaddr,\n                          (family == AF_INET) ? sizeof (struct sockaddr_in)\n                                              : sizeof (struct sockaddr_in6));\n                        found = true;\n                        break;\n                    }\n                }\n\n                if (found)\n                    break;\n            }\n\n            if (str_rc1 == 0)\n                free (if_name);\n            if (str_rc2 == 0)\n                free (if_friendly_name);\n        }\n\n        free (addresses);\n    }\n\n    if (!found) {\n        errno = ENODEV;\n        return -1;\n    }\n    return 0;\n}\n\n#else\n\n//  On other platforms we assume there are no sane interface names.\nint zmq::ip_resolver_t::resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_)\n{\n    LIBZMQ_UNUSED (ip_addr_);\n    LIBZMQ_UNUSED (nic_);\n\n    errno = ENODEV;\n    return -1;\n}\n\n#endif\n\nint zmq::ip_resolver_t::do_getaddrinfo (const char *node_,\n                                        const char *service_,\n                                        const struct addrinfo *hints_,\n                                        struct addrinfo **res_)\n{\n    return getaddrinfo (node_, service_, hints_, res_);\n}\n\nvoid zmq::ip_resolver_t::do_freeaddrinfo (struct addrinfo *res_)\n{\n    freeaddrinfo (res_);\n}\n\n\nunsigned int zmq::ip_resolver_t::do_if_nametoindex (const char *ifname_)\n{\n#ifdef HAVE_IF_NAMETOINDEX\n    return if_nametoindex (ifname_);\n#else\n    LIBZMQ_UNUSED (ifname_);\n    // The function 'if_nametoindex' is not supported on Windows XP.\n    // If we are targeting XP using a vxxx_xp toolset then fail.\n    // This is brutal as this code could be run on later windows clients\n    // meaning the IPv6 zone_id cannot have an interface name.\n    // This could be fixed with a runtime check.\n    return 0;\n#endif\n}\n"
  },
  {
    "path": "src/ip_resolver.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_IP_RESOLVER_HPP_INCLUDED__\n#define __ZMQ_IP_RESOLVER_HPP_INCLUDED__\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netdb.h>\n#endif\n\n#include \"address.hpp\"\n\nnamespace zmq\n{\nunion ip_addr_t\n{\n    sockaddr generic;\n    sockaddr_in ipv4;\n    sockaddr_in6 ipv6;\n\n    int family () const;\n    bool is_multicast () const;\n    uint16_t port () const;\n\n    const struct sockaddr *as_sockaddr () const;\n    zmq_socklen_t sockaddr_len () const;\n\n    void set_port (uint16_t);\n\n    static ip_addr_t any (int family_);\n};\n\nclass ip_resolver_options_t\n{\n  public:\n    ip_resolver_options_t ();\n\n    ip_resolver_options_t &bindable (bool bindable_);\n    ip_resolver_options_t &allow_nic_name (bool allow_);\n    ip_resolver_options_t &ipv6 (bool ipv6_);\n    ip_resolver_options_t &expect_port (bool expect_);\n    ip_resolver_options_t &allow_dns (bool allow_);\n    ip_resolver_options_t &allow_path (bool allow_);\n\n    bool bindable ();\n    bool allow_nic_name ();\n    bool ipv6 ();\n    bool expect_port ();\n    bool allow_dns ();\n    bool allow_path ();\n\n  private:\n    bool _bindable_wanted;\n    bool _nic_name_allowed;\n    bool _ipv6_wanted;\n    bool _port_expected;\n    bool _dns_allowed;\n    bool _path_allowed;\n};\n\nclass ip_resolver_t\n{\n  public:\n    ip_resolver_t (ip_resolver_options_t opts_);\n    virtual ~ip_resolver_t (){};\n\n    int resolve (ip_addr_t *ip_addr_, const char *name_);\n\n  protected:\n    //  Virtual functions that are overridden in tests\n    virtual int do_getaddrinfo (const char *node_,\n                                const char *service_,\n                                const struct addrinfo *hints_,\n                                struct addrinfo **res_);\n\n    virtual void do_freeaddrinfo (struct addrinfo *res_);\n\n    virtual unsigned int do_if_nametoindex (const char *ifname_);\n\n  private:\n    ip_resolver_options_t _options;\n\n    int resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_);\n    int resolve_getaddrinfo (ip_addr_t *ip_addr_, const char *addr_);\n\n#if defined ZMQ_HAVE_WINDOWS\n    int get_interface_name (unsigned long index_, char **dest_) const;\n    int wchar_to_utf8 (const WCHAR *src_, char **dest_) const;\n#endif\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ipc_address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"compat.hpp\"\n#include \"ipc_address.hpp\"\n\n#if defined ZMQ_HAVE_IPC\n\n#include \"err.hpp\"\n\n#include <string>\n\nzmq::ipc_address_t::ipc_address_t ()\n{\n    memset (&_address, 0, sizeof _address);\n}\n\nzmq::ipc_address_t::ipc_address_t (const sockaddr *sa_, socklen_t sa_len_) :\n    _addrlen (sa_len_)\n{\n    zmq_assert (sa_ && sa_len_ > 0);\n\n    memset (&_address, 0, sizeof _address);\n    if (sa_->sa_family == AF_UNIX)\n        memcpy (&_address, sa_, sa_len_);\n}\n\nzmq::ipc_address_t::~ipc_address_t ()\n{\n}\n\nint zmq::ipc_address_t::resolve (const char *path_)\n{\n    const size_t path_len = strlen (path_);\n    if (path_len >= sizeof _address.sun_path) {\n        errno = ENAMETOOLONG;\n        return -1;\n    }\n    if (path_[0] == '@' && !path_[1]) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    _address.sun_family = AF_UNIX;\n    memcpy (_address.sun_path, path_, path_len + 1);\n    /* Abstract sockets start with '\\0' */\n    if (path_[0] == '@')\n        *_address.sun_path = '\\0';\n\n    _addrlen =\n      static_cast<socklen_t> (offsetof (sockaddr_un, sun_path) + path_len);\n    return 0;\n}\n\nint zmq::ipc_address_t::to_string (std::string &addr_) const\n{\n    if (_address.sun_family != AF_UNIX) {\n        addr_.clear ();\n        return -1;\n    }\n\n    const char prefix[] = \"ipc://\";\n    char buf[sizeof prefix + sizeof _address.sun_path];\n    char *pos = buf;\n    memcpy (pos, prefix, sizeof prefix - 1);\n    pos += sizeof prefix - 1;\n    const char *src_pos = _address.sun_path;\n    if (!_address.sun_path[0] && _address.sun_path[1]) {\n        *pos++ = '@';\n        src_pos++;\n    }\n    // according to http://man7.org/linux/man-pages/man7/unix.7.html, NOTES\n    // section, address.sun_path might not always be null-terminated; therefore,\n    // we calculate the length based of addrlen\n    const size_t src_len =\n      strnlen (src_pos, _addrlen - offsetof (sockaddr_un, sun_path)\n                          - (src_pos - _address.sun_path));\n    memcpy (pos, src_pos, src_len);\n    addr_.assign (buf, pos - buf + src_len);\n    return 0;\n}\n\nconst sockaddr *zmq::ipc_address_t::addr () const\n{\n    return reinterpret_cast<const sockaddr *> (&_address);\n}\n\nsocklen_t zmq::ipc_address_t::addrlen () const\n{\n    return _addrlen;\n}\n\n#endif\n"
  },
  {
    "path": "src/ipc_address.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_IPC_ADDRESS_HPP_INCLUDED__\n#define __ZMQ_IPC_ADDRESS_HPP_INCLUDED__\n\n#if defined ZMQ_HAVE_IPC\n\n#include <string>\n\n#if defined ZMQ_HAVE_WINDOWS\n#include <afunix.h>\n#else\n#include <sys/socket.h>\n#include <sys/un.h>\n#endif\n\n#include \"macros.hpp\"\n\nnamespace zmq\n{\nclass ipc_address_t\n{\n  public:\n    ipc_address_t ();\n    ipc_address_t (const sockaddr *sa_, socklen_t sa_len_);\n    ~ipc_address_t ();\n\n    //  This function sets up the address for UNIX domain transport.\n    int resolve (const char *path_);\n\n    //  The opposite to resolve()\n    int to_string (std::string &addr_) const;\n\n    const sockaddr *addr () const;\n    socklen_t addrlen () const;\n\n  private:\n    struct sockaddr_un _address;\n    socklen_t _addrlen;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (ipc_address_t)\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/ipc_connecter.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"ipc_connecter.hpp\"\n\n#if defined ZMQ_HAVE_IPC\n\n#include <new>\n#include <string>\n\n#include \"io_thread.hpp\"\n#include \"random.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"address.hpp\"\n#include \"ipc_address.hpp\"\n#include \"session_base.hpp\"\n\n#if defined ZMQ_HAVE_WINDOWS\n#include <afunix.h>\n#else\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <sys/un.h>\n#endif\n\nzmq::ipc_connecter_t::ipc_connecter_t (class io_thread_t *io_thread_,\n                                       class session_base_t *session_,\n                                       const options_t &options_,\n                                       address_t *addr_,\n                                       bool delayed_start_) :\n    stream_connecter_base_t (\n      io_thread_, session_, options_, addr_, delayed_start_)\n{\n    zmq_assert (_addr->protocol == protocol_name::ipc);\n}\n\nvoid zmq::ipc_connecter_t::out_event ()\n{\n    const fd_t fd = connect ();\n    rm_handle ();\n\n    //  Handle the error condition by attempt to reconnect.\n    if (fd == retired_fd) {\n        close ();\n        add_reconnect_timer ();\n        return;\n    }\n\n    create_engine (fd, get_socket_name<ipc_address_t> (fd, socket_end_local));\n}\n\nvoid zmq::ipc_connecter_t::start_connecting ()\n{\n    //  Open the connecting socket.\n    const int rc = open ();\n\n    //  Connect may succeed in synchronous manner.\n    if (rc == 0) {\n        _handle = add_fd (_s);\n        out_event ();\n    }\n\n    //  Connection establishment may be delayed. Poll for its completion.\n    else if (rc == -1 && errno == EINPROGRESS) {\n        _handle = add_fd (_s);\n        set_pollout (_handle);\n        _socket->event_connect_delayed (\n          make_unconnected_connect_endpoint_pair (_endpoint), zmq_errno ());\n\n        // TODO, tcp_connecter_t adds a connect timer in this case; maybe this\n        // should be done here as well (and then this could be pulled up to\n        // stream_connecter_base_t).\n    }\n    //stop connecting after called zmq_disconnect\n    else if (rc == -1\n             && (options.reconnect_stop & ZMQ_RECONNECT_STOP_AFTER_DISCONNECT)\n             && errno == ECONNREFUSED && _socket->is_disconnected ()) {\n        if (_s != retired_fd)\n            close ();\n    }\n\n    //  Handle any other error condition by eventual reconnect.\n    else {\n        if (_s != retired_fd)\n            close ();\n        add_reconnect_timer ();\n    }\n}\n\nint zmq::ipc_connecter_t::open ()\n{\n    zmq_assert (_s == retired_fd);\n\n    //  Create the socket.\n    _s = open_socket (AF_UNIX, SOCK_STREAM, 0);\n    if (_s == retired_fd)\n        return -1;\n\n    //  Set the non-blocking flag.\n    unblock_socket (_s);\n\n    //  Connect to the remote peer.\n    const int rc = ::connect (_s, _addr->resolved.ipc_addr->addr (),\n                              _addr->resolved.ipc_addr->addrlen ());\n\n    //  Connect was successful immediately.\n    if (rc == 0)\n        return 0;\n\n        //  Translate other error codes indicating asynchronous connect has been\n        //  launched to a uniform EINPROGRESS.\n#ifdef ZMQ_HAVE_WINDOWS\n    const int last_error = WSAGetLastError ();\n    if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK)\n        errno = EINPROGRESS;\n    else\n        errno = wsa_error_to_errno (last_error);\n#else\n    if (rc == -1 && errno == EINTR) {\n        errno = EINPROGRESS;\n    }\n#endif\n\n    //  Forward the error.\n    return -1;\n}\n\nzmq::fd_t zmq::ipc_connecter_t::connect ()\n{\n    //  Following code should handle both Berkeley-derived socket\n    //  implementations and Solaris.\n    int err = 0;\n    zmq_socklen_t len = static_cast<zmq_socklen_t> (sizeof (err));\n    const int rc = getsockopt (_s, SOL_SOCKET, SO_ERROR,\n                               reinterpret_cast<char *> (&err), &len);\n    if (rc == -1) {\n        if (errno == ENOPROTOOPT)\n            errno = 0;\n        err = errno;\n    }\n    if (err != 0) {\n        //  Assert if the error was caused by 0MQ bug.\n        //  Networking problems are OK. No need to assert.\n        errno = err;\n        errno_assert (errno == ECONNREFUSED || errno == ECONNRESET\n                      || errno == ETIMEDOUT || errno == EHOSTUNREACH\n                      || errno == ENETUNREACH || errno == ENETDOWN);\n\n        return retired_fd;\n    }\n\n    const fd_t result = _s;\n    _s = retired_fd;\n    return result;\n}\n\n#endif\n"
  },
  {
    "path": "src/ipc_connecter.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __IPC_CONNECTER_HPP_INCLUDED__\n#define __IPC_CONNECTER_HPP_INCLUDED__\n\n#if defined ZMQ_HAVE_IPC\n\n#include \"fd.hpp\"\n#include \"stream_connecter_base.hpp\"\n\nnamespace zmq\n{\nclass ipc_connecter_t ZMQ_FINAL : public stream_connecter_base_t\n{\n  public:\n    //  If 'delayed_start' is true connecter first waits for a while,\n    //  then starts connection process.\n    ipc_connecter_t (zmq::io_thread_t *io_thread_,\n                     zmq::session_base_t *session_,\n                     const options_t &options_,\n                     address_t *addr_,\n                     bool delayed_start_);\n\n  private:\n    //  Handlers for I/O events.\n    void out_event ();\n\n    //  Internal function to start the actual connection establishment.\n    void start_connecting ();\n\n    //  Open IPC connecting socket. Returns -1 in case of error,\n    //  0 if connect was successful immediately. Returns -1 with\n    //  EAGAIN errno if async connect was launched.\n    int open ();\n\n    //  Get the file descriptor of newly created connection. Returns\n    //  retired_fd if the connection was unsuccessful.\n    fd_t connect ();\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (ipc_connecter_t)\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/ipc_listener.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"ipc_listener.hpp\"\n\n#if defined ZMQ_HAVE_IPC\n\n#include <new>\n\n#include <string.h>\n\n#include \"ipc_address.hpp\"\n#include \"io_thread.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"socket_base.hpp\"\n#include \"address.hpp\"\n\n#ifdef ZMQ_HAVE_WINDOWS\n#ifdef ZMQ_IOTHREAD_POLLER_USE_SELECT\n#error On Windows, IPC does not work with POLLER=select, use POLLER=epoll instead, or disable IPC transport\n#endif\n\n#include <afunix.h>\n#include <direct.h>\n\n#define rmdir rmdir_utf8\n#define unlink unlink_utf8\n\n#else\n#include <unistd.h>\n#include <sys/socket.h>\n#include <fcntl.h>\n#include <sys/un.h>\n#endif\n\n#ifdef ZMQ_HAVE_LOCAL_PEERCRED\n#include <sys/types.h>\n#include <sys/ucred.h>\n#endif\n#ifdef ZMQ_HAVE_SO_PEERCRED\n#include <sys/types.h>\n#include <pwd.h>\n#include <grp.h>\n#if defined ZMQ_HAVE_OPENBSD\n#define ucred sockpeercred\n#endif\n#endif\n\nzmq::ipc_listener_t::ipc_listener_t (io_thread_t *io_thread_,\n                                     socket_base_t *socket_,\n                                     const options_t &options_) :\n    stream_listener_base_t (io_thread_, socket_, options_), _has_file (false)\n{\n}\n\nvoid zmq::ipc_listener_t::in_event ()\n{\n    const fd_t fd = accept ();\n\n    //  If connection was reset by the peer in the meantime, just ignore it.\n    //  TODO: Handle specific errors like ENFILE/EMFILE etc.\n    if (fd == retired_fd) {\n        _socket->event_accept_failed (\n          make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());\n        return;\n    }\n\n    //  Create the engine object for this connection.\n    create_engine (fd);\n}\n\nstd::string\nzmq::ipc_listener_t::get_socket_name (zmq::fd_t fd_,\n                                      socket_end_t socket_end_) const\n{\n    return zmq::get_socket_name<ipc_address_t> (fd_, socket_end_);\n}\n\nint zmq::ipc_listener_t::set_local_address (const char *addr_)\n{\n    //  Create addr on stack for auto-cleanup\n    std::string addr (addr_);\n\n    //  Allow wildcard file\n    if (options.use_fd == -1 && addr[0] == '*') {\n        if (create_ipc_wildcard_address (_tmp_socket_dirname, addr) < 0) {\n            return -1;\n        }\n    }\n\n    //  Get rid of the file associated with the UNIX domain socket that\n    //  may have been left behind by the previous run of the application.\n    //  MUST NOT unlink if the FD is managed by the user, or it will stop\n    //  working after the first client connects. The user will take care of\n    //  cleaning up the file after the service is stopped.\n    if (options.use_fd == -1) {\n        ::unlink (addr.c_str ());\n    }\n    _filename.clear ();\n\n    //  Initialise the address structure.\n    ipc_address_t address;\n    int rc = address.resolve (addr.c_str ());\n    if (rc != 0) {\n        if (!_tmp_socket_dirname.empty ()) {\n            // We need to preserve errno to return to the user\n            const int tmp_errno = errno;\n            ::rmdir (_tmp_socket_dirname.c_str ());\n            _tmp_socket_dirname.clear ();\n            errno = tmp_errno;\n        }\n        return -1;\n    }\n\n    address.to_string (_endpoint);\n\n    if (options.use_fd != -1) {\n        _s = options.use_fd;\n    } else {\n        //  Create a listening socket.\n        _s = open_socket (AF_UNIX, SOCK_STREAM, 0);\n        if (_s == retired_fd) {\n            if (!_tmp_socket_dirname.empty ()) {\n                // We need to preserve errno to return to the user\n                const int tmp_errno = errno;\n                ::rmdir (_tmp_socket_dirname.c_str ());\n                _tmp_socket_dirname.clear ();\n                errno = tmp_errno;\n            }\n            return -1;\n        }\n\n        //  Bind the socket to the file path.\n        rc = bind (_s, const_cast<sockaddr *> (address.addr ()),\n                   address.addrlen ());\n        if (rc != 0)\n            goto error;\n\n        //  Listen for incoming connections.\n        rc = listen (_s, options.backlog);\n        if (rc != 0)\n            goto error;\n    }\n\n    _filename = ZMQ_MOVE (addr);\n    _has_file = true;\n\n    _socket->event_listening (make_unconnected_bind_endpoint_pair (_endpoint),\n                              _s);\n    return 0;\n\nerror:\n    const int err = errno;\n    close ();\n    errno = err;\n    return -1;\n}\n\nint zmq::ipc_listener_t::close ()\n{\n    zmq_assert (_s != retired_fd);\n    const fd_t fd_for_event = _s;\n#ifdef ZMQ_HAVE_WINDOWS\n    int rc = closesocket (_s);\n    wsa_assert (rc != SOCKET_ERROR);\n#else\n    int rc = ::close (_s);\n    errno_assert (rc == 0);\n#endif\n\n    _s = retired_fd;\n\n    if (_has_file && options.use_fd == -1) {\n        if (!_tmp_socket_dirname.empty ()) {\n            //  TODO review this behaviour, it is inconsistent with the use of\n            //  unlink in open since 656cdb959a7482c45db979c1d08ede585d12e315;\n            //  however, we must at least remove the file before removing the\n            //  directory, otherwise it will always fail\n            rc = ::unlink (_filename.c_str ());\n\n            if (rc == 0) {\n                rc = ::rmdir (_tmp_socket_dirname.c_str ());\n                _tmp_socket_dirname.clear ();\n            }\n        }\n\n        if (rc != 0) {\n            _socket->event_close_failed (\n              make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());\n            return -1;\n        }\n    }\n\n    _socket->event_closed (make_unconnected_bind_endpoint_pair (_endpoint),\n                           fd_for_event);\n    return 0;\n}\n\n#if defined ZMQ_HAVE_SO_PEERCRED\n\nbool zmq::ipc_listener_t::filter (fd_t sock_)\n{\n    if (options.ipc_uid_accept_filters.empty ()\n        && options.ipc_pid_accept_filters.empty ()\n        && options.ipc_gid_accept_filters.empty ())\n        return true;\n\n    struct ucred cred;\n    socklen_t size = sizeof (cred);\n\n    if (getsockopt (sock_, SOL_SOCKET, SO_PEERCRED, &cred, &size))\n        return false;\n    if (options.ipc_uid_accept_filters.find (cred.uid)\n          != options.ipc_uid_accept_filters.end ()\n        || options.ipc_gid_accept_filters.find (cred.gid)\n             != options.ipc_gid_accept_filters.end ()\n        || options.ipc_pid_accept_filters.find (cred.pid)\n             != options.ipc_pid_accept_filters.end ())\n        return true;\n\n    const struct passwd *pw;\n    const struct group *gr;\n\n    if (!(pw = getpwuid (cred.uid)))\n        return false;\n    for (options_t::ipc_gid_accept_filters_t::const_iterator\n           it = options.ipc_gid_accept_filters.begin (),\n           end = options.ipc_gid_accept_filters.end ();\n         it != end; it++) {\n        if (!(gr = getgrgid (*it)))\n            continue;\n        for (char **mem = gr->gr_mem; *mem; mem++) {\n            if (!strcmp (*mem, pw->pw_name))\n                return true;\n        }\n    }\n    return false;\n}\n\n#elif defined ZMQ_HAVE_LOCAL_PEERCRED\n\nbool zmq::ipc_listener_t::filter (fd_t sock_)\n{\n    if (options.ipc_uid_accept_filters.empty ()\n        && options.ipc_gid_accept_filters.empty ())\n        return true;\n\n    struct xucred cred;\n    socklen_t size = sizeof (cred);\n\n    if (getsockopt (sock_, 0, LOCAL_PEERCRED, &cred, &size))\n        return false;\n    if (cred.cr_version != XUCRED_VERSION)\n        return false;\n    if (options.ipc_uid_accept_filters.find (cred.cr_uid)\n        != options.ipc_uid_accept_filters.end ())\n        return true;\n    for (int i = 0; i < cred.cr_ngroups; i++) {\n        if (options.ipc_gid_accept_filters.find (cred.cr_groups[i])\n            != options.ipc_gid_accept_filters.end ())\n            return true;\n    }\n\n    return false;\n}\n\n#endif\n\nzmq::fd_t zmq::ipc_listener_t::accept ()\n{\n    //  Accept one connection and deal with different failure modes.\n    //  The situation where connection cannot be accepted due to insufficient\n    //  resources is considered valid and treated by ignoring the connection.\n    zmq_assert (_s != retired_fd);\n#if defined ZMQ_HAVE_SOCK_CLOEXEC && defined HAVE_ACCEPT4\n    fd_t sock = ::accept4 (_s, NULL, NULL, SOCK_CLOEXEC);\n#else\n    struct sockaddr_storage ss;\n    memset (&ss, 0, sizeof (ss));\n#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS\n    int ss_len = sizeof (ss);\n#else\n    socklen_t ss_len = sizeof (ss);\n#endif\n\n    const fd_t sock =\n      ::accept (_s, reinterpret_cast<struct sockaddr *> (&ss), &ss_len);\n#endif\n    if (sock == retired_fd) {\n#if defined ZMQ_HAVE_WINDOWS\n        const int last_error = WSAGetLastError ();\n        wsa_assert (last_error == WSAEWOULDBLOCK || last_error == WSAECONNRESET\n                    || last_error == WSAEMFILE || last_error == WSAENOBUFS);\n#else\n        errno_assert (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR\n                      || errno == ECONNABORTED || errno == EPROTO\n                      || errno == ENFILE);\n#endif\n        return retired_fd;\n    }\n\n    make_socket_noninheritable (sock);\n\n    // IPC accept() filters\n#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\n    if (!filter (sock)) {\n        int rc = ::close (sock);\n        errno_assert (rc == 0);\n        return retired_fd;\n    }\n#endif\n\n    if (zmq::set_nosigpipe (sock)) {\n#ifdef ZMQ_HAVE_WINDOWS\n        const int rc = closesocket (sock);\n        wsa_assert (rc != SOCKET_ERROR);\n#else\n        int rc = ::close (sock);\n        errno_assert (rc == 0);\n#endif\n        return retired_fd;\n    }\n\n    return sock;\n}\n\n#endif\n"
  },
  {
    "path": "src/ipc_listener.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_IPC_LISTENER_HPP_INCLUDED__\n#define __ZMQ_IPC_LISTENER_HPP_INCLUDED__\n\n#if defined ZMQ_HAVE_IPC\n\n#include <string>\n\n#include \"fd.hpp\"\n#include \"stream_listener_base.hpp\"\n\nnamespace zmq\n{\nclass ipc_listener_t ZMQ_FINAL : public stream_listener_base_t\n{\n  public:\n    ipc_listener_t (zmq::io_thread_t *io_thread_,\n                    zmq::socket_base_t *socket_,\n                    const options_t &options_);\n\n    //  Set address to listen on.\n    int set_local_address (const char *addr_);\n\n  protected:\n    std::string get_socket_name (fd_t fd_, socket_end_t socket_end_) const;\n\n  private:\n    //  Handlers for I/O events.\n    void in_event ();\n\n    //  Filter new connections if the OS provides a mechanism to get\n    //  the credentials of the peer process.  Called from accept().\n#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\n    bool filter (fd_t sock_);\n#endif\n\n    int close ();\n\n    //  Accept the new connection. Returns the file descriptor of the\n    //  newly created connection. The function may return retired_fd\n    //  if the connection was dropped while waiting in the listen backlog.\n    fd_t accept ();\n\n    //  True, if the underlying file for UNIX domain socket exists.\n    bool _has_file;\n\n    //  Name of the temporary directory (if any) that has the\n    //  UNIX domain socket\n    std::string _tmp_socket_dirname;\n\n    //  Name of the file associated with the UNIX domain address.\n    std::string _filename;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (ipc_listener_t)\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/kqueue.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"kqueue.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_KQUEUE\n\n#include <sys/time.h>\n#include <sys/types.h>\n#include <sys/event.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <algorithm>\n#include <new>\n\n#include \"macros.hpp\"\n#include \"kqueue.hpp\"\n#include \"err.hpp\"\n#include \"config.hpp\"\n#include \"i_poll_events.hpp\"\n#include \"likely.hpp\"\n\n// NetBSD up to version 9 defines (struct kevent).udata as intptr_t,\n// everyone else as void *.\n#if defined ZMQ_HAVE_NETBSD && defined(ZMQ_NETBSD_KEVENT_UDATA_INTPTR_T)\n#define kevent_udata_t intptr_t\n#else\n#define kevent_udata_t void *\n#endif\n\nzmq::kqueue_t::kqueue_t (const zmq::thread_ctx_t &ctx_) :\n    worker_poller_base_t (ctx_)\n{\n    //  Create event queue\n    kqueue_fd = kqueue ();\n    errno_assert (kqueue_fd != -1);\n#ifdef HAVE_FORK\n    pid = getpid ();\n#endif\n}\n\nzmq::kqueue_t::~kqueue_t ()\n{\n    stop_worker ();\n    close (kqueue_fd);\n}\n\nvoid zmq::kqueue_t::kevent_add (fd_t fd_, short filter_, void *udata_)\n{\n    check_thread ();\n    struct kevent ev;\n\n    EV_SET (&ev, fd_, filter_, EV_ADD, 0, 0, (kevent_udata_t) udata_);\n    int rc = kevent (kqueue_fd, &ev, 1, NULL, 0, NULL);\n    errno_assert (rc != -1);\n}\n\nvoid zmq::kqueue_t::kevent_delete (fd_t fd_, short filter_)\n{\n    struct kevent ev;\n\n    EV_SET (&ev, fd_, filter_, EV_DELETE, 0, 0, 0);\n    int rc = kevent (kqueue_fd, &ev, 1, NULL, 0, NULL);\n    errno_assert (rc != -1);\n}\n\nzmq::kqueue_t::handle_t zmq::kqueue_t::add_fd (fd_t fd_,\n                                               i_poll_events *reactor_)\n{\n    check_thread ();\n    poll_entry_t *pe = new (std::nothrow) poll_entry_t;\n    alloc_assert (pe);\n\n    pe->fd = fd_;\n    pe->flag_pollin = 0;\n    pe->flag_pollout = 0;\n    pe->reactor = reactor_;\n\n    adjust_load (1);\n\n    return pe;\n}\n\nvoid zmq::kqueue_t::rm_fd (handle_t handle_)\n{\n    check_thread ();\n    poll_entry_t *pe = (poll_entry_t *) handle_;\n    if (pe->flag_pollin)\n        kevent_delete (pe->fd, EVFILT_READ);\n    if (pe->flag_pollout)\n        kevent_delete (pe->fd, EVFILT_WRITE);\n    pe->fd = retired_fd;\n    retired.push_back (pe);\n\n    adjust_load (-1);\n}\n\nvoid zmq::kqueue_t::set_pollin (handle_t handle_)\n{\n    check_thread ();\n    poll_entry_t *pe = (poll_entry_t *) handle_;\n    if (likely (!pe->flag_pollin)) {\n        pe->flag_pollin = true;\n        kevent_add (pe->fd, EVFILT_READ, pe);\n    }\n}\n\nvoid zmq::kqueue_t::reset_pollin (handle_t handle_)\n{\n    check_thread ();\n    poll_entry_t *pe = (poll_entry_t *) handle_;\n    if (likely (pe->flag_pollin)) {\n        pe->flag_pollin = false;\n        kevent_delete (pe->fd, EVFILT_READ);\n    }\n}\n\nvoid zmq::kqueue_t::set_pollout (handle_t handle_)\n{\n    check_thread ();\n    poll_entry_t *pe = (poll_entry_t *) handle_;\n    if (likely (!pe->flag_pollout)) {\n        pe->flag_pollout = true;\n        kevent_add (pe->fd, EVFILT_WRITE, pe);\n    }\n}\n\nvoid zmq::kqueue_t::reset_pollout (handle_t handle_)\n{\n    check_thread ();\n    poll_entry_t *pe = (poll_entry_t *) handle_;\n    if (likely (pe->flag_pollout)) {\n        pe->flag_pollout = false;\n        kevent_delete (pe->fd, EVFILT_WRITE);\n    }\n}\n\nvoid zmq::kqueue_t::stop ()\n{\n}\n\nint zmq::kqueue_t::max_fds ()\n{\n    return -1;\n}\n\nvoid zmq::kqueue_t::loop ()\n{\n    while (true) {\n        //  Execute any due timers.\n        int timeout = (int) execute_timers ();\n\n        if (get_load () == 0) {\n            if (timeout == 0)\n                break;\n\n            // TODO sleep for timeout\n            continue;\n        }\n\n        //  Wait for events.\n        struct kevent ev_buf[max_io_events];\n        timespec ts = {timeout / 1000, (timeout % 1000) * 1000000};\n        int n = kevent (kqueue_fd, NULL, 0, &ev_buf[0], max_io_events,\n                        timeout ? &ts : NULL);\n#ifdef HAVE_FORK\n        if (unlikely (pid != getpid ())) {\n            //printf(\"zmq::kqueue_t::loop aborting on forked child %d\\n\", (int)getpid());\n            // simply exit the loop in a forked process.\n            return;\n        }\n#endif\n        if (n == -1) {\n            errno_assert (errno == EINTR);\n            continue;\n        }\n\n        for (int i = 0; i < n; i++) {\n            poll_entry_t *pe = (poll_entry_t *) ev_buf[i].udata;\n\n            if (pe->fd == retired_fd)\n                continue;\n            if (ev_buf[i].flags & EV_EOF)\n                pe->reactor->in_event ();\n            if (pe->fd == retired_fd)\n                continue;\n            if (ev_buf[i].filter == EVFILT_WRITE)\n                pe->reactor->out_event ();\n            if (pe->fd == retired_fd)\n                continue;\n            if (ev_buf[i].filter == EVFILT_READ)\n                pe->reactor->in_event ();\n        }\n\n        //  Destroy retired event sources.\n        for (retired_t::iterator it = retired.begin (); it != retired.end ();\n             ++it) {\n            LIBZMQ_DELETE (*it);\n        }\n        retired.clear ();\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/kqueue.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_KQUEUE_HPP_INCLUDED__\n#define __ZMQ_KQUEUE_HPP_INCLUDED__\n\n//  poller.hpp decides which polling mechanism to use.\n#include \"poller.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_KQUEUE\n\n#include <vector>\n#include <unistd.h>\n\n#include \"ctx.hpp\"\n#include \"fd.hpp\"\n#include \"thread.hpp\"\n#include \"poller_base.hpp\"\n\nnamespace zmq\n{\nstruct i_poll_events;\n\n//  Implements socket polling mechanism using the BSD-specific\n//  kqueue interface.\n\nclass kqueue_t ZMQ_FINAL : public worker_poller_base_t\n{\n  public:\n    typedef void *handle_t;\n\n    kqueue_t (const thread_ctx_t &ctx_);\n    ~kqueue_t () ZMQ_FINAL;\n\n    //  \"poller\" concept.\n    handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);\n    void rm_fd (handle_t handle_);\n    void set_pollin (handle_t handle_);\n    void reset_pollin (handle_t handle_);\n    void set_pollout (handle_t handle_);\n    void reset_pollout (handle_t handle_);\n    void stop ();\n\n    static int max_fds ();\n\n  private:\n    //  Main event loop.\n    void loop () ZMQ_FINAL;\n\n    //  File descriptor referring to the kernel event queue.\n    fd_t kqueue_fd;\n\n    //  Adds the event to the kqueue.\n    void kevent_add (fd_t fd_, short filter_, void *udata_);\n\n    //  Deletes the event from the kqueue.\n    void kevent_delete (fd_t fd_, short filter_);\n\n    struct poll_entry_t\n    {\n        fd_t fd;\n        bool flag_pollin;\n        bool flag_pollout;\n        zmq::i_poll_events *reactor;\n    };\n\n    //  List of retired event sources.\n    typedef std::vector<poll_entry_t *> retired_t;\n    retired_t retired;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (kqueue_t)\n\n#ifdef HAVE_FORK\n    // the process that created this context. Used to detect forking.\n    pid_t pid;\n#endif\n};\n\ntypedef kqueue_t poller_t;\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/lb.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"lb.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n\nzmq::lb_t::lb_t () : _active (0), _current (0), _more (false), _dropping (false)\n{\n}\n\nzmq::lb_t::~lb_t ()\n{\n    zmq_assert (_pipes.empty ());\n}\n\nvoid zmq::lb_t::attach (pipe_t *pipe_)\n{\n    _pipes.push_back (pipe_);\n    activated (pipe_);\n}\n\nvoid zmq::lb_t::pipe_terminated (pipe_t *pipe_)\n{\n    const pipes_t::size_type index = _pipes.index (pipe_);\n\n    //  If we are in the middle of multipart message and current pipe\n    //  have disconnected, we have to drop the remainder of the message.\n    if (index == _current && _more)\n        _dropping = true;\n\n    //  Remove the pipe from the list; adjust number of active pipes\n    //  accordingly.\n    if (index < _active) {\n        _active--;\n        _pipes.swap (index, _active);\n        if (_current == _active)\n            _current = 0;\n    }\n    _pipes.erase (pipe_);\n}\n\nvoid zmq::lb_t::activated (pipe_t *pipe_)\n{\n    //  Move the pipe to the list of active pipes.\n    _pipes.swap (_pipes.index (pipe_), _active);\n    _active++;\n}\n\nint zmq::lb_t::send (msg_t *msg_)\n{\n    return sendpipe (msg_, NULL);\n}\n\nint zmq::lb_t::sendpipe (msg_t *msg_, pipe_t **pipe_)\n{\n    //  Drop the message if required. If we are at the end of the message\n    //  switch back to non-dropping mode.\n    if (_dropping) {\n        _more = (msg_->flags () & msg_t::more) != 0;\n        _dropping = _more;\n\n        int rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n        return 0;\n    }\n\n    while (_active > 0) {\n        if (_pipes[_current]->write (msg_)) {\n            if (pipe_)\n                *pipe_ = _pipes[_current];\n            break;\n        }\n\n        // If send fails for multi-part msg rollback other\n        // parts sent earlier and return EAGAIN.\n        // Application should handle this as suitable\n        if (_more) {\n            _pipes[_current]->rollback ();\n            // At this point the pipe is already being deallocated\n            // and the first N frames are unreachable (_outpipe is\n            // most likely already NULL so rollback won't actually do\n            // anything and they can't be un-written to deliver later).\n            // Return EFAULT to socket_base caller to drop current message\n            // and any other subsequent frames to avoid them being\n            // \"stuck\" and received when a new client reconnects, which\n            // would break atomicity of multi-part messages (in blocking mode\n            // socket_base just tries again and again to send the same message)\n            // Note that given dropping mode returns 0, the user will\n            // never know that the message could not be delivered, but\n            // can't really fix it without breaking backward compatibility.\n            // -2/EAGAIN will make sure socket_base caller does not re-enter\n            // immediately or after a short sleep in blocking mode.\n            _dropping = (msg_->flags () & msg_t::more) != 0;\n            _more = false;\n            errno = EAGAIN;\n            return -2;\n        }\n\n        _active--;\n        if (_current < _active)\n            _pipes.swap (_current, _active);\n        else\n            _current = 0;\n    }\n\n    //  If there are no pipes we cannot send the message.\n    if (_active == 0) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    //  If it's final part of the message we can flush it downstream and\n    //  continue round-robining (load balance).\n    _more = (msg_->flags () & msg_t::more) != 0;\n    if (!_more) {\n        _pipes[_current]->flush ();\n\n        if (++_current >= _active)\n            _current = 0;\n    }\n\n    //  Detach the message from the data buffer.\n    const int rc = msg_->init ();\n    errno_assert (rc == 0);\n\n    return 0;\n}\n\nbool zmq::lb_t::has_out ()\n{\n    //  If one part of the message was already written we can definitely\n    //  write the rest of the message.\n    if (_more)\n        return true;\n\n    while (_active > 0) {\n        //  Check whether a pipe has room for another message.\n        if (_pipes[_current]->check_write ())\n            return true;\n\n        //  Deactivate the pipe.\n        _active--;\n        _pipes.swap (_current, _active);\n        if (_current == _active)\n            _current = 0;\n    }\n\n    return false;\n}\n"
  },
  {
    "path": "src/lb.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_LB_HPP_INCLUDED__\n#define __ZMQ_LB_HPP_INCLUDED__\n\n#include \"array.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\nclass pipe_t;\n\n//  This class manages a set of outbound pipes. On send it load balances\n//  messages fairly among the pipes.\n\nclass lb_t\n{\n  public:\n    lb_t ();\n    ~lb_t ();\n\n    void attach (pipe_t *pipe_);\n    void activated (pipe_t *pipe_);\n    void pipe_terminated (pipe_t *pipe_);\n\n    int send (msg_t *msg_);\n\n    //  Sends a message and stores the pipe that was used in pipe_.\n    //  It is possible for this function to return success but keep pipe_\n    //  unset if the rest of a multipart message to a terminated pipe is\n    //  being dropped. For the first frame, this will never happen.\n    int sendpipe (msg_t *msg_, pipe_t **pipe_);\n\n    bool has_out ();\n\n  private:\n    //  List of outbound pipes.\n    typedef array_t<pipe_t, 2> pipes_t;\n    pipes_t _pipes;\n\n    //  Number of active pipes. All the active pipes are located at the\n    //  beginning of the pipes array.\n    pipes_t::size_type _active;\n\n    //  Points to the last pipe that the most recent message was sent to.\n    pipes_t::size_type _current;\n\n    //  True if last we are in the middle of a multipart message.\n    bool _more;\n\n    //  True if we are dropping current message.\n    bool _dropping;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (lb_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/libzmq.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: libzmq\nDescription: 0MQ c++ library\nVersion: @VERSION@\nLibs: -L${libdir} -lzmq\nLibs.private: -lstdc++ @pkg_config_libs_private@\nRequires.private: @pkg_config_names_private@\nCflags: -I${includedir} @pkg_config_defines@\n"
  },
  {
    "path": "src/libzmq.vers",
    "content": "{\n  global: zmq_*;\n  local: *;\n};\n"
  },
  {
    "path": "src/likely.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_LIKELY_HPP_INCLUDED__\n#define __ZMQ_LIKELY_HPP_INCLUDED__\n\n#if defined __GNUC__\n#define likely(x) __builtin_expect ((x), 1)\n#define unlikely(x) __builtin_expect ((x), 0)\n#else\n#define likely(x) (x)\n#define unlikely(x) (x)\n#endif\n\n\n#endif\n"
  },
  {
    "path": "src/macros.hpp",
    "content": "\n/******************************************************************************/\n/*  0MQ Internal Use                                                          */\n/******************************************************************************/\n\n#define LIBZMQ_UNUSED(object) (void) object\n#define LIBZMQ_DELETE(p_object)                                                \\\n    {                                                                          \\\n        delete p_object;                                                       \\\n        p_object = 0;                                                          \\\n    }\n\n/******************************************************************************/\n\n#if !defined ZMQ_NOEXCEPT\n#if defined ZMQ_HAVE_NOEXCEPT\n#define ZMQ_NOEXCEPT noexcept\n#else\n#define ZMQ_NOEXCEPT\n#endif\n#endif\n\n#if !defined ZMQ_OVERRIDE\n#if defined ZMQ_HAVE_NOEXCEPT\n#define ZMQ_OVERRIDE override\n#else\n#define ZMQ_OVERRIDE\n#endif\n#endif\n\n#if !defined ZMQ_FINAL\n#if defined ZMQ_HAVE_NOEXCEPT\n#define ZMQ_FINAL final\n#else\n#define ZMQ_FINAL\n#endif\n#endif\n\n#if !defined ZMQ_DEFAULT\n#if defined ZMQ_HAVE_NOEXCEPT\n#define ZMQ_DEFAULT = default;\n#else\n#define ZMQ_DEFAULT                                                            \\\n    {                                                                          \\\n    }\n#endif\n#endif\n\n#if !defined ZMQ_NON_COPYABLE_NOR_MOVABLE\n#if defined ZMQ_HAVE_NOEXCEPT\n#define ZMQ_NON_COPYABLE_NOR_MOVABLE(classname)                                \\\n  public:                                                                      \\\n    classname (const classname &) = delete;                                    \\\n    classname &operator= (const classname &) = delete;                         \\\n    classname (classname &&) = delete;                                         \\\n    classname &operator= (classname &&) = delete;\n#else\n#define ZMQ_NON_COPYABLE_NOR_MOVABLE(classname)                                \\\n  private:                                                                     \\\n    classname (const classname &);                                             \\\n    classname &operator= (const classname &);\n#endif\n#endif\n"
  },
  {
    "path": "src/mailbox.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"mailbox.hpp\"\n#include \"err.hpp\"\n\nzmq::mailbox_t::mailbox_t ()\n{\n    //  Get the pipe into passive state. That way, if the users starts by\n    //  polling on the associated file descriptor it will get woken up when\n    //  new command is posted.\n    const bool ok = _cpipe.check_read ();\n    zmq_assert (!ok);\n    _active = false;\n}\n\nzmq::mailbox_t::~mailbox_t ()\n{\n    //  TODO: Retrieve and deallocate commands inside the _cpipe.\n\n    // Work around problem that other threads might still be in our\n    // send() method, by waiting on the mutex before disappearing.\n    _sync.lock ();\n    _sync.unlock ();\n}\n\nzmq::fd_t zmq::mailbox_t::get_fd () const\n{\n    return _signaler.get_fd ();\n}\n\nvoid zmq::mailbox_t::send (const command_t &cmd_)\n{\n    _sync.lock ();\n    _cpipe.write (cmd_, false);\n    const bool ok = _cpipe.flush ();\n    _sync.unlock ();\n    if (!ok)\n        _signaler.send ();\n}\n\nint zmq::mailbox_t::recv (command_t *cmd_, int timeout_)\n{\n    //  Try to get the command straight away.\n    if (_active) {\n        if (_cpipe.read (cmd_))\n            return 0;\n\n        //  If there are no more commands available, switch into passive state.\n        _active = false;\n    }\n\n    //  Wait for signal from the command sender.\n    int rc = _signaler.wait (timeout_);\n    if (rc == -1) {\n        errno_assert (errno == EAGAIN || errno == EINTR);\n        return -1;\n    }\n\n    //  Receive the signal.\n    rc = _signaler.recv_failable ();\n    if (rc == -1) {\n        errno_assert (errno == EAGAIN);\n        return -1;\n    }\n\n    //  Switch into active state.\n    _active = true;\n\n    //  Get a command.\n    const bool ok = _cpipe.read (cmd_);\n    zmq_assert (ok);\n    return 0;\n}\n\nbool zmq::mailbox_t::valid () const\n{\n    return _signaler.valid ();\n}\n"
  },
  {
    "path": "src/mailbox.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_MAILBOX_HPP_INCLUDED__\n#define __ZMQ_MAILBOX_HPP_INCLUDED__\n\n#include <stddef.h>\n\n#include \"signaler.hpp\"\n#include \"fd.hpp\"\n#include \"config.hpp\"\n#include \"command.hpp\"\n#include \"ypipe.hpp\"\n#include \"mutex.hpp\"\n#include \"i_mailbox.hpp\"\n\nnamespace zmq\n{\nclass mailbox_t ZMQ_FINAL : public i_mailbox\n{\n  public:\n    mailbox_t ();\n    ~mailbox_t ();\n\n    fd_t get_fd () const;\n    void send (const command_t &cmd_);\n    int recv (command_t *cmd_, int timeout_);\n\n    bool valid () const;\n\n#ifdef HAVE_FORK\n    // close the file descriptors in the signaller. This is used in a forked\n    // child process to close the file descriptors so that they do not interfere\n    // with the context in the parent process.\n    void forked () ZMQ_FINAL { _signaler.forked (); }\n#endif\n\n  private:\n    //  The pipe to store actual commands.\n    typedef ypipe_t<command_t, command_pipe_granularity> cpipe_t;\n    cpipe_t _cpipe;\n\n    //  Signaler to pass signals from writer thread to reader thread.\n    signaler_t _signaler;\n\n    //  There's only one thread receiving from the mailbox, but there\n    //  is arbitrary number of threads sending. Given that ypipe requires\n    //  synchronised access on both of its endpoints, we have to synchronise\n    //  the sending side.\n    mutex_t _sync;\n\n    //  True if the underlying pipe is active, ie. when we are allowed to\n    //  read commands from it.\n    bool _active;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (mailbox_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/mailbox_safe.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"mailbox_safe.hpp\"\n#include \"clock.hpp\"\n#include \"err.hpp\"\n\n#include <algorithm>\n\nzmq::mailbox_safe_t::mailbox_safe_t (mutex_t *sync_) : _sync (sync_)\n{\n    //  Get the pipe into passive state. That way, if the users starts by\n    //  polling on the associated file descriptor it will get woken up when\n    //  new command is posted.\n    const bool ok = _cpipe.check_read ();\n    zmq_assert (!ok);\n}\n\nzmq::mailbox_safe_t::~mailbox_safe_t ()\n{\n    //  TODO: Retrieve and deallocate commands inside the cpipe.\n\n    // Work around problem that other threads might still be in our\n    // send() method, by waiting on the mutex before disappearing.\n    _sync->lock ();\n    _sync->unlock ();\n}\n\nvoid zmq::mailbox_safe_t::add_signaler (signaler_t *signaler_)\n{\n    _signalers.push_back (signaler_);\n}\n\nvoid zmq::mailbox_safe_t::remove_signaler (signaler_t *signaler_)\n{\n    // TODO: make a copy of array and signal outside the lock\n    const std::vector<zmq::signaler_t *>::iterator end = _signalers.end ();\n    const std::vector<signaler_t *>::iterator it =\n      std::find (_signalers.begin (), end, signaler_);\n\n    if (it != end)\n        _signalers.erase (it);\n}\n\nvoid zmq::mailbox_safe_t::clear_signalers ()\n{\n    _signalers.clear ();\n}\n\nvoid zmq::mailbox_safe_t::send (const command_t &cmd_)\n{\n    _sync->lock ();\n    _cpipe.write (cmd_, false);\n    const bool ok = _cpipe.flush ();\n\n    if (!ok) {\n        _cond_var.broadcast ();\n\n        for (std::vector<signaler_t *>::iterator it = _signalers.begin (),\n                                                 end = _signalers.end ();\n             it != end; ++it) {\n            (*it)->send ();\n        }\n    }\n\n    _sync->unlock ();\n}\n\nint zmq::mailbox_safe_t::recv (command_t *cmd_, int timeout_)\n{\n    //  Try to get the command straight away.\n    if (_cpipe.read (cmd_))\n        return 0;\n\n    //  If the timeout is zero, it will be quicker to release the lock, giving other a chance to send a command\n    //  and immediately relock it.\n    if (timeout_ == 0) {\n        _sync->unlock ();\n        _sync->lock ();\n    } else {\n        //  Wait for signal from the command sender.\n        const int rc = _cond_var.wait (_sync, timeout_);\n        if (rc == -1) {\n            errno_assert (errno == EAGAIN || errno == EINTR);\n            return -1;\n        }\n    }\n\n    //  Another thread may already fetch the command\n    const bool ok = _cpipe.read (cmd_);\n\n    if (!ok) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "src/mailbox_safe.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_MAILBOX_SAFE_HPP_INCLUDED__\n#define __ZMQ_MAILBOX_SAFE_HPP_INCLUDED__\n\n#include <vector>\n#include <stddef.h>\n\n#include \"signaler.hpp\"\n#include \"fd.hpp\"\n#include \"config.hpp\"\n#include \"command.hpp\"\n#include \"ypipe.hpp\"\n#include \"mutex.hpp\"\n#include \"i_mailbox.hpp\"\n#include \"condition_variable.hpp\"\n\nnamespace zmq\n{\nclass mailbox_safe_t ZMQ_FINAL : public i_mailbox\n{\n  public:\n    mailbox_safe_t (mutex_t *sync_);\n    ~mailbox_safe_t ();\n\n    void send (const command_t &cmd_);\n    int recv (command_t *cmd_, int timeout_);\n\n    // Add signaler to mailbox which will be called when a message is ready\n    void add_signaler (signaler_t *signaler_);\n    void remove_signaler (signaler_t *signaler_);\n    void clear_signalers ();\n\n#ifdef HAVE_FORK\n    // close the file descriptors in the signaller. This is used in a forked\n    // child process to close the file descriptors so that they do not interfere\n    // with the context in the parent process.\n    void forked () ZMQ_FINAL\n    {\n        // TODO: call fork on the condition variable\n    }\n#endif\n\n  private:\n    //  The pipe to store actual commands.\n    typedef ypipe_t<command_t, command_pipe_granularity> cpipe_t;\n    cpipe_t _cpipe;\n\n    //  Condition variable to pass signals from writer thread to reader thread.\n    condition_variable_t _cond_var;\n\n    //  Synchronize access to the mailbox from receivers and senders\n    mutex_t *const _sync;\n\n    std::vector<zmq::signaler_t *> _signalers;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (mailbox_safe_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/mechanism.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string.h>\n#include <limits.h>\n\n#include \"mechanism.hpp\"\n#include \"options.hpp\"\n#include \"msg.hpp\"\n#include \"err.hpp\"\n#include \"wire.hpp\"\n#include \"session_base.hpp\"\n\nzmq::mechanism_t::mechanism_t (const options_t &options_) : options (options_)\n{\n}\n\nzmq::mechanism_t::~mechanism_t ()\n{\n}\n\nvoid zmq::mechanism_t::set_peer_routing_id (const void *id_ptr_,\n                                            size_t id_size_)\n{\n    _routing_id.set (static_cast<const unsigned char *> (id_ptr_), id_size_);\n}\n\nvoid zmq::mechanism_t::peer_routing_id (msg_t *msg_)\n{\n    const int rc = msg_->init_size (_routing_id.size ());\n    errno_assert (rc == 0);\n    memcpy (msg_->data (), _routing_id.data (), _routing_id.size ());\n    msg_->set_flags (msg_t::routing_id);\n}\n\nvoid zmq::mechanism_t::set_user_id (const void *user_id_, size_t size_)\n{\n    _user_id.set (static_cast<const unsigned char *> (user_id_), size_);\n    _zap_properties.ZMQ_MAP_INSERT_OR_EMPLACE (\n      std::string (ZMQ_MSG_PROPERTY_USER_ID),\n      std::string (reinterpret_cast<const char *> (user_id_), size_));\n}\n\nconst zmq::blob_t &zmq::mechanism_t::get_user_id () const\n{\n    return _user_id;\n}\n\nconst char socket_type_pair[] = \"PAIR\";\nconst char socket_type_pub[] = \"PUB\";\nconst char socket_type_sub[] = \"SUB\";\nconst char socket_type_req[] = \"REQ\";\nconst char socket_type_rep[] = \"REP\";\nconst char socket_type_dealer[] = \"DEALER\";\nconst char socket_type_router[] = \"ROUTER\";\nconst char socket_type_pull[] = \"PULL\";\nconst char socket_type_push[] = \"PUSH\";\nconst char socket_type_xpub[] = \"XPUB\";\nconst char socket_type_xsub[] = \"XSUB\";\nconst char socket_type_stream[] = \"STREAM\";\n#ifdef ZMQ_BUILD_DRAFT_API\nconst char socket_type_server[] = \"SERVER\";\nconst char socket_type_client[] = \"CLIENT\";\nconst char socket_type_radio[] = \"RADIO\";\nconst char socket_type_dish[] = \"DISH\";\nconst char socket_type_gather[] = \"GATHER\";\nconst char socket_type_scatter[] = \"SCATTER\";\nconst char socket_type_dgram[] = \"DGRAM\";\nconst char socket_type_peer[] = \"PEER\";\nconst char socket_type_channel[] = \"CHANNEL\";\n#endif\n\nconst char *zmq::mechanism_t::socket_type_string (int socket_type_)\n{\n    // TODO the order must of the names must correspond to the values resp. order of ZMQ_* socket type definitions in zmq.h!\n    static const char *names[] = {socket_type_pair,   socket_type_pub,\n                                  socket_type_sub,    socket_type_req,\n                                  socket_type_rep,    socket_type_dealer,\n                                  socket_type_router, socket_type_pull,\n                                  socket_type_push,   socket_type_xpub,\n                                  socket_type_xsub,   socket_type_stream,\n#ifdef ZMQ_BUILD_DRAFT_API\n                                  socket_type_server, socket_type_client,\n                                  socket_type_radio,  socket_type_dish,\n                                  socket_type_gather, socket_type_scatter,\n                                  socket_type_dgram,  socket_type_peer,\n                                  socket_type_channel\n#endif\n    };\n    static const size_t names_count = sizeof (names) / sizeof (names[0]);\n    zmq_assert (socket_type_ >= 0\n                && socket_type_ < static_cast<int> (names_count));\n    return names[socket_type_];\n}\n\nconst size_t name_len_size = sizeof (unsigned char);\nconst size_t value_len_size = sizeof (uint32_t);\n\nstatic size_t property_len (size_t name_len_, size_t value_len_)\n{\n    return name_len_size + name_len_ + value_len_size + value_len_;\n}\n\nstatic size_t name_len (const char *name_)\n{\n    const size_t name_len = strlen (name_);\n    zmq_assert (name_len <= UCHAR_MAX);\n    return name_len;\n}\n\nsize_t zmq::mechanism_t::add_property (unsigned char *ptr_,\n                                       size_t ptr_capacity_,\n                                       const char *name_,\n                                       const void *value_,\n                                       size_t value_len_)\n{\n    const size_t name_len = ::name_len (name_);\n    const size_t total_len = ::property_len (name_len, value_len_);\n    zmq_assert (total_len <= ptr_capacity_);\n\n    *ptr_ = static_cast<unsigned char> (name_len);\n    ptr_ += name_len_size;\n    memcpy (ptr_, name_, name_len);\n    ptr_ += name_len;\n    zmq_assert (value_len_ <= 0x7FFFFFFF);\n    put_uint32 (ptr_, static_cast<uint32_t> (value_len_));\n    ptr_ += value_len_size;\n    memcpy (ptr_, value_, value_len_);\n\n    return total_len;\n}\n\nsize_t zmq::mechanism_t::property_len (const char *name_, size_t value_len_)\n{\n    return ::property_len (name_len (name_), value_len_);\n}\n\n#define ZMTP_PROPERTY_SOCKET_TYPE \"Socket-Type\"\n#define ZMTP_PROPERTY_IDENTITY \"Identity\"\n\nsize_t zmq::mechanism_t::add_basic_properties (unsigned char *ptr_,\n                                               size_t ptr_capacity_) const\n{\n    unsigned char *ptr = ptr_;\n\n    //  Add socket type property\n    const char *socket_type = socket_type_string (options.type);\n    ptr += add_property (ptr, ptr_capacity_, ZMTP_PROPERTY_SOCKET_TYPE,\n                         socket_type, strlen (socket_type));\n\n    //  Add identity (aka routing id) property\n    if (options.type == ZMQ_REQ || options.type == ZMQ_DEALER\n        || options.type == ZMQ_ROUTER) {\n        ptr += add_property (ptr, ptr_capacity_ - (ptr - ptr_),\n                             ZMTP_PROPERTY_IDENTITY, options.routing_id,\n                             options.routing_id_size);\n    }\n\n\n    for (std::map<std::string, std::string>::const_iterator\n           it = options.app_metadata.begin (),\n           end = options.app_metadata.end ();\n         it != end; ++it) {\n        ptr +=\n          add_property (ptr, ptr_capacity_ - (ptr - ptr_), it->first.c_str (),\n                        it->second.c_str (), strlen (it->second.c_str ()));\n    }\n\n    return ptr - ptr_;\n}\n\nsize_t zmq::mechanism_t::basic_properties_len () const\n{\n    const char *socket_type = socket_type_string (options.type);\n    size_t meta_len = 0;\n\n    for (std::map<std::string, std::string>::const_iterator\n           it = options.app_metadata.begin (),\n           end = options.app_metadata.end ();\n         it != end; ++it) {\n        meta_len +=\n          property_len (it->first.c_str (), strlen (it->second.c_str ()));\n    }\n\n    return property_len (ZMTP_PROPERTY_SOCKET_TYPE, strlen (socket_type))\n           + meta_len\n           + ((options.type == ZMQ_REQ || options.type == ZMQ_DEALER\n               || options.type == ZMQ_ROUTER)\n                ? property_len (ZMTP_PROPERTY_IDENTITY, options.routing_id_size)\n                : 0);\n}\n\nvoid zmq::mechanism_t::make_command_with_basic_properties (\n  msg_t *msg_, const char *prefix_, size_t prefix_len_) const\n{\n    const size_t command_size = prefix_len_ + basic_properties_len ();\n    const int rc = msg_->init_size (command_size);\n    errno_assert (rc == 0);\n\n    unsigned char *ptr = static_cast<unsigned char *> (msg_->data ());\n\n    //  Add prefix\n    memcpy (ptr, prefix_, prefix_len_);\n    ptr += prefix_len_;\n\n    add_basic_properties (\n      ptr, command_size - (ptr - static_cast<unsigned char *> (msg_->data ())));\n}\n\nint zmq::mechanism_t::parse_metadata (const unsigned char *ptr_,\n                                      size_t length_,\n                                      bool zap_flag_)\n{\n    size_t bytes_left = length_;\n\n    while (bytes_left > 1) {\n        const size_t name_length = static_cast<size_t> (*ptr_);\n        ptr_ += name_len_size;\n        bytes_left -= name_len_size;\n        if (bytes_left < name_length)\n            break;\n\n        const std::string name =\n          std::string (reinterpret_cast<const char *> (ptr_), name_length);\n        ptr_ += name_length;\n        bytes_left -= name_length;\n        if (bytes_left < value_len_size)\n            break;\n\n        const size_t value_length = static_cast<size_t> (get_uint32 (ptr_));\n        ptr_ += value_len_size;\n        bytes_left -= value_len_size;\n        if (bytes_left < value_length)\n            break;\n\n        const uint8_t *value = ptr_;\n        ptr_ += value_length;\n        bytes_left -= value_length;\n\n        if (name == ZMTP_PROPERTY_IDENTITY && options.recv_routing_id)\n            set_peer_routing_id (value, value_length);\n        else if (name == ZMTP_PROPERTY_SOCKET_TYPE) {\n            if (!check_socket_type (reinterpret_cast<const char *> (value),\n                                    value_length)) {\n                errno = EINVAL;\n                return -1;\n            }\n        } else {\n            const int rc = property (name, value, value_length);\n            if (rc == -1)\n                return -1;\n        }\n        (zap_flag_ ? _zap_properties : _zmtp_properties)\n          .ZMQ_MAP_INSERT_OR_EMPLACE (\n            name,\n            std::string (reinterpret_cast<const char *> (value), value_length));\n    }\n    if (bytes_left > 0) {\n        errno = EPROTO;\n        return -1;\n    }\n    return 0;\n}\n\nint zmq::mechanism_t::property (const std::string & /* name_ */,\n                                const void * /* value_ */,\n                                size_t /* length_ */)\n{\n    //  Default implementation does not check\n    //  property values and returns 0 to signal success.\n    return 0;\n}\n\ntemplate <size_t N>\nstatic bool strequals (const char *actual_type_,\n                       const size_t actual_len_,\n                       const char (&expected_type_)[N])\n{\n    return actual_len_ == N - 1\n           && memcmp (actual_type_, expected_type_, N - 1) == 0;\n}\n\nbool zmq::mechanism_t::check_socket_type (const char *type_,\n                                          const size_t len_) const\n{\n    switch (options.type) {\n        case ZMQ_REQ:\n            return strequals (type_, len_, socket_type_rep)\n                   || strequals (type_, len_, socket_type_router);\n        case ZMQ_REP:\n            return strequals (type_, len_, socket_type_req)\n                   || strequals (type_, len_, socket_type_dealer);\n        case ZMQ_DEALER:\n            return strequals (type_, len_, socket_type_rep)\n                   || strequals (type_, len_, socket_type_dealer)\n                   || strequals (type_, len_, socket_type_router);\n        case ZMQ_ROUTER:\n            return strequals (type_, len_, socket_type_req)\n                   || strequals (type_, len_, socket_type_dealer)\n                   || strequals (type_, len_, socket_type_router);\n        case ZMQ_PUSH:\n            return strequals (type_, len_, socket_type_pull);\n        case ZMQ_PULL:\n            return strequals (type_, len_, socket_type_push);\n        case ZMQ_PUB:\n            return strequals (type_, len_, socket_type_sub)\n                   || strequals (type_, len_, socket_type_xsub);\n        case ZMQ_SUB:\n            return strequals (type_, len_, socket_type_pub)\n                   || strequals (type_, len_, socket_type_xpub);\n        case ZMQ_XPUB:\n            return strequals (type_, len_, socket_type_sub)\n                   || strequals (type_, len_, socket_type_xsub);\n        case ZMQ_XSUB:\n            return strequals (type_, len_, socket_type_pub)\n                   || strequals (type_, len_, socket_type_xpub);\n        case ZMQ_PAIR:\n            return strequals (type_, len_, socket_type_pair);\n#ifdef ZMQ_BUILD_DRAFT_API\n        case ZMQ_SERVER:\n            return strequals (type_, len_, socket_type_client);\n        case ZMQ_CLIENT:\n            return strequals (type_, len_, socket_type_server);\n        case ZMQ_RADIO:\n            return strequals (type_, len_, socket_type_dish);\n        case ZMQ_DISH:\n            return strequals (type_, len_, socket_type_radio);\n        case ZMQ_GATHER:\n            return strequals (type_, len_, socket_type_scatter);\n        case ZMQ_SCATTER:\n            return strequals (type_, len_, socket_type_gather);\n        case ZMQ_DGRAM:\n            return strequals (type_, len_, socket_type_dgram);\n        case ZMQ_PEER:\n            return strequals (type_, len_, socket_type_peer);\n        case ZMQ_CHANNEL:\n            return strequals (type_, len_, socket_type_channel);\n#endif\n        default:\n            break;\n    }\n    return false;\n}\n"
  },
  {
    "path": "src/mechanism.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_MECHANISM_HPP_INCLUDED__\n#define __ZMQ_MECHANISM_HPP_INCLUDED__\n\n#include \"stdint.hpp\"\n#include \"options.hpp\"\n#include \"blob.hpp\"\n#include \"metadata.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\nclass session_base_t;\n\n//  Abstract class representing security mechanism.\n//  Different mechanism extends this class.\n\nclass mechanism_t\n{\n  public:\n    enum status_t\n    {\n        handshaking,\n        ready,\n        error\n    };\n\n    mechanism_t (const options_t &options_);\n\n    virtual ~mechanism_t ();\n\n    //  Prepare next handshake command that is to be sent to the peer.\n    virtual int next_handshake_command (msg_t *msg_) = 0;\n\n    //  Process the handshake command received from the peer.\n    virtual int process_handshake_command (msg_t *msg_) = 0;\n\n    virtual int encode (msg_t *) { return 0; }\n\n    virtual int decode (msg_t *) { return 0; }\n\n    //  Notifies mechanism about availability of ZAP message.\n    virtual int zap_msg_available () { return 0; }\n\n    //  Returns the status of this mechanism.\n    virtual status_t status () const = 0;\n\n    void set_peer_routing_id (const void *id_ptr_, size_t id_size_);\n\n    void peer_routing_id (msg_t *msg_);\n\n    void set_user_id (const void *user_id_, size_t size_);\n\n    const blob_t &get_user_id () const;\n\n    const metadata_t::dict_t &get_zmtp_properties () const\n    {\n        return _zmtp_properties;\n    }\n\n    const metadata_t::dict_t &get_zap_properties () const\n    {\n        return _zap_properties;\n    }\n\n  protected:\n    //  Only used to identify the socket for the Socket-Type\n    //  property in the wire protocol.\n    static const char *socket_type_string (int socket_type_);\n\n    static size_t add_property (unsigned char *ptr_,\n                                size_t ptr_capacity_,\n                                const char *name_,\n                                const void *value_,\n                                size_t value_len_);\n    static size_t property_len (const char *name_, size_t value_len_);\n\n    size_t add_basic_properties (unsigned char *ptr_,\n                                 size_t ptr_capacity_) const;\n    size_t basic_properties_len () const;\n\n    void make_command_with_basic_properties (msg_t *msg_,\n                                             const char *prefix_,\n                                             size_t prefix_len_) const;\n\n    //  Parses a metadata.\n    //  Metadata consists of a list of properties consisting of\n    //  name and value as size-specified strings.\n    //  Returns 0 on success and -1 on error, in which case errno is set.\n    int parse_metadata (const unsigned char *ptr_,\n                        size_t length_,\n                        bool zap_flag_ = false);\n\n    //  This is called by parse_property method whenever it\n    //  parses a new property. The function should return 0\n    //  on success and -1 on error, in which case it should\n    //  set errno. Signaling error prevents parser from\n    //  parsing remaining data.\n    //  Derived classes are supposed to override this\n    //  method to handle custom processing.\n    virtual int\n    property (const std::string &name_, const void *value_, size_t length_);\n\n    const options_t options;\n\n  private:\n    //  Properties received from ZMTP peer.\n    metadata_t::dict_t _zmtp_properties;\n\n    //  Properties received from ZAP server.\n    metadata_t::dict_t _zap_properties;\n\n    blob_t _routing_id;\n\n    blob_t _user_id;\n\n    //  Returns true iff socket associated with the mechanism\n    //  is compatible with a given socket type 'type_'.\n    bool check_socket_type (const char *type_, size_t len_) const;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/mechanism_base.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"mechanism_base.hpp\"\n#include \"session_base.hpp\"\n\nzmq::mechanism_base_t::mechanism_base_t (session_base_t *const session_,\n                                         const options_t &options_) :\n    mechanism_t (options_), session (session_)\n{\n}\n\nint zmq::mechanism_base_t::check_basic_command_structure (msg_t *msg_) const\n{\n    if (msg_->size () <= 1\n        || msg_->size () <= (static_cast<uint8_t *> (msg_->data ()))[0]) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED);\n        errno = EPROTO;\n        return -1;\n    }\n    return 0;\n}\n\nvoid zmq::mechanism_base_t::handle_error_reason (const char *error_reason_,\n                                                 size_t error_reason_len_)\n{\n    const size_t status_code_len = 3;\n    const char zero_digit = '0';\n    const size_t significant_digit_index = 0;\n    const size_t first_zero_digit_index = 1;\n    const size_t second_zero_digit_index = 2;\n    const int factor = 100;\n    if (error_reason_len_ == status_code_len\n        && error_reason_[first_zero_digit_index] == zero_digit\n        && error_reason_[second_zero_digit_index] == zero_digit\n        && error_reason_[significant_digit_index] >= '3'\n        && error_reason_[significant_digit_index] <= '5') {\n        // it is a ZAP error status code (300, 400 or 500), so emit an authentication failure event\n        session->get_socket ()->event_handshake_failed_auth (\n          session->get_endpoint (),\n          (error_reason_[significant_digit_index] - zero_digit) * factor);\n    } else {\n        // this is a violation of the ZAP protocol\n        // TODO zmq_assert in this case?\n    }\n}\n\nbool zmq::mechanism_base_t::zap_required () const\n{\n    return !options.zap_domain.empty ();\n}\n"
  },
  {
    "path": "src/mechanism_base.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_MECHANISM_BASE_HPP_INCLUDED__\n#define __ZMQ_MECHANISM_BASE_HPP_INCLUDED__\n\n#include \"mechanism.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\n\nclass mechanism_base_t : public mechanism_t\n{\n  protected:\n    mechanism_base_t (session_base_t *session_, const options_t &options_);\n\n    session_base_t *const session;\n\n    int check_basic_command_structure (msg_t *msg_) const;\n\n    void handle_error_reason (const char *error_reason_,\n                              size_t error_reason_len_);\n\n    bool zap_required () const;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/metadata.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"metadata.hpp\"\n\nzmq::metadata_t::metadata_t (const dict_t &dict_) : _ref_cnt (1), _dict (dict_)\n{\n}\n\nconst char *zmq::metadata_t::get (const std::string &property_) const\n{\n    const dict_t::const_iterator it = _dict.find (property_);\n    if (it == _dict.end ()) {\n        /** \\todo remove this when support for the deprecated name \"Identity\" is dropped */\n        if (property_ == \"Identity\")\n            return get (ZMQ_MSG_PROPERTY_ROUTING_ID);\n\n        return NULL;\n    }\n    return it->second.c_str ();\n}\n\nvoid zmq::metadata_t::add_ref ()\n{\n    _ref_cnt.add (1);\n}\n\nbool zmq::metadata_t::drop_ref ()\n{\n    return !_ref_cnt.sub (1);\n}\n"
  },
  {
    "path": "src/metadata.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_METADATA_HPP_INCLUDED__\n#define __ZMQ_METADATA_HPP_INCLUDED__\n\n#include <map>\n#include <string>\n\n#include \"atomic_counter.hpp\"\n\nnamespace zmq\n{\nclass metadata_t\n{\n  public:\n    typedef std::map<std::string, std::string> dict_t;\n\n    metadata_t (const dict_t &dict_);\n\n    //  Returns pointer to property value or NULL if\n    //  property is not found.\n    const char *get (const std::string &property_) const;\n\n    void add_ref ();\n\n    //  Drop reference. Returns true iff the reference\n    //  counter drops to zero.\n    bool drop_ref ();\n\n  private:\n    //  Reference counter.\n    atomic_counter_t _ref_cnt;\n\n    //  Dictionary holding metadata.\n    const dict_t _dict;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (metadata_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/msg.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"compat.hpp\"\n#include \"macros.hpp\"\n#include \"msg.hpp\"\n\n#include <string.h>\n#include <stdlib.h>\n#include <new>\n\n#include \"stdint.hpp\"\n#include \"likely.hpp\"\n#include \"metadata.hpp\"\n#include \"err.hpp\"\n\n//  Check whether the sizes of public representation of the message (zmq_msg_t)\n//  and private representation of the message (zmq::msg_t) match.\n\ntypedef char\n  zmq_msg_size_check[2 * ((sizeof (zmq::msg_t) == sizeof (zmq_msg_t)) != 0)\n                     - 1];\n\nbool zmq::msg_t::check () const\n{\n    return _u.base.type >= type_min && _u.base.type <= type_max;\n}\n\nint zmq::msg_t::init (void *data_,\n                      size_t size_,\n                      msg_free_fn *ffn_,\n                      void *hint_,\n                      content_t *content_)\n{\n    if (size_ <= max_vsm_size) {\n        const int rc = init_size (size_);\n\n        if (rc != -1) {\n            memcpy (data (), data_, size_);\n            return 0;\n        }\n        return -1;\n    }\n    if (content_) {\n        return init_external_storage (content_, data_, size_, ffn_, hint_);\n    }\n    return init_data (data_, size_, ffn_, hint_);\n}\n\nint zmq::msg_t::init ()\n{\n    _u.vsm.metadata = NULL;\n    _u.vsm.type = type_vsm;\n    _u.vsm.flags = 0;\n    _u.vsm.size = 0;\n    _u.vsm.group.sgroup.group[0] = '\\0';\n    _u.vsm.group.type = group_type_short;\n    _u.vsm.routing_id = 0;\n    return 0;\n}\n\nint zmq::msg_t::init_size (size_t size_)\n{\n    if (size_ <= max_vsm_size) {\n        _u.vsm.metadata = NULL;\n        _u.vsm.type = type_vsm;\n        _u.vsm.flags = 0;\n        _u.vsm.size = static_cast<unsigned char> (size_);\n        _u.vsm.group.sgroup.group[0] = '\\0';\n        _u.vsm.group.type = group_type_short;\n        _u.vsm.routing_id = 0;\n    } else {\n        _u.lmsg.metadata = NULL;\n        _u.lmsg.type = type_lmsg;\n        _u.lmsg.flags = 0;\n        _u.lmsg.group.sgroup.group[0] = '\\0';\n        _u.lmsg.group.type = group_type_short;\n        _u.lmsg.routing_id = 0;\n        _u.lmsg.content = NULL;\n        if (sizeof (content_t) + size_ > size_)\n            _u.lmsg.content =\n              static_cast<content_t *> (malloc (sizeof (content_t) + size_));\n        if (unlikely (!_u.lmsg.content)) {\n            errno = ENOMEM;\n            return -1;\n        }\n\n        _u.lmsg.content->data = _u.lmsg.content + 1;\n        _u.lmsg.content->size = size_;\n        _u.lmsg.content->ffn = NULL;\n        _u.lmsg.content->hint = NULL;\n        new (&_u.lmsg.content->refcnt) zmq::atomic_counter_t ();\n    }\n    return 0;\n}\n\nint zmq::msg_t::init_buffer (const void *buf_, size_t size_)\n{\n    const int rc = init_size (size_);\n    if (unlikely (rc < 0)) {\n        return -1;\n    }\n    if (size_) {\n        // NULL and zero size is allowed\n        assert (NULL != buf_);\n        memcpy (data (), buf_, size_);\n    }\n    return 0;\n}\n\nint zmq::msg_t::init_external_storage (content_t *content_,\n                                       void *data_,\n                                       size_t size_,\n                                       msg_free_fn *ffn_,\n                                       void *hint_)\n{\n    zmq_assert (NULL != data_);\n    zmq_assert (NULL != content_);\n\n    _u.zclmsg.metadata = NULL;\n    _u.zclmsg.type = type_zclmsg;\n    _u.zclmsg.flags = 0;\n    _u.zclmsg.group.sgroup.group[0] = '\\0';\n    _u.zclmsg.group.type = group_type_short;\n    _u.zclmsg.routing_id = 0;\n\n    _u.zclmsg.content = content_;\n    _u.zclmsg.content->data = data_;\n    _u.zclmsg.content->size = size_;\n    _u.zclmsg.content->ffn = ffn_;\n    _u.zclmsg.content->hint = hint_;\n    new (&_u.zclmsg.content->refcnt) zmq::atomic_counter_t ();\n\n    return 0;\n}\n\nint zmq::msg_t::init_data (void *data_,\n                           size_t size_,\n                           msg_free_fn *ffn_,\n                           void *hint_)\n{\n    //  If data is NULL and size is not 0, a segfault\n    //  would occur once the data is accessed\n    zmq_assert (data_ != NULL || size_ == 0);\n\n    //  Initialize constant message if there's no need to deallocate\n    if (ffn_ == NULL) {\n        _u.cmsg.metadata = NULL;\n        _u.cmsg.type = type_cmsg;\n        _u.cmsg.flags = 0;\n        _u.cmsg.data = data_;\n        _u.cmsg.size = size_;\n        _u.cmsg.group.sgroup.group[0] = '\\0';\n        _u.cmsg.group.type = group_type_short;\n        _u.cmsg.routing_id = 0;\n    } else {\n        _u.lmsg.metadata = NULL;\n        _u.lmsg.type = type_lmsg;\n        _u.lmsg.flags = 0;\n        _u.lmsg.group.sgroup.group[0] = '\\0';\n        _u.lmsg.group.type = group_type_short;\n        _u.lmsg.routing_id = 0;\n        _u.lmsg.content =\n          static_cast<content_t *> (malloc (sizeof (content_t)));\n        if (!_u.lmsg.content) {\n            errno = ENOMEM;\n            return -1;\n        }\n\n        _u.lmsg.content->data = data_;\n        _u.lmsg.content->size = size_;\n        _u.lmsg.content->ffn = ffn_;\n        _u.lmsg.content->hint = hint_;\n        new (&_u.lmsg.content->refcnt) zmq::atomic_counter_t ();\n    }\n    return 0;\n}\n\nint zmq::msg_t::init_delimiter ()\n{\n    _u.delimiter.metadata = NULL;\n    _u.delimiter.type = type_delimiter;\n    _u.delimiter.flags = 0;\n    _u.delimiter.group.sgroup.group[0] = '\\0';\n    _u.delimiter.group.type = group_type_short;\n    _u.delimiter.routing_id = 0;\n    return 0;\n}\n\nint zmq::msg_t::init_join ()\n{\n    _u.base.metadata = NULL;\n    _u.base.type = type_join;\n    _u.base.flags = 0;\n    _u.base.group.sgroup.group[0] = '\\0';\n    _u.base.group.type = group_type_short;\n    _u.base.routing_id = 0;\n    return 0;\n}\n\nint zmq::msg_t::init_leave ()\n{\n    _u.base.metadata = NULL;\n    _u.base.type = type_leave;\n    _u.base.flags = 0;\n    _u.base.group.sgroup.group[0] = '\\0';\n    _u.base.group.type = group_type_short;\n    _u.base.routing_id = 0;\n    return 0;\n}\n\nint zmq::msg_t::init_subscribe (const size_t size_, const unsigned char *topic_)\n{\n    int rc = init_size (size_);\n    if (rc == 0) {\n        set_flags (zmq::msg_t::subscribe);\n\n        //  We explicitly allow a NULL subscription with size zero\n        if (size_) {\n            assert (topic_);\n            memcpy (data (), topic_, size_);\n        }\n    }\n    return rc;\n}\n\nint zmq::msg_t::init_cancel (const size_t size_, const unsigned char *topic_)\n{\n    int rc = init_size (size_);\n    if (rc == 0) {\n        set_flags (zmq::msg_t::cancel);\n\n        //  We explicitly allow a NULL subscription with size zero\n        if (size_) {\n            assert (topic_);\n            memcpy (data (), topic_, size_);\n        }\n    }\n    return rc;\n}\n\nint zmq::msg_t::close ()\n{\n    //  Check the validity of the message.\n    if (unlikely (!check ())) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    if (_u.base.type == type_lmsg) {\n        //  If the content is not shared, or if it is shared and the reference\n        //  count has dropped to zero, deallocate it.\n        if (!(_u.lmsg.flags & msg_t::shared)\n            || !_u.lmsg.content->refcnt.sub (1)) {\n            //  We used \"placement new\" operator to initialize the reference\n            //  counter so we call the destructor explicitly now.\n            _u.lmsg.content->refcnt.~atomic_counter_t ();\n\n            if (_u.lmsg.content->ffn)\n                _u.lmsg.content->ffn (_u.lmsg.content->data,\n                                      _u.lmsg.content->hint);\n            free (_u.lmsg.content);\n        }\n    }\n\n    if (is_zcmsg ()) {\n        zmq_assert (_u.zclmsg.content->ffn);\n\n        //  If the content is not shared, or if it is shared and the reference\n        //  count has dropped to zero, deallocate it.\n        if (!(_u.zclmsg.flags & msg_t::shared)\n            || !_u.zclmsg.content->refcnt.sub (1)) {\n            //  We used \"placement new\" operator to initialize the reference\n            //  counter so we call the destructor explicitly now.\n            _u.zclmsg.content->refcnt.~atomic_counter_t ();\n\n            _u.zclmsg.content->ffn (_u.zclmsg.content->data,\n                                    _u.zclmsg.content->hint);\n        }\n    }\n\n    if (_u.base.metadata != NULL) {\n        if (_u.base.metadata->drop_ref ()) {\n            LIBZMQ_DELETE (_u.base.metadata);\n        }\n        _u.base.metadata = NULL;\n    }\n\n    if (_u.base.group.type == group_type_long) {\n        if (!_u.base.group.lgroup.content->refcnt.sub (1)) {\n            //  We used \"placement new\" operator to initialize the reference\n            //  counter so we call the destructor explicitly now.\n            _u.base.group.lgroup.content->refcnt.~atomic_counter_t ();\n\n            free (_u.base.group.lgroup.content);\n        }\n    }\n\n    //  Make the message invalid.\n    _u.base.type = 0;\n\n    return 0;\n}\n\nint zmq::msg_t::move (msg_t &src_)\n{\n    //  Check the validity of the source.\n    if (unlikely (!src_.check ())) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    int rc = close ();\n    if (unlikely (rc < 0))\n        return rc;\n\n    *this = src_;\n\n    rc = src_.init ();\n    if (unlikely (rc < 0))\n        return rc;\n\n    return 0;\n}\n\nint zmq::msg_t::copy (msg_t &src_)\n{\n    //  Check the validity of the source.\n    if (unlikely (!src_.check ())) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    const int rc = close ();\n    if (unlikely (rc < 0))\n        return rc;\n\n    // The initial reference count, when a non-shared message is initially\n    // shared (between the original and the copy we create here).\n    const atomic_counter_t::integer_t initial_shared_refcnt = 2;\n\n    if (src_.is_lmsg () || src_.is_zcmsg ()) {\n        //  One reference is added to shared messages. Non-shared messages\n        //  are turned into shared messages.\n        if (src_.flags () & msg_t::shared)\n            src_.refcnt ()->add (1);\n        else {\n            src_.set_flags (msg_t::shared);\n            src_.refcnt ()->set (initial_shared_refcnt);\n        }\n    }\n\n    if (src_._u.base.metadata != NULL)\n        src_._u.base.metadata->add_ref ();\n\n    if (src_._u.base.group.type == group_type_long)\n        src_._u.base.group.lgroup.content->refcnt.add (1);\n\n    *this = src_;\n\n    return 0;\n}\n\nvoid *zmq::msg_t::data ()\n{\n    //  Check the validity of the message.\n    zmq_assert (check ());\n\n    switch (_u.base.type) {\n        case type_vsm:\n            return _u.vsm.data;\n        case type_lmsg:\n            return _u.lmsg.content->data;\n        case type_cmsg:\n            return _u.cmsg.data;\n        case type_zclmsg:\n            return _u.zclmsg.content->data;\n        default:\n            zmq_assert (false);\n            return NULL;\n    }\n}\n\nsize_t zmq::msg_t::size () const\n{\n    //  Check the validity of the message.\n    zmq_assert (check ());\n\n    switch (_u.base.type) {\n        case type_vsm:\n            return _u.vsm.size;\n        case type_lmsg:\n            return _u.lmsg.content->size;\n        case type_zclmsg:\n            return _u.zclmsg.content->size;\n        case type_cmsg:\n            return _u.cmsg.size;\n        default:\n            zmq_assert (false);\n            return 0;\n    }\n}\n\nvoid zmq::msg_t::shrink (size_t new_size_)\n{\n    //  Check the validity of the message.\n    zmq_assert (check ());\n    zmq_assert (new_size_ <= size ());\n\n    switch (_u.base.type) {\n        case type_vsm:\n            _u.vsm.size = static_cast<unsigned char> (new_size_);\n            break;\n        case type_lmsg:\n            _u.lmsg.content->size = new_size_;\n            break;\n        case type_zclmsg:\n            _u.zclmsg.content->size = new_size_;\n            break;\n        case type_cmsg:\n            _u.cmsg.size = new_size_;\n            break;\n        default:\n            zmq_assert (false);\n    }\n}\n\nunsigned char zmq::msg_t::flags () const\n{\n    return _u.base.flags;\n}\n\nvoid zmq::msg_t::set_flags (unsigned char flags_)\n{\n    _u.base.flags |= flags_;\n}\n\nvoid zmq::msg_t::reset_flags (unsigned char flags_)\n{\n    _u.base.flags &= ~flags_;\n}\n\nzmq::metadata_t *zmq::msg_t::metadata () const\n{\n    return _u.base.metadata;\n}\n\nvoid zmq::msg_t::set_metadata (zmq::metadata_t *metadata_)\n{\n    assert (metadata_ != NULL);\n    assert (_u.base.metadata == NULL);\n    metadata_->add_ref ();\n    _u.base.metadata = metadata_;\n}\n\nvoid zmq::msg_t::reset_metadata ()\n{\n    if (_u.base.metadata) {\n        if (_u.base.metadata->drop_ref ()) {\n            LIBZMQ_DELETE (_u.base.metadata);\n        }\n        _u.base.metadata = NULL;\n    }\n}\n\nbool zmq::msg_t::is_routing_id () const\n{\n    return (_u.base.flags & routing_id) == routing_id;\n}\n\nbool zmq::msg_t::is_credential () const\n{\n    return (_u.base.flags & credential) == credential;\n}\n\nbool zmq::msg_t::is_delimiter () const\n{\n    return _u.base.type == type_delimiter;\n}\n\nbool zmq::msg_t::is_vsm () const\n{\n    return _u.base.type == type_vsm;\n}\n\nbool zmq::msg_t::is_cmsg () const\n{\n    return _u.base.type == type_cmsg;\n}\n\nbool zmq::msg_t::is_lmsg () const\n{\n    return _u.base.type == type_lmsg;\n}\n\nbool zmq::msg_t::is_zcmsg () const\n{\n    return _u.base.type == type_zclmsg;\n}\n\nbool zmq::msg_t::is_join () const\n{\n    return _u.base.type == type_join;\n}\n\nbool zmq::msg_t::is_leave () const\n{\n    return _u.base.type == type_leave;\n}\n\nbool zmq::msg_t::is_ping () const\n{\n    return (_u.base.flags & CMD_TYPE_MASK) == ping;\n}\n\nbool zmq::msg_t::is_pong () const\n{\n    return (_u.base.flags & CMD_TYPE_MASK) == pong;\n}\n\nbool zmq::msg_t::is_close_cmd () const\n{\n    return (_u.base.flags & CMD_TYPE_MASK) == close_cmd;\n}\n\nsize_t zmq::msg_t::command_body_size () const\n{\n    if (this->is_ping () || this->is_pong ())\n        return this->size () - ping_cmd_name_size;\n    else if (!(this->flags () & msg_t::command)\n             && (this->is_subscribe () || this->is_cancel ()))\n        return this->size ();\n    else if (this->is_subscribe ())\n        return this->size () - sub_cmd_name_size;\n    else if (this->is_cancel ())\n        return this->size () - cancel_cmd_name_size;\n\n    return 0;\n}\n\nvoid *zmq::msg_t::command_body ()\n{\n    unsigned char *data = NULL;\n\n    if (this->is_ping () || this->is_pong ())\n        data =\n          static_cast<unsigned char *> (this->data ()) + ping_cmd_name_size;\n    //  With inproc, command flag is not set for sub/cancel\n    else if (!(this->flags () & msg_t::command)\n             && (this->is_subscribe () || this->is_cancel ()))\n        data = static_cast<unsigned char *> (this->data ());\n    else if (this->is_subscribe ())\n        data = static_cast<unsigned char *> (this->data ()) + sub_cmd_name_size;\n    else if (this->is_cancel ())\n        data =\n          static_cast<unsigned char *> (this->data ()) + cancel_cmd_name_size;\n\n    return data;\n}\n\nvoid zmq::msg_t::add_refs (int refs_)\n{\n    zmq_assert (refs_ >= 0);\n\n    //  Operation not supported for messages with metadata.\n    zmq_assert (_u.base.metadata == NULL);\n\n    //  No copies required.\n    if (!refs_)\n        return;\n\n    //  VSMs, CMSGS and delimiters can be copied straight away. The only\n    //  message type that needs special care are long messages.\n    if (_u.base.type == type_lmsg || is_zcmsg ()) {\n        if (_u.base.flags & msg_t::shared)\n            refcnt ()->add (refs_);\n        else {\n            refcnt ()->set (refs_ + 1);\n            _u.base.flags |= msg_t::shared;\n        }\n    }\n}\n\nbool zmq::msg_t::rm_refs (int refs_)\n{\n    zmq_assert (refs_ >= 0);\n\n    //  Operation not supported for messages with metadata.\n    zmq_assert (_u.base.metadata == NULL);\n\n    //  No copies required.\n    if (!refs_)\n        return true;\n\n    //  If there's only one reference close the message.\n    if ((_u.base.type != type_zclmsg && _u.base.type != type_lmsg)\n        || !(_u.base.flags & msg_t::shared)) {\n        close ();\n        return false;\n    }\n\n    //  The only message type that needs special care are long and zcopy messages.\n    if (_u.base.type == type_lmsg && !_u.lmsg.content->refcnt.sub (refs_)) {\n        //  We used \"placement new\" operator to initialize the reference\n        //  counter so we call the destructor explicitly now.\n        _u.lmsg.content->refcnt.~atomic_counter_t ();\n\n        if (_u.lmsg.content->ffn)\n            _u.lmsg.content->ffn (_u.lmsg.content->data, _u.lmsg.content->hint);\n        free (_u.lmsg.content);\n\n        return false;\n    }\n\n    if (is_zcmsg () && !_u.zclmsg.content->refcnt.sub (refs_)) {\n        // storage for rfcnt is provided externally\n        if (_u.zclmsg.content->ffn) {\n            _u.zclmsg.content->ffn (_u.zclmsg.content->data,\n                                    _u.zclmsg.content->hint);\n        }\n\n        return false;\n    }\n\n    return true;\n}\n\nuint32_t zmq::msg_t::get_routing_id () const\n{\n    return _u.base.routing_id;\n}\n\nint zmq::msg_t::set_routing_id (uint32_t routing_id_)\n{\n    if (routing_id_) {\n        _u.base.routing_id = routing_id_;\n        return 0;\n    }\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::msg_t::reset_routing_id ()\n{\n    _u.base.routing_id = 0;\n    return 0;\n}\n\nconst char *zmq::msg_t::group () const\n{\n    if (_u.base.group.type == group_type_long)\n        return _u.base.group.lgroup.content->group;\n    return _u.base.group.sgroup.group;\n}\n\nint zmq::msg_t::set_group (const char *group_)\n{\n    size_t length = strnlen (group_, ZMQ_GROUP_MAX_LENGTH);\n\n    return set_group (group_, length);\n}\n\nint zmq::msg_t::set_group (const char *group_, size_t length_)\n{\n    if (length_ > ZMQ_GROUP_MAX_LENGTH) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    if (length_ > 14) {\n        _u.base.group.lgroup.type = group_type_long;\n        _u.base.group.lgroup.content =\n          (long_group_t *) malloc (sizeof (long_group_t));\n        assert (_u.base.group.lgroup.content);\n        new (&_u.base.group.lgroup.content->refcnt) zmq::atomic_counter_t ();\n        _u.base.group.lgroup.content->refcnt.set (1);\n        strncpy (_u.base.group.lgroup.content->group, group_, length_);\n        _u.base.group.lgroup.content->group[length_] = '\\0';\n    } else {\n        strncpy (_u.base.group.sgroup.group, group_, length_);\n        _u.base.group.sgroup.group[length_] = '\\0';\n    }\n\n    return 0;\n}\n\nzmq::atomic_counter_t *zmq::msg_t::refcnt ()\n{\n    switch (_u.base.type) {\n        case type_lmsg:\n            return &_u.lmsg.content->refcnt;\n        case type_zclmsg:\n            return &_u.zclmsg.content->refcnt;\n        default:\n            zmq_assert (false);\n            return NULL;\n    }\n}\n"
  },
  {
    "path": "src/msg.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_MSG_HPP_INCLUDE__\n#define __ZMQ_MSG_HPP_INCLUDE__\n\n#include <stddef.h>\n#include <stdio.h>\n\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"fd.hpp\"\n#include \"atomic_counter.hpp\"\n#include \"metadata.hpp\"\n\n//  bits 2-5\n#define CMD_TYPE_MASK 0x1c\n\n//  Signature for free function to deallocate the message content.\n//  Note that it has to be declared as \"C\" so that it is the same as\n//  zmq_free_fn defined in zmq.h.\nextern \"C\" {\ntypedef void (msg_free_fn) (void *data_, void *hint_);\n}\n\nnamespace zmq\n{\n//  Note that this structure needs to be explicitly constructed\n//  (init functions) and destructed (close function).\n\nstatic const char cancel_cmd_name[] = \"\\6CANCEL\";\nstatic const char sub_cmd_name[] = \"\\x9SUBSCRIBE\";\n\nclass msg_t\n{\n  public:\n    //  Shared message buffer. Message data are either allocated in one\n    //  continuous block along with this structure - thus avoiding one\n    //  malloc/free pair or they are stored in user-supplied memory.\n    //  In the latter case, ffn member stores pointer to the function to be\n    //  used to deallocate the data. If the buffer is actually shared (there\n    //  are at least 2 references to it) refcount member contains number of\n    //  references.\n    struct content_t\n    {\n        void *data;\n        size_t size;\n        msg_free_fn *ffn;\n        void *hint;\n        zmq::atomic_counter_t refcnt;\n    };\n\n    //  Message flags.\n    enum\n    {\n        more = 1,    //  Followed by more parts\n        command = 2, //  Command frame (see ZMTP spec)\n        //  Command types, use only bits 2-5 and compare with ==, not bitwise,\n        //  a command can never be of more that one type at the same time\n        ping = 4,\n        pong = 8,\n        subscribe = 12,\n        cancel = 16,\n        close_cmd = 20,\n        credential = 32,\n        routing_id = 64,\n        shared = 128\n    };\n\n    bool check () const;\n    int init ();\n\n    int init (void *data_,\n              size_t size_,\n              msg_free_fn *ffn_,\n              void *hint_,\n              content_t *content_ = NULL);\n\n    int init_size (size_t size_);\n    int init_buffer (const void *buf_, size_t size_);\n    int init_data (void *data_, size_t size_, msg_free_fn *ffn_, void *hint_);\n    int init_external_storage (content_t *content_,\n                               void *data_,\n                               size_t size_,\n                               msg_free_fn *ffn_,\n                               void *hint_);\n    int init_delimiter ();\n    int init_join ();\n    int init_leave ();\n    int init_subscribe (const size_t size_, const unsigned char *topic);\n    int init_cancel (const size_t size_, const unsigned char *topic);\n    int close ();\n    int move (msg_t &src_);\n    int copy (msg_t &src_);\n    void *data ();\n    size_t size () const;\n    unsigned char flags () const;\n    void set_flags (unsigned char flags_);\n    void reset_flags (unsigned char flags_);\n    metadata_t *metadata () const;\n    void set_metadata (metadata_t *metadata_);\n    void reset_metadata ();\n    bool is_routing_id () const;\n    bool is_credential () const;\n    bool is_delimiter () const;\n    bool is_join () const;\n    bool is_leave () const;\n    bool is_ping () const;\n    bool is_pong () const;\n    bool is_close_cmd () const;\n\n    //  These are called on each message received by the session_base class,\n    //  so get them inlined to avoid the overhead of 2 function calls per msg\n    bool is_subscribe () const\n    {\n        return (_u.base.flags & CMD_TYPE_MASK) == subscribe;\n    }\n\n    bool is_cancel () const\n    {\n        return (_u.base.flags & CMD_TYPE_MASK) == cancel;\n    }\n\n    size_t command_body_size () const;\n    void *command_body ();\n    bool is_vsm () const;\n    bool is_cmsg () const;\n    bool is_lmsg () const;\n    bool is_zcmsg () const;\n    uint32_t get_routing_id () const;\n    int set_routing_id (uint32_t routing_id_);\n    int reset_routing_id ();\n    const char *group () const;\n    int set_group (const char *group_);\n    int set_group (const char *, size_t length_);\n\n    //  After calling this function you can copy the message in POD-style\n    //  refs_ times. No need to call copy.\n    void add_refs (int refs_);\n\n    //  Removes references previously added by add_refs. If the number of\n    //  references drops to 0, the message is closed and false is returned.\n    bool rm_refs (int refs_);\n\n    void shrink (size_t new_size_);\n\n    //  Size in bytes of the largest message that is still copied around\n    //  rather than being reference-counted.\n    enum\n    {\n        msg_t_size = 64\n    };\n    enum\n    {\n        max_vsm_size =\n          msg_t_size - (sizeof (metadata_t *) + 3 + 16 + sizeof (uint32_t))\n    };\n    enum\n    {\n        ping_cmd_name_size = 5,   // 4PING\n        cancel_cmd_name_size = 7, // 6CANCEL\n        sub_cmd_name_size = 10    // 9SUBSCRIBE\n    };\n\n  private:\n    zmq::atomic_counter_t *refcnt ();\n\n    //  Different message types.\n    enum type_t\n    {\n        type_min = 101,\n        //  VSM messages store the content in the message itself\n        type_vsm = 101,\n        //  LMSG messages store the content in malloc-ed memory\n        type_lmsg = 102,\n        //  Delimiter messages are used in envelopes\n        type_delimiter = 103,\n        //  CMSG messages point to constant data\n        type_cmsg = 104,\n\n        // zero-copy LMSG message for v2_decoder\n        type_zclmsg = 105,\n\n        //  Join message for radio_dish\n        type_join = 106,\n\n        //  Leave message for radio_dish\n        type_leave = 107,\n\n        type_max = 107\n    };\n\n    enum group_type_t\n    {\n        group_type_short,\n        group_type_long\n    };\n\n    struct long_group_t\n    {\n        char group[ZMQ_GROUP_MAX_LENGTH + 1];\n        atomic_counter_t refcnt;\n    };\n\n    union group_t\n    {\n        unsigned char type;\n        struct\n        {\n            unsigned char type;\n            char group[15];\n        } sgroup;\n        struct\n        {\n            unsigned char type;\n            long_group_t *content;\n        } lgroup;\n    };\n\n    //  Note that fields shared between different message types are not\n    //  moved to the parent class (msg_t). This way we get tighter packing\n    //  of the data. Shared fields can be accessed via 'base' member of\n    //  the union.\n    union\n    {\n        struct\n        {\n            metadata_t *metadata;\n            unsigned char unused[msg_t_size\n                                 - (sizeof (metadata_t *) + 2\n                                    + sizeof (uint32_t) + sizeof (group_t))];\n            unsigned char type;\n            unsigned char flags;\n            uint32_t routing_id;\n            group_t group;\n        } base;\n        struct\n        {\n            metadata_t *metadata;\n            unsigned char data[max_vsm_size];\n            unsigned char size;\n            unsigned char type;\n            unsigned char flags;\n            uint32_t routing_id;\n            group_t group;\n        } vsm;\n        struct\n        {\n            metadata_t *metadata;\n            content_t *content;\n            unsigned char\n              unused[msg_t_size\n                     - (sizeof (metadata_t *) + sizeof (content_t *) + 2\n                        + sizeof (uint32_t) + sizeof (group_t))];\n            unsigned char type;\n            unsigned char flags;\n            uint32_t routing_id;\n            group_t group;\n        } lmsg;\n        struct\n        {\n            metadata_t *metadata;\n            content_t *content;\n            unsigned char\n              unused[msg_t_size\n                     - (sizeof (metadata_t *) + sizeof (content_t *) + 2\n                        + sizeof (uint32_t) + sizeof (group_t))];\n            unsigned char type;\n            unsigned char flags;\n            uint32_t routing_id;\n            group_t group;\n        } zclmsg;\n        struct\n        {\n            metadata_t *metadata;\n            void *data;\n            size_t size;\n            unsigned char unused[msg_t_size\n                                 - (sizeof (metadata_t *) + sizeof (void *)\n                                    + sizeof (size_t) + 2 + sizeof (uint32_t)\n                                    + sizeof (group_t))];\n            unsigned char type;\n            unsigned char flags;\n            uint32_t routing_id;\n            group_t group;\n        } cmsg;\n        struct\n        {\n            metadata_t *metadata;\n            unsigned char unused[msg_t_size\n                                 - (sizeof (metadata_t *) + 2\n                                    + sizeof (uint32_t) + sizeof (group_t))];\n            unsigned char type;\n            unsigned char flags;\n            uint32_t routing_id;\n            group_t group;\n        } delimiter;\n    } _u;\n};\n\ninline int close_and_return (zmq::msg_t *msg_, int echo_)\n{\n    // Since we abort on close failure we preserve errno for success case.\n    const int err = errno;\n    const int rc = msg_->close ();\n    errno_assert (rc == 0);\n    errno = err;\n    return echo_;\n}\n\ninline int close_and_return (zmq::msg_t msg_[], int count_, int echo_)\n{\n    for (int i = 0; i < count_; i++)\n        close_and_return (&msg_[i], 0);\n    return echo_;\n}\n}\n\n#endif\n"
  },
  {
    "path": "src/mtrie.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"mtrie.hpp\"\n#include \"generic_mtrie_impl.hpp\"\n\nnamespace zmq\n{\ntemplate class generic_mtrie_t<pipe_t>;\n}\n"
  },
  {
    "path": "src/mtrie.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_MTRIE_HPP_INCLUDED__\n#define __ZMQ_MTRIE_HPP_INCLUDED__\n\n#include \"generic_mtrie.hpp\"\n\n#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER > 1600)\n#define ZMQ_HAS_EXTERN_TEMPLATE 1\n#else\n#define ZMQ_HAS_EXTERN_TEMPLATE 0\n#endif\n\nnamespace zmq\n{\nclass pipe_t;\n\n#if ZMQ_HAS_EXTERN_TEMPLATE\nextern template class generic_mtrie_t<pipe_t>;\n#endif\n\ntypedef generic_mtrie_t<pipe_t> mtrie_t;\n}\n\n#endif\n"
  },
  {
    "path": "src/mutex.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_MUTEX_HPP_INCLUDED__\n#define __ZMQ_MUTEX_HPP_INCLUDED__\n\n#include \"err.hpp\"\n#include \"macros.hpp\"\n\n//  Mutex class encapsulates OS mutex in a platform-independent way.\n\n#if defined(ZMQ_HAVE_WINDOWS) && !defined(ZMQ_USE_CV_IMPL_PTHREADS)\n\n#include \"windows.hpp\"\n\nnamespace zmq\n{\nclass mutex_t\n{\n  public:\n    mutex_t () { InitializeCriticalSection (&_cs); }\n\n    ~mutex_t () { DeleteCriticalSection (&_cs); }\n\n    void lock () { EnterCriticalSection (&_cs); }\n\n    bool try_lock () { return (TryEnterCriticalSection (&_cs)) ? true : false; }\n\n    void unlock () { LeaveCriticalSection (&_cs); }\n\n    CRITICAL_SECTION *get_cs () { return &_cs; }\n\n  private:\n    CRITICAL_SECTION _cs;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (mutex_t)\n};\n}\n\n#elif defined ZMQ_HAVE_VXWORKS\n\n#include <vxWorks.h>\n#include <semLib.h>\n\nnamespace zmq\n{\nclass mutex_t\n{\n  public:\n    inline mutex_t ()\n    {\n        _semId =\n          semMCreate (SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE);\n    }\n\n    inline ~mutex_t () { semDelete (_semId); }\n\n    inline void lock () { semTake (_semId, WAIT_FOREVER); }\n\n    inline bool try_lock ()\n    {\n        if (semTake (_semId, NO_WAIT) == OK) {\n            return true;\n        }\n        return false;\n    }\n\n    inline void unlock () { semGive (_semId); }\n\n  private:\n    SEM_ID _semId;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (mutex_t)\n};\n}\n\n#else\n\n#include <pthread.h>\n\nnamespace zmq\n{\nclass mutex_t\n{\n  public:\n    inline mutex_t ()\n    {\n        int rc = pthread_mutexattr_init (&_attr);\n        posix_assert (rc);\n\n        rc = pthread_mutexattr_settype (&_attr, PTHREAD_MUTEX_RECURSIVE);\n        posix_assert (rc);\n\n        rc = pthread_mutex_init (&_mutex, &_attr);\n        posix_assert (rc);\n    }\n\n    inline ~mutex_t ()\n    {\n        int rc = pthread_mutex_destroy (&_mutex);\n        posix_assert (rc);\n\n        rc = pthread_mutexattr_destroy (&_attr);\n        posix_assert (rc);\n    }\n\n    inline void lock ()\n    {\n        int rc = pthread_mutex_lock (&_mutex);\n        posix_assert (rc);\n    }\n\n    inline bool try_lock ()\n    {\n        int rc = pthread_mutex_trylock (&_mutex);\n        if (rc == EBUSY)\n            return false;\n\n        posix_assert (rc);\n        return true;\n    }\n\n    inline void unlock ()\n    {\n        int rc = pthread_mutex_unlock (&_mutex);\n        posix_assert (rc);\n    }\n\n    inline pthread_mutex_t *get_mutex () { return &_mutex; }\n\n  private:\n    pthread_mutex_t _mutex;\n    pthread_mutexattr_t _attr;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (mutex_t)\n};\n}\n\n#endif\n\n\nnamespace zmq\n{\nstruct scoped_lock_t\n{\n    scoped_lock_t (mutex_t &mutex_) : _mutex (mutex_) { _mutex.lock (); }\n\n    ~scoped_lock_t () { _mutex.unlock (); }\n\n  private:\n    mutex_t &_mutex;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (scoped_lock_t)\n};\n\n\nstruct scoped_optional_lock_t\n{\n    scoped_optional_lock_t (mutex_t *mutex_) : _mutex (mutex_)\n    {\n        if (_mutex != NULL)\n            _mutex->lock ();\n    }\n\n    ~scoped_optional_lock_t ()\n    {\n        if (_mutex != NULL)\n            _mutex->unlock ();\n    }\n\n  private:\n    mutex_t *_mutex;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (scoped_optional_lock_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/norm_engine.cpp",
    "content": "\n#include \"precompiled.hpp\"\n\n#include \"platform.hpp\"\n\n#if defined ZMQ_HAVE_NORM\n\n#include \"norm_engine.hpp\"\n#ifdef ZMQ_USE_NORM_SOCKET_WRAPPER\n#include \"ip.hpp\"\n#endif\n\n#include \"session_base.hpp\"\n#include \"v2_protocol.hpp\"\n\n\n#ifdef ZMQ_USE_NORM_SOCKET_WRAPPER\n\nstruct norm_wrapper_thread_args_t\n{\n    NormDescriptor norm_descriptor;\n    SOCKET wrapper_write_fd;\n    NormInstanceHandle norm_instance_handle;\n};\n\nDWORD WINAPI normWrapperThread (LPVOID lpParam);\n#endif\n\nzmq::norm_engine_t::norm_engine_t (io_thread_t *parent_,\n                                   const options_t &options_) :\n    io_object_t (parent_),\n    zmq_session (NULL),\n    options (options_),\n    norm_instance (NORM_INSTANCE_INVALID),\n    norm_session (NORM_SESSION_INVALID),\n    is_sender (false),\n    is_receiver (false),\n    zmq_encoder (0),\n    norm_tx_stream (NORM_OBJECT_INVALID),\n    tx_first_msg (true),\n    tx_more_bit (false),\n    zmq_output_ready (false),\n    norm_tx_ready (false),\n    tx_index (0),\n    tx_len (0),\n    zmq_input_ready (false)\n{\n    int rc = tx_msg.init ();\n    errno_assert (0 == rc);\n}\n\nzmq::norm_engine_t::~norm_engine_t ()\n{\n    shutdown (); // in case it was not already called\n}\n\n\nint zmq::norm_engine_t::init (const char *network_, bool send, bool recv)\n{\n    // Parse the \"network_\" address int \"iface\", \"addr\", and \"port\"\n    // norm endpoint format: [id,][<iface>;]<addr>:<port>\n    // First, look for optional local NormNodeId\n    // (default NORM_NODE_ANY causes NORM to use host IP addr for NormNodeId)\n    NormNodeId localId = NORM_NODE_ANY;\n    const char *ifacePtr = strchr (network_, ',');\n    if (NULL != ifacePtr) {\n        size_t idLen = ifacePtr - network_;\n        if (idLen > 31)\n            idLen = 31;\n        char idText[32];\n        strncpy (idText, network_, idLen);\n        idText[idLen] = '\\0';\n        localId = (NormNodeId) atoi (idText);\n        ifacePtr++;\n    } else {\n        ifacePtr = network_;\n    }\n\n    // Second, look for optional multicast ifaceName\n    char ifaceName[256];\n    const char *addrPtr = strchr (ifacePtr, ';');\n    if (NULL != addrPtr) {\n        size_t ifaceLen = addrPtr - ifacePtr;\n        if (ifaceLen > 255)\n            ifaceLen = 255; // return error instead?\n        strncpy (ifaceName, ifacePtr, ifaceLen);\n        ifaceName[ifaceLen] = '\\0';\n        ifacePtr = ifaceName;\n        addrPtr++;\n    } else {\n        addrPtr = ifacePtr;\n        ifacePtr = NULL;\n    }\n\n    // Finally, parse IP address and port number\n    const char *portPtr = strrchr (addrPtr, ':');\n    if (NULL == portPtr) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    char addr[256];\n    size_t addrLen = portPtr - addrPtr;\n    if (addrLen > 255)\n        addrLen = 255;\n    strncpy (addr, addrPtr, addrLen);\n    addr[addrLen] = '\\0';\n    portPtr++;\n    unsigned short portNumber = atoi (portPtr);\n\n    if (NORM_INSTANCE_INVALID == norm_instance) {\n        if (NORM_INSTANCE_INVALID == (norm_instance = NormCreateInstance ())) {\n            // errno set by whatever caused NormCreateInstance() to fail\n            return -1;\n        }\n    }\n\n    // TBD - What do we use for our local NormNodeId?\n    //       (for now we use automatic, IP addr based assignment or passed in 'id')\n    //       a) Use ZMQ Identity somehow?\n    //       b) Add function to use iface addr\n    //       c) Randomize and implement a NORM session layer\n    //          conflict detection/resolution protocol\n\n    norm_session = NormCreateSession (norm_instance, addr, portNumber, localId);\n    if (NORM_SESSION_INVALID == norm_session) {\n        int savedErrno = errno;\n        NormDestroyInstance (norm_instance);\n        norm_instance = NORM_INSTANCE_INVALID;\n        errno = savedErrno;\n        return -1;\n    }\n    // There's many other useful NORM options that could be applied here\n    if (!NormIsUnicastAddress (addr)) {\n        // These only apply for multicast sessions\n        NormSetTTL (norm_session, options.multicast_hops);\n        NormSetRxPortReuse (\n          norm_session,\n          true); // port reuse doesn't work for non-connected unicast\n        NormSetLoopback (norm_session,\n                         true); // needed when multicast users on same machine\n        if (NULL != ifacePtr) {\n            // Note a bad interface may not be caught until sender or receiver start\n            // (Since sender/receiver is not yet started, this always succeeds here)\n            NormSetMulticastInterface (norm_session, ifacePtr);\n        }\n    }\n    if (NormIsUnicastAddress (addr) || options.norm_unicast_nacks) {\n        NormSetDefaultUnicastNack (norm_session, true);\n    }\n    // Set TOS but check TOS ECN bit for CCE modes\n    if ((options.norm_mode == ZMQ_NORM_CCE\n         || options.norm_mode == ZMQ_NORM_CCE_ECNONLY)\n        && (options.tos % 4 == 0)) {\n        // ECN Capable Transport not set, so set it\n        NormSetTOS (norm_session, options.tos + 1);\n    } else if ((options.norm_mode == ZMQ_NORM_CCE\n                || options.norm_mode == ZMQ_NORM_CCE_ECNONLY)\n               && (options.tos % 4 == 3)) {\n        // Congestion Experienced is an invalid setting, remove one of the bits\n        NormSetTOS (norm_session, options.tos - 1);\n    } else {\n        NormSetTOS (norm_session, options.tos);\n    }\n\n    if (recv) {\n        // The alternative NORM_SYNC_CURRENT here would provide \"instant\"\n        // receiver sync to the sender's _current_ message transmission.\n        // NORM_SYNC_STREAM tries to get everything the sender has cached/buffered\n        NormSetDefaultSyncPolicy (norm_session, NORM_SYNC_STREAM);\n        if (!NormStartReceiver (\n              norm_session, (unsigned long) options.norm_buffer_size * 1024)) {\n            // errno set by whatever failed\n            int savedErrno = errno;\n            NormDestroyInstance (norm_instance); // session gets closed, too\n            norm_session = NORM_SESSION_INVALID;\n            norm_instance = NORM_INSTANCE_INVALID;\n            errno = savedErrno;\n            return -1;\n        }\n        is_receiver = true;\n    }\n\n    if (send) {\n        // Handle invalid settings -- num_parity must be >= num_autoparity (which has a default of 0)\n        unsigned char numparity =\n          (options.norm_num_parity >= options.norm_num_autoparity\n             ? options.norm_num_parity\n             : options.norm_num_autoparity);\n        // Handle invalid settings -- block size must be > effective num_parity (which is <255)\n        unsigned char blocksize =\n          (options.norm_block_size > numparity ? options.norm_block_size\n                                               : numparity + 1);\n        // Pick a random sender instance id (aka norm sender session id)\n        NormSessionId instanceId = NormGetRandomSessionId ();\n        // TBD - provide \"options\" for some NORM sender parameters\n        if (!NormStartSender (norm_session, instanceId,\n                              (unsigned long) options.norm_buffer_size * 1024,\n                              options.norm_segment_size, blocksize,\n                              numparity)) {\n            // errno set by whatever failed\n            int savedErrno = errno;\n            NormDestroyInstance (norm_instance); // session gets closed, too\n            norm_session = NORM_SESSION_INVALID;\n            norm_instance = NORM_INSTANCE_INVALID;\n            errno = savedErrno;\n            return -1;\n        }\n        // Handle NORM mode\n        if (options.norm_mode == ZMQ_NORM_FIXED) {\n            NormSetTxRate (norm_session, (double) options.rate * 1000);\n        } else {\n            NormSetCongestionControl (norm_session, true);\n            if (options.norm_mode != ZMQ_NORM_CC) {\n                NormSetEcnSupport (\n                  norm_session,\n                  ((options.norm_mode == ZMQ_NORM_CCE)\n                   || (options.norm_mode == ZMQ_NORM_CCE_ECNONLY)),\n                  options.norm_mode == ZMQ_NORM_CCE_ECNONLY,\n                  options.norm_mode == ZMQ_NORM_CCL);\n            }\n        }\n        if (options.norm_num_autoparity > 0) {\n            NormSetAutoParity (norm_session, options.norm_num_autoparity);\n        }\n        norm_tx_ready = true;\n        is_sender = true;\n        if (NORM_OBJECT_INVALID\n            == (norm_tx_stream = NormStreamOpen (\n                  norm_session,\n                  (unsigned long) options.norm_buffer_size * 1024))) {\n            // errno set by whatever failed\n            int savedErrno = errno;\n            NormDestroyInstance (norm_instance); // session gets closed, too\n            norm_session = NORM_SESSION_INVALID;\n            norm_instance = NORM_INSTANCE_INVALID;\n            errno = savedErrno;\n            return -1;\n        }\n        // NORM Stream options\n        NormStreamSetPushEnable (norm_tx_stream, options.norm_push_enable);\n    }\n\n    //NormSetMessageTrace(norm_session, true);\n    //NormSetDebugLevel(3);\n    //NormOpenDebugLog(norm_instance, \"normLog.txt\");\n\n    return 0; // no error\n} // end zmq::norm_engine_t::init()\n\nvoid zmq::norm_engine_t::shutdown ()\n{\n    // TBD - implement a more graceful shutdown option\n    if (is_receiver) {\n        NormStopReceiver (norm_session);\n\n        // delete any active NormRxStreamState\n        rx_pending_list.Destroy ();\n        rx_ready_list.Destroy ();\n        msg_ready_list.Destroy ();\n\n        is_receiver = false;\n    }\n    if (is_sender) {\n        NormStopSender (norm_session);\n        is_sender = false;\n    }\n    if (NORM_SESSION_INVALID != norm_session) {\n        NormDestroySession (norm_session);\n        norm_session = NORM_SESSION_INVALID;\n    }\n    if (NORM_INSTANCE_INVALID != norm_instance) {\n        NormStopInstance (norm_instance);\n        NormDestroyInstance (norm_instance);\n        norm_instance = NORM_INSTANCE_INVALID;\n    }\n} // end zmq::norm_engine_t::shutdown()\n\nvoid zmq::norm_engine_t::plug (io_thread_t *io_thread_,\n                               session_base_t *session_)\n{\n#ifdef ZMQ_USE_NORM_SOCKET_WRAPPER\n    norm_wrapper_thread_args_t *threadArgs = new norm_wrapper_thread_args_t;\n    int rc = make_fdpair (&wrapper_read_fd, &threadArgs->wrapper_write_fd);\n    errno_assert (rc != -1);\n\n    threadArgs->norm_descriptor = NormGetDescriptor (norm_instance);\n    threadArgs->norm_instance_handle = norm_instance;\n    norm_descriptor_handle = add_fd (wrapper_read_fd);\n#else\n    fd_t normDescriptor = NormGetDescriptor (norm_instance);\n    norm_descriptor_handle = add_fd (normDescriptor);\n#endif\n    // Set POLLIN for notification of pending NormEvents\n    set_pollin (norm_descriptor_handle);\n    // TBD - we may assign the NORM engine to an io_thread in the future???\n    zmq_session = session_;\n    if (is_sender)\n        zmq_output_ready = true;\n    if (is_receiver)\n        zmq_input_ready = true;\n\n\n    if (is_sender)\n        send_data ();\n\n#ifdef ZMQ_USE_NORM_SOCKET_WRAPPER\n    wrapper_thread_handle = CreateThread (NULL, 0, normWrapperThread,\n                                          threadArgs, 0, &wrapper_thread_id);\n#endif\n\n} // end zmq::norm_engine_t::init()\n\nvoid zmq::norm_engine_t::unplug ()\n{\n    rm_fd (norm_descriptor_handle);\n#ifdef ZMQ_USE_NORM_SOCKET_WRAPPER\n    PostThreadMessage (wrapper_thread_id, WM_QUIT, (WPARAM) NULL,\n                       (LPARAM) NULL);\n    WaitForSingleObject (wrapper_thread_handle, INFINITE);\n    DWORD exitCode;\n    GetExitCodeThread (wrapper_thread_handle, &exitCode);\n    zmq_assert (exitCode != -1);\n    int rc = closesocket (wrapper_read_fd);\n    errno_assert (rc != -1);\n#endif\n    zmq_session = NULL;\n} // end zmq::norm_engine_t::unplug()\n\nvoid zmq::norm_engine_t::terminate ()\n{\n    unplug ();\n    shutdown ();\n    delete this;\n}\n\nvoid zmq::norm_engine_t::restart_output ()\n{\n    // There's new message data available from the session\n    zmq_output_ready = true;\n    if (norm_tx_ready)\n        send_data ();\n\n} // end zmq::norm_engine_t::restart_output()\n\nvoid zmq::norm_engine_t::send_data ()\n{\n    // Here we write as much as is available or we can\n    while (zmq_output_ready && norm_tx_ready) {\n        if (0 == tx_len) {\n            // Our tx_buffer needs data to send\n            // Get more data from encoder\n            size_t space = BUFFER_SIZE;\n            unsigned char *bufPtr = (unsigned char *) tx_buffer;\n            tx_len = zmq_encoder.encode (&bufPtr, space);\n            if (0 == tx_len) {\n                if (tx_first_msg) {\n                    // We don't need to mark eom/flush until a message is sent\n                    tx_first_msg = false;\n                } else {\n                    // A prior message was completely written to stream, so\n                    // mark end-of-message and possibly flush (to force packet transmission,\n                    // even if it's not a full segment so message gets delivered quickly)\n                    // NormStreamMarkEom(norm_tx_stream);  // the flush below marks eom\n                    // Note NORM_FLUSH_ACTIVE makes NORM fairly chatty for low duty cycle messaging\n                    // but makes sure content is delivered quickly.  Positive acknowledgements\n                    // with flush override would make NORM more succinct here\n                    NormStreamFlush (norm_tx_stream, true, NORM_FLUSH_ACTIVE);\n                }\n                // Need to pull and load a new message to send\n                if (-1 == zmq_session->pull_msg (&tx_msg)) {\n                    // We need to wait for \"restart_output()\" to be called by ZMQ\n                    zmq_output_ready = false;\n                    break;\n                }\n                zmq_encoder.load_msg (&tx_msg);\n                // Should we write message size header for NORM to use? Or expect NORM\n                // receiver to decode ZMQ message framing format(s)?\n                // OK - we need to use a byte to denote when the ZMQ frame is the _first_\n                //      frame of a message so it can be decoded properly when a receiver\n                //      'syncs' mid-stream.  We key off the the state of the 'more_flag'\n                //      I.e.,If  more_flag _was_ false previously, this is the first\n                //      frame of a ZMQ message.\n                if (tx_more_bit)\n                    tx_buffer[0] =\n                      (char) 0xff; // this is not first frame of message\n                else\n                    tx_buffer[0] = 0x00; // this is first frame of message\n                tx_more_bit = (0 != (tx_msg.flags () & msg_t::more));\n                // Go ahead an get a first chunk of the message\n                bufPtr++;\n                space--;\n                tx_len = 1 + zmq_encoder.encode (&bufPtr, space);\n                tx_index = 0;\n            }\n        }\n        // Do we have data in our tx_buffer pending\n        if (tx_index < tx_len) {\n            // We have data in our tx_buffer to send, so write it to the stream\n            tx_index += NormStreamWrite (norm_tx_stream, tx_buffer + tx_index,\n                                         tx_len - tx_index);\n            if (tx_index < tx_len) {\n                // NORM stream buffer full, wait for NORM_TX_QUEUE_VACANCY\n                norm_tx_ready = false;\n                break;\n            }\n            tx_len = 0; // all buffered data was written\n        }\n    } // end while (zmq_output_ready && norm_tx_ready)\n} // end zmq::norm_engine_t::send_data()\n\nvoid zmq::norm_engine_t::in_event ()\n{\n    // This means a NormEvent is pending, so call NormGetNextEvent() and handle\n    NormEvent event;\n#ifdef ZMQ_USE_NORM_SOCKET_WRAPPER\n    int rc = recv (wrapper_read_fd, reinterpret_cast<char *> (&event),\n                   sizeof (event), 0);\n    errno_assert (rc == sizeof (event));\n#else\n    if (!NormGetNextEvent (norm_instance, &event)) {\n        // NORM has died before we unplugged?!\n        zmq_assert (false);\n        return;\n    }\n#endif\n\n    switch (event.type) {\n        case NORM_TX_QUEUE_VACANCY:\n        case NORM_TX_QUEUE_EMPTY:\n            if (!norm_tx_ready) {\n                norm_tx_ready = true;\n                send_data ();\n            }\n            break;\n\n        case NORM_RX_OBJECT_NEW:\n            //break;\n        case NORM_RX_OBJECT_UPDATED:\n            recv_data (event.object);\n            break;\n\n        case NORM_RX_OBJECT_ABORTED: {\n            NormRxStreamState *rxState =\n              (NormRxStreamState *) NormObjectGetUserData (event.object);\n            if (NULL != rxState) {\n                // Remove the state from the list it's in\n                // This is now unnecessary since deletion takes care of list removal\n                // but in the interest of being clear ...\n                NormRxStreamState::List *list = rxState->AccessList ();\n                if (NULL != list)\n                    list->Remove (*rxState);\n            }\n            delete rxState;\n            break;\n        }\n        case NORM_REMOTE_SENDER_INACTIVE:\n            // Here we free resources used for this formerly active sender.\n            // Note w/ NORM_SYNC_STREAM, if sender reactivates, we may\n            //  get some messages delivered twice.  NORM_SYNC_CURRENT would\n            // mitigate that but might miss data at startup. Always tradeoffs.\n            // Instead of immediately deleting, we could instead initiate a\n            // user configurable timeout here to wait some amount of time\n            // after this event to declare the remote sender truly dead\n            // and delete its state???\n            NormNodeDelete (event.sender);\n            break;\n\n        default:\n            // We ignore some NORM events\n            break;\n    }\n} // zmq::norm_engine_t::in_event()\n\nbool zmq::norm_engine_t::restart_input ()\n{\n    // TBD - should we check/assert that zmq_input_ready was false???\n    zmq_input_ready = true;\n    // Process any pending received messages\n    if (!msg_ready_list.IsEmpty ())\n        recv_data (NORM_OBJECT_INVALID);\n\n    return true;\n} // end zmq::norm_engine_t::restart_input()\n\nvoid zmq::norm_engine_t::recv_data (NormObjectHandle object)\n{\n    if (NORM_OBJECT_INVALID != object) {\n        // Call result of NORM_RX_OBJECT_UPDATED notification\n        // This is a rx_ready indication for a new or existing rx stream\n        // First, determine if this is a stream we already know\n        zmq_assert (NORM_OBJECT_STREAM == NormObjectGetType (object));\n        // Since there can be multiple senders (publishers), we keep\n        // state for each separate rx stream.\n        NormRxStreamState *rxState =\n          (NormRxStreamState *) NormObjectGetUserData (object);\n        if (NULL == rxState) {\n            // This is a new stream, so create rxState with zmq decoder, etc\n            rxState = new (std::nothrow)\n              NormRxStreamState (object, options.maxmsgsize, options.zero_copy,\n                                 options.in_batch_size);\n            errno_assert (rxState);\n\n            if (!rxState->Init ()) {\n                errno_assert (false);\n                delete rxState;\n                return;\n            }\n            NormObjectSetUserData (object, rxState);\n        } else if (!rxState->IsRxReady ()) {\n            // Existing non-ready stream, so remove from pending\n            // list to be promoted to rx_ready_list ...\n            rx_pending_list.Remove (*rxState);\n        }\n        if (!rxState->IsRxReady ()) {\n            // TBD - prepend up front for immediate service?\n            rxState->SetRxReady (true);\n            rx_ready_list.Append (*rxState);\n        }\n    }\n    // This loop repeats until we've read all data available from \"rx ready\" inbound streams\n    // and pushed any accumulated messages we can up to the zmq session.\n    while (!rx_ready_list.IsEmpty ()\n           || (zmq_input_ready && !msg_ready_list.IsEmpty ())) {\n        // Iterate through our rx_ready streams, reading data into the decoder\n        // (This services incoming \"rx ready\" streams in a round-robin fashion)\n        NormRxStreamState::List::Iterator iterator (rx_ready_list);\n        NormRxStreamState *rxState;\n        while (NULL != (rxState = iterator.GetNextItem ())) {\n            switch (rxState->Decode ()) {\n                case 1: // msg completed\n                    // Complete message decoded, move this stream to msg_ready_list\n                    // to push the message up to the session below.  Note the stream\n                    // will be returned to the \"rx_ready_list\" after that's done\n                    rx_ready_list.Remove (*rxState);\n                    msg_ready_list.Append (*rxState);\n                    continue;\n\n                case -1: // decoding error (shouldn't happen w/ NORM, but ...)\n                    // We need to re-sync this stream (decoder buffer was reset)\n                    rxState->SetSync (false);\n                    break;\n\n                default: // 0 - need more data\n                    break;\n            }\n            // Get more data from this stream\n            NormObjectHandle stream = rxState->GetStreamHandle ();\n            // First, make sure we're in sync ...\n            while (!rxState->InSync ()) {\n                // seek NORM message start\n                if (!NormStreamSeekMsgStart (stream)) {\n                    // Need to wait for more data\n                    break;\n                }\n                // read message 'flag' byte to see if this it's a 'final' frame\n                char syncFlag;\n                unsigned int numBytes = 1;\n                if (!NormStreamRead (stream, &syncFlag, &numBytes)) {\n                    // broken stream (can happen on late-joining subscriber)\n                    continue;\n                }\n                if (0 == numBytes) {\n                    // This probably shouldn't happen either since we found msg start\n                    // Need to wait for more data\n                    break;\n                }\n                if (0 == syncFlag)\n                    rxState->SetSync (true);\n                // else keep seeking ...\n            } // end while(!rxState->InSync())\n            if (!rxState->InSync ()) {\n                // Need more data for this stream, so remove from \"rx ready\"\n                // list and iterate to next \"rx ready\" stream\n                rxState->SetRxReady (false);\n                // Move from rx_ready_list to rx_pending_list\n                rx_ready_list.Remove (*rxState);\n                rx_pending_list.Append (*rxState);\n                continue;\n            }\n            // Now we're actually ready to read data from the NORM stream to the zmq_decoder\n            // the underlying zmq_decoder->get_buffer() call sets how much is needed.\n            unsigned int numBytes = rxState->GetBytesNeeded ();\n            if (!NormStreamRead (stream, rxState->AccessBuffer (), &numBytes)) {\n                // broken NORM stream, so re-sync\n                rxState->Init (); // TBD - check result\n                // This will retry syncing, and getting data from this stream\n                // since we don't increment the \"it\" iterator\n                continue;\n            }\n            rxState->IncrementBufferCount (numBytes);\n            if (0 == numBytes) {\n                // All the data available has been read\n                // Need to wait for NORM_RX_OBJECT_UPDATED for this stream\n                rxState->SetRxReady (false);\n                // Move from rx_ready_list to rx_pending_list\n                rx_ready_list.Remove (*rxState);\n                rx_pending_list.Append (*rxState);\n            }\n        } // end while(NULL != (rxState = iterator.GetNextItem()))\n\n        if (zmq_input_ready) {\n            // At this point, we've made a pass through the \"rx_ready\" stream list\n            // Now make a pass through the \"msg_pending\" list (if the zmq session\n            // ready for more input).  This may possibly return streams back to\n            // the \"rx ready\" stream list after their pending message is handled\n            NormRxStreamState::List::Iterator iterator (msg_ready_list);\n            NormRxStreamState *rxState;\n            while (NULL != (rxState = iterator.GetNextItem ())) {\n                msg_t *msg = rxState->AccessMsg ();\n                int rc = zmq_session->push_msg (msg);\n                if (-1 == rc) {\n                    if (EAGAIN == errno) {\n                        // need to wait until session calls \"restart_input()\"\n                        zmq_input_ready = false;\n                        break;\n                    } else {\n                        // session rejected message?\n                        // TBD - handle this better\n                        zmq_assert (false);\n                    }\n                }\n                // else message was accepted.\n                msg_ready_list.Remove (*rxState);\n                if (\n                  rxState\n                    ->IsRxReady ()) // Move back to \"rx_ready\" list to read more data\n                    rx_ready_list.Append (*rxState);\n                else // Move back to \"rx_pending\" list until NORM_RX_OBJECT_UPDATED\n                    msg_ready_list.Append (*rxState);\n            } // end while(NULL != (rxState = iterator.GetNextItem()))\n        } // end if (zmq_input_ready)\n    } // end while ((!rx_ready_list.empty() || (zmq_input_ready && !msg_ready_list.empty()))\n\n    // Alert zmq of the messages we have pushed up\n    zmq_session->flush ();\n\n} // end zmq::norm_engine_t::recv_data()\n\nzmq::norm_engine_t::NormRxStreamState::NormRxStreamState (\n  NormObjectHandle normStream,\n  int64_t maxMsgSize,\n  bool zeroCopy,\n  int inBatchSize) :\n    norm_stream (normStream),\n    max_msg_size (maxMsgSize),\n    zero_copy (zeroCopy),\n    in_batch_size (inBatchSize),\n    in_sync (false),\n    rx_ready (false),\n    zmq_decoder (NULL),\n    skip_norm_sync (false),\n    buffer_ptr (NULL),\n    buffer_size (0),\n    buffer_count (0),\n    prev (NULL),\n    next (NULL),\n    list (NULL)\n{\n}\n\nzmq::norm_engine_t::NormRxStreamState::~NormRxStreamState ()\n{\n    if (NULL != zmq_decoder) {\n        delete zmq_decoder;\n        zmq_decoder = NULL;\n    }\n    if (NULL != list) {\n        list->Remove (*this);\n        list = NULL;\n    }\n}\n\nbool zmq::norm_engine_t::NormRxStreamState::Init ()\n{\n    in_sync = false;\n    skip_norm_sync = false;\n    if (NULL != zmq_decoder)\n        delete zmq_decoder;\n    zmq_decoder =\n      new (std::nothrow) v2_decoder_t (in_batch_size, max_msg_size, zero_copy);\n    alloc_assert (zmq_decoder);\n    if (NULL != zmq_decoder) {\n        buffer_count = 0;\n        buffer_size = 0;\n        zmq_decoder->get_buffer (&buffer_ptr, &buffer_size);\n        return true;\n    } else {\n        return false;\n    }\n} // end zmq::norm_engine_t::NormRxStreamState::Init()\n\n// This decodes any pending data sitting in our stream decoder buffer\n// It returns 1 upon message completion, -1 on error, 1 on msg completion\nint zmq::norm_engine_t::NormRxStreamState::Decode ()\n{\n    // If we have pending bytes to decode, process those first\n    while (buffer_count > 0) {\n        // There's pending data for the decoder to decode\n        size_t processed = 0;\n\n        // This a bit of a kludgy approach used to weed\n        // out the NORM ZMQ message transport \"syncFlag\" byte\n        // from the ZMQ message stream being decoded (but it works!)\n        if (skip_norm_sync) {\n            buffer_ptr++;\n            buffer_count--;\n            skip_norm_sync = false;\n        }\n\n        int rc = zmq_decoder->decode (buffer_ptr, buffer_count, processed);\n        buffer_ptr += processed;\n        buffer_count -= processed;\n        switch (rc) {\n            case 1:\n                // msg completed\n                if (0 == buffer_count) {\n                    buffer_size = 0;\n                    zmq_decoder->get_buffer (&buffer_ptr, &buffer_size);\n                }\n                skip_norm_sync = true;\n                return 1;\n            case -1:\n                // decoder error (reset decoder and state variables)\n                in_sync = false;\n                skip_norm_sync = false; // will get consumed by norm sync check\n                Init ();\n                break;\n\n            case 0:\n                // need more data, keep decoding until buffer exhausted\n                break;\n        }\n    }\n    // Reset buffer pointer/count for next read\n    buffer_count = 0;\n    buffer_size = 0;\n    zmq_decoder->get_buffer (&buffer_ptr, &buffer_size);\n    return 0; //  need more data\n\n} // end zmq::norm_engine_t::NormRxStreamState::Decode()\n\nzmq::norm_engine_t::NormRxStreamState::List::List () : head (NULL), tail (NULL)\n{\n}\n\nzmq::norm_engine_t::NormRxStreamState::List::~List ()\n{\n    Destroy ();\n}\n\nvoid zmq::norm_engine_t::NormRxStreamState::List::Destroy ()\n{\n    NormRxStreamState *item = head;\n    while (NULL != item) {\n        Remove (*item);\n        delete item;\n        item = head;\n    }\n} // end zmq::norm_engine_t::NormRxStreamState::List::Destroy()\n\nvoid zmq::norm_engine_t::NormRxStreamState::List::Append (\n  NormRxStreamState &item)\n{\n    item.prev = tail;\n    if (NULL != tail)\n        tail->next = &item;\n    else\n        head = &item;\n    item.next = NULL;\n    tail = &item;\n    item.list = this;\n} // end zmq::norm_engine_t::NormRxStreamState::List::Append()\n\nvoid zmq::norm_engine_t::NormRxStreamState::List::Remove (\n  NormRxStreamState &item)\n{\n    if (NULL != item.prev)\n        item.prev->next = item.next;\n    else\n        head = item.next;\n    if (NULL != item.next)\n        item.next->prev = item.prev;\n    else\n        tail = item.prev;\n    item.prev = item.next = NULL;\n    item.list = NULL;\n} // end zmq::norm_engine_t::NormRxStreamState::List::Remove()\n\nzmq::norm_engine_t::NormRxStreamState::List::Iterator::Iterator (\n  const List &list) :\n    next_item (list.head)\n{\n}\n\nzmq::norm_engine_t::NormRxStreamState *\nzmq::norm_engine_t::NormRxStreamState::List::Iterator::GetNextItem ()\n{\n    NormRxStreamState *nextItem = next_item;\n    if (NULL != nextItem)\n        next_item = nextItem->next;\n    return nextItem;\n} // end zmq::norm_engine_t::NormRxStreamState::List::Iterator::GetNextItem()\n\nconst zmq::endpoint_uri_pair_t &zmq::norm_engine_t::get_endpoint () const\n{\n    return _empty_endpoint;\n}\n\n\n#ifdef ZMQ_USE_NORM_SOCKET_WRAPPER\n#include <iostream>\nDWORD WINAPI normWrapperThread (LPVOID lpParam)\n{\n    norm_wrapper_thread_args_t *norm_wrapper_thread_args =\n      (norm_wrapper_thread_args_t *) lpParam;\n    NormEvent message;\n    DWORD waitRc;\n    DWORD exitCode = 0;\n    int rc;\n\n    for (;;) {\n        // wait for norm event or message\n        waitRc = MsgWaitForMultipleObjectsEx (\n          1, &norm_wrapper_thread_args->norm_descriptor, INFINITE,\n          QS_ALLPOSTMESSAGE, 0);\n\n        // Check if norm event\n        if (waitRc == WAIT_OBJECT_0) {\n            // Process norm event\n            if (!NormGetNextEvent (\n                  norm_wrapper_thread_args->norm_instance_handle, &message)) {\n                exitCode = -1;\n                break;\n            }\n            rc =\n              send (norm_wrapper_thread_args->wrapper_write_fd,\n                    reinterpret_cast<char *> (&message), sizeof (message), 0);\n            errno_assert (rc != -1);\n            // Check if message\n        } else if (waitRc == WAIT_OBJECT_0 + 1) {\n            // Exit if WM_QUIT is received otherwise do nothing\n            MSG message;\n            GetMessage (&message, 0, 0, 0);\n            if (message.message == WM_QUIT) {\n                break;\n            } else {\n                // do nothing\n            }\n            // Otherwise an error occurred\n        } else {\n            exitCode = -1;\n            break;\n        }\n    }\n    // Free resources\n    rc = closesocket (norm_wrapper_thread_args->wrapper_write_fd);\n    free (norm_wrapper_thread_args);\n    errno_assert (rc != -1);\n\n    return exitCode;\n}\n\n#endif\n\n#endif // ZMQ_HAVE_NORM\n"
  },
  {
    "path": "src/norm_engine.hpp",
    "content": "\n#ifndef __ZMQ_NORM_ENGINE_HPP_INCLUDED__\n#define __ZMQ_NORM_ENGINE_HPP_INCLUDED__\n\n#if defined ZMQ_HAVE_NORM\n\n#if defined(ZMQ_HAVE_WINDOWS) && defined(ZMQ_IOTHREAD_POLLER_USE_EPOLL)\n#define ZMQ_USE_NORM_SOCKET_WRAPPER\n#endif\n\n\n#include \"io_object.hpp\"\n#include \"i_engine.hpp\"\n#include \"options.hpp\"\n#include \"v2_decoder.hpp\"\n#include \"v2_encoder.hpp\"\n\n#include <normApi.h>\n\nnamespace zmq\n{\nclass io_thread_t;\nclass msg_t;\nclass session_base_t;\n\nclass norm_engine_t ZMQ_FINAL : public io_object_t, public i_engine\n{\n  public:\n    norm_engine_t (zmq::io_thread_t *parent_, const options_t &options_);\n    ~norm_engine_t () ZMQ_FINAL;\n\n    // create NORM instance, session, etc\n    int init (const char *network_, bool send, bool recv);\n    void shutdown ();\n\n    bool has_handshake_stage () ZMQ_FINAL { return false; };\n\n    //  i_engine interface implementation.\n    //  Plug the engine to the session.\n    void plug (zmq::io_thread_t *io_thread_,\n               class session_base_t *session_) ZMQ_FINAL;\n\n    //  Terminate and deallocate the engine. Note that 'detached'\n    //  events are not fired on termination.\n    void terminate () ZMQ_FINAL;\n\n    //  This method is called by the session to signalise that more\n    //  messages can be written to the pipe.\n    bool restart_input () ZMQ_FINAL;\n\n    //  This method is called by the session to signalise that there\n    //  are messages to send available.\n    void restart_output () ZMQ_FINAL;\n\n    void zap_msg_available () ZMQ_FINAL {}\n\n    const endpoint_uri_pair_t &get_endpoint () const ZMQ_FINAL;\n\n    // i_poll_events interface implementation.\n    // (we only need in_event() for NormEvent notification)\n    // (i.e., don't have any output events or timers (yet))\n    void in_event ();\n\n  private:\n    void unplug ();\n    void send_data ();\n    void recv_data (NormObjectHandle stream);\n\n\n    enum\n    {\n        BUFFER_SIZE = 2048\n    };\n\n    // Used to keep track of streams from multiple senders\n    class NormRxStreamState\n    {\n      public:\n        NormRxStreamState (NormObjectHandle normStream,\n                           int64_t maxMsgSize,\n                           bool zeroCopy,\n                           int inBatchSize);\n        ~NormRxStreamState ();\n\n        NormObjectHandle GetStreamHandle () const { return norm_stream; }\n\n        bool Init ();\n\n        void SetRxReady (bool state) { rx_ready = state; }\n        bool IsRxReady () const { return rx_ready; }\n\n        void SetSync (bool state) { in_sync = state; }\n        bool InSync () const { return in_sync; }\n\n        // These are used to feed data to decoder\n        // and its underlying \"msg\" buffer\n        char *AccessBuffer () { return (char *) (buffer_ptr + buffer_count); }\n        size_t GetBytesNeeded () const { return buffer_size - buffer_count; }\n        void IncrementBufferCount (size_t count) { buffer_count += count; }\n        msg_t *AccessMsg () { return zmq_decoder->msg (); }\n        // This invokes the decoder \"decode\" method\n        // returning 0 if more data is needed,\n        // 1 if the message is complete, If an error\n        // occurs the 'sync' is dropped and the\n        // decoder re-initialized\n        int Decode ();\n\n        class List\n        {\n          public:\n            List ();\n            ~List ();\n\n            void Append (NormRxStreamState &item);\n            void Remove (NormRxStreamState &item);\n\n            bool IsEmpty () const { return NULL == head; }\n\n            void Destroy ();\n\n            class Iterator\n            {\n              public:\n                Iterator (const List &list);\n                NormRxStreamState *GetNextItem ();\n\n              private:\n                NormRxStreamState *next_item;\n            };\n            friend class Iterator;\n\n          private:\n            NormRxStreamState *head;\n            NormRxStreamState *tail;\n\n        }; // end class zmq::norm_engine_t::NormRxStreamState::List\n\n        friend class List;\n\n        List *AccessList () { return list; }\n\n\n      private:\n        NormObjectHandle norm_stream;\n        int64_t max_msg_size;\n        bool zero_copy;\n        int in_batch_size;\n        bool in_sync;\n        bool rx_ready;\n        v2_decoder_t *zmq_decoder;\n        bool skip_norm_sync;\n        unsigned char *buffer_ptr;\n        size_t buffer_size;\n        size_t buffer_count;\n\n        NormRxStreamState *prev;\n        NormRxStreamState *next;\n        NormRxStreamState::List *list;\n\n    }; // end class zmq::norm_engine_t::NormRxStreamState\n\n    const endpoint_uri_pair_t _empty_endpoint;\n\n    session_base_t *zmq_session;\n    options_t options;\n    NormInstanceHandle norm_instance;\n    handle_t norm_descriptor_handle;\n    NormSessionHandle norm_session;\n    bool is_sender;\n    bool is_receiver;\n    // Sender state\n    msg_t tx_msg;\n    v2_encoder_t zmq_encoder; // for tx messages (we use v2 for now)\n    NormObjectHandle norm_tx_stream;\n    bool tx_first_msg;\n    bool tx_more_bit;\n    bool zmq_output_ready; // zmq has msg(s) to send\n    bool norm_tx_ready;    // norm has tx queue vacancy\n    // TBD - maybe don't need buffer if can access zmq message buffer directly?\n    char tx_buffer[BUFFER_SIZE];\n    unsigned int tx_index;\n    unsigned int tx_len;\n\n    // Receiver state\n    // Lists of norm rx streams from remote senders\n    bool zmq_input_ready; // zmq ready to receive msg(s)\n    NormRxStreamState::List\n      rx_pending_list; // rx streams waiting for data reception\n    NormRxStreamState::List\n      rx_ready_list; // rx streams ready for NormStreamRead()\n    NormRxStreamState::List\n      msg_ready_list; // rx streams w/ msg ready for push to zmq\n\n#ifdef ZMQ_USE_NORM_SOCKET_WRAPPER\n    fd_t\n      wrapper_read_fd; // filedescriptor used to read norm events through the wrapper\n    DWORD wrapper_thread_id;\n    HANDLE wrapper_thread_handle;\n#endif\n\n}; // end class norm_engine_t\n}\n\n#endif // ZMQ_HAVE_NORM\n\n#endif // !__ZMQ_NORM_ENGINE_HPP_INCLUDED__\n"
  },
  {
    "path": "src/null_mechanism.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include <stddef.h>\n#include <string.h>\n#include <stdlib.h>\n\n#include \"err.hpp\"\n#include \"msg.hpp\"\n#include \"session_base.hpp\"\n#include \"null_mechanism.hpp\"\n\nconst char error_command_name[] = \"\\5ERROR\";\nconst size_t error_command_name_len = sizeof (error_command_name) - 1;\nconst size_t error_reason_len_size = 1;\n\nconst char ready_command_name[] = \"\\5READY\";\nconst size_t ready_command_name_len = sizeof (ready_command_name) - 1;\n\nzmq::null_mechanism_t::null_mechanism_t (session_base_t *session_,\n                                         const std::string &peer_address_,\n                                         const options_t &options_) :\n    mechanism_base_t (session_, options_),\n    zap_client_t (session_, peer_address_, options_),\n    _ready_command_sent (false),\n    _error_command_sent (false),\n    _ready_command_received (false),\n    _error_command_received (false),\n    _zap_request_sent (false),\n    _zap_reply_received (false)\n{\n}\n\nzmq::null_mechanism_t::~null_mechanism_t ()\n{\n}\n\nint zmq::null_mechanism_t::next_handshake_command (msg_t *msg_)\n{\n    if (_ready_command_sent || _error_command_sent) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    if (zap_required () && !_zap_reply_received) {\n        if (_zap_request_sent) {\n            errno = EAGAIN;\n            return -1;\n        }\n        //  Given this is a backward-incompatible change, it's behind a socket\n        //  option disabled by default.\n        int rc = session->zap_connect ();\n        if (rc == -1 && options.zap_enforce_domain) {\n            session->get_socket ()->event_handshake_failed_no_detail (\n              session->get_endpoint (), EFAULT);\n            return -1;\n        }\n        if (rc == 0) {\n            send_zap_request ();\n            _zap_request_sent = true;\n\n            //  TODO actually, it is quite unlikely that we can read the ZAP\n            //  reply already, but removing this has some strange side-effect\n            //  (probably because the pipe's in_active flag is true until a read\n            //  is attempted)\n            rc = receive_and_process_zap_reply ();\n            if (rc != 0)\n                return -1;\n\n            _zap_reply_received = true;\n        }\n    }\n\n    if (_zap_reply_received && status_code != \"200\") {\n        _error_command_sent = true;\n        if (status_code != \"300\") {\n            const size_t status_code_len = 3;\n            const int rc = msg_->init_size (\n              error_command_name_len + error_reason_len_size + status_code_len);\n            zmq_assert (rc == 0);\n            unsigned char *msg_data =\n              static_cast<unsigned char *> (msg_->data ());\n            memcpy (msg_data, error_command_name, error_command_name_len);\n            msg_data += error_command_name_len;\n            *msg_data = status_code_len;\n            msg_data += error_reason_len_size;\n            memcpy (msg_data, status_code.c_str (), status_code_len);\n            return 0;\n        }\n        errno = EAGAIN;\n        return -1;\n    }\n\n    make_command_with_basic_properties (msg_, ready_command_name,\n                                        ready_command_name_len);\n\n    _ready_command_sent = true;\n\n    return 0;\n}\n\nint zmq::null_mechanism_t::process_handshake_command (msg_t *msg_)\n{\n    if (_ready_command_received || _error_command_received) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n\n    const unsigned char *cmd_data =\n      static_cast<unsigned char *> (msg_->data ());\n    const size_t data_size = msg_->size ();\n\n    int rc = 0;\n    if (data_size >= ready_command_name_len\n        && !memcmp (cmd_data, ready_command_name, ready_command_name_len))\n        rc = process_ready_command (cmd_data, data_size);\n    else if (data_size >= error_command_name_len\n             && !memcmp (cmd_data, error_command_name, error_command_name_len))\n        rc = process_error_command (cmd_data, data_size);\n    else {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        rc = -1;\n    }\n\n    if (rc == 0) {\n        rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n    }\n    return rc;\n}\n\nint zmq::null_mechanism_t::process_ready_command (\n  const unsigned char *cmd_data_, size_t data_size_)\n{\n    _ready_command_received = true;\n    return parse_metadata (cmd_data_ + ready_command_name_len,\n                           data_size_ - ready_command_name_len);\n}\n\nint zmq::null_mechanism_t::process_error_command (\n  const unsigned char *cmd_data_, size_t data_size_)\n{\n    const size_t fixed_prefix_size =\n      error_command_name_len + error_reason_len_size;\n    if (data_size_ < fixed_prefix_size) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);\n\n        errno = EPROTO;\n        return -1;\n    }\n    const size_t error_reason_len =\n      static_cast<size_t> (cmd_data_[error_command_name_len]);\n    if (error_reason_len > data_size_ - fixed_prefix_size) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);\n\n        errno = EPROTO;\n        return -1;\n    }\n    const char *error_reason =\n      reinterpret_cast<const char *> (cmd_data_) + fixed_prefix_size;\n    handle_error_reason (error_reason, error_reason_len);\n    _error_command_received = true;\n    return 0;\n}\n\nint zmq::null_mechanism_t::zap_msg_available ()\n{\n    if (_zap_reply_received) {\n        errno = EFSM;\n        return -1;\n    }\n    const int rc = receive_and_process_zap_reply ();\n    if (rc == 0)\n        _zap_reply_received = true;\n    return rc == -1 ? -1 : 0;\n}\n\nzmq::mechanism_t::status_t zmq::null_mechanism_t::status () const\n{\n    if (_ready_command_sent && _ready_command_received)\n        return ready;\n\n    const bool command_sent = _ready_command_sent || _error_command_sent;\n    const bool command_received =\n      _ready_command_received || _error_command_received;\n    return command_sent && command_received ? error : handshaking;\n}\n\nvoid zmq::null_mechanism_t::send_zap_request ()\n{\n    zap_client_t::send_zap_request (\"NULL\", 4, NULL, NULL, 0);\n}\n"
  },
  {
    "path": "src/null_mechanism.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_NULL_MECHANISM_HPP_INCLUDED__\n#define __ZMQ_NULL_MECHANISM_HPP_INCLUDED__\n\n#include \"mechanism.hpp\"\n#include \"options.hpp\"\n#include \"zap_client.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\nclass session_base_t;\n\nclass null_mechanism_t ZMQ_FINAL : public zap_client_t\n{\n  public:\n    null_mechanism_t (session_base_t *session_,\n                      const std::string &peer_address_,\n                      const options_t &options_);\n    ~null_mechanism_t ();\n\n    // mechanism implementation\n    int next_handshake_command (msg_t *msg_);\n    int process_handshake_command (msg_t *msg_);\n    int zap_msg_available ();\n    status_t status () const;\n\n  private:\n    bool _ready_command_sent;\n    bool _error_command_sent;\n    bool _ready_command_received;\n    bool _error_command_received;\n    bool _zap_request_sent;\n    bool _zap_reply_received;\n\n    int process_ready_command (const unsigned char *cmd_data_,\n                               size_t data_size_);\n    int process_error_command (const unsigned char *cmd_data_,\n                               size_t data_size_);\n\n    void send_zap_request ();\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/object.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string.h>\n#include <stdarg.h>\n\n#include \"object.hpp\"\n#include \"ctx.hpp\"\n#include \"err.hpp\"\n#include \"pipe.hpp\"\n#include \"io_thread.hpp\"\n#include \"session_base.hpp\"\n#include \"socket_base.hpp\"\n\nzmq::object_t::object_t (ctx_t *ctx_, uint32_t tid_) : _ctx (ctx_), _tid (tid_)\n{\n}\n\nzmq::object_t::object_t (object_t *parent_) :\n    _ctx (parent_->_ctx), _tid (parent_->_tid)\n{\n}\n\nzmq::object_t::~object_t ()\n{\n}\n\nuint32_t zmq::object_t::get_tid () const\n{\n    return _tid;\n}\n\nvoid zmq::object_t::set_tid (uint32_t id_)\n{\n    _tid = id_;\n}\n\nzmq::ctx_t *zmq::object_t::get_ctx () const\n{\n    return _ctx;\n}\n\nvoid zmq::object_t::process_command (const command_t &cmd_)\n{\n    switch (cmd_.type) {\n        case command_t::activate_read:\n            process_activate_read ();\n            break;\n\n        case command_t::activate_write:\n            process_activate_write (cmd_.args.activate_write.msgs_read);\n            break;\n\n        case command_t::stop:\n            process_stop ();\n            break;\n\n        case command_t::plug:\n            process_plug ();\n            process_seqnum ();\n            break;\n\n        case command_t::own:\n            process_own (cmd_.args.own.object);\n            process_seqnum ();\n            break;\n\n        case command_t::attach:\n            process_attach (cmd_.args.attach.engine);\n            process_seqnum ();\n            break;\n\n        case command_t::bind:\n            process_bind (cmd_.args.bind.pipe);\n            process_seqnum ();\n            break;\n\n        case command_t::hiccup:\n            process_hiccup (cmd_.args.hiccup.pipe);\n            break;\n\n        case command_t::pipe_peer_stats:\n            process_pipe_peer_stats (cmd_.args.pipe_peer_stats.queue_count,\n                                     cmd_.args.pipe_peer_stats.socket_base,\n                                     cmd_.args.pipe_peer_stats.endpoint_pair);\n            break;\n\n        case command_t::pipe_stats_publish:\n            process_pipe_stats_publish (\n              cmd_.args.pipe_stats_publish.outbound_queue_count,\n              cmd_.args.pipe_stats_publish.inbound_queue_count,\n              cmd_.args.pipe_stats_publish.endpoint_pair);\n            break;\n\n        case command_t::pipe_term:\n            process_pipe_term ();\n            break;\n\n        case command_t::pipe_term_ack:\n            process_pipe_term_ack ();\n            break;\n\n        case command_t::pipe_hwm:\n            process_pipe_hwm (cmd_.args.pipe_hwm.inhwm,\n                              cmd_.args.pipe_hwm.outhwm);\n            break;\n\n        case command_t::term_req:\n            process_term_req (cmd_.args.term_req.object);\n            break;\n\n        case command_t::term:\n            process_term (cmd_.args.term.linger);\n            break;\n\n        case command_t::term_ack:\n            process_term_ack ();\n            break;\n\n        case command_t::term_endpoint:\n            process_term_endpoint (cmd_.args.term_endpoint.endpoint);\n            break;\n\n        case command_t::reap:\n            process_reap (cmd_.args.reap.socket);\n            break;\n\n        case command_t::reaped:\n            process_reaped ();\n            break;\n\n        case command_t::inproc_connected:\n            process_seqnum ();\n            break;\n\n        case command_t::conn_failed:\n            process_conn_failed ();\n            break;\n\n        case command_t::done:\n        default:\n            zmq_assert (false);\n    }\n}\n\nint zmq::object_t::register_endpoint (const char *addr_,\n                                      const endpoint_t &endpoint_)\n{\n    return _ctx->register_endpoint (addr_, endpoint_);\n}\n\nint zmq::object_t::unregister_endpoint (const std::string &addr_,\n                                        socket_base_t *socket_)\n{\n    return _ctx->unregister_endpoint (addr_, socket_);\n}\n\nvoid zmq::object_t::unregister_endpoints (socket_base_t *socket_)\n{\n    return _ctx->unregister_endpoints (socket_);\n}\n\nzmq::endpoint_t zmq::object_t::find_endpoint (const char *addr_) const\n{\n    return _ctx->find_endpoint (addr_);\n}\n\nvoid zmq::object_t::pend_connection (const std::string &addr_,\n                                     const endpoint_t &endpoint_,\n                                     pipe_t **pipes_)\n{\n    _ctx->pend_connection (addr_, endpoint_, pipes_);\n}\n\nvoid zmq::object_t::connect_pending (const char *addr_,\n                                     zmq::socket_base_t *bind_socket_)\n{\n    return _ctx->connect_pending (addr_, bind_socket_);\n}\n\nvoid zmq::object_t::destroy_socket (socket_base_t *socket_)\n{\n    _ctx->destroy_socket (socket_);\n}\n\nzmq::io_thread_t *zmq::object_t::choose_io_thread (uint64_t affinity_) const\n{\n    return _ctx->choose_io_thread (affinity_);\n}\n\nvoid zmq::object_t::send_stop ()\n{\n    //  'stop' command goes always from administrative thread to\n    //  the current object.\n    command_t cmd;\n    cmd.destination = this;\n    cmd.type = command_t::stop;\n    _ctx->send_command (_tid, cmd);\n}\n\nvoid zmq::object_t::send_plug (own_t *destination_, bool inc_seqnum_)\n{\n    if (inc_seqnum_)\n        destination_->inc_seqnum ();\n\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::plug;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_own (own_t *destination_, own_t *object_)\n{\n    destination_->inc_seqnum ();\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::own;\n    cmd.args.own.object = object_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_attach (session_base_t *destination_,\n                                 i_engine *engine_,\n                                 bool inc_seqnum_)\n{\n    if (inc_seqnum_)\n        destination_->inc_seqnum ();\n\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::attach;\n    cmd.args.attach.engine = engine_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_conn_failed (session_base_t *destination_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::conn_failed;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_bind (own_t *destination_,\n                               pipe_t *pipe_,\n                               bool inc_seqnum_)\n{\n    if (inc_seqnum_)\n        destination_->inc_seqnum ();\n\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::bind;\n    cmd.args.bind.pipe = pipe_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_activate_read (pipe_t *destination_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::activate_read;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_activate_write (pipe_t *destination_,\n                                         uint64_t msgs_read_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::activate_write;\n    cmd.args.activate_write.msgs_read = msgs_read_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_hiccup (pipe_t *destination_, void *pipe_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::hiccup;\n    cmd.args.hiccup.pipe = pipe_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_pipe_peer_stats (pipe_t *destination_,\n                                          uint64_t queue_count_,\n                                          own_t *socket_base_,\n                                          endpoint_uri_pair_t *endpoint_pair_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::pipe_peer_stats;\n    cmd.args.pipe_peer_stats.queue_count = queue_count_;\n    cmd.args.pipe_peer_stats.socket_base = socket_base_;\n    cmd.args.pipe_peer_stats.endpoint_pair = endpoint_pair_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_pipe_stats_publish (\n  own_t *destination_,\n  uint64_t outbound_queue_count_,\n  uint64_t inbound_queue_count_,\n  endpoint_uri_pair_t *endpoint_pair_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::pipe_stats_publish;\n    cmd.args.pipe_stats_publish.outbound_queue_count = outbound_queue_count_;\n    cmd.args.pipe_stats_publish.inbound_queue_count = inbound_queue_count_;\n    cmd.args.pipe_stats_publish.endpoint_pair = endpoint_pair_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_pipe_term (pipe_t *destination_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::pipe_term;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_pipe_term_ack (pipe_t *destination_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::pipe_term_ack;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_pipe_hwm (pipe_t *destination_,\n                                   int inhwm_,\n                                   int outhwm_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::pipe_hwm;\n    cmd.args.pipe_hwm.inhwm = inhwm_;\n    cmd.args.pipe_hwm.outhwm = outhwm_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_term_req (own_t *destination_, own_t *object_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::term_req;\n    cmd.args.term_req.object = object_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_term (own_t *destination_, int linger_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::term;\n    cmd.args.term.linger = linger_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_term_ack (own_t *destination_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::term_ack;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_term_endpoint (own_t *destination_,\n                                        std::string *endpoint_)\n{\n    command_t cmd;\n    cmd.destination = destination_;\n    cmd.type = command_t::term_endpoint;\n    cmd.args.term_endpoint.endpoint = endpoint_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_reap (class socket_base_t *socket_)\n{\n    command_t cmd;\n    cmd.destination = _ctx->get_reaper ();\n    cmd.type = command_t::reap;\n    cmd.args.reap.socket = socket_;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_reaped ()\n{\n    command_t cmd;\n    cmd.destination = _ctx->get_reaper ();\n    cmd.type = command_t::reaped;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_inproc_connected (zmq::socket_base_t *socket_)\n{\n    command_t cmd;\n    cmd.destination = socket_;\n    cmd.type = command_t::inproc_connected;\n    send_command (cmd);\n}\n\nvoid zmq::object_t::send_done ()\n{\n    command_t cmd;\n    cmd.destination = NULL;\n    cmd.type = command_t::done;\n    _ctx->send_command (ctx_t::term_tid, cmd);\n}\n\nvoid zmq::object_t::process_stop ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_plug ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_own (own_t *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_attach (i_engine *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_bind (pipe_t *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_activate_read ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_activate_write (uint64_t)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_hiccup (void *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_pipe_peer_stats (uint64_t,\n                                             own_t *,\n                                             endpoint_uri_pair_t *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_pipe_stats_publish (uint64_t,\n                                                uint64_t,\n                                                endpoint_uri_pair_t *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_pipe_term ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_pipe_term_ack ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_pipe_hwm (int, int)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_term_req (own_t *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_term (int)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_term_ack ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_term_endpoint (std::string *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_reap (class socket_base_t *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_reaped ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_seqnum ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::process_conn_failed ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::object_t::send_command (const command_t &cmd_)\n{\n    _ctx->send_command (cmd_.destination->get_tid (), cmd_);\n}\n"
  },
  {
    "path": "src/object.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_OBJECT_HPP_INCLUDED__\n#define __ZMQ_OBJECT_HPP_INCLUDED__\n\n#include <string>\n\n#include \"endpoint.hpp\"\n#include \"macros.hpp\"\n#include \"stdint.hpp\"\n\nnamespace zmq\n{\nstruct i_engine;\nstruct endpoint_t;\nstruct pending_connection_t;\nstruct command_t;\nclass ctx_t;\nclass pipe_t;\nclass socket_base_t;\nclass session_base_t;\nclass io_thread_t;\nclass own_t;\n\n//  Base class for all objects that participate in inter-thread\n//  communication.\n\nclass object_t\n{\n  public:\n    object_t (zmq::ctx_t *ctx_, uint32_t tid_);\n    object_t (object_t *parent_);\n    virtual ~object_t ();\n\n    uint32_t get_tid () const;\n    void set_tid (uint32_t id_);\n    ctx_t *get_ctx () const;\n    void process_command (const zmq::command_t &cmd_);\n    void send_inproc_connected (zmq::socket_base_t *socket_);\n    void send_bind (zmq::own_t *destination_,\n                    zmq::pipe_t *pipe_,\n                    bool inc_seqnum_ = true);\n\n  protected:\n    //  Using following function, socket is able to access global\n    //  repository of inproc endpoints.\n    int register_endpoint (const char *addr_, const zmq::endpoint_t &endpoint_);\n    int unregister_endpoint (const std::string &addr_, socket_base_t *socket_);\n    void unregister_endpoints (zmq::socket_base_t *socket_);\n    zmq::endpoint_t find_endpoint (const char *addr_) const;\n    void pend_connection (const std::string &addr_,\n                          const endpoint_t &endpoint_,\n                          pipe_t **pipes_);\n    void connect_pending (const char *addr_, zmq::socket_base_t *bind_socket_);\n\n    void destroy_socket (zmq::socket_base_t *socket_);\n\n    //  Logs an message.\n    void log (const char *format_, ...);\n\n    //  Chooses least loaded I/O thread.\n    zmq::io_thread_t *choose_io_thread (uint64_t affinity_) const;\n\n    //  Derived object can use these functions to send commands\n    //  to other objects.\n    void send_stop ();\n    void send_plug (zmq::own_t *destination_, bool inc_seqnum_ = true);\n    void send_own (zmq::own_t *destination_, zmq::own_t *object_);\n    void send_attach (zmq::session_base_t *destination_,\n                      zmq::i_engine *engine_,\n                      bool inc_seqnum_ = true);\n    void send_activate_read (zmq::pipe_t *destination_);\n    void send_activate_write (zmq::pipe_t *destination_, uint64_t msgs_read_);\n    void send_hiccup (zmq::pipe_t *destination_, void *pipe_);\n    void send_pipe_peer_stats (zmq::pipe_t *destination_,\n                               uint64_t queue_count_,\n                               zmq::own_t *socket_base,\n                               endpoint_uri_pair_t *endpoint_pair_);\n    void send_pipe_stats_publish (zmq::own_t *destination_,\n                                  uint64_t outbound_queue_count_,\n                                  uint64_t inbound_queue_count_,\n                                  endpoint_uri_pair_t *endpoint_pair_);\n    void send_pipe_term (zmq::pipe_t *destination_);\n    void send_pipe_term_ack (zmq::pipe_t *destination_);\n    void send_pipe_hwm (zmq::pipe_t *destination_, int inhwm_, int outhwm_);\n    void send_term_req (zmq::own_t *destination_, zmq::own_t *object_);\n    void send_term (zmq::own_t *destination_, int linger_);\n    void send_term_ack (zmq::own_t *destination_);\n    void send_term_endpoint (own_t *destination_, std::string *endpoint_);\n    void send_reap (zmq::socket_base_t *socket_);\n    void send_reaped ();\n    void send_done ();\n    void send_conn_failed (zmq::session_base_t *destination_);\n\n\n    //  These handlers can be overridden by the derived objects. They are\n    //  called when command arrives from another thread.\n    virtual void process_stop ();\n    virtual void process_plug ();\n    virtual void process_own (zmq::own_t *object_);\n    virtual void process_attach (zmq::i_engine *engine_);\n    virtual void process_bind (zmq::pipe_t *pipe_);\n    virtual void process_activate_read ();\n    virtual void process_activate_write (uint64_t msgs_read_);\n    virtual void process_hiccup (void *pipe_);\n    virtual void process_pipe_peer_stats (uint64_t queue_count_,\n                                          zmq::own_t *socket_base_,\n                                          endpoint_uri_pair_t *endpoint_pair_);\n    virtual void\n    process_pipe_stats_publish (uint64_t outbound_queue_count_,\n                                uint64_t inbound_queue_count_,\n                                endpoint_uri_pair_t *endpoint_pair_);\n    virtual void process_pipe_term ();\n    virtual void process_pipe_term_ack ();\n    virtual void process_pipe_hwm (int inhwm_, int outhwm_);\n    virtual void process_term_req (zmq::own_t *object_);\n    virtual void process_term (int linger_);\n    virtual void process_term_ack ();\n    virtual void process_term_endpoint (std::string *endpoint_);\n    virtual void process_reap (zmq::socket_base_t *socket_);\n    virtual void process_reaped ();\n    virtual void process_conn_failed ();\n\n\n    //  Special handler called after a command that requires a seqnum\n    //  was processed. The implementation should catch up with its counter\n    //  of processed commands here.\n    virtual void process_seqnum ();\n\n  private:\n    //  Context provides access to the global state.\n    zmq::ctx_t *const _ctx;\n\n    //  Thread ID of the thread the object belongs to.\n    uint32_t _tid;\n\n    void send_command (const command_t &cmd_);\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (object_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/options.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string.h>\n#include <limits.h>\n#include <set>\n\n#include \"options.hpp\"\n#include \"err.hpp\"\n#include \"macros.hpp\"\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <net/if.h>\n#endif\n\n#if defined IFNAMSIZ\n#define BINDDEVSIZ IFNAMSIZ\n#else\n#define BINDDEVSIZ 16\n#endif\n\nstatic int sockopt_invalid ()\n{\n#if defined(ZMQ_ACT_MILITANT)\n    zmq_assert (false);\n#endif\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::do_getsockopt (void *const optval_,\n                        size_t *const optvallen_,\n                        const std::string &value_)\n{\n    return do_getsockopt (optval_, optvallen_, value_.c_str (),\n                          value_.size () + 1);\n}\n\nint zmq::do_getsockopt (void *const optval_,\n                        size_t *const optvallen_,\n                        const void *value_,\n                        const size_t value_len_)\n{\n    // TODO behaviour is inconsistent with options_t::getsockopt; there, an\n    // *exact* length match is required except for string-like (but not the\n    // CURVE keys!) (and therefore null-ing remaining memory is a no-op, see\n    // comment below)\n    if (*optvallen_ < value_len_) {\n        return sockopt_invalid ();\n    }\n    memcpy (optval_, value_, value_len_);\n    // TODO why is the remaining memory null-ed?\n    memset (static_cast<char *> (optval_) + value_len_, 0,\n            *optvallen_ - value_len_);\n    *optvallen_ = value_len_;\n    return 0;\n}\n\n#ifdef ZMQ_HAVE_CURVE\nstatic int do_getsockopt_curve_key (void *const optval_,\n                                    const size_t *const optvallen_,\n                                    const uint8_t (&curve_key_)[CURVE_KEYSIZE])\n{\n    if (*optvallen_ == CURVE_KEYSIZE) {\n        memcpy (optval_, curve_key_, CURVE_KEYSIZE);\n        return 0;\n    }\n    if (*optvallen_ == CURVE_KEYSIZE_Z85 + 1) {\n        zmq_z85_encode (static_cast<char *> (optval_), curve_key_,\n                        CURVE_KEYSIZE);\n        return 0;\n    }\n    return sockopt_invalid ();\n}\n#endif\n\ntemplate <typename T>\nstatic int do_setsockopt (const void *const optval_,\n                          const size_t optvallen_,\n                          T *const out_value_)\n{\n    if (optvallen_ == sizeof (T)) {\n        memcpy (out_value_, optval_, sizeof (T));\n        return 0;\n    }\n    return sockopt_invalid ();\n}\n\nint zmq::do_setsockopt_int_as_bool_strict (const void *const optval_,\n                                           const size_t optvallen_,\n                                           bool *const out_value_)\n{\n    // TODO handling of values other than 0 or 1 is not consistent,\n    // here it is disallowed, but for other options such as\n    // ZMQ_ROUTER_RAW any positive value is accepted\n    int value = -1;\n    if (do_setsockopt (optval_, optvallen_, &value) == -1)\n        return -1;\n    if (value == 0 || value == 1) {\n        *out_value_ = (value != 0);\n        return 0;\n    }\n    return sockopt_invalid ();\n}\n\nint zmq::do_setsockopt_int_as_bool_relaxed (const void *const optval_,\n                                            const size_t optvallen_,\n                                            bool *const out_value_)\n{\n    int value = -1;\n    if (do_setsockopt (optval_, optvallen_, &value) == -1)\n        return -1;\n    *out_value_ = (value != 0);\n    return 0;\n}\n\nstatic int\ndo_setsockopt_string_allow_empty_strict (const void *const optval_,\n                                         const size_t optvallen_,\n                                         std::string *const out_value_,\n                                         const size_t max_len_)\n{\n    // TODO why is optval_ != NULL not allowed in case of optvallen_== 0?\n    // TODO why are empty strings allowed for some socket options, but not for others?\n    if (optval_ == NULL && optvallen_ == 0) {\n        out_value_->clear ();\n        return 0;\n    }\n    if (optval_ != NULL && optvallen_ > 0 && optvallen_ <= max_len_) {\n        out_value_->assign (static_cast<const char *> (optval_), optvallen_);\n        return 0;\n    }\n    return sockopt_invalid ();\n}\n\nstatic int\ndo_setsockopt_string_allow_empty_relaxed (const void *const optval_,\n                                          const size_t optvallen_,\n                                          std::string *const out_value_,\n                                          const size_t max_len_)\n{\n    // TODO use either do_setsockopt_string_allow_empty_relaxed or\n    // do_setsockopt_string_allow_empty_strict everywhere\n    if (optvallen_ > 0 && optvallen_ <= max_len_) {\n        out_value_->assign (static_cast<const char *> (optval_), optvallen_);\n        return 0;\n    }\n    return sockopt_invalid ();\n}\n\ntemplate <typename T>\nstatic int do_setsockopt_set (const void *const optval_,\n                              const size_t optvallen_,\n                              std::set<T> *const set_)\n{\n    if (optvallen_ == 0 && optval_ == NULL) {\n        set_->clear ();\n        return 0;\n    }\n    if (optvallen_ == sizeof (T) && optval_ != NULL) {\n        set_->insert (*(static_cast<const T *> (optval_)));\n        return 0;\n    }\n    return sockopt_invalid ();\n}\n\n// TODO why is 1000 a sensible default?\nconst int default_hwm = 1000;\n\nzmq::options_t::options_t () :\n    sndhwm (default_hwm),\n    rcvhwm (default_hwm),\n    affinity (0),\n    routing_id_size (0),\n    rate (100),\n    recovery_ivl (10000),\n    multicast_hops (1),\n    multicast_maxtpdu (1500),\n    sndbuf (-1),\n    rcvbuf (-1),\n    tos (0),\n    priority (0),\n    type (-1),\n    linger (-1),\n    connect_timeout (0),\n    tcp_maxrt (0),\n    reconnect_stop (0),\n    reconnect_ivl (100),\n    reconnect_ivl_max (0),\n    backlog (100),\n    maxmsgsize (-1),\n    rcvtimeo (-1),\n    sndtimeo (-1),\n    ipv6 (false),\n    immediate (0),\n    filter (false),\n    invert_matching (false),\n    recv_routing_id (false),\n    raw_socket (false),\n    raw_notify (true),\n    tcp_keepalive (-1),\n    tcp_keepalive_cnt (-1),\n    tcp_keepalive_idle (-1),\n    tcp_keepalive_intvl (-1),\n    mechanism (ZMQ_NULL),\n    as_server (0),\n    gss_principal_nt (ZMQ_GSSAPI_NT_HOSTBASED),\n    gss_service_principal_nt (ZMQ_GSSAPI_NT_HOSTBASED),\n    gss_plaintext (false),\n    socket_id (0),\n    conflate (false),\n    handshake_ivl (30000),\n    connected (false),\n    heartbeat_ttl (0),\n    heartbeat_interval (0),\n    heartbeat_timeout (-1),\n    use_fd (-1),\n    zap_enforce_domain (false),\n    loopback_fastpath (false),\n    multicast_loop (true),\n    in_batch_size (8192),\n    out_batch_size (8192),\n    zero_copy (true),\n    router_notify (0),\n    monitor_event_version (1),\n    wss_trust_system (false),\n    hello_msg (),\n    can_send_hello_msg (false),\n    disconnect_msg (),\n    can_recv_disconnect_msg (false),\n    hiccup_msg (),\n    can_recv_hiccup_msg (false),\n    norm_mode (ZMQ_NORM_CC),\n    norm_unicast_nacks (false),\n    norm_buffer_size (2048),\n    norm_segment_size (1400),\n    norm_block_size (16),\n    norm_num_parity (4),\n    norm_num_autoparity (0),\n    norm_push_enable (false),\n    busy_poll (0)\n{\n    memset (curve_public_key, 0, CURVE_KEYSIZE);\n    memset (curve_secret_key, 0, CURVE_KEYSIZE);\n    memset (curve_server_key, 0, CURVE_KEYSIZE);\n#if defined ZMQ_HAVE_VMCI\n    vmci_buffer_size = 0;\n    vmci_buffer_min_size = 0;\n    vmci_buffer_max_size = 0;\n    vmci_connect_timeout = -1;\n#endif\n}\n\nint zmq::options_t::set_curve_key (uint8_t *destination_,\n                                   const void *optval_,\n                                   size_t optvallen_)\n{\n    switch (optvallen_) {\n        case CURVE_KEYSIZE:\n            memcpy (destination_, optval_, optvallen_);\n            mechanism = ZMQ_CURVE;\n            return 0;\n\n        case CURVE_KEYSIZE_Z85 + 1: {\n            const std::string s (static_cast<const char *> (optval_),\n                                 optvallen_);\n\n            if (zmq_z85_decode (destination_, s.c_str ())) {\n                mechanism = ZMQ_CURVE;\n                return 0;\n            }\n            break;\n        }\n\n        case CURVE_KEYSIZE_Z85:\n            char z85_key[CURVE_KEYSIZE_Z85 + 1];\n            memcpy (z85_key, reinterpret_cast<const char *> (optval_),\n                    optvallen_);\n            z85_key[CURVE_KEYSIZE_Z85] = 0;\n            if (zmq_z85_decode (destination_, z85_key)) {\n                mechanism = ZMQ_CURVE;\n                return 0;\n            }\n            break;\n\n        default:\n            break;\n    }\n    return -1;\n}\n\nconst int deciseconds_per_millisecond = 100;\n\nint zmq::options_t::setsockopt (int option_,\n                                const void *optval_,\n                                size_t optvallen_)\n{\n    const bool is_int = (optvallen_ == sizeof (int));\n    int value = 0;\n    if (is_int)\n        memcpy (&value, optval_, sizeof (int));\n#if defined(ZMQ_ACT_MILITANT)\n    bool malformed = true; //  Did caller pass a bad option value?\n#endif\n\n    switch (option_) {\n        case ZMQ_SNDHWM:\n            if (is_int && value >= 0) {\n                sndhwm = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RCVHWM:\n            if (is_int && value >= 0) {\n                rcvhwm = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_AFFINITY:\n            return do_setsockopt (optval_, optvallen_, &affinity);\n\n        case ZMQ_ROUTING_ID:\n            //  Routing id is any binary string from 1 to 255 octets\n            if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX) {\n                routing_id_size = static_cast<unsigned char> (optvallen_);\n                memcpy (routing_id, optval_, routing_id_size);\n                return 0;\n            }\n            break;\n\n        case ZMQ_RATE:\n            if (is_int && value > 0) {\n                rate = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RECOVERY_IVL:\n            if (is_int && value >= 0) {\n                recovery_ivl = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_SNDBUF:\n            if (is_int && value >= -1) {\n                sndbuf = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RCVBUF:\n            if (is_int && value >= -1) {\n                rcvbuf = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TOS:\n            if (is_int && value >= 0) {\n                tos = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_LINGER:\n            if (is_int && value >= -1) {\n                linger.store (value);\n                return 0;\n            }\n            break;\n\n        case ZMQ_CONNECT_TIMEOUT:\n            if (is_int && value >= 0) {\n                connect_timeout = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TCP_MAXRT:\n            if (is_int && value >= 0) {\n                tcp_maxrt = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RECONNECT_STOP:\n            if (is_int) {\n                reconnect_stop = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RECONNECT_IVL:\n            if (is_int && value >= -1) {\n                reconnect_ivl = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RECONNECT_IVL_MAX:\n            if (is_int && value >= 0) {\n                reconnect_ivl_max = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_BACKLOG:\n            if (is_int && value >= 0) {\n                backlog = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_MAXMSGSIZE:\n            return do_setsockopt (optval_, optvallen_, &maxmsgsize);\n\n        case ZMQ_MULTICAST_HOPS:\n            if (is_int && value > 0) {\n                multicast_hops = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_MULTICAST_MAXTPDU:\n            if (is_int && value > 0) {\n                multicast_maxtpdu = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RCVTIMEO:\n            if (is_int && value >= -1) {\n                rcvtimeo = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_SNDTIMEO:\n            if (is_int && value >= -1) {\n                sndtimeo = value;\n                return 0;\n            }\n            break;\n\n        /*  Deprecated in favor of ZMQ_IPV6  */\n        case ZMQ_IPV4ONLY: {\n            bool value;\n            const int rc =\n              do_setsockopt_int_as_bool_strict (optval_, optvallen_, &value);\n            if (rc == 0)\n                ipv6 = !value;\n            return rc;\n        }\n\n        /*  To replace the somewhat surprising IPV4ONLY */\n        case ZMQ_IPV6:\n            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,\n                                                     &ipv6);\n\n        case ZMQ_SOCKS_PROXY:\n            return do_setsockopt_string_allow_empty_strict (\n              optval_, optvallen_, &socks_proxy_address, SIZE_MAX);\n\n        case ZMQ_SOCKS_USERNAME:\n            /* Make empty string or NULL equivalent. */\n            if (optval_ == NULL || optvallen_ == 0) {\n                socks_proxy_username.clear ();\n                return 0;\n            } else {\n                return do_setsockopt_string_allow_empty_strict (\n                  optval_, optvallen_, &socks_proxy_username, 255);\n            }\n        case ZMQ_SOCKS_PASSWORD:\n            /* Make empty string or NULL equivalent. */\n            if (optval_ == NULL || optvallen_ == 0) {\n                socks_proxy_password.clear ();\n                return 0;\n            } else {\n                return do_setsockopt_string_allow_empty_strict (\n                  optval_, optvallen_, &socks_proxy_password, 255);\n            }\n        case ZMQ_TCP_KEEPALIVE:\n            if (is_int && (value == -1 || value == 0 || value == 1)) {\n                tcp_keepalive = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TCP_KEEPALIVE_CNT:\n            if (is_int && (value == -1 || value >= 0)) {\n                tcp_keepalive_cnt = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TCP_KEEPALIVE_IDLE:\n            if (is_int && (value == -1 || value >= 0)) {\n                tcp_keepalive_idle = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TCP_KEEPALIVE_INTVL:\n            if (is_int && (value == -1 || value >= 0)) {\n                tcp_keepalive_intvl = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_IMMEDIATE:\n            // TODO why is immediate not bool (and called non_immediate, as its meaning appears to be reversed)\n            if (is_int && (value == 0 || value == 1)) {\n                immediate = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TCP_ACCEPT_FILTER: {\n            std::string filter_str;\n            int rc = do_setsockopt_string_allow_empty_strict (\n              optval_, optvallen_, &filter_str, UCHAR_MAX);\n            if (rc == 0) {\n                if (filter_str.empty ()) {\n                    tcp_accept_filters.clear ();\n                } else {\n                    tcp_address_mask_t mask;\n                    rc = mask.resolve (filter_str.c_str (), ipv6);\n                    if (rc == 0) {\n                        tcp_accept_filters.push_back (mask);\n                    }\n                }\n            }\n            return rc;\n        }\n\n#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\n        case ZMQ_IPC_FILTER_UID:\n            return do_setsockopt_set (optval_, optvallen_,\n                                      &ipc_uid_accept_filters);\n\n\n        case ZMQ_IPC_FILTER_GID:\n            return do_setsockopt_set (optval_, optvallen_,\n                                      &ipc_gid_accept_filters);\n#endif\n\n#if defined ZMQ_HAVE_SO_PEERCRED\n        case ZMQ_IPC_FILTER_PID:\n            return do_setsockopt_set (optval_, optvallen_,\n                                      &ipc_pid_accept_filters);\n#endif\n\n        case ZMQ_PLAIN_SERVER:\n            if (is_int && (value == 0 || value == 1)) {\n                as_server = value;\n                mechanism = value ? ZMQ_PLAIN : ZMQ_NULL;\n                return 0;\n            }\n            break;\n\n        case ZMQ_PLAIN_USERNAME:\n            if (optvallen_ == 0 && optval_ == NULL) {\n                mechanism = ZMQ_NULL;\n                return 0;\n            } else if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX\n                       && optval_ != NULL) {\n                plain_username.assign (static_cast<const char *> (optval_),\n                                       optvallen_);\n                as_server = 0;\n                mechanism = ZMQ_PLAIN;\n                return 0;\n            }\n            break;\n\n        case ZMQ_PLAIN_PASSWORD:\n            if (optvallen_ == 0 && optval_ == NULL) {\n                mechanism = ZMQ_NULL;\n                return 0;\n            } else if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX\n                       && optval_ != NULL) {\n                plain_password.assign (static_cast<const char *> (optval_),\n                                       optvallen_);\n                as_server = 0;\n                mechanism = ZMQ_PLAIN;\n                return 0;\n            }\n            break;\n\n        case ZMQ_ZAP_DOMAIN:\n            return do_setsockopt_string_allow_empty_relaxed (\n              optval_, optvallen_, &zap_domain, UCHAR_MAX);\n\n            //  If curve encryption isn't built, these options provoke EINVAL\n#ifdef ZMQ_HAVE_CURVE\n        case ZMQ_CURVE_SERVER:\n            if (is_int && (value == 0 || value == 1)) {\n                as_server = value;\n                mechanism = value ? ZMQ_CURVE : ZMQ_NULL;\n                return 0;\n            }\n            break;\n\n        case ZMQ_CURVE_PUBLICKEY:\n            if (0 == set_curve_key (curve_public_key, optval_, optvallen_)) {\n                return 0;\n            }\n            break;\n\n        case ZMQ_CURVE_SECRETKEY:\n            if (0 == set_curve_key (curve_secret_key, optval_, optvallen_)) {\n                return 0;\n            }\n            break;\n\n        case ZMQ_CURVE_SERVERKEY:\n            if (0 == set_curve_key (curve_server_key, optval_, optvallen_)) {\n                as_server = 0;\n                return 0;\n            }\n            break;\n#endif\n\n        case ZMQ_CONFLATE:\n            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,\n                                                     &conflate);\n\n            //  If libgssapi isn't installed, these options provoke EINVAL\n#ifdef HAVE_LIBGSSAPI_KRB5\n        case ZMQ_GSSAPI_SERVER:\n            if (is_int && (value == 0 || value == 1)) {\n                as_server = value;\n                mechanism = ZMQ_GSSAPI;\n                return 0;\n            }\n            break;\n\n        case ZMQ_GSSAPI_PRINCIPAL:\n            if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX && optval_ != NULL) {\n                gss_principal.assign ((const char *) optval_, optvallen_);\n                mechanism = ZMQ_GSSAPI;\n                return 0;\n            }\n            break;\n\n        case ZMQ_GSSAPI_SERVICE_PRINCIPAL:\n            if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX && optval_ != NULL) {\n                gss_service_principal.assign ((const char *) optval_,\n                                              optvallen_);\n                mechanism = ZMQ_GSSAPI;\n                as_server = 0;\n                return 0;\n            }\n            break;\n\n        case ZMQ_GSSAPI_PLAINTEXT:\n            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,\n                                                     &gss_plaintext);\n\n        case ZMQ_GSSAPI_PRINCIPAL_NAMETYPE:\n            if (is_int\n                && (value == ZMQ_GSSAPI_NT_HOSTBASED\n                    || value == ZMQ_GSSAPI_NT_USER_NAME\n                    || value == ZMQ_GSSAPI_NT_KRB5_PRINCIPAL)) {\n                gss_principal_nt = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE:\n            if (is_int\n                && (value == ZMQ_GSSAPI_NT_HOSTBASED\n                    || value == ZMQ_GSSAPI_NT_USER_NAME\n                    || value == ZMQ_GSSAPI_NT_KRB5_PRINCIPAL)) {\n                gss_service_principal_nt = value;\n                return 0;\n            }\n            break;\n#endif\n\n        case ZMQ_HANDSHAKE_IVL:\n            if (is_int && value >= 0) {\n                handshake_ivl = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_INVERT_MATCHING:\n            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,\n                                                      &invert_matching);\n\n        case ZMQ_HEARTBEAT_IVL:\n            if (is_int && value >= 0) {\n                heartbeat_interval = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_HEARTBEAT_TTL:\n            // Convert this to deciseconds from milliseconds\n            value = value / deciseconds_per_millisecond;\n            if (is_int && value >= 0 && value <= UINT16_MAX) {\n                heartbeat_ttl = static_cast<uint16_t> (value);\n                return 0;\n            }\n            break;\n\n        case ZMQ_HEARTBEAT_TIMEOUT:\n            if (is_int && value >= 0) {\n                heartbeat_timeout = value;\n                return 0;\n            }\n            break;\n\n#ifdef ZMQ_HAVE_VMCI\n        case ZMQ_VMCI_BUFFER_SIZE:\n            return do_setsockopt (optval_, optvallen_, &vmci_buffer_size);\n\n        case ZMQ_VMCI_BUFFER_MIN_SIZE:\n            return do_setsockopt (optval_, optvallen_, &vmci_buffer_min_size);\n\n        case ZMQ_VMCI_BUFFER_MAX_SIZE:\n            return do_setsockopt (optval_, optvallen_, &vmci_buffer_max_size);\n\n        case ZMQ_VMCI_CONNECT_TIMEOUT:\n            return do_setsockopt (optval_, optvallen_, &vmci_connect_timeout);\n#endif\n\n        case ZMQ_USE_FD:\n            if (is_int && value >= -1) {\n                use_fd = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_BINDTODEVICE:\n            return do_setsockopt_string_allow_empty_strict (\n              optval_, optvallen_, &bound_device, BINDDEVSIZ);\n\n        case ZMQ_ZAP_ENFORCE_DOMAIN:\n            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,\n                                                      &zap_enforce_domain);\n\n        case ZMQ_LOOPBACK_FASTPATH:\n            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,\n                                                      &loopback_fastpath);\n\n        case ZMQ_METADATA:\n            if (optvallen_ > 0 && !is_int) {\n                const std::string s (static_cast<const char *> (optval_),\n                                     optvallen_);\n                const size_t pos = s.find (':');\n                if (pos != std::string::npos && pos != 0\n                    && pos != s.length () - 1) {\n                    const std::string key = s.substr (0, pos);\n                    if (key.compare (0, 2, \"X-\") == 0\n                        && key.length () <= UCHAR_MAX) {\n                        std::string val = s.substr (pos + 1, s.length ());\n                        app_metadata.insert (\n                          std::pair<std::string, std::string> (key, val));\n                        return 0;\n                    }\n                }\n            }\n            errno = EINVAL;\n            return -1;\n\n        case ZMQ_MULTICAST_LOOP:\n            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,\n                                                      &multicast_loop);\n\n#ifdef ZMQ_BUILD_DRAFT_API\n        case ZMQ_IN_BATCH_SIZE:\n            if (is_int && value > 0) {\n                in_batch_size = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_OUT_BATCH_SIZE:\n            if (is_int && value > 0) {\n                out_batch_size = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_BUSY_POLL:\n            if (is_int) {\n                busy_poll = value;\n                return 0;\n            }\n            break;\n#ifdef ZMQ_HAVE_WSS\n        case ZMQ_WSS_KEY_PEM:\n            // TODO: check if valid certificate\n            wss_key_pem = std::string ((char *) optval_, optvallen_);\n            return 0;\n        case ZMQ_WSS_CERT_PEM:\n            // TODO: check if valid certificate\n            wss_cert_pem = std::string ((char *) optval_, optvallen_);\n            return 0;\n        case ZMQ_WSS_TRUST_PEM:\n            // TODO: check if valid certificate\n            wss_trust_pem = std::string ((char *) optval_, optvallen_);\n            return 0;\n        case ZMQ_WSS_HOSTNAME:\n            wss_hostname = std::string ((char *) optval_, optvallen_);\n            return 0;\n        case ZMQ_WSS_TRUST_SYSTEM:\n            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,\n                                                     &wss_trust_system);\n#endif\n\n#ifdef ZMQ_HAVE_NORM\n        case ZMQ_NORM_MODE:\n            if (is_int && value >= 0 && value <= 4) {\n                norm_mode = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_UNICAST_NACK:\n            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,\n                                                     &norm_unicast_nacks);\n\n        case ZMQ_NORM_BUFFER_SIZE:\n            if (is_int && value > 0) {\n                norm_buffer_size = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_SEGMENT_SIZE:\n            if (is_int && value > 0) {\n                norm_segment_size = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_BLOCK_SIZE:\n            if (is_int && value > 0 && value <= 255) {\n                norm_block_size = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_NUM_PARITY:\n            if (is_int && value >= 0 && value < 255) {\n                norm_num_parity = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_NUM_AUTOPARITY:\n            if (is_int && value >= 0 && value < 255) {\n                norm_num_autoparity = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_PUSH:\n            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,\n                                                     &norm_push_enable);\n#endif //ZMQ_HAVE_NORM\n\n        case ZMQ_HELLO_MSG:\n            if (optvallen_ > 0) {\n                unsigned char *bytes = (unsigned char *) optval_;\n                hello_msg =\n                  std::vector<unsigned char> (bytes, bytes + optvallen_);\n            } else {\n                hello_msg = std::vector<unsigned char> ();\n            }\n\n            return 0;\n\n        case ZMQ_DISCONNECT_MSG:\n            if (optvallen_ > 0) {\n                unsigned char *bytes = (unsigned char *) optval_;\n                disconnect_msg =\n                  std::vector<unsigned char> (bytes, bytes + optvallen_);\n            } else {\n                disconnect_msg = std::vector<unsigned char> ();\n            }\n\n            return 0;\n\n        case ZMQ_PRIORITY:\n            if (is_int && value >= 0) {\n                priority = value;\n                return 0;\n            }\n            break;\n\n        case ZMQ_HICCUP_MSG:\n            if (optvallen_ > 0) {\n                unsigned char *bytes = (unsigned char *) optval_;\n                hiccup_msg =\n                  std::vector<unsigned char> (bytes, bytes + optvallen_);\n            } else {\n                hiccup_msg = std::vector<unsigned char> ();\n            }\n\n            return 0;\n\n\n#endif\n\n        default:\n#if defined(ZMQ_ACT_MILITANT)\n            //  There are valid scenarios for probing with unknown socket option\n            //  values, e.g. to check if security is enabled or not. This will not\n            //  provoke a militant assert. However, passing bad values to a valid\n            //  socket option will, if ZMQ_ACT_MILITANT is defined.\n            malformed = false;\n#endif\n            break;\n    }\n\n        // TODO mechanism should either be set explicitly, or determined when\n        // connecting. currently, it depends on the order of setsockopt calls\n        // if there is some inconsistency, which is confusing. in addition,\n        // the assumed or set mechanism should be queryable (as a socket option)\n\n#if defined(ZMQ_ACT_MILITANT)\n    //  There is no valid use case for passing an error back to the application\n    //  when it sent malformed arguments to a socket option. Use ./configure\n    //  --with-militant to enable this checking.\n    if (malformed)\n        zmq_assert (false);\n#endif\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::options_t::getsockopt (int option_,\n                                void *optval_,\n                                size_t *optvallen_) const\n{\n    const bool is_int = (*optvallen_ == sizeof (int));\n    int *value = static_cast<int *> (optval_);\n#if defined(ZMQ_ACT_MILITANT)\n    bool malformed = true; //  Did caller pass a bad option value?\n#endif\n\n    switch (option_) {\n        case ZMQ_SNDHWM:\n            if (is_int) {\n                *value = sndhwm;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RCVHWM:\n            if (is_int) {\n                *value = rcvhwm;\n                return 0;\n            }\n            break;\n\n        case ZMQ_AFFINITY:\n            if (*optvallen_ == sizeof (uint64_t)) {\n                *(static_cast<uint64_t *> (optval_)) = affinity;\n                return 0;\n            }\n            break;\n\n        case ZMQ_ROUTING_ID:\n            return do_getsockopt (optval_, optvallen_, routing_id,\n                                  routing_id_size);\n\n        case ZMQ_RATE:\n            if (is_int) {\n                *value = rate;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RECOVERY_IVL:\n            if (is_int) {\n                *value = recovery_ivl;\n                return 0;\n            }\n            break;\n\n        case ZMQ_SNDBUF:\n            if (is_int) {\n                *value = sndbuf;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RCVBUF:\n            if (is_int) {\n                *value = rcvbuf;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TOS:\n            if (is_int) {\n                *value = tos;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TYPE:\n            if (is_int) {\n                *value = type;\n                return 0;\n            }\n            break;\n\n        case ZMQ_LINGER:\n            if (is_int) {\n                *value = linger.load ();\n                return 0;\n            }\n            break;\n\n        case ZMQ_CONNECT_TIMEOUT:\n            if (is_int) {\n                *value = connect_timeout;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TCP_MAXRT:\n            if (is_int) {\n                *value = tcp_maxrt;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RECONNECT_STOP:\n            if (is_int) {\n                *value = reconnect_stop;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RECONNECT_IVL:\n            if (is_int) {\n                *value = reconnect_ivl;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RECONNECT_IVL_MAX:\n            if (is_int) {\n                *value = reconnect_ivl_max;\n                return 0;\n            }\n            break;\n\n        case ZMQ_BACKLOG:\n            if (is_int) {\n                *value = backlog;\n                return 0;\n            }\n            break;\n\n        case ZMQ_MAXMSGSIZE:\n            if (*optvallen_ == sizeof (int64_t)) {\n                *(static_cast<int64_t *> (optval_)) = maxmsgsize;\n                *optvallen_ = sizeof (int64_t);\n                return 0;\n            }\n            break;\n\n        case ZMQ_MULTICAST_HOPS:\n            if (is_int) {\n                *value = multicast_hops;\n                return 0;\n            }\n            break;\n\n        case ZMQ_MULTICAST_MAXTPDU:\n            if (is_int) {\n                *value = multicast_maxtpdu;\n                return 0;\n            }\n            break;\n\n        case ZMQ_RCVTIMEO:\n            if (is_int) {\n                *value = rcvtimeo;\n                return 0;\n            }\n            break;\n\n        case ZMQ_SNDTIMEO:\n            if (is_int) {\n                *value = sndtimeo;\n                return 0;\n            }\n            break;\n\n        case ZMQ_IPV4ONLY:\n            if (is_int) {\n                *value = 1 - ipv6;\n                return 0;\n            }\n            break;\n\n        case ZMQ_IPV6:\n            if (is_int) {\n                *value = ipv6;\n                return 0;\n            }\n            break;\n\n        case ZMQ_IMMEDIATE:\n            if (is_int) {\n                *value = immediate;\n                return 0;\n            }\n            break;\n\n        case ZMQ_SOCKS_PROXY:\n            return do_getsockopt (optval_, optvallen_, socks_proxy_address);\n\n        case ZMQ_SOCKS_USERNAME:\n            return do_getsockopt (optval_, optvallen_, socks_proxy_username);\n\n        case ZMQ_SOCKS_PASSWORD:\n            return do_getsockopt (optval_, optvallen_, socks_proxy_password);\n\n        case ZMQ_TCP_KEEPALIVE:\n            if (is_int) {\n                *value = tcp_keepalive;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TCP_KEEPALIVE_CNT:\n            if (is_int) {\n                *value = tcp_keepalive_cnt;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TCP_KEEPALIVE_IDLE:\n            if (is_int) {\n                *value = tcp_keepalive_idle;\n                return 0;\n            }\n            break;\n\n        case ZMQ_TCP_KEEPALIVE_INTVL:\n            if (is_int) {\n                *value = tcp_keepalive_intvl;\n                return 0;\n            }\n            break;\n\n        case ZMQ_MECHANISM:\n            if (is_int) {\n                *value = mechanism;\n                return 0;\n            }\n            break;\n\n        case ZMQ_PLAIN_SERVER:\n            if (is_int) {\n                *value = as_server && mechanism == ZMQ_PLAIN;\n                return 0;\n            }\n            break;\n\n        case ZMQ_PLAIN_USERNAME:\n            return do_getsockopt (optval_, optvallen_, plain_username);\n\n        case ZMQ_PLAIN_PASSWORD:\n            return do_getsockopt (optval_, optvallen_, plain_password);\n\n        case ZMQ_ZAP_DOMAIN:\n            return do_getsockopt (optval_, optvallen_, zap_domain);\n\n            //  If curve encryption isn't built, these options provoke EINVAL\n#ifdef ZMQ_HAVE_CURVE\n        case ZMQ_CURVE_SERVER:\n            if (is_int) {\n                *value = as_server && mechanism == ZMQ_CURVE;\n                return 0;\n            }\n            break;\n\n        case ZMQ_CURVE_PUBLICKEY:\n            return do_getsockopt_curve_key (optval_, optvallen_,\n                                            curve_public_key);\n\n        case ZMQ_CURVE_SECRETKEY:\n            return do_getsockopt_curve_key (optval_, optvallen_,\n                                            curve_secret_key);\n\n        case ZMQ_CURVE_SERVERKEY:\n            return do_getsockopt_curve_key (optval_, optvallen_,\n                                            curve_server_key);\n#endif\n\n        case ZMQ_CONFLATE:\n            if (is_int) {\n                *value = conflate;\n                return 0;\n            }\n            break;\n\n            //  If libgssapi isn't installed, these options provoke EINVAL\n#ifdef HAVE_LIBGSSAPI_KRB5\n        case ZMQ_GSSAPI_SERVER:\n            if (is_int) {\n                *value = as_server && mechanism == ZMQ_GSSAPI;\n                return 0;\n            }\n            break;\n\n        case ZMQ_GSSAPI_PRINCIPAL:\n            return do_getsockopt (optval_, optvallen_, gss_principal);\n\n        case ZMQ_GSSAPI_SERVICE_PRINCIPAL:\n            return do_getsockopt (optval_, optvallen_, gss_service_principal);\n\n        case ZMQ_GSSAPI_PLAINTEXT:\n            if (is_int) {\n                *value = gss_plaintext;\n                return 0;\n            }\n            break;\n\n        case ZMQ_GSSAPI_PRINCIPAL_NAMETYPE:\n            if (is_int) {\n                *value = gss_principal_nt;\n                return 0;\n            }\n            break;\n        case ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE:\n            if (is_int) {\n                *value = gss_service_principal_nt;\n                return 0;\n            }\n            break;\n#endif\n\n        case ZMQ_HANDSHAKE_IVL:\n            if (is_int) {\n                *value = handshake_ivl;\n                return 0;\n            }\n            break;\n\n        case ZMQ_INVERT_MATCHING:\n            if (is_int) {\n                *value = invert_matching;\n                return 0;\n            }\n            break;\n\n        case ZMQ_HEARTBEAT_IVL:\n            if (is_int) {\n                *value = heartbeat_interval;\n                return 0;\n            }\n            break;\n\n        case ZMQ_HEARTBEAT_TTL:\n            if (is_int) {\n                // Convert the internal deciseconds value to milliseconds\n                *value = heartbeat_ttl * 100;\n                return 0;\n            }\n            break;\n\n        case ZMQ_HEARTBEAT_TIMEOUT:\n            if (is_int) {\n                *value = heartbeat_timeout;\n                return 0;\n            }\n            break;\n\n        case ZMQ_USE_FD:\n            if (is_int) {\n                *value = use_fd;\n                return 0;\n            }\n            break;\n\n        case ZMQ_BINDTODEVICE:\n            return do_getsockopt (optval_, optvallen_, bound_device);\n\n        case ZMQ_ZAP_ENFORCE_DOMAIN:\n            if (is_int) {\n                *value = zap_enforce_domain;\n                return 0;\n            }\n            break;\n\n        case ZMQ_LOOPBACK_FASTPATH:\n            if (is_int) {\n                *value = loopback_fastpath;\n                return 0;\n            }\n            break;\n\n        case ZMQ_MULTICAST_LOOP:\n            if (is_int) {\n                *value = multicast_loop;\n                return 0;\n            }\n            break;\n\n#ifdef ZMQ_BUILD_DRAFT_API\n        case ZMQ_ROUTER_NOTIFY:\n            if (is_int) {\n                *value = router_notify;\n                return 0;\n            }\n            break;\n\n        case ZMQ_IN_BATCH_SIZE:\n            if (is_int) {\n                *value = in_batch_size;\n                return 0;\n            }\n            break;\n\n        case ZMQ_OUT_BATCH_SIZE:\n            if (is_int) {\n                *value = out_batch_size;\n                return 0;\n            }\n            break;\n\n        case ZMQ_PRIORITY:\n            if (is_int) {\n                *value = priority;\n                return 0;\n            }\n            break;\n\n        case ZMQ_BUSY_POLL:\n            if (is_int) {\n                *value = busy_poll;\n            }\n            break;\n\n#ifdef ZMQ_HAVE_NORM\n        case ZMQ_NORM_MODE:\n            if (is_int) {\n                *value = norm_mode;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_UNICAST_NACK:\n            if (is_int) {\n                *value = norm_unicast_nacks;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_BUFFER_SIZE:\n            if (is_int) {\n                *value = norm_buffer_size;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_SEGMENT_SIZE:\n            if (is_int) {\n                *value = norm_segment_size;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_BLOCK_SIZE:\n            if (is_int) {\n                *value = norm_block_size;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_NUM_PARITY:\n            if (is_int) {\n                *value = norm_num_parity;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_NUM_AUTOPARITY:\n            if (is_int) {\n                *value = norm_num_autoparity;\n                return 0;\n            }\n            break;\n\n        case ZMQ_NORM_PUSH:\n            if (is_int) {\n                *value = norm_push_enable;\n                return 0;\n            }\n            break;\n#endif //ZMQ_HAVE_NORM\n\n#endif\n\n\n        default:\n#if defined(ZMQ_ACT_MILITANT)\n            malformed = false;\n#endif\n            break;\n    }\n#if defined(ZMQ_ACT_MILITANT)\n    if (malformed)\n        zmq_assert (false);\n#endif\n    errno = EINVAL;\n    return -1;\n}\n"
  },
  {
    "path": "src/options.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_OPTIONS_HPP_INCLUDED__\n#define __ZMQ_OPTIONS_HPP_INCLUDED__\n\n#include <string>\n#include <vector>\n#include <map>\n\n#include \"atomic_ptr.hpp\"\n#include \"stddef.h\"\n#include \"stdint.hpp\"\n#include \"tcp_address.hpp\"\n\n#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\n#include <set>\n#include <sys/types.h>\n#endif\n#ifdef ZMQ_HAVE_LOCAL_PEERCRED\n#include <sys/ucred.h>\n#endif\n\n#if __cplusplus >= 201103L || (defined _MSC_VER && _MSC_VER >= 1700)\n#include <type_traits>\n#endif\n\n//  Normal base 256 key is 32 bytes\n#define CURVE_KEYSIZE 32\n//  Key encoded using Z85 is 40 bytes\n#define CURVE_KEYSIZE_Z85 40\n\nnamespace zmq\n{\nstruct options_t\n{\n    options_t ();\n\n    int set_curve_key (uint8_t *destination_,\n                       const void *optval_,\n                       size_t optvallen_);\n\n    int setsockopt (int option_, const void *optval_, size_t optvallen_);\n    int getsockopt (int option_, void *optval_, size_t *optvallen_) const;\n\n    //  High-water marks for message pipes.\n    int sndhwm;\n    int rcvhwm;\n\n    //  I/O thread affinity.\n    uint64_t affinity;\n\n    //  Socket routing id.\n    unsigned char routing_id_size;\n    unsigned char routing_id[256];\n\n    //  Maximum transfer rate [kb/s]. Default 100kb/s.\n    int rate;\n\n    //  Reliability time interval [ms]. Default 10 seconds.\n    int recovery_ivl;\n\n    // Sets the time-to-live field in every multicast packet sent.\n    int multicast_hops;\n\n    // Sets the maximum transport data unit size in every multicast\n    // packet sent.\n    int multicast_maxtpdu;\n\n    // SO_SNDBUF and SO_RCVBUF to be passed to underlying transport sockets.\n    int sndbuf;\n    int rcvbuf;\n\n    // Type of service (containing DSCP and ECN socket options)\n    int tos;\n\n    // Protocol-defined priority\n    int priority;\n\n    //  Socket type.\n    int8_t type;\n\n    //  Linger time, in milliseconds.\n    atomic_value_t linger;\n\n    //  Maximum interval in milliseconds beyond which userspace will\n    //  timeout connect().\n    //  Default 0 (unused)\n    int connect_timeout;\n\n    //  Maximum interval in milliseconds beyond which TCP will timeout\n    //  retransmitted packets.\n    //  Default 0 (unused)\n    int tcp_maxrt;\n\n    //  Disable reconnect under certain conditions\n    //  Default 0\n    int reconnect_stop;\n\n    //  Minimum interval between attempts to reconnect, in milliseconds.\n    //  Default 100ms\n    int reconnect_ivl;\n\n    //  Maximum interval between attempts to reconnect, in milliseconds.\n    //  Default 0ms (meaning maximum interval is disabled)\n    int reconnect_ivl_max;\n\n    //  Maximum backlog for pending connections.\n    int backlog;\n\n    //  Maximal size of message to handle.\n    int64_t maxmsgsize;\n\n    // The timeout for send/recv operations for this socket, in milliseconds.\n    int rcvtimeo;\n    int sndtimeo;\n\n    //  If true, IPv6 is enabled (as well as IPv4)\n    bool ipv6;\n\n    //  If 1, connecting pipes are not attached immediately, meaning a send()\n    //  on a socket with only connecting pipes would block\n    int immediate;\n\n    //  If 1, (X)SUB socket should filter the messages. If 0, it should not.\n    bool filter;\n\n    //  If true, the subscription matching on (X)PUB and (X)SUB sockets\n    //  is reversed. Messages are sent to and received by non-matching\n    //  sockets.\n    bool invert_matching;\n\n    //  If true, the routing id message is forwarded to the socket.\n    bool recv_routing_id;\n\n    // if true, router socket accepts non-zmq tcp connections\n    bool raw_socket;\n    bool raw_notify; //  Provide connect notifications\n\n    //  Address of SOCKS proxy\n    std::string socks_proxy_address;\n\n    // Credentials for SOCKS proxy.\n    // Connection method will be basic auth if username\n    // is not empty, no auth otherwise.\n    std::string socks_proxy_username;\n    std::string socks_proxy_password;\n\n    //  TCP keep-alive settings.\n    //  Defaults to -1 = do not change socket options\n    int tcp_keepalive;\n    int tcp_keepalive_cnt;\n    int tcp_keepalive_idle;\n    int tcp_keepalive_intvl;\n\n    // TCP accept() filters\n    typedef std::vector<tcp_address_mask_t> tcp_accept_filters_t;\n    tcp_accept_filters_t tcp_accept_filters;\n\n    // IPC accept() filters\n#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\n    typedef std::set<uid_t> ipc_uid_accept_filters_t;\n    ipc_uid_accept_filters_t ipc_uid_accept_filters;\n    typedef std::set<gid_t> ipc_gid_accept_filters_t;\n    ipc_gid_accept_filters_t ipc_gid_accept_filters;\n#endif\n#if defined ZMQ_HAVE_SO_PEERCRED\n    typedef std::set<pid_t> ipc_pid_accept_filters_t;\n    ipc_pid_accept_filters_t ipc_pid_accept_filters;\n#endif\n\n    //  Security mechanism for all connections on this socket\n    int mechanism;\n\n    //  If peer is acting as server for PLAIN or CURVE mechanisms\n    int as_server;\n\n    //  ZAP authentication domain\n    std::string zap_domain;\n\n    //  Security credentials for PLAIN mechanism\n    std::string plain_username;\n    std::string plain_password;\n\n    //  Security credentials for CURVE mechanism\n    uint8_t curve_public_key[CURVE_KEYSIZE];\n    uint8_t curve_secret_key[CURVE_KEYSIZE];\n    uint8_t curve_server_key[CURVE_KEYSIZE];\n\n    //  Principals for GSSAPI mechanism\n    std::string gss_principal;\n    std::string gss_service_principal;\n\n    //  Name types GSSAPI principals\n    int gss_principal_nt;\n    int gss_service_principal_nt;\n\n    //  If true, gss encryption will be disabled\n    bool gss_plaintext;\n\n    //  ID of the socket.\n    int socket_id;\n\n    //  If true, socket conflates outgoing/incoming messages.\n    //  Applicable to dealer, push/pull, pub/sub socket types.\n    //  Cannot receive multi-part messages.\n    //  Ignores hwm\n    bool conflate;\n\n    //  If connection handshake is not done after this many milliseconds,\n    //  close socket.  Default is 30 secs.  0 means no handshake timeout.\n    int handshake_ivl;\n\n    bool connected;\n    //  If remote peer receives a PING message and doesn't receive another\n    //  message within the ttl value, it should close the connection\n    //  (measured in tenths of a second)\n    uint16_t heartbeat_ttl;\n    //  Time in milliseconds between sending heartbeat PING messages.\n    int heartbeat_interval;\n    //  Time in milliseconds to wait for a PING response before disconnecting\n    int heartbeat_timeout;\n\n#if defined ZMQ_HAVE_VMCI\n    uint64_t vmci_buffer_size;\n    uint64_t vmci_buffer_min_size;\n    uint64_t vmci_buffer_max_size;\n    int vmci_connect_timeout;\n#endif\n\n    //  When creating a new ZMQ socket, if this option is set the value\n    //  will be used as the File Descriptor instead of allocating a new\n    //  one via the socket () system call.\n    int use_fd;\n\n    // Device to bind the underlying socket to, eg. VRF or interface\n    std::string bound_device;\n\n    //  Enforce a non-empty ZAP domain requirement for PLAIN auth\n    bool zap_enforce_domain;\n\n    // Use of loopback fastpath.\n    bool loopback_fastpath;\n\n    //  Loop sent multicast packets to local sockets\n    bool multicast_loop;\n\n    //  Maximal batching size for engines with receiving functionality.\n    //  So, if there are 10 messages that fit into the batch size, all of\n    //  them may be read by a single 'recv' system call, thus avoiding\n    //  unnecessary network stack traversals.\n    int in_batch_size;\n    //  Maximal batching size for engines with sending functionality.\n    //  So, if there are 10 messages that fit into the batch size, all of\n    //  them may be written by a single 'send' system call, thus avoiding\n    //  unnecessary network stack traversals.\n    int out_batch_size;\n\n    // Use zero copy strategy for storing message content when decoding.\n    bool zero_copy;\n\n    // Router socket ZMQ_NOTIFY_CONNECT/ZMQ_NOTIFY_DISCONNECT notifications\n    int router_notify;\n\n    // Application metadata\n    std::map<std::string, std::string> app_metadata;\n\n    // Version of monitor events to emit\n    int monitor_event_version;\n\n    //  WSS Keys\n    std::string wss_key_pem;\n    std::string wss_cert_pem;\n    std::string wss_trust_pem;\n    std::string wss_hostname;\n    bool wss_trust_system;\n\n    //  Hello msg\n    std::vector<unsigned char> hello_msg;\n    bool can_send_hello_msg;\n\n    //  Disconnect msg\n    std::vector<unsigned char> disconnect_msg;\n    bool can_recv_disconnect_msg;\n\n    //  Hiccup msg\n    std::vector<unsigned char> hiccup_msg;\n    bool can_recv_hiccup_msg;\n\n    // NORM Options\n    int norm_mode;\n    bool norm_unicast_nacks;\n    int norm_buffer_size;\n    int norm_segment_size;\n    int norm_block_size;\n    int norm_num_parity;\n    int norm_num_autoparity;\n    bool norm_push_enable;\n\n    //  This option removes several delays caused by scheduling, interrupts and context switching.\n    int busy_poll;\n};\n\ninline bool get_effective_conflate_option (const options_t &options)\n{\n    // conflate is only effective for some socket types\n    return options.conflate\n           && (options.type == ZMQ_DEALER || options.type == ZMQ_PULL\n               || options.type == ZMQ_PUSH || options.type == ZMQ_PUB\n               || options.type == ZMQ_SUB);\n}\n\nint do_getsockopt (void *optval_,\n                   size_t *optvallen_,\n                   const void *value_,\n                   size_t value_len_);\n\ntemplate <typename T>\nint do_getsockopt (void *const optval_, size_t *const optvallen_, T value_)\n{\n#if __cplusplus >= 201103L && (!defined(__GNUC__) || __GNUC__ > 5)\n    static_assert (std::is_trivially_copyable<T>::value,\n                   \"invalid use of do_getsockopt\");\n#endif\n    return do_getsockopt (optval_, optvallen_, &value_, sizeof (T));\n}\n\nint do_getsockopt (void *optval_,\n                   size_t *optvallen_,\n                   const std::string &value_);\n\nint do_setsockopt_int_as_bool_strict (const void *optval_,\n                                      size_t optvallen_,\n                                      bool *out_value_);\n\nint do_setsockopt_int_as_bool_relaxed (const void *optval_,\n                                       size_t optvallen_,\n                                       bool *out_value_);\n}\n\n#endif\n"
  },
  {
    "path": "src/own.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"own.hpp\"\n#include \"err.hpp\"\n#include \"io_thread.hpp\"\n\nzmq::own_t::own_t (class ctx_t *parent_, uint32_t tid_) :\n    object_t (parent_, tid_),\n    _terminating (false),\n    _sent_seqnum (0),\n    _processed_seqnum (0),\n    _owner (NULL),\n    _term_acks (0)\n{\n}\n\nzmq::own_t::own_t (io_thread_t *io_thread_, const options_t &options_) :\n    object_t (io_thread_),\n    options (options_),\n    _terminating (false),\n    _sent_seqnum (0),\n    _processed_seqnum (0),\n    _owner (NULL),\n    _term_acks (0)\n{\n}\n\nzmq::own_t::~own_t ()\n{\n}\n\nvoid zmq::own_t::set_owner (own_t *owner_)\n{\n    zmq_assert (!_owner);\n    _owner = owner_;\n}\n\nvoid zmq::own_t::inc_seqnum ()\n{\n    //  This function may be called from a different thread!\n    _sent_seqnum.add (1);\n}\n\nvoid zmq::own_t::process_seqnum ()\n{\n    //  Catch up with counter of processed commands.\n    _processed_seqnum++;\n\n    //  We may have caught up and still have pending terms acks.\n    check_term_acks ();\n}\n\nvoid zmq::own_t::launch_child (own_t *object_)\n{\n    //  Specify the owner of the object.\n    object_->set_owner (this);\n\n    //  Plug the object into the I/O thread.\n    send_plug (object_);\n\n    //  Take ownership of the object.\n    send_own (this, object_);\n}\n\nvoid zmq::own_t::term_child (own_t *object_)\n{\n    process_term_req (object_);\n}\n\nvoid zmq::own_t::process_term_req (own_t *object_)\n{\n    //  When shutting down we can ignore termination requests from owned\n    //  objects. The termination request was already sent to the object.\n    if (_terminating)\n        return;\n\n    //  If not found, we assume that termination request was already sent to\n    //  the object so we can safely ignore the request.\n    if (0 == _owned.erase (object_))\n        return;\n\n    //  If I/O object is well and alive let's ask it to terminate.\n    register_term_acks (1);\n\n    //  Note that this object is the root of the (partial shutdown) thus, its\n    //  value of linger is used, rather than the value stored by the children.\n    send_term (object_, options.linger.load ());\n}\n\nvoid zmq::own_t::process_own (own_t *object_)\n{\n    //  If the object is already being shut down, new owned objects are\n    //  immediately asked to terminate. Note that linger is set to zero.\n    if (_terminating) {\n        register_term_acks (1);\n        send_term (object_, 0);\n        return;\n    }\n\n    //  Store the reference to the owned object.\n    _owned.insert (object_);\n}\n\nvoid zmq::own_t::terminate ()\n{\n    //  If termination is already underway, there's no point\n    //  in starting it anew.\n    if (_terminating)\n        return;\n\n    //  As for the root of the ownership tree, there's no one to terminate it,\n    //  so it has to terminate itself.\n    if (!_owner) {\n        process_term (options.linger.load ());\n        return;\n    }\n\n    //  If I am an owned object, I'll ask my owner to terminate me.\n    send_term_req (_owner, this);\n}\n\nbool zmq::own_t::is_terminating () const\n{\n    return _terminating;\n}\n\nvoid zmq::own_t::process_term (int linger_)\n{\n    //  Double termination should never happen.\n    zmq_assert (!_terminating);\n\n    //  Send termination request to all owned objects.\n    for (owned_t::iterator it = _owned.begin (), end = _owned.end (); it != end;\n         ++it)\n        send_term (*it, linger_);\n    register_term_acks (static_cast<int> (_owned.size ()));\n    _owned.clear ();\n\n    //  Start termination process and check whether by chance we cannot\n    //  terminate immediately.\n    _terminating = true;\n    check_term_acks ();\n}\n\nvoid zmq::own_t::register_term_acks (int count_)\n{\n    _term_acks += count_;\n}\n\nvoid zmq::own_t::unregister_term_ack ()\n{\n    zmq_assert (_term_acks > 0);\n    _term_acks--;\n\n    //  This may be a last ack we are waiting for before termination...\n    check_term_acks ();\n}\n\nvoid zmq::own_t::process_term_ack ()\n{\n    unregister_term_ack ();\n}\n\nvoid zmq::own_t::check_term_acks ()\n{\n    if (_terminating && _processed_seqnum == _sent_seqnum.get ()\n        && _term_acks == 0) {\n        //  Sanity check. There should be no active children at this point.\n        zmq_assert (_owned.empty ());\n\n        //  The root object has nobody to confirm the termination to.\n        //  Other nodes will confirm the termination to the owner.\n        if (_owner)\n            send_term_ack (_owner);\n\n        //  Deallocate the resources.\n        process_destroy ();\n    }\n}\n\nvoid zmq::own_t::process_destroy ()\n{\n    delete this;\n}\n"
  },
  {
    "path": "src/own.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_OWN_HPP_INCLUDED__\n#define __ZMQ_OWN_HPP_INCLUDED__\n\n#include <set>\n\n#include \"object.hpp\"\n#include \"options.hpp\"\n#include \"atomic_counter.hpp\"\n#include \"stdint.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass io_thread_t;\n\n//  Base class for objects forming a part of ownership hierarchy.\n//  It handles initialisation and destruction of such objects.\n\nclass own_t : public object_t\n{\n  public:\n    //  Note that the owner is unspecified in the constructor.\n    //  It'll be supplied later on when the object is plugged in.\n\n    //  The object is not living within an I/O thread. It has it's own\n    //  thread outside of 0MQ infrastructure.\n    own_t (zmq::ctx_t *parent_, uint32_t tid_);\n\n    //  The object is living within I/O thread.\n    own_t (zmq::io_thread_t *io_thread_, const options_t &options_);\n\n    //  When another owned object wants to send command to this object\n    //  it calls this function to let it know it should not shut down\n    //  before the command is delivered.\n    void inc_seqnum ();\n\n    //  Use following two functions to wait for arbitrary events before\n    //  terminating. Just add number of events to wait for using\n    //  register_tem_acks functions. When event occurs, call\n    //  remove_term_ack. When number of pending acks reaches zero\n    //  object will be deallocated.\n    void register_term_acks (int count_);\n    void unregister_term_ack ();\n\n  protected:\n    //  Launch the supplied object and become its owner.\n    void launch_child (own_t *object_);\n\n    //  Terminate owned object\n    void term_child (own_t *object_);\n\n    //  Ask owner object to terminate this object. It may take a while\n    //  while actual termination is started. This function should not be\n    //  called more than once.\n    void terminate ();\n\n    //  Returns true if the object is in process of termination.\n    bool is_terminating () const;\n\n    //  Derived object destroys own_t. There's no point in allowing\n    //  others to invoke the destructor. At the same time, it has to be\n    //  virtual so that generic own_t deallocation mechanism destroys\n    //  specific type of the owned object correctly.\n    ~own_t () ZMQ_OVERRIDE;\n\n    //  Term handler is protected rather than private so that it can\n    //  be intercepted by the derived class. This is useful to add custom\n    //  steps to the beginning of the termination process.\n    void process_term (int linger_) ZMQ_OVERRIDE;\n\n    //  A place to hook in when physical destruction of the object\n    //  is to be delayed.\n    virtual void process_destroy ();\n\n    //  Socket options associated with this object.\n    options_t options;\n\n  private:\n    //  Set owner of the object\n    void set_owner (own_t *owner_);\n\n    //  Handlers for incoming commands.\n    void process_own (own_t *object_) ZMQ_OVERRIDE;\n    void process_term_req (own_t *object_) ZMQ_OVERRIDE;\n    void process_term_ack () ZMQ_OVERRIDE;\n    void process_seqnum () ZMQ_OVERRIDE;\n\n    //  Check whether all the pending term acks were delivered.\n    //  If so, deallocate this object.\n    void check_term_acks ();\n\n    //  True if termination was already initiated. If so, we can destroy\n    //  the object if there are no more child objects or pending term acks.\n    bool _terminating;\n\n    //  Sequence number of the last command sent to this object.\n    atomic_counter_t _sent_seqnum;\n\n    //  Sequence number of the last command processed by this object.\n    uint64_t _processed_seqnum;\n\n    //  Socket owning this object. It's responsible for shutting down\n    //  this object.\n    own_t *_owner;\n\n    //  List of all objects owned by this socket. We are responsible\n    //  for deallocating them before we quit.\n    typedef std::set<own_t *> owned_t;\n    owned_t _owned;\n\n    //  Number of events we have to get before we can destroy the object.\n    int _term_acks;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (own_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/pair.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"pair.hpp\"\n#include \"err.hpp\"\n#include \"pipe.hpp\"\n#include \"msg.hpp\"\n\nzmq::pair_t::pair_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_), _pipe (NULL)\n{\n    options.type = ZMQ_PAIR;\n}\n\nzmq::pair_t::~pair_t ()\n{\n    zmq_assert (!_pipe);\n}\n\nvoid zmq::pair_t::xattach_pipe (pipe_t *pipe_,\n                                bool subscribe_to_all_,\n                                bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_ != NULL);\n\n    //  ZMQ_PAIR socket can only be connected to a single peer.\n    //  The socket rejects any further connection requests.\n    if (_pipe == NULL)\n        _pipe = pipe_;\n    else\n        pipe_->terminate (false);\n}\n\nvoid zmq::pair_t::xpipe_terminated (pipe_t *pipe_)\n{\n    if (pipe_ == _pipe) {\n        _pipe = NULL;\n    }\n}\n\nvoid zmq::pair_t::xread_activated (pipe_t *)\n{\n    //  There's just one pipe. No lists of active and inactive pipes.\n    //  There's nothing to do here.\n}\n\nvoid zmq::pair_t::xwrite_activated (pipe_t *)\n{\n    //  There's just one pipe. No lists of active and inactive pipes.\n    //  There's nothing to do here.\n}\n\nint zmq::pair_t::xsend (msg_t *msg_)\n{\n    if (!_pipe || !_pipe->write (msg_)) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    if (!(msg_->flags () & msg_t::more))\n        _pipe->flush ();\n\n    //  Detach the original message from the data buffer.\n    const int rc = msg_->init ();\n    errno_assert (rc == 0);\n\n    return 0;\n}\n\nint zmq::pair_t::xrecv (msg_t *msg_)\n{\n    //  Deallocate old content of the message.\n    int rc = msg_->close ();\n    errno_assert (rc == 0);\n\n    if (!_pipe || !_pipe->read (msg_)) {\n        //  Initialise the output parameter to be a 0-byte message.\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n\n        errno = EAGAIN;\n        return -1;\n    }\n    return 0;\n}\n\nbool zmq::pair_t::xhas_in ()\n{\n    if (!_pipe)\n        return false;\n\n    return _pipe->check_read ();\n}\n\nbool zmq::pair_t::xhas_out ()\n{\n    if (!_pipe)\n        return false;\n\n    return _pipe->check_write ();\n}\n"
  },
  {
    "path": "src/pair.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PAIR_HPP_INCLUDED__\n#define __ZMQ_PAIR_HPP_INCLUDED__\n\n#include \"blob.hpp\"\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass pipe_t;\nclass io_thread_t;\n\nclass pair_t ZMQ_FINAL : public socket_base_t\n{\n  public:\n    pair_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~pair_t ();\n\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xsend (zmq::msg_t *msg_);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    bool xhas_out ();\n    void xread_activated (zmq::pipe_t *pipe_);\n    void xwrite_activated (zmq::pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n\n  private:\n    zmq::pipe_t *_pipe;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (pair_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/peer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"peer.hpp\"\n#include \"pipe.hpp\"\n#include \"wire.hpp\"\n#include \"random.hpp\"\n#include \"likely.hpp\"\n#include \"err.hpp\"\n\nzmq::peer_t::peer_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    server_t (parent_, tid_, sid_)\n{\n    options.type = ZMQ_PEER;\n    options.can_send_hello_msg = true;\n    options.can_recv_disconnect_msg = true;\n    options.can_recv_hiccup_msg = true;\n}\n\nuint32_t zmq::peer_t::connect_peer (const char *endpoint_uri_)\n{\n    scoped_optional_lock_t sync_lock (&_sync);\n\n    // connect_peer cannot work with immediate enabled\n    if (options.immediate == 1) {\n        errno = EFAULT;\n        return 0;\n    }\n\n    int rc = socket_base_t::connect_internal (endpoint_uri_);\n    if (rc != 0)\n        return 0;\n\n    return _peer_last_routing_id;\n}\n\nvoid zmq::peer_t::xattach_pipe (pipe_t *pipe_,\n                                bool subscribe_to_all_,\n                                bool locally_initiated_)\n{\n    server_t::xattach_pipe (pipe_, subscribe_to_all_, locally_initiated_);\n    _peer_last_routing_id = pipe_->get_server_socket_routing_id ();\n}\n"
  },
  {
    "path": "src/peer.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PEER_HPP_INCLUDED__\n#define __ZMQ_PEER_HPP_INCLUDED__\n\n#include <map>\n\n#include \"socket_base.hpp\"\n#include \"server.hpp\"\n#include \"session_base.hpp\"\n#include \"stdint.hpp\"\n#include \"blob.hpp\"\n#include \"fq.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass pipe_t;\n\nclass peer_t ZMQ_FINAL : public server_t\n{\n  public:\n    peer_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n\n    uint32_t connect_peer (const char *endpoint_uri_);\n\n  private:\n    uint32_t _peer_last_routing_id;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (peer_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/pgm_receiver.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n\n#if defined ZMQ_HAVE_OPENPGM\n\n#include <new>\n\n#include \"pgm_receiver.hpp\"\n#include \"session_base.hpp\"\n#include \"v1_decoder.hpp\"\n#include \"stdint.hpp\"\n#include \"wire.hpp\"\n#include \"err.hpp\"\n\nzmq::pgm_receiver_t::pgm_receiver_t (class io_thread_t *parent_,\n                                     const options_t &options_) :\n    io_object_t (parent_),\n    has_rx_timer (false),\n    pgm_socket (true, options_),\n    options (options_),\n    session (NULL),\n    active_tsi (NULL),\n    insize (0)\n{\n}\n\nzmq::pgm_receiver_t::~pgm_receiver_t ()\n{\n    //  Destructor should not be called before unplug.\n    zmq_assert (peers.empty ());\n}\n\nint zmq::pgm_receiver_t::init (bool udp_encapsulation_, const char *network_)\n{\n    return pgm_socket.init (udp_encapsulation_, network_);\n}\n\nvoid zmq::pgm_receiver_t::plug (io_thread_t *io_thread_,\n                                session_base_t *session_)\n{\n    LIBZMQ_UNUSED (io_thread_);\n    //  Retrieve PGM fds and start polling.\n    fd_t socket_fd = retired_fd;\n    fd_t waiting_pipe_fd = retired_fd;\n    pgm_socket.get_receiver_fds (&socket_fd, &waiting_pipe_fd);\n    socket_handle = add_fd (socket_fd);\n    pipe_handle = add_fd (waiting_pipe_fd);\n    set_pollin (pipe_handle);\n    set_pollin (socket_handle);\n\n    session = session_;\n\n    //  If there are any subscriptions already queued in the session, drop them.\n    drop_subscriptions ();\n}\n\nvoid zmq::pgm_receiver_t::unplug ()\n{\n    //  Delete decoders.\n    for (peers_t::iterator it = peers.begin (), end = peers.end (); it != end;\n         ++it) {\n        if (it->second.decoder != NULL) {\n            LIBZMQ_DELETE (it->second.decoder);\n        }\n    }\n    peers.clear ();\n    active_tsi = NULL;\n\n    if (has_rx_timer) {\n        cancel_timer (rx_timer_id);\n        has_rx_timer = false;\n    }\n\n    rm_fd (socket_handle);\n    rm_fd (pipe_handle);\n\n    session = NULL;\n}\n\nvoid zmq::pgm_receiver_t::terminate ()\n{\n    unplug ();\n    delete this;\n}\n\nvoid zmq::pgm_receiver_t::restart_output ()\n{\n    drop_subscriptions ();\n}\n\nbool zmq::pgm_receiver_t::restart_input ()\n{\n    zmq_assert (session != NULL);\n    zmq_assert (active_tsi != NULL);\n\n    const peers_t::iterator it = peers.find (*active_tsi);\n    zmq_assert (it != peers.end ());\n    zmq_assert (it->second.joined);\n\n    //  Push the pending message into the session.\n    int rc = session->push_msg (it->second.decoder->msg ());\n    errno_assert (rc == 0);\n\n    if (insize > 0) {\n        rc = process_input (it->second.decoder);\n        if (rc == -1) {\n            //  HWM reached; we will try later.\n            if (errno == EAGAIN) {\n                session->flush ();\n                return true;\n            }\n            //  Data error. Delete message decoder, mark the\n            //  peer as not joined and drop remaining data.\n            it->second.joined = false;\n            LIBZMQ_DELETE (it->second.decoder);\n            insize = 0;\n        }\n    }\n\n    //  Resume polling.\n    set_pollin (pipe_handle);\n    set_pollin (socket_handle);\n\n    active_tsi = NULL;\n    in_event ();\n\n    return true;\n}\n\nconst zmq::endpoint_uri_pair_t &zmq::pgm_receiver_t::get_endpoint () const\n{\n    return _empty_endpoint;\n}\n\nvoid zmq::pgm_receiver_t::in_event ()\n{\n    // If active_tsi is not null, there is a pending restart_input.\n    // Keep the internal state as is so that restart_input would process the right data\n    if (active_tsi) {\n        return;\n    }\n\n    // Read data from the underlying pgm_socket.\n    const pgm_tsi_t *tsi = NULL;\n\n    if (has_rx_timer) {\n        cancel_timer (rx_timer_id);\n        has_rx_timer = false;\n    }\n\n    //  TODO: This loop can effectively block other engines in the same I/O\n    //  thread in the case of high load.\n    while (true) {\n        //  Get new batch of data.\n        //  Note the workaround made not to break strict-aliasing rules.\n        insize = 0;\n        void *tmp = NULL;\n        ssize_t received = pgm_socket.receive (&tmp, &tsi);\n\n        //  No data to process. This may happen if the packet received is\n        //  neither ODATA nor ODATA.\n        if (received == 0) {\n            if (errno == ENOMEM || errno == EBUSY) {\n                const long timeout = pgm_socket.get_rx_timeout ();\n                add_timer (timeout, rx_timer_id);\n                has_rx_timer = true;\n            }\n            break;\n        }\n\n        //  Find the peer based on its TSI.\n        peers_t::iterator it = peers.find (*tsi);\n\n        //  Data loss. Delete decoder and mark the peer as disjoint.\n        if (received == -1) {\n            if (it != peers.end ()) {\n                it->second.joined = false;\n                if (it->second.decoder != NULL) {\n                    LIBZMQ_DELETE (it->second.decoder);\n                }\n            }\n            break;\n        }\n\n        //  New peer. Add it to the list of know but unjoint peers.\n        if (it == peers.end ()) {\n            peer_info_t peer_info = {false, NULL};\n            it = peers.ZMQ_MAP_INSERT_OR_EMPLACE (*tsi, peer_info).first;\n        }\n\n        insize = static_cast<size_t> (received);\n        inpos = (unsigned char *) tmp;\n\n        //  Read the offset of the fist message in the current packet.\n        zmq_assert (insize >= sizeof (uint16_t));\n        uint16_t offset = get_uint16 (inpos);\n        inpos += sizeof (uint16_t);\n        insize -= sizeof (uint16_t);\n\n        //  Join the stream if needed.\n        if (!it->second.joined) {\n            //  There is no beginning of the message in current packet.\n            //  Ignore the data.\n            if (offset == 0xffff)\n                continue;\n\n            zmq_assert (offset <= insize);\n            zmq_assert (it->second.decoder == NULL);\n\n            //  We have to move data to the beginning of the first message.\n            inpos += offset;\n            insize -= offset;\n\n            //  Mark the stream as joined.\n            it->second.joined = true;\n\n            //  Create and connect decoder for the peer.\n            it->second.decoder =\n              new (std::nothrow) v1_decoder_t (0, options.maxmsgsize);\n            alloc_assert (it->second.decoder);\n        }\n\n        int rc = process_input (it->second.decoder);\n        if (rc == -1) {\n            if (errno == EAGAIN) {\n                active_tsi = tsi;\n\n                //  Stop polling.\n                reset_pollin (pipe_handle);\n                reset_pollin (socket_handle);\n\n                break;\n            }\n\n            it->second.joined = false;\n            LIBZMQ_DELETE (it->second.decoder);\n            insize = 0;\n        }\n    }\n\n    //  Flush any messages decoder may have produced.\n    session->flush ();\n}\n\nint zmq::pgm_receiver_t::process_input (v1_decoder_t *decoder)\n{\n    zmq_assert (session != NULL);\n\n    while (insize > 0) {\n        size_t n = 0;\n        int rc = decoder->decode (inpos, insize, n);\n        if (rc == -1)\n            return -1;\n        inpos += n;\n        insize -= n;\n        if (rc == 0)\n            break;\n        rc = session->push_msg (decoder->msg ());\n        if (rc == -1) {\n            errno_assert (errno == EAGAIN);\n            return -1;\n        }\n    }\n    return 0;\n}\n\n\nvoid zmq::pgm_receiver_t::timer_event (int token)\n{\n    zmq_assert (token == rx_timer_id);\n\n    //  Timer cancels on return by poller_base.\n    has_rx_timer = false;\n    in_event ();\n}\n\nvoid zmq::pgm_receiver_t::drop_subscriptions ()\n{\n    msg_t msg;\n    msg.init ();\n    while (session->pull_msg (&msg) == 0)\n        msg.close ();\n}\n\n#endif\n"
  },
  {
    "path": "src/pgm_receiver.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PGM_RECEIVER_HPP_INCLUDED__\n#define __ZMQ_PGM_RECEIVER_HPP_INCLUDED__\n\n#if defined ZMQ_HAVE_OPENPGM\n\n#include <map>\n#include <algorithm>\n\n#include \"io_object.hpp\"\n#include \"i_engine.hpp\"\n#include \"options.hpp\"\n#include \"v1_decoder.hpp\"\n#include \"pgm_socket.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\nclass session_base_t;\n\nclass pgm_receiver_t ZMQ_FINAL : public io_object_t, public i_engine\n{\n  public:\n    pgm_receiver_t (zmq::io_thread_t *parent_, const options_t &options_);\n    ~pgm_receiver_t ();\n\n    int init (bool udp_encapsulation_, const char *network_);\n\n    //  i_engine interface implementation.\n    bool has_handshake_stage () { return false; };\n    void plug (zmq::io_thread_t *io_thread_, zmq::session_base_t *session_);\n    void terminate ();\n    bool restart_input ();\n    void restart_output ();\n    void zap_msg_available () {}\n    const endpoint_uri_pair_t &get_endpoint () const;\n\n    //  i_poll_events interface implementation.\n    void in_event ();\n    void timer_event (int token);\n\n  private:\n    //  Unplug the engine from the session.\n    void unplug ();\n\n    //  Decode received data (inpos, insize) and forward decoded\n    //  messages to the session.\n    int process_input (v1_decoder_t *decoder);\n\n    //  PGM is not able to move subscriptions upstream. Thus, drop all\n    //  the pending subscriptions.\n    void drop_subscriptions ();\n\n    //  RX timeout timer ID.\n    enum\n    {\n        rx_timer_id = 0xa1\n    };\n\n    const endpoint_uri_pair_t _empty_endpoint;\n\n    //  RX timer is running.\n    bool has_rx_timer;\n\n    //  If joined is true we are already getting messages from the peer.\n    //  It it's false, we are getting data but still we haven't seen\n    //  beginning of a message.\n    struct peer_info_t\n    {\n        bool joined;\n        v1_decoder_t *decoder;\n    };\n\n    struct tsi_comp\n    {\n        bool operator() (const pgm_tsi_t &ltsi, const pgm_tsi_t &rtsi) const\n        {\n            uint32_t ll[2], rl[2];\n            memcpy (ll, &ltsi, sizeof (ll));\n            memcpy (rl, &rtsi, sizeof (rl));\n            return (ll[0] < rl[0]) || (ll[0] == rl[0] && ll[1] < rl[1]);\n        }\n    };\n\n    typedef std::map<pgm_tsi_t, peer_info_t, tsi_comp> peers_t;\n    peers_t peers;\n\n    //  PGM socket.\n    pgm_socket_t pgm_socket;\n\n    //  Socket options.\n    options_t options;\n\n    //  Associated session.\n    zmq::session_base_t *session;\n\n    const pgm_tsi_t *active_tsi;\n\n    //  Number of bytes not consumed by the decoder due to pipe overflow.\n    size_t insize;\n\n    //  Pointer to data still waiting to be processed by the decoder.\n    const unsigned char *inpos;\n\n    //  Poll handle associated with PGM socket.\n    handle_t socket_handle;\n\n    //  Poll handle associated with engine PGM waiting pipe.\n    handle_t pipe_handle;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (pgm_receiver_t)\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/pgm_sender.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#if defined ZMQ_HAVE_OPENPGM\n\n#include <stdlib.h>\n\n#include \"io_thread.hpp\"\n#include \"pgm_sender.hpp\"\n#include \"session_base.hpp\"\n#include \"err.hpp\"\n#include \"wire.hpp\"\n#include \"stdint.hpp\"\n#include \"macros.hpp\"\n\nzmq::pgm_sender_t::pgm_sender_t (io_thread_t *parent_,\n                                 const options_t &options_) :\n    io_object_t (parent_),\n    has_tx_timer (false),\n    has_rx_timer (false),\n    session (NULL),\n    encoder (0),\n    more_flag (false),\n    pgm_socket (false, options_),\n    options (options_),\n    handle (static_cast<handle_t> (NULL)),\n    uplink_handle (static_cast<handle_t> (NULL)),\n    rdata_notify_handle (static_cast<handle_t> (NULL)),\n    pending_notify_handle (static_cast<handle_t> (NULL)),\n    out_buffer (NULL),\n    out_buffer_size (0),\n    write_size (0)\n{\n    int rc = msg.init ();\n    errno_assert (rc == 0);\n}\n\nint zmq::pgm_sender_t::init (bool udp_encapsulation_, const char *network_)\n{\n    int rc = pgm_socket.init (udp_encapsulation_, network_);\n    if (rc != 0)\n        return rc;\n\n    out_buffer_size = pgm_socket.get_max_tsdu_size ();\n    out_buffer = (unsigned char *) malloc (out_buffer_size);\n    alloc_assert (out_buffer);\n\n    return rc;\n}\n\nvoid zmq::pgm_sender_t::plug (io_thread_t *io_thread_, session_base_t *session_)\n{\n    LIBZMQ_UNUSED (io_thread_);\n    //  Allocate 2 fds for PGM socket.\n    fd_t downlink_socket_fd = retired_fd;\n    fd_t uplink_socket_fd = retired_fd;\n    fd_t rdata_notify_fd = retired_fd;\n    fd_t pending_notify_fd = retired_fd;\n\n    session = session_;\n\n    //  Fill fds from PGM transport and add them to the poller.\n    pgm_socket.get_sender_fds (&downlink_socket_fd, &uplink_socket_fd,\n                               &rdata_notify_fd, &pending_notify_fd);\n\n    handle = add_fd (downlink_socket_fd);\n    uplink_handle = add_fd (uplink_socket_fd);\n    rdata_notify_handle = add_fd (rdata_notify_fd);\n    pending_notify_handle = add_fd (pending_notify_fd);\n\n    //  Set POLLIN. We will never want to stop polling for uplink = we never\n    //  want to stop processing NAKs.\n    set_pollin (uplink_handle);\n    set_pollin (rdata_notify_handle);\n    set_pollin (pending_notify_handle);\n\n    //  Set POLLOUT for downlink_socket_handle.\n    set_pollout (handle);\n}\n\nvoid zmq::pgm_sender_t::unplug ()\n{\n    if (has_rx_timer) {\n        cancel_timer (rx_timer_id);\n        has_rx_timer = false;\n    }\n\n    if (has_tx_timer) {\n        cancel_timer (tx_timer_id);\n        has_tx_timer = false;\n    }\n\n    rm_fd (handle);\n    rm_fd (uplink_handle);\n    rm_fd (rdata_notify_handle);\n    rm_fd (pending_notify_handle);\n    session = NULL;\n}\n\nvoid zmq::pgm_sender_t::terminate ()\n{\n    unplug ();\n    delete this;\n}\n\nvoid zmq::pgm_sender_t::restart_output ()\n{\n    set_pollout (handle);\n    out_event ();\n}\n\nbool zmq::pgm_sender_t::restart_input ()\n{\n    zmq_assert (false);\n    return true;\n}\n\nconst zmq::endpoint_uri_pair_t &zmq::pgm_sender_t::get_endpoint () const\n{\n    return _empty_endpoint;\n}\n\nzmq::pgm_sender_t::~pgm_sender_t ()\n{\n    int rc = msg.close ();\n    errno_assert (rc == 0);\n\n    if (out_buffer) {\n        free (out_buffer);\n        out_buffer = NULL;\n    }\n}\n\nvoid zmq::pgm_sender_t::in_event ()\n{\n    if (has_rx_timer) {\n        cancel_timer (rx_timer_id);\n        has_rx_timer = false;\n    }\n\n    //  In-event on sender side means NAK or SPMR receiving from some peer.\n    pgm_socket.process_upstream ();\n    if (errno == ENOMEM || errno == EBUSY) {\n        const long timeout = pgm_socket.get_rx_timeout ();\n        add_timer (timeout, rx_timer_id);\n        has_rx_timer = true;\n    }\n}\n\nvoid zmq::pgm_sender_t::out_event ()\n{\n    //  POLLOUT event from send socket. If write buffer is empty,\n    //  try to read new data from the encoder.\n    if (write_size == 0) {\n        //  First two bytes (sizeof uint16_t) are used to store message\n        //  offset in following steps. Note that by passing our buffer to\n        //  the get data function we prevent it from returning its own buffer.\n        unsigned char *bf = out_buffer + sizeof (uint16_t);\n        size_t bfsz = out_buffer_size - sizeof (uint16_t);\n        uint16_t offset = 0xffff;\n\n        size_t bytes = encoder.encode (&bf, bfsz);\n        while (bytes < bfsz) {\n            if (!more_flag && offset == 0xffff)\n                offset = static_cast<uint16_t> (bytes);\n            int rc = session->pull_msg (&msg);\n            if (rc == -1)\n                break;\n            more_flag = msg.flags () & msg_t::more;\n            encoder.load_msg (&msg);\n            bf = out_buffer + sizeof (uint16_t) + bytes;\n            bytes += encoder.encode (&bf, bfsz - bytes);\n        }\n\n        //  If there are no data to write stop polling for output.\n        if (bytes == 0) {\n            reset_pollout (handle);\n            return;\n        }\n\n        write_size = sizeof (uint16_t) + bytes;\n\n        //  Put offset information in the buffer.\n        put_uint16 (out_buffer, offset);\n    }\n\n    if (has_tx_timer) {\n        cancel_timer (tx_timer_id);\n        set_pollout (handle);\n        has_tx_timer = false;\n    }\n\n    //  Send the data.\n    size_t nbytes = pgm_socket.send (out_buffer, write_size);\n\n    //  We can write either all data or 0 which means rate limit reached.\n    if (nbytes == write_size)\n        write_size = 0;\n    else {\n        zmq_assert (nbytes == 0);\n\n        if (errno == ENOMEM) {\n            // Stop polling handle and wait for tx timeout\n            const long timeout = pgm_socket.get_tx_timeout ();\n            add_timer (timeout, tx_timer_id);\n            reset_pollout (handle);\n            has_tx_timer = true;\n        } else\n            errno_assert (errno == EBUSY);\n    }\n}\n\nvoid zmq::pgm_sender_t::timer_event (int token)\n{\n    //  Timer cancels on return by poller_base.\n    if (token == rx_timer_id) {\n        has_rx_timer = false;\n        in_event ();\n    } else if (token == tx_timer_id) {\n        // Restart polling handle and retry sending\n        has_tx_timer = false;\n        set_pollout (handle);\n        out_event ();\n    } else\n        zmq_assert (false);\n}\n\n#endif\n"
  },
  {
    "path": "src/pgm_sender.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PGM_SENDER_HPP_INCLUDED__\n#define __ZMQ_PGM_SENDER_HPP_INCLUDED__\n\n#if defined ZMQ_HAVE_OPENPGM\n\n#include \"stdint.hpp\"\n#include \"io_object.hpp\"\n#include \"i_engine.hpp\"\n#include \"options.hpp\"\n#include \"pgm_socket.hpp\"\n#include \"v1_encoder.hpp\"\n#include \"msg.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\nclass session_base_t;\n\nclass pgm_sender_t ZMQ_FINAL : public io_object_t, public i_engine\n{\n  public:\n    pgm_sender_t (zmq::io_thread_t *parent_, const options_t &options_);\n    ~pgm_sender_t ();\n\n    int init (bool udp_encapsulation_, const char *network_);\n\n    //  i_engine interface implementation.\n    bool has_handshake_stage () { return false; };\n    void plug (zmq::io_thread_t *io_thread_, zmq::session_base_t *session_);\n    void terminate ();\n    bool restart_input ();\n    void restart_output ();\n    void zap_msg_available () {}\n    const endpoint_uri_pair_t &get_endpoint () const;\n\n    //  i_poll_events interface implementation.\n    void in_event ();\n    void out_event ();\n    void timer_event (int token);\n\n  private:\n    //  Unplug the engine from the session.\n    void unplug ();\n\n    //  TX and RX timeout timer ID's.\n    enum\n    {\n        tx_timer_id = 0xa0,\n        rx_timer_id = 0xa1\n    };\n\n    const endpoint_uri_pair_t _empty_endpoint;\n\n    //  Timers are running.\n    bool has_tx_timer;\n    bool has_rx_timer;\n\n    session_base_t *session;\n\n    //  Message encoder.\n    v1_encoder_t encoder;\n\n    msg_t msg;\n\n    //  Keeps track of message boundaries.\n    bool more_flag;\n\n    //  PGM socket.\n    pgm_socket_t pgm_socket;\n\n    //  Socket options.\n    options_t options;\n\n    //  Poll handle associated with PGM socket.\n    handle_t handle;\n    handle_t uplink_handle;\n    handle_t rdata_notify_handle;\n    handle_t pending_notify_handle;\n\n    //  Output buffer from pgm_socket.\n    unsigned char *out_buffer;\n\n    //  Output buffer size.\n    size_t out_buffer_size;\n\n    //  Number of bytes in the buffer to be written to the socket.\n    //  If zero, there are no data to be sent.\n    size_t write_size;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (pgm_sender_t)\n};\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/pgm_socket.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#ifdef ZMQ_HAVE_OPENPGM\n\n#ifdef ZMQ_HAVE_LINUX\n#include <poll.h>\n#endif\n\n#include <stdlib.h>\n#include <string.h>\n#include <string>\n\n#include \"options.hpp\"\n#include \"pgm_socket.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"random.hpp\"\n#include \"stdint.hpp\"\n\n#ifndef MSG_ERRQUEUE\n#define MSG_ERRQUEUE 0x2000\n#endif\n\nzmq::pgm_socket_t::pgm_socket_t (bool receiver_, const options_t &options_) :\n    sock (NULL),\n    options (options_),\n    receiver (receiver_),\n    pgm_msgv (NULL),\n    pgm_msgv_len (0),\n    nbytes_rec (0),\n    nbytes_processed (0),\n    pgm_msgv_processed (0)\n{\n}\n\n//  Resolve PGM socket address.\n//  network_ of the form <interface & multicast group decls>:<IP port>\n//  e.g. eth0;239.192.0.1:7500\n//       link-local;224.250.0.1,224.250.0.2;224.250.0.3:8000\n//       ;[fe80::1%en0]:7500\nint zmq::pgm_socket_t::init_address (const char *network_,\n                                     struct pgm_addrinfo_t **res,\n                                     uint16_t *port_number)\n{\n    //  Parse port number, start from end for IPv6\n    const char *port_delim = strrchr (network_, ':');\n    if (!port_delim) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    *port_number = atoi (port_delim + 1);\n\n    char network[256];\n    if (port_delim - network_ >= (int) sizeof (network) - 1) {\n        errno = EINVAL;\n        return -1;\n    }\n    memset (network, '\\0', sizeof (network));\n    memcpy (network, network_, port_delim - network_);\n\n    pgm_error_t *pgm_error = NULL;\n    struct pgm_addrinfo_t hints;\n\n    memset (&hints, 0, sizeof (hints));\n    hints.ai_family = AF_UNSPEC;\n    if (!pgm_getaddrinfo (network, NULL, res, &pgm_error)) {\n        //  Invalid parameters don't set pgm_error_t.\n        zmq_assert (pgm_error != NULL);\n        if (pgm_error->domain == PGM_ERROR_DOMAIN_IF &&\n\n            //  NB: cannot catch EAI_BADFLAGS.\n            (pgm_error->code != PGM_ERROR_SERVICE\n             && pgm_error->code != PGM_ERROR_SOCKTNOSUPPORT)) {\n            //  User, host, or network configuration or transient error.\n            pgm_error_free (pgm_error);\n            errno = EINVAL;\n            return -1;\n        }\n\n        //  Fatal OpenPGM internal error.\n        zmq_assert (false);\n    }\n    return 0;\n}\n\n//  Create, bind and connect PGM socket.\nint zmq::pgm_socket_t::init (bool udp_encapsulation_, const char *network_)\n{\n    //  Can not open transport before destroying old one.\n    zmq_assert (sock == NULL);\n    zmq_assert (options.rate > 0);\n\n    //  Zero counter used in msgrecv.\n    nbytes_rec = 0;\n    nbytes_processed = 0;\n    pgm_msgv_processed = 0;\n\n    uint16_t port_number;\n    struct pgm_addrinfo_t *res = NULL;\n    sa_family_t sa_family;\n\n    pgm_error_t *pgm_error = NULL;\n\n    if (init_address (network_, &res, &port_number) < 0) {\n        goto err_abort;\n    }\n\n    zmq_assert (res != NULL);\n\n    //  Pick up detected IP family.\n    sa_family = res->ai_send_addrs[0].gsr_group.ss_family;\n\n    //  Create IP/PGM or UDP/PGM socket.\n    if (udp_encapsulation_) {\n        if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP,\n                         &pgm_error)) {\n            //  Invalid parameters don't set pgm_error_t.\n            zmq_assert (pgm_error != NULL);\n            if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET\n                && (pgm_error->code != PGM_ERROR_BADF\n                    && pgm_error->code != PGM_ERROR_FAULT\n                    && pgm_error->code != PGM_ERROR_NOPROTOOPT\n                    && pgm_error->code != PGM_ERROR_FAILED))\n\n                //  User, host, or network configuration or transient error.\n                goto err_abort;\n\n            //  Fatal OpenPGM internal error.\n            zmq_assert (false);\n        }\n\n        //  All options are of data type int\n        const int encapsulation_port = port_number;\n        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT,\n                             &encapsulation_port, sizeof (encapsulation_port)))\n            goto err_abort;\n        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT,\n                             &encapsulation_port, sizeof (encapsulation_port)))\n            goto err_abort;\n    } else {\n        if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM,\n                         &pgm_error)) {\n            //  Invalid parameters don't set pgm_error_t.\n            zmq_assert (pgm_error != NULL);\n            if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET\n                && (pgm_error->code != PGM_ERROR_BADF\n                    && pgm_error->code != PGM_ERROR_FAULT\n                    && pgm_error->code != PGM_ERROR_NOPROTOOPT\n                    && pgm_error->code != PGM_ERROR_FAILED))\n\n                //  User, host, or network configuration or transient error.\n                goto err_abort;\n\n            //  Fatal OpenPGM internal error.\n            zmq_assert (false);\n        }\n    }\n\n    {\n        const int rcvbuf = (int) options.rcvbuf;\n        if (rcvbuf >= 0) {\n            if (!pgm_setsockopt (sock, SOL_SOCKET, SO_RCVBUF, &rcvbuf,\n                                 sizeof (rcvbuf)))\n                goto err_abort;\n        }\n\n        const int sndbuf = (int) options.sndbuf;\n        if (sndbuf >= 0) {\n            if (!pgm_setsockopt (sock, SOL_SOCKET, SO_SNDBUF, &sndbuf,\n                                 sizeof (sndbuf)))\n                goto err_abort;\n        }\n\n        const int max_tpdu = (int) options.multicast_maxtpdu;\n        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_MTU, &max_tpdu,\n                             sizeof (max_tpdu)))\n            goto err_abort;\n    }\n\n    if (receiver) {\n        const int recv_only = 1, rxw_max_tpdu = (int) options.multicast_maxtpdu,\n                  rxw_sqns = compute_sqns (rxw_max_tpdu),\n                  peer_expiry = pgm_secs (300), spmr_expiry = pgm_msecs (25),\n                  nak_bo_ivl = pgm_msecs (50), nak_rpt_ivl = pgm_msecs (200),\n                  nak_rdata_ivl = pgm_msecs (200), nak_data_retries = 50,\n                  nak_ncf_retries = 50;\n\n        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only,\n                             sizeof (recv_only))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_RXW_SQNS, &rxw_sqns,\n                                sizeof (rxw_sqns))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_PEER_EXPIRY,\n                                &peer_expiry, sizeof (peer_expiry))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_SPMR_EXPIRY,\n                                &spmr_expiry, sizeof (spmr_expiry))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl,\n                                sizeof (nak_bo_ivl))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_RPT_IVL,\n                                &nak_rpt_ivl, sizeof (nak_rpt_ivl))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL,\n                                &nak_rdata_ivl, sizeof (nak_rdata_ivl))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES,\n                                &nak_data_retries, sizeof (nak_data_retries))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES,\n                                &nak_ncf_retries, sizeof (nak_ncf_retries)))\n            goto err_abort;\n    } else {\n        const int send_only = 1, max_rte = (int) ((options.rate * 1000) / 8),\n                  txw_max_tpdu = (int) options.multicast_maxtpdu,\n                  txw_sqns = compute_sqns (txw_max_tpdu),\n                  ambient_spm = pgm_secs (30),\n                  heartbeat_spm[] = {\n                    pgm_msecs (100), pgm_msecs (100),  pgm_msecs (100),\n                    pgm_msecs (100), pgm_msecs (1300), pgm_secs (7),\n                    pgm_secs (16),   pgm_secs (25),    pgm_secs (30)};\n\n        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_only,\n                             sizeof (send_only))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_ODATA_MAX_RTE, &max_rte,\n                                sizeof (max_rte))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_SQNS, &txw_sqns,\n                                sizeof (txw_sqns))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_AMBIENT_SPM,\n                                &ambient_spm, sizeof (ambient_spm))\n            || !pgm_setsockopt (sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM,\n                                &heartbeat_spm, sizeof (heartbeat_spm)))\n            goto err_abort;\n    }\n\n    //  PGM transport GSI.\n    struct pgm_sockaddr_t addr;\n\n    memset (&addr, 0, sizeof (addr));\n    addr.sa_port = port_number;\n    addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT;\n\n    //  Create random GSI.\n    uint32_t buf[2];\n    buf[0] = generate_random ();\n    buf[1] = generate_random ();\n    if (!pgm_gsi_create_from_data (&addr.sa_addr.gsi, (uint8_t *) buf, 8))\n        goto err_abort;\n\n\n    //  Bind a transport to the specified network devices.\n    struct pgm_interface_req_t if_req;\n    memset (&if_req, 0, sizeof (if_req));\n    if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface;\n    if_req.ir_scope_id = 0;\n    if (AF_INET6 == sa_family) {\n        struct sockaddr_in6 sa6;\n        memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof (sa6));\n        if_req.ir_scope_id = sa6.sin6_scope_id;\n    }\n    if (!pgm_bind3 (sock, &addr, sizeof (addr), &if_req, sizeof (if_req),\n                    &if_req, sizeof (if_req), &pgm_error)) {\n        //  Invalid parameters don't set pgm_error_t.\n        zmq_assert (pgm_error != NULL);\n        if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET\n             || pgm_error->domain == PGM_ERROR_DOMAIN_IF)\n            && (pgm_error->code != PGM_ERROR_INVAL\n                && pgm_error->code != PGM_ERROR_BADF\n                && pgm_error->code != PGM_ERROR_FAULT))\n\n            //  User, host, or network configuration or transient error.\n            goto err_abort;\n\n        //  Fatal OpenPGM internal error.\n        zmq_assert (false);\n    }\n\n    //  Join IP multicast groups.\n    for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) {\n        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_JOIN_GROUP,\n                             &res->ai_recv_addrs[i], sizeof (struct group_req)))\n            goto err_abort;\n    }\n    if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_GROUP,\n                         &res->ai_send_addrs[0], sizeof (struct group_req)))\n        goto err_abort;\n\n    pgm_freeaddrinfo (res);\n    res = NULL;\n\n    //  Set IP level parameters.\n    {\n        // Multicast loopback disabled by default\n        const int multicast_loop = 0;\n        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_LOOP,\n                             &multicast_loop, sizeof (multicast_loop)))\n            goto err_abort;\n\n        const int multicast_hops = options.multicast_hops;\n        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_HOPS,\n                             &multicast_hops, sizeof (multicast_hops)))\n            goto err_abort;\n\n        //  Expedited Forwarding PHB for network elements, no ECN.\n        //  Ignore return value due to varied runtime support.\n        const int dscp = 0x2e << 2;\n        if (AF_INET6 != sa_family)\n            pgm_setsockopt (sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof (dscp));\n\n        const int nonblocking = 1;\n        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking,\n                             sizeof (nonblocking)))\n            goto err_abort;\n    }\n\n    //  Connect PGM transport to start state machine.\n    if (!pgm_connect (sock, &pgm_error)) {\n        //  Invalid parameters don't set pgm_error_t.\n        zmq_assert (pgm_error != NULL);\n        goto err_abort;\n    }\n\n    //  For receiver transport preallocate pgm_msgv array.\n    if (receiver) {\n        zmq_assert (options.in_batch_size > 0);\n        size_t max_tsdu_size = get_max_tsdu_size ();\n        pgm_msgv_len = (int) options.in_batch_size / max_tsdu_size;\n        if ((int) options.in_batch_size % max_tsdu_size)\n            pgm_msgv_len++;\n        zmq_assert (pgm_msgv_len);\n\n        pgm_msgv = (pgm_msgv_t *) malloc (sizeof (pgm_msgv_t) * pgm_msgv_len);\n        alloc_assert (pgm_msgv);\n    }\n\n    return 0;\n\nerr_abort:\n    if (sock != NULL) {\n        pgm_close (sock, FALSE);\n        sock = NULL;\n    }\n    if (res != NULL) {\n        pgm_freeaddrinfo (res);\n        res = NULL;\n    }\n    if (pgm_error != NULL) {\n        pgm_error_free (pgm_error);\n        pgm_error = NULL;\n    }\n    errno = EINVAL;\n    return -1;\n}\n\nzmq::pgm_socket_t::~pgm_socket_t ()\n{\n    if (pgm_msgv)\n        free (pgm_msgv);\n    if (sock)\n        pgm_close (sock, TRUE);\n}\n\n//  Get receiver fds. receive_fd_ is signaled for incoming packets,\n//  waiting_pipe_fd_ is signaled for state driven events and data.\nvoid zmq::pgm_socket_t::get_receiver_fds (fd_t *receive_fd_,\n                                          fd_t *waiting_pipe_fd_)\n{\n    socklen_t socklen;\n    bool rc;\n\n    zmq_assert (receive_fd_);\n    zmq_assert (waiting_pipe_fd_);\n\n    socklen = sizeof (*receive_fd_);\n    rc =\n      pgm_getsockopt (sock, IPPROTO_PGM, PGM_RECV_SOCK, receive_fd_, &socklen);\n    zmq_assert (rc);\n    zmq_assert (socklen == sizeof (*receive_fd_));\n\n    socklen = sizeof (*waiting_pipe_fd_);\n    rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_PENDING_SOCK, waiting_pipe_fd_,\n                         &socklen);\n    zmq_assert (rc);\n    zmq_assert (socklen == sizeof (*waiting_pipe_fd_));\n}\n\n//  Get fds and store them into user allocated memory.\n//  send_fd is for non-blocking send wire notifications.\n//  receive_fd_ is for incoming back-channel protocol packets.\n//  rdata_notify_fd_ is raised for waiting repair transmissions.\n//  pending_notify_fd_ is for state driven events.\nvoid zmq::pgm_socket_t::get_sender_fds (fd_t *send_fd_,\n                                        fd_t *receive_fd_,\n                                        fd_t *rdata_notify_fd_,\n                                        fd_t *pending_notify_fd_)\n{\n    socklen_t socklen;\n    bool rc;\n\n    zmq_assert (send_fd_);\n    zmq_assert (receive_fd_);\n    zmq_assert (rdata_notify_fd_);\n    zmq_assert (pending_notify_fd_);\n\n    socklen = sizeof (*send_fd_);\n    rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_SEND_SOCK, send_fd_, &socklen);\n    zmq_assert (rc);\n    zmq_assert (socklen == sizeof (*receive_fd_));\n\n    socklen = sizeof (*receive_fd_);\n    rc =\n      pgm_getsockopt (sock, IPPROTO_PGM, PGM_RECV_SOCK, receive_fd_, &socklen);\n    zmq_assert (rc);\n    zmq_assert (socklen == sizeof (*receive_fd_));\n\n    socklen = sizeof (*rdata_notify_fd_);\n    rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_REPAIR_SOCK, rdata_notify_fd_,\n                         &socklen);\n    zmq_assert (rc);\n    zmq_assert (socklen == sizeof (*rdata_notify_fd_));\n\n    socklen = sizeof (*pending_notify_fd_);\n    rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_PENDING_SOCK,\n                         pending_notify_fd_, &socklen);\n    zmq_assert (rc);\n    zmq_assert (socklen == sizeof (*pending_notify_fd_));\n}\n\n//  Send one APDU, transmit window owned memory.\n//  data_len_ must be less than one TPDU.\nsize_t zmq::pgm_socket_t::send (unsigned char *data_, size_t data_len_)\n{\n    size_t nbytes = 0;\n\n    const int status = pgm_send (sock, data_, data_len_, &nbytes);\n\n    //  We have to write all data as one packet.\n    if (nbytes > 0) {\n        zmq_assert (status == PGM_IO_STATUS_NORMAL);\n        zmq_assert (nbytes == data_len_);\n    } else {\n        zmq_assert (status == PGM_IO_STATUS_RATE_LIMITED\n                    || status == PGM_IO_STATUS_WOULD_BLOCK);\n\n        if (status == PGM_IO_STATUS_RATE_LIMITED)\n            errno = ENOMEM;\n        else\n            errno = EBUSY;\n    }\n\n    //  Save return value.\n    last_tx_status = status;\n\n    return nbytes;\n}\n\nlong zmq::pgm_socket_t::get_rx_timeout ()\n{\n    if (last_rx_status != PGM_IO_STATUS_RATE_LIMITED\n        && last_rx_status != PGM_IO_STATUS_TIMER_PENDING)\n        return -1;\n\n    struct timeval tv;\n    socklen_t optlen = sizeof (tv);\n    const bool rc = pgm_getsockopt (sock, IPPROTO_PGM,\n                                    last_rx_status == PGM_IO_STATUS_RATE_LIMITED\n                                      ? PGM_RATE_REMAIN\n                                      : PGM_TIME_REMAIN,\n                                    &tv, &optlen);\n    zmq_assert (rc);\n\n    const long timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);\n\n    return timeout;\n}\n\nlong zmq::pgm_socket_t::get_tx_timeout ()\n{\n    if (last_tx_status != PGM_IO_STATUS_RATE_LIMITED)\n        return -1;\n\n    struct timeval tv;\n    socklen_t optlen = sizeof (tv);\n    const bool rc =\n      pgm_getsockopt (sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);\n    zmq_assert (rc);\n\n    const long timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);\n\n    return timeout;\n}\n\n//  Return max TSDU size without fragmentation from current PGM transport.\nsize_t zmq::pgm_socket_t::get_max_tsdu_size ()\n{\n    int max_tsdu = 0;\n    socklen_t optlen = sizeof (max_tsdu);\n\n    bool rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_MSS, &max_tsdu, &optlen);\n    zmq_assert (rc);\n    zmq_assert (optlen == sizeof (max_tsdu));\n    return (size_t) max_tsdu;\n}\n\n//  pgm_recvmsgv is called to fill the pgm_msgv array up to  pgm_msgv_len.\n//  In subsequent calls data from pgm_msgv structure are returned.\nssize_t zmq::pgm_socket_t::receive (void **raw_data_, const pgm_tsi_t **tsi_)\n{\n    size_t raw_data_len = 0;\n\n    //  We just sent all data from pgm_transport_recvmsgv up\n    //  and have to return 0 that another engine in this thread is scheduled.\n    if (nbytes_rec == nbytes_processed && nbytes_rec > 0) {\n        //  Reset all the counters.\n        nbytes_rec = 0;\n        nbytes_processed = 0;\n        pgm_msgv_processed = 0;\n        errno = EAGAIN;\n        return 0;\n    }\n\n    //  If we have are going first time or if we have processed all pgm_msgv_t\n    //  structure previously read from the pgm socket.\n    if (nbytes_rec == nbytes_processed) {\n        //  Check program flow.\n        zmq_assert (pgm_msgv_processed == 0);\n        zmq_assert (nbytes_processed == 0);\n        zmq_assert (nbytes_rec == 0);\n\n        //  Receive a vector of Application Protocol Domain Unit's (APDUs)\n        //  from the transport.\n        pgm_error_t *pgm_error = NULL;\n\n        const int status = pgm_recvmsgv (sock, pgm_msgv, pgm_msgv_len,\n                                         MSG_ERRQUEUE, &nbytes_rec, &pgm_error);\n\n        //  Invalid parameters.\n        zmq_assert (status != PGM_IO_STATUS_ERROR);\n\n        last_rx_status = status;\n\n        //  In a case when no ODATA/RDATA fired POLLIN event (SPM...)\n        //  pgm_recvmsg returns PGM_IO_STATUS_TIMER_PENDING.\n        if (status == PGM_IO_STATUS_TIMER_PENDING) {\n            zmq_assert (nbytes_rec == 0);\n\n            //  In case if no RDATA/ODATA caused POLLIN 0 is\n            //  returned.\n            nbytes_rec = 0;\n            errno = EBUSY;\n            return 0;\n        }\n\n        //  Send SPMR, NAK, ACK is rate limited.\n        if (status == PGM_IO_STATUS_RATE_LIMITED) {\n            zmq_assert (nbytes_rec == 0);\n\n            //  In case if no RDATA/ODATA caused POLLIN 0 is returned.\n            nbytes_rec = 0;\n            errno = ENOMEM;\n            return 0;\n        }\n\n        //  No peers and hence no incoming packets.\n        if (status == PGM_IO_STATUS_WOULD_BLOCK) {\n            zmq_assert (nbytes_rec == 0);\n\n            //  In case if no RDATA/ODATA caused POLLIN 0 is returned.\n            nbytes_rec = 0;\n            errno = EAGAIN;\n            return 0;\n        }\n\n        //  Data loss.\n        if (status == PGM_IO_STATUS_RESET) {\n            struct pgm_sk_buff_t *skb = pgm_msgv[0].msgv_skb[0];\n\n            //  Save lost data TSI.\n            *tsi_ = &skb->tsi;\n            nbytes_rec = 0;\n\n            //  In case of dala loss -1 is returned.\n            errno = EINVAL;\n            pgm_free_skb (skb);\n            return -1;\n        }\n\n        zmq_assert (status == PGM_IO_STATUS_NORMAL);\n    } else {\n        zmq_assert (pgm_msgv_processed <= pgm_msgv_len);\n    }\n\n    // Zero byte payloads are valid in PGM, but not 0MQ protocol.\n    zmq_assert (nbytes_rec > 0);\n\n    // Only one APDU per pgm_msgv_t structure is allowed.\n    zmq_assert (pgm_msgv[pgm_msgv_processed].msgv_len == 1);\n\n    struct pgm_sk_buff_t *skb = pgm_msgv[pgm_msgv_processed].msgv_skb[0];\n\n    //  Take pointers from pgm_msgv_t structure.\n    *raw_data_ = skb->data;\n    raw_data_len = skb->len;\n\n    //  Save current TSI.\n    *tsi_ = &skb->tsi;\n\n    //  Move the the next pgm_msgv_t structure.\n    pgm_msgv_processed++;\n    zmq_assert (pgm_msgv_processed <= pgm_msgv_len);\n    nbytes_processed += raw_data_len;\n\n    return raw_data_len;\n}\n\nvoid zmq::pgm_socket_t::process_upstream ()\n{\n    pgm_msgv_t dummy_msg;\n\n    size_t dummy_bytes = 0;\n    pgm_error_t *pgm_error = NULL;\n\n    const int status = pgm_recvmsgv (sock, &dummy_msg, 1, MSG_ERRQUEUE,\n                                     &dummy_bytes, &pgm_error);\n\n    //  Invalid parameters.\n    zmq_assert (status != PGM_IO_STATUS_ERROR);\n\n    //  No data should be returned.\n    zmq_assert (dummy_bytes == 0\n                && (status == PGM_IO_STATUS_TIMER_PENDING\n                    || status == PGM_IO_STATUS_RATE_LIMITED\n                    || status == PGM_IO_STATUS_WOULD_BLOCK));\n\n    last_rx_status = status;\n\n    if (status == PGM_IO_STATUS_TIMER_PENDING)\n        errno = EBUSY;\n    else if (status == PGM_IO_STATUS_RATE_LIMITED)\n        errno = ENOMEM;\n    else\n        errno = EAGAIN;\n}\n\nint zmq::pgm_socket_t::compute_sqns (int tpdu_)\n{\n    //  Convert rate into B/ms.\n    uint64_t rate = uint64_t (options.rate) / 8;\n\n    //  Compute the size of the buffer in bytes.\n    uint64_t size = uint64_t (options.recovery_ivl) * rate;\n\n    //  Translate the size into number of packets.\n    uint64_t sqns = size / tpdu_;\n\n    //  Buffer should be able to hold at least one packet.\n    if (sqns == 0)\n        sqns = 1;\n\n    return (int) sqns;\n}\n\n#endif\n"
  },
  {
    "path": "src/pgm_socket.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __PGM_SOCKET_HPP_INCLUDED__\n#define __PGM_SOCKET_HPP_INCLUDED__\n\n#if defined ZMQ_HAVE_OPENPGM\n\n#ifdef ZMQ_HAVE_WINDOWS\n#define __PGM_WININT_H__\n#endif\n\n#include <pgm/pgm.h>\n\n#if defined(ZMQ_HAVE_OSX) || defined(ZMQ_HAVE_NETBSD)\n#include <pgm/in.h>\n#endif\n\n#include \"fd.hpp\"\n#include \"options.hpp\"\n\nnamespace zmq\n{\n//  Encapsulates PGM socket.\nclass pgm_socket_t\n{\n  public:\n    //  If receiver_ is true PGM transport is not generating SPM packets.\n    pgm_socket_t (bool receiver_, const options_t &options_);\n\n    //  Closes the transport.\n    ~pgm_socket_t ();\n\n    //  Initialize PGM network structures (GSI, GSRs).\n    int init (bool udp_encapsulation_, const char *network_);\n\n    //  Resolve PGM socket address.\n    static int init_address (const char *network_,\n                             struct pgm_addrinfo_t **addr,\n                             uint16_t *port_number);\n\n    //   Get receiver fds and store them into user allocated memory.\n    void get_receiver_fds (fd_t *receive_fd_, fd_t *waiting_pipe_fd_);\n\n    //   Get sender and receiver fds and store it to user allocated\n    //   memory. Receive fd is used to process NAKs from peers.\n    void get_sender_fds (fd_t *send_fd_,\n                         fd_t *receive_fd_,\n                         fd_t *rdata_notify_fd_,\n                         fd_t *pending_notify_fd_);\n\n    //  Send data as one APDU, transmit window owned memory.\n    size_t send (unsigned char *data_, size_t data_len_);\n\n    //  Returns max tsdu size without fragmentation.\n    size_t get_max_tsdu_size ();\n\n    //  Receive data from pgm socket.\n    ssize_t receive (void **data_, const pgm_tsi_t **tsi_);\n\n    long get_rx_timeout ();\n    long get_tx_timeout ();\n\n    //  POLLIN on sender side should mean NAK or SPMR receiving.\n    //  process_upstream function is used to handle such a situation.\n    void process_upstream ();\n\n  private:\n    //  Compute size of the buffer based on rate and recovery interval.\n    int compute_sqns (int tpdu_);\n\n    //  OpenPGM transport.\n    pgm_sock_t *sock;\n\n    int last_rx_status, last_tx_status;\n\n    //  Associated socket options.\n    options_t options;\n\n    //  true when pgm_socket should create receiving side.\n    bool receiver;\n\n    //  Array of pgm_msgv_t structures to store received data\n    //  from the socket (pgm_transport_recvmsgv).\n    pgm_msgv_t *pgm_msgv;\n\n    //  Size of pgm_msgv array.\n    size_t pgm_msgv_len;\n\n    // How many bytes were read from pgm socket.\n    size_t nbytes_rec;\n\n    //  How many bytes were processed from last pgm socket read.\n    size_t nbytes_processed;\n\n    //  How many messages from pgm_msgv were already sent up.\n    size_t pgm_msgv_processed;\n};\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/pipe.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <new>\n#include <stddef.h>\n\n#include \"macros.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n\n#include \"ypipe.hpp\"\n#include \"ypipe_conflate.hpp\"\n\nint zmq::pipepair (object_t *parents_[2],\n                   pipe_t *pipes_[2],\n                   const int hwms_[2],\n                   const bool conflate_[2])\n{\n    //   Creates two pipe objects. These objects are connected by two ypipes,\n    //   each to pass messages in one direction.\n\n    typedef ypipe_t<msg_t, message_pipe_granularity> upipe_normal_t;\n    typedef ypipe_conflate_t<msg_t> upipe_conflate_t;\n\n    pipe_t::upipe_t *upipe1;\n    if (conflate_[0])\n        upipe1 = new (std::nothrow) upipe_conflate_t ();\n    else\n        upipe1 = new (std::nothrow) upipe_normal_t ();\n    alloc_assert (upipe1);\n\n    pipe_t::upipe_t *upipe2;\n    if (conflate_[1])\n        upipe2 = new (std::nothrow) upipe_conflate_t ();\n    else\n        upipe2 = new (std::nothrow) upipe_normal_t ();\n    alloc_assert (upipe2);\n\n    pipes_[0] = new (std::nothrow)\n      pipe_t (parents_[0], upipe1, upipe2, hwms_[1], hwms_[0], conflate_[0]);\n    alloc_assert (pipes_[0]);\n    pipes_[1] = new (std::nothrow)\n      pipe_t (parents_[1], upipe2, upipe1, hwms_[0], hwms_[1], conflate_[1]);\n    alloc_assert (pipes_[1]);\n\n    pipes_[0]->set_peer (pipes_[1]);\n    pipes_[1]->set_peer (pipes_[0]);\n\n    return 0;\n}\n\nvoid zmq::send_routing_id (pipe_t *pipe_, const options_t &options_)\n{\n    zmq::msg_t id;\n    const int rc = id.init_size (options_.routing_id_size);\n    errno_assert (rc == 0);\n    memcpy (id.data (), options_.routing_id, options_.routing_id_size);\n    id.set_flags (zmq::msg_t::routing_id);\n    const bool written = pipe_->write (&id);\n    zmq_assert (written);\n    pipe_->flush ();\n}\n\nvoid zmq::send_hello_msg (pipe_t *pipe_, const options_t &options_)\n{\n    zmq::msg_t hello;\n    const int rc =\n      hello.init_buffer (&options_.hello_msg[0], options_.hello_msg.size ());\n    errno_assert (rc == 0);\n    const bool written = pipe_->write (&hello);\n    zmq_assert (written);\n    pipe_->flush ();\n}\n\nzmq::pipe_t::pipe_t (object_t *parent_,\n                     upipe_t *inpipe_,\n                     upipe_t *outpipe_,\n                     int inhwm_,\n                     int outhwm_,\n                     bool conflate_) :\n    object_t (parent_),\n    _in_pipe (inpipe_),\n    _out_pipe (outpipe_),\n    _in_active (true),\n    _out_active (true),\n    _hwm (outhwm_),\n    _lwm (compute_lwm (inhwm_)),\n    _in_hwm_boost (-1),\n    _out_hwm_boost (-1),\n    _msgs_read (0),\n    _msgs_written (0),\n    _peers_msgs_read (0),\n    _peer (NULL),\n    _sink (NULL),\n    _state (active),\n    _delay (true),\n    _server_socket_routing_id (0),\n    _conflate (conflate_)\n{\n    _disconnect_msg.init ();\n}\n\nzmq::pipe_t::~pipe_t ()\n{\n    _disconnect_msg.close ();\n}\n\nvoid zmq::pipe_t::set_peer (pipe_t *peer_)\n{\n    //  Peer can be set once only.\n    zmq_assert (!_peer);\n    _peer = peer_;\n}\n\nvoid zmq::pipe_t::set_event_sink (i_pipe_events *sink_)\n{\n    // Sink can be set once only.\n    zmq_assert (!_sink);\n    _sink = sink_;\n}\n\nvoid zmq::pipe_t::set_server_socket_routing_id (\n  uint32_t server_socket_routing_id_)\n{\n    _server_socket_routing_id = server_socket_routing_id_;\n}\n\nuint32_t zmq::pipe_t::get_server_socket_routing_id () const\n{\n    return _server_socket_routing_id;\n}\n\nvoid zmq::pipe_t::set_router_socket_routing_id (\n  const blob_t &router_socket_routing_id_)\n{\n    _router_socket_routing_id.set_deep_copy (router_socket_routing_id_);\n}\n\nconst zmq::blob_t &zmq::pipe_t::get_routing_id () const\n{\n    return _router_socket_routing_id;\n}\n\nbool zmq::pipe_t::check_read ()\n{\n    if (unlikely (!_in_active))\n        return false;\n    if (unlikely (_state != active && _state != waiting_for_delimiter))\n        return false;\n\n    //  Check if there's an item in the pipe.\n    if (!_in_pipe->check_read ()) {\n        _in_active = false;\n        return false;\n    }\n\n    //  If the next item in the pipe is message delimiter,\n    //  initiate termination process.\n    if (_in_pipe->probe (is_delimiter)) {\n        msg_t msg;\n        const bool ok = _in_pipe->read (&msg);\n        zmq_assert (ok);\n        process_delimiter ();\n        return false;\n    }\n\n    return true;\n}\n\nbool zmq::pipe_t::read (msg_t *msg_)\n{\n    if (unlikely (!_in_active))\n        return false;\n    if (unlikely (_state != active && _state != waiting_for_delimiter))\n        return false;\n\n    while (true) {\n        if (!_in_pipe->read (msg_)) {\n            _in_active = false;\n            return false;\n        }\n\n        //  If this is a credential, ignore it and receive next message.\n        if (unlikely (msg_->is_credential ())) {\n            const int rc = msg_->close ();\n            zmq_assert (rc == 0);\n        } else {\n            break;\n        }\n    }\n\n    //  If delimiter was read, start termination process of the pipe.\n    if (msg_->is_delimiter ()) {\n        process_delimiter ();\n        return false;\n    }\n\n    if (!(msg_->flags () & msg_t::more) && !msg_->is_routing_id ())\n        _msgs_read++;\n\n    if (_lwm > 0 && _msgs_read % _lwm == 0)\n        send_activate_write (_peer, _msgs_read);\n\n    return true;\n}\n\nbool zmq::pipe_t::check_write ()\n{\n    if (unlikely (!_out_active || _state != active))\n        return false;\n\n    const bool full = !check_hwm ();\n\n    if (unlikely (full)) {\n        _out_active = false;\n        return false;\n    }\n\n    return true;\n}\n\nbool zmq::pipe_t::write (const msg_t *msg_)\n{\n    if (unlikely (!check_write ()))\n        return false;\n\n    const bool more = (msg_->flags () & msg_t::more) != 0;\n    const bool is_routing_id = msg_->is_routing_id ();\n    _out_pipe->write (*msg_, more);\n    if (!more && !is_routing_id)\n        _msgs_written++;\n\n    return true;\n}\n\nvoid zmq::pipe_t::rollback () const\n{\n    //  Remove incomplete message from the outbound pipe.\n    msg_t msg;\n    if (_out_pipe) {\n        while (_out_pipe->unwrite (&msg)) {\n            zmq_assert (msg.flags () & msg_t::more);\n            const int rc = msg.close ();\n            errno_assert (rc == 0);\n        }\n    }\n}\n\nvoid zmq::pipe_t::flush ()\n{\n    //  The peer does not exist anymore at this point.\n    if (_state == term_ack_sent)\n        return;\n\n    if (_out_pipe && !_out_pipe->flush ())\n        send_activate_read (_peer);\n}\n\nvoid zmq::pipe_t::process_activate_read ()\n{\n    if (!_in_active && (_state == active || _state == waiting_for_delimiter)) {\n        _in_active = true;\n        _sink->read_activated (this);\n    }\n}\n\nvoid zmq::pipe_t::process_activate_write (uint64_t msgs_read_)\n{\n    //  Remember the peer's message sequence number.\n    _peers_msgs_read = msgs_read_;\n\n    if (!_out_active && _state == active) {\n        _out_active = true;\n        _sink->write_activated (this);\n    }\n}\n\nvoid zmq::pipe_t::process_hiccup (void *pipe_)\n{\n    //  Destroy old outpipe. Note that the read end of the pipe was already\n    //  migrated to this thread.\n    zmq_assert (_out_pipe);\n    _out_pipe->flush ();\n    msg_t msg;\n    while (_out_pipe->read (&msg)) {\n        if (!(msg.flags () & msg_t::more))\n            _msgs_written--;\n        const int rc = msg.close ();\n        errno_assert (rc == 0);\n    }\n    LIBZMQ_DELETE (_out_pipe);\n\n    //  Plug in the new outpipe.\n    zmq_assert (pipe_);\n    _out_pipe = static_cast<upipe_t *> (pipe_);\n    _out_active = true;\n\n    //  If appropriate, notify the user about the hiccup.\n    if (_state == active)\n        _sink->hiccuped (this);\n}\n\nvoid zmq::pipe_t::process_pipe_term ()\n{\n    zmq_assert (_state == active || _state == delimiter_received\n                || _state == term_req_sent1);\n\n    //  This is the simple case of peer-induced termination. If there are no\n    //  more pending messages to read, or if the pipe was configured to drop\n    //  pending messages, we can move directly to the term_ack_sent state.\n    //  Otherwise we'll hang up in waiting_for_delimiter state till all\n    //  pending messages are read.\n    if (_state == active) {\n        if (_delay)\n            _state = waiting_for_delimiter;\n        else {\n            _state = term_ack_sent;\n            _out_pipe = NULL;\n            send_pipe_term_ack (_peer);\n        }\n    }\n\n    //  Delimiter happened to arrive before the term command. Now we have the\n    //  term command as well, so we can move straight to term_ack_sent state.\n    else if (_state == delimiter_received) {\n        _state = term_ack_sent;\n        _out_pipe = NULL;\n        send_pipe_term_ack (_peer);\n    }\n\n    //  This is the case where both ends of the pipe are closed in parallel.\n    //  We simply reply to the request by ack and continue waiting for our\n    //  own ack.\n    else if (_state == term_req_sent1) {\n        _state = term_req_sent2;\n        _out_pipe = NULL;\n        send_pipe_term_ack (_peer);\n    }\n}\n\nvoid zmq::pipe_t::process_pipe_term_ack ()\n{\n    //  Notify the user that all the references to the pipe should be dropped.\n    zmq_assert (_sink);\n    _sink->pipe_terminated (this);\n\n    //  In term_ack_sent and term_req_sent2 states there's nothing to do.\n    //  Simply deallocate the pipe. In term_req_sent1 state we have to ack\n    //  the peer before deallocating this side of the pipe.\n    //  All the other states are invalid.\n    if (_state == term_req_sent1) {\n        _out_pipe = NULL;\n        send_pipe_term_ack (_peer);\n    } else\n        zmq_assert (_state == term_ack_sent || _state == term_req_sent2);\n\n    //  We'll deallocate the inbound pipe, the peer will deallocate the outbound\n    //  pipe (which is an inbound pipe from its point of view).\n    //  First, delete all the unread messages in the pipe. We have to do it by\n    //  hand because msg_t doesn't have automatic destructor. Then deallocate\n    //  the ypipe itself.\n\n    if (!_conflate) {\n        msg_t msg;\n        while (_in_pipe->read (&msg)) {\n            const int rc = msg.close ();\n            errno_assert (rc == 0);\n        }\n    }\n\n    LIBZMQ_DELETE (_in_pipe);\n\n    //  Deallocate the pipe object\n    delete this;\n}\n\nvoid zmq::pipe_t::process_pipe_hwm (int inhwm_, int outhwm_)\n{\n    set_hwms (inhwm_, outhwm_);\n}\n\nvoid zmq::pipe_t::set_nodelay ()\n{\n    this->_delay = false;\n}\n\nvoid zmq::pipe_t::terminate (bool delay_)\n{\n    //  Overload the value specified at pipe creation.\n    _delay = delay_;\n\n    //  If terminate was already called, we can ignore the duplicate invocation.\n    if (_state == term_req_sent1 || _state == term_req_sent2) {\n        return;\n    }\n    //  If the pipe is in the final phase of async termination, it's going to\n    //  closed anyway. No need to do anything special here.\n    if (_state == term_ack_sent) {\n        return;\n    }\n    //  The simple sync termination case. Ask the peer to terminate and wait\n    //  for the ack.\n    if (_state == active) {\n        send_pipe_term (_peer);\n        _state = term_req_sent1;\n    }\n    //  There are still pending messages available, but the user calls\n    //  'terminate'. We can act as if all the pending messages were read.\n    else if (_state == waiting_for_delimiter && !_delay) {\n        //  Drop any unfinished outbound messages.\n        rollback ();\n        _out_pipe = NULL;\n        send_pipe_term_ack (_peer);\n        _state = term_ack_sent;\n    }\n    //  If there are pending messages still available, do nothing.\n    else if (_state == waiting_for_delimiter) {\n    }\n    //  We've already got delimiter, but not term command yet. We can ignore\n    //  the delimiter and ack synchronously terminate as if we were in\n    //  active state.\n    else if (_state == delimiter_received) {\n        send_pipe_term (_peer);\n        _state = term_req_sent1;\n    }\n    //  There are no other states.\n    else {\n        zmq_assert (false);\n    }\n\n    //  Stop outbound flow of messages.\n    _out_active = false;\n\n    if (_out_pipe) {\n        //  Drop any unfinished outbound messages.\n        rollback ();\n\n        //  Write the delimiter into the pipe. Note that watermarks are not\n        //  checked; thus the delimiter can be written even when the pipe is full.\n        msg_t msg;\n        msg.init_delimiter ();\n        _out_pipe->write (msg, false);\n        flush ();\n    }\n}\n\nbool zmq::pipe_t::is_delimiter (const msg_t &msg_)\n{\n    return msg_.is_delimiter ();\n}\n\nint zmq::pipe_t::compute_lwm (int hwm_)\n{\n    //  Compute the low water mark. Following point should be taken\n    //  into consideration:\n    //\n    //  1. LWM has to be less than HWM.\n    //  2. LWM cannot be set to very low value (such as zero) as after filling\n    //     the queue it would start to refill only after all the messages are\n    //     read from it and thus unnecessarily hold the progress back.\n    //  3. LWM cannot be set to very high value (such as HWM-1) as it would\n    //     result in lock-step filling of the queue - if a single message is\n    //     read from a full queue, writer thread is resumed to write exactly one\n    //     message to the queue and go back to sleep immediately. This would\n    //     result in low performance.\n    //\n    //  Given the 3. it would be good to keep HWM and LWM as far apart as\n    //  possible to reduce the thread switching overhead to almost zero.\n    //  Let's make LWM 1/2 of HWM.\n    const int result = (hwm_ + 1) / 2;\n\n    return result;\n}\n\nvoid zmq::pipe_t::process_delimiter ()\n{\n    zmq_assert (_state == active || _state == waiting_for_delimiter);\n\n    if (_state == active)\n        _state = delimiter_received;\n    else {\n        rollback ();\n        _out_pipe = NULL;\n        send_pipe_term_ack (_peer);\n        _state = term_ack_sent;\n    }\n}\n\nvoid zmq::pipe_t::hiccup ()\n{\n    //  If termination is already under way do nothing.\n    if (_state != active)\n        return;\n\n    //  We'll drop the pointer to the inpipe. From now on, the peer is\n    //  responsible for deallocating it.\n\n    //  Create new inpipe.\n    _in_pipe =\n      _conflate\n        ? static_cast<upipe_t *> (new (std::nothrow) ypipe_conflate_t<msg_t> ())\n        : new (std::nothrow) ypipe_t<msg_t, message_pipe_granularity> ();\n\n    alloc_assert (_in_pipe);\n    _in_active = true;\n\n    //  Notify the peer about the hiccup.\n    send_hiccup (_peer, _in_pipe);\n}\n\nvoid zmq::pipe_t::set_hwms (int inhwm_, int outhwm_)\n{\n    int in = inhwm_ + std::max (_in_hwm_boost, 0);\n    int out = outhwm_ + std::max (_out_hwm_boost, 0);\n\n    // if either send or recv side has hwm <= 0 it means infinite so we should set hwms infinite\n    if (inhwm_ <= 0 || _in_hwm_boost == 0)\n        in = 0;\n\n    if (outhwm_ <= 0 || _out_hwm_boost == 0)\n        out = 0;\n\n    _lwm = compute_lwm (in);\n    _hwm = out;\n}\n\nvoid zmq::pipe_t::set_hwms_boost (int inhwmboost_, int outhwmboost_)\n{\n    _in_hwm_boost = inhwmboost_;\n    _out_hwm_boost = outhwmboost_;\n}\n\nbool zmq::pipe_t::check_hwm () const\n{\n    const bool full =\n      _hwm > 0 && _msgs_written - _peers_msgs_read >= uint64_t (_hwm);\n    return !full;\n}\n\nvoid zmq::pipe_t::send_hwms_to_peer (int inhwm_, int outhwm_)\n{\n    if (_state == active)\n        send_pipe_hwm (_peer, inhwm_, outhwm_);\n}\n\nvoid zmq::pipe_t::set_endpoint_pair (zmq::endpoint_uri_pair_t endpoint_pair_)\n{\n    _endpoint_pair = ZMQ_MOVE (endpoint_pair_);\n}\n\nconst zmq::endpoint_uri_pair_t &zmq::pipe_t::get_endpoint_pair () const\n{\n    return _endpoint_pair;\n}\n\nvoid zmq::pipe_t::send_stats_to_peer (own_t *socket_base_)\n{\n    if (_state == active) {\n        endpoint_uri_pair_t *ep =\n          new (std::nothrow) endpoint_uri_pair_t (_endpoint_pair);\n        send_pipe_peer_stats (_peer, _msgs_written - _peers_msgs_read,\n                              socket_base_, ep);\n    }\n}\n\nvoid zmq::pipe_t::process_pipe_peer_stats (uint64_t queue_count_,\n                                           own_t *socket_base_,\n                                           endpoint_uri_pair_t *endpoint_pair_)\n{\n    send_pipe_stats_publish (socket_base_, queue_count_,\n                             _msgs_written - _peers_msgs_read, endpoint_pair_);\n}\n\nvoid zmq::pipe_t::send_disconnect_msg ()\n{\n    if (_disconnect_msg.size () > 0 && _out_pipe) {\n        // Rollback any incomplete message in the pipe, and push the disconnect message.\n        rollback ();\n\n        _out_pipe->write (_disconnect_msg, false);\n        flush ();\n        _disconnect_msg.init ();\n    }\n}\n\nvoid zmq::pipe_t::set_disconnect_msg (\n  const std::vector<unsigned char> &disconnect_)\n{\n    _disconnect_msg.close ();\n    const int rc =\n      _disconnect_msg.init_buffer (&disconnect_[0], disconnect_.size ());\n    errno_assert (rc == 0);\n}\n\nvoid zmq::pipe_t::send_hiccup_msg (const std::vector<unsigned char> &hiccup_)\n{\n    if (!hiccup_.empty () && _out_pipe) {\n        msg_t msg;\n        const int rc = msg.init_buffer (&hiccup_[0], hiccup_.size ());\n        errno_assert (rc == 0);\n\n        _out_pipe->write (msg, false);\n        flush ();\n    }\n}\n"
  },
  {
    "path": "src/pipe.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PIPE_HPP_INCLUDED__\n#define __ZMQ_PIPE_HPP_INCLUDED__\n\n#include \"ypipe_base.hpp\"\n#include \"config.hpp\"\n#include \"object.hpp\"\n#include \"stdint.hpp\"\n#include \"array.hpp\"\n#include \"blob.hpp\"\n#include \"options.hpp\"\n#include \"endpoint.hpp\"\n#include \"msg.hpp\"\n\nnamespace zmq\n{\nclass pipe_t;\n\n//  Create a pipepair for bi-directional transfer of messages.\n//  First HWM is for messages passed from first pipe to the second pipe.\n//  Second HWM is for messages passed from second pipe to the first pipe.\n//  Delay specifies how the pipe behaves when the peer terminates. If true\n//  pipe receives all the pending messages before terminating, otherwise it\n//  terminates straight away.\n//  If conflate is true, only the most recently arrived message could be\n//  read (older messages are discarded)\nint pipepair (zmq::object_t *parents_[2],\n              zmq::pipe_t *pipes_[2],\n              const int hwms_[2],\n              const bool conflate_[2]);\n\nstruct i_pipe_events\n{\n    virtual ~i_pipe_events () ZMQ_DEFAULT;\n\n    virtual void read_activated (zmq::pipe_t *pipe_) = 0;\n    virtual void write_activated (zmq::pipe_t *pipe_) = 0;\n    virtual void hiccuped (zmq::pipe_t *pipe_) = 0;\n    virtual void pipe_terminated (zmq::pipe_t *pipe_) = 0;\n};\n\n//  Note that pipe can be stored in three different arrays.\n//  The array of inbound pipes (1), the array of outbound pipes (2) and\n//  the generic array of pipes to be deallocated (3).\n\nclass pipe_t ZMQ_FINAL : public object_t,\n                         public array_item_t<1>,\n                         public array_item_t<2>,\n                         public array_item_t<3>\n{\n    //  This allows pipepair to create pipe objects.\n    friend int pipepair (zmq::object_t *parents_[2],\n                         zmq::pipe_t *pipes_[2],\n                         const int hwms_[2],\n                         const bool conflate_[2]);\n\n  public:\n    //  Specifies the object to send events to.\n    void set_event_sink (i_pipe_events *sink_);\n\n    //  Pipe endpoint can store an routing ID to be used by its clients.\n    void set_server_socket_routing_id (uint32_t server_socket_routing_id_);\n    uint32_t get_server_socket_routing_id () const;\n\n    //  Pipe endpoint can store an opaque ID to be used by its clients.\n    void set_router_socket_routing_id (const blob_t &router_socket_routing_id_);\n    const blob_t &get_routing_id () const;\n\n    //  Returns true if there is at least one message to read in the pipe.\n    bool check_read ();\n\n    //  Reads a message to the underlying pipe.\n    bool read (msg_t *msg_);\n\n    //  Checks whether messages can be written to the pipe. If the pipe is\n    //  closed or if writing the message would cause high watermark the\n    //  function returns false.\n    bool check_write ();\n\n    //  Writes a message to the underlying pipe. Returns false if the\n    //  message does not pass check_write. If false, the message object\n    //  retains ownership of its message buffer.\n    bool write (const msg_t *msg_);\n\n    //  Remove unfinished parts of the outbound message from the pipe.\n    void rollback () const;\n\n    //  Flush the messages downstream.\n    void flush ();\n\n    //  Temporarily disconnects the inbound message stream and drops\n    //  all the messages on the fly. Causes 'hiccuped' event to be generated\n    //  in the peer.\n    void hiccup ();\n\n    //  Ensure the pipe won't block on receiving pipe_term.\n    void set_nodelay ();\n\n    //  Ask pipe to terminate. The termination will happen asynchronously\n    //  and user will be notified about actual deallocation by 'terminated'\n    //  event. If delay is true, the pending messages will be processed\n    //  before actual shutdown.\n    void terminate (bool delay_);\n\n    //  Set the high water marks.\n    void set_hwms (int inhwm_, int outhwm_);\n\n    //  Set the boost to high water marks, used by inproc sockets so total hwm are sum of connect and bind sockets watermarks\n    void set_hwms_boost (int inhwmboost_, int outhwmboost_);\n\n    // send command to peer for notify the change of hwm\n    void send_hwms_to_peer (int inhwm_, int outhwm_);\n\n    //  Returns true if HWM is not reached\n    bool check_hwm () const;\n\n    void set_endpoint_pair (endpoint_uri_pair_t endpoint_pair_);\n    const endpoint_uri_pair_t &get_endpoint_pair () const;\n\n    void send_stats_to_peer (own_t *socket_base_);\n\n    void send_disconnect_msg ();\n    void set_disconnect_msg (const std::vector<unsigned char> &disconnect_);\n\n    void send_hiccup_msg (const std::vector<unsigned char> &hiccup_);\n\n  private:\n    //  Type of the underlying lock-free pipe.\n    typedef ypipe_base_t<msg_t> upipe_t;\n\n    //  Command handlers.\n    void process_activate_read () ZMQ_OVERRIDE;\n    void process_activate_write (uint64_t msgs_read_) ZMQ_OVERRIDE;\n    void process_hiccup (void *pipe_) ZMQ_OVERRIDE;\n    void\n    process_pipe_peer_stats (uint64_t queue_count_,\n                             own_t *socket_base_,\n                             endpoint_uri_pair_t *endpoint_pair_) ZMQ_OVERRIDE;\n    void process_pipe_term () ZMQ_OVERRIDE;\n    void process_pipe_term_ack () ZMQ_OVERRIDE;\n    void process_pipe_hwm (int inhwm_, int outhwm_) ZMQ_OVERRIDE;\n\n    //  Handler for delimiter read from the pipe.\n    void process_delimiter ();\n\n    //  Constructor is private. Pipe can only be created using\n    //  pipepair function.\n    pipe_t (object_t *parent_,\n            upipe_t *inpipe_,\n            upipe_t *outpipe_,\n            int inhwm_,\n            int outhwm_,\n            bool conflate_);\n\n    //  Pipepair uses this function to let us know about\n    //  the peer pipe object.\n    void set_peer (pipe_t *peer_);\n\n    //  Destructor is private. Pipe objects destroy themselves.\n    ~pipe_t () ZMQ_OVERRIDE;\n\n    //  Underlying pipes for both directions.\n    upipe_t *_in_pipe;\n    upipe_t *_out_pipe;\n\n    //  Can the pipe be read from / written to?\n    bool _in_active;\n    bool _out_active;\n\n    //  High watermark for the outbound pipe.\n    int _hwm;\n\n    //  Low watermark for the inbound pipe.\n    int _lwm;\n\n    // boosts for high and low watermarks, used with inproc sockets so hwm are sum of send and recv hmws on each side of pipe\n    int _in_hwm_boost;\n    int _out_hwm_boost;\n\n    //  Number of messages read and written so far.\n    uint64_t _msgs_read;\n    uint64_t _msgs_written;\n\n    //  Last received peer's msgs_read. The actual number in the peer\n    //  can be higher at the moment.\n    uint64_t _peers_msgs_read;\n\n    //  The pipe object on the other side of the pipepair.\n    pipe_t *_peer;\n\n    //  Sink to send events to.\n    i_pipe_events *_sink;\n\n    //  States of the pipe endpoint:\n    //  active: common state before any termination begins,\n    //  delimiter_received: delimiter was read from pipe before\n    //      term command was received,\n    //  waiting_for_delimiter: term command was already received\n    //      from the peer but there are still pending messages to read,\n    //  term_ack_sent: all pending messages were already read and\n    //      all we are waiting for is ack from the peer,\n    //  term_req_sent1: 'terminate' was explicitly called by the user,\n    //  term_req_sent2: user called 'terminate' and then we've got\n    //      term command from the peer as well.\n    enum\n    {\n        active,\n        delimiter_received,\n        waiting_for_delimiter,\n        term_ack_sent,\n        term_req_sent1,\n        term_req_sent2\n    } _state;\n\n    //  If true, we receive all the pending inbound messages before\n    //  terminating. If false, we terminate immediately when the peer\n    //  asks us to.\n    bool _delay;\n\n    //  Routing id of the writer. Used uniquely by the reader side.\n    blob_t _router_socket_routing_id;\n\n    //  Routing id of the writer. Used uniquely by the reader side.\n    int _server_socket_routing_id;\n\n    //  Returns true if the message is delimiter; false otherwise.\n    static bool is_delimiter (const msg_t &msg_);\n\n    //  Computes appropriate low watermark from the given high watermark.\n    static int compute_lwm (int hwm_);\n\n    const bool _conflate;\n\n    // The endpoints of this pipe.\n    endpoint_uri_pair_t _endpoint_pair;\n\n    // Disconnect msg\n    msg_t _disconnect_msg;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (pipe_t)\n};\n\nvoid send_routing_id (pipe_t *pipe_, const options_t &options_);\n\nvoid send_hello_msg (pipe_t *pipe_, const options_t &options_);\n}\n\n#endif\n"
  },
  {
    "path": "src/plain_client.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n\n#include <string>\n#include <limits.h>\n\n#include \"msg.hpp\"\n#include \"err.hpp\"\n#include \"plain_client.hpp\"\n#include \"session_base.hpp\"\n#include \"plain_common.hpp\"\n\nzmq::plain_client_t::plain_client_t (session_base_t *const session_,\n                                     const options_t &options_) :\n    mechanism_base_t (session_, options_), _state (sending_hello)\n{\n}\n\nzmq::plain_client_t::~plain_client_t ()\n{\n}\n\nint zmq::plain_client_t::next_handshake_command (msg_t *msg_)\n{\n    int rc = 0;\n\n    switch (_state) {\n        case sending_hello:\n            produce_hello (msg_);\n            _state = waiting_for_welcome;\n            break;\n        case sending_initiate:\n            produce_initiate (msg_);\n            _state = waiting_for_ready;\n            break;\n        default:\n            errno = EAGAIN;\n            rc = -1;\n    }\n    return rc;\n}\n\nint zmq::plain_client_t::process_handshake_command (msg_t *msg_)\n{\n    const unsigned char *cmd_data =\n      static_cast<unsigned char *> (msg_->data ());\n    const size_t data_size = msg_->size ();\n\n    int rc = 0;\n    if (data_size >= welcome_prefix_len\n        && !memcmp (cmd_data, welcome_prefix, welcome_prefix_len))\n        rc = process_welcome (cmd_data, data_size);\n    else if (data_size >= ready_prefix_len\n             && !memcmp (cmd_data, ready_prefix, ready_prefix_len))\n        rc = process_ready (cmd_data, data_size);\n    else if (data_size >= error_prefix_len\n             && !memcmp (cmd_data, error_prefix, error_prefix_len))\n        rc = process_error (cmd_data, data_size);\n    else {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        rc = -1;\n    }\n\n    if (rc == 0) {\n        rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n    }\n\n    return rc;\n}\n\nzmq::mechanism_t::status_t zmq::plain_client_t::status () const\n{\n    switch (_state) {\n        case ready:\n            return mechanism_t::ready;\n        case error_command_received:\n            return mechanism_t::error;\n        default:\n            return mechanism_t::handshaking;\n    }\n}\n\nvoid zmq::plain_client_t::produce_hello (msg_t *msg_) const\n{\n    const std::string username = options.plain_username;\n    zmq_assert (username.length () <= UCHAR_MAX);\n\n    const std::string password = options.plain_password;\n    zmq_assert (password.length () <= UCHAR_MAX);\n\n    const size_t command_size = hello_prefix_len + brief_len_size\n                                + username.length () + brief_len_size\n                                + password.length ();\n\n    const int rc = msg_->init_size (command_size);\n    errno_assert (rc == 0);\n\n    unsigned char *ptr = static_cast<unsigned char *> (msg_->data ());\n    memcpy (ptr, hello_prefix, hello_prefix_len);\n    ptr += hello_prefix_len;\n\n    *ptr++ = static_cast<unsigned char> (username.length ());\n    memcpy (ptr, username.c_str (), username.length ());\n    ptr += username.length ();\n\n    *ptr++ = static_cast<unsigned char> (password.length ());\n    memcpy (ptr, password.c_str (), password.length ());\n}\n\nint zmq::plain_client_t::process_welcome (const unsigned char *cmd_data_,\n                                          size_t data_size_)\n{\n    LIBZMQ_UNUSED (cmd_data_);\n\n    if (_state != waiting_for_welcome) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n    if (data_size_ != welcome_prefix_len) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME);\n        errno = EPROTO;\n        return -1;\n    }\n    _state = sending_initiate;\n    return 0;\n}\n\nvoid zmq::plain_client_t::produce_initiate (msg_t *msg_) const\n{\n    make_command_with_basic_properties (msg_, initiate_prefix,\n                                        initiate_prefix_len);\n}\n\nint zmq::plain_client_t::process_ready (const unsigned char *cmd_data_,\n                                        size_t data_size_)\n{\n    if (_state != waiting_for_ready) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n    const int rc = parse_metadata (cmd_data_ + ready_prefix_len,\n                                   data_size_ - ready_prefix_len);\n    if (rc == 0)\n        _state = ready;\n    else\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA);\n\n    return rc;\n}\n\nint zmq::plain_client_t::process_error (const unsigned char *cmd_data_,\n                                        size_t data_size_)\n{\n    if (_state != waiting_for_welcome && _state != waiting_for_ready) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n    const size_t start_of_error_reason = error_prefix_len + brief_len_size;\n    if (data_size_ < start_of_error_reason) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);\n        errno = EPROTO;\n        return -1;\n    }\n    const size_t error_reason_len =\n      static_cast<size_t> (cmd_data_[error_prefix_len]);\n    if (error_reason_len > data_size_ - start_of_error_reason) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);\n        errno = EPROTO;\n        return -1;\n    }\n    const char *error_reason =\n      reinterpret_cast<const char *> (cmd_data_) + start_of_error_reason;\n    handle_error_reason (error_reason, error_reason_len);\n    _state = error_command_received;\n    return 0;\n}\n"
  },
  {
    "path": "src/plain_client.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PLAIN_CLIENT_HPP_INCLUDED__\n#define __ZMQ_PLAIN_CLIENT_HPP_INCLUDED__\n\n#include \"mechanism_base.hpp\"\n#include \"options.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\n\nclass plain_client_t ZMQ_FINAL : public mechanism_base_t\n{\n  public:\n    plain_client_t (session_base_t *session_, const options_t &options_);\n    ~plain_client_t ();\n\n    // mechanism implementation\n    int next_handshake_command (msg_t *msg_);\n    int process_handshake_command (msg_t *msg_);\n    status_t status () const;\n\n  private:\n    enum state_t\n    {\n        sending_hello,\n        waiting_for_welcome,\n        sending_initiate,\n        waiting_for_ready,\n        error_command_received,\n        ready\n    };\n\n    state_t _state;\n\n    void produce_hello (msg_t *msg_) const;\n    void produce_initiate (msg_t *msg_) const;\n\n    int process_welcome (const unsigned char *cmd_data_, size_t data_size_);\n    int process_ready (const unsigned char *cmd_data_, size_t data_size_);\n    int process_error (const unsigned char *cmd_data_, size_t data_size_);\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/plain_common.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PLAIN_COMMON_HPP_INCLUDED__\n#define __ZMQ_PLAIN_COMMON_HPP_INCLUDED__\n\nnamespace zmq\n{\nconst char hello_prefix[] = \"\\x05HELLO\";\nconst size_t hello_prefix_len = sizeof (hello_prefix) - 1;\n\nconst char welcome_prefix[] = \"\\x07WELCOME\";\nconst size_t welcome_prefix_len = sizeof (welcome_prefix) - 1;\n\nconst char initiate_prefix[] = \"\\x08INITIATE\";\nconst size_t initiate_prefix_len = sizeof (initiate_prefix) - 1;\n\nconst char ready_prefix[] = \"\\x05READY\";\nconst size_t ready_prefix_len = sizeof (ready_prefix) - 1;\n\nconst char error_prefix[] = \"\\x05ERROR\";\nconst size_t error_prefix_len = sizeof (error_prefix) - 1;\n\nconst size_t brief_len_size = sizeof (char);\n}\n\n#endif\n"
  },
  {
    "path": "src/plain_server.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include <string>\n\n#include \"msg.hpp\"\n#include \"session_base.hpp\"\n#include \"err.hpp\"\n#include \"plain_server.hpp\"\n#include \"wire.hpp\"\n#include \"plain_common.hpp\"\n\nzmq::plain_server_t::plain_server_t (session_base_t *session_,\n                                     const std::string &peer_address_,\n                                     const options_t &options_) :\n    mechanism_base_t (session_, options_),\n    zap_client_common_handshake_t (\n      session_, peer_address_, options_, sending_welcome)\n{\n    //  Note that there is no point to PLAIN if ZAP is not set up to handle the\n    //  username and password, so if ZAP is not configured it is considered a\n    //  failure.\n    //  Given this is a backward-incompatible change, it's behind a socket\n    //  option disabled by default.\n    if (options.zap_enforce_domain)\n        zmq_assert (zap_required ());\n}\n\nzmq::plain_server_t::~plain_server_t ()\n{\n}\n\nint zmq::plain_server_t::next_handshake_command (msg_t *msg_)\n{\n    int rc = 0;\n\n    switch (state) {\n        case sending_welcome:\n            produce_welcome (msg_);\n            state = waiting_for_initiate;\n            break;\n        case sending_ready:\n            produce_ready (msg_);\n            state = ready;\n            break;\n        case sending_error:\n            produce_error (msg_);\n            state = error_sent;\n            break;\n        default:\n            errno = EAGAIN;\n            rc = -1;\n    }\n    return rc;\n}\n\nint zmq::plain_server_t::process_handshake_command (msg_t *msg_)\n{\n    int rc = 0;\n\n    switch (state) {\n        case waiting_for_hello:\n            rc = process_hello (msg_);\n            break;\n        case waiting_for_initiate:\n            rc = process_initiate (msg_);\n            break;\n        default:\n            //  TODO see comment in curve_server_t::process_handshake_command\n            session->get_socket ()->event_handshake_failed_protocol (\n              session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED);\n            errno = EPROTO;\n            rc = -1;\n            break;\n    }\n    if (rc == 0) {\n        rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n    }\n    return rc;\n}\n\nint zmq::plain_server_t::process_hello (msg_t *msg_)\n{\n    int rc = check_basic_command_structure (msg_);\n    if (rc == -1)\n        return -1;\n\n    const char *ptr = static_cast<char *> (msg_->data ());\n    size_t bytes_left = msg_->size ();\n\n    if (bytes_left < hello_prefix_len\n        || memcmp (ptr, hello_prefix, hello_prefix_len) != 0) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n    ptr += hello_prefix_len;\n    bytes_left -= hello_prefix_len;\n\n    if (bytes_left < 1) {\n        //  PLAIN I: invalid PLAIN client, did not send username\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);\n        errno = EPROTO;\n        return -1;\n    }\n    const uint8_t username_length = *ptr++;\n    bytes_left -= sizeof (username_length);\n\n    if (bytes_left < username_length) {\n        //  PLAIN I: invalid PLAIN client, sent malformed username\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);\n        errno = EPROTO;\n        return -1;\n    }\n    const std::string username = std::string (ptr, username_length);\n    ptr += username_length;\n    bytes_left -= username_length;\n    if (bytes_left < 1) {\n        //  PLAIN I: invalid PLAIN client, did not send password\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);\n        errno = EPROTO;\n        return -1;\n    }\n\n    const uint8_t password_length = *ptr++;\n    bytes_left -= sizeof (password_length);\n    if (bytes_left != password_length) {\n        //  PLAIN I: invalid PLAIN client, sent malformed password or\n        //  extraneous data\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);\n        errno = EPROTO;\n        return -1;\n    }\n\n    const std::string password = std::string (ptr, password_length);\n\n    //  Use ZAP protocol (RFC 27) to authenticate the user.\n    rc = session->zap_connect ();\n    if (rc != 0) {\n        session->get_socket ()->event_handshake_failed_no_detail (\n          session->get_endpoint (), EFAULT);\n        return -1;\n    }\n\n    send_zap_request (username, password);\n    state = waiting_for_zap_reply;\n\n    //  TODO actually, it is quite unlikely that we can read the ZAP\n    //  reply already, but removing this has some strange side-effect\n    //  (probably because the pipe's in_active flag is true until a read\n    //  is attempted)\n    return receive_and_process_zap_reply () == -1 ? -1 : 0;\n}\n\nvoid zmq::plain_server_t::produce_welcome (msg_t *msg_)\n{\n    const int rc = msg_->init_size (welcome_prefix_len);\n    errno_assert (rc == 0);\n    memcpy (msg_->data (), welcome_prefix, welcome_prefix_len);\n}\n\nint zmq::plain_server_t::process_initiate (msg_t *msg_)\n{\n    const unsigned char *ptr = static_cast<unsigned char *> (msg_->data ());\n    const size_t bytes_left = msg_->size ();\n\n    if (bytes_left < initiate_prefix_len\n        || memcmp (ptr, initiate_prefix, initiate_prefix_len) != 0) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n        errno = EPROTO;\n        return -1;\n    }\n    const int rc = parse_metadata (ptr + initiate_prefix_len,\n                                   bytes_left - initiate_prefix_len);\n    if (rc == 0)\n        state = sending_ready;\n    return rc;\n}\n\nvoid zmq::plain_server_t::produce_ready (msg_t *msg_) const\n{\n    make_command_with_basic_properties (msg_, ready_prefix, ready_prefix_len);\n}\n\nvoid zmq::plain_server_t::produce_error (msg_t *msg_) const\n{\n    const char expected_status_code_len = 3;\n    zmq_assert (status_code.length ()\n                == static_cast<size_t> (expected_status_code_len));\n    const size_t status_code_len_size = sizeof (expected_status_code_len);\n    const int rc = msg_->init_size (error_prefix_len + status_code_len_size\n                                    + expected_status_code_len);\n    zmq_assert (rc == 0);\n    char *msg_data = static_cast<char *> (msg_->data ());\n    memcpy (msg_data, error_prefix, error_prefix_len);\n    msg_data[error_prefix_len] = expected_status_code_len;\n    memcpy (msg_data + error_prefix_len + status_code_len_size,\n            status_code.c_str (), status_code.length ());\n}\n\nvoid zmq::plain_server_t::send_zap_request (const std::string &username_,\n                                            const std::string &password_)\n{\n    const uint8_t *credentials[] = {\n      reinterpret_cast<const uint8_t *> (username_.c_str ()),\n      reinterpret_cast<const uint8_t *> (password_.c_str ())};\n    size_t credentials_sizes[] = {username_.size (), password_.size ()};\n    const char plain_mechanism_name[] = \"PLAIN\";\n    zap_client_t::send_zap_request (\n      plain_mechanism_name, sizeof (plain_mechanism_name) - 1, credentials,\n      credentials_sizes, sizeof (credentials) / sizeof (credentials[0]));\n}\n"
  },
  {
    "path": "src/plain_server.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PLAIN_SERVER_HPP_INCLUDED__\n#define __ZMQ_PLAIN_SERVER_HPP_INCLUDED__\n\n#include \"options.hpp\"\n#include \"zap_client.hpp\"\n\nnamespace zmq\n{\nclass msg_t;\nclass session_base_t;\n\nclass plain_server_t ZMQ_FINAL : public zap_client_common_handshake_t\n{\n  public:\n    plain_server_t (session_base_t *session_,\n                    const std::string &peer_address_,\n                    const options_t &options_);\n    ~plain_server_t ();\n\n    // mechanism implementation\n    int next_handshake_command (msg_t *msg_);\n    int process_handshake_command (msg_t *msg_);\n\n  private:\n    static void produce_welcome (msg_t *msg_);\n    void produce_ready (msg_t *msg_) const;\n    void produce_error (msg_t *msg_) const;\n\n    int process_hello (msg_t *msg_);\n    int process_initiate (msg_t *msg_);\n\n    void send_zap_request (const std::string &username_,\n                           const std::string &password_);\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/poll.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"poll.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_POLL\n\n#include <sys/types.h>\n#include <sys/time.h>\n#include <poll.h>\n#include <algorithm>\n\n#include \"poll.hpp\"\n#include \"err.hpp\"\n#include \"config.hpp\"\n#include \"i_poll_events.hpp\"\n\nzmq::poll_t::poll_t (const zmq::thread_ctx_t &ctx_) :\n    worker_poller_base_t (ctx_), retired (false)\n{\n}\n\nzmq::poll_t::~poll_t ()\n{\n    stop_worker ();\n}\n\nzmq::poll_t::handle_t zmq::poll_t::add_fd (fd_t fd_, i_poll_events *events_)\n{\n    check_thread ();\n    zmq_assert (fd_ != retired_fd);\n\n    //  If the file descriptor table is too small expand it.\n    fd_table_t::size_type sz = fd_table.size ();\n    if (sz <= (fd_table_t::size_type) fd_) {\n        fd_table.resize (fd_ + 1);\n        while (sz != (fd_table_t::size_type) (fd_ + 1)) {\n            fd_table[sz].index = retired_fd;\n            ++sz;\n        }\n    }\n\n    pollfd pfd = {fd_, 0, 0};\n    pollset.push_back (pfd);\n    zmq_assert (fd_table[fd_].index == retired_fd);\n\n    fd_table[fd_].index = pollset.size () - 1;\n    fd_table[fd_].events = events_;\n\n    //  Increase the load metric of the thread.\n    adjust_load (1);\n\n    return fd_;\n}\n\nvoid zmq::poll_t::rm_fd (handle_t handle_)\n{\n    check_thread ();\n    fd_t index = fd_table[handle_].index;\n    zmq_assert (index != retired_fd);\n\n    //  Mark the fd as unused.\n    pollset[index].fd = retired_fd;\n    fd_table[handle_].index = retired_fd;\n    retired = true;\n\n    //  Decrease the load metric of the thread.\n    adjust_load (-1);\n}\n\nvoid zmq::poll_t::set_pollin (handle_t handle_)\n{\n    check_thread ();\n    fd_t index = fd_table[handle_].index;\n    pollset[index].events |= POLLIN;\n}\n\nvoid zmq::poll_t::reset_pollin (handle_t handle_)\n{\n    check_thread ();\n    fd_t index = fd_table[handle_].index;\n    pollset[index].events &= ~((short) POLLIN);\n}\n\nvoid zmq::poll_t::set_pollout (handle_t handle_)\n{\n    check_thread ();\n    fd_t index = fd_table[handle_].index;\n    pollset[index].events |= POLLOUT;\n}\n\nvoid zmq::poll_t::reset_pollout (handle_t handle_)\n{\n    check_thread ();\n    fd_t index = fd_table[handle_].index;\n    pollset[index].events &= ~((short) POLLOUT);\n}\n\nvoid zmq::poll_t::stop ()\n{\n    check_thread ();\n    //  no-op... thread is stopped when no more fds or timers are registered\n}\n\nint zmq::poll_t::max_fds ()\n{\n    return -1;\n}\n\nvoid zmq::poll_t::loop ()\n{\n    while (true) {\n        //  Execute any due timers.\n        int timeout = (int) execute_timers ();\n\n        cleanup_retired ();\n\n        if (pollset.empty ()) {\n            zmq_assert (get_load () == 0);\n\n            if (timeout == 0)\n                break;\n\n            // TODO sleep for timeout\n            continue;\n        }\n\n        //  Wait for events.\n        int rc = poll (&pollset[0], static_cast<nfds_t> (pollset.size ()),\n                       timeout ? timeout : -1);\n        if (rc == -1) {\n            errno_assert (errno == EINTR);\n            continue;\n        }\n\n        //  If there are no events (i.e. it's a timeout) there's no point\n        //  in checking the pollset.\n        if (rc == 0)\n            continue;\n\n        for (pollset_t::size_type i = 0; i != pollset.size (); i++) {\n            zmq_assert (!(pollset[i].revents & POLLNVAL));\n            if (pollset[i].fd == retired_fd)\n                continue;\n            if (pollset[i].revents & (POLLERR | POLLHUP))\n                fd_table[pollset[i].fd].events->in_event ();\n            if (pollset[i].fd == retired_fd)\n                continue;\n            if (pollset[i].revents & POLLOUT)\n                fd_table[pollset[i].fd].events->out_event ();\n            if (pollset[i].fd == retired_fd)\n                continue;\n            if (pollset[i].revents & POLLIN)\n                fd_table[pollset[i].fd].events->in_event ();\n        }\n    }\n}\n\nvoid zmq::poll_t::cleanup_retired ()\n{\n    //  Clean up the pollset and update the fd_table accordingly.\n    if (retired) {\n        pollset_t::size_type i = 0;\n        while (i < pollset.size ()) {\n            if (pollset[i].fd == retired_fd)\n                pollset.erase (pollset.begin () + i);\n            else {\n                fd_table[pollset[i].fd].index = i;\n                i++;\n            }\n        }\n        retired = false;\n    }\n}\n\n\n#endif\n"
  },
  {
    "path": "src/poll.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_POLL_HPP_INCLUDED__\n#define __ZMQ_POLL_HPP_INCLUDED__\n\n//  poller.hpp decides which polling mechanism to use.\n#include \"poller.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_POLL\n\n#if defined ZMQ_HAVE_WINDOWS\n#error                                                                         \\\n  \"poll is broken on Windows for the purpose of the I/O thread poller, use select instead; \"\\\n  \"see https://github.com/zeromq/libzmq/issues/3107\"\n#endif\n\n#include <poll.h>\n#include <stddef.h>\n#include <vector>\n\n#include \"ctx.hpp\"\n#include \"fd.hpp\"\n#include \"thread.hpp\"\n#include \"poller_base.hpp\"\n\nnamespace zmq\n{\nstruct i_poll_events;\n\n//  Implements socket polling mechanism using the POSIX.1-2001\n//  poll() system call.\n\nclass poll_t ZMQ_FINAL : public worker_poller_base_t\n{\n  public:\n    typedef fd_t handle_t;\n\n    poll_t (const thread_ctx_t &ctx_);\n    ~poll_t ();\n\n    //  \"poller\" concept.\n    //  These methods may only be called from an event callback; add_fd may also be called before start.\n    handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);\n    void rm_fd (handle_t handle_);\n    void set_pollin (handle_t handle_);\n    void reset_pollin (handle_t handle_);\n    void set_pollout (handle_t handle_);\n    void reset_pollout (handle_t handle_);\n    void stop ();\n\n    static int max_fds ();\n\n  private:\n    //  Main event loop.\n    void loop () ZMQ_FINAL;\n\n    void cleanup_retired ();\n\n    struct fd_entry_t\n    {\n        fd_t index;\n        zmq::i_poll_events *events;\n    };\n\n    //  This table stores data for registered descriptors.\n    typedef std::vector<fd_entry_t> fd_table_t;\n    fd_table_t fd_table;\n\n    //  Pollset to pass to the poll function.\n    typedef std::vector<pollfd> pollset_t;\n    pollset_t pollset;\n\n    //  If true, there's at least one retired event source.\n    bool retired;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (poll_t)\n};\n\ntypedef poll_t poller_t;\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/poller.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_POLLER_HPP_INCLUDED__\n#define __ZMQ_POLLER_HPP_INCLUDED__\n\n#if defined ZMQ_IOTHREAD_POLLER_USE_KQUEUE                                     \\\n    + defined ZMQ_IOTHREAD_POLLER_USE_EPOLL                                    \\\n    + defined ZMQ_IOTHREAD_POLLER_USE_DEVPOLL                                  \\\n    + defined ZMQ_IOTHREAD_POLLER_USE_POLLSET                                  \\\n    + defined ZMQ_IOTHREAD_POLLER_USE_POLL                                     \\\n    + defined ZMQ_IOTHREAD_POLLER_USE_SELECT                                   \\\n  > 1\n#error More than one of the ZMQ_IOTHREAD_POLLER_USE_* macros defined\n#endif\n\n#if defined ZMQ_IOTHREAD_POLLER_USE_KQUEUE\n#include \"kqueue.hpp\"\n#elif defined ZMQ_IOTHREAD_POLLER_USE_EPOLL\n#include \"epoll.hpp\"\n#elif defined ZMQ_IOTHREAD_POLLER_USE_DEVPOLL\n#include \"devpoll.hpp\"\n#elif defined ZMQ_IOTHREAD_POLLER_USE_POLLSET\n#include \"pollset.hpp\"\n#elif defined ZMQ_IOTHREAD_POLLER_USE_POLL\n#include \"poll.hpp\"\n#elif defined ZMQ_IOTHREAD_POLLER_USE_SELECT\n#include \"select.hpp\"\n#elif defined ZMQ_HAVE_GNU\n#define ZMQ_IOTHREAD_POLLER_USE_POLL\n#include \"poll.hpp\"\n#else\n#error None of the ZMQ_IOTHREAD_POLLER_USE_* macros defined\n#endif\n\n#if (defined ZMQ_POLL_BASED_ON_SELECT + defined ZMQ_POLL_BASED_ON_POLL) > 1\n#error More than one of the ZMQ_POLL_BASED_ON_* macros defined\n#elif (defined ZMQ_POLL_BASED_ON_SELECT + defined ZMQ_POLL_BASED_ON_POLL) == 0\n#error None of the ZMQ_POLL_BASED_ON_* macros defined\n#endif\n\n#endif\n"
  },
  {
    "path": "src/poller_base.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"poller_base.hpp\"\n#include \"i_poll_events.hpp\"\n#include \"err.hpp\"\n\nzmq::poller_base_t::~poller_base_t ()\n{\n    //  Make sure there is no more load on the shutdown.\n    zmq_assert (get_load () == 0);\n}\n\nint zmq::poller_base_t::get_load () const\n{\n    return _load.get ();\n}\n\nvoid zmq::poller_base_t::adjust_load (int amount_)\n{\n    if (amount_ > 0)\n        _load.add (amount_);\n    else if (amount_ < 0)\n        _load.sub (-amount_);\n}\n\nvoid zmq::poller_base_t::add_timer (int timeout_, i_poll_events *sink_, int id_)\n{\n    uint64_t expiration = _clock.now_ms () + timeout_;\n    timer_info_t info = {sink_, id_};\n    _timers.insert (timers_t::value_type (expiration, info));\n}\n\nvoid zmq::poller_base_t::cancel_timer (i_poll_events *sink_, int id_)\n{\n    //  Complexity of this operation is O(n). We assume it is rarely used.\n    for (timers_t::iterator it = _timers.begin (), end = _timers.end ();\n         it != end; ++it)\n        if (it->second.sink == sink_ && it->second.id == id_) {\n            _timers.erase (it);\n            return;\n        }\n\n    //  We should generally never get here. Calling 'cancel_timer ()' on\n    //  an already expired or canceled timer (or even worse - on a timer which\n    //  never existed, supplying bad sink_ and/or id_ values) does not make any\n    //  sense.\n    //  But in some edge cases this might happen. As described in issue #3645\n    //  `timer_event ()` call from `execute_timers ()` might call `cancel_timer ()`\n    //  on already canceled (deleted) timer.\n    //  As soon as that is resolved an 'assert (false)' should be put here.\n}\n\nuint64_t zmq::poller_base_t::execute_timers ()\n{\n    //  Fast track.\n    if (_timers.empty ())\n        return 0;\n\n    //  Get the current time.\n    const uint64_t current = _clock.now_ms ();\n\n    //  Execute the timers that are already due.\n    uint64_t res = 0;\n    timer_info_t timer_temp;\n    timers_t::iterator it;\n\n    do {\n        it = _timers.begin ();\n\n        //  If we have to wait to execute the item, same will be true for\n        //  all the following items because multimap is sorted. Thus we can\n        //  stop checking the subsequent timers.\n        if (it->first > current) {\n            res = it->first - current;\n            break;\n        }\n\n        //  Save and remove the timer because timer_event() call might delete\n        //  exactly this timer and then the iterator will be invalid.\n        timer_temp = it->second;\n        _timers.erase (it);\n\n        //  Trigger the timer.\n        timer_temp.sink->timer_event (timer_temp.id);\n\n    } while (!_timers.empty ());\n\n    //  Return the time to wait for the next timer (at least 1ms), or 0, if\n    //  there are no more timers.\n    return res;\n}\n\nzmq::worker_poller_base_t::worker_poller_base_t (const thread_ctx_t &ctx_) :\n    _ctx (ctx_)\n{\n}\n\nvoid zmq::worker_poller_base_t::stop_worker ()\n{\n    _worker.stop ();\n}\n\nvoid zmq::worker_poller_base_t::start (const char *name_)\n{\n    zmq_assert (get_load () > 0);\n    _ctx.start_thread (_worker, worker_routine, this, name_);\n}\n\nvoid zmq::worker_poller_base_t::check_thread () const\n{\n#ifndef NDEBUG\n    zmq_assert (!_worker.get_started () || _worker.is_current_thread ());\n#endif\n}\n\nvoid zmq::worker_poller_base_t::worker_routine (void *arg_)\n{\n    (static_cast<worker_poller_base_t *> (arg_))->loop ();\n}\n"
  },
  {
    "path": "src/poller_base.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_POLLER_BASE_HPP_INCLUDED__\n#define __ZMQ_POLLER_BASE_HPP_INCLUDED__\n\n#include <map>\n\n#include \"clock.hpp\"\n#include \"atomic_counter.hpp\"\n#include \"ctx.hpp\"\n\nnamespace zmq\n{\nstruct i_poll_events;\n\n// A build of libzmq must provide an implementation of the poller_t concept. By\n// convention, this is done via a typedef.\n//\n// At the time of writing, the following implementations of the poller_t\n// concept exist: zmq::devpoll_t, zmq::epoll_t, zmq::kqueue_t, zmq::poll_t,\n// zmq::pollset_t, zmq::select_t\n//\n// An implementation of the poller_t concept must provide the following public\n// methods:\n//   Returns load of the poller.\n// int get_load() const;\n//\n//   Add a timeout to expire in timeout_ milliseconds. After the\n//   expiration, timer_event on sink_ object will be called with\n//   argument set to id_.\n// void add_timer(int timeout_, zmq::i_poll_events *sink_, int id_);\n//\n//   Cancel the timer created by sink_ object with ID equal to id_.\n// void cancel_timer(zmq::i_poll_events *sink_, int id_);\n//\n//   Adds a fd to the poller. Initially, no events are activated. These must\n//   be activated by the set_* methods using the returned handle_.\n// handle_t add_fd(fd_t fd_, zmq::i_poll_events *events_);\n//\n//   Deactivates any events that may be active for the given handle_, and\n//   removes the fd associated with the given handle_.\n// void rm_fd(handle_t handle_);\n//\n//   The set_* and reset_* methods activate resp. deactivate polling for\n//   input/output readiness on the respective handle_, such that the\n//   in_event/out_event methods on the associated zmq::i_poll_events object\n//   will be called.\n//   Note: while handle_t and fd_t may be the same type, and may even have the\n//   same values for some implementation, this may not be assumed in general.\n//   The methods may only be called with the handle returned by add_fd.\n// void set_pollin(handle_t handle_);\n// void reset_pollin(handle_t handle_);\n// void set_pollout(handle_t handle_);//\n// void reset_pollout(handle_t handle_);\n//\n//   Starts operation of the poller. See below for details.\n// void start();\n//\n//   Request termination of the poller.\n//   TODO: might be removed in the future, as it has no effect.\n// void stop();\n//\n//   Returns the maximum number of fds that can be added to an instance of the\n//   poller at the same time, or -1 if there is no such fixed limit.\n// static int max_fds();\n//\n// Most of the methods may only be called from a zmq::i_poll_events callback\n// function when invoked by the poller (and, therefore, typically from the\n// poller's worker thread), with the following exceptions:\n// - get_load may be called from outside\n// - add_fd and add_timer may be called from outside before start\n// - start may be called from outside once\n//\n// After a poller is started, it waits for the registered events (input/output\n// readiness, timeout) to happen, and calls the respective functions on the\n// zmq::i_poll_events object. It terminates when no further registrations (fds\n// or timers) exist.\n//\n// Before start, add_fd must have been called at least once. Behavior may be\n// undefined otherwise.\n//\n// If the poller is implemented by a single worker thread (the\n// worker_poller_base_t base  class may be used to implement such a poller),\n// no synchronization is required for the data structures modified by\n// add_fd, rm_fd, add_timer, cancel_timer, (re)set_poll(in|out). However,\n// reentrancy must be considered, e.g. when one of the functions modifies\n// a container that is being iterated by the poller.\n\n\n// A class that can be used as abase class for implementations of the poller\n// concept.\n//\n// For documentation of the public methods, see the description of the poller_t\n// concept.\nclass poller_base_t\n{\n  public:\n    poller_base_t () ZMQ_DEFAULT;\n    virtual ~poller_base_t ();\n\n    // Methods from the poller concept.\n    int get_load () const;\n    void add_timer (int timeout_, zmq::i_poll_events *sink_, int id_);\n    void cancel_timer (zmq::i_poll_events *sink_, int id_);\n\n  protected:\n    //  Called by individual poller implementations to manage the load.\n    void adjust_load (int amount_);\n\n    //  Executes any timers that are due. Returns number of milliseconds\n    //  to wait to match the next timer or 0 meaning \"no timers\".\n    uint64_t execute_timers ();\n\n  private:\n    //  Clock instance private to this I/O thread.\n    clock_t _clock;\n\n    //  List of active timers.\n    struct timer_info_t\n    {\n        zmq::i_poll_events *sink;\n        int id;\n    };\n    typedef std::multimap<uint64_t, timer_info_t> timers_t;\n    timers_t _timers;\n\n    //  Load of the poller. Currently the number of file descriptors\n    //  registered.\n    atomic_counter_t _load;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (poller_base_t)\n};\n\n//  Base class for a poller with a single worker thread.\nclass worker_poller_base_t : public poller_base_t\n{\n  public:\n    worker_poller_base_t (const thread_ctx_t &ctx_);\n\n    // Methods from the poller concept.\n    void start (const char *name = NULL);\n\n  protected:\n    //  Checks whether the currently executing thread is the worker thread\n    //  via an assertion.\n    //  Should be called by the add_fd, removed_fd, set_*, reset_* functions\n    //  to ensure correct usage.\n    void check_thread () const;\n\n    //  Stops the worker thread. Should be called from the destructor of the\n    //  leaf class.\n    void stop_worker ();\n\n  private:\n    //  Main worker thread routine.\n    static void worker_routine (void *arg_);\n\n    virtual void loop () = 0;\n\n    // Reference to ZMQ context.\n    const thread_ctx_t &_ctx;\n\n    //  Handle of the physical thread doing the I/O work.\n    thread_t _worker;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/polling_util.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"polling_util.hpp\"\n\n#if defined ZMQ_POLL_BASED_ON_POLL\n#include <limits.h>\n#include <algorithm>\n\nzmq::timeout_t zmq::compute_timeout (const bool first_pass_,\n                                     const long timeout_,\n                                     const uint64_t now_,\n                                     const uint64_t end_)\n{\n    if (first_pass_)\n        return 0;\n\n    if (timeout_ < 0)\n        return -1;\n\n    return static_cast<zmq::timeout_t> (\n      std::min<uint64_t> (end_ - now_, INT_MAX));\n}\n#endif\n"
  },
  {
    "path": "src/polling_util.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SOCKET_POLLING_UTIL_HPP_INCLUDED__\n#define __ZMQ_SOCKET_POLLING_UTIL_HPP_INCLUDED__\n\n#include <stdlib.h>\n#include <vector>\n\n#if defined ZMQ_HAVE_WINDOWS\n#include <winsock.h>\n#else\n#include <sys/select.h>\n#endif\n\n#include \"macros.hpp\"\n#include \"stdint.hpp\"\n#include \"platform.hpp\"\n#include \"err.hpp\"\n\nnamespace zmq\n{\ntemplate <typename T, size_t S> class fast_vector_t\n{\n  public:\n    explicit fast_vector_t (const size_t nitems_)\n    {\n        if (nitems_ > S) {\n            _buf = new (std::nothrow) T[nitems_];\n            //  TODO since this function is called by a client, we could return errno == ENOMEM here\n            alloc_assert (_buf);\n        } else {\n            _buf = _static_buf;\n        }\n    }\n\n    T &operator[] (const size_t i) { return _buf[i]; }\n\n    ~fast_vector_t ()\n    {\n        if (_buf != _static_buf)\n            delete[] _buf;\n    }\n\n  private:\n    T _static_buf[S];\n    T *_buf;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (fast_vector_t)\n};\n\ntemplate <typename T, size_t S> class resizable_fast_vector_t\n{\n  public:\n    resizable_fast_vector_t () : _dynamic_buf (NULL) {}\n\n    void resize (const size_t nitems_)\n    {\n        if (_dynamic_buf) {\n            _dynamic_buf->resize (nitems_);\n        } else if (nitems_ > S) {\n            _dynamic_buf = new (std::nothrow) std::vector<T> (nitems_);\n            //  TODO since this function is called by a client, we could return errno == ENOMEM here\n            alloc_assert (_dynamic_buf);\n            memcpy (&(*_dynamic_buf)[0], _static_buf, sizeof _static_buf);\n        }\n    }\n\n    T *get_buf ()\n    {\n        // e.g. MSVC 2008 does not have std::vector::data, so we use &...[0]\n        return _dynamic_buf ? &(*_dynamic_buf)[0] : _static_buf;\n    }\n\n    T &operator[] (const size_t i) { return get_buf ()[i]; }\n\n    ~resizable_fast_vector_t () { delete _dynamic_buf; }\n\n  private:\n    T _static_buf[S];\n    std::vector<T> *_dynamic_buf;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (resizable_fast_vector_t)\n};\n\n#if defined ZMQ_POLL_BASED_ON_POLL\ntypedef int timeout_t;\n\ntimeout_t\ncompute_timeout (bool first_pass_, long timeout_, uint64_t now_, uint64_t end_);\n#endif\n#if (!defined ZMQ_POLL_BASED_ON_POLL && defined ZMQ_POLL_BASED_ON_SELECT)      \\\n  || defined ZMQ_HAVE_PPOLL\n#if defined ZMQ_HAVE_WINDOWS\ninline size_t valid_pollset_bytes (const fd_set &pollset_)\n{\n    // On Windows we don't need to copy the whole fd_set.\n    // SOCKETS are continuous from the beginning of fd_array in fd_set.\n    // We just need to copy fd_count elements of fd_array.\n    // We gain huge memcpy() improvement if number of used SOCKETs is much lower than FD_SETSIZE.\n    return reinterpret_cast<const char *> (\n             &pollset_.fd_array[pollset_.fd_count])\n           - reinterpret_cast<const char *> (&pollset_);\n}\n#else\ninline size_t valid_pollset_bytes (const fd_set & /*pollset_*/)\n{\n    return sizeof (fd_set);\n}\n#endif\n\n\n#if defined ZMQ_HAVE_WINDOWS\n// struct fd_set {\n//  u_int   fd_count;\n//  SOCKET  fd_array[1];\n// };\n// NOTE: offsetof(fd_set, fd_array)==sizeof(SOCKET) on both x86 and x64\n//       due to alignment bytes for the latter.\nclass optimized_fd_set_t\n{\n  public:\n    explicit optimized_fd_set_t (size_t nevents_) : _fd_set (1 + nevents_) {}\n\n    fd_set *get () { return reinterpret_cast<fd_set *> (&_fd_set[0]); }\n\n  private:\n    fast_vector_t<SOCKET, 1 + ZMQ_POLLITEMS_DFLT> _fd_set;\n};\n\nclass resizable_optimized_fd_set_t\n{\n  public:\n    void resize (size_t nevents_) { _fd_set.resize (1 + nevents_); }\n\n    fd_set *get () { return reinterpret_cast<fd_set *> (&_fd_set[0]); }\n\n  private:\n    resizable_fast_vector_t<SOCKET, 1 + ZMQ_POLLITEMS_DFLT> _fd_set;\n};\n#else\nclass optimized_fd_set_t\n{\n  public:\n    explicit optimized_fd_set_t (size_t /*nevents_*/) {}\n\n    fd_set *get () { return &_fd_set; }\n\n  private:\n    fd_set _fd_set;\n};\n\nclass resizable_optimized_fd_set_t : public optimized_fd_set_t\n{\n  public:\n    resizable_optimized_fd_set_t () : optimized_fd_set_t (0) {}\n\n    void resize (size_t /*nevents_*/) {}\n};\n#endif\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "src/pollset.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"pollset.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_POLLSET\n\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <algorithm>\n#include <new>\n\n#include \"macros.hpp\"\n#include \"err.hpp\"\n#include \"config.hpp\"\n#include \"i_poll_events.hpp\"\n\nzmq::pollset_t::pollset_t (const zmq::thread_ctx_t &ctx_) :\n    ctx (ctx_), stopping (false)\n{\n    pollset_fd = pollset_create (-1);\n    errno_assert (pollset_fd != -1);\n}\n\nzmq::pollset_t::~pollset_t ()\n{\n    //  Wait till the worker thread exits.\n    worker.stop ();\n\n    pollset_destroy (pollset_fd);\n    for (retired_t::iterator it = retired.begin (); it != retired.end (); ++it)\n        LIBZMQ_DELETE (*it);\n}\n\nzmq::pollset_t::handle_t zmq::pollset_t::add_fd (fd_t fd_,\n                                                 i_poll_events *events_)\n{\n    poll_entry_t *pe = new (std::nothrow) poll_entry_t;\n    alloc_assert (pe);\n\n    pe->fd = fd_;\n    pe->flag_pollin = false;\n    pe->flag_pollout = false;\n    pe->events = events_;\n\n    struct poll_ctl pc;\n    pc.fd = fd_;\n    pc.cmd = PS_ADD;\n    pc.events = 0;\n\n    int rc = pollset_ctl (pollset_fd, &pc, 1);\n    errno_assert (rc != -1);\n\n    //  Increase the load metric of the thread.\n    adjust_load (1);\n\n    if (fd_ >= fd_table.size ()) {\n        fd_table.resize (fd_ + 1, NULL);\n    }\n    fd_table[fd_] = pe;\n    return pe;\n}\n\nvoid zmq::pollset_t::rm_fd (handle_t handle_)\n{\n    poll_entry_t *pe = (poll_entry_t *) handle_;\n\n    struct poll_ctl pc;\n    pc.fd = pe->fd;\n    pc.cmd = PS_DELETE;\n    pc.events = 0;\n    pollset_ctl (pollset_fd, &pc, 1);\n\n    fd_table[pe->fd] = NULL;\n\n    pe->fd = retired_fd;\n    retired.push_back (pe);\n\n    //  Decrease the load metric of the thread.\n    adjust_load (-1);\n}\n\nvoid zmq::pollset_t::set_pollin (handle_t handle_)\n{\n    poll_entry_t *pe = (poll_entry_t *) handle_;\n    if (likely (!pe->flag_pollin)) {\n        struct poll_ctl pc;\n        pc.fd = pe->fd;\n        pc.cmd = PS_MOD;\n        pc.events = POLLIN;\n\n        const int rc = pollset_ctl (pollset_fd, &pc, 1);\n        errno_assert (rc != -1);\n\n        pe->flag_pollin = true;\n    }\n}\n\nvoid zmq::pollset_t::reset_pollin (handle_t handle_)\n{\n    poll_entry_t *pe = (poll_entry_t *) handle_;\n    if (unlikely (!pe->flag_pollin)) {\n        return;\n    }\n\n    struct poll_ctl pc;\n    pc.fd = pe->fd;\n    pc.events = 0;\n\n    pc.cmd = PS_DELETE;\n    int rc = pollset_ctl (pollset_fd, &pc, 1);\n\n    if (pe->flag_pollout) {\n        pc.events = POLLOUT;\n        pc.cmd = PS_MOD;\n        rc = pollset_ctl (pollset_fd, &pc, 1);\n        errno_assert (rc != -1);\n    }\n\n    pe->flag_pollin = false;\n}\n\nvoid zmq::pollset_t::set_pollout (handle_t handle_)\n{\n    poll_entry_t *pe = (poll_entry_t *) handle_;\n    if (likely (!pe->flag_pollout)) {\n        struct poll_ctl pc;\n        pc.fd = pe->fd;\n        pc.cmd = PS_MOD;\n        pc.events = POLLOUT;\n\n        const int rc = pollset_ctl (pollset_fd, &pc, 1);\n        errno_assert (rc != -1);\n\n        pe->flag_pollout = true;\n    }\n}\n\nvoid zmq::pollset_t::reset_pollout (handle_t handle_)\n{\n    poll_entry_t *pe = (poll_entry_t *) handle_;\n    if (unlikely (!pe->flag_pollout)) {\n        return;\n    }\n\n    struct poll_ctl pc;\n    pc.fd = pe->fd;\n    pc.events = 0;\n\n    pc.cmd = PS_DELETE;\n    int rc = pollset_ctl (pollset_fd, &pc, 1);\n    errno_assert (rc != -1);\n\n    if (pe->flag_pollin) {\n        pc.cmd = PS_MOD;\n        pc.events = POLLIN;\n        rc = pollset_ctl (pollset_fd, &pc, 1);\n        errno_assert (rc != -1);\n    }\n    pe->flag_pollout = false;\n}\n\nvoid zmq::pollset_t::start ()\n{\n    ctx.start_thread (worker, worker_routine, this);\n}\n\nvoid zmq::pollset_t::stop ()\n{\n    stopping = true;\n}\n\nint zmq::pollset_t::max_fds ()\n{\n    return -1;\n}\n\nvoid zmq::pollset_t::loop ()\n{\n    struct pollfd polldata_array[max_io_events];\n\n    while (!stopping) {\n        //  Execute any due timers.\n        int timeout = (int) execute_timers ();\n\n        //  Wait for events.\n        int n = pollset_poll (pollset_fd, polldata_array, max_io_events,\n                              timeout ? timeout : -1);\n        if (n == -1) {\n            errno_assert (errno == EINTR);\n            continue;\n        }\n\n        for (int i = 0; i < n; i++) {\n            poll_entry_t *pe = fd_table[polldata_array[i].fd];\n            if (!pe)\n                continue;\n\n            if (pe->fd == retired_fd)\n                continue;\n            if (polldata_array[i].revents & (POLLERR | POLLHUP))\n                pe->events->in_event ();\n            if (pe->fd == retired_fd)\n                continue;\n            if (polldata_array[i].revents & POLLOUT)\n                pe->events->out_event ();\n            if (pe->fd == retired_fd)\n                continue;\n            if (polldata_array[i].revents & POLLIN)\n                pe->events->in_event ();\n        }\n\n        //  Destroy retired event sources.\n        for (retired_t::iterator it = retired.begin (); it != retired.end ();\n             ++it)\n            LIBZMQ_DELETE (*it);\n        retired.clear ();\n    }\n}\n\nvoid zmq::pollset_t::worker_routine (void *arg_)\n{\n    ((pollset_t *) arg_)->loop ();\n}\n\n#endif\n"
  },
  {
    "path": "src/pollset.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_POLLSET_HPP_INCLUDED__\n#define __ZMQ_POLLSET_HPP_INCLUDED__\n\n//  poller.hpp decides which polling mechanism to use.\n#include \"poller.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_POLLSET\n\n#include <sys/poll.h>\n#include <sys/pollset.h>\n#include <vector>\n\n#include \"ctx.hpp\"\n#include \"fd.hpp\"\n#include \"thread.hpp\"\n#include \"poller_base.hpp\"\n\nnamespace zmq\n{\nstruct i_poll_events;\n\n//  This class implements socket polling mechanism using the AIX-specific\n//  pollset mechanism.\n\nclass pollset_t ZMQ_FINAL : public poller_base_t\n{\n  public:\n    typedef void *handle_t;\n\n    pollset_t (const thread_ctx_t &ctx_);\n    ~pollset_t () ZMQ_FINAL;\n\n    //  \"poller\" concept.\n    handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);\n    void rm_fd (handle_t handle_);\n    void set_pollin (handle_t handle_);\n    void reset_pollin (handle_t handle_);\n    void set_pollout (handle_t handle_);\n    void reset_pollout (handle_t handle_);\n    void start ();\n    void stop ();\n\n    static int max_fds ();\n\n  private:\n    //  Main worker thread routine.\n    static void worker_routine (void *arg_);\n\n    //  Main event loop.\n    void loop () ZMQ_FINAL;\n\n    // Reference to ZMQ context.\n    const thread_ctx_t &ctx;\n\n    //  Main pollset file descriptor\n    ::pollset_t pollset_fd;\n\n    struct poll_entry_t\n    {\n        fd_t fd;\n        bool flag_pollin;\n        bool flag_pollout;\n        zmq::i_poll_events *events;\n    };\n\n    //  List of retired event sources.\n    typedef std::vector<poll_entry_t *> retired_t;\n    retired_t retired;\n\n    //  This table stores data for registered descriptors.\n    typedef std::vector<poll_entry_t *> fd_table_t;\n    fd_table_t fd_table;\n\n    //  If true, thread is in the process of shutting down.\n    bool stopping;\n\n    //  Handle of the physical thread doing the I/O work.\n    thread_t worker;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (pollset_t)\n};\n\ntypedef pollset_t poller_t;\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/precompiled.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n"
  },
  {
    "path": "src/precompiled.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PRECOMPILED_HPP_INCLUDED__\n#define __ZMQ_PRECOMPILED_HPP_INCLUDED__\n\n//  On AIX platform, poll.h has to be included first to get consistent\n//  definition of pollfd structure (AIX uses 'reqevents' and 'retnevents'\n//  instead of 'events' and 'revents' and defines macros to map from POSIX-y\n//  names to AIX-specific names).\n//  zmq.h must be included *after* poll.h for AIX to build properly.\n//  precompiled.hpp includes include/zmq.h\n#if defined ZMQ_POLL_BASED_ON_POLL && defined ZMQ_HAVE_AIX\n#include <poll.h>\n#endif\n\n#include \"platform.hpp\"\n\n#define __STDC_LIMIT_MACROS\n\n// This must be included before any windows headers are compiled.\n#if defined ZMQ_HAVE_WINDOWS\n#include \"windows.hpp\"\n#endif\n\n#if defined ZMQ_HAVE_OPENBSD\n#define ucred sockpeercred\n#endif\n\n// 0MQ definitions and exported functions\n#include \"../include/zmq.h\"\n\n// 0MQ DRAFT definitions and exported functions\n#include \"zmq_draft.h\"\n\n// TODO: expand pch implementation to non-windows builds.\n#ifdef _MSC_VER\n\n// standard C headers\n#include <assert.h>\n#include <ctype.h>\n#include <errno.h>\n#include <io.h>\n#include <ipexport.h>\n#include <iphlpapi.h>\n#include <limits.h>\n#include <mstcpip.h>\n#include <mswsock.h>\n#include <process.h>\n#include <rpc.h>\n#include <signal.h>\n#include <stdarg.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <time.h>\n#include <winsock2.h>\n#include <ws2tcpip.h>\n\n// standard C++ headers\n#include <algorithm>\n#include <climits>\n#include <cmath>\n#include <cstddef>\n#include <cstdlib>\n#include <cstring>\n#include <deque>\n#include <limits>\n#include <map>\n#include <new>\n#include <set>\n#include <sstream>\n#include <string>\n#include <vector>\n\n#if _MSC_VER >= 1800\n#include <inttypes.h>\n#endif\n\n#if _MSC_VER >= 1700\n#include <atomic>\n#endif\n\n#if defined _WIN32_WCE\n#include <cmnintrin.h>\n#else\n#include <intrin.h>\n#endif\n\n#if defined HAVE_LIBGSSAPI_KRB5\n#include \"err.hpp\"\n#include \"msg.hpp\"\n#include \"mechanism.hpp\"\n#include \"session_base.hpp\"\n#include \"gssapi_server.hpp\"\n#include \"wire.hpp\"\n#include <gssapi/gssapi.h>\n#include <gssapi/gssapi_krb5.h>\n#endif\n\n#include \"options.hpp\"\n\n#endif // _MSC_VER\n\n#endif //ifndef __ZMQ_PRECOMPILED_HPP_INCLUDED__\n"
  },
  {
    "path": "src/proxy.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include <stddef.h>\n#include \"poller.hpp\"\n#include \"proxy.hpp\"\n#include \"likely.hpp\"\n#include \"msg.hpp\"\n\n#if defined ZMQ_POLL_BASED_ON_POLL && !defined ZMQ_HAVE_WINDOWS                \\\n  && !defined ZMQ_HAVE_AIX\n#include <poll.h>\n#endif\n\n// These headers end up pulling in zmq.h somewhere in their include\n// dependency chain\n#include \"socket_base.hpp\"\n#include \"err.hpp\"\n\nint zmq::proxy (class socket_base_t *frontend_,\n                class socket_base_t *backend_,\n                class socket_base_t *capture_)\n{\n    return zmq::proxy_steerable (frontend_, backend_, capture_, NULL);\n}\n\n#ifdef ZMQ_HAVE_POLLER\n\n#include \"socket_poller.hpp\"\n\n//  Macros for repetitive code.\n\n//  PROXY_CLEANUP() must not be used before these variables are initialized.\n#define PROXY_CLEANUP()                                                        \\\n    do {                                                                       \\\n        delete poller_all;                                                     \\\n        delete poller_in;                                                      \\\n        delete poller_receive_blocked;                                         \\\n        delete poller_send_blocked;                                            \\\n        delete poller_both_blocked;                                            \\\n        delete poller_frontend_only;                                           \\\n        delete poller_backend_only;                                            \\\n    } while (false)\n\n\n#define CHECK_RC_EXIT_ON_FAILURE()                                             \\\n    do {                                                                       \\\n        if (rc < 0) {                                                          \\\n            PROXY_CLEANUP ();                                                  \\\n            return close_and_return (&msg, -1);                                \\\n        }                                                                      \\\n    } while (false)\n\n#endif //  ZMQ_HAVE_POLLER\n\nstatic int\ncapture (class zmq::socket_base_t *capture_, zmq::msg_t *msg_, int more_ = 0)\n{\n    //  Copy message to capture socket if any\n    if (capture_) {\n        zmq::msg_t ctrl;\n        int rc = ctrl.init ();\n        if (unlikely (rc < 0))\n            return -1;\n        rc = ctrl.copy (*msg_);\n        if (unlikely (rc < 0))\n            return -1;\n        rc = capture_->send (&ctrl, more_ ? ZMQ_SNDMORE : 0);\n        if (unlikely (rc < 0))\n            return -1;\n    }\n    return 0;\n}\n\nstruct stats_socket\n{\n    uint64_t count, bytes;\n};\nstruct stats_endpoint\n{\n    stats_socket send, recv;\n};\nstruct stats_proxy\n{\n    stats_endpoint frontend, backend;\n};\n\nstatic int forward (class zmq::socket_base_t *from_,\n                    class zmq::socket_base_t *to_,\n                    class zmq::socket_base_t *capture_,\n                    zmq::msg_t *msg_,\n                    stats_socket &recving,\n                    stats_socket &sending)\n{\n    // Forward a burst of messages\n    for (unsigned int i = 0; i < zmq::proxy_burst_size; i++) {\n        int more;\n        size_t moresz;\n\n        // Forward all the parts of one message\n        while (true) {\n            int rc = from_->recv (msg_, ZMQ_DONTWAIT);\n            if (rc < 0) {\n                if (likely (errno == EAGAIN && i > 0))\n                    return 0; // End of burst\n\n                return -1;\n            }\n\n            size_t nbytes = msg_->size ();\n            recving.count += 1;\n            recving.bytes += nbytes;\n\n            moresz = sizeof more;\n            rc = from_->getsockopt (ZMQ_RCVMORE, &more, &moresz);\n            if (unlikely (rc < 0))\n                return -1;\n\n            //  Copy message to capture socket if any\n            rc = capture (capture_, msg_, more);\n            if (unlikely (rc < 0))\n                return -1;\n\n            rc = to_->send (msg_, more ? ZMQ_SNDMORE : 0);\n            if (unlikely (rc < 0))\n                return -1;\n            sending.count += 1;\n            sending.bytes += nbytes;\n\n            if (more == 0)\n                break;\n        }\n    }\n\n    return 0;\n}\n\nenum proxy_state_t\n{\n    active,\n    paused,\n    terminated\n};\n\n// Handle control request [5]PAUSE, [6]RESUME, [9]TERMINATE,\n// [10]STATISTICS.  Only STATISTICS results in a send.\nstatic int handle_control (class zmq::socket_base_t *control_,\n                           proxy_state_t &state,\n                           const stats_proxy &stats)\n{\n    zmq::msg_t cmsg;\n    int rc = cmsg.init ();\n    if (rc != 0) {\n        return -1;\n    }\n    rc = control_->recv (&cmsg, ZMQ_DONTWAIT);\n    if (rc < 0) {\n        return -1;\n    }\n    uint8_t *const command = static_cast<uint8_t *> (cmsg.data ());\n    const size_t msiz = cmsg.size ();\n\n    if (msiz == 10 && 0 == memcmp (command, \"STATISTICS\", 10)) {\n        // The stats are a cross product:\n        //\n        // (Front,Back) X (Recv,Sent) X (Number,Bytes).\n        //\n        // that is flattened into sequence of 8 message parts according to the\n        // zmq_proxy_steerable(3) documentation as:\n        //\n        // (frn, frb, fsn, fsb, brn, brb, bsn, bsb)\n        //\n        // f=front/b=back, r=recv/s=send, n=number/b=bytes.\n        const uint64_t stat_vals[8] = {\n          stats.frontend.recv.count, stats.frontend.recv.bytes,\n          stats.frontend.send.count, stats.frontend.send.bytes,\n          stats.backend.recv.count,  stats.backend.recv.bytes,\n          stats.backend.send.count,  stats.backend.send.bytes};\n\n        for (size_t ind = 0; ind < 8; ++ind) {\n            cmsg.init_size (sizeof (uint64_t));\n            memcpy (cmsg.data (), stat_vals + ind, sizeof (uint64_t));\n            rc = control_->send (&cmsg, ind < 7 ? ZMQ_SNDMORE : 0);\n            if (unlikely (rc < 0)) {\n                return -1;\n            }\n        }\n        return 0;\n    }\n\n    if (msiz == 5 && 0 == memcmp (command, \"PAUSE\", 5)) {\n        state = paused;\n    } else if (msiz == 6 && 0 == memcmp (command, \"RESUME\", 6)) {\n        state = active;\n    } else if (msiz == 9 && 0 == memcmp (command, \"TERMINATE\", 9)) {\n        state = terminated;\n    }\n\n    int type;\n    size_t sz = sizeof (type);\n    zmq_getsockopt (control_, ZMQ_TYPE, &type, &sz);\n    if (type == ZMQ_REP) {\n        // satisfy REP duty and reply no matter what.\n        cmsg.init_size (0);\n        rc = control_->send (&cmsg, 0);\n        if (unlikely (rc < 0)) {\n            return -1;\n        }\n    }\n    return 0;\n}\n\n#ifdef ZMQ_HAVE_POLLER\nint zmq::proxy_steerable (class socket_base_t *frontend_,\n                          class socket_base_t *backend_,\n                          class socket_base_t *capture_,\n                          class socket_base_t *control_)\n{\n    msg_t msg;\n    int rc = msg.init ();\n    if (rc != 0)\n        return -1;\n\n    //  The algorithm below assumes ratio of requests and replies processed\n    //  under full load to be 1:1.\n\n    //  Proxy can be in these three states\n    proxy_state_t state = active;\n\n    bool frontend_equal_to_backend;\n    bool frontend_in = false;\n    bool frontend_out = false;\n    bool backend_in = false;\n    bool backend_out = false;\n    zmq::socket_poller_t::event_t events[4];\n    int nevents = 3; // increase to 4 if we have control_\n\n    stats_proxy stats = {{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}};\n\n    //  Don't allocate these pollers from stack because they will take more than 900 kB of stack!\n    //  On Windows this blows up default stack of 1 MB and aborts the program.\n    //  I wanted to use std::shared_ptr here as the best solution but that requires C++11...\n    zmq::socket_poller_t *poller_all =\n      new (std::nothrow) zmq::socket_poller_t; //  Poll for everything.\n    zmq::socket_poller_t *poller_in = new (std::nothrow) zmq::\n      socket_poller_t; //  Poll only 'ZMQ_POLLIN' on all sockets. Initial blocking poll in loop.\n    zmq::socket_poller_t *poller_receive_blocked = new (std::nothrow)\n      zmq::socket_poller_t; //  All except 'ZMQ_POLLIN' on 'frontend_'.\n\n    //  If frontend_==backend_ 'poller_send_blocked' and 'poller_receive_blocked' are the same, 'ZMQ_POLLIN' is ignored.\n    //  In that case 'poller_send_blocked' is not used. We need only 'poller_receive_blocked'.\n    //  We also don't need 'poller_both_blocked', 'poller_backend_only' nor 'poller_frontend_only' no need to initialize it.\n    //  We save some RAM and time for initialization.\n    zmq::socket_poller_t *poller_send_blocked =\n      NULL; //  All except 'ZMQ_POLLIN' on 'backend_'.\n    zmq::socket_poller_t *poller_both_blocked =\n      NULL; //  All except 'ZMQ_POLLIN' on both 'frontend_' and 'backend_'.\n    zmq::socket_poller_t *poller_frontend_only =\n      NULL; //  Only 'ZMQ_POLLIN' and 'ZMQ_POLLOUT' on 'frontend_'.\n    zmq::socket_poller_t *poller_backend_only =\n      NULL; //  Only 'ZMQ_POLLIN' and 'ZMQ_POLLOUT' on 'backend_'.\n\n    if (frontend_ != backend_) {\n        poller_send_blocked = new (std::nothrow)\n          zmq::socket_poller_t; //  All except 'ZMQ_POLLIN' on 'backend_'.\n        poller_both_blocked = new (std::nothrow) zmq::\n          socket_poller_t; //  All except 'ZMQ_POLLIN' on both 'frontend_' and 'backend_'.\n        poller_frontend_only = new (std::nothrow) zmq::\n          socket_poller_t; //  Only 'ZMQ_POLLIN' and 'ZMQ_POLLOUT' on 'frontend_'.\n        poller_backend_only = new (std::nothrow) zmq::\n          socket_poller_t; //  Only 'ZMQ_POLLIN' and 'ZMQ_POLLOUT' on 'backend_'.\n        frontend_equal_to_backend = false;\n    } else\n        frontend_equal_to_backend = true;\n\n    if (poller_all == NULL || poller_in == NULL\n        || poller_receive_blocked == NULL\n        || ((poller_send_blocked == NULL || poller_both_blocked == NULL)\n            && !frontend_equal_to_backend)) {\n        PROXY_CLEANUP ();\n        return close_and_return (&msg, -1);\n    }\n\n    zmq::socket_poller_t *poller_wait =\n      poller_in; //  Poller for blocking wait, initially all 'ZMQ_POLLIN'.\n\n    //  Register 'frontend_' and 'backend_' with pollers.\n    rc = poller_all->add (frontend_, NULL,\n                          ZMQ_POLLIN | ZMQ_POLLOUT); //  Everything.\n    CHECK_RC_EXIT_ON_FAILURE ();\n    rc = poller_in->add (frontend_, NULL, ZMQ_POLLIN); //  All 'ZMQ_POLLIN's.\n    CHECK_RC_EXIT_ON_FAILURE ();\n\n    if (frontend_equal_to_backend) {\n        //  If frontend_==backend_ 'poller_send_blocked' and 'poller_receive_blocked' are the same,\n        //  so we don't need 'poller_send_blocked'. We need only 'poller_receive_blocked'.\n        //  We also don't need 'poller_both_blocked', no need to initialize it.\n        rc = poller_receive_blocked->add (frontend_, NULL, ZMQ_POLLOUT);\n        CHECK_RC_EXIT_ON_FAILURE ();\n    } else {\n        rc = poller_all->add (backend_, NULL,\n                              ZMQ_POLLIN | ZMQ_POLLOUT); //  Everything.\n        CHECK_RC_EXIT_ON_FAILURE ();\n        rc = poller_in->add (backend_, NULL, ZMQ_POLLIN); //  All 'ZMQ_POLLIN's.\n        CHECK_RC_EXIT_ON_FAILURE ();\n        rc = poller_both_blocked->add (\n          frontend_, NULL, ZMQ_POLLOUT); //  Waiting only for 'ZMQ_POLLOUT'.\n        CHECK_RC_EXIT_ON_FAILURE ();\n        rc = poller_both_blocked->add (\n          backend_, NULL, ZMQ_POLLOUT); //  Waiting only for 'ZMQ_POLLOUT'.\n        CHECK_RC_EXIT_ON_FAILURE ();\n        rc = poller_send_blocked->add (\n          backend_, NULL,\n          ZMQ_POLLOUT); //  All except 'ZMQ_POLLIN' on 'backend_'.\n        CHECK_RC_EXIT_ON_FAILURE ();\n        rc = poller_send_blocked->add (\n          frontend_, NULL,\n          ZMQ_POLLIN | ZMQ_POLLOUT); //  All except 'ZMQ_POLLIN' on 'backend_'.\n        CHECK_RC_EXIT_ON_FAILURE ();\n        rc = poller_receive_blocked->add (\n          frontend_, NULL,\n          ZMQ_POLLOUT); //  All except 'ZMQ_POLLIN' on 'frontend_'.\n        CHECK_RC_EXIT_ON_FAILURE ();\n        rc = poller_receive_blocked->add (\n          backend_, NULL,\n          ZMQ_POLLIN | ZMQ_POLLOUT); //  All except 'ZMQ_POLLIN' on 'frontend_'.\n        CHECK_RC_EXIT_ON_FAILURE ();\n        rc =\n          poller_frontend_only->add (frontend_, NULL, ZMQ_POLLIN | ZMQ_POLLOUT);\n        CHECK_RC_EXIT_ON_FAILURE ();\n        rc =\n          poller_backend_only->add (backend_, NULL, ZMQ_POLLIN | ZMQ_POLLOUT);\n        CHECK_RC_EXIT_ON_FAILURE ();\n    }\n\n    if (control_) {\n        ++nevents;\n\n        // wherever you go, there you are.\n\n        rc = poller_all->add (control_, NULL, ZMQ_POLLIN);\n        CHECK_RC_EXIT_ON_FAILURE ();\n\n        rc = poller_in->add (control_, NULL, ZMQ_POLLIN);\n        CHECK_RC_EXIT_ON_FAILURE ();\n\n        rc = poller_receive_blocked->add (control_, NULL, ZMQ_POLLIN);\n        CHECK_RC_EXIT_ON_FAILURE ();\n\n        rc = poller_send_blocked->add (control_, NULL, ZMQ_POLLIN);\n        CHECK_RC_EXIT_ON_FAILURE ();\n\n        rc = poller_both_blocked->add (control_, NULL, ZMQ_POLLIN);\n        CHECK_RC_EXIT_ON_FAILURE ();\n\n        rc = poller_frontend_only->add (control_, NULL, ZMQ_POLLIN);\n        CHECK_RC_EXIT_ON_FAILURE ();\n\n        rc = poller_backend_only->add (control_, NULL, ZMQ_POLLIN);\n        CHECK_RC_EXIT_ON_FAILURE ();\n    }\n\n    bool request_processed = false, reply_processed = false;\n\n    while (state != terminated) {\n        //  Blocking wait initially only for 'ZMQ_POLLIN' - 'poller_wait' points to 'poller_in'.\n        //  If one of receiving end's queue is full ('ZMQ_POLLOUT' not available),\n        //  'poller_wait' is pointed to 'poller_receive_blocked', 'poller_send_blocked' or 'poller_both_blocked'.\n        rc = poller_wait->wait (events, nevents, -1);\n        if (rc < 0 && errno == EAGAIN)\n            rc = 0;\n        CHECK_RC_EXIT_ON_FAILURE ();\n\n        //  Some of events waited for by 'poller_wait' have arrived, now poll for everything without blocking.\n        rc = poller_all->wait (events, nevents, 0);\n        if (rc < 0 && errno == EAGAIN)\n            rc = 0;\n        CHECK_RC_EXIT_ON_FAILURE ();\n\n        //  Process events.\n        for (int i = 0; i < rc; i++) {\n            if (control_ && events[i].socket == control_) {\n                rc = handle_control (control_, state, stats);\n                CHECK_RC_EXIT_ON_FAILURE ();\n                continue;\n            }\n\n            if (events[i].socket == frontend_) {\n                frontend_in = (events[i].events & ZMQ_POLLIN) != 0;\n                frontend_out = (events[i].events & ZMQ_POLLOUT) != 0;\n            } else\n                //  This 'if' needs to be after check for 'frontend_' in order never\n                //  to be reached in case frontend_==backend_, so we ensure backend_in=false in that case.\n                if (events[i].socket == backend_) {\n                    backend_in = (events[i].events & ZMQ_POLLIN) != 0;\n                    backend_out = (events[i].events & ZMQ_POLLOUT) != 0;\n                }\n        }\n\n        if (state == active) {\n            //  Process a request, 'ZMQ_POLLIN' on 'frontend_' and 'ZMQ_POLLOUT' on 'backend_'.\n            //  In case of frontend_==backend_ there's no 'ZMQ_POLLOUT' event.\n            if (frontend_in && (backend_out || frontend_equal_to_backend)) {\n                rc = forward (frontend_, backend_, capture_, &msg,\n                              stats.frontend.recv, stats.backend.send);\n                CHECK_RC_EXIT_ON_FAILURE ();\n                request_processed = true;\n                frontend_in = backend_out = false;\n            } else\n                request_processed = false;\n\n            //  Process a reply, 'ZMQ_POLLIN' on 'backend_' and 'ZMQ_POLLOUT' on 'frontend_'.\n            //  If 'frontend_' and 'backend_' are the same this is not needed because previous processing\n            //  covers all of the cases. 'backend_in' is always false if frontend_==backend_ due to\n            //  design in 'for' event processing loop.\n            if (backend_in && frontend_out) {\n                rc = forward (backend_, frontend_, capture_, &msg,\n                              stats.backend.recv, stats.frontend.send);\n                CHECK_RC_EXIT_ON_FAILURE ();\n                reply_processed = true;\n                backend_in = frontend_out = false;\n            } else\n                reply_processed = false;\n\n            if (request_processed || reply_processed) {\n                //  If request/reply is processed that means we had at least one 'ZMQ_POLLOUT' event.\n                //  Enable corresponding 'ZMQ_POLLIN' for blocking wait if any was disabled.\n                if (poller_wait != poller_in) {\n                    if (request_processed) { //  'frontend_' -> 'backend_'\n                        if (poller_wait == poller_both_blocked)\n                            poller_wait = poller_send_blocked;\n                        else if (poller_wait == poller_receive_blocked\n                                 || poller_wait == poller_frontend_only)\n                            poller_wait = poller_in;\n                    }\n                    if (reply_processed) { //  'backend_' -> 'frontend_'\n                        if (poller_wait == poller_both_blocked)\n                            poller_wait = poller_receive_blocked;\n                        else if (poller_wait == poller_send_blocked\n                                 || poller_wait == poller_backend_only)\n                            poller_wait = poller_in;\n                    }\n                }\n            } else {\n                //  No requests have been processed, there were no 'ZMQ_POLLIN' with corresponding 'ZMQ_POLLOUT' events.\n                //  That means that out queue(s) is/are full or one out queue is full and second one has no messages to process.\n                //  Disable receiving 'ZMQ_POLLIN' for sockets for which there's no 'ZMQ_POLLOUT',\n                //  or wait only on both 'backend_''s or 'frontend_''s 'ZMQ_POLLIN' and 'ZMQ_POLLOUT'.\n                if (frontend_in) {\n                    if (frontend_out)\n                        // If frontend_in and frontend_out are true, obviously backend_in and backend_out are both false.\n                        // In that case we need to wait for both 'ZMQ_POLLIN' and 'ZMQ_POLLOUT' only on 'backend_'.\n                        // We'll never get here in case of frontend_==backend_ because then frontend_out will always be false.\n                        poller_wait = poller_backend_only;\n                    else {\n                        if (poller_wait == poller_send_blocked)\n                            poller_wait = poller_both_blocked;\n                        else if (poller_wait == poller_in)\n                            poller_wait = poller_receive_blocked;\n                    }\n                }\n                if (backend_in) {\n                    //  Will never be reached if frontend_==backend_, 'backend_in' will\n                    //  always be false due to design in 'for' event processing loop.\n                    if (backend_out)\n                        // If backend_in and backend_out are true, obviously frontend_in and frontend_out are both false.\n                        // In that case we need to wait for both 'ZMQ_POLLIN' and 'ZMQ_POLLOUT' only on 'frontend_'.\n                        poller_wait = poller_frontend_only;\n                    else {\n                        if (poller_wait == poller_receive_blocked)\n                            poller_wait = poller_both_blocked;\n                        else if (poller_wait == poller_in)\n                            poller_wait = poller_send_blocked;\n                    }\n                }\n            }\n        }\n    }\n    PROXY_CLEANUP ();\n    return close_and_return (&msg, 0);\n}\n\n#else //  ZMQ_HAVE_POLLER\n\nint zmq::proxy_steerable (class socket_base_t *frontend_,\n                          class socket_base_t *backend_,\n                          class socket_base_t *capture_,\n                          class socket_base_t *control_)\n{\n    msg_t msg;\n    int rc = msg.init ();\n    if (rc != 0)\n        return -1;\n\n    //  The algorithm below assumes ratio of requests and replies processed\n    //  under full load to be 1:1.\n\n    zmq_pollitem_t items[] = {{frontend_, 0, ZMQ_POLLIN, 0},\n                              {backend_, 0, ZMQ_POLLIN, 0},\n                              {control_, 0, ZMQ_POLLIN, 0}};\n    const int qt_poll_items = control_ ? 3 : 2;\n\n    zmq_pollitem_t itemsout[] = {{frontend_, 0, ZMQ_POLLOUT, 0},\n                                 {backend_, 0, ZMQ_POLLOUT, 0}};\n\n    stats_proxy stats = {0};\n\n    //  Proxy can be in these three states\n    proxy_state_t state = active;\n\n    while (state != terminated) {\n        //  Wait while there are either requests or replies to process.\n        rc = zmq_poll (&items[0], qt_poll_items, -1);\n        if (unlikely (rc < 0))\n            return close_and_return (&msg, -1);\n\n        if (control_ && items[2].revents & ZMQ_POLLIN) {\n            rc = handle_control (control_, state, stats);\n            if (unlikely (rc < 0))\n                return close_and_return (&msg, -1);\n        }\n\n        //  Get the pollout separately because when combining this with pollin it maxes the CPU\n        //  because pollout shall most of the time return directly.\n        //  POLLOUT is only checked when frontend and backend sockets are not the same.\n        if (frontend_ != backend_) {\n            rc = zmq_poll (&itemsout[0], 2, 0);\n            if (unlikely (rc < 0)) {\n                return close_and_return (&msg, -1);\n            }\n        }\n\n        if (state == active && items[0].revents & ZMQ_POLLIN\n            && (frontend_ == backend_ || itemsout[1].revents & ZMQ_POLLOUT)) {\n            rc = forward (frontend_, backend_, capture_, &msg,\n                          stats.frontend.recv, stats.backend.send);\n            if (unlikely (rc < 0))\n                return close_and_return (&msg, -1);\n        }\n        //  Process a reply\n        if (state == active && frontend_ != backend_\n            && items[1].revents & ZMQ_POLLIN\n            && itemsout[0].revents & ZMQ_POLLOUT) {\n            rc = forward (backend_, frontend_, capture_, &msg,\n                          stats.backend.recv, stats.frontend.send);\n            if (unlikely (rc < 0))\n                return close_and_return (&msg, -1);\n        }\n    }\n\n    return close_and_return (&msg, 0);\n}\n\n#endif //  ZMQ_HAVE_POLLER\n"
  },
  {
    "path": "src/proxy.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PROXY_HPP_INCLUDED__\n#define __ZMQ_PROXY_HPP_INCLUDED__\n\nnamespace zmq\n{\nint proxy (class socket_base_t *frontend_,\n           class socket_base_t *backend_,\n           class socket_base_t *capture_);\n\nint proxy_steerable (class socket_base_t *frontend_,\n                     class socket_base_t *backend_,\n                     class socket_base_t *capture_,\n                     class socket_base_t *control_);\n}\n\n#endif\n"
  },
  {
    "path": "src/pub.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"pub.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n\nzmq::pub_t::pub_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    xpub_t (parent_, tid_, sid_)\n{\n    options.type = ZMQ_PUB;\n}\n\nzmq::pub_t::~pub_t ()\n{\n}\n\nvoid zmq::pub_t::xattach_pipe (pipe_t *pipe_,\n                               bool subscribe_to_all_,\n                               bool locally_initiated_)\n{\n    zmq_assert (pipe_);\n\n    //  Don't delay pipe termination as there is no one\n    //  to receive the delimiter.\n    pipe_->set_nodelay ();\n\n    xpub_t::xattach_pipe (pipe_, subscribe_to_all_, locally_initiated_);\n}\n\nint zmq::pub_t::xrecv (class msg_t *)\n{\n    //  Messages cannot be received from PUB socket.\n    errno = ENOTSUP;\n    return -1;\n}\n\nbool zmq::pub_t::xhas_in ()\n{\n    return false;\n}\n"
  },
  {
    "path": "src/pub.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PUB_HPP_INCLUDED__\n#define __ZMQ_PUB_HPP_INCLUDED__\n\n#include \"xpub.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass io_thread_t;\nclass socket_base_t;\nclass msg_t;\n\nclass pub_t ZMQ_FINAL : public xpub_t\n{\n  public:\n    pub_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~pub_t ();\n\n    //  Implementations of virtual functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_ = false,\n                       bool locally_initiated_ = false);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (pub_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/pull.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"pull.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n#include \"pipe.hpp\"\n\nzmq::pull_t::pull_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_)\n{\n    options.type = ZMQ_PULL;\n}\n\nzmq::pull_t::~pull_t ()\n{\n}\n\nvoid zmq::pull_t::xattach_pipe (pipe_t *pipe_,\n                                bool subscribe_to_all_,\n                                bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_);\n    _fq.attach (pipe_);\n}\n\nvoid zmq::pull_t::xread_activated (pipe_t *pipe_)\n{\n    _fq.activated (pipe_);\n}\n\nvoid zmq::pull_t::xpipe_terminated (pipe_t *pipe_)\n{\n    _fq.pipe_terminated (pipe_);\n}\n\nint zmq::pull_t::xrecv (msg_t *msg_)\n{\n    return _fq.recv (msg_);\n}\n\nbool zmq::pull_t::xhas_in ()\n{\n    return _fq.has_in ();\n}\n"
  },
  {
    "path": "src/pull.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PULL_HPP_INCLUDED__\n#define __ZMQ_PULL_HPP_INCLUDED__\n\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n#include \"fq.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass pipe_t;\nclass msg_t;\nclass io_thread_t;\n\nclass pull_t ZMQ_FINAL : public socket_base_t\n{\n  public:\n    pull_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~pull_t ();\n\n  protected:\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    void xread_activated (zmq::pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n\n  private:\n    //  Fair queueing object for inbound pipes.\n    fq_t _fq;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (pull_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/push.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"push.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n\nzmq::push_t::push_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_)\n{\n    options.type = ZMQ_PUSH;\n}\n\nzmq::push_t::~push_t ()\n{\n}\n\nvoid zmq::push_t::xattach_pipe (pipe_t *pipe_,\n                                bool subscribe_to_all_,\n                                bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    //  Don't delay pipe termination as there is no one\n    //  to receive the delimiter.\n    pipe_->set_nodelay ();\n\n    zmq_assert (pipe_);\n    _lb.attach (pipe_);\n}\n\nvoid zmq::push_t::xwrite_activated (pipe_t *pipe_)\n{\n    _lb.activated (pipe_);\n}\n\nvoid zmq::push_t::xpipe_terminated (pipe_t *pipe_)\n{\n    _lb.pipe_terminated (pipe_);\n}\n\nint zmq::push_t::xsend (msg_t *msg_)\n{\n    return _lb.send (msg_);\n}\n\nbool zmq::push_t::xhas_out ()\n{\n    return _lb.has_out ();\n}\n"
  },
  {
    "path": "src/push.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_PUSH_HPP_INCLUDED__\n#define __ZMQ_PUSH_HPP_INCLUDED__\n\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n#include \"lb.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass pipe_t;\nclass msg_t;\nclass io_thread_t;\n\nclass push_t ZMQ_FINAL : public socket_base_t\n{\n  public:\n    push_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~push_t ();\n\n  protected:\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xsend (zmq::msg_t *msg_);\n    bool xhas_out ();\n    void xwrite_activated (zmq::pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n\n  private:\n    //  Load balancer managing the outbound pipes.\n    lb_t _lb;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (push_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/radio.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string.h>\n\n#include \"radio.hpp\"\n#include \"macros.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n\nzmq::radio_t::radio_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_, true), _lossy (true)\n{\n    options.type = ZMQ_RADIO;\n}\n\nzmq::radio_t::~radio_t ()\n{\n}\n\nvoid zmq::radio_t::xattach_pipe (pipe_t *pipe_,\n                                 bool subscribe_to_all_,\n                                 bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_);\n\n    //  Don't delay pipe termination as there is no one\n    //  to receive the delimiter.\n    pipe_->set_nodelay ();\n\n    _dist.attach (pipe_);\n\n    if (subscribe_to_all_)\n        _udp_pipes.push_back (pipe_);\n    //  The pipe is active when attached. Let's read the subscriptions from\n    //  it, if any.\n    else\n        xread_activated (pipe_);\n}\n\nvoid zmq::radio_t::xread_activated (pipe_t *pipe_)\n{\n    //  There are some subscriptions waiting. Let's process them.\n    msg_t msg;\n    while (pipe_->read (&msg)) {\n        //  Apply the subscription to the trie\n        if (msg.is_join () || msg.is_leave ()) {\n            std::string group = std::string (msg.group ());\n\n            if (msg.is_join ())\n                _subscriptions.ZMQ_MAP_INSERT_OR_EMPLACE (ZMQ_MOVE (group),\n                                                          pipe_);\n            else {\n                std::pair<subscriptions_t::iterator, subscriptions_t::iterator>\n                  range = _subscriptions.equal_range (group);\n\n                for (subscriptions_t::iterator it = range.first;\n                     it != range.second; ++it) {\n                    if (it->second == pipe_) {\n                        _subscriptions.erase (it);\n                        break;\n                    }\n                }\n            }\n        }\n        msg.close ();\n    }\n}\n\nvoid zmq::radio_t::xwrite_activated (pipe_t *pipe_)\n{\n    _dist.activated (pipe_);\n}\nint zmq::radio_t::xsetsockopt (int option_,\n                               const void *optval_,\n                               size_t optvallen_)\n{\n    if (optvallen_ != sizeof (int) || *static_cast<const int *> (optval_) < 0) {\n        errno = EINVAL;\n        return -1;\n    }\n    if (option_ == ZMQ_XPUB_NODROP)\n        _lossy = (*static_cast<const int *> (optval_) == 0);\n    else {\n        errno = EINVAL;\n        return -1;\n    }\n    return 0;\n}\n\nvoid zmq::radio_t::xpipe_terminated (pipe_t *pipe_)\n{\n    for (subscriptions_t::iterator it = _subscriptions.begin (),\n                                   end = _subscriptions.end ();\n         it != end;) {\n        if (it->second == pipe_) {\n#if __cplusplus >= 201103L || (defined _MSC_VER && _MSC_VER >= 1700)\n            it = _subscriptions.erase (it);\n#else\n            _subscriptions.erase (it++);\n#endif\n        } else {\n            ++it;\n        }\n    }\n\n    {\n        const udp_pipes_t::iterator end = _udp_pipes.end ();\n        const udp_pipes_t::iterator it =\n          std::find (_udp_pipes.begin (), end, pipe_);\n        if (it != end)\n            _udp_pipes.erase (it);\n    }\n\n    _dist.pipe_terminated (pipe_);\n}\n\nint zmq::radio_t::xsend (msg_t *msg_)\n{\n    //  Radio sockets do not allow multipart data (ZMQ_SNDMORE)\n    if (msg_->flags () & msg_t::more) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    _dist.unmatch ();\n\n    const std::pair<subscriptions_t::iterator, subscriptions_t::iterator>\n      range = _subscriptions.equal_range (std::string (msg_->group ()));\n\n    for (subscriptions_t::iterator it = range.first; it != range.second; ++it)\n        _dist.match (it->second);\n\n    for (udp_pipes_t::iterator it = _udp_pipes.begin (),\n                               end = _udp_pipes.end ();\n         it != end; ++it)\n        _dist.match (*it);\n\n    int rc = -1;\n    if (_lossy || _dist.check_hwm ()) {\n        if (_dist.send_to_matching (msg_) == 0) {\n            rc = 0; //  Yay, sent successfully\n        }\n    } else\n        errno = EAGAIN;\n\n    return rc;\n}\n\nbool zmq::radio_t::xhas_out ()\n{\n    return _dist.has_out ();\n}\n\nint zmq::radio_t::xrecv (msg_t *msg_)\n{\n    //  Messages cannot be received from PUB socket.\n    LIBZMQ_UNUSED (msg_);\n    errno = ENOTSUP;\n    return -1;\n}\n\nbool zmq::radio_t::xhas_in ()\n{\n    return false;\n}\n\nzmq::radio_session_t::radio_session_t (io_thread_t *io_thread_,\n                                       bool connect_,\n                                       socket_base_t *socket_,\n                                       const options_t &options_,\n                                       address_t *addr_) :\n    session_base_t (io_thread_, connect_, socket_, options_, addr_),\n    _state (group)\n{\n}\n\nzmq::radio_session_t::~radio_session_t ()\n{\n}\n\nint zmq::radio_session_t::push_msg (msg_t *msg_)\n{\n    if (msg_->flags () & msg_t::command) {\n        char *command_data = static_cast<char *> (msg_->data ());\n        const size_t data_size = msg_->size ();\n\n        int group_length;\n        const char *group;\n\n        msg_t join_leave_msg;\n        int rc;\n\n        //  Set the msg type to either JOIN or LEAVE\n        if (data_size >= 5 && memcmp (command_data, \"\\4JOIN\", 5) == 0) {\n            group_length = static_cast<int> (data_size) - 5;\n            group = command_data + 5;\n            rc = join_leave_msg.init_join ();\n        } else if (data_size >= 6 && memcmp (command_data, \"\\5LEAVE\", 6) == 0) {\n            group_length = static_cast<int> (data_size) - 6;\n            group = command_data + 6;\n            rc = join_leave_msg.init_leave ();\n        }\n        //  If it is not a JOIN or LEAVE just push the message\n        else\n            return session_base_t::push_msg (msg_);\n\n        errno_assert (rc == 0);\n\n        //  Set the group\n        rc = join_leave_msg.set_group (group, group_length);\n        errno_assert (rc == 0);\n\n        //  Close the current command\n        rc = msg_->close ();\n        errno_assert (rc == 0);\n\n        //  Push the join or leave command\n        *msg_ = join_leave_msg;\n        return session_base_t::push_msg (msg_);\n    }\n    return session_base_t::push_msg (msg_);\n}\n\nint zmq::radio_session_t::pull_msg (msg_t *msg_)\n{\n    if (_state == group) {\n        int rc = session_base_t::pull_msg (&_pending_msg);\n        if (rc != 0)\n            return rc;\n\n        const char *group = _pending_msg.group ();\n        const int length = static_cast<int> (strlen (group));\n\n        //  First frame is the group\n        rc = msg_->init_size (length);\n        errno_assert (rc == 0);\n        msg_->set_flags (msg_t::more);\n        memcpy (msg_->data (), group, length);\n\n        //  Next status is the body\n        _state = body;\n        return 0;\n    }\n    *msg_ = _pending_msg;\n    _state = group;\n    return 0;\n}\n\nvoid zmq::radio_session_t::reset ()\n{\n    session_base_t::reset ();\n    _state = group;\n}\n"
  },
  {
    "path": "src/radio.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_RADIO_HPP_INCLUDED__\n#define __ZMQ_RADIO_HPP_INCLUDED__\n\n#include <map>\n#include <string>\n#include <vector>\n\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n#include \"dist.hpp\"\n#include \"msg.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass pipe_t;\nclass io_thread_t;\n\nclass radio_t ZMQ_FINAL : public socket_base_t\n{\n  public:\n    radio_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~radio_t ();\n\n    //  Implementations of virtual functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_ = false,\n                       bool locally_initiated_ = false);\n    int xsend (zmq::msg_t *msg_);\n    bool xhas_out ();\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    void xread_activated (zmq::pipe_t *pipe_);\n    void xwrite_activated (zmq::pipe_t *pipe_);\n    int xsetsockopt (int option_, const void *optval_, size_t optvallen_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n\n  private:\n    //  List of all subscriptions mapped to corresponding pipes.\n    typedef std::multimap<std::string, pipe_t *> subscriptions_t;\n    subscriptions_t _subscriptions;\n\n    //  List of udp pipes\n    typedef std::vector<pipe_t *> udp_pipes_t;\n    udp_pipes_t _udp_pipes;\n\n    //  Distributor of messages holding the list of outbound pipes.\n    dist_t _dist;\n\n    //  Drop messages if HWM reached, otherwise return with EAGAIN\n    bool _lossy;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (radio_t)\n};\n\nclass radio_session_t ZMQ_FINAL : public session_base_t\n{\n  public:\n    radio_session_t (zmq::io_thread_t *io_thread_,\n                     bool connect_,\n                     zmq::socket_base_t *socket_,\n                     const options_t &options_,\n                     address_t *addr_);\n    ~radio_session_t ();\n\n    //  Overrides of the functions from session_base_t.\n    int push_msg (msg_t *msg_);\n    int pull_msg (msg_t *msg_);\n    void reset ();\n\n  private:\n    enum\n    {\n        group,\n        body\n    } _state;\n\n    msg_t _pending_msg;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (radio_session_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/radix_tree.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"err.hpp\"\n#include \"radix_tree.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n#include <iterator>\n#include <vector>\n\nnode_t::node_t (unsigned char *data_) : _data (data_)\n{\n}\n\nuint32_t node_t::refcount ()\n{\n    uint32_t u32;\n    memcpy (&u32, _data, sizeof (u32));\n    return u32;\n}\n\nvoid node_t::set_refcount (uint32_t value_)\n{\n    memcpy (_data, &value_, sizeof (value_));\n}\n\nuint32_t node_t::prefix_length ()\n{\n    uint32_t u32;\n    memcpy (&u32, _data + sizeof (uint32_t), sizeof (u32));\n    return u32;\n}\n\nvoid node_t::set_prefix_length (uint32_t value_)\n{\n    memcpy (_data + sizeof (value_), &value_, sizeof (value_));\n}\n\nuint32_t node_t::edgecount ()\n{\n    uint32_t u32;\n    memcpy (&u32, _data + 2 * sizeof (uint32_t), sizeof (u32));\n    return u32;\n}\n\nvoid node_t::set_edgecount (uint32_t value_)\n{\n    memcpy (_data + 2 * sizeof (value_), &value_, sizeof (value_));\n}\n\nunsigned char *node_t::prefix ()\n{\n    return _data + 3 * sizeof (uint32_t);\n}\n\nvoid node_t::set_prefix (const unsigned char *bytes_)\n{\n    memcpy (prefix (), bytes_, prefix_length ());\n}\n\nunsigned char *node_t::first_bytes ()\n{\n    return prefix () + prefix_length ();\n}\n\nvoid node_t::set_first_bytes (const unsigned char *bytes_)\n{\n    memcpy (first_bytes (), bytes_, edgecount ());\n}\n\nunsigned char node_t::first_byte_at (size_t index_)\n{\n    zmq_assert (index_ < edgecount ());\n    return first_bytes ()[index_];\n}\n\nvoid node_t::set_first_byte_at (size_t index_, unsigned char byte_)\n{\n    zmq_assert (index_ < edgecount ());\n    first_bytes ()[index_] = byte_;\n}\n\nunsigned char *node_t::node_pointers ()\n{\n    return prefix () + prefix_length () + edgecount ();\n}\n\nvoid node_t::set_node_pointers (const unsigned char *pointers_)\n{\n    memcpy (node_pointers (), pointers_, edgecount () * sizeof (void *));\n}\n\nnode_t node_t::node_at (size_t index_)\n{\n    zmq_assert (index_ < edgecount ());\n\n    unsigned char *data;\n    memcpy (&data, node_pointers () + index_ * sizeof (void *), sizeof (data));\n    return node_t (data);\n}\n\nvoid node_t::set_node_at (size_t index_, node_t node_)\n{\n    zmq_assert (index_ < edgecount ());\n    memcpy (node_pointers () + index_ * sizeof (void *), &node_._data,\n            sizeof (node_._data));\n}\n\nvoid node_t::set_edge_at (size_t index_,\n                          unsigned char first_byte_,\n                          node_t node_)\n{\n    set_first_byte_at (index_, first_byte_);\n    set_node_at (index_, node_);\n}\n\nbool node_t::operator== (node_t other_) const\n{\n    return _data == other_._data;\n}\n\nbool node_t::operator!= (node_t other_) const\n{\n    return !(*this == other_);\n}\n\nvoid node_t::resize (size_t prefix_length_, size_t edgecount_)\n{\n    const size_t node_size = 3 * sizeof (uint32_t) + prefix_length_\n                             + edgecount_ * (1 + sizeof (void *));\n    unsigned char *new_data =\n      static_cast<unsigned char *> (realloc (_data, node_size));\n    zmq_assert (new_data);\n    _data = new_data;\n    set_prefix_length (static_cast<uint32_t> (prefix_length_));\n    set_edgecount (static_cast<uint32_t> (edgecount_));\n}\n\nnode_t make_node (size_t refcount_, size_t prefix_length_, size_t edgecount_)\n{\n    const size_t node_size = 3 * sizeof (uint32_t) + prefix_length_\n                             + edgecount_ * (1 + sizeof (void *));\n\n    unsigned char *data = static_cast<unsigned char *> (malloc (node_size));\n    zmq_assert (data);\n\n    node_t node (data);\n    node.set_refcount (static_cast<uint32_t> (refcount_));\n    node.set_prefix_length (static_cast<uint32_t> (prefix_length_));\n    node.set_edgecount (static_cast<uint32_t> (edgecount_));\n    return node;\n}\n\n// ----------------------------------------------------------------------\n\nzmq::radix_tree_t::radix_tree_t () : _root (make_node (0, 0, 0)), _size (0)\n{\n}\n\nstatic void free_nodes (node_t node_)\n{\n    for (size_t i = 0, count = node_.edgecount (); i < count; ++i)\n        free_nodes (node_.node_at (i));\n    free (node_._data);\n}\n\nzmq::radix_tree_t::~radix_tree_t ()\n{\n    free_nodes (_root);\n}\n\nmatch_result_t::match_result_t (size_t key_bytes_matched_,\n                                size_t prefix_bytes_matched_,\n                                size_t edge_index_,\n                                size_t parent_edge_index_,\n                                node_t current_,\n                                node_t parent_,\n                                node_t grandparent_) :\n    _key_bytes_matched (key_bytes_matched_),\n    _prefix_bytes_matched (prefix_bytes_matched_),\n    _edge_index (edge_index_),\n    _parent_edge_index (parent_edge_index_),\n    _current_node (current_),\n    _parent_node (parent_),\n    _grandparent_node (grandparent_)\n{\n}\n\nmatch_result_t zmq::radix_tree_t::match (const unsigned char *key_,\n                                         size_t key_size_,\n                                         bool is_lookup_ = false) const\n{\n    zmq_assert (key_);\n\n    // Node we're currently at in the traversal and its predecessors.\n    node_t current_node = _root;\n    node_t parent_node = current_node;\n    node_t grandparent_node = current_node;\n    // Index of the next byte to match in the key.\n    size_t key_byte_index = 0;\n    // Index of the next byte to match in the current node's prefix.\n    size_t prefix_byte_index = 0;\n    // Index of the edge from parent to current node.\n    size_t edge_index = 0;\n    // Index of the edge from grandparent to parent.\n    size_t parent_edge_index = 0;\n\n    while (current_node.prefix_length () > 0 || current_node.edgecount () > 0) {\n        const unsigned char *const prefix = current_node.prefix ();\n        const size_t prefix_length = current_node.prefix_length ();\n\n        for (prefix_byte_index = 0;\n             prefix_byte_index < prefix_length && key_byte_index < key_size_;\n             ++prefix_byte_index, ++key_byte_index) {\n            if (prefix[prefix_byte_index] != key_[key_byte_index])\n                break;\n        }\n\n        // Even if a prefix of the key matches and we're doing a\n        // lookup, this means we've found a matching subscription.\n        if (is_lookup_ && prefix_byte_index == prefix_length\n            && current_node.refcount () > 0) {\n            key_byte_index = key_size_;\n            break;\n        }\n\n        // There was a mismatch or we've matched the whole key, so\n        // there's nothing more to do.\n        if (prefix_byte_index != prefix_length || key_byte_index == key_size_)\n            break;\n\n        // We need to match the rest of the key. Check if there's an\n        // outgoing edge from this node.\n        node_t next_node = current_node;\n        for (size_t i = 0, edgecount = current_node.edgecount (); i < edgecount;\n             ++i) {\n            if (current_node.first_byte_at (i) == key_[key_byte_index]) {\n                parent_edge_index = edge_index;\n                edge_index = i;\n                next_node = current_node.node_at (i);\n                break;\n            }\n        }\n\n        if (next_node == current_node)\n            break; // No outgoing edge.\n        grandparent_node = parent_node;\n        parent_node = current_node;\n        current_node = next_node;\n    }\n\n    return match_result_t (key_byte_index, prefix_byte_index, edge_index,\n                           parent_edge_index, current_node, parent_node,\n                           grandparent_node);\n}\n\nbool zmq::radix_tree_t::add (const unsigned char *key_, size_t key_size_)\n{\n    const match_result_t match_result = match (key_, key_size_);\n    const size_t key_bytes_matched = match_result._key_bytes_matched;\n    const size_t prefix_bytes_matched = match_result._prefix_bytes_matched;\n    const size_t edge_index = match_result._edge_index;\n    node_t current_node = match_result._current_node;\n    node_t parent_node = match_result._parent_node;\n\n    if (key_bytes_matched != key_size_) {\n        // Not all characters match, we might have to split the node.\n        if (prefix_bytes_matched == current_node.prefix_length ()) {\n            // The mismatch is at one of the outgoing edges, so we\n            // create an edge from the current node to a new leaf node\n            // that has the rest of the key as the prefix.\n            node_t key_node = make_node (1, key_size_ - key_bytes_matched, 0);\n            key_node.set_prefix (key_ + key_bytes_matched);\n\n            // Reallocate for one more edge.\n            current_node.resize (current_node.prefix_length (),\n                                 current_node.edgecount () + 1);\n\n            // Make room for the new edge. We need to shift the chunk\n            // of node pointers one byte to the right. Since resize()\n            // increments the edgecount by 1, node_pointers() tells us the\n            // destination address. The chunk of node pointers starts\n            // at one byte to the left of this destination.\n            //\n            // Since the regions can overlap, we use memmove.\n            memmove (current_node.node_pointers (),\n                     current_node.node_pointers () - 1,\n                     (current_node.edgecount () - 1) * sizeof (void *));\n\n            // Add an edge to the new node.\n            current_node.set_edge_at (current_node.edgecount () - 1,\n                                      key_[key_bytes_matched], key_node);\n\n            // We need to update all pointers to the current node\n            // after the call to resize().\n            if (current_node.prefix_length () == 0)\n                _root._data = current_node._data;\n            else\n                parent_node.set_node_at (edge_index, current_node);\n            _size.add (1);\n            return true;\n        }\n\n        // There was a mismatch, so we need to split this node.\n        //\n        // Create two nodes that will be reachable from the parent.\n        // One node will have the rest of the characters from the key,\n        // and the other node will have the rest of the characters\n        // from the current node's prefix.\n        node_t key_node = make_node (1, key_size_ - key_bytes_matched, 0);\n        node_t split_node =\n          make_node (current_node.refcount (),\n                     current_node.prefix_length () - prefix_bytes_matched,\n                     current_node.edgecount ());\n\n        // Copy the prefix chunks to the new nodes.\n        key_node.set_prefix (key_ + key_bytes_matched);\n        split_node.set_prefix (current_node.prefix () + prefix_bytes_matched);\n\n        // Copy the current node's edges to the new node.\n        split_node.set_first_bytes (current_node.first_bytes ());\n        split_node.set_node_pointers (current_node.node_pointers ());\n\n        // Resize the current node to accommodate a prefix comprising\n        // the matched characters and 2 outgoing edges to the above\n        // nodes. Set the refcount to 0 since this node doesn't hold a\n        // key.\n        current_node.resize (prefix_bytes_matched, 2);\n        current_node.set_refcount (0);\n\n        // Add links to the new nodes. We don't need to copy the\n        // prefix since resize() retains it in the current node.\n        current_node.set_edge_at (0, key_node.prefix ()[0], key_node);\n        current_node.set_edge_at (1, split_node.prefix ()[0], split_node);\n\n        _size.add (1);\n        parent_node.set_node_at (edge_index, current_node);\n        return true;\n    }\n\n    // All characters in the key match, but we still might need to split.\n    if (prefix_bytes_matched != current_node.prefix_length ()) {\n        // All characters in the key match, but not all characters\n        // from the current node's prefix match.\n\n        // Create a node that contains the rest of the characters from\n        // the current node's prefix and the outgoing edges from the\n        // current node.\n        node_t split_node =\n          make_node (current_node.refcount (),\n                     current_node.prefix_length () - prefix_bytes_matched,\n                     current_node.edgecount ());\n        split_node.set_prefix (current_node.prefix () + prefix_bytes_matched);\n        split_node.set_first_bytes (current_node.first_bytes ());\n        split_node.set_node_pointers (current_node.node_pointers ());\n\n        // Resize the current node to hold only the matched characters\n        // from its prefix and one edge to the new node.\n        current_node.resize (prefix_bytes_matched, 1);\n\n        // Add an edge to the split node and set the refcount to 1\n        // since this key wasn't inserted earlier. We don't need to\n        // set the prefix because the first `prefix_bytes_matched` bytes\n        // in the prefix are preserved by resize().\n        current_node.set_edge_at (0, split_node.prefix ()[0], split_node);\n        current_node.set_refcount (1);\n\n        _size.add (1);\n        parent_node.set_node_at (edge_index, current_node);\n        return true;\n    }\n\n    zmq_assert (key_bytes_matched == key_size_);\n    zmq_assert (prefix_bytes_matched == current_node.prefix_length ());\n\n    _size.add (1);\n    current_node.set_refcount (current_node.refcount () + 1);\n    return current_node.refcount () == 1;\n}\n\nbool zmq::radix_tree_t::rm (const unsigned char *key_, size_t key_size_)\n{\n    const match_result_t match_result = match (key_, key_size_);\n    const size_t key_bytes_matched = match_result._key_bytes_matched;\n    const size_t prefix_bytes_matched = match_result._prefix_bytes_matched;\n    const size_t edge_index = match_result._edge_index;\n    const size_t parent_edge_index = match_result._parent_edge_index;\n    node_t current_node = match_result._current_node;\n    node_t parent_node = match_result._parent_node;\n    node_t grandparent_node = match_result._grandparent_node;\n\n    if (key_bytes_matched != key_size_\n        || prefix_bytes_matched != current_node.prefix_length ()\n        || current_node.refcount () == 0)\n        return false;\n\n    current_node.set_refcount (current_node.refcount () - 1);\n    _size.sub (1);\n    if (current_node.refcount () > 0)\n        return false;\n\n    // Don't delete the root node.\n    if (current_node == _root)\n        return true;\n\n    const size_t outgoing_edges = current_node.edgecount ();\n    if (outgoing_edges > 1)\n        // This node can't be merged with any other node, so there's\n        // nothing more to do.\n        return true;\n\n    if (outgoing_edges == 1) {\n        // Merge this node with the single child node.\n        node_t child = current_node.node_at (0);\n\n        // Make room for the child node's prefix and edges. We need to\n        // keep the old prefix length since resize() will overwrite\n        // it.\n        const uint32_t old_prefix_length = current_node.prefix_length ();\n        current_node.resize (old_prefix_length + child.prefix_length (),\n                             child.edgecount ());\n\n        // Append the child node's prefix to the current node.\n        memcpy (current_node.prefix () + old_prefix_length, child.prefix (),\n                child.prefix_length ());\n\n        // Copy the rest of child node's data to the current node.\n        current_node.set_first_bytes (child.first_bytes ());\n        current_node.set_node_pointers (child.node_pointers ());\n        current_node.set_refcount (child.refcount ());\n\n        free (child._data);\n        parent_node.set_node_at (edge_index, current_node);\n        return true;\n    }\n\n    if (parent_node.edgecount () == 2 && parent_node.refcount () == 0\n        && parent_node != _root) {\n        // Removing this node leaves the parent with one child.\n        // If the parent doesn't hold a key or if it isn't the root,\n        // we can merge it with its single child node.\n        zmq_assert (edge_index < 2);\n        node_t other_child = parent_node.node_at (!edge_index);\n\n        // Make room for the child node's prefix and edges. We need to\n        // keep the old prefix length since resize() will overwrite\n        // it.\n        const uint32_t old_prefix_length = parent_node.prefix_length ();\n        parent_node.resize (old_prefix_length + other_child.prefix_length (),\n                            other_child.edgecount ());\n\n        // Append the child node's prefix to the current node.\n        memcpy (parent_node.prefix () + old_prefix_length,\n                other_child.prefix (), other_child.prefix_length ());\n\n        // Copy the rest of child node's data to the current node.\n        parent_node.set_first_bytes (other_child.first_bytes ());\n        parent_node.set_node_pointers (other_child.node_pointers ());\n        parent_node.set_refcount (other_child.refcount ());\n\n        free (current_node._data);\n        free (other_child._data);\n        grandparent_node.set_node_at (parent_edge_index, parent_node);\n        return true;\n    }\n\n    // This is a leaf node that doesn't leave its parent with one\n    // outgoing edge. Remove the outgoing edge to this node from the\n    // parent.\n    zmq_assert (outgoing_edges == 0);\n\n    // Replace the edge to the current node with the last edge. An\n    // edge consists of a byte and a pointer to the next node. First\n    // replace the byte.\n    const size_t last_index = parent_node.edgecount () - 1;\n    const unsigned char last_byte = parent_node.first_byte_at (last_index);\n    const node_t last_node = parent_node.node_at (last_index);\n    parent_node.set_edge_at (edge_index, last_byte, last_node);\n\n    // Move the chunk of pointers one byte to the left, effectively\n    // deleting the last byte in the region of first bytes by\n    // overwriting it.\n    memmove (parent_node.node_pointers () - 1, parent_node.node_pointers (),\n             parent_node.edgecount () * sizeof (void *));\n\n    // Shrink the parent node to the new size, which \"deletes\" the\n    // last pointer in the chunk of node pointers.\n    parent_node.resize (parent_node.prefix_length (),\n                        parent_node.edgecount () - 1);\n\n    // Nothing points to this node now, so we can reclaim it.\n    free (current_node._data);\n\n    if (parent_node.prefix_length () == 0)\n        _root._data = parent_node._data;\n    else\n        grandparent_node.set_node_at (parent_edge_index, parent_node);\n    return true;\n}\n\nbool zmq::radix_tree_t::check (const unsigned char *key_, size_t key_size_)\n{\n    if (_root.refcount () > 0)\n        return true;\n\n    match_result_t match_result = match (key_, key_size_, true);\n    return match_result._key_bytes_matched == key_size_\n           && match_result._prefix_bytes_matched\n                == match_result._current_node.prefix_length ()\n           && match_result._current_node.refcount () > 0;\n}\n\nstatic void\nvisit_keys (node_t node_,\n            std::vector<unsigned char> &buffer_,\n            void (*func_) (unsigned char *data_, size_t size_, void *arg_),\n            void *arg_)\n{\n    const size_t prefix_length = node_.prefix_length ();\n    buffer_.reserve (buffer_.size () + prefix_length);\n    std::copy (node_.prefix (), node_.prefix () + prefix_length,\n               std::back_inserter (buffer_));\n\n    if (node_.refcount () > 0) {\n        zmq_assert (!buffer_.empty ());\n        func_ (&buffer_[0], buffer_.size (), arg_);\n    }\n\n    for (size_t i = 0, edgecount = node_.edgecount (); i < edgecount; ++i) {\n        visit_keys (node_.node_at (i), buffer_, func_, arg_);\n    }\n    buffer_.resize (static_cast<uint32_t> (buffer_.size () - prefix_length));\n}\n\nvoid zmq::radix_tree_t::apply (\n  void (*func_) (unsigned char *data_, size_t size_, void *arg_), void *arg_)\n{\n    if (_root.refcount () > 0)\n        func_ (NULL, 0, arg_); // Root node is always empty.\n\n    std::vector<unsigned char> buffer;\n    for (size_t i = 0; i < _root.edgecount (); ++i)\n        visit_keys (_root.node_at (i), buffer, func_, arg_);\n}\n\nsize_t zmq::radix_tree_t::size () const\n{\n    return _size.get ();\n}\n"
  },
  {
    "path": "src/radix_tree.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef RADIX_TREE_HPP\n#define RADIX_TREE_HPP\n\n#include <stddef.h>\n\n#include \"stdint.hpp\"\n#include \"atomic_counter.hpp\"\n\n// Wrapper type for a node's data layout.\n//\n// There are 3 32-bit unsigned integers that act as a header. These\n// integers represent the following values in this order:\n//\n// (1) The reference count of the key held by the node. This is 0 if\n// the node doesn't hold a key.\n//\n// (2) The number of characters in the node's prefix. The prefix is a\n// part of one or more keys in the tree, e.g. the prefix of each node\n// in a trie consists of a single character.\n//\n// (3) The number of outgoing edges from this node.\n//\n// The rest of the layout consists of 3 chunks in this order:\n//\n// (1) The node's prefix as a sequence of one or more bytes. The root\n// node always has an empty prefix, unlike other nodes in the tree.\n//\n// (2) The first byte of the prefix of each of this node's children.\n//\n// (3) The pointer to each child node.\n//\n// The link to each child is looked up using its index, e.g. the child\n// with index 0 will have its first byte and node pointer at the start\n// of the chunk of first bytes and node pointers respectively.\nstruct node_t\n{\n    explicit node_t (unsigned char *data_);\n\n    bool operator== (node_t other_) const;\n    bool operator!= (node_t other_) const;\n\n    uint32_t refcount ();\n    uint32_t prefix_length ();\n    uint32_t edgecount ();\n    unsigned char *prefix ();\n    unsigned char *first_bytes ();\n    unsigned char first_byte_at (size_t index_);\n    unsigned char *node_pointers ();\n    node_t node_at (size_t index_);\n    void set_refcount (uint32_t value_);\n    void set_prefix_length (uint32_t value_);\n    void set_edgecount (uint32_t value_);\n    void set_prefix (const unsigned char *bytes_);\n    void set_first_bytes (const unsigned char *bytes_);\n    void set_first_byte_at (size_t index_, unsigned char byte_);\n    void set_node_pointers (const unsigned char *pointers_);\n    void set_node_at (size_t index_, node_t node_);\n    void set_edge_at (size_t index_, unsigned char first_byte_, node_t node_);\n    void resize (size_t prefix_length_, size_t edgecount_);\n\n    unsigned char *_data;\n};\n\nnode_t make_node (size_t refcount_, size_t prefix_length_, size_t edgecount_);\n\nstruct match_result_t\n{\n    match_result_t (size_t key_bytes_matched_,\n                    size_t prefix_bytes_matched_,\n                    size_t edge_index_,\n                    size_t parent_edge_index_,\n                    node_t current_,\n                    node_t parent_,\n                    node_t grandparent);\n\n    size_t _key_bytes_matched;\n    size_t _prefix_bytes_matched;\n    size_t _edge_index;\n    size_t _parent_edge_index;\n    node_t _current_node;\n    node_t _parent_node;\n    node_t _grandparent_node;\n};\n\nnamespace zmq\n{\nclass radix_tree_t\n{\n  public:\n    radix_tree_t ();\n    ~radix_tree_t ();\n\n    //  Add key to the tree. Returns true if this was a new key rather\n    //  than a duplicate.\n    bool add (const unsigned char *key_, size_t key_size_);\n\n    //  Remove key from the tree. Returns true if the item is actually\n    //  removed from the tree.\n    bool rm (const unsigned char *key_, size_t key_size_);\n\n    //  Check whether particular key is in the tree.\n    bool check (const unsigned char *key_, size_t key_size_);\n\n    //  Apply the function supplied to each key in the tree.\n    void apply (void (*func_) (unsigned char *data, size_t size, void *arg),\n                void *arg_);\n\n    //  Retrieve size of the radix tree. Note this is a multithread safe function.\n    size_t size () const;\n\n  private:\n    match_result_t\n    match (const unsigned char *key_, size_t key_size_, bool is_lookup_) const;\n\n    node_t _root;\n    atomic_counter_t _size;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/random.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <stdlib.h>\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#endif\n\n#include \"random.hpp\"\n#include \"stdint.hpp\"\n#include \"clock.hpp\"\n#include \"mutex.hpp\"\n#include \"macros.hpp\"\n\n#if defined(ZMQ_USE_LIBSODIUM)\n#include \"sodium.h\"\n#endif\n\nvoid zmq::seed_random ()\n{\n#if defined ZMQ_HAVE_WINDOWS\n    const int pid = static_cast<int> (GetCurrentProcessId ());\n#else\n    int pid = static_cast<int> (getpid ());\n#endif\n    srand (static_cast<unsigned int> (clock_t::now_us () + pid));\n}\n\nuint32_t zmq::generate_random ()\n{\n    //  Compensate for the fact that rand() returns signed integer.\n    const uint32_t low = static_cast<uint32_t> (rand ());\n    uint32_t high = static_cast<uint32_t> (rand ());\n    high <<= (sizeof (int) * 8 - 1);\n    return high | low;\n}\n\nstatic void manage_random (bool init_)\n{\n#if defined(ZMQ_USE_LIBSODIUM)\n    if (init_) {\n        //  sodium_init() is now documented as thread-safe in recent versions\n        int rc = sodium_init ();\n        zmq_assert (rc != -1);\n#if defined(ZMQ_LIBSODIUM_RANDOMBYTES_CLOSE)\n    } else {\n        // randombytes_close either a no-op or not threadsafe\n        // doing this without refcounting can cause crashes\n        // if called while a context is active\n        randombytes_close ();\n#endif\n    }\n#else\n    LIBZMQ_UNUSED (init_);\n#endif\n}\n\nvoid zmq::random_open ()\n{\n    manage_random (true);\n}\n\nvoid zmq::random_close ()\n{\n    manage_random (false);\n}\n"
  },
  {
    "path": "src/random.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_RANDOM_HPP_INCLUDED__\n#define __ZMQ_RANDOM_HPP_INCLUDED__\n\n#include \"stdint.hpp\"\n\nnamespace zmq\n{\n//  Seeds the random number generator.\nvoid seed_random ();\n\n//  Generates random value.\nuint32_t generate_random ();\n\n//  [De-]Initialise crypto library, if needed.\n//  Serialised and refcounted, so that it can be called\n//  from multiple threads, each with its own context, and from\n//  the various zmq_utils curve functions safely.\nvoid random_open ();\nvoid random_close ();\n}\n\n#endif\n"
  },
  {
    "path": "src/raw_decoder.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <stdlib.h>\n#include <string.h>\n\n#include \"raw_decoder.hpp\"\n#include \"err.hpp\"\n\nzmq::raw_decoder_t::raw_decoder_t (size_t bufsize_) : _allocator (bufsize_, 1)\n{\n    const int rc = _in_progress.init ();\n    errno_assert (rc == 0);\n}\n\nzmq::raw_decoder_t::~raw_decoder_t ()\n{\n    const int rc = _in_progress.close ();\n    errno_assert (rc == 0);\n}\n\nvoid zmq::raw_decoder_t::get_buffer (unsigned char **data_, size_t *size_)\n{\n    *data_ = _allocator.allocate ();\n    *size_ = _allocator.size ();\n}\n\nint zmq::raw_decoder_t::decode (const uint8_t *data_,\n                                size_t size_,\n                                size_t &bytes_used_)\n{\n    const int rc =\n      _in_progress.init (const_cast<unsigned char *> (data_), size_,\n                         shared_message_memory_allocator::call_dec_ref,\n                         _allocator.buffer (), _allocator.provide_content ());\n\n    // if the buffer serves as memory for a zero-copy message, release it\n    // and allocate a new buffer in get_buffer for the next decode\n    if (_in_progress.is_zcmsg ()) {\n        _allocator.advance_content ();\n        _allocator.release ();\n    }\n\n    errno_assert (rc != -1);\n    bytes_used_ = size_;\n    return 1;\n}\n"
  },
  {
    "path": "src/raw_decoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_RAW_DECODER_HPP_INCLUDED__\n#define __ZMQ_RAW_DECODER_HPP_INCLUDED__\n\n#include \"msg.hpp\"\n#include \"i_decoder.hpp\"\n#include \"stdint.hpp\"\n#include \"decoder_allocators.hpp\"\n\nnamespace zmq\n{\n//  Decoder for 0MQ v1 framing protocol. Converts data stream into messages.\n\nclass raw_decoder_t ZMQ_FINAL : public i_decoder\n{\n  public:\n    raw_decoder_t (size_t bufsize_);\n    ~raw_decoder_t ();\n\n    //  i_decoder interface.\n\n    void get_buffer (unsigned char **data_, size_t *size_);\n\n    int decode (const unsigned char *data_, size_t size_, size_t &bytes_used_);\n\n    msg_t *msg () { return &_in_progress; }\n\n    void resize_buffer (size_t) {}\n\n  private:\n    msg_t _in_progress;\n\n    shared_message_memory_allocator _allocator;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (raw_decoder_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/raw_encoder.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"encoder.hpp\"\n#include \"raw_encoder.hpp\"\n#include \"msg.hpp\"\n\nzmq::raw_encoder_t::raw_encoder_t (size_t bufsize_) :\n    encoder_base_t<raw_encoder_t> (bufsize_)\n{\n    //  Write 0 bytes to the batch and go to message_ready state.\n    next_step (NULL, 0, &raw_encoder_t::raw_message_ready, true);\n}\n\nzmq::raw_encoder_t::~raw_encoder_t ()\n{\n}\n\nvoid zmq::raw_encoder_t::raw_message_ready ()\n{\n    next_step (in_progress ()->data (), in_progress ()->size (),\n               &raw_encoder_t::raw_message_ready, true);\n}\n"
  },
  {
    "path": "src/raw_encoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_RAW_ENCODER_HPP_INCLUDED__\n#define __ZMQ_RAW_ENCODER_HPP_INCLUDED__\n\n#include <stddef.h>\n#include <string.h>\n#include <stdlib.h>\n\n#include \"encoder.hpp\"\n\nnamespace zmq\n{\n//  Encoder for 0MQ framing protocol. Converts messages into data batches.\n\nclass raw_encoder_t ZMQ_FINAL : public encoder_base_t<raw_encoder_t>\n{\n  public:\n    raw_encoder_t (size_t bufsize_);\n    ~raw_encoder_t ();\n\n  private:\n    void raw_message_ready ();\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (raw_encoder_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/raw_engine.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n\n#include <limits.h>\n#include <string.h>\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#endif\n\n#include <new>\n#include <sstream>\n\n#include \"raw_engine.hpp\"\n#include \"io_thread.hpp\"\n#include \"session_base.hpp\"\n#include \"v1_encoder.hpp\"\n#include \"v1_decoder.hpp\"\n#include \"v2_encoder.hpp\"\n#include \"v2_decoder.hpp\"\n#include \"null_mechanism.hpp\"\n#include \"plain_client.hpp\"\n#include \"plain_server.hpp\"\n#include \"gssapi_client.hpp\"\n#include \"gssapi_server.hpp\"\n#include \"curve_client.hpp\"\n#include \"curve_server.hpp\"\n#include \"raw_decoder.hpp\"\n#include \"raw_encoder.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"tcp.hpp\"\n#include \"likely.hpp\"\n#include \"wire.hpp\"\n\nzmq::raw_engine_t::raw_engine_t (\n  fd_t fd_,\n  const options_t &options_,\n  const endpoint_uri_pair_t &endpoint_uri_pair_) :\n    stream_engine_base_t (fd_, options_, endpoint_uri_pair_, false)\n{\n}\n\nzmq::raw_engine_t::~raw_engine_t ()\n{\n}\n\nvoid zmq::raw_engine_t::plug_internal ()\n{\n    // no handshaking for raw sock, instantiate raw encoder and decoders\n    _encoder = new (std::nothrow) raw_encoder_t (_options.out_batch_size);\n    alloc_assert (_encoder);\n\n    _decoder = new (std::nothrow) raw_decoder_t (_options.in_batch_size);\n    alloc_assert (_decoder);\n\n    _next_msg = &raw_engine_t::pull_msg_from_session;\n    _process_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n      &raw_engine_t::push_raw_msg_to_session);\n\n    properties_t properties;\n    if (init_properties (properties)) {\n        //  Compile metadata.\n        zmq_assert (_metadata == NULL);\n        _metadata = new (std::nothrow) metadata_t (properties);\n        alloc_assert (_metadata);\n    }\n\n    if (_options.raw_notify) {\n        //  For raw sockets, send an initial 0-length message to the\n        // application so that it knows a peer has connected.\n        msg_t connector;\n        connector.init ();\n        push_raw_msg_to_session (&connector);\n        connector.close ();\n        session ()->flush ();\n    }\n\n    set_pollin ();\n    set_pollout ();\n    //  Flush all the data that may have been already received downstream.\n    in_event ();\n}\n\nbool zmq::raw_engine_t::handshake ()\n{\n    return true;\n}\n\nvoid zmq::raw_engine_t::error (error_reason_t reason_)\n{\n    if (_options.raw_socket && _options.raw_notify) {\n        //  For raw sockets, send a final 0-length message to the application\n        //  so that it knows the peer has been disconnected.\n        msg_t terminator;\n        terminator.init ();\n        push_raw_msg_to_session (&terminator);\n        terminator.close ();\n    }\n    stream_engine_base_t::error (reason_);\n}\n\nint zmq::raw_engine_t::push_raw_msg_to_session (msg_t *msg_)\n{\n    if (_metadata && _metadata != msg_->metadata ())\n        msg_->set_metadata (_metadata);\n    return push_msg_to_session (msg_);\n}\n"
  },
  {
    "path": "src/raw_engine.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_RAW_ENGINE_HPP_INCLUDED__\n#define __ZMQ_RAW_ENGINE_HPP_INCLUDED__\n\n#include <stddef.h>\n\n#include \"fd.hpp\"\n#include \"i_engine.hpp\"\n#include \"io_object.hpp\"\n#include \"i_encoder.hpp\"\n#include \"i_decoder.hpp\"\n#include \"options.hpp\"\n#include \"socket_base.hpp\"\n#include \"metadata.hpp\"\n#include \"msg.hpp\"\n#include \"stream_engine_base.hpp\"\n\nnamespace zmq\n{\n//  Protocol revisions\n\nclass io_thread_t;\nclass session_base_t;\nclass mechanism_t;\n\n//  This engine handles any socket with SOCK_STREAM semantics,\n//  e.g. TCP socket or an UNIX domain socket.\n\nclass raw_engine_t ZMQ_FINAL : public stream_engine_base_t\n{\n  public:\n    raw_engine_t (fd_t fd_,\n                  const options_t &options_,\n                  const endpoint_uri_pair_t &endpoint_uri_pair_);\n    ~raw_engine_t ();\n\n  protected:\n    void error (error_reason_t reason_);\n    void plug_internal ();\n    bool handshake ();\n\n  private:\n    int push_raw_msg_to_session (msg_t *msg_);\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (raw_engine_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/reaper.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"reaper.hpp\"\n#include \"socket_base.hpp\"\n#include \"err.hpp\"\n\nzmq::reaper_t::reaper_t (class ctx_t *ctx_, uint32_t tid_) :\n    object_t (ctx_, tid_),\n    _mailbox_handle (static_cast<poller_t::handle_t> (NULL)),\n    _poller (NULL),\n    _sockets (0),\n    _terminating (false)\n{\n    if (!_mailbox.valid ())\n        return;\n\n    _poller = new (std::nothrow) poller_t (*ctx_);\n    alloc_assert (_poller);\n\n    if (_mailbox.get_fd () != retired_fd) {\n        _mailbox_handle = _poller->add_fd (_mailbox.get_fd (), this);\n        _poller->set_pollin (_mailbox_handle);\n    }\n\n#ifdef HAVE_FORK\n    _pid = getpid ();\n#endif\n}\n\nzmq::reaper_t::~reaper_t ()\n{\n    LIBZMQ_DELETE (_poller);\n}\n\nzmq::mailbox_t *zmq::reaper_t::get_mailbox ()\n{\n    return &_mailbox;\n}\n\nvoid zmq::reaper_t::start ()\n{\n    zmq_assert (_mailbox.valid ());\n\n    //  Start the thread.\n    _poller->start (\"Reaper\");\n}\n\nvoid zmq::reaper_t::stop ()\n{\n    if (get_mailbox ()->valid ()) {\n        send_stop ();\n    }\n}\n\nvoid zmq::reaper_t::in_event ()\n{\n    while (true) {\n#ifdef HAVE_FORK\n        if (unlikely (_pid != getpid ())) {\n            //printf(\"zmq::reaper_t::in_event return in child process %d\\n\", (int)getpid());\n            return;\n        }\n#endif\n\n        //  Get the next command. If there is none, exit.\n        command_t cmd;\n        const int rc = _mailbox.recv (&cmd, 0);\n        if (rc != 0 && errno == EINTR)\n            continue;\n        if (rc != 0 && errno == EAGAIN)\n            break;\n        errno_assert (rc == 0);\n\n        //  Process the command.\n        cmd.destination->process_command (cmd);\n    }\n}\n\nvoid zmq::reaper_t::out_event ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::reaper_t::timer_event (int)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::reaper_t::process_stop ()\n{\n    _terminating = true;\n\n    //  If there are no sockets being reaped finish immediately.\n    if (!_sockets) {\n        send_done ();\n        _poller->rm_fd (_mailbox_handle);\n        _poller->stop ();\n    }\n}\n\nvoid zmq::reaper_t::process_reap (socket_base_t *socket_)\n{\n    //  Add the socket to the poller.\n    socket_->start_reaping (_poller);\n\n    ++_sockets;\n}\n\nvoid zmq::reaper_t::process_reaped ()\n{\n    --_sockets;\n\n    //  If reaped was already asked to terminate and there are no more sockets,\n    //  finish immediately.\n    if (!_sockets && _terminating) {\n        send_done ();\n        _poller->rm_fd (_mailbox_handle);\n        _poller->stop ();\n    }\n}\n"
  },
  {
    "path": "src/reaper.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_REAPER_HPP_INCLUDED__\n#define __ZMQ_REAPER_HPP_INCLUDED__\n\n#include \"object.hpp\"\n#include \"mailbox.hpp\"\n#include \"poller.hpp\"\n#include \"i_poll_events.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass socket_base_t;\n\nclass reaper_t ZMQ_FINAL : public object_t, public i_poll_events\n{\n  public:\n    reaper_t (zmq::ctx_t *ctx_, uint32_t tid_);\n    ~reaper_t ();\n\n    mailbox_t *get_mailbox ();\n\n    void start ();\n    void stop ();\n\n    //  i_poll_events implementation.\n    void in_event ();\n    void out_event ();\n    void timer_event (int id_);\n\n  private:\n    //  Command handlers.\n    void process_stop ();\n    void process_reap (zmq::socket_base_t *socket_);\n    void process_reaped ();\n\n    //  Reaper thread accesses incoming commands via this mailbox.\n    mailbox_t _mailbox;\n\n    //  Handle associated with mailbox' file descriptor.\n    poller_t::handle_t _mailbox_handle;\n\n    //  I/O multiplexing is performed using a poller object.\n    poller_t *_poller;\n\n    //  Number of sockets being reaped at the moment.\n    int _sockets;\n\n    //  If true, we were already asked to terminate.\n    bool _terminating;\n\n#ifdef HAVE_FORK\n    // the process that created this context. Used to detect forking.\n    pid_t _pid;\n#endif\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (reaper_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/rep.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"rep.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n\nzmq::rep_t::rep_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    router_t (parent_, tid_, sid_),\n    _sending_reply (false),\n    _request_begins (true)\n{\n    options.type = ZMQ_REP;\n}\n\nzmq::rep_t::~rep_t ()\n{\n}\n\nint zmq::rep_t::xsend (msg_t *msg_)\n{\n    //  If we are in the middle of receiving a request, we cannot send reply.\n    if (!_sending_reply) {\n        errno = EFSM;\n        return -1;\n    }\n\n    const bool more = (msg_->flags () & msg_t::more) != 0;\n\n    //  Push message to the reply pipe.\n    const int rc = router_t::xsend (msg_);\n    if (rc != 0)\n        return rc;\n\n    //  If the reply is complete flip the FSM back to request receiving state.\n    if (!more)\n        _sending_reply = false;\n\n    return 0;\n}\n\nint zmq::rep_t::xrecv (msg_t *msg_)\n{\n    //  If we are in middle of sending a reply, we cannot receive next request.\n    if (_sending_reply) {\n        errno = EFSM;\n        return -1;\n    }\n\n    //  First thing to do when receiving a request is to copy all the labels\n    //  to the reply pipe.\n    if (_request_begins) {\n        while (true) {\n            int rc = router_t::xrecv (msg_);\n            if (rc != 0)\n                return rc;\n\n            if ((msg_->flags () & msg_t::more)) {\n                //  Empty message part delimits the traceback stack.\n                const bool bottom = (msg_->size () == 0);\n\n                //  Push it to the reply pipe.\n                rc = router_t::xsend (msg_);\n                errno_assert (rc == 0);\n\n                if (bottom)\n                    break;\n            } else {\n                //  If the traceback stack is malformed, discard anything\n                //  already sent to pipe (we're at end of invalid message).\n                rc = router_t::rollback ();\n                errno_assert (rc == 0);\n            }\n        }\n        _request_begins = false;\n    }\n\n    //  Get next message part to return to the user.\n    const int rc = router_t::xrecv (msg_);\n    if (rc != 0)\n        return rc;\n\n    //  If whole request is read, flip the FSM to reply-sending state.\n    if (!(msg_->flags () & msg_t::more)) {\n        _sending_reply = true;\n        _request_begins = true;\n    }\n\n    return 0;\n}\n\nbool zmq::rep_t::xhas_in ()\n{\n    if (_sending_reply)\n        return false;\n\n    return router_t::xhas_in ();\n}\n\nbool zmq::rep_t::xhas_out ()\n{\n    if (!_sending_reply)\n        return false;\n\n    return router_t::xhas_out ();\n}\n"
  },
  {
    "path": "src/rep.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_REP_HPP_INCLUDED__\n#define __ZMQ_REP_HPP_INCLUDED__\n\n#include \"router.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass io_thread_t;\nclass socket_base_t;\n\nclass rep_t ZMQ_FINAL : public router_t\n{\n  public:\n    rep_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~rep_t ();\n\n    //  Overrides of functions from socket_base_t.\n    int xsend (zmq::msg_t *msg_);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    bool xhas_out ();\n\n  private:\n    //  If true, we are in process of sending the reply. If false we are\n    //  in process of receiving a request.\n    bool _sending_reply;\n\n    //  If true, we are starting to receive a request. The beginning\n    //  of the request is the backtrace stack.\n    bool _request_begins;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (rep_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/req.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"req.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n#include \"wire.hpp\"\n#include \"random.hpp\"\n#include \"likely.hpp\"\n\nzmq::req_t::req_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    dealer_t (parent_, tid_, sid_),\n    _receiving_reply (false),\n    _message_begins (true),\n    _reply_pipe (NULL),\n    _request_id_frames_enabled (false),\n    _request_id (generate_random ()),\n    _strict (true)\n{\n    options.type = ZMQ_REQ;\n}\n\nzmq::req_t::~req_t ()\n{\n}\n\nint zmq::req_t::xsend (msg_t *msg_)\n{\n    //  If we've sent a request and we still haven't got the reply,\n    //  we can't send another request unless the strict option is disabled.\n    if (_receiving_reply) {\n        if (_strict) {\n            errno = EFSM;\n            return -1;\n        }\n\n        _receiving_reply = false;\n        _message_begins = true;\n    }\n\n    //  First part of the request is the request routing id.\n    if (_message_begins) {\n        _reply_pipe = NULL;\n\n        if (_request_id_frames_enabled) {\n            _request_id++;\n\n            msg_t id;\n            int rc = id.init_size (sizeof (uint32_t));\n            memcpy (id.data (), &_request_id, sizeof (uint32_t));\n            errno_assert (rc == 0);\n            id.set_flags (msg_t::more);\n\n            rc = dealer_t::sendpipe (&id, &_reply_pipe);\n            if (rc != 0) {\n                return -1;\n            }\n        }\n\n        msg_t bottom;\n        int rc = bottom.init ();\n        errno_assert (rc == 0);\n        bottom.set_flags (msg_t::more);\n\n        rc = dealer_t::sendpipe (&bottom, &_reply_pipe);\n        if (rc != 0)\n            return -1;\n        zmq_assert (_reply_pipe);\n\n        _message_begins = false;\n\n        // Eat all currently available messages before the request is fully\n        // sent. This is done to avoid:\n        //   REQ sends request to A, A replies, B replies too.\n        //   A's reply was first and matches, that is used.\n        //   An hour later REQ sends a request to B. B's old reply is used.\n        msg_t drop;\n        while (true) {\n            rc = drop.init ();\n            errno_assert (rc == 0);\n            rc = dealer_t::xrecv (&drop);\n            if (rc != 0)\n                break;\n            drop.close ();\n        }\n    }\n\n    bool more = (msg_->flags () & msg_t::more) != 0;\n\n    int rc = dealer_t::xsend (msg_);\n    if (rc != 0)\n        return rc;\n\n    //  If the request was fully sent, flip the FSM into reply-receiving state.\n    if (!more) {\n        _receiving_reply = true;\n        _message_begins = true;\n    }\n\n    return 0;\n}\n\nint zmq::req_t::xrecv (msg_t *msg_)\n{\n    //  If request wasn't send, we can't wait for reply.\n    if (!_receiving_reply) {\n        errno = EFSM;\n        return -1;\n    }\n\n    //  Skip messages until one with the right first frames is found.\n    while (_message_begins) {\n        //  If enabled, the first frame must have the correct request_id.\n        if (_request_id_frames_enabled) {\n            int rc = recv_reply_pipe (msg_);\n            if (rc != 0)\n                return rc;\n\n            if (unlikely (!(msg_->flags () & msg_t::more)\n                          || msg_->size () != sizeof (_request_id)\n                          || *static_cast<uint32_t *> (msg_->data ())\n                               != _request_id)) {\n                //  Skip the remaining frames and try the next message\n                while (msg_->flags () & msg_t::more) {\n                    rc = recv_reply_pipe (msg_);\n                    errno_assert (rc == 0);\n                }\n                continue;\n            }\n        }\n\n        //  The next frame must be 0.\n        // TODO: Failing this check should also close the connection with the peer!\n        int rc = recv_reply_pipe (msg_);\n        if (rc != 0)\n            return rc;\n\n        if (unlikely (!(msg_->flags () & msg_t::more) || msg_->size () != 0)) {\n            //  Skip the remaining frames and try the next message\n            while (msg_->flags () & msg_t::more) {\n                rc = recv_reply_pipe (msg_);\n                errno_assert (rc == 0);\n            }\n            continue;\n        }\n\n        _message_begins = false;\n    }\n\n    const int rc = recv_reply_pipe (msg_);\n    if (rc != 0)\n        return rc;\n\n    //  If the reply is fully received, flip the FSM into request-sending state.\n    if (!(msg_->flags () & msg_t::more)) {\n        _receiving_reply = false;\n        _message_begins = true;\n    }\n\n    return 0;\n}\n\nbool zmq::req_t::xhas_in ()\n{\n    //  TODO: Duplicates should be removed here.\n\n    if (!_receiving_reply)\n        return false;\n\n    return dealer_t::xhas_in ();\n}\n\nbool zmq::req_t::xhas_out ()\n{\n    if (_receiving_reply && _strict)\n        return false;\n\n    return dealer_t::xhas_out ();\n}\n\nint zmq::req_t::xsetsockopt (int option_,\n                             const void *optval_,\n                             size_t optvallen_)\n{\n    const bool is_int = (optvallen_ == sizeof (int));\n    int value = 0;\n    if (is_int)\n        memcpy (&value, optval_, sizeof (int));\n\n    switch (option_) {\n        case ZMQ_REQ_CORRELATE:\n            if (is_int && value >= 0) {\n                _request_id_frames_enabled = (value != 0);\n                return 0;\n            }\n            break;\n\n        case ZMQ_REQ_RELAXED:\n            if (is_int && value >= 0) {\n                _strict = (value == 0);\n                return 0;\n            }\n            break;\n\n        default:\n            break;\n    }\n\n    return dealer_t::xsetsockopt (option_, optval_, optvallen_);\n}\n\nvoid zmq::req_t::xpipe_terminated (pipe_t *pipe_)\n{\n    if (_reply_pipe == pipe_)\n        _reply_pipe = NULL;\n    dealer_t::xpipe_terminated (pipe_);\n}\n\nint zmq::req_t::recv_reply_pipe (msg_t *msg_)\n{\n    while (true) {\n        pipe_t *pipe = NULL;\n        const int rc = dealer_t::recvpipe (msg_, &pipe);\n        if (rc != 0)\n            return rc;\n        if (!_reply_pipe || pipe == _reply_pipe)\n            return 0;\n    }\n}\n\nzmq::req_session_t::req_session_t (io_thread_t *io_thread_,\n                                   bool connect_,\n                                   socket_base_t *socket_,\n                                   const options_t &options_,\n                                   address_t *addr_) :\n    session_base_t (io_thread_, connect_, socket_, options_, addr_),\n    _state (bottom)\n{\n}\n\nzmq::req_session_t::~req_session_t ()\n{\n}\n\nint zmq::req_session_t::push_msg (msg_t *msg_)\n{\n    //  Ignore commands, they are processed by the engine and should not\n    //  affect the state machine.\n    if (unlikely (msg_->flags () & msg_t::command))\n        return 0;\n\n    switch (_state) {\n        case bottom:\n            if (msg_->flags () == msg_t::more) {\n                //  In case option ZMQ_CORRELATE is on, allow request_id to be\n                //  transferred as first frame (would be too cumbersome to check\n                //  whether the option is actually on or not).\n                if (msg_->size () == sizeof (uint32_t)) {\n                    _state = request_id;\n                    return session_base_t::push_msg (msg_);\n                }\n                if (msg_->size () == 0) {\n                    _state = body;\n                    return session_base_t::push_msg (msg_);\n                }\n            }\n            break;\n        case request_id:\n            if (msg_->flags () == msg_t::more && msg_->size () == 0) {\n                _state = body;\n                return session_base_t::push_msg (msg_);\n            }\n            break;\n        case body:\n            if (msg_->flags () == msg_t::more)\n                return session_base_t::push_msg (msg_);\n            if (msg_->flags () == 0) {\n                _state = bottom;\n                return session_base_t::push_msg (msg_);\n            }\n            break;\n    }\n    errno = EFAULT;\n    return -1;\n}\n\nvoid zmq::req_session_t::reset ()\n{\n    session_base_t::reset ();\n    _state = bottom;\n}\n"
  },
  {
    "path": "src/req.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_REQ_HPP_INCLUDED__\n#define __ZMQ_REQ_HPP_INCLUDED__\n\n#include \"dealer.hpp\"\n#include \"stdint.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass io_thread_t;\nclass socket_base_t;\n\nclass req_t ZMQ_FINAL : public dealer_t\n{\n  public:\n    req_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~req_t ();\n\n    //  Overrides of functions from socket_base_t.\n    int xsend (zmq::msg_t *msg_);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    bool xhas_out ();\n    int xsetsockopt (int option_, const void *optval_, size_t optvallen_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n\n  protected:\n    //  Receive only from the pipe the request was sent to, discarding\n    //  frames from other pipes.\n    int recv_reply_pipe (zmq::msg_t *msg_);\n\n  private:\n    //  If true, request was already sent and reply wasn't received yet or\n    //  was received partially.\n    bool _receiving_reply;\n\n    //  If true, we are starting to send/recv a message. The first part\n    //  of the message must be empty message part (backtrace stack bottom).\n    bool _message_begins;\n\n    //  The pipe the request was sent to and where the reply is expected.\n    zmq::pipe_t *_reply_pipe;\n\n    //  Whether request id frames shall be sent and expected.\n    bool _request_id_frames_enabled;\n\n    //  The current request id. It is incremented every time before a new\n    //  request is sent.\n    uint32_t _request_id;\n\n    //  If false, send() will reset its internal state and terminate the\n    //  reply_pipe's connection instead of failing if a previous request is\n    //  still pending.\n    bool _strict;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (req_t)\n};\n\nclass req_session_t ZMQ_FINAL : public session_base_t\n{\n  public:\n    req_session_t (zmq::io_thread_t *io_thread_,\n                   bool connect_,\n                   zmq::socket_base_t *socket_,\n                   const options_t &options_,\n                   address_t *addr_);\n    ~req_session_t ();\n\n    //  Overrides of the functions from session_base_t.\n    int push_msg (msg_t *msg_);\n    void reset ();\n\n  private:\n    enum\n    {\n        bottom,\n        request_id,\n        body\n    } _state;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (req_session_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/router.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"router.hpp\"\n#include \"pipe.hpp\"\n#include \"wire.hpp\"\n#include \"random.hpp\"\n#include \"likely.hpp\"\n#include \"err.hpp\"\n\nzmq::router_t::router_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    routing_socket_base_t (parent_, tid_, sid_),\n    _prefetched (false),\n    _routing_id_sent (false),\n    _current_in (NULL),\n    _terminate_current_in (false),\n    _more_in (false),\n    _current_out (NULL),\n    _more_out (false),\n    _next_integral_routing_id (generate_random ()),\n    _mandatory (false),\n    //  raw_socket functionality in ROUTER is deprecated\n    _raw_socket (false),\n    _probe_router (false),\n    _handover (false)\n{\n    options.type = ZMQ_ROUTER;\n    options.recv_routing_id = true;\n    options.raw_socket = false;\n    options.can_send_hello_msg = true;\n    options.can_recv_disconnect_msg = true;\n\n    _prefetched_id.init ();\n    _prefetched_msg.init ();\n}\n\nzmq::router_t::~router_t ()\n{\n    zmq_assert (_anonymous_pipes.empty ());\n    _prefetched_id.close ();\n    _prefetched_msg.close ();\n}\n\nvoid zmq::router_t::xattach_pipe (pipe_t *pipe_,\n                                  bool subscribe_to_all_,\n                                  bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n\n    zmq_assert (pipe_);\n\n    if (_probe_router) {\n        msg_t probe_msg;\n        int rc = probe_msg.init ();\n        errno_assert (rc == 0);\n\n        rc = pipe_->write (&probe_msg);\n        // zmq_assert (rc) is not applicable here, since it is not a bug.\n        LIBZMQ_UNUSED (rc);\n\n        pipe_->flush ();\n\n        rc = probe_msg.close ();\n        errno_assert (rc == 0);\n    }\n\n    const bool routing_id_ok = identify_peer (pipe_, locally_initiated_);\n    if (routing_id_ok)\n        _fq.attach (pipe_);\n    else\n        _anonymous_pipes.insert (pipe_);\n}\n\nint zmq::router_t::xsetsockopt (int option_,\n                                const void *optval_,\n                                size_t optvallen_)\n{\n    const bool is_int = (optvallen_ == sizeof (int));\n    int value = 0;\n    if (is_int)\n        memcpy (&value, optval_, sizeof (int));\n\n    switch (option_) {\n        case ZMQ_ROUTER_RAW:\n            if (is_int && value >= 0) {\n                _raw_socket = (value != 0);\n                if (_raw_socket) {\n                    options.recv_routing_id = false;\n                    options.raw_socket = true;\n                }\n                return 0;\n            }\n            break;\n\n        case ZMQ_ROUTER_MANDATORY:\n            if (is_int && value >= 0) {\n                _mandatory = (value != 0);\n                return 0;\n            }\n            break;\n\n        case ZMQ_PROBE_ROUTER:\n            if (is_int && value >= 0) {\n                _probe_router = (value != 0);\n                return 0;\n            }\n            break;\n\n        case ZMQ_ROUTER_HANDOVER:\n            if (is_int && value >= 0) {\n                _handover = (value != 0);\n                return 0;\n            }\n            break;\n\n#ifdef ZMQ_BUILD_DRAFT_API\n        case ZMQ_ROUTER_NOTIFY:\n            if (is_int && value >= 0\n                && value <= (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT)) {\n                options.router_notify = value;\n                return 0;\n            }\n            break;\n#endif\n\n        default:\n            return routing_socket_base_t::xsetsockopt (option_, optval_,\n                                                       optvallen_);\n    }\n    errno = EINVAL;\n    return -1;\n}\n\n\nvoid zmq::router_t::xpipe_terminated (pipe_t *pipe_)\n{\n    if (0 == _anonymous_pipes.erase (pipe_)) {\n        erase_out_pipe (pipe_);\n        _fq.pipe_terminated (pipe_);\n        pipe_->rollback ();\n        if (pipe_ == _current_out)\n            _current_out = NULL;\n    }\n}\n\nvoid zmq::router_t::xread_activated (pipe_t *pipe_)\n{\n    const std::set<pipe_t *>::iterator it = _anonymous_pipes.find (pipe_);\n    if (it == _anonymous_pipes.end ())\n        _fq.activated (pipe_);\n    else {\n        const bool routing_id_ok = identify_peer (pipe_, false);\n        if (routing_id_ok) {\n            _anonymous_pipes.erase (it);\n            _fq.attach (pipe_);\n        }\n    }\n}\n\nint zmq::router_t::xsend (msg_t *msg_)\n{\n    //  If this is the first part of the message it's the ID of the\n    //  peer to send the message to.\n    if (!_more_out) {\n        zmq_assert (!_current_out);\n\n        //  If we have malformed message (prefix with no subsequent message)\n        //  then just silently ignore it.\n        //  TODO: The connections should be killed instead.\n        if (msg_->flags () & msg_t::more) {\n            _more_out = true;\n\n            //  Find the pipe associated with the routing id stored in the prefix.\n            //  If there's no such pipe just silently ignore the message, unless\n            //  router_mandatory is set.\n            out_pipe_t *out_pipe = lookup_out_pipe (\n              blob_t (static_cast<unsigned char *> (msg_->data ()),\n                      msg_->size (), zmq::reference_tag_t ()));\n\n            if (out_pipe) {\n                _current_out = out_pipe->pipe;\n\n                // Check whether pipe is closed or not\n                if (!_current_out->check_write ()) {\n                    // Check whether pipe is full or not\n                    const bool pipe_full = !_current_out->check_hwm ();\n                    out_pipe->active = false;\n                    _current_out = NULL;\n\n                    if (_mandatory) {\n                        _more_out = false;\n                        if (pipe_full)\n                            errno = EAGAIN;\n                        else\n                            errno = EHOSTUNREACH;\n                        return -1;\n                    }\n                }\n            } else if (_mandatory) {\n                _more_out = false;\n                errno = EHOSTUNREACH;\n                return -1;\n            }\n        }\n\n        int rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n        return 0;\n    }\n\n    //  Ignore the MORE flag for raw-sock or assert?\n    if (options.raw_socket)\n        msg_->reset_flags (msg_t::more);\n\n    //  Check whether this is the last part of the message.\n    _more_out = (msg_->flags () & msg_t::more) != 0;\n\n    //  Push the message into the pipe. If there's no out pipe, just drop it.\n    if (_current_out) {\n        // Close the remote connection if user has asked to do so\n        // by sending zero length message.\n        // Pending messages in the pipe will be dropped (on receiving term- ack)\n        if (_raw_socket && msg_->size () == 0) {\n            _current_out->terminate (false);\n            int rc = msg_->close ();\n            errno_assert (rc == 0);\n            rc = msg_->init ();\n            errno_assert (rc == 0);\n            _current_out = NULL;\n            return 0;\n        }\n\n        const bool ok = _current_out->write (msg_);\n        if (unlikely (!ok)) {\n            // Message failed to send - we must close it ourselves.\n            const int rc = msg_->close ();\n            errno_assert (rc == 0);\n            // HWM was checked before, so the pipe must be gone. Roll back\n            // messages that were piped, for example REP labels.\n            _current_out->rollback ();\n            _current_out = NULL;\n        } else {\n            if (!_more_out) {\n                _current_out->flush ();\n                _current_out = NULL;\n            }\n        }\n    } else {\n        const int rc = msg_->close ();\n        errno_assert (rc == 0);\n    }\n\n    //  Detach the message from the data buffer.\n    const int rc = msg_->init ();\n    errno_assert (rc == 0);\n\n    return 0;\n}\n\nint zmq::router_t::xrecv (msg_t *msg_)\n{\n    if (_prefetched) {\n        if (!_routing_id_sent) {\n            const int rc = msg_->move (_prefetched_id);\n            errno_assert (rc == 0);\n            _routing_id_sent = true;\n        } else {\n            const int rc = msg_->move (_prefetched_msg);\n            errno_assert (rc == 0);\n            _prefetched = false;\n        }\n        _more_in = (msg_->flags () & msg_t::more) != 0;\n\n        if (!_more_in) {\n            if (_terminate_current_in) {\n                _current_in->terminate (true);\n                _terminate_current_in = false;\n            }\n            _current_in = NULL;\n        }\n        return 0;\n    }\n\n    pipe_t *pipe = NULL;\n    int rc = _fq.recvpipe (msg_, &pipe);\n\n    //  It's possible that we receive peer's routing id. That happens\n    //  after reconnection. The current implementation assumes that\n    //  the peer always uses the same routing id.\n    while (rc == 0 && msg_->is_routing_id ())\n        rc = _fq.recvpipe (msg_, &pipe);\n\n    if (rc != 0)\n        return -1;\n\n    zmq_assert (pipe != NULL);\n\n    //  If we are in the middle of reading a message, just return the next part.\n    if (_more_in) {\n        _more_in = (msg_->flags () & msg_t::more) != 0;\n\n        if (!_more_in) {\n            if (_terminate_current_in) {\n                _current_in->terminate (true);\n                _terminate_current_in = false;\n            }\n            _current_in = NULL;\n        }\n    } else {\n        //  We are at the beginning of a message.\n        //  Keep the message part we have in the prefetch buffer\n        //  and return the ID of the peer instead.\n        rc = _prefetched_msg.move (*msg_);\n        errno_assert (rc == 0);\n        _prefetched = true;\n        _current_in = pipe;\n\n        const blob_t &routing_id = pipe->get_routing_id ();\n        rc = msg_->init_size (routing_id.size ());\n        errno_assert (rc == 0);\n        memcpy (msg_->data (), routing_id.data (), routing_id.size ());\n        msg_->set_flags (msg_t::more);\n        if (_prefetched_msg.metadata ())\n            msg_->set_metadata (_prefetched_msg.metadata ());\n        _routing_id_sent = true;\n    }\n\n    return 0;\n}\n\nint zmq::router_t::rollback ()\n{\n    if (_current_out) {\n        _current_out->rollback ();\n        _current_out = NULL;\n        _more_out = false;\n    }\n    return 0;\n}\n\nbool zmq::router_t::xhas_in ()\n{\n    //  If we are in the middle of reading the messages, there are\n    //  definitely more parts available.\n    if (_more_in)\n        return true;\n\n    //  We may already have a message pre-fetched.\n    if (_prefetched)\n        return true;\n\n    //  Try to read the next message.\n    //  The message, if read, is kept in the pre-fetch buffer.\n    pipe_t *pipe = NULL;\n    int rc = _fq.recvpipe (&_prefetched_msg, &pipe);\n\n    //  It's possible that we receive peer's routing id. That happens\n    //  after reconnection. The current implementation assumes that\n    //  the peer always uses the same routing id.\n    //  TODO: handle the situation when the peer changes its routing id.\n    while (rc == 0 && _prefetched_msg.is_routing_id ())\n        rc = _fq.recvpipe (&_prefetched_msg, &pipe);\n\n    if (rc != 0)\n        return false;\n\n    zmq_assert (pipe != NULL);\n\n    const blob_t &routing_id = pipe->get_routing_id ();\n    rc = _prefetched_id.init_size (routing_id.size ());\n    errno_assert (rc == 0);\n    memcpy (_prefetched_id.data (), routing_id.data (), routing_id.size ());\n    _prefetched_id.set_flags (msg_t::more);\n    if (_prefetched_msg.metadata ())\n        _prefetched_id.set_metadata (_prefetched_msg.metadata ());\n\n    _prefetched = true;\n    _routing_id_sent = false;\n    _current_in = pipe;\n\n    return true;\n}\n\nstatic bool check_pipe_hwm (const zmq::pipe_t &pipe_)\n{\n    return pipe_.check_hwm ();\n}\n\nbool zmq::router_t::xhas_out ()\n{\n    //  In theory, ROUTER socket is always ready for writing (except when\n    //  MANDATORY is set). Whether actual attempt to write succeeds depends\n    //  on which pipe the message is going to be routed to.\n\n    if (!_mandatory)\n        return true;\n\n    return any_of_out_pipes (check_pipe_hwm);\n}\n\nint zmq::router_t::get_peer_state (const void *routing_id_,\n                                   size_t routing_id_size_) const\n{\n    int res = 0;\n\n    // TODO remove the const_cast, see comment in lookup_out_pipe\n    const blob_t routing_id_blob (\n      static_cast<unsigned char *> (const_cast<void *> (routing_id_)),\n      routing_id_size_, reference_tag_t ());\n    const out_pipe_t *out_pipe = lookup_out_pipe (routing_id_blob);\n    if (!out_pipe) {\n        errno = EHOSTUNREACH;\n        return -1;\n    }\n\n    if (out_pipe->pipe->check_hwm ())\n        res |= ZMQ_POLLOUT;\n\n    /** \\todo does it make any sense to check the inpipe as well? */\n\n    return res;\n}\n\nbool zmq::router_t::identify_peer (pipe_t *pipe_, bool locally_initiated_)\n{\n    msg_t msg;\n    blob_t routing_id;\n\n    if (locally_initiated_ && connect_routing_id_is_set ()) {\n        const std::string connect_routing_id = extract_connect_routing_id ();\n        routing_id.set (\n          reinterpret_cast<const unsigned char *> (connect_routing_id.c_str ()),\n          connect_routing_id.length ());\n        //  Not allowed to duplicate an existing rid\n        zmq_assert (!has_out_pipe (routing_id));\n    } else if (\n      options\n        .raw_socket) { //  Always assign an integral routing id for raw-socket\n        unsigned char buf[5];\n        buf[0] = 0;\n        put_uint32 (buf + 1, _next_integral_routing_id++);\n        routing_id.set (buf, sizeof buf);\n    } else if (!options.raw_socket) {\n        //  Pick up handshake cases and also case where next integral routing id is set\n        msg.init ();\n        const bool ok = pipe_->read (&msg);\n        if (!ok)\n            return false;\n\n        if (msg.size () == 0) {\n            //  Fall back on the auto-generation\n            unsigned char buf[5];\n            buf[0] = 0;\n            put_uint32 (buf + 1, _next_integral_routing_id++);\n            routing_id.set (buf, sizeof buf);\n            msg.close ();\n        } else {\n            routing_id.set (static_cast<unsigned char *> (msg.data ()),\n                            msg.size ());\n            msg.close ();\n\n            //  Try to remove an existing routing id entry to allow the new\n            //  connection to take the routing id.\n            const out_pipe_t *const existing_outpipe =\n              lookup_out_pipe (routing_id);\n\n            if (existing_outpipe) {\n                if (!_handover)\n                    //  Ignore peers with duplicate ID\n                    return false;\n\n                //  We will allow the new connection to take over this\n                //  routing id. Temporarily assign a new routing id to the\n                //  existing pipe so we can terminate it asynchronously.\n                unsigned char buf[5];\n                buf[0] = 0;\n                put_uint32 (buf + 1, _next_integral_routing_id++);\n                blob_t new_routing_id (buf, sizeof buf);\n\n                pipe_t *const old_pipe = existing_outpipe->pipe;\n\n                erase_out_pipe (old_pipe);\n                old_pipe->set_router_socket_routing_id (new_routing_id);\n                add_out_pipe (ZMQ_MOVE (new_routing_id), old_pipe);\n\n                if (old_pipe == _current_in)\n                    _terminate_current_in = true;\n                else\n                    old_pipe->terminate (true);\n            }\n        }\n    }\n\n    pipe_->set_router_socket_routing_id (routing_id);\n    add_out_pipe (ZMQ_MOVE (routing_id), pipe_);\n\n    return true;\n}\n"
  },
  {
    "path": "src/router.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_ROUTER_HPP_INCLUDED__\n#define __ZMQ_ROUTER_HPP_INCLUDED__\n\n#include <map>\n\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n#include \"stdint.hpp\"\n#include \"blob.hpp\"\n#include \"msg.hpp\"\n#include \"fq.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass pipe_t;\n\n//  TODO: This class uses O(n) scheduling. Rewrite it to use O(1) algorithm.\nclass router_t : public routing_socket_base_t\n{\n  public:\n    router_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~router_t () ZMQ_OVERRIDE;\n\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_) ZMQ_FINAL;\n    int\n    xsetsockopt (int option_, const void *optval_, size_t optvallen_) ZMQ_FINAL;\n    int xsend (zmq::msg_t *msg_) ZMQ_OVERRIDE;\n    int xrecv (zmq::msg_t *msg_) ZMQ_OVERRIDE;\n    bool xhas_in () ZMQ_OVERRIDE;\n    bool xhas_out () ZMQ_OVERRIDE;\n    void xread_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    void xpipe_terminated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    int get_peer_state (const void *routing_id_,\n                        size_t routing_id_size_) const ZMQ_FINAL;\n\n  protected:\n    //  Rollback any message parts that were sent but not yet flushed.\n    int rollback ();\n\n  private:\n    //  Receive peer id and update lookup map\n    bool identify_peer (pipe_t *pipe_, bool locally_initiated_);\n\n    //  Fair queueing object for inbound pipes.\n    fq_t _fq;\n\n    //  True iff there is a message held in the pre-fetch buffer.\n    bool _prefetched;\n\n    //  If true, the receiver got the message part with\n    //  the peer's identity.\n    bool _routing_id_sent;\n\n    //  Holds the prefetched identity.\n    msg_t _prefetched_id;\n\n    //  Holds the prefetched message.\n    msg_t _prefetched_msg;\n\n    //  The pipe we are currently reading from\n    zmq::pipe_t *_current_in;\n\n    //  Should current_in should be terminate after all parts received?\n    bool _terminate_current_in;\n\n    //  If true, more incoming message parts are expected.\n    bool _more_in;\n\n    //  We keep a set of pipes that have not been identified yet.\n    std::set<pipe_t *> _anonymous_pipes;\n\n    //  The pipe we are currently writing to.\n    zmq::pipe_t *_current_out;\n\n    //  If true, more outgoing message parts are expected.\n    bool _more_out;\n\n    //  Routing IDs are generated. It's a simple increment and wrap-over\n    //  algorithm. This value is the next ID to use (if not used already).\n    uint32_t _next_integral_routing_id;\n\n    // If true, report EAGAIN to the caller instead of silently dropping\n    // the message targeting an unknown peer.\n    bool _mandatory;\n    bool _raw_socket;\n\n    // if true, send an empty message to every connected router peer\n    bool _probe_router;\n\n    // If true, the router will reassign an identity upon encountering a\n    // name collision. The new pipe will take the identity, the old pipe\n    // will be terminated.\n    bool _handover;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (router_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/scatter.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"scatter.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n\nzmq::scatter_t::scatter_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_, true)\n{\n    options.type = ZMQ_SCATTER;\n}\n\nzmq::scatter_t::~scatter_t ()\n{\n}\n\nvoid zmq::scatter_t::xattach_pipe (pipe_t *pipe_,\n                                   bool subscribe_to_all_,\n                                   bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    //  Don't delay pipe termination as there is no one\n    //  to receive the delimiter.\n    pipe_->set_nodelay ();\n\n    zmq_assert (pipe_);\n    _lb.attach (pipe_);\n}\n\nvoid zmq::scatter_t::xwrite_activated (pipe_t *pipe_)\n{\n    _lb.activated (pipe_);\n}\n\nvoid zmq::scatter_t::xpipe_terminated (pipe_t *pipe_)\n{\n    _lb.pipe_terminated (pipe_);\n}\n\nint zmq::scatter_t::xsend (msg_t *msg_)\n{\n    //  SCATTER sockets do not allow multipart data (ZMQ_SNDMORE)\n    if (msg_->flags () & msg_t::more) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    return _lb.send (msg_);\n}\n\nbool zmq::scatter_t::xhas_out ()\n{\n    return _lb.has_out ();\n}\n"
  },
  {
    "path": "src/scatter.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SCATTER_HPP_INCLUDED__\n#define __ZMQ_SCATTER_HPP_INCLUDED__\n\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n#include \"lb.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass pipe_t;\nclass msg_t;\nclass io_thread_t;\n\nclass scatter_t ZMQ_FINAL : public socket_base_t\n{\n  public:\n    scatter_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~scatter_t ();\n\n  protected:\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xsend (zmq::msg_t *msg_);\n    bool xhas_out ();\n    void xwrite_activated (zmq::pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n\n  private:\n    //  Load balancer managing the outbound pipes.\n    lb_t _lb;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (scatter_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/secure_allocator.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SECURE_ALLOCATOR_HPP_INCLUDED__\n#define __ZMQ_SECURE_ALLOCATOR_HPP_INCLUDED__\n\n#include \"platform.hpp\"\n#include \"macros.hpp\"\n\n#ifdef ZMQ_HAVE_CURVE\n\n#if defined(ZMQ_USE_LIBSODIUM)\n#include \"sodium.h\"\n#endif\n\n#include <memory>\n\nnamespace zmq\n{\n#if defined(ZMQ_USE_LIBSODIUM)\ntemplate <class T> struct secure_allocator_t\n{\n    typedef T value_type;\n\n    secure_allocator_t () ZMQ_DEFAULT;\n\n    template <class U>\n    secure_allocator_t (const secure_allocator_t<U> &) ZMQ_NOEXCEPT\n    {\n    }\n    T *allocate (std::size_t n) ZMQ_NOEXCEPT\n    {\n        T *res = static_cast<T *> (sodium_allocarray (sizeof (T), n));\n        alloc_assert (res);\n        return res;\n    }\n    void deallocate (T *p, std::size_t) ZMQ_NOEXCEPT\n    {\n        if (p)\n            sodium_free (p);\n    }\n\n    // the following is only required with C++98\n    // TODO maybe make this conditionally compiled\n    typedef T *pointer;\n    typedef const T *const_pointer;\n    typedef T &reference;\n    typedef const T &const_reference;\n    typedef std::size_t size_type;\n    typedef std::ptrdiff_t difference_type;\n    template <class U> struct rebind\n    {\n        typedef secure_allocator_t<U> other;\n    };\n\n    void construct (pointer p, const_reference val)\n    {\n        new ((void *) p) value_type (val);\n    }\n    void destroy (pointer p) { p->~value_type (); }\n    size_type max_size () const { return SIZE_MAX; }\n};\ntemplate <class T, class U>\nbool operator== (const secure_allocator_t<T> &, const secure_allocator_t<U> &)\n{\n    return true;\n}\ntemplate <class T, class U>\nbool operator!= (const secure_allocator_t<T> &, const secure_allocator_t<U> &)\n{\n    return false;\n}\n#else\ntemplate <typename T> struct secure_allocator_t : std::allocator<T>\n{\n    secure_allocator_t () ZMQ_DEFAULT;\n\n    template <class U>\n    secure_allocator_t (const secure_allocator_t<U> &) ZMQ_NOEXCEPT\n    {\n    }\n\n    template <class U> struct rebind\n    {\n        typedef secure_allocator_t<U> other;\n    };\n};\n#endif\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/select.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"select.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_SELECT\n\n#if defined ZMQ_HAVE_WINDOWS\n#elif defined ZMQ_HAVE_HPUX\n#include <sys/param.h>\n#include <sys/types.h>\n#include <sys/time.h>\n#elif defined ZMQ_HAVE_OPENVMS\n#include <sys/types.h>\n#include <sys/time.h>\n#elif defined ZMQ_HAVE_VXWORKS\n#include <sys/types.h>\n#include <sys/time.h>\n#include <strings.h>\n#else\n#include <sys/select.h>\n#endif\n\n#include \"err.hpp\"\n#include \"config.hpp\"\n#include \"i_poll_events.hpp\"\n\n#include <algorithm>\n#include <limits>\n#include <climits>\n\nzmq::select_t::select_t (const zmq::thread_ctx_t &ctx_) :\n    worker_poller_base_t (ctx_),\n#if defined ZMQ_HAVE_WINDOWS\n    //  Fine as long as map is not cleared.\n    _current_family_entry_it (_family_entries.end ())\n#else\n    _max_fd (retired_fd)\n#endif\n{\n#if defined ZMQ_HAVE_WINDOWS\n    for (size_t i = 0; i < fd_family_cache_size; ++i)\n        _fd_family_cache[i] = std::make_pair (retired_fd, 0);\n#endif\n}\n\nzmq::select_t::~select_t ()\n{\n    stop_worker ();\n}\n\nzmq::select_t::handle_t zmq::select_t::add_fd (fd_t fd_, i_poll_events *events_)\n{\n    check_thread ();\n    zmq_assert (fd_ != retired_fd);\n\n    fd_entry_t fd_entry;\n    fd_entry.fd = fd_;\n    fd_entry.events = events_;\n\n#if defined ZMQ_HAVE_WINDOWS\n    u_short family = get_fd_family (fd_);\n    wsa_assert (family != AF_UNSPEC);\n    family_entry_t &family_entry = _family_entries[family];\n#else\n    family_entry_t &family_entry = _family_entry;\n#endif\n    family_entry.fd_entries.push_back (fd_entry);\n    FD_SET (fd_, &family_entry.fds_set.error);\n\n#if !defined ZMQ_HAVE_WINDOWS\n    if (fd_ > _max_fd)\n        _max_fd = fd_;\n#endif\n\n    adjust_load (1);\n\n    return fd_;\n}\n\nzmq::select_t::fd_entries_t::iterator\nzmq::select_t::find_fd_entry_by_handle (fd_entries_t &fd_entries_,\n                                        handle_t handle_)\n{\n    fd_entries_t::iterator fd_entry_it;\n    for (fd_entry_it = fd_entries_.begin (); fd_entry_it != fd_entries_.end ();\n         ++fd_entry_it)\n        if (fd_entry_it->fd == handle_)\n            break;\n\n    return fd_entry_it;\n}\n\nvoid zmq::select_t::trigger_events (const fd_entries_t &fd_entries_,\n                                    const fds_set_t &local_fds_set_,\n                                    int event_count_)\n{\n    //  Size is cached to avoid iteration through recently added descriptors.\n    for (fd_entries_t::size_type i = 0, size = fd_entries_.size ();\n         i < size && event_count_ > 0; ++i) {\n        //  fd_entries_[i] may not be stored, since calls to\n        //  in_event/out_event may reallocate the vector\n\n        if (is_retired_fd (fd_entries_[i]))\n            continue;\n\n        if (FD_ISSET (fd_entries_[i].fd, &local_fds_set_.read)) {\n            fd_entries_[i].events->in_event ();\n            --event_count_;\n        }\n\n        //  TODO: can the is_retired_fd be true at this point? if it\n        //  was retired before, we would already have continued, and I\n        //  don't see where it might have been modified\n        //  And if rc == 0, we can break instead of continuing\n        if (is_retired_fd (fd_entries_[i]) || event_count_ == 0)\n            continue;\n\n        if (FD_ISSET (fd_entries_[i].fd, &local_fds_set_.write)) {\n            fd_entries_[i].events->out_event ();\n            --event_count_;\n        }\n\n        //  TODO: same as above\n        if (is_retired_fd (fd_entries_[i]) || event_count_ == 0)\n            continue;\n\n        if (FD_ISSET (fd_entries_[i].fd, &local_fds_set_.error)) {\n            fd_entries_[i].events->in_event ();\n            --event_count_;\n        }\n    }\n}\n\n#if defined ZMQ_HAVE_WINDOWS\nint zmq::select_t::try_retire_fd_entry (\n  family_entries_t::iterator family_entry_it_, zmq::fd_t &handle_)\n{\n    family_entry_t &family_entry = family_entry_it_->second;\n\n    fd_entries_t::iterator fd_entry_it =\n      find_fd_entry_by_handle (family_entry.fd_entries, handle_);\n\n    if (fd_entry_it == family_entry.fd_entries.end ())\n        return 0;\n\n    fd_entry_t &fd_entry = *fd_entry_it;\n    zmq_assert (fd_entry.fd != retired_fd);\n\n    if (family_entry_it_ != _current_family_entry_it) {\n        //  Family is not currently being iterated and can be safely\n        //  modified in-place. So later it can be skipped without\n        //  re-verifying its content.\n        family_entry.fd_entries.erase (fd_entry_it);\n    } else {\n        //  Otherwise mark removed entries as retired. It will be cleaned up\n        //  at the end of the iteration. See zmq::select_t::loop\n        fd_entry.fd = retired_fd;\n        family_entry.has_retired = true;\n    }\n    family_entry.fds_set.remove_fd (handle_);\n    return 1;\n}\n#endif\n\nvoid zmq::select_t::rm_fd (handle_t handle_)\n{\n    check_thread ();\n    int retired = 0;\n#if defined ZMQ_HAVE_WINDOWS\n    u_short family = get_fd_family (handle_);\n    if (family != AF_UNSPEC) {\n        family_entries_t::iterator family_entry_it =\n          _family_entries.find (family);\n\n        retired += try_retire_fd_entry (family_entry_it, handle_);\n    } else {\n        //  get_fd_family may fail and return AF_UNSPEC if the socket was not\n        //  successfully connected. In that case, we need to look for the\n        //  socket in all family_entries.\n        family_entries_t::iterator end = _family_entries.end ();\n        for (family_entries_t::iterator family_entry_it =\n               _family_entries.begin ();\n             family_entry_it != end; ++family_entry_it) {\n            if (retired += try_retire_fd_entry (family_entry_it, handle_)) {\n                break;\n            }\n        }\n    }\n#else\n    fd_entries_t::iterator fd_entry_it =\n      find_fd_entry_by_handle (_family_entry.fd_entries, handle_);\n    assert (fd_entry_it != _family_entry.fd_entries.end ());\n\n    zmq_assert (fd_entry_it->fd != retired_fd);\n    fd_entry_it->fd = retired_fd;\n    _family_entry.fds_set.remove_fd (handle_);\n\n    ++retired;\n\n    if (handle_ == _max_fd) {\n        _max_fd = retired_fd;\n        for (fd_entry_it = _family_entry.fd_entries.begin ();\n             fd_entry_it != _family_entry.fd_entries.end (); ++fd_entry_it)\n            if (fd_entry_it->fd > _max_fd)\n                _max_fd = fd_entry_it->fd;\n    }\n\n    _family_entry.has_retired = true;\n#endif\n    zmq_assert (retired == 1);\n    adjust_load (-1);\n}\n\nvoid zmq::select_t::set_pollin (handle_t handle_)\n{\n    check_thread ();\n#if defined ZMQ_HAVE_WINDOWS\n    u_short family = get_fd_family (handle_);\n    wsa_assert (family != AF_UNSPEC);\n    family_entry_t &family_entry = _family_entries[family];\n#else\n    family_entry_t &family_entry = _family_entry;\n#endif\n    FD_SET (handle_, &family_entry.fds_set.read);\n}\n\nvoid zmq::select_t::reset_pollin (handle_t handle_)\n{\n    check_thread ();\n#if defined ZMQ_HAVE_WINDOWS\n    u_short family = get_fd_family (handle_);\n    wsa_assert (family != AF_UNSPEC);\n    family_entry_t &family_entry = _family_entries[family];\n#else\n    family_entry_t &family_entry = _family_entry;\n#endif\n    FD_CLR (handle_, &family_entry.fds_set.read);\n}\n\nvoid zmq::select_t::set_pollout (handle_t handle_)\n{\n    check_thread ();\n#if defined ZMQ_HAVE_WINDOWS\n    u_short family = get_fd_family (handle_);\n    wsa_assert (family != AF_UNSPEC);\n    family_entry_t &family_entry = _family_entries[family];\n#else\n    family_entry_t &family_entry = _family_entry;\n#endif\n    FD_SET (handle_, &family_entry.fds_set.write);\n}\n\nvoid zmq::select_t::reset_pollout (handle_t handle_)\n{\n    check_thread ();\n#if defined ZMQ_HAVE_WINDOWS\n    u_short family = get_fd_family (handle_);\n    wsa_assert (family != AF_UNSPEC);\n    family_entry_t &family_entry = _family_entries[family];\n#else\n    family_entry_t &family_entry = _family_entry;\n#endif\n    FD_CLR (handle_, &family_entry.fds_set.write);\n}\n\nvoid zmq::select_t::stop ()\n{\n    check_thread ();\n    //  no-op... thread is stopped when no more fds or timers are registered\n}\n\nint zmq::select_t::max_fds ()\n{\n    return FD_SETSIZE;\n}\n\nvoid zmq::select_t::loop ()\n{\n    while (true) {\n        //  Execute any due timers.\n        int timeout = static_cast<int> (execute_timers ());\n\n        cleanup_retired ();\n\n#ifdef _WIN32\n        if (_family_entries.empty ()) {\n#else\n        if (_family_entry.fd_entries.empty ()) {\n#endif\n            zmq_assert (get_load () == 0);\n\n            if (timeout == 0)\n                break;\n\n            // TODO sleep for timeout\n            continue;\n        }\n\n#if defined ZMQ_HAVE_OSX\n        struct timeval tv = {(long) (timeout / 1000), timeout % 1000 * 1000};\n#else\n        struct timeval tv = {static_cast<long> (timeout / 1000),\n                             static_cast<long> (timeout % 1000 * 1000)};\n#endif\n\n#if defined ZMQ_HAVE_WINDOWS\n        /*\n            On Windows select does not allow to mix descriptors from different\n            service providers. It seems to work for AF_INET and AF_INET6,\n            but fails for AF_INET and VMCI. The workaround is to use\n            WSAEventSelect and WSAWaitForMultipleEvents to wait, then use\n            select to find out what actually changed. WSAWaitForMultipleEvents\n            cannot be used alone, because it does not support more than 64 events\n            which is not enough.\n\n            To reduce unnecessary overhead, WSA is only used when there are more\n            than one family. Moreover, AF_INET and AF_INET6 are considered the same\n            family because Windows seems to handle them properly.\n            See get_fd_family for details.\n        */\n\n        //  If there is just one family, there is no reason to use WSA events.\n        int rc = 0;\n        const bool use_wsa_events = _family_entries.size () > 1;\n        if (use_wsa_events) {\n            // TODO: I don't really understand why we are doing this. If any of\n            // the events was signaled, we will call select for each fd_family\n            // afterwards. The only benefit is if none of the events was\n            // signaled, then we continue early.\n            // IMHO, either WSAEventSelect/WSAWaitForMultipleEvents or select\n            // should be used, but not both\n\n            wsa_events_t wsa_events;\n\n            for (family_entries_t::iterator family_entry_it =\n                   _family_entries.begin ();\n                 family_entry_it != _family_entries.end (); ++family_entry_it) {\n                family_entry_t &family_entry = family_entry_it->second;\n\n                for (fd_entries_t::iterator fd_entry_it =\n                       family_entry.fd_entries.begin ();\n                     fd_entry_it != family_entry.fd_entries.end ();\n                     ++fd_entry_it) {\n                    fd_t fd = fd_entry_it->fd;\n\n                    //  http://stackoverflow.com/q/35043420/188530\n                    if (FD_ISSET (fd, &family_entry.fds_set.read)\n                        && FD_ISSET (fd, &family_entry.fds_set.write))\n                        rc = WSAEventSelect (fd, wsa_events.events[3],\n                                             FD_READ | FD_ACCEPT | FD_CLOSE\n                                               | FD_WRITE | FD_CONNECT);\n                    else if (FD_ISSET (fd, &family_entry.fds_set.read))\n                        rc = WSAEventSelect (fd, wsa_events.events[0],\n                                             FD_READ | FD_ACCEPT | FD_CLOSE);\n                    else if (FD_ISSET (fd, &family_entry.fds_set.write))\n                        rc = WSAEventSelect (fd, wsa_events.events[1],\n                                             FD_WRITE | FD_CONNECT);\n                    else\n                        rc = 0;\n\n                    wsa_assert (rc != SOCKET_ERROR);\n                }\n            }\n\n            rc = WSAWaitForMultipleEvents (4, wsa_events.events, FALSE,\n                                           timeout ? timeout : INFINITE, FALSE);\n            wsa_assert (rc != (int) WSA_WAIT_FAILED);\n            zmq_assert (rc != WSA_WAIT_IO_COMPLETION);\n\n            if (rc == WSA_WAIT_TIMEOUT)\n                continue;\n        }\n\n        for (_current_family_entry_it = _family_entries.begin ();\n             _current_family_entry_it != _family_entries.end ();\n             ++_current_family_entry_it) {\n            family_entry_t &family_entry = _current_family_entry_it->second;\n\n\n            if (use_wsa_events) {\n                //  There is no reason to wait again after WSAWaitForMultipleEvents.\n                //  Simply collect what is ready.\n                struct timeval tv_nodelay = {0, 0};\n                select_family_entry (family_entry, 0, true, tv_nodelay);\n            } else {\n                select_family_entry (family_entry, 0, timeout > 0, tv);\n            }\n        }\n#else\n        select_family_entry (_family_entry, _max_fd + 1, timeout > 0, tv);\n#endif\n    }\n}\n\nvoid zmq::select_t::select_family_entry (family_entry_t &family_entry_,\n                                         const int max_fd_,\n                                         const bool use_timeout_,\n                                         struct timeval &tv_)\n{\n    //  select will fail when run with empty sets.\n    fd_entries_t &fd_entries = family_entry_.fd_entries;\n    if (fd_entries.empty ())\n        return;\n\n    fds_set_t local_fds_set = family_entry_.fds_set;\n    int rc = select (max_fd_, &local_fds_set.read, &local_fds_set.write,\n                     &local_fds_set.error, use_timeout_ ? &tv_ : NULL);\n\n#if defined ZMQ_HAVE_WINDOWS\n    wsa_assert (rc != SOCKET_ERROR);\n#else\n    if (rc == -1) {\n        errno_assert (errno == EINTR);\n        return;\n    }\n#endif\n\n    trigger_events (fd_entries, local_fds_set, rc);\n\n    cleanup_retired (family_entry_);\n}\n\nzmq::select_t::fds_set_t::fds_set_t ()\n{\n    FD_ZERO (&read);\n    FD_ZERO (&write);\n    FD_ZERO (&error);\n}\n\nzmq::select_t::fds_set_t::fds_set_t (const fds_set_t &other_)\n{\n#if defined ZMQ_HAVE_WINDOWS\n    // On Windows we don't need to copy the whole fd_set.\n    // SOCKETS are continuous from the beginning of fd_array in fd_set.\n    // We just need to copy fd_count elements of fd_array.\n    // We gain huge memcpy() improvement if number of used SOCKETs is much lower than FD_SETSIZE.\n    memcpy (&read, &other_.read,\n            (char *) (other_.read.fd_array + other_.read.fd_count)\n              - (char *) &other_.read);\n    memcpy (&write, &other_.write,\n            (char *) (other_.write.fd_array + other_.write.fd_count)\n              - (char *) &other_.write);\n    memcpy (&error, &other_.error,\n            (char *) (other_.error.fd_array + other_.error.fd_count)\n              - (char *) &other_.error);\n#else\n    memcpy (&read, &other_.read, sizeof other_.read);\n    memcpy (&write, &other_.write, sizeof other_.write);\n    memcpy (&error, &other_.error, sizeof other_.error);\n#endif\n}\n\nzmq::select_t::fds_set_t &\nzmq::select_t::fds_set_t::operator= (const fds_set_t &other_)\n{\n#if defined ZMQ_HAVE_WINDOWS\n    // On Windows we don't need to copy the whole fd_set.\n    // SOCKETS are continuous from the beginning of fd_array in fd_set.\n    // We just need to copy fd_count elements of fd_array.\n    // We gain huge memcpy() improvement if number of used SOCKETs is much lower than FD_SETSIZE.\n    memcpy (&read, &other_.read,\n            (char *) (other_.read.fd_array + other_.read.fd_count)\n              - (char *) &other_.read);\n    memcpy (&write, &other_.write,\n            (char *) (other_.write.fd_array + other_.write.fd_count)\n              - (char *) &other_.write);\n    memcpy (&error, &other_.error,\n            (char *) (other_.error.fd_array + other_.error.fd_count)\n              - (char *) &other_.error);\n#else\n    memcpy (&read, &other_.read, sizeof other_.read);\n    memcpy (&write, &other_.write, sizeof other_.write);\n    memcpy (&error, &other_.error, sizeof other_.error);\n#endif\n    return *this;\n}\n\nvoid zmq::select_t::fds_set_t::remove_fd (const fd_t &fd_)\n{\n    FD_CLR (fd_, &read);\n    FD_CLR (fd_, &write);\n    FD_CLR (fd_, &error);\n}\n\nbool zmq::select_t::cleanup_retired (family_entry_t &family_entry_)\n{\n    if (family_entry_.has_retired) {\n        family_entry_.has_retired = false;\n        family_entry_.fd_entries.erase (\n          std::remove_if (family_entry_.fd_entries.begin (),\n                          family_entry_.fd_entries.end (), is_retired_fd),\n          family_entry_.fd_entries.end ());\n    }\n    return family_entry_.fd_entries.empty ();\n}\n\nvoid zmq::select_t::cleanup_retired ()\n{\n#ifdef _WIN32\n    for (family_entries_t::iterator it = _family_entries.begin ();\n         it != _family_entries.end ();) {\n        if (cleanup_retired (it->second))\n            it = _family_entries.erase (it);\n        else\n            ++it;\n    }\n#else\n    cleanup_retired (_family_entry);\n#endif\n}\n\nbool zmq::select_t::is_retired_fd (const fd_entry_t &entry_)\n{\n    return entry_.fd == retired_fd;\n}\n\nzmq::select_t::family_entry_t::family_entry_t () : has_retired (false)\n{\n}\n\n\n#if defined ZMQ_HAVE_WINDOWS\nu_short zmq::select_t::get_fd_family (fd_t fd_)\n{\n    // cache the results of determine_fd_family, as this is frequently called\n    // for the same sockets, and determine_fd_family is expensive\n    size_t i;\n    for (i = 0; i < fd_family_cache_size; ++i) {\n        const std::pair<fd_t, u_short> &entry = _fd_family_cache[i];\n        if (entry.first == fd_) {\n            return entry.second;\n        }\n        if (entry.first == retired_fd)\n            break;\n    }\n\n    std::pair<fd_t, u_short> res =\n      std::make_pair (fd_, determine_fd_family (fd_));\n    if (i < fd_family_cache_size) {\n        _fd_family_cache[i] = res;\n    } else {\n        // just overwrite a random entry\n        // could be optimized by some LRU strategy\n        _fd_family_cache[rand () % fd_family_cache_size] = res;\n    }\n\n    return res.second;\n}\n\nu_short zmq::select_t::determine_fd_family (fd_t fd_)\n{\n    //  Use sockaddr_storage instead of sockaddr to accommodate different structure sizes\n    sockaddr_storage addr = {0};\n    int addr_size = sizeof addr;\n\n    int type;\n    int type_length = sizeof (int);\n\n    int rc = getsockopt (fd_, SOL_SOCKET, SO_TYPE,\n                         reinterpret_cast<char *> (&type), &type_length);\n\n    if (rc == 0) {\n        if (type == SOCK_DGRAM)\n            return AF_INET;\n\n        rc =\n          getsockname (fd_, reinterpret_cast<sockaddr *> (&addr), &addr_size);\n\n        //  AF_INET and AF_INET6 can be mixed in select\n        //  TODO: If proven otherwise, should simply return addr.sa_family\n        if (rc != SOCKET_ERROR)\n            return addr.ss_family == AF_INET6 ? AF_INET : addr.ss_family;\n    }\n\n    return AF_UNSPEC;\n}\n\nzmq::select_t::wsa_events_t::wsa_events_t ()\n{\n    events[0] = WSACreateEvent ();\n    wsa_assert (events[0] != WSA_INVALID_EVENT);\n    events[1] = WSACreateEvent ();\n    wsa_assert (events[1] != WSA_INVALID_EVENT);\n    events[2] = WSACreateEvent ();\n    wsa_assert (events[2] != WSA_INVALID_EVENT);\n    events[3] = WSACreateEvent ();\n    wsa_assert (events[3] != WSA_INVALID_EVENT);\n}\n\nzmq::select_t::wsa_events_t::~wsa_events_t ()\n{\n    wsa_assert (WSACloseEvent (events[0]));\n    wsa_assert (WSACloseEvent (events[1]));\n    wsa_assert (WSACloseEvent (events[2]));\n    wsa_assert (WSACloseEvent (events[3]));\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/select.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SELECT_HPP_INCLUDED__\n#define __ZMQ_SELECT_HPP_INCLUDED__\n\n//  poller.hpp decides which polling mechanism to use.\n#include \"poller.hpp\"\n#if defined ZMQ_IOTHREAD_POLLER_USE_SELECT\n\n#include <stddef.h>\n#include <vector>\n#include <map>\n\n#if defined ZMQ_HAVE_WINDOWS\n#elif defined ZMQ_HAVE_OPENVMS\n#include <sys/types.h>\n#include <sys/time.h>\n#else\n#include <sys/select.h>\n#endif\n\n#include \"ctx.hpp\"\n#include \"fd.hpp\"\n#include \"poller_base.hpp\"\n\nnamespace zmq\n{\nstruct i_poll_events;\n\n//  Implements socket polling mechanism using POSIX.1-2001 select()\n//  function.\n\nclass select_t ZMQ_FINAL : public worker_poller_base_t\n{\n  public:\n    typedef fd_t handle_t;\n\n    select_t (const thread_ctx_t &ctx_);\n    ~select_t () ZMQ_FINAL;\n\n    //  \"poller\" concept.\n    handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);\n    void rm_fd (handle_t handle_);\n    void set_pollin (handle_t handle_);\n    void reset_pollin (handle_t handle_);\n    void set_pollout (handle_t handle_);\n    void reset_pollout (handle_t handle_);\n    void stop ();\n\n    static int max_fds ();\n\n  private:\n    //  Main event loop.\n    void loop () ZMQ_FINAL;\n\n    //  Internal state.\n    struct fds_set_t\n    {\n        fds_set_t ();\n        fds_set_t (const fds_set_t &other_);\n        fds_set_t &operator= (const fds_set_t &other_);\n        //  Convenience method to descriptor from all sets.\n        void remove_fd (const fd_t &fd_);\n\n        fd_set read;\n        fd_set write;\n        fd_set error;\n    };\n\n    struct fd_entry_t\n    {\n        fd_t fd;\n        zmq::i_poll_events *events;\n    };\n    typedef std::vector<fd_entry_t> fd_entries_t;\n\n    void trigger_events (const fd_entries_t &fd_entries_,\n                         const fds_set_t &local_fds_set_,\n                         int event_count_);\n\n    struct family_entry_t\n    {\n        family_entry_t ();\n\n        fd_entries_t fd_entries;\n        fds_set_t fds_set;\n        bool has_retired;\n    };\n\n    void select_family_entry (family_entry_t &family_entry_,\n                              int max_fd_,\n                              bool use_timeout_,\n                              struct timeval &tv_);\n\n#if defined ZMQ_HAVE_WINDOWS\n    typedef std::map<u_short, family_entry_t> family_entries_t;\n\n    struct wsa_events_t\n    {\n        wsa_events_t ();\n        ~wsa_events_t ();\n\n        //  read, write, error and readwrite\n        WSAEVENT events[4];\n    };\n\n    family_entries_t _family_entries;\n    // See loop for details.\n    family_entries_t::iterator _current_family_entry_it;\n\n    int try_retire_fd_entry (family_entries_t::iterator family_entry_it_,\n                             zmq::fd_t &handle_);\n\n    static const size_t fd_family_cache_size = 8;\n    std::pair<fd_t, u_short> _fd_family_cache[fd_family_cache_size];\n\n    u_short get_fd_family (fd_t fd_);\n\n    //  Socket's family or AF_UNSPEC on error.\n    static u_short determine_fd_family (fd_t fd_);\n#else\n    //  on non-Windows, we can treat all fds as one family\n    family_entry_t _family_entry;\n    fd_t _max_fd;\n#endif\n\n    void cleanup_retired ();\n    bool cleanup_retired (family_entry_t &family_entry_);\n\n    //  Checks if an fd_entry_t is retired.\n    static bool is_retired_fd (const fd_entry_t &entry_);\n\n    static fd_entries_t::iterator\n    find_fd_entry_by_handle (fd_entries_t &fd_entries_, handle_t handle_);\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (select_t)\n};\n\ntypedef select_t poller_t;\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/server.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"server.hpp\"\n#include \"pipe.hpp\"\n#include \"wire.hpp\"\n#include \"random.hpp\"\n#include \"likely.hpp\"\n#include \"err.hpp\"\n\nzmq::server_t::server_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_, true),\n    _next_routing_id (generate_random ())\n{\n    options.type = ZMQ_SERVER;\n    options.can_send_hello_msg = true;\n    options.can_recv_disconnect_msg = true;\n}\n\nzmq::server_t::~server_t ()\n{\n    zmq_assert (_out_pipes.empty ());\n}\n\nvoid zmq::server_t::xattach_pipe (pipe_t *pipe_,\n                                  bool subscribe_to_all_,\n                                  bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_);\n\n    uint32_t routing_id = _next_routing_id++;\n    if (!routing_id)\n        routing_id = _next_routing_id++; //  Never use Routing ID zero\n\n    pipe_->set_server_socket_routing_id (routing_id);\n    //  Add the record into output pipes lookup table\n    outpipe_t outpipe = {pipe_, true};\n    const bool ok =\n      _out_pipes.ZMQ_MAP_INSERT_OR_EMPLACE (routing_id, outpipe).second;\n    zmq_assert (ok);\n\n    _fq.attach (pipe_);\n}\n\nvoid zmq::server_t::xpipe_terminated (pipe_t *pipe_)\n{\n    const out_pipes_t::iterator it =\n      _out_pipes.find (pipe_->get_server_socket_routing_id ());\n    zmq_assert (it != _out_pipes.end ());\n    _out_pipes.erase (it);\n    _fq.pipe_terminated (pipe_);\n}\n\nvoid zmq::server_t::xread_activated (pipe_t *pipe_)\n{\n    _fq.activated (pipe_);\n}\n\nvoid zmq::server_t::xwrite_activated (pipe_t *pipe_)\n{\n    const out_pipes_t::iterator end = _out_pipes.end ();\n    out_pipes_t::iterator it;\n    for (it = _out_pipes.begin (); it != end; ++it)\n        if (it->second.pipe == pipe_)\n            break;\n\n    zmq_assert (it != _out_pipes.end ());\n    zmq_assert (!it->second.active);\n    it->second.active = true;\n}\n\nint zmq::server_t::xsend (msg_t *msg_)\n{\n    //  SERVER sockets do not allow multipart data (ZMQ_SNDMORE)\n    if (msg_->flags () & msg_t::more) {\n        errno = EINVAL;\n        return -1;\n    }\n    //  Find the pipe associated with the routing stored in the message.\n    const uint32_t routing_id = msg_->get_routing_id ();\n    out_pipes_t::iterator it = _out_pipes.find (routing_id);\n\n    if (it != _out_pipes.end ()) {\n        if (!it->second.pipe->check_write ()) {\n            it->second.active = false;\n            errno = EAGAIN;\n            return -1;\n        }\n    } else {\n        errno = EHOSTUNREACH;\n        return -1;\n    }\n\n    //  Message might be delivered over inproc, so we reset routing id\n    int rc = msg_->reset_routing_id ();\n    errno_assert (rc == 0);\n\n    const bool ok = it->second.pipe->write (msg_);\n    if (unlikely (!ok)) {\n        // Message failed to send - we must close it ourselves.\n        rc = msg_->close ();\n        errno_assert (rc == 0);\n    } else\n        it->second.pipe->flush ();\n\n    //  Detach the message from the data buffer.\n    rc = msg_->init ();\n    errno_assert (rc == 0);\n\n    return 0;\n}\n\nint zmq::server_t::xrecv (msg_t *msg_)\n{\n    pipe_t *pipe = NULL;\n    int rc = _fq.recvpipe (msg_, &pipe);\n\n    // Drop any messages with more flag\n    while (rc == 0 && msg_->flags () & msg_t::more) {\n        // drop all frames of the current multi-frame message\n        rc = _fq.recvpipe (msg_, NULL);\n\n        while (rc == 0 && msg_->flags () & msg_t::more)\n            rc = _fq.recvpipe (msg_, NULL);\n\n        // get the new message\n        if (rc == 0)\n            rc = _fq.recvpipe (msg_, &pipe);\n    }\n\n    if (rc != 0)\n        return rc;\n\n    zmq_assert (pipe != NULL);\n\n    const uint32_t routing_id = pipe->get_server_socket_routing_id ();\n    msg_->set_routing_id (routing_id);\n\n    return 0;\n}\n\nbool zmq::server_t::xhas_in ()\n{\n    return _fq.has_in ();\n}\n\nbool zmq::server_t::xhas_out ()\n{\n    //  In theory, SERVER socket is always ready for writing. Whether actual\n    //  attempt to write succeeds depends on which pipe the message is going\n    //  to be routed to.\n    return true;\n}\n\nint zmq::server_t::xdisconnect_peer (uint32_t routing_id_)\n{\n    out_pipes_t::iterator it = _out_pipes.find (routing_id_);\n    if (it == _out_pipes.end ()) {\n        errno = EHOSTUNREACH;\n        return -1;\n    }\n\n    // Terminate the pipe; xpipe_terminated will erase it from maps.\n    it->second.pipe->terminate (false);\n    return 0;\n}\n"
  },
  {
    "path": "src/server.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SERVER_HPP_INCLUDED__\n#define __ZMQ_SERVER_HPP_INCLUDED__\n\n#include <map>\n\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n#include \"stdint.hpp\"\n#include \"blob.hpp\"\n#include \"fq.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass pipe_t;\n\n//  TODO: This class uses O(n) scheduling. Rewrite it to use O(1) algorithm.\nclass server_t : public socket_base_t\n{\n  public:\n    server_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~server_t ();\n\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xsend (zmq::msg_t *msg_);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    bool xhas_out ();\n    void xread_activated (zmq::pipe_t *pipe_);\n    void xwrite_activated (zmq::pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n    int xdisconnect_peer (uint32_t routing_id_);\n\n  private:\n    //  Fair queueing object for inbound pipes.\n    fq_t _fq;\n\n    struct outpipe_t\n    {\n        zmq::pipe_t *pipe;\n        bool active;\n    };\n\n    //  Outbound pipes indexed by the peer IDs.\n    typedef std::map<uint32_t, outpipe_t> out_pipes_t;\n    out_pipes_t _out_pipes;\n\n    //  Routing IDs are generated. It's a simple increment and wrap-over\n    //  algorithm. This value is the next ID to use (if not used already).\n    uint32_t _next_routing_id;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (server_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/session_base.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"session_base.hpp\"\n#include \"i_engine.hpp\"\n#include \"err.hpp\"\n#include \"pipe.hpp\"\n#include \"likely.hpp\"\n#include \"tcp_connecter.hpp\"\n#include \"ws_connecter.hpp\"\n#include \"ipc_connecter.hpp\"\n#include \"tipc_connecter.hpp\"\n#include \"socks_connecter.hpp\"\n#include \"vmci_connecter.hpp\"\n#include \"vsock_connecter.hpp\"\n#include \"pgm_sender.hpp\"\n#include \"pgm_receiver.hpp\"\n#include \"address.hpp\"\n#include \"norm_engine.hpp\"\n#include \"udp_engine.hpp\"\n\n#include \"ctx.hpp\"\n#include \"req.hpp\"\n#include \"radio.hpp\"\n#include \"dish.hpp\"\n\nzmq::session_base_t *zmq::session_base_t::create (class io_thread_t *io_thread_,\n                                                  bool active_,\n                                                  class socket_base_t *socket_,\n                                                  const options_t &options_,\n                                                  address_t *addr_)\n{\n    session_base_t *s = NULL;\n    switch (options_.type) {\n        case ZMQ_REQ:\n            s = new (std::nothrow)\n              req_session_t (io_thread_, active_, socket_, options_, addr_);\n            break;\n        case ZMQ_RADIO:\n            s = new (std::nothrow)\n              radio_session_t (io_thread_, active_, socket_, options_, addr_);\n            break;\n        case ZMQ_DISH:\n            s = new (std::nothrow)\n              dish_session_t (io_thread_, active_, socket_, options_, addr_);\n            break;\n        case ZMQ_DEALER:\n        case ZMQ_REP:\n        case ZMQ_ROUTER:\n        case ZMQ_PUB:\n        case ZMQ_XPUB:\n        case ZMQ_SUB:\n        case ZMQ_XSUB:\n        case ZMQ_PUSH:\n        case ZMQ_PULL:\n        case ZMQ_PAIR:\n        case ZMQ_STREAM:\n        case ZMQ_SERVER:\n        case ZMQ_CLIENT:\n        case ZMQ_GATHER:\n        case ZMQ_SCATTER:\n        case ZMQ_DGRAM:\n        case ZMQ_PEER:\n        case ZMQ_CHANNEL:\n#ifdef ZMQ_BUILD_DRAFT_API\n            if (options_.can_send_hello_msg && options_.hello_msg.size () > 0)\n                s = new (std::nothrow) hello_msg_session_t (\n                  io_thread_, active_, socket_, options_, addr_);\n            else\n                s = new (std::nothrow) session_base_t (\n                  io_thread_, active_, socket_, options_, addr_);\n\n            break;\n#else\n            s = new (std::nothrow)\n              session_base_t (io_thread_, active_, socket_, options_, addr_);\n            break;\n#endif\n\n        default:\n            errno = EINVAL;\n            return NULL;\n    }\n    alloc_assert (s);\n    return s;\n}\n\nzmq::session_base_t::session_base_t (class io_thread_t *io_thread_,\n                                     bool active_,\n                                     class socket_base_t *socket_,\n                                     const options_t &options_,\n                                     address_t *addr_) :\n    own_t (io_thread_, options_),\n    io_object_t (io_thread_),\n    _active (active_),\n    _pipe (NULL),\n    _zap_pipe (NULL),\n    _incomplete_in (false),\n    _pending (false),\n    _engine (NULL),\n    _socket (socket_),\n    _io_thread (io_thread_),\n    _has_linger_timer (false),\n    _addr (addr_)\n#ifdef ZMQ_HAVE_WSS\n    ,\n    _wss_hostname (options_.wss_hostname)\n#endif\n{\n}\n\nconst zmq::endpoint_uri_pair_t &zmq::session_base_t::get_endpoint () const\n{\n    return _engine->get_endpoint ();\n}\n\nzmq::session_base_t::~session_base_t ()\n{\n    zmq_assert (!_pipe);\n    zmq_assert (!_zap_pipe);\n\n    //  If there's still a pending linger timer, remove it.\n    if (_has_linger_timer) {\n        cancel_timer (linger_timer_id);\n        _has_linger_timer = false;\n    }\n\n    //  Close the engine.\n    if (_engine)\n        _engine->terminate ();\n\n    LIBZMQ_DELETE (_addr);\n}\n\nvoid zmq::session_base_t::attach_pipe (pipe_t *pipe_)\n{\n    zmq_assert (!is_terminating ());\n    zmq_assert (!_pipe);\n    zmq_assert (pipe_);\n    _pipe = pipe_;\n    _pipe->set_event_sink (this);\n}\n\nint zmq::session_base_t::pull_msg (msg_t *msg_)\n{\n    if (!_pipe || !_pipe->read (msg_)) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    _incomplete_in = (msg_->flags () & msg_t::more) != 0;\n\n    return 0;\n}\n\nint zmq::session_base_t::push_msg (msg_t *msg_)\n{\n    //  pass subscribe/cancel to the sockets\n    if ((msg_->flags () & msg_t::command) && !msg_->is_subscribe ()\n        && !msg_->is_cancel ())\n        return 0;\n    if (_pipe && _pipe->write (msg_)) {\n        const int rc = msg_->init ();\n        errno_assert (rc == 0);\n        return 0;\n    }\n\n    errno = EAGAIN;\n    return -1;\n}\n\nint zmq::session_base_t::read_zap_msg (msg_t *msg_)\n{\n    if (_zap_pipe == NULL) {\n        errno = ENOTCONN;\n        return -1;\n    }\n\n    if (!_zap_pipe->read (msg_)) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    return 0;\n}\n\nint zmq::session_base_t::write_zap_msg (msg_t *msg_)\n{\n    if (_zap_pipe == NULL || !_zap_pipe->write (msg_)) {\n        errno = ENOTCONN;\n        return -1;\n    }\n\n    if ((msg_->flags () & msg_t::more) == 0)\n        _zap_pipe->flush ();\n\n    const int rc = msg_->init ();\n    errno_assert (rc == 0);\n    return 0;\n}\n\nvoid zmq::session_base_t::reset ()\n{\n}\n\nvoid zmq::session_base_t::flush ()\n{\n    if (_pipe)\n        _pipe->flush ();\n}\n\nvoid zmq::session_base_t::rollback ()\n{\n    if (_pipe)\n        _pipe->rollback ();\n}\n\nvoid zmq::session_base_t::clean_pipes ()\n{\n    zmq_assert (_pipe != NULL);\n\n    //  Get rid of half-processed messages in the out pipe. Flush any\n    //  unflushed messages upstream.\n    _pipe->rollback ();\n    _pipe->flush ();\n\n    //  Remove any half-read message from the in pipe.\n    while (_incomplete_in) {\n        msg_t msg;\n        int rc = msg.init ();\n        errno_assert (rc == 0);\n        rc = pull_msg (&msg);\n        errno_assert (rc == 0);\n        rc = msg.close ();\n        errno_assert (rc == 0);\n    }\n}\n\nvoid zmq::session_base_t::pipe_terminated (pipe_t *pipe_)\n{\n    // Drop the reference to the deallocated pipe if required.\n    zmq_assert (pipe_ == _pipe || pipe_ == _zap_pipe\n                || _terminating_pipes.count (pipe_) == 1);\n\n    if (pipe_ == _pipe) {\n        // If this is our current pipe, remove it\n        _pipe = NULL;\n        if (_has_linger_timer) {\n            cancel_timer (linger_timer_id);\n            _has_linger_timer = false;\n        }\n    } else if (pipe_ == _zap_pipe)\n        _zap_pipe = NULL;\n    else\n        // Remove the pipe from the detached pipes set\n        _terminating_pipes.erase (pipe_);\n\n    if (!is_terminating () && options.raw_socket) {\n        if (_engine) {\n            _engine->terminate ();\n            _engine = NULL;\n        }\n        terminate ();\n    }\n\n    //  If we are waiting for pending messages to be sent, at this point\n    //  we are sure that there will be no more messages and we can proceed\n    //  with termination safely.\n    if (_pending && !_pipe && !_zap_pipe && _terminating_pipes.empty ()) {\n        _pending = false;\n        own_t::process_term (0);\n    }\n}\n\nvoid zmq::session_base_t::read_activated (pipe_t *pipe_)\n{\n    // Skip activating if we're detaching this pipe\n    if (unlikely (pipe_ != _pipe && pipe_ != _zap_pipe)) {\n        zmq_assert (_terminating_pipes.count (pipe_) == 1);\n        return;\n    }\n\n    if (unlikely (_engine == NULL)) {\n        if (_pipe)\n            _pipe->check_read ();\n        return;\n    }\n\n    if (likely (pipe_ == _pipe))\n        _engine->restart_output ();\n    else {\n        // i.e. pipe_ == zap_pipe\n        _engine->zap_msg_available ();\n    }\n}\n\nvoid zmq::session_base_t::write_activated (pipe_t *pipe_)\n{\n    // Skip activating if we're detaching this pipe\n    if (_pipe != pipe_) {\n        zmq_assert (_terminating_pipes.count (pipe_) == 1);\n        return;\n    }\n\n    if (_engine)\n        _engine->restart_input ();\n}\n\nvoid zmq::session_base_t::hiccuped (pipe_t *)\n{\n    //  Hiccups are always sent from session to socket, not the other\n    //  way round.\n    zmq_assert (false);\n}\n\nzmq::socket_base_t *zmq::session_base_t::get_socket () const\n{\n    return _socket;\n}\n\nvoid zmq::session_base_t::process_plug ()\n{\n    if (_active)\n        start_connecting (false);\n}\n\n//  This functions can return 0 on success or -1 and errno=ECONNREFUSED if ZAP\n//  is not setup (IE: inproc://zeromq.zap.01 does not exist in the same context)\n//  or it aborts on any other error. In other words, either ZAP is not\n//  configured or if it is configured it MUST be configured correctly and it\n//  MUST work, otherwise authentication cannot be guaranteed and it would be a\n//  security flaw.\nint zmq::session_base_t::zap_connect ()\n{\n    if (_zap_pipe != NULL)\n        return 0;\n\n    endpoint_t peer = find_endpoint (\"inproc://zeromq.zap.01\");\n    if (peer.socket == NULL) {\n        errno = ECONNREFUSED;\n        return -1;\n    }\n    zmq_assert (peer.options.type == ZMQ_REP || peer.options.type == ZMQ_ROUTER\n                || peer.options.type == ZMQ_SERVER);\n\n    //  Create a bi-directional pipe that will connect\n    //  session with zap socket.\n    object_t *parents[2] = {this, peer.socket};\n    pipe_t *new_pipes[2] = {NULL, NULL};\n    int hwms[2] = {0, 0};\n    bool conflates[2] = {false, false};\n    int rc = pipepair (parents, new_pipes, hwms, conflates);\n    errno_assert (rc == 0);\n\n    //  Attach local end of the pipe to this socket object.\n    _zap_pipe = new_pipes[0];\n    _zap_pipe->set_nodelay ();\n    _zap_pipe->set_event_sink (this);\n\n    send_bind (peer.socket, new_pipes[1], false);\n\n    //  Send empty routing id if required by the peer.\n    if (peer.options.recv_routing_id) {\n        msg_t id;\n        rc = id.init ();\n        errno_assert (rc == 0);\n        id.set_flags (msg_t::routing_id);\n        bool ok = _zap_pipe->write (&id);\n        zmq_assert (ok);\n        _zap_pipe->flush ();\n    }\n\n    return 0;\n}\n\nbool zmq::session_base_t::zap_enabled () const\n{\n    return (options.mechanism != ZMQ_NULL || !options.zap_domain.empty ());\n}\n\nvoid zmq::session_base_t::process_attach (i_engine *engine_)\n{\n    zmq_assert (engine_ != NULL);\n    zmq_assert (!_engine);\n    _engine = engine_;\n\n    if (!engine_->has_handshake_stage ())\n        engine_ready ();\n\n    //  Plug in the engine.\n    _engine->plug (_io_thread, this);\n}\n\nvoid zmq::session_base_t::engine_ready ()\n{\n    //  Create the pipe if it does not exist yet.\n    if (!_pipe && !is_terminating ()) {\n        object_t *parents[2] = {this, _socket};\n        pipe_t *pipes[2] = {NULL, NULL};\n\n        const bool conflate = get_effective_conflate_option (options);\n\n        int hwms[2] = {conflate ? -1 : options.rcvhwm,\n                       conflate ? -1 : options.sndhwm};\n        bool conflates[2] = {conflate, conflate};\n        const int rc = pipepair (parents, pipes, hwms, conflates);\n        errno_assert (rc == 0);\n\n        //  Plug the local end of the pipe.\n        pipes[0]->set_event_sink (this);\n\n        //  Remember the local end of the pipe.\n        zmq_assert (!_pipe);\n        _pipe = pipes[0];\n\n        //  The endpoints strings are not set on bind, set them here so that\n        //  events can use them.\n        pipes[0]->set_endpoint_pair (_engine->get_endpoint ());\n        pipes[1]->set_endpoint_pair (_engine->get_endpoint ());\n\n        //  Ask socket to plug into the remote end of the pipe.\n        send_bind (_socket, pipes[1]);\n    }\n}\n\nvoid zmq::session_base_t::engine_error (bool handshaked_,\n                                        zmq::i_engine::error_reason_t reason_)\n{\n    //  Engine is dead. Let's forget about it.\n    _engine = NULL;\n\n    //  Remove any half-done messages from the pipes.\n    if (_pipe) {\n        clean_pipes ();\n\n        //  Only send disconnect message if socket was accepted and handshake was completed\n        if (!_active && handshaked_ && options.can_recv_disconnect_msg\n            && !options.disconnect_msg.empty ()) {\n            _pipe->set_disconnect_msg (options.disconnect_msg);\n            _pipe->send_disconnect_msg ();\n        }\n\n        //  Only send hiccup message if socket was connected and handshake was completed\n        if (_active && handshaked_ && options.can_recv_hiccup_msg\n            && !options.hiccup_msg.empty ()) {\n            _pipe->send_hiccup_msg (options.hiccup_msg);\n        }\n    }\n\n    zmq_assert (reason_ == i_engine::connection_error\n                || reason_ == i_engine::timeout_error\n                || reason_ == i_engine::protocol_error);\n\n    switch (reason_) {\n        case i_engine::timeout_error:\n            /* FALLTHROUGH */\n        case i_engine::connection_error:\n            if (_active) {\n                reconnect ();\n                break;\n            }\n\n        case i_engine::protocol_error:\n            if (_pending) {\n                if (_pipe)\n                    _pipe->terminate (false);\n                if (_zap_pipe)\n                    _zap_pipe->terminate (false);\n            } else {\n                terminate ();\n            }\n            break;\n    }\n\n    //  Just in case there's only a delimiter in the pipe.\n    if (_pipe)\n        _pipe->check_read ();\n\n    if (_zap_pipe)\n        _zap_pipe->check_read ();\n}\n\nvoid zmq::session_base_t::process_term (int linger_)\n{\n    zmq_assert (!_pending);\n\n    //  If the termination of the pipe happens before the term command is\n    //  delivered there's nothing much to do. We can proceed with the\n    //  standard termination immediately.\n    if (!_pipe && !_zap_pipe && _terminating_pipes.empty ()) {\n        own_t::process_term (0);\n        return;\n    }\n\n    _pending = true;\n\n    if (_pipe != NULL) {\n        //  If there's finite linger value, delay the termination.\n        //  If linger is infinite (negative) we don't even have to set\n        //  the timer.\n        if (linger_ > 0) {\n            zmq_assert (!_has_linger_timer);\n            add_timer (linger_, linger_timer_id);\n            _has_linger_timer = true;\n        }\n\n        //  Start pipe termination process. Delay the termination till all messages\n        //  are processed in case the linger time is non-zero.\n        _pipe->terminate (linger_ != 0);\n\n        //  TODO: Should this go into pipe_t::terminate ?\n        //  In case there's no engine and there's only delimiter in the\n        //  pipe it wouldn't be ever read. Thus we check for it explicitly.\n        if (!_engine)\n            _pipe->check_read ();\n    }\n\n    if (_zap_pipe != NULL)\n        _zap_pipe->terminate (false);\n}\n\nvoid zmq::session_base_t::timer_event (int id_)\n{\n    //  Linger period expired. We can proceed with termination even though\n    //  there are still pending messages to be sent.\n    zmq_assert (id_ == linger_timer_id);\n    _has_linger_timer = false;\n\n    //  Ask pipe to terminate even though there may be pending messages in it.\n    zmq_assert (_pipe);\n    _pipe->terminate (false);\n}\n\nvoid zmq::session_base_t::process_conn_failed ()\n{\n    std::string *ep = new (std::string);\n    _addr->to_string (*ep);\n    send_term_endpoint (_socket, ep);\n}\n\nvoid zmq::session_base_t::reconnect ()\n{\n    //  For delayed connect situations, terminate the pipe\n    //  and reestablish later on\n    if (_pipe && options.immediate == 1\n#ifdef ZMQ_HAVE_OPENPGM\n        && _addr->protocol != protocol_name::pgm\n        && _addr->protocol != protocol_name::epgm\n#endif\n#ifdef ZMQ_HAVE_NORM\n        && _addr->protocol != protocol_name::norm\n#endif\n        && _addr->protocol != protocol_name::udp) {\n        _pipe->hiccup ();\n        _pipe->terminate (false);\n        _terminating_pipes.insert (_pipe);\n        _pipe = NULL;\n\n        if (_has_linger_timer) {\n            cancel_timer (linger_timer_id);\n            _has_linger_timer = false;\n        }\n    }\n\n    reset ();\n\n    //  Reconnect.\n    if (options.reconnect_ivl > 0)\n        start_connecting (true);\n    else {\n        std::string *ep = new (std::string);\n        _addr->to_string (*ep);\n        send_term_endpoint (_socket, ep);\n    }\n\n    //  For subscriber sockets we hiccup the inbound pipe, which will cause\n    //  the socket object to resend all the subscriptions.\n    if (_pipe\n        && (options.type == ZMQ_SUB || options.type == ZMQ_XSUB\n            || options.type == ZMQ_DISH))\n        _pipe->hiccup ();\n}\n\nvoid zmq::session_base_t::start_connecting (bool wait_)\n{\n    zmq_assert (_active);\n\n    //  Choose I/O thread to run connecter in. Given that we are already\n    //  running in an I/O thread, there must be at least one available.\n    io_thread_t *io_thread = choose_io_thread (options.affinity);\n    zmq_assert (io_thread);\n\n    //  Create the connecter object.\n    own_t *connecter = NULL;\n    if (_addr->protocol == protocol_name::tcp) {\n        if (!options.socks_proxy_address.empty ()) {\n            address_t *proxy_address = new (std::nothrow)\n              address_t (protocol_name::tcp, options.socks_proxy_address,\n                         this->get_ctx ());\n            alloc_assert (proxy_address);\n            connecter = new (std::nothrow) socks_connecter_t (\n              io_thread, this, options, _addr, proxy_address, wait_);\n            alloc_assert (connecter);\n            if (!options.socks_proxy_username.empty ()) {\n                reinterpret_cast<socks_connecter_t *> (connecter)\n                  ->set_auth_method_basic (options.socks_proxy_username,\n                                           options.socks_proxy_password);\n            }\n        } else {\n            connecter = new (std::nothrow)\n              tcp_connecter_t (io_thread, this, options, _addr, wait_);\n        }\n    }\n#if defined ZMQ_HAVE_IPC\n    else if (_addr->protocol == protocol_name::ipc) {\n        connecter = new (std::nothrow)\n          ipc_connecter_t (io_thread, this, options, _addr, wait_);\n    }\n#endif\n#if defined ZMQ_HAVE_TIPC\n    else if (_addr->protocol == protocol_name::tipc) {\n        connecter = new (std::nothrow)\n          tipc_connecter_t (io_thread, this, options, _addr, wait_);\n    }\n#endif\n#if defined ZMQ_HAVE_VMCI\n    else if (_addr->protocol == protocol_name::vmci) {\n        connecter = new (std::nothrow)\n          vmci_connecter_t (io_thread, this, options, _addr, wait_);\n    }\n#endif\n#if defined ZMQ_HAVE_WS\n    else if (_addr->protocol == protocol_name::ws) {\n        connecter = new (std::nothrow) ws_connecter_t (\n          io_thread, this, options, _addr, wait_, false, std::string ());\n    }\n#endif\n#if defined ZMQ_HAVE_WSS\n    else if (_addr->protocol == protocol_name::wss) {\n        connecter = new (std::nothrow) ws_connecter_t (\n          io_thread, this, options, _addr, wait_, true, _wss_hostname);\n    }\n#endif\n#if defined ZMQ_HAVE_VSOCK\n    else if (_addr->protocol == protocol_name::vsock) {\n        connecter = new (std::nothrow)\n          vsock_connecter_t (io_thread, this, options, _addr, wait_);\n    }\n#endif\n\n    if (connecter != NULL) {\n        alloc_assert (connecter);\n        launch_child (connecter);\n        return;\n    }\n\n    if (_addr->protocol == protocol_name::udp) {\n        zmq_assert (options.type == ZMQ_DISH || options.type == ZMQ_RADIO\n                    || options.type == ZMQ_DGRAM);\n\n        udp_engine_t *engine = new (std::nothrow) udp_engine_t (options);\n        alloc_assert (engine);\n\n        bool recv = false;\n        bool send = false;\n\n        if (options.type == ZMQ_RADIO) {\n            send = true;\n            recv = false;\n        } else if (options.type == ZMQ_DISH) {\n            send = false;\n            recv = true;\n        } else if (options.type == ZMQ_DGRAM) {\n            send = true;\n            recv = true;\n        }\n\n        int rc = engine->init (_addr, send, recv);\n        errno_assert (rc == 0);\n\n        send_attach (this, engine);\n\n        return;\n    }\n\n#ifdef ZMQ_HAVE_OPENPGM\n\n    //  Both PGM and EPGM transports are using the same infrastructure.\n    if (_addr->protocol == \"pgm\" || _addr->protocol == \"epgm\") {\n        zmq_assert (options.type == ZMQ_PUB || options.type == ZMQ_XPUB\n                    || options.type == ZMQ_SUB || options.type == ZMQ_XSUB);\n\n        //  For EPGM transport with UDP encapsulation of PGM is used.\n        bool const udp_encapsulation = _addr->protocol == \"epgm\";\n\n        //  At this point we'll create message pipes to the session straight\n        //  away. There's no point in delaying it as no concept of 'connect'\n        //  exists with PGM anyway.\n        if (options.type == ZMQ_PUB || options.type == ZMQ_XPUB) {\n            //  PGM sender.\n            pgm_sender_t *pgm_sender =\n              new (std::nothrow) pgm_sender_t (io_thread, options);\n            alloc_assert (pgm_sender);\n\n            int rc =\n              pgm_sender->init (udp_encapsulation, _addr->address.c_str ());\n            errno_assert (rc == 0);\n\n            send_attach (this, pgm_sender);\n        } else {\n            //  PGM receiver.\n            pgm_receiver_t *pgm_receiver =\n              new (std::nothrow) pgm_receiver_t (io_thread, options);\n            alloc_assert (pgm_receiver);\n\n            int rc =\n              pgm_receiver->init (udp_encapsulation, _addr->address.c_str ());\n            errno_assert (rc == 0);\n\n            send_attach (this, pgm_receiver);\n        }\n\n        return;\n    }\n#endif\n\n#ifdef ZMQ_HAVE_NORM\n    if (_addr->protocol == \"norm\") {\n        //  At this point we'll create message pipes to the session straight\n        //  away. There's no point in delaying it as no concept of 'connect'\n        //  exists with NORM anyway.\n        if (options.type == ZMQ_PUB || options.type == ZMQ_XPUB) {\n            //  NORM sender.\n            norm_engine_t *norm_sender =\n              new (std::nothrow) norm_engine_t (io_thread, options);\n            alloc_assert (norm_sender);\n\n            int rc = norm_sender->init (_addr->address.c_str (), true, false);\n            errno_assert (rc == 0);\n\n            send_attach (this, norm_sender);\n        } else { // ZMQ_SUB or ZMQ_XSUB\n\n            //  NORM receiver.\n            norm_engine_t *norm_receiver =\n              new (std::nothrow) norm_engine_t (io_thread, options);\n            alloc_assert (norm_receiver);\n\n            int rc = norm_receiver->init (_addr->address.c_str (), false, true);\n            errno_assert (rc == 0);\n\n            send_attach (this, norm_receiver);\n        }\n        return;\n    }\n#endif // ZMQ_HAVE_NORM\n\n    zmq_assert (false);\n}\n\nzmq::hello_msg_session_t::hello_msg_session_t (io_thread_t *io_thread_,\n                                               bool connect_,\n                                               socket_base_t *socket_,\n                                               const options_t &options_,\n                                               address_t *addr_) :\n    session_base_t (io_thread_, connect_, socket_, options_, addr_),\n    _new_pipe (true)\n{\n}\n\nzmq::hello_msg_session_t::~hello_msg_session_t ()\n{\n}\n\n\nint zmq::hello_msg_session_t::pull_msg (msg_t *msg_)\n{\n    if (_new_pipe) {\n        _new_pipe = false;\n\n        const int rc =\n          msg_->init_buffer (&options.hello_msg[0], options.hello_msg.size ());\n        errno_assert (rc == 0);\n\n        return 0;\n    }\n\n    return session_base_t::pull_msg (msg_);\n}\n\nvoid zmq::hello_msg_session_t::reset ()\n{\n    session_base_t::reset ();\n    _new_pipe = true;\n}\n"
  },
  {
    "path": "src/session_base.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SESSION_BASE_HPP_INCLUDED__\n#define __ZMQ_SESSION_BASE_HPP_INCLUDED__\n\n#include <stdarg.h>\n\n#include \"own.hpp\"\n#include \"io_object.hpp\"\n#include \"pipe.hpp\"\n#include \"socket_base.hpp\"\n#include \"i_engine.hpp\"\n#include \"msg.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\nstruct i_engine;\nstruct address_t;\n\nclass session_base_t : public own_t, public io_object_t, public i_pipe_events\n{\n  public:\n    //  Create a session of the particular type.\n    static session_base_t *create (zmq::io_thread_t *io_thread_,\n                                   bool active_,\n                                   zmq::socket_base_t *socket_,\n                                   const options_t &options_,\n                                   address_t *addr_);\n\n    //  To be used once only, when creating the session.\n    void attach_pipe (zmq::pipe_t *pipe_);\n\n    //  Following functions are the interface exposed towards the engine.\n    virtual void reset ();\n    void flush ();\n    void rollback ();\n    void engine_error (bool handshaked_, zmq::i_engine::error_reason_t reason_);\n    void engine_ready ();\n\n    //  i_pipe_events interface implementation.\n    void read_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    void write_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    void hiccuped (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    void pipe_terminated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n\n    //  Delivers a message. Returns 0 if successful; -1 otherwise.\n    //  The function takes ownership of the message.\n    virtual int push_msg (msg_t *msg_);\n\n    int zap_connect ();\n    bool zap_enabled () const;\n\n    //  Fetches a message. Returns 0 if successful; -1 otherwise.\n    //  The caller is responsible for freeing the message when no\n    //  longer used.\n    virtual int pull_msg (msg_t *msg_);\n\n    //  Receives message from ZAP socket.\n    //  Returns 0 on success; -1 otherwise.\n    //  The caller is responsible for freeing the message.\n    int read_zap_msg (msg_t *msg_);\n\n    //  Sends message to ZAP socket.\n    //  Returns 0 on success; -1 otherwise.\n    //  The function takes ownership of the message.\n    int write_zap_msg (msg_t *msg_);\n\n    socket_base_t *get_socket () const;\n    const endpoint_uri_pair_t &get_endpoint () const;\n\n  protected:\n    session_base_t (zmq::io_thread_t *io_thread_,\n                    bool active_,\n                    zmq::socket_base_t *socket_,\n                    const options_t &options_,\n                    address_t *addr_);\n    ~session_base_t () ZMQ_OVERRIDE;\n\n  private:\n    void start_connecting (bool wait_);\n\n    void reconnect ();\n\n    //  Handlers for incoming commands.\n    void process_plug () ZMQ_FINAL;\n    void process_attach (zmq::i_engine *engine_) ZMQ_FINAL;\n    void process_term (int linger_) ZMQ_FINAL;\n    void process_conn_failed () ZMQ_OVERRIDE;\n\n    //  i_poll_events handlers.\n    void timer_event (int id_) ZMQ_FINAL;\n\n    //  Remove any half processed messages. Flush unflushed messages.\n    //  Call this function when engine disconnect to get rid of leftovers.\n    void clean_pipes ();\n\n    //  If true, this session (re)connects to the peer. Otherwise, it's\n    //  a transient session created by the listener.\n    const bool _active;\n\n    //  Pipe connecting the session to its socket.\n    zmq::pipe_t *_pipe;\n\n    //  Pipe used to exchange messages with ZAP socket.\n    zmq::pipe_t *_zap_pipe;\n\n    //  This set is added to with pipes we are disconnecting, but haven't yet completed\n    std::set<pipe_t *> _terminating_pipes;\n\n    //  This flag is true if the remainder of the message being processed\n    //  is still in the in pipe.\n    bool _incomplete_in;\n\n    //  True if termination have been suspended to push the pending\n    //  messages to the network.\n    bool _pending;\n\n    //  The protocol I/O engine connected to the session.\n    zmq::i_engine *_engine;\n\n    //  The socket the session belongs to.\n    zmq::socket_base_t *_socket;\n\n    //  I/O thread the session is living in. It will be used to plug in\n    //  the engines into the same thread.\n    zmq::io_thread_t *_io_thread;\n\n    //  ID of the linger timer\n    enum\n    {\n        linger_timer_id = 0x20\n    };\n\n    //  True is linger timer is running.\n    bool _has_linger_timer;\n\n    //  Protocol and address to use when connecting.\n    address_t *_addr;\n\n#ifdef ZMQ_HAVE_WSS\n    //  TLS handshake, we need to take a copy when the session is created,\n    //  in order to maintain the value at the creation time\n    const std::string _wss_hostname;\n#endif\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (session_base_t)\n};\n\nclass hello_msg_session_t ZMQ_FINAL : public session_base_t\n{\n  public:\n    hello_msg_session_t (zmq::io_thread_t *io_thread_,\n                         bool connect_,\n                         zmq::socket_base_t *socket_,\n                         const options_t &options_,\n                         address_t *addr_);\n    ~hello_msg_session_t ();\n\n    //  Overrides of the functions from session_base_t.\n    int pull_msg (msg_t *msg_);\n    void reset ();\n\n  private:\n    bool _new_pipe;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (hello_msg_session_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/signaler.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"poller.hpp\"\n#include \"polling_util.hpp\"\n\n#if defined ZMQ_POLL_BASED_ON_POLL\n#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_AIX\n#include <poll.h>\n#endif\n#elif defined ZMQ_POLL_BASED_ON_SELECT\n#if defined ZMQ_HAVE_WINDOWS\n#elif defined ZMQ_HAVE_HPUX\n#include <sys/param.h>\n#include <sys/types.h>\n#include <sys/time.h>\n#elif defined ZMQ_HAVE_OPENVMS\n#include <sys/types.h>\n#include <sys/time.h>\n#elif defined ZMQ_HAVE_VXWORKS\n#include <sys/types.h>\n#include <sys/time.h>\n#include <sockLib.h>\n#include <strings.h>\n#else\n#include <sys/select.h>\n#endif\n#endif\n\n#include \"signaler.hpp\"\n#include \"likely.hpp\"\n#include \"stdint.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"fd.hpp\"\n#include \"ip.hpp\"\n#include \"tcp.hpp\"\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#include <netinet/tcp.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#endif\n\n#if !defined(ZMQ_HAVE_WINDOWS)\n// Helper to sleep for specific number of milliseconds (or until signal)\n//\nstatic int sleep_ms (unsigned int ms_)\n{\n    if (ms_ == 0)\n        return 0;\n#if defined ZMQ_HAVE_ANDROID\n    usleep (ms_ * 1000);\n    return 0;\n#elif defined ZMQ_HAVE_VXWORKS\n    struct timespec ns_;\n    ns_.tv_sec = ms_ / 1000;\n    ns_.tv_nsec = ms_ % 1000 * 1000000;\n    return nanosleep (&ns_, 0);\n#else\n    return usleep (ms_ * 1000);\n#endif\n}\n\n// Helper to wait on close(), for non-blocking sockets, until it completes\n// If EAGAIN is received, will sleep briefly (1-100ms) then try again, until\n// the overall timeout is reached.\n//\nstatic int close_wait_ms (int fd_, unsigned int max_ms_ = 2000)\n{\n    unsigned int ms_so_far = 0;\n    const unsigned int min_step_ms = 1;\n    const unsigned int max_step_ms = 100;\n    const unsigned int step_ms =\n      std::min (std::max (min_step_ms, max_ms_ / 10), max_step_ms);\n\n    int rc = 0; // do not sleep on first attempt\n    do {\n        if (rc == -1 && errno == EAGAIN) {\n            sleep_ms (step_ms);\n            ms_so_far += step_ms;\n        }\n        rc = close (fd_);\n    } while (ms_so_far < max_ms_ && rc == -1 && errno == EAGAIN);\n\n    return rc;\n}\n#endif\n\nzmq::signaler_t::signaler_t ()\n{\n    //  Create the socketpair for signaling.\n    if (make_fdpair (&_r, &_w) == 0) {\n        unblock_socket (_w);\n        unblock_socket (_r);\n    }\n#ifdef HAVE_FORK\n    pid = getpid ();\n#endif\n}\n\n// This might get run after some part of construction failed, leaving one or\n// both of _r and _w retired_fd.\nzmq::signaler_t::~signaler_t ()\n{\n#if defined ZMQ_HAVE_EVENTFD\n    if (_r == retired_fd)\n        return;\n    int rc = close_wait_ms (_r);\n    errno_assert (rc == 0);\n#elif defined ZMQ_HAVE_WINDOWS\n    if (_w != retired_fd) {\n        const struct linger so_linger = {1, 0};\n        int rc = setsockopt (_w, SOL_SOCKET, SO_LINGER,\n                             reinterpret_cast<const char *> (&so_linger),\n                             sizeof so_linger);\n        //  Only check shutdown if WSASTARTUP was previously done\n        if (rc == 0 || WSAGetLastError () != WSANOTINITIALISED) {\n            wsa_assert (rc != SOCKET_ERROR);\n            rc = closesocket (_w);\n            wsa_assert (rc != SOCKET_ERROR);\n            if (_r == retired_fd)\n                return;\n            rc = closesocket (_r);\n            wsa_assert (rc != SOCKET_ERROR);\n        }\n    }\n#else\n    if (_w != retired_fd) {\n        int rc = close_wait_ms (_w);\n        errno_assert (rc == 0);\n    }\n    if (_r != retired_fd) {\n        int rc = close_wait_ms (_r);\n        errno_assert (rc == 0);\n    }\n#endif\n}\n\nzmq::fd_t zmq::signaler_t::get_fd () const\n{\n    return _r;\n}\n\nvoid zmq::signaler_t::send ()\n{\n#if defined HAVE_FORK\n    if (unlikely (pid != getpid ())) {\n        //printf(\"Child process %d signaler_t::send returning without sending #1\\n\", getpid());\n        return; // do not send anything in forked child context\n    }\n#endif\n#if defined ZMQ_HAVE_EVENTFD\n    const uint64_t inc = 1;\n    ssize_t sz = write (_w, &inc, sizeof (inc));\n    errno_assert (sz == sizeof (inc));\n#elif defined ZMQ_HAVE_WINDOWS\n    const char dummy = 0;\n    int nbytes;\n    do {\n        nbytes = ::send (_w, &dummy, sizeof (dummy), 0);\n        wsa_assert (nbytes != SOCKET_ERROR);\n        // wsa_assert does not abort on WSAEWOULDBLOCK. If we get this, we retry.\n    } while (nbytes == SOCKET_ERROR);\n    // Given the small size of dummy (should be 1) expect that send was able to send everything.\n    zmq_assert (nbytes == sizeof (dummy));\n#elif defined ZMQ_HAVE_VXWORKS\n    unsigned char dummy = 0;\n    while (true) {\n        ssize_t nbytes = ::send (_w, (char *) &dummy, sizeof (dummy), 0);\n        if (unlikely (nbytes == -1 && errno == EINTR))\n            continue;\n#if defined(HAVE_FORK)\n        if (unlikely (pid != getpid ())) {\n            //printf(\"Child process %d signaler_t::send returning without sending #2\\n\", getpid());\n            errno = EINTR;\n            break;\n        }\n#endif\n        zmq_assert (nbytes == sizeof dummy);\n        break;\n    }\n#else\n    unsigned char dummy = 0;\n    while (true) {\n        ssize_t nbytes = ::send (_w, &dummy, sizeof (dummy), 0);\n        if (unlikely (nbytes == -1 && errno == EINTR))\n            continue;\n#if defined(HAVE_FORK)\n        if (unlikely (pid != getpid ())) {\n            //printf(\"Child process %d signaler_t::send returning without sending #2\\n\", getpid());\n            errno = EINTR;\n            break;\n        }\n#endif\n        zmq_assert (nbytes == sizeof dummy);\n        break;\n    }\n#endif\n}\n\nint zmq::signaler_t::wait (int timeout_) const\n{\n#ifdef HAVE_FORK\n    if (unlikely (pid != getpid ())) {\n        // we have forked and the file descriptor is closed. Emulate an interrupt\n        // response.\n        //printf(\"Child process %d signaler_t::wait returning simulating interrupt #1\\n\", getpid());\n        errno = EINTR;\n        return -1;\n    }\n#endif\n\n#ifdef ZMQ_POLL_BASED_ON_POLL\n    struct pollfd pfd;\n    pfd.fd = _r;\n    pfd.events = POLLIN;\n    const int rc = poll (&pfd, 1, timeout_);\n    if (unlikely (rc < 0)) {\n        errno_assert (errno == EINTR);\n        return -1;\n    }\n    if (unlikely (rc == 0)) {\n        errno = EAGAIN;\n        return -1;\n    }\n#ifdef HAVE_FORK\n    if (unlikely (pid != getpid ())) {\n        // we have forked and the file descriptor is closed. Emulate an interrupt\n        // response.\n        //printf(\"Child process %d signaler_t::wait returning simulating interrupt #2\\n\", getpid());\n        errno = EINTR;\n        return -1;\n    }\n#endif\n    zmq_assert (rc == 1);\n    zmq_assert (pfd.revents & POLLIN);\n    return 0;\n\n#elif defined ZMQ_POLL_BASED_ON_SELECT\n\n    optimized_fd_set_t fds (1);\n    FD_ZERO (fds.get ());\n    FD_SET (_r, fds.get ());\n    struct timeval timeout;\n    if (timeout_ >= 0) {\n        timeout.tv_sec = timeout_ / 1000;\n        timeout.tv_usec = timeout_ % 1000 * 1000;\n    }\n#ifdef ZMQ_HAVE_WINDOWS\n    int rc =\n      select (0, fds.get (), NULL, NULL, timeout_ >= 0 ? &timeout : NULL);\n    wsa_assert (rc != SOCKET_ERROR);\n#else\n    int rc =\n      select (_r + 1, fds.get (), NULL, NULL, timeout_ >= 0 ? &timeout : NULL);\n    if (unlikely (rc < 0)) {\n        errno_assert (errno == EINTR);\n        return -1;\n    }\n#endif\n    if (unlikely (rc == 0)) {\n        errno = EAGAIN;\n        return -1;\n    }\n    zmq_assert (rc == 1);\n    return 0;\n\n#else\n#error\n#endif\n}\n\nvoid zmq::signaler_t::recv ()\n{\n//  Attempt to read a signal.\n#if defined ZMQ_HAVE_EVENTFD\n    uint64_t dummy;\n    ssize_t sz = read (_r, &dummy, sizeof (dummy));\n    errno_assert (sz == sizeof (dummy));\n\n    //  If we accidentally grabbed the next signal(s) along with the current\n    //  one, return it back to the eventfd object.\n    if (unlikely (dummy > 1)) {\n        const uint64_t inc = dummy - 1;\n        ssize_t sz2 = write (_w, &inc, sizeof (inc));\n        errno_assert (sz2 == sizeof (inc));\n        return;\n    }\n\n    zmq_assert (dummy == 1);\n#else\n    unsigned char dummy;\n#if defined ZMQ_HAVE_WINDOWS\n    const int nbytes =\n      ::recv (_r, reinterpret_cast<char *> (&dummy), sizeof (dummy), 0);\n    wsa_assert (nbytes != SOCKET_ERROR);\n#elif defined ZMQ_HAVE_VXWORKS\n    ssize_t nbytes = ::recv (_r, (char *) &dummy, sizeof (dummy), 0);\n    errno_assert (nbytes >= 0);\n#else\n    ssize_t nbytes = ::recv (_r, &dummy, sizeof (dummy), 0);\n    errno_assert (nbytes >= 0);\n#endif\n    zmq_assert (nbytes == sizeof (dummy));\n    zmq_assert (dummy == 0);\n#endif\n}\n\nint zmq::signaler_t::recv_failable ()\n{\n//  Attempt to read a signal.\n#if defined ZMQ_HAVE_EVENTFD\n    uint64_t dummy;\n    ssize_t sz = read (_r, &dummy, sizeof (dummy));\n    if (sz == -1) {\n        errno_assert (errno == EAGAIN);\n        return -1;\n    }\n    errno_assert (sz == sizeof (dummy));\n\n    //  If we accidentally grabbed the next signal(s) along with the current\n    //  one, return it back to the eventfd object.\n    if (unlikely (dummy > 1)) {\n        const uint64_t inc = dummy - 1;\n        ssize_t sz2 = write (_w, &inc, sizeof (inc));\n        errno_assert (sz2 == sizeof (inc));\n        return 0;\n    }\n\n    zmq_assert (dummy == 1);\n\n#else\n    unsigned char dummy;\n#if defined ZMQ_HAVE_WINDOWS\n    const int nbytes =\n      ::recv (_r, reinterpret_cast<char *> (&dummy), sizeof (dummy), 0);\n    if (nbytes == SOCKET_ERROR) {\n        const int last_error = WSAGetLastError ();\n        if (last_error == WSAEWOULDBLOCK) {\n            errno = EAGAIN;\n            return -1;\n        }\n        wsa_assert (last_error == WSAEWOULDBLOCK);\n    }\n#elif defined ZMQ_HAVE_VXWORKS\n    ssize_t nbytes = ::recv (_r, (char *) &dummy, sizeof (dummy), 0);\n    if (nbytes == -1) {\n        if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {\n            errno = EAGAIN;\n            return -1;\n        }\n        errno_assert (errno == EAGAIN || errno == EWOULDBLOCK\n                      || errno == EINTR);\n    }\n#else\n    ssize_t nbytes = ::recv (_r, &dummy, sizeof (dummy), 0);\n    if (nbytes == -1) {\n        if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {\n            errno = EAGAIN;\n            return -1;\n        }\n        errno_assert (errno == EAGAIN || errno == EWOULDBLOCK\n                      || errno == EINTR);\n    }\n#endif\n    zmq_assert (nbytes == sizeof (dummy));\n    zmq_assert (dummy == 0);\n#endif\n    return 0;\n}\n\nbool zmq::signaler_t::valid () const\n{\n    return _w != retired_fd;\n}\n\n#ifdef HAVE_FORK\nvoid zmq::signaler_t::forked ()\n{\n    //  Close file descriptors created in the parent and create new pair\n    close (_r);\n    close (_w);\n    make_fdpair (&_r, &_w);\n}\n#endif\n"
  },
  {
    "path": "src/signaler.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SIGNALER_HPP_INCLUDED__\n#define __ZMQ_SIGNALER_HPP_INCLUDED__\n\n#ifdef HAVE_FORK\n#include <unistd.h>\n#endif\n\n#include \"fd.hpp\"\n#include \"macros.hpp\"\n\nnamespace zmq\n{\n//  This is a cross-platform equivalent to signal_fd. However, as opposed\n//  to signal_fd there can be at most one signal in the signaler at any\n//  given moment. Attempt to send a signal before receiving the previous\n//  one will result in undefined behaviour.\n\nclass signaler_t\n{\n  public:\n    signaler_t ();\n    ~signaler_t ();\n\n    // Returns the socket/file descriptor\n    // May return retired_fd if the signaler could not be initialized.\n    fd_t get_fd () const;\n    void send ();\n    int wait (int timeout_) const;\n    void recv ();\n    int recv_failable ();\n\n    bool valid () const;\n\n#ifdef HAVE_FORK\n    // close the file descriptors in a forked child process so that they\n    // do not interfere with the context in the parent process.\n    void forked ();\n#endif\n\n  private:\n    //  Underlying write & read file descriptor\n    //  Will be -1 if an error occurred during initialization, e.g. we\n    //  exceeded the number of available handles\n    fd_t _w;\n    fd_t _r;\n\n#ifdef HAVE_FORK\n    // the process that created this context. Used to detect forking.\n    pid_t pid;\n    // idempotent close of file descriptors that is safe to use by destructor\n    // and forked().\n    void close_internal ();\n#endif\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (signaler_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/socket_base.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <new>\n#include <string>\n#include <algorithm>\n#include <limits>\n\n#include \"macros.hpp\"\n\n#if defined ZMQ_HAVE_WINDOWS\n#if defined _MSC_VER\n#if defined _WIN32_WCE\n#include <cmnintrin.h>\n#else\n#include <intrin.h>\n#endif\n#endif\n#else\n#include <unistd.h>\n#include <ctype.h>\n#endif\n\n#include \"socket_base.hpp\"\n#include \"tcp_listener.hpp\"\n#include \"ws_listener.hpp\"\n#include \"ipc_listener.hpp\"\n#include \"tipc_listener.hpp\"\n#include \"tcp_connecter.hpp\"\n#ifdef ZMQ_HAVE_WS\n#include \"ws_address.hpp\"\n#endif\n#include \"io_thread.hpp\"\n#include \"session_base.hpp\"\n#include \"config.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n#include \"ctx.hpp\"\n#include \"likely.hpp\"\n#include \"msg.hpp\"\n#include \"address.hpp\"\n#include \"ipc_address.hpp\"\n#include \"tcp_address.hpp\"\n#include \"udp_address.hpp\"\n#include \"tipc_address.hpp\"\n#include \"mailbox.hpp\"\n#include \"mailbox_safe.hpp\"\n\n#ifdef ZMQ_HAVE_WSS\n#include \"wss_address.hpp\"\n#endif\n\n#if defined ZMQ_HAVE_VSOCK\n// fix header conflict with VMCI\n#define sockaddr_vm linux_sockaddr_vm\n#define VMADDR_PORT_ANY LINUX_VMADDR_PORT_ANY\n#define VMADDR_CID_ANY LINUX_VMADDR_CID_ANY\n#include \"vsock_address.hpp\"\n#include \"vsock_listener.hpp\"\n#undef sockaddr_vm\n#undef VMADDR_CID_ANY\n#undef VMADDR_PORT_ANY\n#endif\n\n#if defined ZMQ_HAVE_VMCI\n#include \"vmci_address.hpp\"\n#include \"vmci_listener.hpp\"\n#endif\n\n\n#ifdef ZMQ_HAVE_OPENPGM\n#include \"pgm_socket.hpp\"\n#endif\n\n#include \"pair.hpp\"\n#include \"pub.hpp\"\n#include \"sub.hpp\"\n#include \"req.hpp\"\n#include \"rep.hpp\"\n#include \"pull.hpp\"\n#include \"push.hpp\"\n#include \"dealer.hpp\"\n#include \"router.hpp\"\n#include \"xpub.hpp\"\n#include \"xsub.hpp\"\n#include \"stream.hpp\"\n#include \"server.hpp\"\n#include \"client.hpp\"\n#include \"radio.hpp\"\n#include \"dish.hpp\"\n#include \"gather.hpp\"\n#include \"scatter.hpp\"\n#include \"dgram.hpp\"\n#include \"peer.hpp\"\n#include \"channel.hpp\"\n\nvoid zmq::socket_base_t::inprocs_t::emplace (const char *endpoint_uri_,\n                                             pipe_t *pipe_)\n{\n    _inprocs.ZMQ_MAP_INSERT_OR_EMPLACE (std::string (endpoint_uri_), pipe_);\n}\n\nint zmq::socket_base_t::inprocs_t::erase_pipes (\n  const std::string &endpoint_uri_str_)\n{\n    const std::pair<map_t::iterator, map_t::iterator> range =\n      _inprocs.equal_range (endpoint_uri_str_);\n    if (range.first == range.second) {\n        errno = ENOENT;\n        return -1;\n    }\n\n    for (map_t::iterator it = range.first; it != range.second; ++it) {\n        it->second->send_disconnect_msg ();\n        it->second->terminate (true);\n    }\n    _inprocs.erase (range.first, range.second);\n    return 0;\n}\n\nvoid zmq::socket_base_t::inprocs_t::erase_pipe (const pipe_t *pipe_)\n{\n    for (map_t::iterator it = _inprocs.begin (), end = _inprocs.end ();\n         it != end; ++it)\n        if (it->second == pipe_) {\n            _inprocs.erase (it);\n            break;\n        }\n}\n\nbool zmq::socket_base_t::check_tag () const\n{\n    return _tag == 0xbaddecaf;\n}\n\nbool zmq::socket_base_t::is_thread_safe () const\n{\n    return _thread_safe;\n}\n\nzmq::socket_base_t *zmq::socket_base_t::create (int type_,\n                                                class ctx_t *parent_,\n                                                uint32_t tid_,\n                                                int sid_)\n{\n    socket_base_t *s = NULL;\n    switch (type_) {\n        case ZMQ_PAIR:\n            s = new (std::nothrow) pair_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_PUB:\n            s = new (std::nothrow) pub_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_SUB:\n            s = new (std::nothrow) sub_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_REQ:\n            s = new (std::nothrow) req_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_REP:\n            s = new (std::nothrow) rep_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_DEALER:\n            s = new (std::nothrow) dealer_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_ROUTER:\n            s = new (std::nothrow) router_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_PULL:\n            s = new (std::nothrow) pull_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_PUSH:\n            s = new (std::nothrow) push_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_XPUB:\n            s = new (std::nothrow) xpub_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_XSUB:\n            s = new (std::nothrow) xsub_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_STREAM:\n            s = new (std::nothrow) stream_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_SERVER:\n            s = new (std::nothrow) server_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_CLIENT:\n            s = new (std::nothrow) client_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_RADIO:\n            s = new (std::nothrow) radio_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_DISH:\n            s = new (std::nothrow) dish_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_GATHER:\n            s = new (std::nothrow) gather_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_SCATTER:\n            s = new (std::nothrow) scatter_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_DGRAM:\n            s = new (std::nothrow) dgram_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_PEER:\n            s = new (std::nothrow) peer_t (parent_, tid_, sid_);\n            break;\n        case ZMQ_CHANNEL:\n            s = new (std::nothrow) channel_t (parent_, tid_, sid_);\n            break;\n        default:\n            errno = EINVAL;\n            return NULL;\n    }\n\n    alloc_assert (s);\n\n    if (s->_mailbox == NULL) {\n        s->_destroyed = true;\n        LIBZMQ_DELETE (s);\n        return NULL;\n    }\n\n    return s;\n}\n\nzmq::socket_base_t::socket_base_t (ctx_t *parent_,\n                                   uint32_t tid_,\n                                   int sid_,\n                                   bool thread_safe_) :\n    own_t (parent_, tid_),\n    _sync (),\n    _tag (0xbaddecaf),\n    _ctx_terminated (false),\n    _destroyed (false),\n    _poller (NULL),\n    _handle (static_cast<poller_t::handle_t> (NULL)),\n    _last_tsc (0),\n    _ticks (0),\n    _rcvmore (false),\n    _monitor_socket (NULL),\n    _monitor_events (0),\n    _thread_safe (thread_safe_),\n    _reaper_signaler (NULL),\n    _monitor_sync (),\n    _disconnected (false)\n{\n    options.socket_id = sid_;\n    options.ipv6 = (parent_->get (ZMQ_IPV6) != 0);\n    options.linger.store (parent_->get (ZMQ_BLOCKY) ? -1 : 0);\n    options.zero_copy = parent_->get (ZMQ_ZERO_COPY_RECV) != 0;\n\n    if (_thread_safe) {\n        _mailbox = new (std::nothrow) mailbox_safe_t (&_sync);\n        zmq_assert (_mailbox);\n    } else {\n        mailbox_t *m = new (std::nothrow) mailbox_t ();\n        zmq_assert (m);\n\n        if (m->get_fd () != retired_fd)\n            _mailbox = m;\n        else {\n            LIBZMQ_DELETE (m);\n            _mailbox = NULL;\n        }\n    }\n}\n\nint zmq::socket_base_t::get_peer_state (const void *routing_id_,\n                                        size_t routing_id_size_) const\n{\n    LIBZMQ_UNUSED (routing_id_);\n    LIBZMQ_UNUSED (routing_id_size_);\n\n    //  Only ROUTER sockets support this\n    errno = ENOTSUP;\n    return -1;\n}\n\nzmq::socket_base_t::~socket_base_t ()\n{\n    if (_mailbox)\n        LIBZMQ_DELETE (_mailbox);\n\n    if (_reaper_signaler)\n        LIBZMQ_DELETE (_reaper_signaler);\n\n    scoped_lock_t lock (_monitor_sync);\n    stop_monitor ();\n\n    zmq_assert (_destroyed);\n}\n\nzmq::i_mailbox *zmq::socket_base_t::get_mailbox () const\n{\n    return _mailbox;\n}\n\nvoid zmq::socket_base_t::stop ()\n{\n    //  Called by ctx when it is terminated (zmq_ctx_term).\n    //  'stop' command is sent from the threads that called zmq_ctx_term to\n    //  the thread owning the socket. This way, blocking call in the\n    //  owner thread can be interrupted.\n    send_stop ();\n}\n\n// TODO consider renaming protocol_ to scheme_ in conformance with RFC 3986\n// terminology, but this requires extensive changes to be consistent\nint zmq::socket_base_t::parse_uri (const char *uri_,\n                                   std::string &protocol_,\n                                   std::string &path_)\n{\n    zmq_assert (uri_ != NULL);\n\n    const std::string uri (uri_);\n    const std::string::size_type pos = uri.find (\"://\");\n    if (pos == std::string::npos) {\n        errno = EINVAL;\n        return -1;\n    }\n    protocol_ = uri.substr (0, pos);\n    path_ = uri.substr (pos + 3);\n\n    if (protocol_.empty () || path_.empty ()) {\n        errno = EINVAL;\n        return -1;\n    }\n    return 0;\n}\n\nint zmq::socket_base_t::check_protocol (const std::string &protocol_) const\n{\n    //  First check out whether the protocol is something we are aware of.\n    if (protocol_ != protocol_name::inproc\n#if defined ZMQ_HAVE_IPC\n        && protocol_ != protocol_name::ipc\n#endif\n        && protocol_ != protocol_name::tcp\n#ifdef ZMQ_HAVE_WS\n        && protocol_ != protocol_name::ws\n#endif\n#ifdef ZMQ_HAVE_WSS\n        && protocol_ != protocol_name::wss\n#endif\n#if defined ZMQ_HAVE_OPENPGM\n        //  pgm/epgm transports only available if 0MQ is compiled with OpenPGM.\n        && protocol_ != protocol_name::pgm\n        && protocol_ != protocol_name::epgm\n#endif\n#if defined ZMQ_HAVE_TIPC\n        // TIPC transport is only available on Linux.\n        && protocol_ != protocol_name::tipc\n#endif\n#if defined ZMQ_HAVE_NORM\n        && protocol_ != protocol_name::norm\n#endif\n#if defined ZMQ_HAVE_VMCI\n        && protocol_ != protocol_name::vmci\n#endif\n#if defined ZMQ_HAVE_VSOCK\n        && protocol_ != protocol_name::vsock\n#endif\n        && protocol_ != protocol_name::udp) {\n        errno = EPROTONOSUPPORT;\n        return -1;\n    }\n\n    //  Check whether socket type and transport protocol match.\n    //  Specifically, multicast protocols can't be combined with\n    //  bi-directional messaging patterns (socket types).\n#if defined ZMQ_HAVE_OPENPGM || defined ZMQ_HAVE_NORM\n#if defined ZMQ_HAVE_OPENPGM && defined ZMQ_HAVE_NORM\n    if ((protocol_ == protocol_name::pgm || protocol_ == protocol_name::epgm\n         || protocol_ == protocol_name::norm)\n#elif defined ZMQ_HAVE_OPENPGM\n    if ((protocol_ == protocol_name::pgm || protocol_ == protocol_name::epgm)\n#else // defined ZMQ_HAVE_NORM\n    if (protocol_ == protocol_name::norm\n#endif\n        && options.type != ZMQ_PUB && options.type != ZMQ_SUB\n        && options.type != ZMQ_XPUB && options.type != ZMQ_XSUB) {\n        errno = ENOCOMPATPROTO;\n        return -1;\n    }\n#endif\n\n    if (protocol_ == protocol_name::udp\n        && (options.type != ZMQ_DISH && options.type != ZMQ_RADIO\n            && options.type != ZMQ_DGRAM)) {\n        errno = ENOCOMPATPROTO;\n        return -1;\n    }\n\n    //  Protocol is available.\n    return 0;\n}\n\nvoid zmq::socket_base_t::attach_pipe (pipe_t *pipe_,\n                                      bool subscribe_to_all_,\n                                      bool locally_initiated_)\n{\n    //  First, register the pipe so that we can terminate it later on.\n    pipe_->set_event_sink (this);\n    _pipes.push_back (pipe_);\n\n    //  Let the derived socket type know about new pipe.\n    xattach_pipe (pipe_, subscribe_to_all_, locally_initiated_);\n\n    //  If the socket is already being closed, ask any new pipes to terminate\n    //  straight away.\n    if (is_terminating ()) {\n        register_term_acks (1);\n        pipe_->terminate (false);\n    }\n}\n\nint zmq::socket_base_t::setsockopt (int option_,\n                                    const void *optval_,\n                                    size_t optvallen_)\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n    if (unlikely (_ctx_terminated)) {\n        errno = ETERM;\n        return -1;\n    }\n\n    //  First, check whether specific socket type overloads the option.\n    int rc = xsetsockopt (option_, optval_, optvallen_);\n    if (rc == 0 || errno != EINVAL) {\n        return rc;\n    }\n\n    //  If the socket type doesn't support the option, pass it to\n    //  the generic option parser.\n    rc = options.setsockopt (option_, optval_, optvallen_);\n    update_pipe_options (option_);\n\n    return rc;\n}\n\nint zmq::socket_base_t::getsockopt (int option_,\n                                    void *optval_,\n                                    size_t *optvallen_)\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n    if (unlikely (_ctx_terminated)) {\n        errno = ETERM;\n        return -1;\n    }\n\n    //  First, check whether specific socket type overloads the option.\n    int rc = xgetsockopt (option_, optval_, optvallen_);\n    if (rc == 0 || errno != EINVAL) {\n        return rc;\n    }\n\n    if (option_ == ZMQ_RCVMORE) {\n        return do_getsockopt<int> (optval_, optvallen_, _rcvmore ? 1 : 0);\n    }\n\n    if (option_ == ZMQ_FD) {\n        if (_thread_safe) {\n            // thread safe socket doesn't provide file descriptor\n            errno = EINVAL;\n            return -1;\n        }\n\n        return do_getsockopt<fd_t> (\n          optval_, optvallen_,\n          (static_cast<mailbox_t *> (_mailbox))->get_fd ());\n    }\n\n    if (option_ == ZMQ_EVENTS) {\n        const int rc = process_commands (0, false);\n        if (rc != 0 && (errno == EINTR || errno == ETERM)) {\n            return -1;\n        }\n        errno_assert (rc == 0);\n\n        return do_getsockopt<int> (optval_, optvallen_,\n                                   (has_out () ? ZMQ_POLLOUT : 0)\n                                     | (has_in () ? ZMQ_POLLIN : 0));\n    }\n\n    if (option_ == ZMQ_LAST_ENDPOINT) {\n        return do_getsockopt (optval_, optvallen_, _last_endpoint);\n    }\n\n    if (option_ == ZMQ_THREAD_SAFE) {\n        return do_getsockopt<int> (optval_, optvallen_, _thread_safe ? 1 : 0);\n    }\n\n    return options.getsockopt (option_, optval_, optvallen_);\n}\n\nint zmq::socket_base_t::join (const char *group_)\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n    return xjoin (group_);\n}\n\nint zmq::socket_base_t::leave (const char *group_)\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n    return xleave (group_);\n}\n\nint zmq::socket_base_t::disconnect_peer (uint32_t routing_id_)\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n    return xdisconnect_peer (routing_id_);\n}\n\nvoid zmq::socket_base_t::add_signaler (signaler_t *s_)\n{\n    zmq_assert (_thread_safe);\n\n    scoped_lock_t sync_lock (_sync);\n    (static_cast<mailbox_safe_t *> (_mailbox))->add_signaler (s_);\n}\n\nvoid zmq::socket_base_t::remove_signaler (signaler_t *s_)\n{\n    zmq_assert (_thread_safe);\n\n    scoped_lock_t sync_lock (_sync);\n    (static_cast<mailbox_safe_t *> (_mailbox))->remove_signaler (s_);\n}\n\nint zmq::socket_base_t::bind (const char *endpoint_uri_)\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n    if (unlikely (_ctx_terminated)) {\n        errno = ETERM;\n        return -1;\n    }\n\n    //  Process pending commands, if any.\n    int rc = process_commands (0, false);\n    if (unlikely (rc != 0)) {\n        return -1;\n    }\n\n    //  Parse endpoint_uri_ string.\n    std::string protocol;\n    std::string address;\n    if (parse_uri (endpoint_uri_, protocol, address)\n        || check_protocol (protocol)) {\n        return -1;\n    }\n\n    if (protocol == protocol_name::inproc) {\n        const endpoint_t endpoint = {this, options};\n        rc = register_endpoint (endpoint_uri_, endpoint);\n        if (rc == 0) {\n            connect_pending (endpoint_uri_, this);\n            _last_endpoint.assign (endpoint_uri_);\n            options.connected = true;\n        }\n        return rc;\n    }\n\n#if defined ZMQ_HAVE_OPENPGM || defined ZMQ_HAVE_NORM\n#if defined ZMQ_HAVE_OPENPGM && defined ZMQ_HAVE_NORM\n    if (protocol == protocol_name::pgm || protocol == protocol_name::epgm\n        || protocol == protocol_name::norm) {\n#elif defined ZMQ_HAVE_OPENPGM\n    if (protocol == protocol_name::pgm || protocol == protocol_name::epgm) {\n#else // defined ZMQ_HAVE_NORM\n    if (protocol == protocol_name::norm) {\n#endif\n        //  For convenience's sake, bind can be used interchangeable with\n        //  connect for PGM, EPGM, NORM transports.\n        rc = connect (endpoint_uri_);\n        if (rc != -1)\n            options.connected = true;\n        return rc;\n    }\n#endif\n\n    if (protocol == protocol_name::udp) {\n        if (!(options.type == ZMQ_DGRAM || options.type == ZMQ_DISH)) {\n            errno = ENOCOMPATPROTO;\n            return -1;\n        }\n\n        //  Choose the I/O thread to run the session in.\n        io_thread_t *io_thread = choose_io_thread (options.affinity);\n        if (!io_thread) {\n            errno = EMTHREAD;\n            return -1;\n        }\n\n        address_t *paddr =\n          new (std::nothrow) address_t (protocol, address, this->get_ctx ());\n        alloc_assert (paddr);\n\n        paddr->resolved.udp_addr = new (std::nothrow) udp_address_t ();\n        alloc_assert (paddr->resolved.udp_addr);\n        rc = paddr->resolved.udp_addr->resolve (address.c_str (), true,\n                                                options.ipv6);\n        if (rc != 0) {\n            LIBZMQ_DELETE (paddr);\n            return -1;\n        }\n\n        session_base_t *session =\n          session_base_t::create (io_thread, true, this, options, paddr);\n        errno_assert (session);\n\n        //  Create a bi-directional pipe.\n        object_t *parents[2] = {this, session};\n        pipe_t *new_pipes[2] = {NULL, NULL};\n\n        int hwms[2] = {options.sndhwm, options.rcvhwm};\n        bool conflates[2] = {false, false};\n        rc = pipepair (parents, new_pipes, hwms, conflates);\n        errno_assert (rc == 0);\n\n        //  Attach local end of the pipe to the socket object.\n        attach_pipe (new_pipes[0], true, true);\n        pipe_t *const newpipe = new_pipes[0];\n\n        //  Attach remote end of the pipe to the session object later on.\n        session->attach_pipe (new_pipes[1]);\n\n        //  Save last endpoint URI\n        paddr->to_string (_last_endpoint);\n\n        //  TODO shouldn't this use _last_endpoint instead of endpoint_uri_? as in the other cases\n        add_endpoint (endpoint_uri_pair_t (endpoint_uri_, std::string (),\n                                           endpoint_type_none),\n                      static_cast<own_t *> (session), newpipe);\n\n        return 0;\n    }\n\n    //  Remaining transports require to be run in an I/O thread, so at this\n    //  point we'll choose one.\n    io_thread_t *io_thread = choose_io_thread (options.affinity);\n    if (!io_thread) {\n        errno = EMTHREAD;\n        return -1;\n    }\n\n    if (protocol == protocol_name::tcp) {\n        tcp_listener_t *listener =\n          new (std::nothrow) tcp_listener_t (io_thread, this, options);\n        alloc_assert (listener);\n        rc = listener->set_local_address (address.c_str ());\n        if (rc != 0) {\n            LIBZMQ_DELETE (listener);\n            event_bind_failed (make_unconnected_bind_endpoint_pair (address),\n                               zmq_errno ());\n            return -1;\n        }\n\n        // Save last endpoint URI\n        listener->get_local_address (_last_endpoint);\n\n        add_endpoint (make_unconnected_bind_endpoint_pair (_last_endpoint),\n                      static_cast<own_t *> (listener), NULL);\n        options.connected = true;\n        return 0;\n    }\n\n#ifdef ZMQ_HAVE_WS\n#ifdef ZMQ_HAVE_WSS\n    if (protocol == protocol_name::ws || protocol == protocol_name::wss) {\n        ws_listener_t *listener = new (std::nothrow) ws_listener_t (\n          io_thread, this, options, protocol == protocol_name::wss);\n#else\n    if (protocol == protocol_name::ws) {\n        ws_listener_t *listener =\n          new (std::nothrow) ws_listener_t (io_thread, this, options, false);\n#endif\n        alloc_assert (listener);\n        rc = listener->set_local_address (address.c_str ());\n        if (rc != 0) {\n            LIBZMQ_DELETE (listener);\n            event_bind_failed (make_unconnected_bind_endpoint_pair (address),\n                               zmq_errno ());\n            return -1;\n        }\n\n        // Save last endpoint URI\n        listener->get_local_address (_last_endpoint);\n\n        add_endpoint (make_unconnected_bind_endpoint_pair (_last_endpoint),\n                      static_cast<own_t *> (listener), NULL);\n        options.connected = true;\n        return 0;\n    }\n#endif\n\n#if defined ZMQ_HAVE_IPC\n    if (protocol == protocol_name::ipc) {\n        ipc_listener_t *listener =\n          new (std::nothrow) ipc_listener_t (io_thread, this, options);\n        alloc_assert (listener);\n        int rc = listener->set_local_address (address.c_str ());\n        if (rc != 0) {\n            LIBZMQ_DELETE (listener);\n            event_bind_failed (make_unconnected_bind_endpoint_pair (address),\n                               zmq_errno ());\n            return -1;\n        }\n\n        // Save last endpoint URI\n        listener->get_local_address (_last_endpoint);\n\n        add_endpoint (make_unconnected_bind_endpoint_pair (_last_endpoint),\n                      static_cast<own_t *> (listener), NULL);\n        options.connected = true;\n        return 0;\n    }\n#endif\n#if defined ZMQ_HAVE_TIPC\n    if (protocol == protocol_name::tipc) {\n        tipc_listener_t *listener =\n          new (std::nothrow) tipc_listener_t (io_thread, this, options);\n        alloc_assert (listener);\n        int rc = listener->set_local_address (address.c_str ());\n        if (rc != 0) {\n            LIBZMQ_DELETE (listener);\n            event_bind_failed (make_unconnected_bind_endpoint_pair (address),\n                               zmq_errno ());\n            return -1;\n        }\n\n        // Save last endpoint URI\n        listener->get_local_address (_last_endpoint);\n\n        // TODO shouldn't this use _last_endpoint as in the other cases?\n        add_endpoint (make_unconnected_bind_endpoint_pair (endpoint_uri_),\n                      static_cast<own_t *> (listener), NULL);\n        options.connected = true;\n        return 0;\n    }\n#endif\n#if defined ZMQ_HAVE_VMCI\n    if (protocol == protocol_name::vmci) {\n        vmci_listener_t *listener =\n          new (std::nothrow) vmci_listener_t (io_thread, this, options);\n        alloc_assert (listener);\n        int rc = listener->set_local_address (address.c_str ());\n        if (rc != 0) {\n            LIBZMQ_DELETE (listener);\n            event_bind_failed (make_unconnected_bind_endpoint_pair (address),\n                               zmq_errno ());\n            return -1;\n        }\n\n        listener->get_local_address (_last_endpoint);\n\n        add_endpoint (make_unconnected_bind_endpoint_pair (_last_endpoint),\n                      static_cast<own_t *> (listener), NULL);\n        options.connected = true;\n        return 0;\n    }\n#endif\n\n#if defined ZMQ_HAVE_VSOCK\n    if (protocol == protocol_name::vsock) {\n        vsock_listener_t *listener =\n          new (std::nothrow) vsock_listener_t (io_thread, this, options);\n        alloc_assert (listener);\n        int rc = listener->set_local_address (address.c_str ());\n        if (rc != 0) {\n            LIBZMQ_DELETE (listener);\n            event_bind_failed (make_unconnected_bind_endpoint_pair (address),\n                               zmq_errno ());\n            return -1;\n        }\n\n        listener->get_local_address (_last_endpoint);\n\n        add_endpoint (make_unconnected_bind_endpoint_pair (_last_endpoint),\n                      static_cast<own_t *> (listener), NULL);\n        options.connected = true;\n        return 0;\n    }\n#endif\n\n    zmq_assert (false);\n    return -1;\n}\n\nint zmq::socket_base_t::connect (const char *endpoint_uri_)\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n    return connect_internal (endpoint_uri_);\n}\n\nint zmq::socket_base_t::connect_internal (const char *endpoint_uri_)\n{\n    if (unlikely (_ctx_terminated)) {\n        errno = ETERM;\n        return -1;\n    }\n\n    //  Process pending commands, if any.\n    int rc = process_commands (0, false);\n    if (unlikely (rc != 0)) {\n        return -1;\n    }\n\n    //  Parse endpoint_uri_ string.\n    std::string protocol;\n    std::string address;\n    if (parse_uri (endpoint_uri_, protocol, address)\n        || check_protocol (protocol)) {\n        return -1;\n    }\n\n    if (protocol == protocol_name::inproc) {\n        //  TODO: inproc connect is specific with respect to creating pipes\n        //  as there's no 'reconnect' functionality implemented. Once that\n        //  is in place we should follow generic pipe creation algorithm.\n\n        //  Find the peer endpoint.\n        const endpoint_t peer = find_endpoint (endpoint_uri_);\n\n        // The total HWM for an inproc connection should be the sum of\n        // the binder's HWM and the connector's HWM.\n        const int sndhwm = peer.socket == NULL ? options.sndhwm\n                           : options.sndhwm != 0 && peer.options.rcvhwm != 0\n                             ? options.sndhwm + peer.options.rcvhwm\n                             : 0;\n        const int rcvhwm = peer.socket == NULL ? options.rcvhwm\n                           : options.rcvhwm != 0 && peer.options.sndhwm != 0\n                             ? options.rcvhwm + peer.options.sndhwm\n                             : 0;\n\n        //  Create a bi-directional pipe to connect the peers.\n        object_t *parents[2] = {this, peer.socket == NULL ? this : peer.socket};\n        pipe_t *new_pipes[2] = {NULL, NULL};\n\n        const bool conflate = get_effective_conflate_option (options);\n\n        int hwms[2] = {conflate ? -1 : sndhwm, conflate ? -1 : rcvhwm};\n        bool conflates[2] = {conflate, conflate};\n        rc = pipepair (parents, new_pipes, hwms, conflates);\n        if (!conflate) {\n            new_pipes[0]->set_hwms_boost (peer.options.sndhwm,\n                                          peer.options.rcvhwm);\n            new_pipes[1]->set_hwms_boost (options.sndhwm, options.rcvhwm);\n        }\n\n        errno_assert (rc == 0);\n\n        if (!peer.socket) {\n            //  The peer doesn't exist yet so we don't know whether\n            //  to send the routing id message or not. To resolve this,\n            //  we always send our routing id and drop it later if\n            //  the peer doesn't expect it.\n            send_routing_id (new_pipes[0], options);\n\n#ifdef ZMQ_BUILD_DRAFT_API\n            //  If set, send the hello msg of the local socket to the peer.\n            if (options.can_send_hello_msg && options.hello_msg.size () > 0) {\n                send_hello_msg (new_pipes[0], options);\n            }\n#endif\n\n            const endpoint_t endpoint = {this, options};\n            pend_connection (std::string (endpoint_uri_), endpoint, new_pipes);\n        } else {\n            //  If required, send the routing id of the local socket to the peer.\n            if (peer.options.recv_routing_id) {\n                send_routing_id (new_pipes[0], options);\n            }\n\n            //  If required, send the routing id of the peer to the local socket.\n            if (options.recv_routing_id) {\n                send_routing_id (new_pipes[1], peer.options);\n            }\n\n#ifdef ZMQ_BUILD_DRAFT_API\n            //  If set, send the hello msg of the local socket to the peer.\n            if (options.can_send_hello_msg && options.hello_msg.size () > 0) {\n                send_hello_msg (new_pipes[0], options);\n            }\n\n            //  If set, send the hello msg of the peer to the local socket.\n            if (peer.options.can_send_hello_msg\n                && peer.options.hello_msg.size () > 0) {\n                send_hello_msg (new_pipes[1], peer.options);\n            }\n\n            if (peer.options.can_recv_disconnect_msg\n                && peer.options.disconnect_msg.size () > 0)\n                new_pipes[0]->set_disconnect_msg (peer.options.disconnect_msg);\n#endif\n\n            //  Attach remote end of the pipe to the peer socket. Note that peer's\n            //  seqnum was incremented in find_endpoint function. We don't need it\n            //  increased here.\n            send_bind (peer.socket, new_pipes[1], false);\n        }\n\n        //  Attach local end of the pipe to this socket object.\n        attach_pipe (new_pipes[0], false, true);\n\n        // Save last endpoint URI\n        _last_endpoint.assign (endpoint_uri_);\n\n        // remember inproc connections for disconnect\n        _inprocs.emplace (endpoint_uri_, new_pipes[0]);\n\n        options.connected = true;\n        return 0;\n    }\n    const bool is_single_connect =\n      (options.type == ZMQ_DEALER || options.type == ZMQ_SUB\n       || options.type == ZMQ_PUB || options.type == ZMQ_REQ);\n    if (unlikely (is_single_connect)) {\n        if (0 != _endpoints.count (endpoint_uri_)) {\n            // There is no valid use for multiple connects for SUB-PUB nor\n            // DEALER-ROUTER nor REQ-REP. Multiple connects produces\n            // nonsensical results.\n            return 0;\n        }\n    }\n\n    //  Choose the I/O thread to run the session in.\n    io_thread_t *io_thread = choose_io_thread (options.affinity);\n    if (!io_thread) {\n        errno = EMTHREAD;\n        return -1;\n    }\n\n    address_t *paddr =\n      new (std::nothrow) address_t (protocol, address, this->get_ctx ());\n    alloc_assert (paddr);\n\n    //  Resolve address (if needed by the protocol)\n    if (protocol == protocol_name::tcp) {\n        //  Do some basic sanity checks on tcp:// address syntax\n        //  - hostname starts with digit or letter, with embedded '-' or '.'\n        //  - IPv6 address may contain hex chars and colons.\n        //  - IPv6 link local address may contain % followed by interface name / zone_id\n        //    (Reference: https://tools.ietf.org/html/rfc4007)\n        //  - IPv4 address may contain decimal digits and dots.\n        //  - Address must end in \":port\" where port is *, or numeric\n        //  - Address may contain two parts separated by ':'\n        //  Following code is quick and dirty check to catch obvious errors,\n        //  without trying to be fully accurate.\n        const char *check = address.c_str ();\n        if (isalnum (*check) || isxdigit (*check) || *check == '['\n            || *check == ':') {\n            check++;\n            while (isalnum (*check) || isxdigit (*check) || *check == '.'\n                   || *check == '-' || *check == ':' || *check == '%'\n                   || *check == ';' || *check == '[' || *check == ']'\n                   || *check == '_' || *check == '*') {\n                check++;\n            }\n        }\n        //  Assume the worst, now look for success\n        rc = -1;\n        //  Did we reach the end of the address safely?\n        if (*check == 0) {\n            //  Do we have a valid port string? (cannot be '*' in connect\n            check = strrchr (address.c_str (), ':');\n            if (check) {\n                check++;\n                if (*check && (isdigit (*check)))\n                    rc = 0; //  Valid\n            }\n        }\n        if (rc == -1) {\n            errno = EINVAL;\n            LIBZMQ_DELETE (paddr);\n            return -1;\n        }\n        //  Defer resolution until a socket is opened\n        paddr->resolved.tcp_addr = NULL;\n    }\n#ifdef ZMQ_HAVE_WS\n#ifdef ZMQ_HAVE_WSS\n    else if (protocol == protocol_name::ws || protocol == protocol_name::wss) {\n        if (protocol == protocol_name::wss) {\n            paddr->resolved.wss_addr = new (std::nothrow) wss_address_t ();\n            alloc_assert (paddr->resolved.wss_addr);\n            rc = paddr->resolved.wss_addr->resolve (address.c_str (), false,\n                                                    options.ipv6);\n        } else\n#else\n    else if (protocol == protocol_name::ws) {\n#endif\n        {\n            paddr->resolved.ws_addr = new (std::nothrow) ws_address_t ();\n            alloc_assert (paddr->resolved.ws_addr);\n            rc = paddr->resolved.ws_addr->resolve (address.c_str (), false,\n                                                   options.ipv6);\n        }\n\n        if (rc != 0) {\n            LIBZMQ_DELETE (paddr);\n            return -1;\n        }\n    }\n#endif\n\n#if defined ZMQ_HAVE_IPC\n    else if (protocol == protocol_name::ipc) {\n        paddr->resolved.ipc_addr = new (std::nothrow) ipc_address_t ();\n        alloc_assert (paddr->resolved.ipc_addr);\n        int rc = paddr->resolved.ipc_addr->resolve (address.c_str ());\n        if (rc != 0) {\n            LIBZMQ_DELETE (paddr);\n            return -1;\n        }\n    }\n#endif\n\n    if (protocol == protocol_name::udp) {\n        if (options.type != ZMQ_RADIO) {\n            errno = ENOCOMPATPROTO;\n            LIBZMQ_DELETE (paddr);\n            return -1;\n        }\n\n        paddr->resolved.udp_addr = new (std::nothrow) udp_address_t ();\n        alloc_assert (paddr->resolved.udp_addr);\n        rc = paddr->resolved.udp_addr->resolve (address.c_str (), false,\n                                                options.ipv6);\n        if (rc != 0) {\n            LIBZMQ_DELETE (paddr);\n            return -1;\n        }\n    }\n\n    // TBD - Should we check address for ZMQ_HAVE_NORM???\n\n#ifdef ZMQ_HAVE_OPENPGM\n    if (protocol == protocol_name::pgm || protocol == protocol_name::epgm) {\n        struct pgm_addrinfo_t *res = NULL;\n        uint16_t port_number = 0;\n        int rc =\n          pgm_socket_t::init_address (address.c_str (), &res, &port_number);\n        if (res != NULL)\n            pgm_freeaddrinfo (res);\n        if (rc != 0 || port_number == 0) {\n            return -1;\n        }\n    }\n#endif\n#if defined ZMQ_HAVE_TIPC\n    else if (protocol == protocol_name::tipc) {\n        paddr->resolved.tipc_addr = new (std::nothrow) tipc_address_t ();\n        alloc_assert (paddr->resolved.tipc_addr);\n        int rc = paddr->resolved.tipc_addr->resolve (address.c_str ());\n        if (rc != 0) {\n            LIBZMQ_DELETE (paddr);\n            return -1;\n        }\n        const sockaddr_tipc *const saddr =\n          reinterpret_cast<const sockaddr_tipc *> (\n            paddr->resolved.tipc_addr->addr ());\n        // Cannot connect to random Port Identity\n        if (saddr->addrtype == TIPC_ADDR_ID\n            && paddr->resolved.tipc_addr->is_random ()) {\n            LIBZMQ_DELETE (paddr);\n            errno = EINVAL;\n            return -1;\n        }\n    }\n#endif\n#if defined ZMQ_HAVE_VMCI\n    else if (protocol == protocol_name::vmci) {\n        paddr->resolved.vmci_addr =\n          new (std::nothrow) vmci_address_t (this->get_ctx ());\n        alloc_assert (paddr->resolved.vmci_addr);\n        int rc = paddr->resolved.vmci_addr->resolve (address.c_str ());\n        if (rc != 0) {\n            LIBZMQ_DELETE (paddr);\n            return -1;\n        }\n    }\n#endif\n#if defined ZMQ_HAVE_VSOCK\n    else if (protocol == protocol_name::vsock) {\n        paddr->resolved.vsock_addr =\n          new (std::nothrow) vsock_address_t (this->get_ctx ());\n        alloc_assert (paddr->resolved.vsock_addr);\n        int rc = paddr->resolved.vsock_addr->resolve (address.c_str ());\n        if (rc != 0) {\n            LIBZMQ_DELETE (paddr);\n            return -1;\n        }\n    }\n#endif\n\n    //  Create session.\n    session_base_t *session =\n      session_base_t::create (io_thread, true, this, options, paddr);\n    errno_assert (session);\n\n    //  PGM does not support subscription forwarding; ask for all data to be\n    //  sent to this pipe. (same for NORM, currently?)\n#if defined ZMQ_HAVE_OPENPGM && defined ZMQ_HAVE_NORM\n    const bool subscribe_to_all =\n      protocol == protocol_name::pgm || protocol == protocol_name::epgm\n      || protocol == protocol_name::norm || protocol == protocol_name::udp;\n#elif defined ZMQ_HAVE_OPENPGM\n    const bool subscribe_to_all = protocol == protocol_name::pgm\n                                  || protocol == protocol_name::epgm\n                                  || protocol == protocol_name::udp;\n#elif defined ZMQ_HAVE_NORM\n    const bool subscribe_to_all =\n      protocol == protocol_name::norm || protocol == protocol_name::udp;\n#else\n    const bool subscribe_to_all = protocol == protocol_name::udp;\n#endif\n    pipe_t *newpipe = NULL;\n\n    if (options.immediate != 1 || subscribe_to_all) {\n        //  Create a bi-directional pipe.\n        object_t *parents[2] = {this, session};\n        pipe_t *new_pipes[2] = {NULL, NULL};\n\n        const bool conflate = get_effective_conflate_option (options);\n\n        int hwms[2] = {conflate ? -1 : options.sndhwm,\n                       conflate ? -1 : options.rcvhwm};\n        bool conflates[2] = {conflate, conflate};\n        rc = pipepair (parents, new_pipes, hwms, conflates);\n        errno_assert (rc == 0);\n\n        //  Attach local end of the pipe to the socket object.\n        attach_pipe (new_pipes[0], subscribe_to_all, true);\n        newpipe = new_pipes[0];\n\n        //  Attach remote end of the pipe to the session object later on.\n        session->attach_pipe (new_pipes[1]);\n    }\n\n    //  Save last endpoint URI\n    paddr->to_string (_last_endpoint);\n\n    add_endpoint (make_unconnected_connect_endpoint_pair (endpoint_uri_),\n                  static_cast<own_t *> (session), newpipe);\n    return 0;\n}\n\nstd::string\nzmq::socket_base_t::resolve_tcp_addr (std::string endpoint_uri_pair_,\n                                      const char *tcp_address_)\n{\n    // The resolved last_endpoint is used as a key in the endpoints map.\n    // The address passed by the user might not match in the TCP case due to\n    // IPv4-in-IPv6 mapping (EG: tcp://[::ffff:127.0.0.1]:9999), so try to\n    // resolve before giving up. Given at this stage we don't know whether a\n    // socket is connected or bound, try with both.\n    if (_endpoints.find (endpoint_uri_pair_) == _endpoints.end ()) {\n        tcp_address_t *tcp_addr = new (std::nothrow) tcp_address_t ();\n        alloc_assert (tcp_addr);\n        int rc = tcp_addr->resolve (tcp_address_, false, options.ipv6);\n\n        if (rc == 0) {\n            tcp_addr->to_string (endpoint_uri_pair_);\n            if (_endpoints.find (endpoint_uri_pair_) == _endpoints.end ()) {\n                rc = tcp_addr->resolve (tcp_address_, true, options.ipv6);\n                if (rc == 0) {\n                    tcp_addr->to_string (endpoint_uri_pair_);\n                }\n            }\n        }\n        LIBZMQ_DELETE (tcp_addr);\n    }\n    return endpoint_uri_pair_;\n}\n\nvoid zmq::socket_base_t::add_endpoint (\n  const endpoint_uri_pair_t &endpoint_pair_, own_t *endpoint_, pipe_t *pipe_)\n{\n    //  Activate the session. Make it a child of this socket.\n    launch_child (endpoint_);\n    _endpoints.ZMQ_MAP_INSERT_OR_EMPLACE (endpoint_pair_.identifier (),\n                                          endpoint_pipe_t (endpoint_, pipe_));\n\n    if (pipe_ != NULL)\n        pipe_->set_endpoint_pair (endpoint_pair_);\n}\n\nint zmq::socket_base_t::term_endpoint (const char *endpoint_uri_)\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n    //  Check whether the context hasn't been shut down yet.\n    if (unlikely (_ctx_terminated)) {\n        errno = ETERM;\n        return -1;\n    }\n\n    //  Check whether endpoint address passed to the function is valid.\n    if (unlikely (!endpoint_uri_)) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    //  Process pending commands, if any, since there could be pending unprocessed process_own()'s\n    //  (from launch_child() for example) we're asked to terminate now.\n    const int rc = process_commands (0, false);\n    if (unlikely (rc != 0)) {\n        return -1;\n    }\n\n    //  Parse endpoint_uri_ string.\n    std::string uri_protocol;\n    std::string uri_path;\n    if (parse_uri (endpoint_uri_, uri_protocol, uri_path)\n        || check_protocol (uri_protocol)) {\n        return -1;\n    }\n\n    const std::string endpoint_uri_str = std::string (endpoint_uri_);\n\n    // Disconnect an inproc socket\n    if (uri_protocol == protocol_name::inproc) {\n        return unregister_endpoint (endpoint_uri_str, this) == 0\n                 ? 0\n                 : _inprocs.erase_pipes (endpoint_uri_str);\n    }\n\n    const std::string resolved_endpoint_uri =\n      uri_protocol == protocol_name::tcp\n        ? resolve_tcp_addr (endpoint_uri_str, uri_path.c_str ())\n        : endpoint_uri_str;\n\n    //  Find the endpoints range (if any) corresponding to the endpoint_uri_pair_ string.\n    const std::pair<endpoints_t::iterator, endpoints_t::iterator> range =\n      _endpoints.equal_range (resolved_endpoint_uri);\n    if (range.first == range.second) {\n        errno = ENOENT;\n        return -1;\n    }\n\n    for (endpoints_t::iterator it = range.first; it != range.second; ++it) {\n        //  If we have an associated pipe, terminate it.\n        if (it->second.second != NULL)\n            it->second.second->terminate (false);\n        term_child (it->second.first);\n    }\n    _endpoints.erase (range.first, range.second);\n\n    if (options.reconnect_stop & ZMQ_RECONNECT_STOP_AFTER_DISCONNECT) {\n        _disconnected = true;\n    }\n\n    return 0;\n}\n\nint zmq::socket_base_t::send (msg_t *msg_, int flags_)\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n    //  Check whether the context hasn't been shut down yet.\n    if (unlikely (_ctx_terminated)) {\n        errno = ETERM;\n        return -1;\n    }\n\n    //  Check whether message passed to the function is valid.\n    if (unlikely (!msg_ || !msg_->check ())) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    //  Process pending commands, if any.\n    int rc = process_commands (0, true);\n    if (unlikely (rc != 0)) {\n        return -1;\n    }\n\n    //  Clear any user-visible flags that are set on the message.\n    msg_->reset_flags (msg_t::more);\n\n    //  At this point we impose the flags on the message.\n    if (flags_ & ZMQ_SNDMORE)\n        msg_->set_flags (msg_t::more);\n\n    msg_->reset_metadata ();\n\n    //  Try to send the message using method in each socket class\n    rc = xsend (msg_);\n    if (rc == 0) {\n        return 0;\n    }\n    //  Special case for ZMQ_PUSH: -2 means pipe is dead while a\n    //  multi-part send is in progress and can't be recovered, so drop\n    //  silently when in blocking mode to keep backward compatibility.\n    if (unlikely (rc == -2)) {\n        if (!((flags_ & ZMQ_DONTWAIT) || options.sndtimeo == 0)) {\n            rc = msg_->close ();\n            errno_assert (rc == 0);\n            rc = msg_->init ();\n            errno_assert (rc == 0);\n            return 0;\n        }\n    }\n    if (unlikely (errno != EAGAIN)) {\n        return -1;\n    }\n\n    //  In case of non-blocking send we'll simply propagate\n    //  the error - including EAGAIN - up the stack.\n    if ((flags_ & ZMQ_DONTWAIT) || options.sndtimeo == 0) {\n        return -1;\n    }\n\n    //  Compute the time when the timeout should occur.\n    //  If the timeout is infinite, don't care.\n    int timeout = options.sndtimeo;\n    const uint64_t end = timeout < 0 ? 0 : (_clock.now_ms () + timeout);\n\n    //  Oops, we couldn't send the message. Wait for the next\n    //  command, process it and try to send the message again.\n    //  If timeout is reached in the meantime, return EAGAIN.\n    while (true) {\n        if (unlikely (process_commands (timeout, false) != 0)) {\n            return -1;\n        }\n        rc = xsend (msg_);\n        if (rc == 0)\n            break;\n        if (unlikely (errno != EAGAIN)) {\n            return -1;\n        }\n        if (timeout > 0) {\n            timeout = static_cast<int> (end - _clock.now_ms ());\n            if (timeout <= 0) {\n                errno = EAGAIN;\n                return -1;\n            }\n        }\n    }\n\n    return 0;\n}\n\nint zmq::socket_base_t::recv (msg_t *msg_, int flags_)\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n    //  Check whether the context hasn't been shut down yet.\n    if (unlikely (_ctx_terminated)) {\n        errno = ETERM;\n        return -1;\n    }\n\n    //  Check whether message passed to the function is valid.\n    if (unlikely (!msg_ || !msg_->check ())) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    //  Once every inbound_poll_rate messages check for signals and process\n    //  incoming commands. This happens only if we are not polling altogether\n    //  because there are messages available all the time. If poll occurs,\n    //  ticks is set to zero and thus we avoid this code.\n    //\n    //  Note that 'recv' uses different command throttling algorithm (the one\n    //  described above) from the one used by 'send'. This is because counting\n    //  ticks is more efficient than doing RDTSC all the time.\n    if (++_ticks == inbound_poll_rate) {\n        if (unlikely (process_commands (0, false) != 0)) {\n            return -1;\n        }\n        _ticks = 0;\n    }\n\n    //  Get the message.\n    int rc = xrecv (msg_);\n    if (unlikely (rc != 0 && errno != EAGAIN)) {\n        return -1;\n    }\n\n    //  If we have the message, return immediately.\n    if (rc == 0) {\n        extract_flags (msg_);\n        return 0;\n    }\n\n    //  If the message cannot be fetched immediately, there are two scenarios.\n    //  For non-blocking recv, commands are processed in case there's an\n    //  activate_reader command already waiting in a command pipe.\n    //  If it's not, return EAGAIN.\n    if ((flags_ & ZMQ_DONTWAIT) || options.rcvtimeo == 0) {\n        if (unlikely (process_commands (0, false) != 0)) {\n            return -1;\n        }\n        _ticks = 0;\n\n        rc = xrecv (msg_);\n        if (rc < 0) {\n            return rc;\n        }\n        extract_flags (msg_);\n\n        return 0;\n    }\n\n    //  Compute the time when the timeout should occur.\n    //  If the timeout is infinite, don't care.\n    int timeout = options.rcvtimeo;\n    const uint64_t end = timeout < 0 ? 0 : (_clock.now_ms () + timeout);\n\n    //  In blocking scenario, commands are processed over and over again until\n    //  we are able to fetch a message.\n    bool block = (_ticks != 0);\n    while (true) {\n        if (unlikely (process_commands (block ? timeout : 0, false) != 0)) {\n            return -1;\n        }\n        rc = xrecv (msg_);\n        if (rc == 0) {\n            _ticks = 0;\n            break;\n        }\n        if (unlikely (errno != EAGAIN)) {\n            return -1;\n        }\n        block = true;\n        if (timeout > 0) {\n            timeout = static_cast<int> (end - _clock.now_ms ());\n            if (timeout <= 0) {\n                errno = EAGAIN;\n                return -1;\n            }\n        }\n    }\n\n    extract_flags (msg_);\n    return 0;\n}\n\nint zmq::socket_base_t::close ()\n{\n    scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n    //  Remove all existing signalers for thread safe sockets\n    if (_thread_safe)\n        (static_cast<mailbox_safe_t *> (_mailbox))->clear_signalers ();\n\n    //  Mark the socket as dead\n    _tag = 0xdeadbeef;\n\n\n    //  Transfer the ownership of the socket from this application thread\n    //  to the reaper thread which will take care of the rest of shutdown\n    //  process.\n    send_reap (this);\n\n    return 0;\n}\n\nbool zmq::socket_base_t::has_in ()\n{\n    return xhas_in ();\n}\n\nbool zmq::socket_base_t::has_out ()\n{\n    return xhas_out ();\n}\n\nvoid zmq::socket_base_t::start_reaping (poller_t *poller_)\n{\n    //  Plug the socket to the reaper thread.\n    _poller = poller_;\n\n    fd_t fd;\n\n    if (!_thread_safe)\n        fd = (static_cast<mailbox_t *> (_mailbox))->get_fd ();\n    else {\n        scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n        _reaper_signaler = new (std::nothrow) signaler_t ();\n        zmq_assert (_reaper_signaler);\n\n        //  Add signaler to the safe mailbox\n        fd = _reaper_signaler->get_fd ();\n        (static_cast<mailbox_safe_t *> (_mailbox))\n          ->add_signaler (_reaper_signaler);\n\n        //  Send a signal to make sure reaper handle existing commands\n        _reaper_signaler->send ();\n    }\n\n    _handle = _poller->add_fd (fd, this);\n    _poller->set_pollin (_handle);\n\n    //  Initialise the termination and check whether it can be deallocated\n    //  immediately.\n    terminate ();\n    check_destroy ();\n}\n\nint zmq::socket_base_t::process_commands (int timeout_, bool throttle_)\n{\n    if (timeout_ == 0) {\n        //  If we are asked not to wait, check whether we haven't processed\n        //  commands recently, so that we can throttle the new commands.\n\n        //  Get the CPU's tick counter. If 0, the counter is not available.\n        const uint64_t tsc = zmq::clock_t::rdtsc ();\n\n        //  Optimised version of command processing - it doesn't have to check\n        //  for incoming commands each time. It does so only if certain time\n        //  elapsed since last command processing. Command delay varies\n        //  depending on CPU speed: It's ~1ms on 3GHz CPU, ~2ms on 1.5GHz CPU\n        //  etc. The optimisation makes sense only on platforms where getting\n        //  a timestamp is a very cheap operation (tens of nanoseconds).\n        if (tsc && throttle_) {\n            //  Check whether TSC haven't jumped backwards (in case of migration\n            //  between CPU cores) and whether certain time have elapsed since\n            //  last command processing. If it didn't do nothing.\n            if (tsc >= _last_tsc && tsc - _last_tsc <= max_command_delay)\n                return 0;\n            _last_tsc = tsc;\n        }\n    }\n\n    //  Check whether there are any commands pending for this thread.\n    command_t cmd;\n    int rc = _mailbox->recv (&cmd, timeout_);\n\n    if (rc != 0 && errno == EINTR)\n        return -1;\n\n    //  Process all available commands.\n    while (rc == 0 || errno == EINTR) {\n        if (rc == 0) {\n            cmd.destination->process_command (cmd);\n        }\n        rc = _mailbox->recv (&cmd, 0);\n    }\n\n    zmq_assert (errno == EAGAIN);\n\n    if (_ctx_terminated) {\n        errno = ETERM;\n        return -1;\n    }\n\n    return 0;\n}\n\nvoid zmq::socket_base_t::process_stop ()\n{\n    //  Here, someone have called zmq_ctx_term while the socket was still alive.\n    //  We'll remember the fact so that any blocking call is interrupted and any\n    //  further attempt to use the socket will return ETERM. The user is still\n    //  responsible for calling zmq_close on the socket though!\n    scoped_lock_t lock (_monitor_sync);\n    stop_monitor ();\n\n    _ctx_terminated = true;\n}\n\nvoid zmq::socket_base_t::process_bind (pipe_t *pipe_)\n{\n    attach_pipe (pipe_);\n}\n\nvoid zmq::socket_base_t::process_term (int linger_)\n{\n    //  Unregister all inproc endpoints associated with this socket.\n    //  Doing this we make sure that no new pipes from other sockets (inproc)\n    //  will be initiated.\n    unregister_endpoints (this);\n\n    //  Ask all attached pipes to terminate.\n    for (pipes_t::size_type i = 0, size = _pipes.size (); i != size; ++i) {\n        //  Only inprocs might have a disconnect message set\n        _pipes[i]->send_disconnect_msg ();\n        _pipes[i]->terminate (false);\n    }\n    register_term_acks (static_cast<int> (_pipes.size ()));\n\n    //  Continue the termination process immediately.\n    own_t::process_term (linger_);\n}\n\nvoid zmq::socket_base_t::process_term_endpoint (std::string *endpoint_)\n{\n    term_endpoint (endpoint_->c_str ());\n    delete endpoint_;\n}\n\nvoid zmq::socket_base_t::process_pipe_stats_publish (\n  uint64_t outbound_queue_count_,\n  uint64_t inbound_queue_count_,\n  endpoint_uri_pair_t *endpoint_pair_)\n{\n    uint64_t values[2] = {outbound_queue_count_, inbound_queue_count_};\n    event (*endpoint_pair_, values, 2, ZMQ_EVENT_PIPES_STATS);\n    delete endpoint_pair_;\n}\n\n/*\n * There are 2 pipes per connection, and the inbound one _must_ be queried from\n * the I/O thread. So ask the outbound pipe, in the application thread, to send\n * a message (pipe_peer_stats) to its peer. The message will carry the outbound\n * pipe stats and endpoint, and the reference to the socket object.\n * The inbound pipe on the I/O thread will then add its own stats and endpoint,\n * and write back a message to the socket object (pipe_stats_publish) which\n * will raise an event with the data.\n */\nint zmq::socket_base_t::query_pipes_stats ()\n{\n    {\n        scoped_lock_t lock (_monitor_sync);\n        if (!(_monitor_events & ZMQ_EVENT_PIPES_STATS)) {\n            errno = EINVAL;\n            return -1;\n        }\n    }\n    if (_pipes.size () == 0) {\n        errno = EAGAIN;\n        return -1;\n    }\n    for (pipes_t::size_type i = 0, size = _pipes.size (); i != size; ++i) {\n        _pipes[i]->send_stats_to_peer (this);\n    }\n\n    return 0;\n}\n\nvoid zmq::socket_base_t::update_pipe_options (int option_)\n{\n    if (option_ == ZMQ_SNDHWM || option_ == ZMQ_RCVHWM) {\n        for (pipes_t::size_type i = 0, size = _pipes.size (); i != size; ++i) {\n            _pipes[i]->set_hwms (options.rcvhwm, options.sndhwm);\n            _pipes[i]->send_hwms_to_peer (options.sndhwm, options.rcvhwm);\n        }\n    }\n}\n\nvoid zmq::socket_base_t::process_destroy ()\n{\n    _destroyed = true;\n}\n\nint zmq::socket_base_t::xsetsockopt (int, const void *, size_t)\n{\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::socket_base_t::xgetsockopt (int, void *, size_t *)\n{\n    errno = EINVAL;\n    return -1;\n}\n\nbool zmq::socket_base_t::xhas_out ()\n{\n    return false;\n}\n\nint zmq::socket_base_t::xsend (msg_t *)\n{\n    errno = ENOTSUP;\n    return -1;\n}\n\nbool zmq::socket_base_t::xhas_in ()\n{\n    return false;\n}\n\nint zmq::socket_base_t::xjoin (const char *group_)\n{\n    LIBZMQ_UNUSED (group_);\n    errno = ENOTSUP;\n    return -1;\n}\n\nint zmq::socket_base_t::xleave (const char *group_)\n{\n    LIBZMQ_UNUSED (group_);\n    errno = ENOTSUP;\n    return -1;\n}\n\nint zmq::socket_base_t::xdisconnect_peer (uint32_t)\n{\n    errno = ENOTSUP;\n    return -1;\n}\n\nint zmq::socket_base_t::xrecv (msg_t *)\n{\n    errno = ENOTSUP;\n    return -1;\n}\n\nvoid zmq::socket_base_t::xread_activated (pipe_t *)\n{\n    zmq_assert (false);\n}\nvoid zmq::socket_base_t::xwrite_activated (pipe_t *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::socket_base_t::xhiccuped (pipe_t *)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::socket_base_t::in_event ()\n{\n    //  This function is invoked only once the socket is running in the context\n    //  of the reaper thread. Process any commands from other threads/sockets\n    //  that may be available at the moment. Ultimately, the socket will\n    //  be destroyed.\n    {\n        scoped_optional_lock_t sync_lock (_thread_safe ? &_sync : NULL);\n\n        //  If the socket is thread safe we need to unsignal the reaper signaler\n        if (_thread_safe)\n            _reaper_signaler->recv ();\n\n        process_commands (0, false);\n    }\n    check_destroy ();\n}\n\nvoid zmq::socket_base_t::out_event ()\n{\n    zmq_assert (false);\n}\n\nvoid zmq::socket_base_t::timer_event (int)\n{\n    zmq_assert (false);\n}\n\nvoid zmq::socket_base_t::check_destroy ()\n{\n    //  If the object was already marked as destroyed, finish the deallocation.\n    if (_destroyed) {\n        //  Remove the socket from the reaper's poller.\n        _poller->rm_fd (_handle);\n\n        //  Remove the socket from the context.\n        destroy_socket (this);\n\n        //  Notify the reaper about the fact.\n        send_reaped ();\n\n        //  Deallocate.\n        own_t::process_destroy ();\n    }\n}\n\nvoid zmq::socket_base_t::read_activated (pipe_t *pipe_)\n{\n    xread_activated (pipe_);\n}\n\nvoid zmq::socket_base_t::write_activated (pipe_t *pipe_)\n{\n    xwrite_activated (pipe_);\n}\n\nvoid zmq::socket_base_t::hiccuped (pipe_t *pipe_)\n{\n    if (options.immediate == 1)\n        pipe_->terminate (false);\n    else\n        // Notify derived sockets of the hiccup\n        xhiccuped (pipe_);\n}\n\nvoid zmq::socket_base_t::pipe_terminated (pipe_t *pipe_)\n{\n    //  Notify the specific socket type about the pipe termination.\n    xpipe_terminated (pipe_);\n\n    // Remove pipe from inproc pipes\n    _inprocs.erase_pipe (pipe_);\n\n    //  Remove the pipe from the list of attached pipes and confirm its\n    //  termination if we are already shutting down.\n    _pipes.erase (pipe_);\n\n    // Remove the pipe from _endpoints (set it to NULL).\n    const std::string &identifier = pipe_->get_endpoint_pair ().identifier ();\n    if (!identifier.empty ()) {\n        std::pair<endpoints_t::iterator, endpoints_t::iterator> range;\n        range = _endpoints.equal_range (identifier);\n\n        for (endpoints_t::iterator it = range.first; it != range.second; ++it) {\n            if (it->second.second == pipe_) {\n                it->second.second = NULL;\n                break;\n            }\n        }\n    }\n\n    if (is_terminating ())\n        unregister_term_ack ();\n}\n\nvoid zmq::socket_base_t::extract_flags (const msg_t *msg_)\n{\n    //  Test whether routing_id flag is valid for this socket type.\n    if (unlikely (msg_->flags () & msg_t::routing_id))\n        zmq_assert (options.recv_routing_id);\n\n    //  Remove MORE flag.\n    _rcvmore = (msg_->flags () & msg_t::more) != 0;\n}\n\nint zmq::socket_base_t::monitor (const char *endpoint_,\n                                 uint64_t events_,\n                                 int event_version_,\n                                 int type_)\n{\n    scoped_lock_t lock (_monitor_sync);\n\n    if (unlikely (_ctx_terminated)) {\n        errno = ETERM;\n        return -1;\n    }\n\n    //  Event version 1 supports only first 16 events.\n    if (unlikely (event_version_ == 1 && events_ >> 16 != 0)) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    //  Support deregistering monitoring endpoints as well\n    if (endpoint_ == NULL) {\n        stop_monitor ();\n        return 0;\n    }\n    //  Parse endpoint_uri_ string.\n    std::string protocol;\n    std::string address;\n    if (parse_uri (endpoint_, protocol, address) || check_protocol (protocol))\n        return -1;\n\n    //  Event notification only supported over inproc://\n    if (protocol != protocol_name::inproc) {\n        errno = EPROTONOSUPPORT;\n        return -1;\n    }\n\n    // already monitoring. Stop previous monitor before starting new one.\n    if (_monitor_socket != NULL) {\n        stop_monitor (true);\n    }\n\n    // Check if the specified socket type is supported. It must be a\n    // one-way socket types that support the SNDMORE flag.\n    switch (type_) {\n        case ZMQ_PAIR:\n            break;\n        case ZMQ_PUB:\n            break;\n        case ZMQ_PUSH:\n            break;\n        default:\n            errno = EINVAL;\n            return -1;\n    }\n\n    //  Register events to monitor\n    _monitor_events = events_;\n    options.monitor_event_version = event_version_;\n    //  Create a monitor socket of the specified type.\n    _monitor_socket = zmq_socket (get_ctx (), type_);\n    if (_monitor_socket == NULL)\n        return -1;\n\n    //  Never block context termination on pending event messages\n    int linger = 0;\n    int rc =\n      zmq_setsockopt (_monitor_socket, ZMQ_LINGER, &linger, sizeof (linger));\n    if (rc == -1)\n        stop_monitor (false);\n\n    //  Spawn the monitor socket endpoint\n    rc = zmq_bind (_monitor_socket, endpoint_);\n    if (rc == -1)\n        stop_monitor (false);\n    return rc;\n}\n\nvoid zmq::socket_base_t::event_connected (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, zmq::fd_t fd_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (fd_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_CONNECTED);\n}\n\nvoid zmq::socket_base_t::event_connect_delayed (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, int err_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (err_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_CONNECT_DELAYED);\n}\n\nvoid zmq::socket_base_t::event_connect_retried (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, int interval_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (interval_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_CONNECT_RETRIED);\n}\n\nvoid zmq::socket_base_t::event_listening (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, zmq::fd_t fd_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (fd_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_LISTENING);\n}\n\nvoid zmq::socket_base_t::event_bind_failed (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, int err_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (err_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_BIND_FAILED);\n}\n\nvoid zmq::socket_base_t::event_accepted (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, zmq::fd_t fd_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (fd_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_ACCEPTED);\n}\n\nvoid zmq::socket_base_t::event_accept_failed (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, int err_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (err_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_ACCEPT_FAILED);\n}\n\nvoid zmq::socket_base_t::event_closed (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, zmq::fd_t fd_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (fd_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_CLOSED);\n}\n\nvoid zmq::socket_base_t::event_close_failed (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, int err_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (err_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_CLOSE_FAILED);\n}\n\nvoid zmq::socket_base_t::event_disconnected (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, zmq::fd_t fd_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (fd_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_DISCONNECTED);\n}\n\nvoid zmq::socket_base_t::event_handshake_failed_no_detail (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, int err_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (err_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL);\n}\n\nvoid zmq::socket_base_t::event_handshake_failed_protocol (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, int err_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (err_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL);\n}\n\nvoid zmq::socket_base_t::event_handshake_failed_auth (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, int err_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (err_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH);\n}\n\nvoid zmq::socket_base_t::event_handshake_succeeded (\n  const endpoint_uri_pair_t &endpoint_uri_pair_, int err_)\n{\n    uint64_t values[1] = {static_cast<uint64_t> (err_)};\n    event (endpoint_uri_pair_, values, 1, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n}\n\nvoid zmq::socket_base_t::event (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                                uint64_t values_[],\n                                uint64_t values_count_,\n                                uint64_t type_)\n{\n    scoped_lock_t lock (_monitor_sync);\n    if (_monitor_events & type_) {\n        monitor_event (type_, values_, values_count_, endpoint_uri_pair_);\n    }\n}\n\n//  Send a monitor event\nvoid zmq::socket_base_t::monitor_event (\n  uint64_t event_,\n  const uint64_t values_[],\n  uint64_t values_count_,\n  const endpoint_uri_pair_t &endpoint_uri_pair_) const\n{\n    // this is a private method which is only called from\n    // contexts where the _monitor_sync mutex has been locked before\n\n    if (_monitor_socket) {\n        zmq_msg_t msg;\n\n        switch (options.monitor_event_version) {\n            case 1: {\n                //  The API should not allow to activate unsupported events\n                zmq_assert (event_ <= std::numeric_limits<uint16_t>::max ());\n                //  v1 only allows one value\n                zmq_assert (values_count_ == 1);\n                zmq_assert (values_[0]\n                            <= std::numeric_limits<uint32_t>::max ());\n\n                //  Send event and value in first frame\n                const uint16_t event = static_cast<uint16_t> (event_);\n                const uint32_t value = static_cast<uint32_t> (values_[0]);\n                zmq_msg_init_size (&msg, sizeof (event) + sizeof (value));\n                uint8_t *data = static_cast<uint8_t *> (zmq_msg_data (&msg));\n                //  Avoid dereferencing uint32_t on unaligned address\n                memcpy (data + 0, &event, sizeof (event));\n                memcpy (data + sizeof (event), &value, sizeof (value));\n                zmq_msg_send (&msg, _monitor_socket, ZMQ_SNDMORE);\n\n                const std::string &endpoint_uri =\n                  endpoint_uri_pair_.identifier ();\n\n                //  Send address in second frame\n                zmq_msg_init_size (&msg, endpoint_uri.size ());\n                memcpy (zmq_msg_data (&msg), endpoint_uri.c_str (),\n                        endpoint_uri.size ());\n                zmq_msg_send (&msg, _monitor_socket, 0);\n            } break;\n            case 2: {\n                //  Send event in first frame (64bit unsigned)\n                zmq_msg_init_size (&msg, sizeof (event_));\n                memcpy (zmq_msg_data (&msg), &event_, sizeof (event_));\n                zmq_msg_send (&msg, _monitor_socket, ZMQ_SNDMORE);\n\n                //  Send number of values that will follow in second frame\n                zmq_msg_init_size (&msg, sizeof (values_count_));\n                memcpy (zmq_msg_data (&msg), &values_count_,\n                        sizeof (values_count_));\n                zmq_msg_send (&msg, _monitor_socket, ZMQ_SNDMORE);\n\n                //  Send values in third-Nth frames (64bit unsigned)\n                for (uint64_t i = 0; i < values_count_; ++i) {\n                    zmq_msg_init_size (&msg, sizeof (values_[i]));\n                    memcpy (zmq_msg_data (&msg), &values_[i],\n                            sizeof (values_[i]));\n                    zmq_msg_send (&msg, _monitor_socket, ZMQ_SNDMORE);\n                }\n\n                //  Send local endpoint URI in second-to-last frame (string)\n                zmq_msg_init_size (&msg, endpoint_uri_pair_.local.size ());\n                memcpy (zmq_msg_data (&msg), endpoint_uri_pair_.local.c_str (),\n                        endpoint_uri_pair_.local.size ());\n                zmq_msg_send (&msg, _monitor_socket, ZMQ_SNDMORE);\n\n                //  Send remote endpoint URI in last frame (string)\n                zmq_msg_init_size (&msg, endpoint_uri_pair_.remote.size ());\n                memcpy (zmq_msg_data (&msg), endpoint_uri_pair_.remote.c_str (),\n                        endpoint_uri_pair_.remote.size ());\n                zmq_msg_send (&msg, _monitor_socket, 0);\n            } break;\n        }\n    }\n}\n\nvoid zmq::socket_base_t::stop_monitor (bool send_monitor_stopped_event_)\n{\n    // this is a private method which is only called from\n    // contexts where the _monitor_sync mutex has been locked before\n\n    if (_monitor_socket) {\n        if ((_monitor_events & ZMQ_EVENT_MONITOR_STOPPED)\n            && send_monitor_stopped_event_) {\n            uint64_t values[1] = {0};\n            monitor_event (ZMQ_EVENT_MONITOR_STOPPED, values, 1,\n                           endpoint_uri_pair_t ());\n        }\n        zmq_close (_monitor_socket);\n        _monitor_socket = NULL;\n        _monitor_events = 0;\n    }\n}\n\nbool zmq::socket_base_t::is_disconnected () const\n{\n    return _disconnected;\n}\n\nzmq::routing_socket_base_t::routing_socket_base_t (class ctx_t *parent_,\n                                                   uint32_t tid_,\n                                                   int sid_) :\n    socket_base_t (parent_, tid_, sid_)\n{\n}\n\nzmq::routing_socket_base_t::~routing_socket_base_t ()\n{\n    zmq_assert (_out_pipes.empty ());\n}\n\nint zmq::routing_socket_base_t::xsetsockopt (int option_,\n                                             const void *optval_,\n                                             size_t optvallen_)\n{\n    switch (option_) {\n        case ZMQ_CONNECT_ROUTING_ID:\n            // TODO why isn't it possible to set an empty connect_routing_id\n            //   (which is the default value)\n            if (optval_ && optvallen_) {\n                _connect_routing_id.assign (static_cast<const char *> (optval_),\n                                            optvallen_);\n                return 0;\n            }\n            break;\n    }\n    errno = EINVAL;\n    return -1;\n}\n\nvoid zmq::routing_socket_base_t::xwrite_activated (pipe_t *pipe_)\n{\n    const out_pipes_t::iterator end = _out_pipes.end ();\n    out_pipes_t::iterator it;\n    for (it = _out_pipes.begin (); it != end; ++it)\n        if (it->second.pipe == pipe_)\n            break;\n\n    zmq_assert (it != end);\n    zmq_assert (!it->second.active);\n    it->second.active = true;\n}\n\nstd::string zmq::routing_socket_base_t::extract_connect_routing_id ()\n{\n    std::string res = ZMQ_MOVE (_connect_routing_id);\n    _connect_routing_id.clear ();\n    return res;\n}\n\nbool zmq::routing_socket_base_t::connect_routing_id_is_set () const\n{\n    return !_connect_routing_id.empty ();\n}\n\nvoid zmq::routing_socket_base_t::add_out_pipe (blob_t routing_id_,\n                                               pipe_t *pipe_)\n{\n    //  Add the record into output pipes lookup table\n    const out_pipe_t outpipe = {pipe_, true};\n    const bool ok =\n      _out_pipes.ZMQ_MAP_INSERT_OR_EMPLACE (ZMQ_MOVE (routing_id_), outpipe)\n        .second;\n    zmq_assert (ok);\n}\n\nbool zmq::routing_socket_base_t::has_out_pipe (const blob_t &routing_id_) const\n{\n    return 0 != _out_pipes.count (routing_id_);\n}\n\nzmq::routing_socket_base_t::out_pipe_t *\nzmq::routing_socket_base_t::lookup_out_pipe (const blob_t &routing_id_)\n{\n    // TODO we could probably avoid constructor a temporary blob_t to call this function\n    out_pipes_t::iterator it = _out_pipes.find (routing_id_);\n    return it == _out_pipes.end () ? NULL : &it->second;\n}\n\nconst zmq::routing_socket_base_t::out_pipe_t *\nzmq::routing_socket_base_t::lookup_out_pipe (const blob_t &routing_id_) const\n{\n    // TODO we could probably avoid constructor a temporary blob_t to call this function\n    const out_pipes_t::const_iterator it = _out_pipes.find (routing_id_);\n    return it == _out_pipes.end () ? NULL : &it->second;\n}\n\nvoid zmq::routing_socket_base_t::erase_out_pipe (const pipe_t *pipe_)\n{\n    const size_t erased = _out_pipes.erase (pipe_->get_routing_id ());\n    zmq_assert (erased);\n}\n\nzmq::routing_socket_base_t::out_pipe_t\nzmq::routing_socket_base_t::try_erase_out_pipe (const blob_t &routing_id_)\n{\n    const out_pipes_t::iterator it = _out_pipes.find (routing_id_);\n    out_pipe_t res = {NULL, false};\n    if (it != _out_pipes.end ()) {\n        res = it->second;\n        _out_pipes.erase (it);\n    }\n    return res;\n}\n"
  },
  {
    "path": "src/socket_base.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SOCKET_BASE_HPP_INCLUDED__\n#define __ZMQ_SOCKET_BASE_HPP_INCLUDED__\n\n#include <string>\n#include <map>\n#include <stdarg.h>\n\n#include \"own.hpp\"\n#include \"array.hpp\"\n#include \"blob.hpp\"\n#include \"stdint.hpp\"\n#include \"poller.hpp\"\n#include \"i_poll_events.hpp\"\n#include \"i_mailbox.hpp\"\n#include \"clock.hpp\"\n#include \"pipe.hpp\"\n#include \"endpoint.hpp\"\n\nextern \"C\" {\nvoid zmq_free_event (void *data_, void *hint_);\n}\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass pipe_t;\n\nclass socket_base_t : public own_t,\n                      public array_item_t<>,\n                      public i_poll_events,\n                      public i_pipe_events\n{\n    friend class reaper_t;\n\n  public:\n    //  Returns false if object is not a socket.\n    bool check_tag () const;\n\n    //  Returns whether the socket is thread-safe.\n    bool is_thread_safe () const;\n\n    //  Create a socket of a specified type.\n    static socket_base_t *\n    create (int type_, zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n\n    //  Returns the mailbox associated with this socket.\n    i_mailbox *get_mailbox () const;\n\n    //  Interrupt blocking call if the socket is stuck in one.\n    //  This function can be called from a different thread!\n    void stop ();\n\n    //  Interface for communication with the API layer.\n    int setsockopt (int option_, const void *optval_, size_t optvallen_);\n    int getsockopt (int option_, void *optval_, size_t *optvallen_);\n    int bind (const char *endpoint_uri_);\n    int connect (const char *endpoint_uri_);\n    int term_endpoint (const char *endpoint_uri_);\n    int send (zmq::msg_t *msg_, int flags_);\n    int recv (zmq::msg_t *msg_, int flags_);\n    void add_signaler (signaler_t *s_);\n    void remove_signaler (signaler_t *s_);\n    int close ();\n\n    //  These functions are used by the polling mechanism to determine\n    //  which events are to be reported from this socket.\n    bool has_in ();\n    bool has_out ();\n\n    //  Joining and leaving groups\n    int join (const char *group_);\n    int leave (const char *group_);\n\n    //  Using this function reaper thread ask the socket to register with\n    //  its poller.\n    void start_reaping (poller_t *poller_);\n\n    //  i_poll_events implementation. This interface is used when socket\n    //  is handled by the poller in the reaper thread.\n    void in_event () ZMQ_FINAL;\n    void out_event () ZMQ_FINAL;\n    void timer_event (int id_) ZMQ_FINAL;\n\n    //  i_pipe_events interface implementation.\n    void read_activated (pipe_t *pipe_) ZMQ_FINAL;\n    void write_activated (pipe_t *pipe_) ZMQ_FINAL;\n    void hiccuped (pipe_t *pipe_) ZMQ_FINAL;\n    void pipe_terminated (pipe_t *pipe_) ZMQ_FINAL;\n    void lock ();\n    void unlock ();\n\n    int monitor (const char *endpoint_,\n                 uint64_t events_,\n                 int event_version_,\n                 int type_);\n\n    void event_connected (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                          zmq::fd_t fd_);\n    void event_connect_delayed (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                                int err_);\n    void event_connect_retried (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                                int interval_);\n    void event_listening (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                          zmq::fd_t fd_);\n    void event_bind_failed (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                            int err_);\n    void event_accepted (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                         zmq::fd_t fd_);\n    void event_accept_failed (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                              int err_);\n    void event_closed (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                       zmq::fd_t fd_);\n    void event_close_failed (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                             int err_);\n    void event_disconnected (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                             zmq::fd_t fd_);\n    void event_handshake_failed_no_detail (\n      const endpoint_uri_pair_t &endpoint_uri_pair_, int err_);\n    void event_handshake_failed_protocol (\n      const endpoint_uri_pair_t &endpoint_uri_pair_, int err_);\n    void\n    event_handshake_failed_auth (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                                 int err_);\n    void\n    event_handshake_succeeded (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                               int err_);\n\n    //  Query the state of a specific peer. The default implementation\n    //  always returns an ENOTSUP error.\n    virtual int get_peer_state (const void *routing_id_,\n                                size_t routing_id_size_) const;\n\n    //  Request for pipes statistics - will generate a ZMQ_EVENT_PIPES_STATS\n    //  after gathering the data asynchronously. Requires event monitoring to\n    //  be enabled.\n    int query_pipes_stats ();\n\n    bool is_disconnected () const;\n\n    // Disconnect a specific peer given its routing id. Default ENOTSUP.\n    int disconnect_peer (uint32_t routing_id_);\n\n  protected:\n    socket_base_t (zmq::ctx_t *parent_,\n                   uint32_t tid_,\n                   int sid_,\n                   bool thread_safe_ = false);\n    ~socket_base_t () ZMQ_OVERRIDE;\n\n    //  Concrete algorithms for the x- methods are to be defined by\n    //  individual socket types.\n    virtual void xattach_pipe (zmq::pipe_t *pipe_,\n                               bool subscribe_to_all_ = false,\n                               bool locally_initiated_ = false) = 0;\n\n    //  The default implementation assumes there are no specific socket\n    //  options for the particular socket type. If not so, ZMQ_FINAL this\n    //  method.\n    virtual int\n    xsetsockopt (int option_, const void *optval_, size_t optvallen_);\n\n    //  The default implementation assumes there are no specific socket\n    //  options for the particular socket type. If not so, ZMQ_FINAL this\n    //  method.\n    virtual int xgetsockopt (int option_, void *optval_, size_t *optvallen_);\n\n    //  The default implementation assumes that send is not supported.\n    virtual bool xhas_out ();\n    virtual int xsend (zmq::msg_t *msg_);\n\n    //  The default implementation assumes that recv in not supported.\n    virtual bool xhas_in ();\n    virtual int xrecv (zmq::msg_t *msg_);\n\n    //  i_pipe_events will be forwarded to these functions.\n    virtual void xread_activated (pipe_t *pipe_);\n    virtual void xwrite_activated (pipe_t *pipe_);\n    virtual void xhiccuped (pipe_t *pipe_);\n    virtual void xpipe_terminated (pipe_t *pipe_) = 0;\n\n    //  the default implementation assumes that joub and leave are not supported.\n    virtual int xjoin (const char *group_);\n    virtual int xleave (const char *group_);\n\n    // Default implementation returns ENOTSUP. Specific sockets may override.\n    virtual int xdisconnect_peer (uint32_t routing_id_);\n\n    //  Delay actual destruction of the socket.\n    void process_destroy () ZMQ_FINAL;\n\n    int connect_internal (const char *endpoint_uri_);\n\n    // Mutex for synchronize access to the socket in thread safe mode\n    mutex_t _sync;\n\n  private:\n    // test if event should be sent and then dispatch it\n    void event (const endpoint_uri_pair_t &endpoint_uri_pair_,\n                uint64_t values_[],\n                uint64_t values_count_,\n                uint64_t type_);\n\n    // Socket event data dispatch\n    void monitor_event (uint64_t event_,\n                        const uint64_t values_[],\n                        uint64_t values_count_,\n                        const endpoint_uri_pair_t &endpoint_uri_pair_) const;\n\n    // Monitor socket cleanup\n    void stop_monitor (bool send_monitor_stopped_event_ = true);\n\n    //  Creates new endpoint ID and adds the endpoint to the map.\n    void add_endpoint (const endpoint_uri_pair_t &endpoint_pair_,\n                       own_t *endpoint_,\n                       pipe_t *pipe_);\n\n    //  Map of open endpoints.\n    typedef std::pair<own_t *, pipe_t *> endpoint_pipe_t;\n    typedef std::multimap<std::string, endpoint_pipe_t> endpoints_t;\n    endpoints_t _endpoints;\n\n    //  Map of open inproc endpoints.\n    class inprocs_t\n    {\n      public:\n        void emplace (const char *endpoint_uri_, pipe_t *pipe_);\n        int erase_pipes (const std::string &endpoint_uri_str_);\n        void erase_pipe (const pipe_t *pipe_);\n\n      private:\n        typedef std::multimap<std::string, pipe_t *> map_t;\n        map_t _inprocs;\n    };\n    inprocs_t _inprocs;\n\n    //  To be called after processing commands or invoking any command\n    //  handlers explicitly. If required, it will deallocate the socket.\n    void check_destroy ();\n\n    //  Moves the flags from the message to local variables,\n    //  to be later retrieved by getsockopt.\n    void extract_flags (const msg_t *msg_);\n\n    //  Used to check whether the object is a socket.\n    uint32_t _tag;\n\n    //  If true, associated context was already terminated.\n    bool _ctx_terminated;\n\n    //  If true, object should have been already destroyed. However,\n    //  destruction is delayed while we unwind the stack to the point\n    //  where it doesn't intersect the object being destroyed.\n    bool _destroyed;\n\n    //  Parse URI string.\n    static int\n    parse_uri (const char *uri_, std::string &protocol_, std::string &path_);\n\n    //  Check whether transport protocol, as specified in connect or\n    //  bind, is available and compatible with the socket type.\n    int check_protocol (const std::string &protocol_) const;\n\n    //  Register the pipe with this socket.\n    void attach_pipe (zmq::pipe_t *pipe_,\n                      bool subscribe_to_all_ = false,\n                      bool locally_initiated_ = false);\n\n    //  Processes commands sent to this socket (if any). If timeout is -1,\n    //  returns only after at least one command was processed.\n    //  If throttle argument is true, commands are processed at most once\n    //  in a predefined time period.\n    int process_commands (int timeout_, bool throttle_);\n\n    //  Handlers for incoming commands.\n    void process_stop () ZMQ_FINAL;\n    void process_bind (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    void\n    process_pipe_stats_publish (uint64_t outbound_queue_count_,\n                                uint64_t inbound_queue_count_,\n                                endpoint_uri_pair_t *endpoint_pair_) ZMQ_FINAL;\n    void process_term (int linger_) ZMQ_FINAL;\n    void process_term_endpoint (std::string *endpoint_) ZMQ_FINAL;\n\n    void update_pipe_options (int option_);\n\n    std::string resolve_tcp_addr (std::string endpoint_uri_,\n                                  const char *tcp_address_);\n\n    //  Socket's mailbox object.\n    i_mailbox *_mailbox;\n\n    //  List of attached pipes.\n    typedef array_t<pipe_t, 3> pipes_t;\n    pipes_t _pipes;\n\n    //  Reaper's poller and handle of this socket within it.\n    poller_t *_poller;\n    poller_t::handle_t _handle;\n\n    //  Timestamp of when commands were processed the last time.\n    uint64_t _last_tsc;\n\n    //  Number of messages received since last command processing.\n    int _ticks;\n\n    //  True if the last message received had MORE flag set.\n    bool _rcvmore;\n\n    //  Improves efficiency of time measurement.\n    clock_t _clock;\n\n    // Monitor socket;\n    void *_monitor_socket;\n\n    // Bitmask of events being monitored\n    int64_t _monitor_events;\n\n    // Last socket endpoint resolved URI\n    std::string _last_endpoint;\n\n    // Indicate if the socket is thread safe\n    const bool _thread_safe;\n\n    // Signaler to be used in the reaping stage\n    signaler_t *_reaper_signaler;\n\n    // Mutex to synchronize access to the monitor Pair socket\n    mutex_t _monitor_sync;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (socket_base_t)\n\n    // Add a flag for mark disconnect action\n    bool _disconnected;\n};\n\nclass routing_socket_base_t : public socket_base_t\n{\n  protected:\n    routing_socket_base_t (class ctx_t *parent_, uint32_t tid_, int sid_);\n    ~routing_socket_base_t () ZMQ_OVERRIDE;\n\n    // methods from socket_base_t\n    int xsetsockopt (int option_,\n                     const void *optval_,\n                     size_t optvallen_) ZMQ_OVERRIDE;\n    void xwrite_activated (pipe_t *pipe_) ZMQ_FINAL;\n\n    // own methods\n    std::string extract_connect_routing_id ();\n    bool connect_routing_id_is_set () const;\n\n    struct out_pipe_t\n    {\n        pipe_t *pipe;\n        bool active;\n    };\n\n    void add_out_pipe (blob_t routing_id_, pipe_t *pipe_);\n    bool has_out_pipe (const blob_t &routing_id_) const;\n    out_pipe_t *lookup_out_pipe (const blob_t &routing_id_);\n    const out_pipe_t *lookup_out_pipe (const blob_t &routing_id_) const;\n    void erase_out_pipe (const pipe_t *pipe_);\n    out_pipe_t try_erase_out_pipe (const blob_t &routing_id_);\n    template <typename Func> bool any_of_out_pipes (Func func_)\n    {\n        bool res = false;\n        for (out_pipes_t::iterator it = _out_pipes.begin (),\n                                   end = _out_pipes.end ();\n             it != end && !res; ++it) {\n            res |= func_ (*it->second.pipe);\n        }\n\n        return res;\n    }\n\n  private:\n    //  Outbound pipes indexed by the peer IDs.\n    typedef std::map<blob_t, out_pipe_t> out_pipes_t;\n    out_pipes_t _out_pipes;\n\n    // Next assigned name on a zmq_connect() call used by ROUTER and STREAM socket types\n    std::string _connect_routing_id;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/socket_poller.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"socket_poller.hpp\"\n#include \"err.hpp\"\n#include \"polling_util.hpp\"\n#include \"macros.hpp\"\n\n#include <limits.h>\n\nstatic bool is_thread_safe (const zmq::socket_base_t &socket_)\n{\n    // do not use getsockopt here, since that would fail during context termination\n    return socket_.is_thread_safe ();\n}\n\n// compare elements to value\ntemplate <class It, class T, class Pred>\nstatic It find_if2 (It b_, It e_, const T &value, Pred pred)\n{\n    for (; b_ != e_; ++b_) {\n        if (pred (*b_, value)) {\n            break;\n        }\n    }\n    return b_;\n}\n\nzmq::socket_poller_t::socket_poller_t () :\n    _tag (0xCAFEBABE),\n    _signaler (NULL)\n#if defined ZMQ_POLL_BASED_ON_POLL\n    ,\n    _pollfds (NULL)\n#elif defined ZMQ_POLL_BASED_ON_SELECT\n    ,\n    _max_fd (0)\n#endif\n{\n    rebuild ();\n}\n\nzmq::socket_poller_t::~socket_poller_t ()\n{\n    //  Mark the socket_poller as dead\n    _tag = 0xdeadbeef;\n\n    for (items_t::iterator it = _items.begin (), end = _items.end (); it != end;\n         ++it) {\n        // TODO shouldn't this zmq_assert (it->socket->check_tag ()) instead?\n        if (it->socket && it->socket->check_tag ()\n            && is_thread_safe (*it->socket)) {\n            it->socket->remove_signaler (_signaler);\n        }\n    }\n\n    if (_signaler != NULL) {\n        LIBZMQ_DELETE (_signaler);\n    }\n\n#if defined ZMQ_POLL_BASED_ON_POLL\n    if (_pollfds) {\n        free (_pollfds);\n        _pollfds = NULL;\n    }\n#endif\n}\n\nbool zmq::socket_poller_t::check_tag () const\n{\n    return _tag == 0xCAFEBABE;\n}\n\nint zmq::socket_poller_t::signaler_fd (fd_t *fd_) const\n{\n    if (_signaler) {\n        *fd_ = _signaler->get_fd ();\n        return 0;\n    }\n    // Only thread-safe socket types are guaranteed to have a signaler.\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::socket_poller_t::add (socket_base_t *socket_,\n                               void *user_data_,\n                               short events_)\n{\n    if (find_if2 (_items.begin (), _items.end (), socket_, &is_socket)\n        != _items.end ()) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    if (is_thread_safe (*socket_)) {\n        if (_signaler == NULL) {\n            _signaler = new (std::nothrow) signaler_t ();\n            if (!_signaler) {\n                errno = ENOMEM;\n                return -1;\n            }\n            if (!_signaler->valid ()) {\n                delete _signaler;\n                _signaler = NULL;\n                errno = EMFILE;\n                return -1;\n            }\n        }\n\n        socket_->add_signaler (_signaler);\n    }\n\n    const item_t item = {socket_, 0, user_data_, events_\n#if defined ZMQ_POLL_BASED_ON_POLL\n                         ,\n                         -1\n#endif\n    };\n    try {\n        _items.push_back (item);\n    }\n    catch (const std::bad_alloc &) {\n        errno = ENOMEM;\n        return -1;\n    }\n    _need_rebuild = true;\n\n    return 0;\n}\n\nint zmq::socket_poller_t::add_fd (fd_t fd_, void *user_data_, short events_)\n{\n    if (find_if2 (_items.begin (), _items.end (), fd_, &is_fd)\n        != _items.end ()) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    const item_t item = {NULL, fd_, user_data_, events_\n#if defined ZMQ_POLL_BASED_ON_POLL\n                         ,\n                         -1\n#endif\n    };\n    try {\n        _items.push_back (item);\n    }\n    catch (const std::bad_alloc &) {\n        errno = ENOMEM;\n        return -1;\n    }\n    _need_rebuild = true;\n\n    return 0;\n}\n\nint zmq::socket_poller_t::modify (const socket_base_t *socket_, short events_)\n{\n    const items_t::iterator it =\n      find_if2 (_items.begin (), _items.end (), socket_, &is_socket);\n\n    if (it == _items.end ()) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    it->events = events_;\n    _need_rebuild = true;\n\n    return 0;\n}\n\n\nint zmq::socket_poller_t::modify_fd (fd_t fd_, short events_)\n{\n    const items_t::iterator it =\n      find_if2 (_items.begin (), _items.end (), fd_, &is_fd);\n\n    if (it == _items.end ()) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    it->events = events_;\n    _need_rebuild = true;\n\n    return 0;\n}\n\n\nint zmq::socket_poller_t::remove (socket_base_t *socket_)\n{\n    const items_t::iterator it =\n      find_if2 (_items.begin (), _items.end (), socket_, &is_socket);\n\n    if (it == _items.end ()) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    _items.erase (it);\n    _need_rebuild = true;\n\n    if (is_thread_safe (*socket_)) {\n        socket_->remove_signaler (_signaler);\n    }\n\n    return 0;\n}\n\nint zmq::socket_poller_t::remove_fd (fd_t fd_)\n{\n    const items_t::iterator it =\n      find_if2 (_items.begin (), _items.end (), fd_, &is_fd);\n\n    if (it == _items.end ()) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    _items.erase (it);\n    _need_rebuild = true;\n\n    return 0;\n}\n\nint zmq::socket_poller_t::rebuild ()\n{\n    _use_signaler = false;\n    _pollset_size = 0;\n    _need_rebuild = false;\n\n#if defined ZMQ_POLL_BASED_ON_POLL\n\n    if (_pollfds) {\n        free (_pollfds);\n        _pollfds = NULL;\n    }\n\n    for (items_t::iterator it = _items.begin (), end = _items.end (); it != end;\n         ++it) {\n        if (it->events) {\n            if (it->socket && is_thread_safe (*it->socket)) {\n                if (!_use_signaler) {\n                    _use_signaler = true;\n                    _pollset_size++;\n                }\n            } else\n                _pollset_size++;\n        }\n    }\n\n    if (_pollset_size == 0)\n        return 0;\n\n    _pollfds = static_cast<pollfd *> (malloc (_pollset_size * sizeof (pollfd)));\n\n    if (!_pollfds) {\n        errno = ENOMEM;\n        _need_rebuild = true;\n        return -1;\n    }\n\n    int item_nbr = 0;\n\n    if (_use_signaler) {\n        item_nbr = 1;\n        _pollfds[0].fd = _signaler->get_fd ();\n        _pollfds[0].events = POLLIN;\n    }\n\n    for (items_t::iterator it = _items.begin (), end = _items.end (); it != end;\n         ++it) {\n        if (it->events) {\n            if (it->socket) {\n                if (!is_thread_safe (*it->socket)) {\n                    size_t fd_size = sizeof (zmq::fd_t);\n                    const int rc = it->socket->getsockopt (\n                      ZMQ_FD, &_pollfds[item_nbr].fd, &fd_size);\n                    zmq_assert (rc == 0);\n\n                    _pollfds[item_nbr].events = POLLIN;\n                    item_nbr++;\n                }\n            } else {\n                _pollfds[item_nbr].fd = it->fd;\n                _pollfds[item_nbr].events =\n                  (it->events & ZMQ_POLLIN ? POLLIN : 0)\n                  | (it->events & ZMQ_POLLOUT ? POLLOUT : 0)\n                  | (it->events & ZMQ_POLLPRI ? POLLPRI : 0);\n                it->pollfd_index = item_nbr;\n                item_nbr++;\n            }\n        }\n    }\n\n#elif defined ZMQ_POLL_BASED_ON_SELECT\n\n    //  Ensure we do not attempt to select () on more than FD_SETSIZE\n    //  file descriptors.\n    zmq_assert (_items.size () <= FD_SETSIZE);\n\n    _pollset_in.resize (_items.size ());\n    _pollset_out.resize (_items.size ());\n    _pollset_err.resize (_items.size ());\n\n    FD_ZERO (_pollset_in.get ());\n    FD_ZERO (_pollset_out.get ());\n    FD_ZERO (_pollset_err.get ());\n\n    for (items_t::iterator it = _items.begin (), end = _items.end (); it != end;\n         ++it) {\n        if (it->socket && is_thread_safe (*it->socket) && it->events) {\n            _use_signaler = true;\n            FD_SET (_signaler->get_fd (), _pollset_in.get ());\n            _pollset_size = 1;\n            break;\n        }\n    }\n\n    _max_fd = 0;\n\n    //  Build the fd_sets for passing to select ().\n    for (items_t::iterator it = _items.begin (), end = _items.end (); it != end;\n         ++it) {\n        if (it->events) {\n            //  If the poll item is a 0MQ socket we are interested in input on the\n            //  notification file descriptor retrieved by the ZMQ_FD socket option.\n            if (it->socket) {\n                if (!is_thread_safe (*it->socket)) {\n                    zmq::fd_t notify_fd;\n                    size_t fd_size = sizeof (zmq::fd_t);\n                    int rc =\n                      it->socket->getsockopt (ZMQ_FD, &notify_fd, &fd_size);\n                    zmq_assert (rc == 0);\n\n                    FD_SET (notify_fd, _pollset_in.get ());\n                    if (_max_fd < notify_fd)\n                        _max_fd = notify_fd;\n\n                    _pollset_size++;\n                }\n            }\n            //  Else, the poll item is a raw file descriptor. Convert the poll item\n            //  events to the appropriate fd_sets.\n            else {\n                if (it->events & ZMQ_POLLIN)\n                    FD_SET (it->fd, _pollset_in.get ());\n                if (it->events & ZMQ_POLLOUT)\n                    FD_SET (it->fd, _pollset_out.get ());\n                if (it->events & ZMQ_POLLERR)\n                    FD_SET (it->fd, _pollset_err.get ());\n                if (_max_fd < it->fd)\n                    _max_fd = it->fd;\n\n                _pollset_size++;\n            }\n        }\n    }\n\n#endif\n\n    return 0;\n}\n\nvoid zmq::socket_poller_t::zero_trail_events (\n  zmq::socket_poller_t::event_t *events_, int n_events_, int found_)\n{\n    for (int i = found_; i < n_events_; ++i) {\n        events_[i].socket = NULL;\n        events_[i].fd = zmq::retired_fd;\n        events_[i].user_data = NULL;\n        events_[i].events = 0;\n    }\n}\n\n#if defined ZMQ_POLL_BASED_ON_POLL\nint zmq::socket_poller_t::check_events (zmq::socket_poller_t::event_t *events_,\n                                        int n_events_)\n#elif defined ZMQ_POLL_BASED_ON_SELECT\nint zmq::socket_poller_t::check_events (zmq::socket_poller_t::event_t *events_,\n                                        int n_events_,\n                                        fd_set &inset_,\n                                        fd_set &outset_,\n                                        fd_set &errset_)\n#endif\n{\n    int found = 0;\n    for (items_t::iterator it = _items.begin (), end = _items.end ();\n         it != end && found < n_events_; ++it) {\n        //  The poll item is a 0MQ socket. Retrieve pending events\n        //  using the ZMQ_EVENTS socket option.\n        if (it->socket) {\n            size_t events_size = sizeof (uint32_t);\n            uint32_t events;\n            if (it->socket->getsockopt (ZMQ_EVENTS, &events, &events_size)\n                == -1) {\n                return -1;\n            }\n\n            if (it->events & events) {\n                events_[found].socket = it->socket;\n                events_[found].fd = zmq::retired_fd;\n                events_[found].user_data = it->user_data;\n                events_[found].events = it->events & events;\n                ++found;\n            }\n        }\n        //  Else, the poll item is a raw file descriptor, simply convert\n        //  the events to zmq_pollitem_t-style format.\n        else if (it->events) {\n#if defined ZMQ_POLL_BASED_ON_POLL\n            zmq_assert (it->pollfd_index >= 0);\n            const short revents = _pollfds[it->pollfd_index].revents;\n            short events = 0;\n\n            if (revents & POLLIN)\n                events |= ZMQ_POLLIN;\n            if (revents & POLLOUT)\n                events |= ZMQ_POLLOUT;\n            if (revents & POLLPRI)\n                events |= ZMQ_POLLPRI;\n            if (revents & ~(POLLIN | POLLOUT | POLLPRI))\n                events |= ZMQ_POLLERR;\n\n#elif defined ZMQ_POLL_BASED_ON_SELECT\n\n            short events = 0;\n\n            if (FD_ISSET (it->fd, &inset_))\n                events |= ZMQ_POLLIN;\n            if (FD_ISSET (it->fd, &outset_))\n                events |= ZMQ_POLLOUT;\n            if (FD_ISSET (it->fd, &errset_))\n                events |= ZMQ_POLLERR;\n#endif //POLL_SELECT\n\n            if (events) {\n                events_[found].socket = NULL;\n                events_[found].fd = it->fd;\n                events_[found].user_data = it->user_data;\n                events_[found].events = events;\n                ++found;\n            }\n        }\n    }\n\n    return found;\n}\n\n//Return 0 if timeout is expired otherwise 1\nint zmq::socket_poller_t::adjust_timeout (zmq::clock_t &clock_,\n                                          long timeout_,\n                                          uint64_t &now_,\n                                          uint64_t &end_,\n                                          bool &first_pass_)\n{\n    //  If socket_poller_t::timeout is zero, exit immediately whether there\n    //  are events or not.\n    if (timeout_ == 0)\n        return 0;\n\n    //  At this point we are meant to wait for events but there are none.\n    //  If timeout is infinite we can just loop until we get some events.\n    if (timeout_ < 0) {\n        if (first_pass_)\n            first_pass_ = false;\n        return 1;\n    }\n\n    //  The timeout is finite and there are no events. In the first pass\n    //  we get a timestamp of when the polling have begun. (We assume that\n    //  first pass have taken negligible time). We also compute the time\n    //  when the polling should time out.\n    now_ = clock_.now_ms ();\n    if (first_pass_) {\n        end_ = now_ + timeout_;\n        first_pass_ = false;\n        return 1;\n    }\n\n    //  Find out whether timeout have expired.\n    if (now_ >= end_)\n        return 0;\n\n    return 1;\n}\n\nint zmq::socket_poller_t::wait (zmq::socket_poller_t::event_t *events_,\n                                int n_events_,\n                                long timeout_)\n{\n    if (_items.empty () && timeout_ < 0) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    if (_need_rebuild) {\n        const int rc = rebuild ();\n        if (rc == -1)\n            return -1;\n    }\n\n    if (unlikely (_pollset_size == 0)) {\n        if (timeout_ < 0) {\n            // Fail instead of trying to sleep forever\n            errno = EFAULT;\n            return -1;\n        }\n        // We'll report an error (timed out) as if the list was non-empty and\n        // no event occurred within the specified timeout. Otherwise the caller\n        // needs to check the return value AND the event to avoid using the\n        // nullified event data.\n        errno = EAGAIN;\n        if (timeout_ == 0)\n            return -1;\n#if defined ZMQ_HAVE_WINDOWS\n        Sleep (timeout_ > 0 ? timeout_ : INFINITE);\n        return -1;\n#elif defined ZMQ_HAVE_ANDROID\n        usleep (timeout_ * 1000);\n        return -1;\n#elif defined ZMQ_HAVE_OSX\n        usleep (timeout_ * 1000);\n        errno = EAGAIN;\n        return -1;\n#elif defined ZMQ_HAVE_VXWORKS\n        struct timespec ns_;\n        ns_.tv_sec = timeout_ / 1000;\n        ns_.tv_nsec = timeout_ % 1000 * 1000000;\n        nanosleep (&ns_, 0);\n        return -1;\n#else\n        usleep (timeout_ * 1000);\n        return -1;\n#endif\n    }\n\n#if defined ZMQ_POLL_BASED_ON_POLL\n    zmq::clock_t clock;\n    uint64_t now = 0;\n    uint64_t end = 0;\n\n    bool first_pass = true;\n\n    while (true) {\n        //  Compute the timeout for the subsequent poll.\n        int timeout;\n        if (first_pass)\n            timeout = 0;\n        else if (timeout_ < 0)\n            timeout = -1;\n        else\n            timeout =\n              static_cast<int> (std::min<uint64_t> (end - now, INT_MAX));\n\n        //  Wait for events.\n        const int rc = poll (_pollfds, _pollset_size, timeout);\n        if (rc == -1 && errno == EINTR) {\n            return -1;\n        }\n        errno_assert (rc >= 0);\n\n        //  Receive the signal from pollfd\n        if (_use_signaler && _pollfds[0].revents & POLLIN)\n            _signaler->recv ();\n\n        //  Check for the events.\n        const int found = check_events (events_, n_events_);\n        if (found) {\n            if (found > 0)\n                zero_trail_events (events_, n_events_, found);\n            return found;\n        }\n\n        //  Adjust timeout or break\n        if (adjust_timeout (clock, timeout_, now, end, first_pass) == 0)\n            break;\n    }\n    errno = EAGAIN;\n    return -1;\n\n#elif defined ZMQ_POLL_BASED_ON_SELECT\n\n    zmq::clock_t clock;\n    uint64_t now = 0;\n    uint64_t end = 0;\n\n    bool first_pass = true;\n\n    optimized_fd_set_t inset (_pollset_size);\n    optimized_fd_set_t outset (_pollset_size);\n    optimized_fd_set_t errset (_pollset_size);\n\n    while (true) {\n        //  Compute the timeout for the subsequent poll.\n        timeval timeout;\n        timeval *ptimeout;\n        if (first_pass) {\n            timeout.tv_sec = 0;\n            timeout.tv_usec = 0;\n            ptimeout = &timeout;\n        } else if (timeout_ < 0)\n            ptimeout = NULL;\n        else {\n            timeout.tv_sec = static_cast<long> ((end - now) / 1000);\n            timeout.tv_usec = static_cast<long> ((end - now) % 1000 * 1000);\n            ptimeout = &timeout;\n        }\n\n        //  Wait for events. Ignore interrupts if there's infinite timeout.\n        memcpy (inset.get (), _pollset_in.get (),\n                valid_pollset_bytes (*_pollset_in.get ()));\n        memcpy (outset.get (), _pollset_out.get (),\n                valid_pollset_bytes (*_pollset_out.get ()));\n        memcpy (errset.get (), _pollset_err.get (),\n                valid_pollset_bytes (*_pollset_err.get ()));\n        const int rc = select (static_cast<int> (_max_fd + 1), inset.get (),\n                               outset.get (), errset.get (), ptimeout);\n#if defined ZMQ_HAVE_WINDOWS\n        if (unlikely (rc == SOCKET_ERROR)) {\n            errno = wsa_error_to_errno (WSAGetLastError ());\n            wsa_assert (errno == ENOTSOCK);\n            return -1;\n        }\n#else\n        if (unlikely (rc == -1)) {\n            errno_assert (errno == EINTR || errno == EBADF);\n            return -1;\n        }\n#endif\n\n        if (_use_signaler && FD_ISSET (_signaler->get_fd (), inset.get ()))\n            _signaler->recv ();\n\n        //  Check for the events.\n        const int found = check_events (events_, n_events_, *inset.get (),\n                                        *outset.get (), *errset.get ());\n        if (found) {\n            if (found > 0)\n                zero_trail_events (events_, n_events_, found);\n            return found;\n        }\n\n        //  Adjust timeout or break\n        if (adjust_timeout (clock, timeout_, now, end, first_pass) == 0)\n            break;\n    }\n\n    errno = EAGAIN;\n    return -1;\n\n#else\n\n    //  Exotic platforms that support neither poll() nor select().\n    errno = ENOTSUP;\n    return -1;\n\n#endif\n}\n"
  },
  {
    "path": "src/socket_poller.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SOCKET_POLLER_HPP_INCLUDED__\n#define __ZMQ_SOCKET_POLLER_HPP_INCLUDED__\n\n#include \"poller.hpp\"\n\n#if defined ZMQ_POLL_BASED_ON_POLL && !defined ZMQ_HAVE_WINDOWS\n#include <poll.h>\n#endif\n\n#if defined ZMQ_HAVE_WINDOWS\n#include \"windows.hpp\"\n#elif defined ZMQ_HAVE_VXWORKS\n#include <unistd.h>\n#include <sys/time.h>\n#include <strings.h>\n#else\n#include <unistd.h>\n#endif\n\n#include <vector>\n\n#include \"socket_base.hpp\"\n#include \"signaler.hpp\"\n#include \"polling_util.hpp\"\n\nnamespace zmq\n{\nclass socket_poller_t\n{\n  public:\n    socket_poller_t ();\n    ~socket_poller_t ();\n\n    typedef zmq_poller_event_t event_t;\n\n    int add (socket_base_t *socket_, void *user_data_, short events_);\n    int modify (const socket_base_t *socket_, short events_);\n    int remove (socket_base_t *socket_);\n\n    int add_fd (fd_t fd_, void *user_data_, short events_);\n    int modify_fd (fd_t fd_, short events_);\n    int remove_fd (fd_t fd_);\n    // Returns the signaler's fd if there is one, otherwise errors.\n    int signaler_fd (fd_t *fd_) const;\n\n    int wait (event_t *events_, int n_events_, long timeout_);\n\n    int size () const { return static_cast<int> (_items.size ()); };\n\n    //  Return false if object is not a socket.\n    bool check_tag () const;\n\n  private:\n    typedef struct item_t\n    {\n        socket_base_t *socket;\n        fd_t fd;\n        void *user_data;\n        short events;\n#if defined ZMQ_POLL_BASED_ON_POLL\n        int pollfd_index;\n#endif\n    } item_t;\n\n    static void zero_trail_events (zmq::socket_poller_t::event_t *events_,\n                                   int n_events_,\n                                   int found_);\n#if defined ZMQ_POLL_BASED_ON_POLL\n    int check_events (zmq::socket_poller_t::event_t *events_, int n_events_);\n#elif defined ZMQ_POLL_BASED_ON_SELECT\n    int check_events (zmq::socket_poller_t::event_t *events_,\n                      int n_events_,\n                      fd_set &inset_,\n                      fd_set &outset_,\n                      fd_set &errset_);\n#endif\n    static int adjust_timeout (zmq::clock_t &clock_,\n                               long timeout_,\n                               uint64_t &now_,\n                               uint64_t &end_,\n                               bool &first_pass_);\n    static bool is_socket (const item_t &item, const socket_base_t *socket_)\n    {\n        return item.socket == socket_;\n    }\n    static bool is_fd (const item_t &item, fd_t fd_)\n    {\n        return !item.socket && item.fd == fd_;\n    }\n\n    int rebuild ();\n\n    //  Used to check whether the object is a socket_poller.\n    uint32_t _tag;\n\n    //  Signaler used for thread safe sockets polling\n    signaler_t *_signaler;\n\n    //  List of sockets\n    typedef std::vector<item_t> items_t;\n    items_t _items;\n\n    //  Does the pollset needs rebuilding?\n    bool _need_rebuild;\n\n    //  Should the signaler be used for the thread safe polling?\n    bool _use_signaler;\n\n    //  Size of the pollset\n    int _pollset_size;\n\n#if defined ZMQ_POLL_BASED_ON_POLL\n    pollfd *_pollfds;\n#elif defined ZMQ_POLL_BASED_ON_SELECT\n    resizable_optimized_fd_set_t _pollset_in;\n    resizable_optimized_fd_set_t _pollset_out;\n    resizable_optimized_fd_set_t _pollset_err;\n    zmq::fd_t _max_fd;\n#endif\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (socket_poller_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/socks.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <sys/types.h>\n\n#include \"err.hpp\"\n#include \"socks.hpp\"\n#include \"tcp.hpp\"\n#include \"blob.hpp\"\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netdb.h>\n#endif\n\nzmq::socks_greeting_t::socks_greeting_t (uint8_t method_) : num_methods (1)\n{\n    methods[0] = method_;\n}\n\nzmq::socks_greeting_t::socks_greeting_t (const uint8_t *methods_,\n                                         uint8_t num_methods_) :\n    num_methods (num_methods_)\n{\n    for (uint8_t i = 0; i < num_methods_; i++)\n        methods[i] = methods_[i];\n}\n\nzmq::socks_greeting_encoder_t::socks_greeting_encoder_t () :\n    _bytes_encoded (0), _bytes_written (0)\n{\n}\n\nvoid zmq::socks_greeting_encoder_t::encode (const socks_greeting_t &greeting_)\n{\n    uint8_t *ptr = _buf;\n\n    *ptr++ = 0x05;\n    *ptr++ = static_cast<uint8_t> (greeting_.num_methods);\n    for (uint8_t i = 0; i < greeting_.num_methods; i++)\n        *ptr++ = greeting_.methods[i];\n\n    _bytes_encoded = 2 + greeting_.num_methods;\n    _bytes_written = 0;\n}\n\nint zmq::socks_greeting_encoder_t::output (fd_t fd_)\n{\n    const int rc =\n      tcp_write (fd_, _buf + _bytes_written, _bytes_encoded - _bytes_written);\n    if (rc > 0)\n        _bytes_written += static_cast<size_t> (rc);\n    return rc;\n}\n\nbool zmq::socks_greeting_encoder_t::has_pending_data () const\n{\n    return _bytes_written < _bytes_encoded;\n}\n\nvoid zmq::socks_greeting_encoder_t::reset ()\n{\n    _bytes_encoded = _bytes_written = 0;\n}\n\nzmq::socks_choice_t::socks_choice_t (unsigned char method_) : method (method_)\n{\n}\n\nzmq::socks_choice_decoder_t::socks_choice_decoder_t () : _bytes_read (0)\n{\n}\n\nint zmq::socks_choice_decoder_t::input (fd_t fd_)\n{\n    zmq_assert (_bytes_read < 2);\n    const int rc = tcp_read (fd_, _buf + _bytes_read, 2 - _bytes_read);\n    if (rc > 0) {\n        _bytes_read += static_cast<size_t> (rc);\n        if (_buf[0] != 0x05)\n            return -1;\n    }\n    return rc;\n}\n\nbool zmq::socks_choice_decoder_t::message_ready () const\n{\n    return _bytes_read == 2;\n}\n\nzmq::socks_choice_t zmq::socks_choice_decoder_t::decode ()\n{\n    zmq_assert (message_ready ());\n    return socks_choice_t (_buf[1]);\n}\n\nvoid zmq::socks_choice_decoder_t::reset ()\n{\n    _bytes_read = 0;\n}\n\n\nzmq::socks_basic_auth_request_t::socks_basic_auth_request_t (\n  const std::string &username_, const std::string &password_) :\n    username (username_), password (password_)\n{\n    zmq_assert (username_.size () <= UINT8_MAX);\n    zmq_assert (password_.size () <= UINT8_MAX);\n}\n\n\nzmq::socks_basic_auth_request_encoder_t::socks_basic_auth_request_encoder_t () :\n    _bytes_encoded (0), _bytes_written (0)\n{\n}\n\nvoid zmq::socks_basic_auth_request_encoder_t::encode (\n  const socks_basic_auth_request_t &req_)\n{\n    unsigned char *ptr = _buf;\n    *ptr++ = 0x01;\n    *ptr++ = static_cast<unsigned char> (req_.username.size ());\n    memcpy (ptr, req_.username.c_str (), req_.username.size ());\n    ptr += req_.username.size ();\n    *ptr++ = static_cast<unsigned char> (req_.password.size ());\n    memcpy (ptr, req_.password.c_str (), req_.password.size ());\n    ptr += req_.password.size ();\n\n    _bytes_encoded = ptr - _buf;\n    _bytes_written = 0;\n}\n\nint zmq::socks_basic_auth_request_encoder_t::output (fd_t fd_)\n{\n    const int rc =\n      tcp_write (fd_, _buf + _bytes_written, _bytes_encoded - _bytes_written);\n    if (rc > 0)\n        _bytes_written += static_cast<size_t> (rc);\n    return rc;\n}\n\nbool zmq::socks_basic_auth_request_encoder_t::has_pending_data () const\n{\n    return _bytes_written < _bytes_encoded;\n}\n\nvoid zmq::socks_basic_auth_request_encoder_t::reset ()\n{\n    _bytes_encoded = _bytes_written = 0;\n}\n\n\nzmq::socks_auth_response_t::socks_auth_response_t (uint8_t response_code_) :\n    response_code (response_code_)\n{\n}\n\nzmq::socks_auth_response_decoder_t::socks_auth_response_decoder_t () :\n    _bytes_read (0)\n{\n}\n\nint zmq::socks_auth_response_decoder_t::input (fd_t fd_)\n{\n    zmq_assert (_bytes_read < 2);\n    const int rc = tcp_read (fd_, _buf + _bytes_read, 2 - _bytes_read);\n    if (rc > 0) {\n        _bytes_read += static_cast<size_t> (rc);\n        if (_buf[0] != 0x01)\n            return -1;\n    }\n    return rc;\n}\n\nbool zmq::socks_auth_response_decoder_t::message_ready () const\n{\n    return _bytes_read == 2;\n}\n\nzmq::socks_auth_response_t zmq::socks_auth_response_decoder_t::decode ()\n{\n    zmq_assert (message_ready ());\n    return socks_auth_response_t (_buf[1]);\n}\n\nvoid zmq::socks_auth_response_decoder_t::reset ()\n{\n    _bytes_read = 0;\n}\n\n\nzmq::socks_request_t::socks_request_t (uint8_t command_,\n                                       std::string hostname_,\n                                       uint16_t port_) :\n    command (command_), hostname (ZMQ_MOVE (hostname_)), port (port_)\n{\n    zmq_assert (hostname.size () <= UINT8_MAX);\n}\n\nzmq::socks_request_encoder_t::socks_request_encoder_t () :\n    _bytes_encoded (0), _bytes_written (0)\n{\n}\n\nvoid zmq::socks_request_encoder_t::encode (const socks_request_t &req_)\n{\n    zmq_assert (req_.hostname.size () <= UINT8_MAX);\n\n    unsigned char *ptr = _buf;\n    *ptr++ = 0x05;\n    *ptr++ = req_.command;\n    *ptr++ = 0x00;\n\n#if defined ZMQ_HAVE_OPENVMS && defined __ia64 && __INITIAL_POINTER_SIZE == 64\n    __addrinfo64 hints, *res = NULL;\n#else\n    addrinfo hints, *res = NULL;\n#endif\n\n    memset (&hints, 0, sizeof hints);\n\n    //  Suppress potential DNS lookups.\n    hints.ai_flags = AI_NUMERICHOST;\n\n    const int rc = getaddrinfo (req_.hostname.c_str (), NULL, &hints, &res);\n    if (rc == 0 && res->ai_family == AF_INET) {\n        const struct sockaddr_in *sockaddr_in =\n          reinterpret_cast<const struct sockaddr_in *> (res->ai_addr);\n        *ptr++ = 0x01;\n        memcpy (ptr, &sockaddr_in->sin_addr, 4);\n        ptr += 4;\n    } else if (rc == 0 && res->ai_family == AF_INET6) {\n        const struct sockaddr_in6 *sockaddr_in6 =\n          reinterpret_cast<const struct sockaddr_in6 *> (res->ai_addr);\n        *ptr++ = 0x04;\n        memcpy (ptr, &sockaddr_in6->sin6_addr, 16);\n        ptr += 16;\n    } else {\n        *ptr++ = 0x03;\n        *ptr++ = static_cast<unsigned char> (req_.hostname.size ());\n        memcpy (ptr, req_.hostname.c_str (), req_.hostname.size ());\n        ptr += req_.hostname.size ();\n    }\n\n    if (rc == 0)\n        freeaddrinfo (res);\n\n    *ptr++ = req_.port / 256;\n    *ptr++ = req_.port % 256;\n\n    _bytes_encoded = ptr - _buf;\n    _bytes_written = 0;\n}\n\nint zmq::socks_request_encoder_t::output (fd_t fd_)\n{\n    const int rc =\n      tcp_write (fd_, _buf + _bytes_written, _bytes_encoded - _bytes_written);\n    if (rc > 0)\n        _bytes_written += static_cast<size_t> (rc);\n    return rc;\n}\n\nbool zmq::socks_request_encoder_t::has_pending_data () const\n{\n    return _bytes_written < _bytes_encoded;\n}\n\nvoid zmq::socks_request_encoder_t::reset ()\n{\n    _bytes_encoded = _bytes_written = 0;\n}\n\nzmq::socks_response_t::socks_response_t (uint8_t response_code_,\n                                         const std::string &address_,\n                                         uint16_t port_) :\n    response_code (response_code_), address (address_), port (port_)\n{\n}\n\nzmq::socks_response_decoder_t::socks_response_decoder_t () : _bytes_read (0)\n{\n}\n\nint zmq::socks_response_decoder_t::input (fd_t fd_)\n{\n    size_t n = 0;\n\n    if (_bytes_read < 5)\n        n = 5 - _bytes_read;\n    else {\n        const uint8_t atyp = _buf[3];\n        zmq_assert (atyp == 0x01 || atyp == 0x03 || atyp == 0x04);\n        if (atyp == 0x01)\n            n = 3 + 2;\n        else if (atyp == 0x03)\n            n = _buf[4] + 2;\n        else if (atyp == 0x04)\n            n = 15 + 2;\n    }\n    const int rc = tcp_read (fd_, _buf + _bytes_read, n);\n    if (rc > 0) {\n        _bytes_read += static_cast<size_t> (rc);\n        if (_buf[0] != 0x05)\n            return -1;\n        if (_bytes_read >= 2)\n            if (_buf[1] > 0x08)\n                return -1;\n        if (_bytes_read >= 3)\n            if (_buf[2] != 0x00)\n                return -1;\n        if (_bytes_read >= 4) {\n            const uint8_t atyp = _buf[3];\n            if (atyp != 0x01 && atyp != 0x03 && atyp != 0x04)\n                return -1;\n        }\n    }\n    return rc;\n}\n\nbool zmq::socks_response_decoder_t::message_ready () const\n{\n    if (_bytes_read < 4)\n        return false;\n\n    const uint8_t atyp = _buf[3];\n    zmq_assert (atyp == 0x01 || atyp == 0x03 || atyp == 0x04);\n    if (atyp == 0x01)\n        return _bytes_read == 10;\n    if (atyp == 0x03)\n        return _bytes_read > 4 && _bytes_read == 4 + 1 + _buf[4] + 2u;\n\n    return _bytes_read == 22;\n}\n\nzmq::socks_response_t zmq::socks_response_decoder_t::decode ()\n{\n    zmq_assert (message_ready ());\n    return socks_response_t (_buf[1], \"\", 0);\n}\n\nvoid zmq::socks_response_decoder_t::reset ()\n{\n    _bytes_read = 0;\n}\n"
  },
  {
    "path": "src/socks.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SOCKS_HPP_INCLUDED__\n#define __ZMQ_SOCKS_HPP_INCLUDED__\n\n#include <string>\n#include \"fd.hpp\"\n#include \"stdint.hpp\"\n\nnamespace zmq\n{\nstruct socks_greeting_t\n{\n    socks_greeting_t (uint8_t method_);\n    socks_greeting_t (const uint8_t *methods_, uint8_t num_methods_);\n\n    uint8_t methods[UINT8_MAX];\n    const size_t num_methods;\n};\n\nclass socks_greeting_encoder_t\n{\n  public:\n    socks_greeting_encoder_t ();\n    void encode (const socks_greeting_t &greeting_);\n    int output (fd_t fd_);\n    bool has_pending_data () const;\n    void reset ();\n\n  private:\n    size_t _bytes_encoded;\n    size_t _bytes_written;\n    uint8_t _buf[2 + UINT8_MAX];\n};\n\nstruct socks_choice_t\n{\n    socks_choice_t (uint8_t method_);\n\n    uint8_t method;\n};\n\nclass socks_choice_decoder_t\n{\n  public:\n    socks_choice_decoder_t ();\n    int input (fd_t fd_);\n    bool message_ready () const;\n    socks_choice_t decode ();\n    void reset ();\n\n  private:\n    unsigned char _buf[2];\n    size_t _bytes_read;\n};\n\n\nstruct socks_basic_auth_request_t\n{\n    socks_basic_auth_request_t (const std::string &username_,\n                                const std::string &password_);\n\n    const std::string username;\n    const std::string password;\n};\n\nclass socks_basic_auth_request_encoder_t\n{\n  public:\n    socks_basic_auth_request_encoder_t ();\n    void encode (const socks_basic_auth_request_t &req_);\n    int output (fd_t fd_);\n    bool has_pending_data () const;\n    void reset ();\n\n  private:\n    size_t _bytes_encoded;\n    size_t _bytes_written;\n    uint8_t _buf[1 + 1 + UINT8_MAX + 1 + UINT8_MAX];\n};\n\nstruct socks_auth_response_t\n{\n    socks_auth_response_t (uint8_t response_code_);\n    uint8_t response_code;\n};\n\nclass socks_auth_response_decoder_t\n{\n  public:\n    socks_auth_response_decoder_t ();\n    int input (fd_t fd_);\n    bool message_ready () const;\n    socks_auth_response_t decode ();\n    void reset ();\n\n  private:\n    int8_t _buf[2];\n    size_t _bytes_read;\n};\n\nstruct socks_request_t\n{\n    socks_request_t (uint8_t command_, std::string hostname_, uint16_t port_);\n\n    const uint8_t command;\n    const std::string hostname;\n    const uint16_t port;\n};\n\nclass socks_request_encoder_t\n{\n  public:\n    socks_request_encoder_t ();\n    void encode (const socks_request_t &req_);\n    int output (fd_t fd_);\n    bool has_pending_data () const;\n    void reset ();\n\n  private:\n    size_t _bytes_encoded;\n    size_t _bytes_written;\n    uint8_t _buf[4 + UINT8_MAX + 1 + 2];\n};\n\nstruct socks_response_t\n{\n    socks_response_t (uint8_t response_code_,\n                      const std::string &address_,\n                      uint16_t port_);\n    uint8_t response_code;\n    std::string address;\n    uint16_t port;\n};\n\nclass socks_response_decoder_t\n{\n  public:\n    socks_response_decoder_t ();\n    int input (fd_t fd_);\n    bool message_ready () const;\n    socks_response_t decode ();\n    void reset ();\n\n  private:\n    int8_t _buf[4 + UINT8_MAX + 1 + 2];\n    size_t _bytes_read;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/socks_connecter.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <new>\n#include <string>\n\n#include \"macros.hpp\"\n#include \"socks_connecter.hpp\"\n#include \"random.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"tcp.hpp\"\n#include \"address.hpp\"\n#include \"tcp_address.hpp\"\n#include \"session_base.hpp\"\n#include \"socks.hpp\"\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#if defined ZMQ_HAVE_VXWORKS\n#include <sockLib.h>\n#endif\n#endif\n\nzmq::socks_connecter_t::socks_connecter_t (class io_thread_t *io_thread_,\n                                           class session_base_t *session_,\n                                           const options_t &options_,\n                                           address_t *addr_,\n                                           address_t *proxy_addr_,\n                                           bool delayed_start_) :\n    stream_connecter_base_t (\n      io_thread_, session_, options_, addr_, delayed_start_),\n    _proxy_addr (proxy_addr_),\n    _auth_method (socks_no_auth_required),\n    _status (unplugged)\n{\n    zmq_assert (_addr->protocol == protocol_name::tcp);\n    _proxy_addr->to_string (_endpoint);\n}\n\nzmq::socks_connecter_t::~socks_connecter_t ()\n{\n    LIBZMQ_DELETE (_proxy_addr);\n}\n\nvoid zmq::socks_connecter_t::set_auth_method_none ()\n{\n    _auth_method = socks_no_auth_required;\n    _auth_username.clear ();\n    _auth_password.clear ();\n}\n\nvoid zmq::socks_connecter_t::set_auth_method_basic (\n  const std::string &username_, const std::string &password_)\n{\n    _auth_method = socks_basic_auth;\n    _auth_username = username_;\n    _auth_password = password_;\n}\n\nvoid zmq::socks_connecter_t::in_event ()\n{\n    int expected_status = -1;\n    zmq_assert (_status != unplugged);\n\n    if (_status == waiting_for_choice) {\n        int rc = _choice_decoder.input (_s);\n        if (rc == 0 || rc == -1)\n            error ();\n        else if (_choice_decoder.message_ready ()) {\n            const socks_choice_t choice = _choice_decoder.decode ();\n            rc = process_server_response (choice);\n            if (rc == -1)\n                error ();\n            else {\n                if (choice.method == socks_basic_auth)\n                    expected_status = sending_basic_auth_request;\n                else\n                    expected_status = sending_request;\n            }\n        }\n    } else if (_status == waiting_for_auth_response) {\n        int rc = _auth_response_decoder.input (_s);\n        if (rc == 0 || rc == -1)\n            error ();\n        else if (_auth_response_decoder.message_ready ()) {\n            const socks_auth_response_t auth_response =\n              _auth_response_decoder.decode ();\n            rc = process_server_response (auth_response);\n            if (rc == -1)\n                error ();\n            else {\n                expected_status = sending_request;\n            }\n        }\n    } else if (_status == waiting_for_response) {\n        int rc = _response_decoder.input (_s);\n        if (rc == 0 || rc == -1)\n            error ();\n        else if (_response_decoder.message_ready ()) {\n            const socks_response_t response = _response_decoder.decode ();\n            rc = process_server_response (response);\n            if (rc == -1)\n                error ();\n            else {\n                rm_handle ();\n                create_engine (\n                  _s, get_socket_name<tcp_address_t> (_s, socket_end_local));\n                _s = -1;\n                _status = unplugged;\n            }\n        }\n    } else\n        error ();\n\n    if (expected_status == sending_basic_auth_request) {\n        _basic_auth_request_encoder.encode (\n          socks_basic_auth_request_t (_auth_username, _auth_password));\n        reset_pollin (_handle);\n        set_pollout (_handle);\n        _status = sending_basic_auth_request;\n    } else if (expected_status == sending_request) {\n        std::string hostname;\n        uint16_t port = 0;\n        if (parse_address (_addr->address, hostname, port) == -1)\n            error ();\n        else {\n            _request_encoder.encode (socks_request_t (1, hostname, port));\n            reset_pollin (_handle);\n            set_pollout (_handle);\n            _status = sending_request;\n        }\n    }\n}\n\nvoid zmq::socks_connecter_t::out_event ()\n{\n    zmq_assert (\n      _status == waiting_for_proxy_connection || _status == sending_greeting\n      || _status == sending_basic_auth_request || _status == sending_request);\n\n    if (_status == waiting_for_proxy_connection) {\n        const int rc = static_cast<int> (check_proxy_connection ());\n        if (rc == -1)\n            error ();\n        else {\n            _greeting_encoder.encode (socks_greeting_t (_auth_method));\n            _status = sending_greeting;\n        }\n    } else if (_status == sending_greeting) {\n        zmq_assert (_greeting_encoder.has_pending_data ());\n        const int rc = _greeting_encoder.output (_s);\n        if (rc == -1 || rc == 0)\n            error ();\n        else if (!_greeting_encoder.has_pending_data ()) {\n            reset_pollout (_handle);\n            set_pollin (_handle);\n            _status = waiting_for_choice;\n        }\n    } else if (_status == sending_basic_auth_request) {\n        zmq_assert (_basic_auth_request_encoder.has_pending_data ());\n        const int rc = _basic_auth_request_encoder.output (_s);\n        if (rc == -1 || rc == 0)\n            error ();\n        else if (!_basic_auth_request_encoder.has_pending_data ()) {\n            reset_pollout (_handle);\n            set_pollin (_handle);\n            _status = waiting_for_auth_response;\n        }\n    } else {\n        zmq_assert (_request_encoder.has_pending_data ());\n        const int rc = _request_encoder.output (_s);\n        if (rc == -1 || rc == 0)\n            error ();\n        else if (!_request_encoder.has_pending_data ()) {\n            reset_pollout (_handle);\n            set_pollin (_handle);\n            _status = waiting_for_response;\n        }\n    }\n}\n\nvoid zmq::socks_connecter_t::start_connecting ()\n{\n    zmq_assert (_status == unplugged);\n\n    //  Open the connecting socket.\n    const int rc = connect_to_proxy ();\n\n    //  Connect may succeed in synchronous manner.\n    if (rc == 0) {\n        _handle = add_fd (_s);\n        set_pollout (_handle);\n        _status = sending_greeting;\n    }\n    //  Connection establishment may be delayed. Poll for its completion.\n    else if (errno == EINPROGRESS) {\n        _handle = add_fd (_s);\n        set_pollout (_handle);\n        _status = waiting_for_proxy_connection;\n        _socket->event_connect_delayed (\n          make_unconnected_connect_endpoint_pair (_endpoint), zmq_errno ());\n    }\n    //  Handle any other error condition by eventual reconnect.\n    else {\n        if (_s != retired_fd)\n            close ();\n        add_reconnect_timer ();\n    }\n}\n\nint zmq::socks_connecter_t::process_server_response (\n  const socks_choice_t &response_)\n{\n    return response_.method == socks_no_auth_required\n               || response_.method == socks_basic_auth\n             ? 0\n             : -1;\n}\n\nint zmq::socks_connecter_t::process_server_response (\n  const socks_response_t &response_)\n{\n    return response_.response_code == 0 ? 0 : -1;\n}\n\nint zmq::socks_connecter_t::process_server_response (\n  const socks_auth_response_t &response_)\n{\n    return response_.response_code == 0 ? 0 : -1;\n}\n\nvoid zmq::socks_connecter_t::error ()\n{\n    rm_fd (_handle);\n    close ();\n    _greeting_encoder.reset ();\n    _choice_decoder.reset ();\n    _basic_auth_request_encoder.reset ();\n    _auth_response_decoder.reset ();\n    _request_encoder.reset ();\n    _response_decoder.reset ();\n    _status = unplugged;\n    add_reconnect_timer ();\n}\n\nint zmq::socks_connecter_t::connect_to_proxy ()\n{\n    zmq_assert (_s == retired_fd);\n\n    //  Resolve the address\n    if (_proxy_addr->resolved.tcp_addr != NULL) {\n        LIBZMQ_DELETE (_proxy_addr->resolved.tcp_addr);\n    }\n\n    _proxy_addr->resolved.tcp_addr = new (std::nothrow) tcp_address_t ();\n    alloc_assert (_proxy_addr->resolved.tcp_addr);\n    //  Automatic fallback to ipv4 is disabled here since this was the existing\n    //  behaviour, however I don't see a real reason for this. Maybe this can\n    //  be changed to true (and then the parameter can be removed entirely).\n    _s = tcp_open_socket (_proxy_addr->address.c_str (), options, false, false,\n                          _proxy_addr->resolved.tcp_addr);\n    if (_s == retired_fd) {\n        //  TODO we should emit some event in this case!\n        LIBZMQ_DELETE (_proxy_addr->resolved.tcp_addr);\n        return -1;\n    }\n    zmq_assert (_proxy_addr->resolved.tcp_addr != NULL);\n\n    // Set the socket to non-blocking mode so that we get async connect().\n    unblock_socket (_s);\n\n    const tcp_address_t *const tcp_addr = _proxy_addr->resolved.tcp_addr;\n\n    int rc;\n\n    // Set a source address for conversations\n    if (tcp_addr->has_src_addr ()) {\n#if defined ZMQ_HAVE_VXWORKS\n        rc = ::bind (_s, (sockaddr *) tcp_addr->src_addr (),\n                     tcp_addr->src_addrlen ());\n#else\n        rc = ::bind (_s, tcp_addr->src_addr (), tcp_addr->src_addrlen ());\n#endif\n        if (rc == -1) {\n            close ();\n            return -1;\n        }\n    }\n\n    //  Connect to the remote peer.\n#if defined ZMQ_HAVE_VXWORKS\n    rc = ::connect (_s, (sockaddr *) tcp_addr->addr (), tcp_addr->addrlen ());\n#else\n    rc = ::connect (_s, tcp_addr->addr (), tcp_addr->addrlen ());\n#endif\n    //  Connect was successful immediately.\n    if (rc == 0)\n        return 0;\n\n        //  Translate error codes indicating asynchronous connect has been\n        //  launched to a uniform EINPROGRESS.\n#ifdef ZMQ_HAVE_WINDOWS\n    const int last_error = WSAGetLastError ();\n    if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK)\n        errno = EINPROGRESS;\n    else {\n        errno = wsa_error_to_errno (last_error);\n        close ();\n    }\n#else\n    if (errno == EINTR)\n        errno = EINPROGRESS;\n#endif\n    return -1;\n}\n\nzmq::fd_t zmq::socks_connecter_t::check_proxy_connection () const\n{\n    //  Async connect has finished. Check whether an error occurred\n    int err = 0;\n#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS\n    int len = sizeof err;\n#else\n    socklen_t len = sizeof err;\n#endif\n\n    int rc = getsockopt (_s, SOL_SOCKET, SO_ERROR,\n                         reinterpret_cast<char *> (&err), &len);\n\n    //  Assert if the error was caused by 0MQ bug.\n    //  Networking problems are OK. No need to assert.\n#ifdef ZMQ_HAVE_WINDOWS\n    zmq_assert (rc == 0);\n    if (err != 0) {\n        wsa_assert (err == WSAECONNREFUSED || err == WSAETIMEDOUT\n                    || err == WSAECONNABORTED || err == WSAEHOSTUNREACH\n                    || err == WSAENETUNREACH || err == WSAENETDOWN\n                    || err == WSAEACCES || err == WSAEINVAL\n                    || err == WSAEADDRINUSE);\n        return -1;\n    }\n#else\n    //  Following code should handle both Berkeley-derived socket\n    //  implementations and Solaris.\n    if (rc == -1)\n        err = errno;\n    if (err != 0) {\n        errno = err;\n        errno_assert (errno == ECONNREFUSED || errno == ECONNRESET\n                      || errno == ETIMEDOUT || errno == EHOSTUNREACH\n                      || errno == ENETUNREACH || errno == ENETDOWN\n                      || errno == EINVAL);\n        return -1;\n    }\n#endif\n\n    rc = tune_tcp_socket (_s);\n    rc = rc\n         | tune_tcp_keepalives (\n           _s, options.tcp_keepalive, options.tcp_keepalive_cnt,\n           options.tcp_keepalive_idle, options.tcp_keepalive_intvl);\n    if (rc != 0)\n        return -1;\n\n    return 0;\n}\n\nint zmq::socks_connecter_t::parse_address (const std::string &address_,\n                                           std::string &hostname_,\n                                           uint16_t &port_)\n{\n    //  Find the ':' at end that separates address from the port number.\n    const size_t idx = address_.rfind (':');\n    if (idx == std::string::npos) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    //  Extract hostname\n    if (idx < 2 || address_[0] != '[' || address_[idx - 1] != ']')\n        hostname_ = address_.substr (0, idx);\n    else\n        hostname_ = address_.substr (1, idx - 2);\n\n    //  Separate the hostname/port.\n    const std::string port_str = address_.substr (idx + 1);\n    //  Parse the port number (0 is not a valid port).\n    port_ = static_cast<uint16_t> (atoi (port_str.c_str ()));\n    if (port_ == 0) {\n        errno = EINVAL;\n        return -1;\n    }\n    return 0;\n}\n"
  },
  {
    "path": "src/socks_connecter.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __SOCKS_CONNECTER_HPP_INCLUDED__\n#define __SOCKS_CONNECTER_HPP_INCLUDED__\n\n#include \"fd.hpp\"\n#include \"stream_connecter_base.hpp\"\n#include \"stdint.hpp\"\n#include \"socks.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\nclass session_base_t;\nstruct address_t;\n\nclass socks_connecter_t ZMQ_FINAL : public stream_connecter_base_t\n{\n  public:\n    //  If 'delayed_start' is true connecter first waits for a while,\n    //  then starts connection process.\n    socks_connecter_t (zmq::io_thread_t *io_thread_,\n                       zmq::session_base_t *session_,\n                       const options_t &options_,\n                       address_t *addr_,\n                       address_t *proxy_addr_,\n                       bool delayed_start_);\n    ~socks_connecter_t ();\n\n    void set_auth_method_basic (const std::string &username,\n                                const std::string &password);\n    void set_auth_method_none ();\n\n\n  private:\n    enum\n    {\n        unplugged,\n        waiting_for_reconnect_time,\n        waiting_for_proxy_connection,\n        sending_greeting,\n        waiting_for_choice,\n        sending_basic_auth_request,\n        waiting_for_auth_response,\n        sending_request,\n        waiting_for_response\n    };\n\n    //  Method ID\n    enum\n    {\n        socks_no_auth_required = 0x00,\n        socks_basic_auth = 0x02,\n        socks_no_acceptable_method = 0xff\n    };\n\n    //  Handlers for I/O events.\n    void in_event ();\n    void out_event ();\n\n    //  Internal function to start the actual connection establishment.\n    void start_connecting ();\n\n    static int process_server_response (const socks_choice_t &response_);\n    static int process_server_response (const socks_response_t &response_);\n    static int process_server_response (const socks_auth_response_t &response_);\n\n    static int parse_address (const std::string &address_,\n                              std::string &hostname_,\n                              uint16_t &port_);\n\n    int connect_to_proxy ();\n\n    void error ();\n\n    //  Open TCP connecting socket. Returns -1 in case of error,\n    //  0 if connect was successful immediately. Returns -1 with\n    //  EAGAIN errno if async connect was launched.\n    int open ();\n\n    //  Get the file descriptor of newly created connection. Returns\n    //  retired_fd if the connection was unsuccessful.\n    zmq::fd_t check_proxy_connection () const;\n\n    socks_greeting_encoder_t _greeting_encoder;\n    socks_choice_decoder_t _choice_decoder;\n    socks_basic_auth_request_encoder_t _basic_auth_request_encoder;\n    socks_auth_response_decoder_t _auth_response_decoder;\n    socks_request_encoder_t _request_encoder;\n    socks_response_decoder_t _response_decoder;\n\n    //  SOCKS address; owned by this connecter.\n    address_t *_proxy_addr;\n\n    // User defined authentication method\n    int _auth_method;\n\n    // Credentials for basic authentication\n    std::string _auth_username;\n    std::string _auth_password;\n\n    int _status;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (socks_connecter_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/stdint.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_STDINT_HPP_INCLUDED__\n#define __ZMQ_STDINT_HPP_INCLUDED__\n\n#if defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_OPENVMS\n\n#include <inttypes.h>\n\n#elif defined _MSC_VER && _MSC_VER < 1600\n\n#ifndef int8_t\ntypedef __int8 int8_t;\n#endif\n#ifndef int16_t\ntypedef __int16 int16_t;\n#endif\n#ifndef int32_t\ntypedef __int32 int32_t;\n#endif\n#ifndef int64_t\ntypedef __int64 int64_t;\n#endif\n#ifndef uint8_t\ntypedef unsigned __int8 uint8_t;\n#endif\n#ifndef uint16_t\ntypedef unsigned __int16 uint16_t;\n#endif\n#ifndef uint32_t\ntypedef unsigned __int32 uint32_t;\n#endif\n#ifndef uint64_t\ntypedef unsigned __int64 uint64_t;\n#endif\n#ifndef UINT16_MAX\n#define UINT16_MAX _UI16_MAX\n#endif\n#ifndef UINT32_MAX\n#define UINT32_MAX _UI32_MAX\n#endif\n\n#else\n\n#include <stdint.h>\n\n#endif\n\n#ifndef UINT8_MAX\n#define UINT8_MAX 0xFF\n#endif\n\n#endif\n"
  },
  {
    "path": "src/stream.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"stream.hpp\"\n#include \"pipe.hpp\"\n#include \"wire.hpp\"\n#include \"random.hpp\"\n#include \"likely.hpp\"\n#include \"err.hpp\"\n\nzmq::stream_t::stream_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    routing_socket_base_t (parent_, tid_, sid_),\n    _prefetched (false),\n    _routing_id_sent (false),\n    _current_out (NULL),\n    _more_out (false),\n    _next_integral_routing_id (generate_random ())\n{\n    options.type = ZMQ_STREAM;\n    options.raw_socket = true;\n\n    _prefetched_routing_id.init ();\n    _prefetched_msg.init ();\n}\n\nzmq::stream_t::~stream_t ()\n{\n    _prefetched_routing_id.close ();\n    _prefetched_msg.close ();\n}\n\nvoid zmq::stream_t::xattach_pipe (pipe_t *pipe_,\n                                  bool subscribe_to_all_,\n                                  bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n\n    zmq_assert (pipe_);\n\n    identify_peer (pipe_, locally_initiated_);\n    _fq.attach (pipe_);\n}\n\nvoid zmq::stream_t::xpipe_terminated (pipe_t *pipe_)\n{\n    erase_out_pipe (pipe_);\n    _fq.pipe_terminated (pipe_);\n    // TODO router_t calls pipe_->rollback() here; should this be done here as\n    // well? then xpipe_terminated could be pulled up to routing_socket_base_t\n    if (pipe_ == _current_out)\n        _current_out = NULL;\n}\n\nvoid zmq::stream_t::xread_activated (pipe_t *pipe_)\n{\n    _fq.activated (pipe_);\n}\n\nint zmq::stream_t::xsend (msg_t *msg_)\n{\n    //  If this is the first part of the message it's the ID of the\n    //  peer to send the message to.\n    if (!_more_out) {\n        zmq_assert (!_current_out);\n\n        //  If we have malformed message (prefix with no subsequent message)\n        //  then just silently ignore it.\n        //  TODO: The connections should be killed instead.\n        if (msg_->flags () & msg_t::more) {\n            //  Find the pipe associated with the routing id stored in the prefix.\n            //  If there's no such pipe return an error\n\n            out_pipe_t *out_pipe = lookup_out_pipe (\n              blob_t (static_cast<unsigned char *> (msg_->data ()),\n                      msg_->size (), reference_tag_t ()));\n\n            if (out_pipe) {\n                _current_out = out_pipe->pipe;\n                if (!_current_out->check_write ()) {\n                    out_pipe->active = false;\n                    _current_out = NULL;\n                    errno = EAGAIN;\n                    return -1;\n                }\n            } else {\n                errno = EHOSTUNREACH;\n                return -1;\n            }\n        }\n\n        //  Expect one more message frame.\n        _more_out = true;\n\n        int rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n        return 0;\n    }\n\n    //  Ignore the MORE flag\n    msg_->reset_flags (msg_t::more);\n\n    //  This is the last part of the message.\n    _more_out = false;\n\n    //  Push the message into the pipe. If there's no out pipe, just drop it.\n    if (_current_out) {\n        // Close the remote connection if user has asked to do so\n        // by sending zero length message.\n        // Pending messages in the pipe will be dropped (on receiving term- ack)\n        if (msg_->size () == 0) {\n            _current_out->terminate (false);\n            int rc = msg_->close ();\n            errno_assert (rc == 0);\n            rc = msg_->init ();\n            errno_assert (rc == 0);\n            _current_out = NULL;\n            return 0;\n        }\n        const bool ok = _current_out->write (msg_);\n        if (likely (ok))\n            _current_out->flush ();\n        _current_out = NULL;\n    } else {\n        const int rc = msg_->close ();\n        errno_assert (rc == 0);\n    }\n\n    //  Detach the message from the data buffer.\n    const int rc = msg_->init ();\n    errno_assert (rc == 0);\n\n    return 0;\n}\n\nint zmq::stream_t::xsetsockopt (int option_,\n                                const void *optval_,\n                                size_t optvallen_)\n{\n    switch (option_) {\n        case ZMQ_STREAM_NOTIFY:\n            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,\n                                                     &options.raw_notify);\n\n        default:\n            return routing_socket_base_t::xsetsockopt (option_, optval_,\n                                                       optvallen_);\n    }\n}\n\nint zmq::stream_t::xrecv (msg_t *msg_)\n{\n    if (_prefetched) {\n        if (!_routing_id_sent) {\n            const int rc = msg_->move (_prefetched_routing_id);\n            errno_assert (rc == 0);\n            _routing_id_sent = true;\n        } else {\n            const int rc = msg_->move (_prefetched_msg);\n            errno_assert (rc == 0);\n            _prefetched = false;\n        }\n        return 0;\n    }\n\n    pipe_t *pipe = NULL;\n    int rc = _fq.recvpipe (&_prefetched_msg, &pipe);\n    if (rc != 0)\n        return -1;\n\n    zmq_assert (pipe != NULL);\n    zmq_assert ((_prefetched_msg.flags () & msg_t::more) == 0);\n\n    //  We have received a frame with TCP data.\n    //  Rather than sending this frame, we keep it in prefetched\n    //  buffer and send a frame with peer's ID.\n    const blob_t &routing_id = pipe->get_routing_id ();\n    rc = msg_->close ();\n    errno_assert (rc == 0);\n    rc = msg_->init_size (routing_id.size ());\n    errno_assert (rc == 0);\n\n    // forward metadata (if any)\n    metadata_t *metadata = _prefetched_msg.metadata ();\n    if (metadata)\n        msg_->set_metadata (metadata);\n\n    memcpy (msg_->data (), routing_id.data (), routing_id.size ());\n    msg_->set_flags (msg_t::more);\n\n    _prefetched = true;\n    _routing_id_sent = true;\n\n    return 0;\n}\n\nbool zmq::stream_t::xhas_in ()\n{\n    //  We may already have a message pre-fetched.\n    if (_prefetched)\n        return true;\n\n    //  Try to read the next message.\n    //  The message, if read, is kept in the pre-fetch buffer.\n    pipe_t *pipe = NULL;\n    int rc = _fq.recvpipe (&_prefetched_msg, &pipe);\n    if (rc != 0)\n        return false;\n\n    zmq_assert (pipe != NULL);\n    zmq_assert ((_prefetched_msg.flags () & msg_t::more) == 0);\n\n    const blob_t &routing_id = pipe->get_routing_id ();\n    rc = _prefetched_routing_id.init_size (routing_id.size ());\n    errno_assert (rc == 0);\n\n    // forward metadata (if any)\n    metadata_t *metadata = _prefetched_msg.metadata ();\n    if (metadata)\n        _prefetched_routing_id.set_metadata (metadata);\n\n    memcpy (_prefetched_routing_id.data (), routing_id.data (),\n            routing_id.size ());\n    _prefetched_routing_id.set_flags (msg_t::more);\n\n    _prefetched = true;\n    _routing_id_sent = false;\n\n    return true;\n}\n\nbool zmq::stream_t::xhas_out ()\n{\n    //  In theory, STREAM socket is always ready for writing. Whether actual\n    //  attempt to write succeeds depends on which pipe the message is going\n    //  to be routed to.\n    return true;\n}\n\nvoid zmq::stream_t::identify_peer (pipe_t *pipe_, bool locally_initiated_)\n{\n    //  Always assign routing id for raw-socket\n    unsigned char buffer[5];\n    buffer[0] = 0;\n    blob_t routing_id;\n    if (locally_initiated_ && connect_routing_id_is_set ()) {\n        const std::string connect_routing_id = extract_connect_routing_id ();\n        routing_id.set (\n          reinterpret_cast<const unsigned char *> (connect_routing_id.c_str ()),\n          connect_routing_id.length ());\n        //  Not allowed to duplicate an existing rid\n        zmq_assert (!has_out_pipe (routing_id));\n    } else {\n        put_uint32 (buffer + 1, _next_integral_routing_id++);\n        routing_id.set (buffer, sizeof buffer);\n        memcpy (options.routing_id, routing_id.data (), routing_id.size ());\n        options.routing_id_size =\n          static_cast<unsigned char> (routing_id.size ());\n    }\n    pipe_->set_router_socket_routing_id (routing_id);\n    add_out_pipe (ZMQ_MOVE (routing_id), pipe_);\n}\n"
  },
  {
    "path": "src/stream.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_STREAM_HPP_INCLUDED__\n#define __ZMQ_STREAM_HPP_INCLUDED__\n\n#include <map>\n\n#include \"router.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass pipe_t;\n\nclass stream_t ZMQ_FINAL : public routing_socket_base_t\n{\n  public:\n    stream_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~stream_t ();\n\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_);\n    int xsend (zmq::msg_t *msg_);\n    int xrecv (zmq::msg_t *msg_);\n    bool xhas_in ();\n    bool xhas_out ();\n    void xread_activated (zmq::pipe_t *pipe_);\n    void xpipe_terminated (zmq::pipe_t *pipe_);\n    int xsetsockopt (int option_, const void *optval_, size_t optvallen_);\n\n  private:\n    //  Generate peer's id and update lookup map\n    void identify_peer (pipe_t *pipe_, bool locally_initiated_);\n\n    //  Fair queueing object for inbound pipes.\n    fq_t _fq;\n\n    //  True iff there is a message held in the pre-fetch buffer.\n    bool _prefetched;\n\n    //  If true, the receiver got the message part with\n    //  the peer's identity.\n    bool _routing_id_sent;\n\n    //  Holds the prefetched identity.\n    msg_t _prefetched_routing_id;\n\n    //  Holds the prefetched message.\n    msg_t _prefetched_msg;\n\n    //  The pipe we are currently writing to.\n    zmq::pipe_t *_current_out;\n\n    //  If true, more outgoing message parts are expected.\n    bool _more_out;\n\n    //  Routing IDs are generated. It's a simple increment and wrap-over\n    //  algorithm. This value is the next ID to use (if not used already).\n    uint32_t _next_integral_routing_id;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (stream_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/stream_connecter_base.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"stream_connecter_base.hpp\"\n#include \"session_base.hpp\"\n#include \"address.hpp\"\n#include \"random.hpp\"\n#include \"zmtp_engine.hpp\"\n#include \"raw_engine.hpp\"\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#else\n#include <winsock2.h>\n#endif\n\n#include <limits>\n\nzmq::stream_connecter_base_t::stream_connecter_base_t (\n  zmq::io_thread_t *io_thread_,\n  zmq::session_base_t *session_,\n  const zmq::options_t &options_,\n  zmq::address_t *addr_,\n  bool delayed_start_) :\n    own_t (io_thread_, options_),\n    io_object_t (io_thread_),\n    _addr (addr_),\n    _s (retired_fd),\n    _handle (static_cast<handle_t> (NULL)),\n    _socket (session_->get_socket ()),\n    _delayed_start (delayed_start_),\n    _reconnect_timer_started (false),\n    _current_reconnect_ivl (-1),\n    _session (session_)\n{\n    zmq_assert (_addr);\n    _addr->to_string (_endpoint);\n    // TODO the return value is unused! what if it fails? if this is impossible\n    // or does not matter, change such that endpoint in initialized using an\n    // initializer, and make endpoint const\n}\n\nzmq::stream_connecter_base_t::~stream_connecter_base_t ()\n{\n    zmq_assert (!_reconnect_timer_started);\n    zmq_assert (!_handle);\n    zmq_assert (_s == retired_fd);\n}\n\nvoid zmq::stream_connecter_base_t::process_plug ()\n{\n    if (_delayed_start)\n        add_reconnect_timer ();\n    else\n        start_connecting ();\n}\n\nvoid zmq::stream_connecter_base_t::process_term (int linger_)\n{\n    if (_reconnect_timer_started) {\n        cancel_timer (reconnect_timer_id);\n        _reconnect_timer_started = false;\n    }\n\n    if (_handle) {\n        rm_handle ();\n    }\n\n    if (_s != retired_fd)\n        close ();\n\n    own_t::process_term (linger_);\n}\n\nvoid zmq::stream_connecter_base_t::add_reconnect_timer ()\n{\n    if (options.reconnect_ivl > 0) {\n        const int interval = get_new_reconnect_ivl ();\n        add_timer (interval, reconnect_timer_id);\n        _socket->event_connect_retried (\n          make_unconnected_connect_endpoint_pair (_endpoint), interval);\n        _reconnect_timer_started = true;\n    }\n}\n\nint zmq::stream_connecter_base_t::get_new_reconnect_ivl ()\n{\n    if (options.reconnect_ivl_max > 0) {\n        int candidate_interval = 0;\n        if (_current_reconnect_ivl == -1)\n            candidate_interval = options.reconnect_ivl;\n        else if (_current_reconnect_ivl > std::numeric_limits<int>::max () / 2)\n            candidate_interval = std::numeric_limits<int>::max ();\n        else\n            candidate_interval = _current_reconnect_ivl * 2;\n\n        if (candidate_interval > options.reconnect_ivl_max)\n            _current_reconnect_ivl = options.reconnect_ivl_max;\n        else\n            _current_reconnect_ivl = candidate_interval;\n        return _current_reconnect_ivl;\n    } else {\n        if (_current_reconnect_ivl == -1)\n            _current_reconnect_ivl = options.reconnect_ivl;\n        //  The new interval is the base interval + random value.\n        const int random_jitter = generate_random () % options.reconnect_ivl;\n        const int interval =\n          _current_reconnect_ivl\n              < std::numeric_limits<int>::max () - random_jitter\n            ? _current_reconnect_ivl + random_jitter\n            : std::numeric_limits<int>::max ();\n        return interval;\n    }\n}\n\nvoid zmq::stream_connecter_base_t::rm_handle ()\n{\n    rm_fd (_handle);\n    _handle = static_cast<handle_t> (NULL);\n}\n\nvoid zmq::stream_connecter_base_t::close ()\n{\n    // TODO before, this was an assertion for _s != retired_fd, but this does not match usage of close\n    if (_s != retired_fd) {\n#ifdef ZMQ_HAVE_WINDOWS\n        const int rc = closesocket (_s);\n        wsa_assert (rc != SOCKET_ERROR);\n#else\n        const int rc = ::close (_s);\n        errno_assert (rc == 0);\n#endif\n        _socket->event_closed (\n          make_unconnected_connect_endpoint_pair (_endpoint), _s);\n        _s = retired_fd;\n    }\n}\n\nvoid zmq::stream_connecter_base_t::in_event ()\n{\n    //  We are not polling for incoming data, so we are actually called\n    //  because of error here. However, we can get error on out event as well\n    //  on some platforms, so we'll simply handle both events in the same way.\n    out_event ();\n}\n\nvoid zmq::stream_connecter_base_t::create_engine (\n  fd_t fd_, const std::string &local_address_)\n{\n    const endpoint_uri_pair_t endpoint_pair (local_address_, _endpoint,\n                                             endpoint_type_connect);\n\n    //  Create the engine object for this connection.\n    i_engine *engine;\n    if (options.raw_socket)\n        engine = new (std::nothrow) raw_engine_t (fd_, options, endpoint_pair);\n    else\n        engine = new (std::nothrow) zmtp_engine_t (fd_, options, endpoint_pair);\n    alloc_assert (engine);\n\n    //  Attach the engine to the corresponding session object.\n    send_attach (_session, engine);\n\n    //  Shut the connecter down.\n    terminate ();\n\n    _socket->event_connected (endpoint_pair, fd_);\n}\n\nvoid zmq::stream_connecter_base_t::timer_event (int id_)\n{\n    zmq_assert (id_ == reconnect_timer_id);\n    _reconnect_timer_started = false;\n    start_connecting ();\n}\n"
  },
  {
    "path": "src/stream_connecter_base.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __STREAM_CONNECTER_BASE_HPP_INCLUDED__\n#define __STREAM_CONNECTER_BASE_HPP_INCLUDED__\n\n#include \"fd.hpp\"\n#include \"own.hpp\"\n#include \"io_object.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\nclass session_base_t;\nstruct address_t;\n\nclass stream_connecter_base_t : public own_t, public io_object_t\n{\n  public:\n    //  If 'delayed_start' is true connecter first waits for a while,\n    //  then starts connection process.\n    stream_connecter_base_t (zmq::io_thread_t *io_thread_,\n                             zmq::session_base_t *session_,\n                             const options_t &options_,\n                             address_t *addr_,\n                             bool delayed_start_);\n\n    ~stream_connecter_base_t () ZMQ_OVERRIDE;\n\n  protected:\n    //  Handlers for incoming commands.\n    void process_plug () ZMQ_FINAL;\n    void process_term (int linger_) ZMQ_OVERRIDE;\n\n    //  Handlers for I/O events.\n    void in_event () ZMQ_OVERRIDE;\n    void timer_event (int id_) ZMQ_OVERRIDE;\n\n    //  Internal function to create the engine after connection was established.\n    virtual void create_engine (fd_t fd, const std::string &local_address_);\n\n    //  Internal function to add a reconnect timer\n    void add_reconnect_timer ();\n\n    //  Removes the handle from the poller.\n    void rm_handle ();\n\n    //  Close the connecting socket.\n    void close ();\n\n    //  Address to connect to. Owned by session_base_t.\n    //  It is non-const since some parts may change during opening.\n    address_t *const _addr;\n\n    //  Underlying socket.\n    fd_t _s;\n\n    //  Handle corresponding to the listening socket, if file descriptor is\n    //  registered with the poller, or NULL.\n    handle_t _handle;\n\n    // String representation of endpoint to connect to\n    std::string _endpoint;\n\n    // Socket\n    zmq::socket_base_t *const _socket;\n\n  private:\n    //  ID of the timer used to delay the reconnection.\n    enum\n    {\n        reconnect_timer_id = 1\n    };\n\n    //  Internal function to return a reconnect backoff delay.\n    //  Will modify the current_reconnect_ivl used for next call\n    //  Returns the currently used interval\n    int get_new_reconnect_ivl ();\n\n    virtual void start_connecting () = 0;\n\n    //  If true, connecter is waiting a while before trying to connect.\n    const bool _delayed_start;\n\n    //  True iff a timer has been started.\n    bool _reconnect_timer_started;\n\n    //  Current reconnect ivl, updated for backoff strategy\n    int _current_reconnect_ivl;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (stream_connecter_base_t)\n\n  protected:\n    //  Reference to the session we belong to.\n    zmq::session_base_t *const _session;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/stream_engine_base.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n\n#include <limits.h>\n#include <string.h>\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#endif\n\n#include <new>\n#include <sstream>\n\n#include \"stream_engine_base.hpp\"\n#include \"io_thread.hpp\"\n#include \"session_base.hpp\"\n#include \"v1_encoder.hpp\"\n#include \"v1_decoder.hpp\"\n#include \"v2_encoder.hpp\"\n#include \"v2_decoder.hpp\"\n#include \"null_mechanism.hpp\"\n#include \"plain_client.hpp\"\n#include \"plain_server.hpp\"\n#include \"gssapi_client.hpp\"\n#include \"gssapi_server.hpp\"\n#include \"curve_client.hpp\"\n#include \"curve_server.hpp\"\n#include \"raw_decoder.hpp\"\n#include \"raw_encoder.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"tcp.hpp\"\n#include \"likely.hpp\"\n#include \"wire.hpp\"\n\nstatic std::string get_peer_address (zmq::fd_t s_)\n{\n    std::string peer_address;\n\n    const int family = zmq::get_peer_ip_address (s_, peer_address);\n    if (family == 0)\n        peer_address.clear ();\n#if defined ZMQ_HAVE_SO_PEERCRED\n    else if (family == PF_UNIX) {\n        struct ucred cred;\n        socklen_t size = sizeof (cred);\n        if (!getsockopt (s_, SOL_SOCKET, SO_PEERCRED, &cred, &size)) {\n            std::ostringstream buf;\n            buf << \":\" << cred.uid << \":\" << cred.gid << \":\" << cred.pid;\n            peer_address += buf.str ();\n        }\n    }\n#elif defined ZMQ_HAVE_LOCAL_PEERCRED\n    else if (family == PF_UNIX) {\n        struct xucred cred;\n        socklen_t size = sizeof (cred);\n        if (!getsockopt (s_, 0, LOCAL_PEERCRED, &cred, &size)\n            && cred.cr_version == XUCRED_VERSION) {\n            std::ostringstream buf;\n            buf << \":\" << cred.cr_uid << \":\";\n            if (cred.cr_ngroups > 0)\n                buf << cred.cr_groups[0];\n            buf << \":\";\n            peer_address += buf.str ();\n        }\n    }\n#endif\n\n    return peer_address;\n}\n\nzmq::stream_engine_base_t::stream_engine_base_t (\n  fd_t fd_,\n  const options_t &options_,\n  const endpoint_uri_pair_t &endpoint_uri_pair_,\n  bool has_handshake_stage_) :\n    _options (options_),\n    _inpos (NULL),\n    _insize (0),\n    _decoder (NULL),\n    _outpos (NULL),\n    _outsize (0),\n    _encoder (NULL),\n    _mechanism (NULL),\n    _next_msg (NULL),\n    _process_msg (NULL),\n    _metadata (NULL),\n    _input_stopped (false),\n    _output_stopped (false),\n    _endpoint_uri_pair (endpoint_uri_pair_),\n    _has_handshake_timer (false),\n    _has_ttl_timer (false),\n    _has_timeout_timer (false),\n    _has_heartbeat_timer (false),\n    _peer_address (get_peer_address (fd_)),\n    _s (fd_),\n    _handle (static_cast<handle_t> (NULL)),\n    _plugged (false),\n    _handshaking (true),\n    _io_error (false),\n    _session (NULL),\n    _socket (NULL),\n    _has_handshake_stage (has_handshake_stage_)\n{\n    const int rc = _tx_msg.init ();\n    errno_assert (rc == 0);\n\n    //  Put the socket into non-blocking mode.\n    unblock_socket (_s);\n}\n\nzmq::stream_engine_base_t::~stream_engine_base_t ()\n{\n    zmq_assert (!_plugged);\n\n    if (_s != retired_fd) {\n#ifdef ZMQ_HAVE_WINDOWS\n        const int rc = closesocket (_s);\n        wsa_assert (rc != SOCKET_ERROR);\n#else\n        int rc = close (_s);\n#if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)\n        // FreeBSD may return ECONNRESET on close() under load but this is not\n        // an error.\n        if (rc == -1 && errno == ECONNRESET)\n            rc = 0;\n#endif\n        errno_assert (rc == 0);\n#endif\n        _s = retired_fd;\n    }\n\n    const int rc = _tx_msg.close ();\n    errno_assert (rc == 0);\n\n    //  Drop reference to metadata and destroy it if we are\n    //  the only user.\n    if (_metadata != NULL) {\n        if (_metadata->drop_ref ()) {\n            LIBZMQ_DELETE (_metadata);\n        }\n    }\n\n    LIBZMQ_DELETE (_encoder);\n    LIBZMQ_DELETE (_decoder);\n    LIBZMQ_DELETE (_mechanism);\n}\n\nvoid zmq::stream_engine_base_t::plug (io_thread_t *io_thread_,\n                                      session_base_t *session_)\n{\n    zmq_assert (!_plugged);\n    _plugged = true;\n\n    //  Connect to session object.\n    zmq_assert (!_session);\n    zmq_assert (session_);\n    _session = session_;\n    _socket = _session->get_socket ();\n\n    //  Connect to I/O threads poller object.\n    io_object_t::plug (io_thread_);\n    _handle = add_fd (_s);\n    _io_error = false;\n\n    plug_internal ();\n}\n\nvoid zmq::stream_engine_base_t::unplug ()\n{\n    zmq_assert (_plugged);\n    _plugged = false;\n\n    //  Cancel all timers.\n    if (_has_handshake_timer) {\n        cancel_timer (handshake_timer_id);\n        _has_handshake_timer = false;\n    }\n\n    if (_has_ttl_timer) {\n        cancel_timer (heartbeat_ttl_timer_id);\n        _has_ttl_timer = false;\n    }\n\n    if (_has_timeout_timer) {\n        cancel_timer (heartbeat_timeout_timer_id);\n        _has_timeout_timer = false;\n    }\n\n    if (_has_heartbeat_timer) {\n        cancel_timer (heartbeat_ivl_timer_id);\n        _has_heartbeat_timer = false;\n    }\n    //  Cancel all fd subscriptions.\n    if (!_io_error)\n        rm_fd (_handle);\n\n    //  Disconnect from I/O threads poller object.\n    io_object_t::unplug ();\n\n    _session = NULL;\n}\n\nvoid zmq::stream_engine_base_t::terminate ()\n{\n    unplug ();\n    delete this;\n}\n\nvoid zmq::stream_engine_base_t::in_event ()\n{\n    // ignore errors\n    const bool res = in_event_internal ();\n    LIBZMQ_UNUSED (res);\n}\n\nbool zmq::stream_engine_base_t::in_event_internal ()\n{\n    zmq_assert (!_io_error);\n\n    //  If still handshaking, receive and process the greeting message.\n    if (unlikely (_handshaking)) {\n        if (handshake ()) {\n            //  Handshaking was successful.\n            //  Switch into the normal message flow.\n            _handshaking = false;\n\n            if (_mechanism == NULL && _has_handshake_stage) {\n                _session->engine_ready ();\n\n                if (_has_handshake_timer) {\n                    cancel_timer (handshake_timer_id);\n                    _has_handshake_timer = false;\n                }\n            }\n        } else\n            return false;\n    }\n\n\n    zmq_assert (_decoder);\n\n    //  If there has been an I/O error, stop polling.\n    if (_input_stopped) {\n        rm_fd (_handle);\n        _io_error = true;\n        return true; // TODO or return false in this case too?\n    }\n\n    //  If there's no data to process in the buffer...\n    if (!_insize) {\n        //  Retrieve the buffer and read as much data as possible.\n        //  Note that buffer can be arbitrarily large. However, we assume\n        //  the underlying TCP layer has fixed buffer size and thus the\n        //  number of bytes read will be always limited.\n        size_t bufsize = 0;\n        _decoder->get_buffer (&_inpos, &bufsize);\n\n        const int rc = read (_inpos, bufsize);\n\n        if (rc == -1) {\n            if (errno != EAGAIN) {\n                error (connection_error);\n                return false;\n            }\n            return true;\n        }\n\n        //  Adjust input size\n        _insize = static_cast<size_t> (rc);\n        // Adjust buffer size to received bytes\n        _decoder->resize_buffer (_insize);\n    }\n\n    int rc = 0;\n    size_t processed = 0;\n\n    while (_insize > 0) {\n        rc = _decoder->decode (_inpos, _insize, processed);\n        zmq_assert (processed <= _insize);\n        _inpos += processed;\n        _insize -= processed;\n        if (rc == 0 || rc == -1)\n            break;\n        rc = (this->*_process_msg) (_decoder->msg ());\n        if (rc == -1)\n            break;\n    }\n\n    //  Tear down the connection if we have failed to decode input data\n    //  or the session has rejected the message.\n    if (rc == -1) {\n        if (errno != EAGAIN) {\n            // In cases where the src/dst have the same IP and the dst uses an ephemeral port, reconnection\n            // eventually results in the src and dest IP and port clashing (google tcp self connection)\n            // While this is a protocol_error (you have the single zmq socket handshaking with itself)\n            // we do not want to to stop reconnection from happening\n            if (!_endpoint_uri_pair.clash ()) {\n                error (protocol_error);\n                return false;\n            }\n        }\n        _input_stopped = true;\n        reset_pollin (_handle);\n    }\n\n    _session->flush ();\n    return true;\n}\n\nvoid zmq::stream_engine_base_t::out_event ()\n{\n    zmq_assert (!_io_error);\n\n    //  If write buffer is empty, try to read new data from the encoder.\n    if (!_outsize) {\n        //  Even when we stop polling as soon as there is no\n        //  data to send, the poller may invoke out_event one\n        //  more time due to 'speculative write' optimisation.\n        if (unlikely (_encoder == NULL)) {\n            zmq_assert (_handshaking);\n            return;\n        }\n\n        _outpos = NULL;\n        _outsize = _encoder->encode (&_outpos, 0);\n\n        while (_outsize < static_cast<size_t> (_options.out_batch_size)) {\n            if ((this->*_next_msg) (&_tx_msg) == -1) {\n                //  ws_engine can cause an engine error and delete it, so\n                //  bail out immediately to avoid use-after-free\n                if (errno == ECONNRESET)\n                    return;\n                else\n                    break;\n            }\n            _encoder->load_msg (&_tx_msg);\n            unsigned char *bufptr = _outpos + _outsize;\n            const size_t n =\n              _encoder->encode (&bufptr, _options.out_batch_size - _outsize);\n            zmq_assert (n > 0);\n            if (_outpos == NULL)\n                _outpos = bufptr;\n            _outsize += n;\n        }\n\n        //  If there is no data to send, stop polling for output.\n        if (_outsize == 0) {\n            _output_stopped = true;\n            reset_pollout ();\n            return;\n        }\n    }\n\n    //  If there are any data to write in write buffer, write as much as\n    //  possible to the socket. Note that amount of data to write can be\n    //  arbitrarily large. However, we assume that underlying TCP layer has\n    //  limited transmission buffer and thus the actual number of bytes\n    //  written should be reasonably modest.\n    const int nbytes = write (_outpos, _outsize);\n\n    //  IO error has occurred. We stop waiting for output events.\n    //  The engine is not terminated until we detect input error;\n    //  this is necessary to prevent losing incoming messages.\n    if (nbytes == -1) {\n        reset_pollout ();\n        return;\n    }\n\n    _outpos += nbytes;\n    _outsize -= nbytes;\n\n    //  If we are still handshaking and there are no data\n    //  to send, stop polling for output.\n    if (unlikely (_handshaking))\n        if (_outsize == 0)\n            reset_pollout ();\n}\n\nvoid zmq::stream_engine_base_t::restart_output ()\n{\n    if (unlikely (_io_error))\n        return;\n\n    if (likely (_output_stopped)) {\n        set_pollout ();\n        _output_stopped = false;\n    }\n\n    //  Speculative write: The assumption is that at the moment new message\n    //  was sent by the user the socket is probably available for writing.\n    //  Thus we try to write the data to socket avoiding polling for POLLOUT.\n    //  Consequently, the latency should be better in request/reply scenarios.\n    out_event ();\n}\n\nbool zmq::stream_engine_base_t::restart_input ()\n{\n    zmq_assert (_input_stopped);\n    zmq_assert (_session != NULL);\n    zmq_assert (_decoder != NULL);\n\n    int rc = (this->*_process_msg) (_decoder->msg ());\n    if (rc == -1) {\n        if (errno == EAGAIN)\n            _session->flush ();\n        else {\n            error (protocol_error);\n            return false;\n        }\n        return true;\n    }\n\n    while (_insize > 0) {\n        size_t processed = 0;\n        rc = _decoder->decode (_inpos, _insize, processed);\n        zmq_assert (processed <= _insize);\n        _inpos += processed;\n        _insize -= processed;\n        if (rc == 0 || rc == -1)\n            break;\n        rc = (this->*_process_msg) (_decoder->msg ());\n        if (rc == -1)\n            break;\n    }\n\n    if (rc == -1 && errno == EAGAIN)\n        _session->flush ();\n    else if (_io_error) {\n        error (connection_error);\n        return false;\n    } else if (rc == -1) {\n        error (protocol_error);\n        return false;\n    }\n\n    else {\n        _input_stopped = false;\n        set_pollin ();\n        _session->flush ();\n\n        //  Speculative read.\n        if (!in_event_internal ())\n            return false;\n    }\n\n    return true;\n}\n\nint zmq::stream_engine_base_t::next_handshake_command (msg_t *msg_)\n{\n    zmq_assert (_mechanism != NULL);\n\n    if (_mechanism->status () == mechanism_t::ready) {\n        mechanism_ready ();\n        return pull_and_encode (msg_);\n    }\n    if (_mechanism->status () == mechanism_t::error) {\n        errno = EPROTO;\n        return -1;\n    }\n    const int rc = _mechanism->next_handshake_command (msg_);\n\n    if (rc == 0)\n        msg_->set_flags (msg_t::command);\n\n    return rc;\n}\n\nint zmq::stream_engine_base_t::process_handshake_command (msg_t *msg_)\n{\n    zmq_assert (_mechanism != NULL);\n    const int rc = _mechanism->process_handshake_command (msg_);\n    if (rc == 0) {\n        if (_mechanism->status () == mechanism_t::ready)\n            mechanism_ready ();\n        else if (_mechanism->status () == mechanism_t::error) {\n            errno = EPROTO;\n            return -1;\n        }\n        if (_output_stopped)\n            restart_output ();\n    }\n\n    return rc;\n}\n\nvoid zmq::stream_engine_base_t::zap_msg_available ()\n{\n    zmq_assert (_mechanism != NULL);\n\n    const int rc = _mechanism->zap_msg_available ();\n    if (rc == -1) {\n        error (protocol_error);\n        return;\n    }\n    if (_input_stopped)\n        if (!restart_input ())\n            return;\n    if (_output_stopped)\n        restart_output ();\n}\n\nconst zmq::endpoint_uri_pair_t &zmq::stream_engine_base_t::get_endpoint () const\n{\n    return _endpoint_uri_pair;\n}\n\nvoid zmq::stream_engine_base_t::mechanism_ready ()\n{\n    if (_options.heartbeat_interval > 0 && !_has_heartbeat_timer) {\n        add_timer (_options.heartbeat_interval, heartbeat_ivl_timer_id);\n        _has_heartbeat_timer = true;\n    }\n\n    if (_has_handshake_stage)\n        _session->engine_ready ();\n\n    bool flush_session = false;\n\n    if (_options.recv_routing_id) {\n        msg_t routing_id;\n        _mechanism->peer_routing_id (&routing_id);\n        const int rc = _session->push_msg (&routing_id);\n        if (rc == -1 && errno == EAGAIN) {\n            // If the write is failing at this stage with\n            // an EAGAIN the pipe must be being shut down,\n            // so we can just bail out of the routing id set.\n            return;\n        }\n        errno_assert (rc == 0);\n        flush_session = true;\n    }\n\n    if (_options.router_notify & ZMQ_NOTIFY_CONNECT) {\n        msg_t connect_notification;\n        connect_notification.init ();\n        const int rc = _session->push_msg (&connect_notification);\n        if (rc == -1 && errno == EAGAIN) {\n            // If the write is failing at this stage with\n            // an EAGAIN the pipe must be being shut down,\n            // so we can just bail out of the notification.\n            return;\n        }\n        errno_assert (rc == 0);\n        flush_session = true;\n    }\n\n    if (flush_session)\n        _session->flush ();\n\n    _next_msg = &stream_engine_base_t::pull_and_encode;\n    _process_msg = &stream_engine_base_t::write_credential;\n\n    //  Compile metadata.\n    properties_t properties;\n    init_properties (properties);\n\n    //  Add ZAP properties.\n    const properties_t &zap_properties = _mechanism->get_zap_properties ();\n    properties.insert (zap_properties.begin (), zap_properties.end ());\n\n    //  Add ZMTP properties.\n    const properties_t &zmtp_properties = _mechanism->get_zmtp_properties ();\n    properties.insert (zmtp_properties.begin (), zmtp_properties.end ());\n\n    zmq_assert (_metadata == NULL);\n    if (!properties.empty ()) {\n        _metadata = new (std::nothrow) metadata_t (properties);\n        alloc_assert (_metadata);\n    }\n\n    if (_has_handshake_timer) {\n        cancel_timer (handshake_timer_id);\n        _has_handshake_timer = false;\n    }\n\n    _socket->event_handshake_succeeded (_endpoint_uri_pair, 0);\n}\n\nint zmq::stream_engine_base_t::write_credential (msg_t *msg_)\n{\n    zmq_assert (_mechanism != NULL);\n    zmq_assert (_session != NULL);\n\n    const blob_t &credential = _mechanism->get_user_id ();\n    if (credential.size () > 0) {\n        msg_t msg;\n        int rc = msg.init_size (credential.size ());\n        zmq_assert (rc == 0);\n        memcpy (msg.data (), credential.data (), credential.size ());\n        msg.set_flags (msg_t::credential);\n        rc = _session->push_msg (&msg);\n        if (rc == -1) {\n            rc = msg.close ();\n            errno_assert (rc == 0);\n            return -1;\n        }\n    }\n    _process_msg = &stream_engine_base_t::decode_and_push;\n    return decode_and_push (msg_);\n}\n\nint zmq::stream_engine_base_t::pull_and_encode (msg_t *msg_)\n{\n    zmq_assert (_mechanism != NULL);\n\n    if (_session->pull_msg (msg_) == -1)\n        return -1;\n    if (_mechanism->encode (msg_) == -1)\n        return -1;\n    return 0;\n}\n\nint zmq::stream_engine_base_t::decode_and_push (msg_t *msg_)\n{\n    zmq_assert (_mechanism != NULL);\n\n    if (_mechanism->decode (msg_) == -1)\n        return -1;\n\n    if (_has_timeout_timer) {\n        _has_timeout_timer = false;\n        cancel_timer (heartbeat_timeout_timer_id);\n    }\n\n    if (_has_ttl_timer) {\n        _has_ttl_timer = false;\n        cancel_timer (heartbeat_ttl_timer_id);\n    }\n\n    if (msg_->flags () & msg_t::command) {\n        process_command_message (msg_);\n    }\n\n    if (_metadata)\n        msg_->set_metadata (_metadata);\n    if (_session->push_msg (msg_) == -1) {\n        if (errno == EAGAIN)\n            _process_msg = &stream_engine_base_t::push_one_then_decode_and_push;\n        return -1;\n    }\n    return 0;\n}\n\nint zmq::stream_engine_base_t::push_one_then_decode_and_push (msg_t *msg_)\n{\n    const int rc = _session->push_msg (msg_);\n    if (rc == 0)\n        _process_msg = &stream_engine_base_t::decode_and_push;\n    return rc;\n}\n\nint zmq::stream_engine_base_t::pull_msg_from_session (msg_t *msg_)\n{\n    return _session->pull_msg (msg_);\n}\n\nint zmq::stream_engine_base_t::push_msg_to_session (msg_t *msg_)\n{\n    return _session->push_msg (msg_);\n}\n\nvoid zmq::stream_engine_base_t::error (error_reason_t reason_)\n{\n    zmq_assert (_session);\n\n    if ((_options.router_notify & ZMQ_NOTIFY_DISCONNECT) && !_handshaking) {\n        // For router sockets with disconnect notification, rollback\n        // any incomplete message in the pipe, and push the disconnect\n        // notification message.\n        _session->rollback ();\n\n        msg_t disconnect_notification;\n        disconnect_notification.init ();\n        _session->push_msg (&disconnect_notification);\n    }\n\n    // protocol errors have been signaled already at the point where they occurred\n    if (reason_ != protocol_error\n        && (_mechanism == NULL\n            || _mechanism->status () == mechanism_t::handshaking)) {\n        const int err = errno;\n        _socket->event_handshake_failed_no_detail (_endpoint_uri_pair, err);\n        // special case: connecting to non-ZMTP process which immediately drops connection,\n        // or which never responds with greeting, should be treated as a protocol error\n        // (i.e. stop reconnect)\n        if (((reason_ == connection_error) || (reason_ == timeout_error))\n            && (_options.reconnect_stop\n                & ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED)) {\n            reason_ = protocol_error;\n        }\n    }\n\n    _socket->event_disconnected (_endpoint_uri_pair, _s);\n    _session->flush ();\n    _session->engine_error (\n      !_handshaking\n        && (_mechanism == NULL\n            || _mechanism->status () != mechanism_t::handshaking),\n      reason_);\n    unplug ();\n    delete this;\n}\n\nvoid zmq::stream_engine_base_t::set_handshake_timer ()\n{\n    zmq_assert (!_has_handshake_timer);\n\n    if (_options.handshake_ivl > 0) {\n        add_timer (_options.handshake_ivl, handshake_timer_id);\n        _has_handshake_timer = true;\n    }\n}\n\nbool zmq::stream_engine_base_t::init_properties (properties_t &properties_)\n{\n    if (_peer_address.empty ())\n        return false;\n    properties_.ZMQ_MAP_INSERT_OR_EMPLACE (\n      std::string (ZMQ_MSG_PROPERTY_PEER_ADDRESS), _peer_address);\n\n    //  Private property to support deprecated SRCFD\n    std::ostringstream stream;\n    stream << static_cast<int> (_s);\n    std::string fd_string = stream.str ();\n    properties_.ZMQ_MAP_INSERT_OR_EMPLACE (std::string (\"__fd\"),\n                                           ZMQ_MOVE (fd_string));\n    return true;\n}\n\nvoid zmq::stream_engine_base_t::timer_event (int id_)\n{\n    if (id_ == handshake_timer_id) {\n        _has_handshake_timer = false;\n        //  handshake timer expired before handshake completed, so engine fail\n        error (timeout_error);\n    } else if (id_ == heartbeat_ivl_timer_id) {\n        _next_msg = &stream_engine_base_t::produce_ping_message;\n        out_event ();\n        add_timer (_options.heartbeat_interval, heartbeat_ivl_timer_id);\n    } else if (id_ == heartbeat_ttl_timer_id) {\n        _has_ttl_timer = false;\n        error (timeout_error);\n    } else if (id_ == heartbeat_timeout_timer_id) {\n        _has_timeout_timer = false;\n        error (timeout_error);\n    } else\n        // There are no other valid timer ids!\n        assert (false);\n}\n\nint zmq::stream_engine_base_t::read (void *data_, size_t size_)\n{\n    const int rc = zmq::tcp_read (_s, data_, size_);\n\n    if (rc == 0) {\n        // connection closed by peer\n        errno = EPIPE;\n        return -1;\n    }\n\n    return rc;\n}\n\nint zmq::stream_engine_base_t::write (const void *data_, size_t size_)\n{\n    return zmq::tcp_write (_s, data_, size_);\n}\n"
  },
  {
    "path": "src/stream_engine_base.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_STREAM_ENGINE_BASE_HPP_INCLUDED__\n#define __ZMQ_STREAM_ENGINE_BASE_HPP_INCLUDED__\n\n#include <stddef.h>\n\n#include \"fd.hpp\"\n#include \"i_engine.hpp\"\n#include \"io_object.hpp\"\n#include \"i_encoder.hpp\"\n#include \"i_decoder.hpp\"\n#include \"options.hpp\"\n#include \"socket_base.hpp\"\n#include \"metadata.hpp\"\n#include \"msg.hpp\"\n#include \"tcp.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\nclass session_base_t;\nclass mechanism_t;\n\n//  This engine handles any socket with SOCK_STREAM semantics,\n//  e.g. TCP socket or an UNIX domain socket.\n\nclass stream_engine_base_t : public io_object_t, public i_engine\n{\n  public:\n    stream_engine_base_t (fd_t fd_,\n                          const options_t &options_,\n                          const endpoint_uri_pair_t &endpoint_uri_pair_,\n                          bool has_handshake_stage_);\n    ~stream_engine_base_t () ZMQ_OVERRIDE;\n\n    //  i_engine interface implementation.\n    bool has_handshake_stage () ZMQ_FINAL { return _has_handshake_stage; };\n    void plug (zmq::io_thread_t *io_thread_,\n               zmq::session_base_t *session_) ZMQ_FINAL;\n    void terminate () ZMQ_FINAL;\n    bool restart_input () ZMQ_FINAL;\n    void restart_output () ZMQ_FINAL;\n    void zap_msg_available () ZMQ_FINAL;\n    const endpoint_uri_pair_t &get_endpoint () const ZMQ_FINAL;\n\n    //  i_poll_events interface implementation.\n    void in_event () ZMQ_FINAL;\n    void out_event () ZMQ_OVERRIDE;\n    void timer_event (int id_) ZMQ_FINAL;\n\n  protected:\n    typedef metadata_t::dict_t properties_t;\n    bool init_properties (properties_t &properties_);\n\n    //  Function to handle network disconnections.\n    virtual void error (error_reason_t reason_);\n\n    int next_handshake_command (msg_t *msg_);\n    int process_handshake_command (msg_t *msg_);\n\n    int pull_msg_from_session (msg_t *msg_);\n    int push_msg_to_session (msg_t *msg_);\n\n    int pull_and_encode (msg_t *msg_);\n    virtual int decode_and_push (msg_t *msg_);\n    int push_one_then_decode_and_push (msg_t *msg_);\n\n    void set_handshake_timer ();\n\n    virtual bool handshake () { return true; };\n    virtual void plug_internal () {};\n\n    virtual int process_command_message (msg_t *msg_)\n    {\n        LIBZMQ_UNUSED (msg_);\n        return -1;\n    };\n    virtual int produce_ping_message (msg_t *msg_)\n    {\n        LIBZMQ_UNUSED (msg_);\n        return -1;\n    };\n    virtual int process_heartbeat_message (msg_t *msg_)\n    {\n        LIBZMQ_UNUSED (msg_);\n        return -1;\n    };\n    virtual int produce_pong_message (msg_t *msg_)\n    {\n        LIBZMQ_UNUSED (msg_);\n        return -1;\n    };\n\n    virtual int read (void *data, size_t size_);\n    virtual int write (const void *data_, size_t size_);\n\n    void reset_pollout () { io_object_t::reset_pollout (_handle); }\n    void set_pollout () { io_object_t::set_pollout (_handle); }\n    void set_pollin () { io_object_t::set_pollin (_handle); }\n    session_base_t *session () { return _session; }\n    socket_base_t *socket () { return _socket; }\n\n    const options_t _options;\n\n    unsigned char *_inpos;\n    size_t _insize;\n    i_decoder *_decoder;\n\n    unsigned char *_outpos;\n    size_t _outsize;\n    i_encoder *_encoder;\n\n    mechanism_t *_mechanism;\n\n    int (stream_engine_base_t::*_next_msg) (msg_t *msg_);\n    int (stream_engine_base_t::*_process_msg) (msg_t *msg_);\n\n    //  Metadata to be attached to received messages. May be NULL.\n    metadata_t *_metadata;\n\n    //  True iff the engine couldn't consume the last decoded message.\n    bool _input_stopped;\n\n    //  True iff the engine doesn't have any message to encode.\n    bool _output_stopped;\n\n    //  Representation of the connected endpoints.\n    const endpoint_uri_pair_t _endpoint_uri_pair;\n\n    //  ID of the handshake timer\n    enum\n    {\n        handshake_timer_id = 0x40\n    };\n\n    //  True is linger timer is running.\n    bool _has_handshake_timer;\n\n    //  Heartbeat stuff\n    enum\n    {\n        heartbeat_ivl_timer_id = 0x80,\n        heartbeat_timeout_timer_id = 0x81,\n        heartbeat_ttl_timer_id = 0x82\n    };\n    bool _has_ttl_timer;\n    bool _has_timeout_timer;\n    bool _has_heartbeat_timer;\n\n\n    const std::string _peer_address;\n\n  private:\n    bool in_event_internal ();\n\n    //  Unplug the engine from the session.\n    void unplug ();\n\n    int write_credential (msg_t *msg_);\n\n    void mechanism_ready ();\n\n    //  Underlying socket.\n    fd_t _s;\n\n    handle_t _handle;\n\n    bool _plugged;\n\n    //  When true, we are still trying to determine whether\n    //  the peer is using versioned protocol, and if so, which\n    //  version.  When false, normal message flow has started.\n    bool _handshaking;\n\n    msg_t _tx_msg;\n\n    bool _io_error;\n\n    //  The session this engine is attached to.\n    zmq::session_base_t *_session;\n\n    //  Socket\n    zmq::socket_base_t *_socket;\n\n    //  Indicate if engine has an handshake stage, if it does, engine must call session.engine_ready\n    //  when handshake is completed.\n    bool _has_handshake_stage;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (stream_engine_base_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/stream_listener_base.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"stream_listener_base.hpp\"\n#include \"session_base.hpp\"\n#include \"socket_base.hpp\"\n#include \"zmtp_engine.hpp\"\n#include \"raw_engine.hpp\"\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#else\n#include <winsock2.h>\n#endif\n\nzmq::stream_listener_base_t::stream_listener_base_t (\n  zmq::io_thread_t *io_thread_,\n  zmq::socket_base_t *socket_,\n  const zmq::options_t &options_) :\n    own_t (io_thread_, options_),\n    io_object_t (io_thread_),\n    _s (retired_fd),\n    _handle (static_cast<handle_t> (NULL)),\n    _socket (socket_)\n{\n}\n\nzmq::stream_listener_base_t::~stream_listener_base_t ()\n{\n    zmq_assert (_s == retired_fd);\n    zmq_assert (!_handle);\n}\n\nint zmq::stream_listener_base_t::get_local_address (std::string &addr_) const\n{\n    addr_ = get_socket_name (_s, socket_end_local);\n    return addr_.empty () ? -1 : 0;\n}\n\nvoid zmq::stream_listener_base_t::process_plug ()\n{\n    //  Start polling for incoming connections.\n    _handle = add_fd (_s);\n    set_pollin (_handle);\n}\n\nvoid zmq::stream_listener_base_t::process_term (int linger_)\n{\n    rm_fd (_handle);\n    _handle = static_cast<handle_t> (NULL);\n    close ();\n    own_t::process_term (linger_);\n}\n\nint zmq::stream_listener_base_t::close ()\n{\n    // TODO this is identical to stream_connector_base_t::close\n\n    zmq_assert (_s != retired_fd);\n#ifdef ZMQ_HAVE_WINDOWS\n    const int rc = closesocket (_s);\n    wsa_assert (rc != SOCKET_ERROR);\n#else\n    const int rc = ::close (_s);\n    errno_assert (rc == 0);\n#endif\n    _socket->event_closed (make_unconnected_bind_endpoint_pair (_endpoint), _s);\n    _s = retired_fd;\n\n    return 0;\n}\n\nvoid zmq::stream_listener_base_t::create_engine (fd_t fd_)\n{\n    const endpoint_uri_pair_t endpoint_pair (\n      get_socket_name (fd_, socket_end_local),\n      get_socket_name (fd_, socket_end_remote), endpoint_type_bind);\n\n    i_engine *engine;\n    if (options.raw_socket)\n        engine = new (std::nothrow) raw_engine_t (fd_, options, endpoint_pair);\n    else\n        engine = new (std::nothrow) zmtp_engine_t (fd_, options, endpoint_pair);\n    alloc_assert (engine);\n\n    //  Choose I/O thread to run connecter in. Given that we are already\n    //  running in an I/O thread, there must be at least one available.\n    io_thread_t *io_thread = choose_io_thread (options.affinity);\n    zmq_assert (io_thread);\n\n    //  Create and launch a session object.\n    session_base_t *session =\n      session_base_t::create (io_thread, false, _socket, options, NULL);\n    errno_assert (session);\n    session->inc_seqnum ();\n    launch_child (session);\n    send_attach (session, engine, false);\n\n    _socket->event_accepted (endpoint_pair, fd_);\n}\n"
  },
  {
    "path": "src/stream_listener_base.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_STREAM_LISTENER_BASE_HPP_INCLUDED__\n#define __ZMQ_STREAM_LISTENER_BASE_HPP_INCLUDED__\n\n#include <string>\n\n#include \"fd.hpp\"\n#include \"own.hpp\"\n#include \"stdint.hpp\"\n#include \"io_object.hpp\"\n#include \"address.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\nclass socket_base_t;\n\nclass stream_listener_base_t : public own_t, public io_object_t\n{\n  public:\n    stream_listener_base_t (zmq::io_thread_t *io_thread_,\n                            zmq::socket_base_t *socket_,\n                            const options_t &options_);\n    ~stream_listener_base_t () ZMQ_OVERRIDE;\n\n    // Get the bound address for use with wildcards\n    int get_local_address (std::string &addr_) const;\n\n  protected:\n    virtual std::string get_socket_name (fd_t fd_,\n                                         socket_end_t socket_end_) const = 0;\n\n  private:\n    //  Handlers for incoming commands.\n    void process_plug () ZMQ_FINAL;\n    void process_term (int linger_) ZMQ_FINAL;\n\n  protected:\n    //  Close the listening socket.\n    virtual int close ();\n\n    virtual void create_engine (fd_t fd);\n\n    //  Underlying socket.\n    fd_t _s;\n\n    //  Handle corresponding to the listening socket.\n    handle_t _handle;\n\n    //  Socket the listener belongs to.\n    zmq::socket_base_t *_socket;\n\n    // String representation of endpoint to bind to\n    std::string _endpoint;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (stream_listener_base_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/sub.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"sub.hpp\"\n#include \"msg.hpp\"\n\nzmq::sub_t::sub_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    xsub_t (parent_, tid_, sid_)\n{\n    options.type = ZMQ_SUB;\n\n    //  Switch filtering messages on (as opposed to XSUB which where the\n    //  filtering is off).\n    options.filter = true;\n}\n\nzmq::sub_t::~sub_t ()\n{\n}\n\nint zmq::sub_t::xsetsockopt (int option_,\n                             const void *optval_,\n                             size_t optvallen_)\n{\n    if (option_ != ZMQ_SUBSCRIBE && option_ != ZMQ_UNSUBSCRIBE) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    //  Create the subscription message.\n    msg_t msg;\n    int rc;\n    const unsigned char *data = static_cast<const unsigned char *> (optval_);\n    if (option_ == ZMQ_SUBSCRIBE) {\n        rc = msg.init_subscribe (optvallen_, data);\n    } else {\n        rc = msg.init_cancel (optvallen_, data);\n    }\n    errno_assert (rc == 0);\n\n    //  Pass it further on in the stack.\n    rc = xsub_t::xsend (&msg);\n    return close_and_return (&msg, rc);\n}\n\nint zmq::sub_t::xsend (msg_t *)\n{\n    //  Override the XSUB's send.\n    errno = ENOTSUP;\n    return -1;\n}\n\nbool zmq::sub_t::xhas_out ()\n{\n    //  Override the XSUB's send.\n    return false;\n}\n"
  },
  {
    "path": "src/sub.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_SUB_HPP_INCLUDED__\n#define __ZMQ_SUB_HPP_INCLUDED__\n\n#include \"xsub.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass io_thread_t;\nclass socket_base_t;\n\nclass sub_t ZMQ_FINAL : public xsub_t\n{\n  public:\n    sub_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~sub_t ();\n\n  protected:\n    int xsetsockopt (int option_, const void *optval_, size_t optvallen_);\n    int xsend (zmq::msg_t *msg_);\n    bool xhas_out ();\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (sub_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/tcp.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"ip.hpp\"\n#include \"tcp.hpp\"\n#include \"err.hpp\"\n#include \"options.hpp\"\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <fcntl.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <unistd.h>\n#ifdef ZMQ_HAVE_VXWORKS\n#include <sockLib.h>\n#endif\n#endif\n\n#if defined ZMQ_HAVE_OPENVMS\n#include <ioctl.h>\n#endif\n\n#ifdef __APPLE__\n#include <TargetConditionals.h>\n#endif\n\nint zmq::tune_tcp_socket (fd_t s_)\n{\n    //  Disable Nagle's algorithm. We are doing data batching on 0MQ level,\n    //  so using Nagle wouldn't improve throughput in anyway, but it would\n    //  hurt latency.\n    int nodelay = 1;\n    const int rc =\n      setsockopt (s_, IPPROTO_TCP, TCP_NODELAY,\n                  reinterpret_cast<char *> (&nodelay), sizeof (int));\n    assert_success_or_recoverable (s_, rc);\n    if (rc != 0)\n        return rc;\n\n#ifdef ZMQ_HAVE_OPENVMS\n    //  Disable delayed acknowledgements as they hurt latency significantly.\n    int nodelack = 1;\n    rc = setsockopt (s_, IPPROTO_TCP, TCP_NODELACK, (char *) &nodelack,\n                     sizeof (int));\n    assert_success_or_recoverable (s_, rc);\n#endif\n    return rc;\n}\n\nint zmq::set_tcp_send_buffer (fd_t sockfd_, int bufsize_)\n{\n    const int rc =\n      setsockopt (sockfd_, SOL_SOCKET, SO_SNDBUF,\n                  reinterpret_cast<char *> (&bufsize_), sizeof bufsize_);\n    assert_success_or_recoverable (sockfd_, rc);\n    return rc;\n}\n\nint zmq::set_tcp_receive_buffer (fd_t sockfd_, int bufsize_)\n{\n    const int rc =\n      setsockopt (sockfd_, SOL_SOCKET, SO_RCVBUF,\n                  reinterpret_cast<char *> (&bufsize_), sizeof bufsize_);\n    assert_success_or_recoverable (sockfd_, rc);\n    return rc;\n}\n\nint zmq::tune_tcp_keepalives (fd_t s_,\n                              int keepalive_,\n                              int keepalive_cnt_,\n                              int keepalive_idle_,\n                              int keepalive_intvl_)\n{\n    // These options are used only under certain #ifdefs below.\n    LIBZMQ_UNUSED (keepalive_);\n    LIBZMQ_UNUSED (keepalive_cnt_);\n    LIBZMQ_UNUSED (keepalive_idle_);\n    LIBZMQ_UNUSED (keepalive_intvl_);\n\n    // If none of the #ifdefs apply, then s_ is unused.\n    LIBZMQ_UNUSED (s_);\n\n    //  Tuning TCP keep-alives if platform allows it\n    //  All values = -1 means skip and leave it for OS\n#ifdef ZMQ_HAVE_WINDOWS\n    if (keepalive_ != -1) {\n        tcp_keepalive keepalive_opts;\n        keepalive_opts.onoff = keepalive_;\n        keepalive_opts.keepalivetime =\n          keepalive_idle_ != -1 ? keepalive_idle_ * 1000 : 7200000;\n        keepalive_opts.keepaliveinterval =\n          keepalive_intvl_ != -1 ? keepalive_intvl_ * 1000 : 1000;\n        DWORD num_bytes_returned;\n        const int rc = WSAIoctl (s_, SIO_KEEPALIVE_VALS, &keepalive_opts,\n                                 sizeof (keepalive_opts), NULL, 0,\n                                 &num_bytes_returned, NULL, NULL);\n        assert_success_or_recoverable (s_, rc);\n        if (rc == SOCKET_ERROR)\n            return rc;\n    }\n#else\n#ifdef ZMQ_HAVE_SO_KEEPALIVE\n    if (keepalive_ != -1) {\n        int rc =\n          setsockopt (s_, SOL_SOCKET, SO_KEEPALIVE,\n                      reinterpret_cast<char *> (&keepalive_), sizeof (int));\n        assert_success_or_recoverable (s_, rc);\n        if (rc != 0)\n            return rc;\n\n#ifdef ZMQ_HAVE_TCP_KEEPCNT\n        if (keepalive_cnt_ != -1) {\n            int rc = setsockopt (s_, IPPROTO_TCP, TCP_KEEPCNT, &keepalive_cnt_,\n                                 sizeof (int));\n            assert_success_or_recoverable (s_, rc);\n            if (rc != 0)\n                return rc;\n        }\n#endif // ZMQ_HAVE_TCP_KEEPCNT\n\n#ifdef ZMQ_HAVE_TCP_KEEPIDLE\n        if (keepalive_idle_ != -1) {\n            int rc = setsockopt (s_, IPPROTO_TCP, TCP_KEEPIDLE,\n                                 &keepalive_idle_, sizeof (int));\n            assert_success_or_recoverable (s_, rc);\n            if (rc != 0)\n                return rc;\n        }\n#else // ZMQ_HAVE_TCP_KEEPIDLE\n#ifdef ZMQ_HAVE_TCP_KEEPALIVE\n        if (keepalive_idle_ != -1) {\n            int rc = setsockopt (s_, IPPROTO_TCP, TCP_KEEPALIVE,\n                                 &keepalive_idle_, sizeof (int));\n            assert_success_or_recoverable (s_, rc);\n            if (rc != 0)\n                return rc;\n        }\n#endif // ZMQ_HAVE_TCP_KEEPALIVE\n#endif // ZMQ_HAVE_TCP_KEEPIDLE\n\n#ifdef ZMQ_HAVE_TCP_KEEPINTVL\n        if (keepalive_intvl_ != -1) {\n            int rc = setsockopt (s_, IPPROTO_TCP, TCP_KEEPINTVL,\n                                 &keepalive_intvl_, sizeof (int));\n            assert_success_or_recoverable (s_, rc);\n            if (rc != 0)\n                return rc;\n        }\n#endif // ZMQ_HAVE_TCP_KEEPINTVL\n    }\n#endif // ZMQ_HAVE_SO_KEEPALIVE\n#endif // ZMQ_HAVE_WINDOWS\n\n    return 0;\n}\n\nint zmq::tune_tcp_maxrt (fd_t sockfd_, int timeout_)\n{\n    if (timeout_ <= 0)\n        return 0;\n\n    LIBZMQ_UNUSED (sockfd_);\n\n#if defined(ZMQ_HAVE_WINDOWS) && defined(TCP_MAXRT)\n    // msdn says it's supported in >= Vista, >= Windows Server 2003\n    timeout_ /= 1000; // in seconds\n    const int rc =\n      setsockopt (sockfd_, IPPROTO_TCP, TCP_MAXRT,\n                  reinterpret_cast<char *> (&timeout_), sizeof (timeout_));\n    assert_success_or_recoverable (sockfd_, rc);\n    return rc;\n// FIXME: should be ZMQ_HAVE_TCP_USER_TIMEOUT\n#elif defined(TCP_USER_TIMEOUT)\n    int rc = setsockopt (sockfd_, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout_,\n                         sizeof (timeout_));\n    assert_success_or_recoverable (sockfd_, rc);\n    return rc;\n#else\n    return 0;\n#endif\n}\n\nint zmq::tcp_write (fd_t s_, const void *data_, size_t size_)\n{\n#ifdef ZMQ_HAVE_WINDOWS\n\n    const int nbytes = send (s_, (char *) data_, static_cast<int> (size_), 0);\n\n    //  If not a single byte can be written to the socket in non-blocking mode\n    //  we'll get an error (this may happen during the speculative write).\n    const int last_error = WSAGetLastError ();\n    if (nbytes == SOCKET_ERROR && last_error == WSAEWOULDBLOCK)\n        return 0;\n\n    //  Signalise peer failure.\n    if (nbytes == SOCKET_ERROR\n        && (last_error == WSAENETDOWN || last_error == WSAENETRESET\n            || last_error == WSAEHOSTUNREACH || last_error == WSAECONNABORTED\n            || last_error == WSAETIMEDOUT || last_error == WSAECONNRESET))\n        return -1;\n\n    //  Circumvent a Windows bug:\n    //  See https://support.microsoft.com/en-us/kb/201213\n    //  See https://zeromq.jira.com/browse/LIBZMQ-195\n    if (nbytes == SOCKET_ERROR && last_error == WSAENOBUFS)\n        return 0;\n\n    wsa_assert (nbytes != SOCKET_ERROR);\n    return nbytes;\n\n#else\n    ssize_t nbytes = send (s_, static_cast<const char *> (data_), size_, 0);\n\n    //  Several errors are OK. When speculative write is being done we may not\n    //  be able to write a single byte from the socket. Also, SIGSTOP issued\n    //  by a debugging tool can result in EINTR error.\n    if (nbytes == -1\n        && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))\n        return 0;\n\n    //  Signalise peer failure.\n    if (nbytes == -1) {\n#if !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE\n        errno_assert (errno != EACCES && errno != EBADF && errno != EDESTADDRREQ\n                      && errno != EFAULT && errno != EISCONN\n                      && errno != EMSGSIZE && errno != ENOMEM\n                      && errno != ENOTSOCK && errno != EOPNOTSUPP);\n#else\n        errno_assert (errno != EACCES && errno != EDESTADDRREQ\n                      && errno != EFAULT && errno != EISCONN\n                      && errno != EMSGSIZE && errno != ENOMEM\n                      && errno != ENOTSOCK && errno != EOPNOTSUPP);\n#endif\n        return -1;\n    }\n\n    return static_cast<int> (nbytes);\n\n#endif\n}\n\nint zmq::tcp_read (fd_t s_, void *data_, size_t size_)\n{\n#ifdef ZMQ_HAVE_WINDOWS\n\n    const int rc =\n      recv (s_, static_cast<char *> (data_), static_cast<int> (size_), 0);\n\n    //  If not a single byte can be read from the socket in non-blocking mode\n    //  we'll get an error (this may happen during the speculative read).\n    if (rc == SOCKET_ERROR) {\n        const int last_error = WSAGetLastError ();\n        if (last_error == WSAEWOULDBLOCK) {\n            errno = EAGAIN;\n        } else {\n            wsa_assert (\n              last_error == WSAENETDOWN || last_error == WSAENETRESET\n              || last_error == WSAECONNABORTED || last_error == WSAETIMEDOUT\n              || last_error == WSAECONNRESET || last_error == WSAECONNREFUSED\n              || last_error == WSAENOTCONN || last_error == WSAENOBUFS);\n            errno = wsa_error_to_errno (last_error);\n        }\n    }\n\n    return rc == SOCKET_ERROR ? -1 : rc;\n\n#else\n\n    const ssize_t rc = recv (s_, static_cast<char *> (data_), size_, 0);\n\n    //  Several errors are OK. When speculative read is being done we may not\n    //  be able to read a single byte from the socket. Also, SIGSTOP issued\n    //  by a debugging tool can result in EINTR error.\n    if (rc == -1) {\n#if !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE\n        errno_assert (errno != EBADF && errno != EFAULT && errno != ENOMEM\n                      && errno != ENOTSOCK);\n#else\n        errno_assert (errno != EFAULT && errno != ENOMEM && errno != ENOTSOCK);\n#endif\n        if (errno == EWOULDBLOCK || errno == EINTR)\n            errno = EAGAIN;\n    }\n\n    return static_cast<int> (rc);\n\n#endif\n}\n\nvoid zmq::tcp_tune_loopback_fast_path (const fd_t socket_)\n{\n#if defined ZMQ_HAVE_WINDOWS && defined SIO_LOOPBACK_FAST_PATH\n    int sio_loopback_fastpath = 1;\n    DWORD number_of_bytes_returned = 0;\n\n    const int rc = WSAIoctl (\n      socket_, SIO_LOOPBACK_FAST_PATH, &sio_loopback_fastpath,\n      sizeof sio_loopback_fastpath, NULL, 0, &number_of_bytes_returned, 0, 0);\n\n    if (SOCKET_ERROR == rc) {\n        const DWORD last_error = ::WSAGetLastError ();\n\n        if (WSAEOPNOTSUPP == last_error) {\n            // This system is not Windows 8 or Server 2012, and the call is not supported.\n        } else {\n            wsa_assert (false);\n        }\n    }\n#else\n    LIBZMQ_UNUSED (socket_);\n#endif\n}\n\nvoid zmq::tune_tcp_busy_poll (fd_t socket_, int busy_poll_)\n{\n#if defined(ZMQ_HAVE_BUSY_POLL)\n    if (busy_poll_ > 0) {\n        const int rc =\n          setsockopt (socket_, SOL_SOCKET, SO_BUSY_POLL,\n                      reinterpret_cast<char *> (&busy_poll_), sizeof (int));\n        assert_success_or_recoverable (socket_, rc);\n    }\n#else\n    LIBZMQ_UNUSED (socket_);\n    LIBZMQ_UNUSED (busy_poll_);\n#endif\n}\n\nzmq::fd_t zmq::tcp_open_socket (const char *address_,\n                                const zmq::options_t &options_,\n                                bool local_,\n                                bool fallback_to_ipv4_,\n                                zmq::tcp_address_t *out_tcp_addr_)\n{\n    //  Convert the textual address into address structure.\n    int rc = out_tcp_addr_->resolve (address_, local_, options_.ipv6);\n    if (rc != 0)\n        return retired_fd;\n\n    //  Create the socket.\n    fd_t s = open_socket (out_tcp_addr_->family (), SOCK_STREAM, IPPROTO_TCP);\n\n    //  IPv6 address family not supported, try automatic downgrade to IPv4.\n    if (s == retired_fd && fallback_to_ipv4_\n        && out_tcp_addr_->family () == AF_INET6 && errno == EAFNOSUPPORT\n        && options_.ipv6) {\n        rc = out_tcp_addr_->resolve (address_, local_, false);\n        if (rc != 0) {\n            return retired_fd;\n        }\n        s = open_socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\n    }\n\n    if (s == retired_fd) {\n        return retired_fd;\n    }\n\n    //  On some systems, IPv4 mapping in IPv6 sockets is disabled by default.\n    //  Switch it on in such cases.\n    if (out_tcp_addr_->family () == AF_INET6)\n        enable_ipv4_mapping (s);\n\n    // Set the IP Type-Of-Service priority for this socket\n    if (options_.tos != 0)\n        set_ip_type_of_service (s, options_.tos);\n\n    // Set the protocol-defined priority for this socket\n    if (options_.priority != 0)\n        set_socket_priority (s, options_.priority);\n\n    // Set the socket to loopback fastpath if configured.\n    if (options_.loopback_fastpath)\n        tcp_tune_loopback_fast_path (s);\n\n    // Bind the socket to a device if applicable\n    if (!options_.bound_device.empty ())\n        if (bind_to_device (s, options_.bound_device) == -1)\n            goto setsockopt_error;\n\n    //  Set the socket buffer limits for the underlying socket.\n    if (options_.sndbuf >= 0)\n        set_tcp_send_buffer (s, options_.sndbuf);\n    if (options_.rcvbuf >= 0)\n        set_tcp_receive_buffer (s, options_.rcvbuf);\n\n    //  This option removes several delays caused by scheduling, interrupts and context switching.\n    if (options_.busy_poll)\n        tune_tcp_busy_poll (s, options_.busy_poll);\n    return s;\n\nsetsockopt_error:\n#ifdef ZMQ_HAVE_WINDOWS\n    rc = closesocket (s);\n    wsa_assert (rc != SOCKET_ERROR);\n#else\n    rc = ::close (s);\n    errno_assert (rc == 0);\n#endif\n    return retired_fd;\n}\n"
  },
  {
    "path": "src/tcp.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_TCP_HPP_INCLUDED__\n#define __ZMQ_TCP_HPP_INCLUDED__\n\n#include \"fd.hpp\"\n\nnamespace zmq\n{\nclass tcp_address_t;\nstruct options_t;\n\n//  Tunes the supplied TCP socket for the best latency.\nint tune_tcp_socket (fd_t s_);\n\n//  Sets the socket send buffer size.\nint set_tcp_send_buffer (fd_t sockfd_, int bufsize_);\n\n//  Sets the socket receive buffer size.\nint set_tcp_receive_buffer (fd_t sockfd_, int bufsize_);\n\n//  Tunes TCP keep-alives\nint tune_tcp_keepalives (fd_t s_,\n                         int keepalive_,\n                         int keepalive_cnt_,\n                         int keepalive_idle_,\n                         int keepalive_intvl_);\n\n//  Tunes TCP max retransmit timeout\nint tune_tcp_maxrt (fd_t sockfd_, int timeout_);\n\n//  Writes data to the socket. Returns the number of bytes actually\n//  written (even zero is to be considered to be a success). In case\n//  of error or orderly shutdown by the other peer -1 is returned.\nint tcp_write (fd_t s_, const void *data_, size_t size_);\n\n//  Reads data from the socket (up to 'size' bytes).\n//  Returns the number of bytes actually read or -1 on error.\n//  Zero indicates the peer has closed the connection.\nint tcp_read (fd_t s_, void *data_, size_t size_);\n\nvoid tcp_tune_loopback_fast_path (fd_t socket_);\n\nvoid tune_tcp_busy_poll (fd_t socket_, int busy_poll_);\n\n//  Resolves the given address_ string, opens a socket and sets socket options\n//  according to the passed options_. On success, returns the socket\n//  descriptor and assigns the resolved address to out_tcp_addr_. In case of\n//  an error, retired_fd is returned, and the value of out_tcp_addr_ is undefined.\n//  errno is set to an error code describing the cause of the error.\nfd_t tcp_open_socket (const char *address_,\n                      const options_t &options_,\n                      bool local_,\n                      bool fallback_to_ipv4_,\n                      tcp_address_t *out_tcp_addr_);\n}\n\n#endif\n"
  },
  {
    "path": "src/tcp_address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string>\n\n#include \"macros.hpp\"\n#include \"tcp_address.hpp\"\n#include \"stdint.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <sys/types.h>\n#include <arpa/inet.h>\n#include <netinet/tcp.h>\n#include <net/if.h>\n#include <netdb.h>\n#include <ctype.h>\n#include <unistd.h>\n#include <stdlib.h>\n#endif\n\n#include <limits.h>\n\nzmq::tcp_address_t::tcp_address_t () : _has_src_addr (false)\n{\n    memset (&_address, 0, sizeof (_address));\n    memset (&_source_address, 0, sizeof (_source_address));\n}\n\nzmq::tcp_address_t::tcp_address_t (const sockaddr *sa_, socklen_t sa_len_) :\n    _has_src_addr (false)\n{\n    zmq_assert (sa_ && sa_len_ > 0);\n\n    memset (&_address, 0, sizeof (_address));\n    memset (&_source_address, 0, sizeof (_source_address));\n    if (sa_->sa_family == AF_INET\n        && sa_len_ >= static_cast<socklen_t> (sizeof (_address.ipv4)))\n        memcpy (&_address.ipv4, sa_, sizeof (_address.ipv4));\n    else if (sa_->sa_family == AF_INET6\n             && sa_len_ >= static_cast<socklen_t> (sizeof (_address.ipv6)))\n        memcpy (&_address.ipv6, sa_, sizeof (_address.ipv6));\n}\n\nint zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv6_)\n{\n    // Test the ';' to know if we have a source address in name_\n    const char *src_delimiter = strrchr (name_, ';');\n    if (src_delimiter) {\n        const std::string src_name (name_, src_delimiter - name_);\n\n        ip_resolver_options_t src_resolver_opts;\n\n        src_resolver_opts\n          .bindable (true)\n          //  Restrict hostname/service to literals to avoid any DNS\n          //  lookups or service-name irregularity due to\n          //  indeterminate socktype.\n          .allow_dns (false)\n          .allow_nic_name (true)\n          .ipv6 (ipv6_)\n          .expect_port (true);\n\n        ip_resolver_t src_resolver (src_resolver_opts);\n\n        const int rc =\n          src_resolver.resolve (&_source_address, src_name.c_str ());\n        if (rc != 0)\n            return -1;\n        name_ = src_delimiter + 1;\n        _has_src_addr = true;\n    }\n\n    ip_resolver_options_t resolver_opts;\n\n    resolver_opts.bindable (local_)\n      .allow_dns (true)\n      .allow_nic_name (local_)\n      .ipv6 (ipv6_)\n      .expect_port (true);\n\n    ip_resolver_t resolver (resolver_opts);\n\n    return resolver.resolve (&_address, name_);\n}\n\ntemplate <size_t N1, size_t N2>\nstatic std::string make_address_string (const char *hbuf_,\n                                        uint16_t port_,\n                                        const char (&ipv6_prefix_)[N1],\n                                        const char (&ipv6_suffix_)[N2])\n{\n    const size_t max_port_str_length = 5;\n    char buf[NI_MAXHOST + sizeof ipv6_prefix_ + sizeof ipv6_suffix_\n             + max_port_str_length];\n    char *pos = buf;\n    memcpy (pos, ipv6_prefix_, sizeof ipv6_prefix_ - 1);\n    pos += sizeof ipv6_prefix_ - 1;\n    const size_t hbuf_len = strlen (hbuf_);\n    memcpy (pos, hbuf_, hbuf_len);\n    pos += hbuf_len;\n    memcpy (pos, ipv6_suffix_, sizeof ipv6_suffix_ - 1);\n    pos += sizeof ipv6_suffix_ - 1;\n    int res = snprintf (pos, max_port_str_length + 1, \"%d\", ntohs (port_));\n    zmq_assert (res > 0 && res < (int) (max_port_str_length + 1));\n    pos += res;\n    return std::string (buf, pos - buf);\n}\n\nint zmq::tcp_address_t::to_string (std::string &addr_) const\n{\n    if (_address.family () != AF_INET && _address.family () != AF_INET6) {\n        addr_.clear ();\n        return -1;\n    }\n\n    //  Not using service resolving because of\n    //  https://github.com/zeromq/libzmq/commit/1824574f9b5a8ce786853320e3ea09fe1f822bc4\n    char hbuf[NI_MAXHOST];\n    const int rc = getnameinfo (addr (), addrlen (), hbuf, sizeof (hbuf), NULL,\n                                0, NI_NUMERICHOST);\n    if (rc != 0) {\n        addr_.clear ();\n        return rc;\n    }\n\n    const char ipv4_prefix[] = \"tcp://\";\n    const char ipv4_suffix[] = \":\";\n    const char ipv6_prefix[] = \"tcp://[\";\n    const char ipv6_suffix[] = \"]:\";\n    if (_address.family () == AF_INET6) {\n        addr_ = make_address_string (hbuf, _address.ipv6.sin6_port, ipv6_prefix,\n                                     ipv6_suffix);\n    } else {\n        addr_ = make_address_string (hbuf, _address.ipv4.sin_port, ipv4_prefix,\n                                     ipv4_suffix);\n    }\n    return 0;\n}\n\nconst sockaddr *zmq::tcp_address_t::addr () const\n{\n    return _address.as_sockaddr ();\n}\n\nsocklen_t zmq::tcp_address_t::addrlen () const\n{\n    return _address.sockaddr_len ();\n}\n\nconst sockaddr *zmq::tcp_address_t::src_addr () const\n{\n    return _source_address.as_sockaddr ();\n}\n\nsocklen_t zmq::tcp_address_t::src_addrlen () const\n{\n    return _source_address.sockaddr_len ();\n}\n\nbool zmq::tcp_address_t::has_src_addr () const\n{\n    return _has_src_addr;\n}\n\n#if defined ZMQ_HAVE_WINDOWS\nunsigned short zmq::tcp_address_t::family () const\n#else\nsa_family_t zmq::tcp_address_t::family () const\n#endif\n{\n    return _address.family ();\n}\n\nzmq::tcp_address_mask_t::tcp_address_mask_t () : _address_mask (-1)\n{\n    memset (&_network_address, 0, sizeof (_network_address));\n}\n\nint zmq::tcp_address_mask_t::resolve (const char *name_, bool ipv6_)\n{\n    // Find '/' at the end that separates address from the cidr mask number.\n    // Allow empty mask clause and treat it like '/32' for ipv4 or '/128' for ipv6.\n    std::string addr_str, mask_str;\n    const char *delimiter = strrchr (name_, '/');\n    if (delimiter != NULL) {\n        addr_str.assign (name_, delimiter - name_);\n        mask_str.assign (delimiter + 1);\n        if (mask_str.empty ()) {\n            errno = EINVAL;\n            return -1;\n        }\n    } else\n        addr_str.assign (name_);\n\n    // Parse address part using standard routines.\n    ip_resolver_options_t resolver_opts;\n\n    resolver_opts.bindable (false)\n      .allow_dns (false)\n      .allow_nic_name (false)\n      .ipv6 (ipv6_)\n      .expect_port (false);\n\n    ip_resolver_t resolver (resolver_opts);\n\n    const int rc = resolver.resolve (&_network_address, addr_str.c_str ());\n    if (rc != 0)\n        return rc;\n\n    // Parse the cidr mask number.\n    const int full_mask_ipv4 =\n      sizeof (_network_address.ipv4.sin_addr) * CHAR_BIT;\n    const int full_mask_ipv6 =\n      sizeof (_network_address.ipv6.sin6_addr) * CHAR_BIT;\n    if (mask_str.empty ()) {\n        _address_mask = _network_address.family () == AF_INET6 ? full_mask_ipv6\n                                                               : full_mask_ipv4;\n    } else if (mask_str == \"0\")\n        _address_mask = 0;\n    else {\n        const long mask = strtol (mask_str.c_str (), NULL, 10);\n        if ((mask < 1)\n            || (_network_address.family () == AF_INET6 && mask > full_mask_ipv6)\n            || (_network_address.family () != AF_INET6\n                && mask > full_mask_ipv4)) {\n            errno = EINVAL;\n            return -1;\n        }\n        _address_mask = static_cast<int> (mask);\n    }\n\n    return 0;\n}\n\nbool zmq::tcp_address_mask_t::match_address (const struct sockaddr *ss_,\n                                             const socklen_t ss_len_) const\n{\n    zmq_assert (_address_mask != -1 && ss_ != NULL\n                && ss_len_\n                     >= static_cast<socklen_t> (sizeof (struct sockaddr)));\n\n    if (ss_->sa_family != _network_address.generic.sa_family)\n        return false;\n\n    if (_address_mask > 0) {\n        int mask;\n        const uint8_t *our_bytes, *their_bytes;\n        if (ss_->sa_family == AF_INET6) {\n            zmq_assert (ss_len_ == sizeof (struct sockaddr_in6));\n            their_bytes = reinterpret_cast<const uint8_t *> (\n              &((reinterpret_cast<const struct sockaddr_in6 *> (ss_))\n                  ->sin6_addr));\n            our_bytes = reinterpret_cast<const uint8_t *> (\n              &_network_address.ipv6.sin6_addr);\n            mask = sizeof (struct in6_addr) * 8;\n        } else {\n            zmq_assert (ss_len_ == sizeof (struct sockaddr_in));\n            their_bytes = reinterpret_cast<const uint8_t *> (&(\n              (reinterpret_cast<const struct sockaddr_in *> (ss_))->sin_addr));\n            our_bytes = reinterpret_cast<const uint8_t *> (\n              &_network_address.ipv4.sin_addr);\n            mask = sizeof (struct in_addr) * 8;\n        }\n        if (_address_mask < mask)\n            mask = _address_mask;\n\n        const size_t full_bytes = mask / 8;\n        if (memcmp (our_bytes, their_bytes, full_bytes) != 0)\n            return false;\n\n        const uint8_t last_byte_bits = 0xffU << (8 - mask % 8);\n        if (last_byte_bits) {\n            if ((their_bytes[full_bytes] & last_byte_bits)\n                != (our_bytes[full_bytes] & last_byte_bits))\n                return false;\n        }\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "src/tcp_address.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_TCP_ADDRESS_HPP_INCLUDED__\n#define __ZMQ_TCP_ADDRESS_HPP_INCLUDED__\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <sys/socket.h>\n#include <netinet/in.h>\n#endif\n\n#include \"ip_resolver.hpp\"\n\nnamespace zmq\n{\nclass tcp_address_t\n{\n  public:\n    tcp_address_t ();\n    tcp_address_t (const sockaddr *sa_, socklen_t sa_len_);\n\n    //  This function translates textual TCP address into an address\n    //  structure. If 'local' is true, names are resolved as local interface\n    //  names. If it is false, names are resolved as remote hostnames.\n    //  If 'ipv6' is true, the name may resolve to IPv6 address.\n    int resolve (const char *name_, bool local_, bool ipv6_);\n\n    //  The opposite to resolve()\n    int to_string (std::string &addr_) const;\n\n#if defined ZMQ_HAVE_WINDOWS\n    unsigned short family () const;\n#else\n    sa_family_t family () const;\n#endif\n    const sockaddr *addr () const;\n    socklen_t addrlen () const;\n\n    const sockaddr *src_addr () const;\n    socklen_t src_addrlen () const;\n    bool has_src_addr () const;\n\n  private:\n    ip_addr_t _address;\n    ip_addr_t _source_address;\n    bool _has_src_addr;\n};\n\nclass tcp_address_mask_t\n{\n  public:\n    tcp_address_mask_t ();\n\n    // This function enhances tcp_address_t::resolve() with ability to parse\n    // additional cidr-like(/xx) mask value at the end of the name string.\n    // Works only with remote hostnames.\n    int resolve (const char *name_, bool ipv6_);\n\n    bool match_address (const struct sockaddr *ss_, socklen_t ss_len_) const;\n\n  private:\n    ip_addr_t _network_address;\n    int _address_mask;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/tcp_connecter.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <new>\n#include <string>\n\n#include \"macros.hpp\"\n#include \"tcp_connecter.hpp\"\n#include \"io_thread.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"tcp.hpp\"\n#include \"address.hpp\"\n#include \"tcp_address.hpp\"\n#include \"session_base.hpp\"\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <arpa/inet.h>\n#include <netinet/tcp.h>\n#include <netinet/in.h>\n#include <netdb.h>\n#include <fcntl.h>\n#ifdef ZMQ_HAVE_VXWORKS\n#include <sockLib.h>\n#endif\n#ifdef ZMQ_HAVE_OPENVMS\n#include <ioctl.h>\n#endif\n#endif\n\n#ifdef __APPLE__\n#include <TargetConditionals.h>\n#endif\n\nzmq::tcp_connecter_t::tcp_connecter_t (class io_thread_t *io_thread_,\n                                       class session_base_t *session_,\n                                       const options_t &options_,\n                                       address_t *addr_,\n                                       bool delayed_start_) :\n    stream_connecter_base_t (\n      io_thread_, session_, options_, addr_, delayed_start_),\n    _connect_timer_started (false)\n{\n    zmq_assert (_addr->protocol == protocol_name::tcp);\n}\n\nzmq::tcp_connecter_t::~tcp_connecter_t ()\n{\n    zmq_assert (!_connect_timer_started);\n}\n\nvoid zmq::tcp_connecter_t::process_term (int linger_)\n{\n    if (_connect_timer_started) {\n        cancel_timer (connect_timer_id);\n        _connect_timer_started = false;\n    }\n\n    stream_connecter_base_t::process_term (linger_);\n}\n\nvoid zmq::tcp_connecter_t::out_event ()\n{\n    if (_connect_timer_started) {\n        cancel_timer (connect_timer_id);\n        _connect_timer_started = false;\n    }\n\n    //  TODO this is still very similar to (t)ipc_connecter_t, maybe the\n    //  differences can be factored out\n\n    rm_handle ();\n\n    const fd_t fd = connect ();\n\n    if (fd == retired_fd\n        && ((options.reconnect_stop & ZMQ_RECONNECT_STOP_CONN_REFUSED)\n            && errno == ECONNREFUSED)) {\n        send_conn_failed (_session);\n        close ();\n        terminate ();\n        return;\n    }\n\n    //  Handle the error condition by attempt to reconnect.\n    if (fd == retired_fd || !tune_socket (fd)) {\n        close ();\n        add_reconnect_timer ();\n        return;\n    }\n\n    create_engine (fd, get_socket_name<tcp_address_t> (fd, socket_end_local));\n}\n\nvoid zmq::tcp_connecter_t::timer_event (int id_)\n{\n    if (id_ == connect_timer_id) {\n        _connect_timer_started = false;\n        rm_handle ();\n        close ();\n        add_reconnect_timer ();\n    } else\n        stream_connecter_base_t::timer_event (id_);\n}\n\nvoid zmq::tcp_connecter_t::start_connecting ()\n{\n    //  Open the connecting socket.\n    const int rc = open ();\n\n    //  Connect may succeed in synchronous manner.\n    if (rc == 0) {\n        _handle = add_fd (_s);\n        out_event ();\n    }\n\n    //  Connection establishment may be delayed. Poll for its completion.\n    else if (rc == -1 && errno == EINPROGRESS) {\n        _handle = add_fd (_s);\n        set_pollout (_handle);\n        _socket->event_connect_delayed (\n          make_unconnected_connect_endpoint_pair (_endpoint), zmq_errno ());\n\n        //  add userspace connect timeout\n        add_connect_timer ();\n    }\n\n    //  Handle any other error condition by eventual reconnect.\n    else {\n        if (_s != retired_fd)\n            close ();\n        add_reconnect_timer ();\n    }\n}\n\nvoid zmq::tcp_connecter_t::add_connect_timer ()\n{\n    if (options.connect_timeout > 0) {\n        add_timer (options.connect_timeout, connect_timer_id);\n        _connect_timer_started = true;\n    }\n}\n\nint zmq::tcp_connecter_t::open ()\n{\n    zmq_assert (_s == retired_fd);\n\n    //  Resolve the address\n    if (_addr->resolved.tcp_addr != NULL) {\n        LIBZMQ_DELETE (_addr->resolved.tcp_addr);\n    }\n\n    _addr->resolved.tcp_addr = new (std::nothrow) tcp_address_t ();\n    alloc_assert (_addr->resolved.tcp_addr);\n    _s = tcp_open_socket (_addr->address.c_str (), options, false, true,\n                          _addr->resolved.tcp_addr);\n    if (_s == retired_fd) {\n        //  TODO we should emit some event in this case!\n\n        LIBZMQ_DELETE (_addr->resolved.tcp_addr);\n        return -1;\n    }\n    zmq_assert (_addr->resolved.tcp_addr != NULL);\n\n    // Set the socket to non-blocking mode so that we get async connect().\n    unblock_socket (_s);\n\n    const tcp_address_t *const tcp_addr = _addr->resolved.tcp_addr;\n\n    int rc;\n\n    // Set a source address for conversations\n    if (tcp_addr->has_src_addr ()) {\n        //  Allow reusing of the address, to connect to different servers\n        //  using the same source port on the client.\n        int flag = 1;\n#ifdef ZMQ_HAVE_WINDOWS\n        rc = setsockopt (_s, SOL_SOCKET, SO_REUSEADDR,\n                         reinterpret_cast<const char *> (&flag), sizeof (int));\n        wsa_assert (rc != SOCKET_ERROR);\n#elif defined ZMQ_HAVE_VXWORKS\n        rc = setsockopt (_s, SOL_SOCKET, SO_REUSEADDR, (char *) &flag,\n                         sizeof (int));\n        errno_assert (rc == 0);\n#else\n        rc = setsockopt (_s, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int));\n        errno_assert (rc == 0);\n#endif\n\n#if defined ZMQ_HAVE_VXWORKS\n        rc = ::bind (_s, (sockaddr *) tcp_addr->src_addr (),\n                     tcp_addr->src_addrlen ());\n#else\n        rc = ::bind (_s, tcp_addr->src_addr (), tcp_addr->src_addrlen ());\n#endif\n        if (rc == -1)\n            return -1;\n    }\n\n    //  Connect to the remote peer.\n#if defined ZMQ_HAVE_VXWORKS\n    rc = ::connect (_s, (sockaddr *) tcp_addr->addr (), tcp_addr->addrlen ());\n#else\n    rc = ::connect (_s, tcp_addr->addr (), tcp_addr->addrlen ());\n#endif\n    //  Connect was successful immediately.\n    if (rc == 0) {\n        return 0;\n    }\n\n    //  Translate error codes indicating asynchronous connect has been\n    //  launched to a uniform EINPROGRESS.\n#ifdef ZMQ_HAVE_WINDOWS\n    const int last_error = WSAGetLastError ();\n    if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK)\n        errno = EINPROGRESS;\n    else\n        errno = wsa_error_to_errno (last_error);\n#else\n    if (errno == EINTR)\n        errno = EINPROGRESS;\n#endif\n    return -1;\n}\n\nzmq::fd_t zmq::tcp_connecter_t::connect ()\n{\n    //  Async connect has finished. Check whether an error occurred\n    int err = 0;\n#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS\n    int len = sizeof err;\n#else\n    socklen_t len = sizeof err;\n#endif\n\n    const int rc = getsockopt (_s, SOL_SOCKET, SO_ERROR,\n                               reinterpret_cast<char *> (&err), &len);\n\n    //  Assert if the error was caused by 0MQ bug.\n    //  Networking problems are OK. No need to assert.\n#ifdef ZMQ_HAVE_WINDOWS\n    zmq_assert (rc == 0);\n    if (err != 0) {\n        if (err == WSAEBADF || err == WSAENOPROTOOPT || err == WSAENOTSOCK\n            || err == WSAENOBUFS) {\n            wsa_assert_no (err);\n        }\n        errno = wsa_error_to_errno (err);\n        return retired_fd;\n    }\n#else\n    //  Following code should handle both Berkeley-derived socket\n    //  implementations and Solaris.\n    if (rc == -1)\n        err = errno;\n    if (err != 0) {\n        errno = err;\n#if !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE\n        errno_assert (errno != EBADF && errno != ENOPROTOOPT\n                      && errno != ENOTSOCK && errno != ENOBUFS);\n#else\n        errno_assert (errno != ENOPROTOOPT && errno != ENOTSOCK\n                      && errno != ENOBUFS);\n#endif\n        return retired_fd;\n    }\n#endif\n\n    //  Return the newly connected socket.\n    const fd_t result = _s;\n    _s = retired_fd;\n    return result;\n}\n\nbool zmq::tcp_connecter_t::tune_socket (const fd_t fd_)\n{\n    const int rc = tune_tcp_socket (fd_)\n                   | tune_tcp_keepalives (\n                     fd_, options.tcp_keepalive, options.tcp_keepalive_cnt,\n                     options.tcp_keepalive_idle, options.tcp_keepalive_intvl)\n                   | tune_tcp_maxrt (fd_, options.tcp_maxrt);\n    return rc == 0;\n}\n"
  },
  {
    "path": "src/tcp_connecter.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __TCP_CONNECTER_HPP_INCLUDED__\n#define __TCP_CONNECTER_HPP_INCLUDED__\n\n#include \"fd.hpp\"\n#include \"stdint.hpp\"\n#include \"stream_connecter_base.hpp\"\n\nnamespace zmq\n{\nclass tcp_connecter_t ZMQ_FINAL : public stream_connecter_base_t\n{\n  public:\n    //  If 'delayed_start' is true connecter first waits for a while,\n    //  then starts connection process.\n    tcp_connecter_t (zmq::io_thread_t *io_thread_,\n                     zmq::session_base_t *session_,\n                     const options_t &options_,\n                     address_t *addr_,\n                     bool delayed_start_);\n    ~tcp_connecter_t ();\n\n  private:\n    //  ID of the timer used to check the connect timeout, must be different from stream_connecter_base_t::reconnect_timer_id.\n    enum\n    {\n        connect_timer_id = 2\n    };\n\n    //  Handlers for incoming commands.\n    void process_term (int linger_);\n\n    //  Handlers for I/O events.\n    void out_event ();\n    void timer_event (int id_);\n\n    //  Internal function to start the actual connection establishment.\n    void start_connecting ();\n\n    //  Internal function to add a connect timer\n    void add_connect_timer ();\n\n    //  Open TCP connecting socket. Returns -1 in case of error,\n    //  0 if connect was successful immediately. Returns -1 with\n    //  EAGAIN errno if async connect was launched.\n    int open ();\n\n    //  Get the file descriptor of newly created connection. Returns\n    //  retired_fd if the connection was unsuccessful.\n    fd_t connect ();\n\n    //  Tunes a connected socket.\n    bool tune_socket (fd_t fd_);\n\n    //  True iff a timer has been started.\n    bool _connect_timer_started;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (tcp_connecter_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/tcp_listener.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <new>\n\n#include <string>\n#include <stdio.h>\n\n#include \"tcp_listener.hpp\"\n#include \"io_thread.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"tcp.hpp\"\n#include \"socket_base.hpp\"\n#include \"address.hpp\"\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#include <sys/socket.h>\n#include <arpa/inet.h>\n#include <netinet/tcp.h>\n#include <netinet/in.h>\n#include <netdb.h>\n#include <fcntl.h>\n#ifdef ZMQ_HAVE_VXWORKS\n#include <sockLib.h>\n#endif\n#endif\n\n#ifdef ZMQ_HAVE_OPENVMS\n#include <ioctl.h>\n#endif\n\nzmq::tcp_listener_t::tcp_listener_t (io_thread_t *io_thread_,\n                                     socket_base_t *socket_,\n                                     const options_t &options_) :\n    stream_listener_base_t (io_thread_, socket_, options_)\n{\n}\n\nvoid zmq::tcp_listener_t::in_event ()\n{\n    const fd_t fd = accept ();\n\n    //  If connection was reset by the peer in the meantime, just ignore it.\n    //  TODO: Handle specific errors like ENFILE/EMFILE etc.\n    if (fd == retired_fd) {\n        _socket->event_accept_failed (\n          make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());\n        return;\n    }\n\n    int rc = tune_tcp_socket (fd);\n    rc = rc\n         | tune_tcp_keepalives (\n           fd, options.tcp_keepalive, options.tcp_keepalive_cnt,\n           options.tcp_keepalive_idle, options.tcp_keepalive_intvl);\n    rc = rc | tune_tcp_maxrt (fd, options.tcp_maxrt);\n    if (rc != 0) {\n        _socket->event_accept_failed (\n          make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());\n        return;\n    }\n\n    //  Create the engine object for this connection.\n    create_engine (fd);\n}\n\nstd::string\nzmq::tcp_listener_t::get_socket_name (zmq::fd_t fd_,\n                                      socket_end_t socket_end_) const\n{\n    return zmq::get_socket_name<tcp_address_t> (fd_, socket_end_);\n}\n\nint zmq::tcp_listener_t::create_socket (const char *addr_)\n{\n    _s = tcp_open_socket (addr_, options, true, true, &_address);\n    if (_s == retired_fd) {\n        return -1;\n    }\n\n    //  TODO why is this only done for the listener?\n    make_socket_noninheritable (_s);\n\n    //  Allow reusing of the address.\n    int flag = 1;\n    int rc;\n#ifdef ZMQ_HAVE_WINDOWS\n    //  TODO this was changed for Windows from SO_REUSEADDRE to\n    //  SE_EXCLUSIVEADDRUSE by 0ab65324195ad70205514d465b03d851a6de051c,\n    //  so the comment above is no longer correct; also, now the settings are\n    //  different between listener and connecter with a src address.\n    //  is this intentional?\n    rc = setsockopt (_s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,\n                     reinterpret_cast<const char *> (&flag), sizeof (int));\n    wsa_assert (rc != SOCKET_ERROR);\n#elif defined ZMQ_HAVE_VXWORKS\n    rc =\n      setsockopt (_s, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof (int));\n    errno_assert (rc == 0);\n#else\n    rc = setsockopt (_s, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int));\n    errno_assert (rc == 0);\n#endif\n\n    //  Bind the socket to the network interface and port.\n#if defined ZMQ_HAVE_VXWORKS\n    rc = bind (_s, (sockaddr *) _address.addr (), _address.addrlen ());\n#else\n    rc = bind (_s, _address.addr (), _address.addrlen ());\n#endif\n#ifdef ZMQ_HAVE_WINDOWS\n    if (rc == SOCKET_ERROR) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        goto error;\n    }\n#else\n    if (rc != 0)\n        goto error;\n#endif\n\n    //  Listen for incoming connections.\n    rc = listen (_s, options.backlog);\n#ifdef ZMQ_HAVE_WINDOWS\n    if (rc == SOCKET_ERROR) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        goto error;\n    }\n#else\n    if (rc != 0)\n        goto error;\n#endif\n\n    return 0;\n\nerror:\n    const int err = errno;\n    close ();\n    errno = err;\n    return -1;\n}\n\nint zmq::tcp_listener_t::set_local_address (const char *addr_)\n{\n    if (options.use_fd != -1) {\n        //  in this case, the addr_ passed is not used and ignored, since the\n        //  socket was already created by the application\n        _s = options.use_fd;\n    } else {\n        if (create_socket (addr_) == -1)\n            return -1;\n    }\n\n    _endpoint = get_socket_name (_s, socket_end_local);\n\n    _socket->event_listening (make_unconnected_bind_endpoint_pair (_endpoint),\n                              _s);\n    return 0;\n}\n\nzmq::fd_t zmq::tcp_listener_t::accept ()\n{\n    //  The situation where connection cannot be accepted due to insufficient\n    //  resources is considered valid and treated by ignoring the connection.\n    //  Accept one connection and deal with different failure modes.\n    zmq_assert (_s != retired_fd);\n\n    struct sockaddr_storage ss;\n    memset (&ss, 0, sizeof (ss));\n#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS\n    int ss_len = sizeof (ss);\n#else\n    socklen_t ss_len = sizeof (ss);\n#endif\n#if defined ZMQ_HAVE_SOCK_CLOEXEC && defined HAVE_ACCEPT4\n    fd_t sock = ::accept4 (_s, reinterpret_cast<struct sockaddr *> (&ss),\n                           &ss_len, SOCK_CLOEXEC);\n#else\n    const fd_t sock =\n      ::accept (_s, reinterpret_cast<struct sockaddr *> (&ss), &ss_len);\n#endif\n\n    if (sock == retired_fd) {\n#if defined ZMQ_HAVE_WINDOWS\n        const int last_error = WSAGetLastError ();\n        wsa_assert (last_error == WSAEWOULDBLOCK || last_error == WSAECONNRESET\n                    || last_error == WSAEMFILE || last_error == WSAENOBUFS);\n#elif defined ZMQ_HAVE_ANDROID\n        errno_assert (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR\n                      || errno == ECONNABORTED || errno == EPROTO\n                      || errno == ENOBUFS || errno == ENOMEM || errno == EMFILE\n                      || errno == ENFILE || errno == EINVAL);\n#else\n        errno_assert (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR\n                      || errno == ECONNABORTED || errno == EPROTO\n                      || errno == ENOBUFS || errno == ENOMEM || errno == EMFILE\n                      || errno == ENFILE);\n#endif\n        return retired_fd;\n    }\n\n    make_socket_noninheritable (sock);\n\n    if (!options.tcp_accept_filters.empty ()) {\n        bool matched = false;\n        for (options_t::tcp_accept_filters_t::size_type\n               i = 0,\n               size = options.tcp_accept_filters.size ();\n             i != size; ++i) {\n            if (options.tcp_accept_filters[i].match_address (\n                  reinterpret_cast<struct sockaddr *> (&ss), ss_len)) {\n                matched = true;\n                break;\n            }\n        }\n        if (!matched) {\n#ifdef ZMQ_HAVE_WINDOWS\n            const int rc = closesocket (sock);\n            wsa_assert (rc != SOCKET_ERROR);\n#else\n            int rc = ::close (sock);\n            errno_assert (rc == 0);\n#endif\n            return retired_fd;\n        }\n    }\n\n    if (zmq::set_nosigpipe (sock)) {\n#ifdef ZMQ_HAVE_WINDOWS\n        const int rc = closesocket (sock);\n        wsa_assert (rc != SOCKET_ERROR);\n#else\n        int rc = ::close (sock);\n        errno_assert (rc == 0);\n#endif\n        return retired_fd;\n    }\n\n    // Set the IP Type-Of-Service priority for this client socket\n    if (options.tos != 0)\n        set_ip_type_of_service (sock, options.tos);\n\n    // Set the protocol-defined priority for this client socket\n    if (options.priority != 0)\n        set_socket_priority (sock, options.priority);\n\n    return sock;\n}\n"
  },
  {
    "path": "src/tcp_listener.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_TCP_LISTENER_HPP_INCLUDED__\n#define __ZMQ_TCP_LISTENER_HPP_INCLUDED__\n\n#include \"fd.hpp\"\n#include \"tcp_address.hpp\"\n#include \"stream_listener_base.hpp\"\n\nnamespace zmq\n{\nclass tcp_listener_t ZMQ_FINAL : public stream_listener_base_t\n{\n  public:\n    tcp_listener_t (zmq::io_thread_t *io_thread_,\n                    zmq::socket_base_t *socket_,\n                    const options_t &options_);\n\n    //  Set address to listen on.\n    int set_local_address (const char *addr_);\n\n  protected:\n    std::string get_socket_name (fd_t fd_, socket_end_t socket_end_) const;\n\n  private:\n    //  Handlers for I/O events.\n    void in_event ();\n\n    //  Accept the new connection. Returns the file descriptor of the\n    //  newly created connection. The function may return retired_fd\n    //  if the connection was dropped while waiting in the listen backlog\n    //  or was denied because of accept filters.\n    fd_t accept ();\n\n    int create_socket (const char *addr_);\n\n    //  Address to listen on.\n    tcp_address_t _address;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (tcp_listener_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/thread.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"thread.hpp\"\n#include \"err.hpp\"\n\n#ifdef ZMQ_HAVE_WINDOWS\n#include <winnt.h>\n#endif\n\n#ifdef __MINGW32__\n#include \"pthread.h\"\n#endif\n\nbool zmq::thread_t::get_started () const\n{\n    return _started;\n}\n\n#ifdef ZMQ_HAVE_WINDOWS\n\nextern \"C\" {\n#if defined _WIN32_WCE\nstatic DWORD thread_routine (LPVOID arg_)\n#else\nstatic unsigned int __stdcall thread_routine (void *arg_)\n#endif\n{\n    zmq::thread_t *self = static_cast<zmq::thread_t *> (arg_);\n    self->applyThreadName ();\n    self->_tfn (self->_arg);\n    return 0;\n}\n}\n\nvoid zmq::thread_t::start (thread_fn *tfn_, void *arg_, const char *name_)\n{\n    _tfn = tfn_;\n    _arg = arg_;\n    if (name_)\n        strncpy (_name, name_, sizeof (_name) - 1);\n\n    // set default stack size to 4MB to avoid std::map stack overflow on x64\n    unsigned int stack = 0;\n#if defined _WIN64\n    stack = 0x400000;\n#endif\n\n#if defined _WIN32_WCE\n    _descriptor = (HANDLE) CreateThread (NULL, stack, &::thread_routine, this,\n                                         0, &_thread_id);\n#else\n    _descriptor = (HANDLE) _beginthreadex (NULL, stack, &::thread_routine, this,\n                                           0, &_thread_id);\n#endif\n    win_assert (_descriptor != NULL);\n    _started = true;\n}\n\nbool zmq::thread_t::is_current_thread () const\n{\n    return GetCurrentThreadId () == _thread_id;\n}\n\nvoid zmq::thread_t::stop ()\n{\n    if (_started) {\n        const DWORD rc = WaitForSingleObject (_descriptor, INFINITE);\n        win_assert (rc != WAIT_FAILED);\n        const BOOL rc2 = CloseHandle (_descriptor);\n        win_assert (rc2 != 0);\n    }\n}\n\nvoid zmq::thread_t::setSchedulingParameters (\n  int priority_, int scheduling_policy_, const std::set<int> &affinity_cpus_)\n{\n    // not implemented\n    LIBZMQ_UNUSED (priority_);\n    LIBZMQ_UNUSED (scheduling_policy_);\n    LIBZMQ_UNUSED (affinity_cpus_);\n}\n\nvoid zmq::thread_t::\n  applySchedulingParameters () // to be called in secondary thread context\n{\n    // not implemented\n}\n\n#ifdef _MSC_VER\n\nnamespace\n{\n#pragma pack(push, 8)\nstruct thread_info_t\n{\n    DWORD _type;\n    LPCSTR _name;\n    DWORD _thread_id;\n    DWORD _flags;\n};\n#pragma pack(pop)\n}\n\n#endif\n\nvoid zmq::thread_t::\n  applyThreadName () // to be called in secondary thread context\n{\n    if (!_name[0] || !IsDebuggerPresent ())\n        return;\n\n#ifdef _MSC_VER\n\n    thread_info_t thread_info;\n    thread_info._type = 0x1000;\n    thread_info._name = _name;\n    thread_info._thread_id = -1;\n    thread_info._flags = 0;\n\n    __try {\n        const DWORD MS_VC_EXCEPTION = 0x406D1388;\n        RaiseException (MS_VC_EXCEPTION, 0,\n                        sizeof (thread_info) / sizeof (ULONG_PTR),\n                        (ULONG_PTR *) &thread_info);\n    }\n    __except (EXCEPTION_CONTINUE_EXECUTION) {\n    }\n\n#elif defined(__MINGW32__)\n\n    int rc = pthread_setname_np (pthread_self (), _name);\n    if (rc)\n        return;\n\n#else\n\n        // not implemented\n\n#endif\n}\n\n\n#elif defined ZMQ_HAVE_VXWORKS\n\nextern \"C\" {\nstatic void *thread_routine (void *arg_)\n{\n    zmq::thread_t *self = (zmq::thread_t *) arg_;\n    self->applySchedulingParameters ();\n    self->_tfn (self->_arg);\n    return NULL;\n}\n}\n\nvoid zmq::thread_t::start (thread_fn *tfn_, void *arg_, const char *name_)\n{\n    LIBZMQ_UNUSED (name_);\n    _tfn = tfn_;\n    _arg = arg_;\n    _descriptor = taskSpawn (NULL, DEFAULT_PRIORITY, DEFAULT_OPTIONS,\n                             DEFAULT_STACK_SIZE, (FUNCPTR) thread_routine,\n                             (int) this, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n    if (_descriptor != NULL || _descriptor > 0)\n        _started = true;\n}\n\nvoid zmq::thread_t::stop ()\n{\n    if (_started)\n        while ((_descriptor != NULL || _descriptor > 0)\n               && taskIdVerify (_descriptor) == 0) {\n        }\n}\n\nbool zmq::thread_t::is_current_thread () const\n{\n    return taskIdSelf () == _descriptor;\n}\n\nvoid zmq::thread_t::setSchedulingParameters (\n  int priority_, int schedulingPolicy_, const std::set<int> &affinity_cpus_)\n{\n    _thread_priority = priority_;\n    _thread_sched_policy = schedulingPolicy_;\n    _thread_affinity_cpus = affinity_cpus_;\n}\n\nvoid zmq::thread_t::\n  applySchedulingParameters () // to be called in secondary thread context\n{\n    int priority =\n      (_thread_priority >= 0 ? _thread_priority : DEFAULT_PRIORITY);\n    priority = (priority < UCHAR_MAX ? priority : DEFAULT_PRIORITY);\n    if (_descriptor != NULL || _descriptor > 0) {\n        taskPrioritySet (_descriptor, priority);\n    }\n}\n\nvoid zmq::thread_t::\n  applyThreadName () // to be called in secondary thread context\n{\n    // not implemented\n}\n\n#else\n\n#include <signal.h>\n#include <unistd.h>\n#include <sys/time.h>\n#include <sys/resource.h>\n\nextern \"C\" {\nstatic void *thread_routine (void *arg_)\n{\n#if !defined ZMQ_HAVE_OPENVMS && !defined ZMQ_HAVE_ANDROID\n    //  Following code will guarantee more predictable latencies as it'll\n    //  disallow any signal handling in the I/O thread.\n    sigset_t signal_set;\n    int rc = sigfillset (&signal_set);\n    errno_assert (rc == 0);\n    rc = pthread_sigmask (SIG_BLOCK, &signal_set, NULL);\n    posix_assert (rc);\n#endif\n    zmq::thread_t *self = (zmq::thread_t *) arg_;\n    self->applySchedulingParameters ();\n    self->applyThreadName ();\n    self->_tfn (self->_arg);\n    return NULL;\n}\n}\n\nvoid zmq::thread_t::start (thread_fn *tfn_, void *arg_, const char *name_)\n{\n    _tfn = tfn_;\n    _arg = arg_;\n    if (name_)\n        strncpy (_name, name_, sizeof (_name) - 1);\n    int rc = pthread_create (&_descriptor, NULL, thread_routine, this);\n    posix_assert (rc);\n    _started = true;\n}\n\nvoid zmq::thread_t::stop ()\n{\n    if (_started) {\n        int rc = pthread_join (_descriptor, NULL);\n        posix_assert (rc);\n    }\n}\n\nbool zmq::thread_t::is_current_thread () const\n{\n    return bool (pthread_equal (pthread_self (), _descriptor));\n}\n\nvoid zmq::thread_t::setSchedulingParameters (\n  int priority_, int scheduling_policy_, const std::set<int> &affinity_cpus_)\n{\n    _thread_priority = priority_;\n    _thread_sched_policy = scheduling_policy_;\n    _thread_affinity_cpus = affinity_cpus_;\n}\n\nvoid zmq::thread_t::\n  applySchedulingParameters () // to be called in secondary thread context\n{\n#if defined _POSIX_THREAD_PRIORITY_SCHEDULING                                  \\\n  && _POSIX_THREAD_PRIORITY_SCHEDULING >= 0\n    int policy = 0;\n    struct sched_param param;\n\n#if _POSIX_THREAD_PRIORITY_SCHEDULING == 0                                     \\\n  && defined _SC_THREAD_PRIORITY_SCHEDULING\n    if (sysconf (_SC_THREAD_PRIORITY_SCHEDULING) < 0) {\n        return;\n    }\n#endif\n    int rc = pthread_getschedparam (pthread_self (), &policy, &param);\n    posix_assert (rc);\n\n    if (_thread_sched_policy != ZMQ_THREAD_SCHED_POLICY_DFLT) {\n        policy = _thread_sched_policy;\n    }\n\n    /* Quoting docs:\n       \"Linux allows the static priority range 1 to 99 for the SCHED_FIFO and\n       SCHED_RR policies, and the priority 0 for the remaining policies.\"\n       Other policies may use the \"nice value\" in place of the priority:\n    */\n    bool use_nice_instead_priority =\n      (policy != SCHED_FIFO) && (policy != SCHED_RR);\n\n    if (use_nice_instead_priority)\n        param.sched_priority =\n          0; // this is the only supported priority for most scheduling policies\n    else if (_thread_priority != ZMQ_THREAD_PRIORITY_DFLT)\n        param.sched_priority =\n          _thread_priority; // user should provide a value between 1 and 99\n\n#ifdef __NetBSD__\n    if (policy == SCHED_OTHER)\n        param.sched_priority = -1;\n#endif\n\n    rc = pthread_setschedparam (pthread_self (), policy, &param);\n\n#if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)\n    // If this feature is unavailable at run-time, don't abort.\n    if (rc == ENOSYS)\n        return;\n#endif\n\n    posix_assert (rc);\n\n#if !defined ZMQ_HAVE_VXWORKS\n    if (use_nice_instead_priority\n        && _thread_priority != ZMQ_THREAD_PRIORITY_DFLT\n        && _thread_priority > 0) {\n        // assume the user wants to decrease the thread's nice value\n        // i.e., increase the chance of this thread being scheduled: try setting that to\n        // maximum priority.\n        rc = nice (-20);\n\n        errno_assert (rc != -1);\n        // IMPORTANT: EPERM is typically returned for unprivileged processes: that's because\n        //            CAP_SYS_NICE capability is required or RLIMIT_NICE resource limit should be changed to avoid EPERM!\n    }\n#endif\n\n#ifdef ZMQ_HAVE_PTHREAD_SET_AFFINITY\n    if (!_thread_affinity_cpus.empty ()) {\n        cpu_set_t cpuset;\n        CPU_ZERO (&cpuset);\n        for (std::set<int>::const_iterator it = _thread_affinity_cpus.begin (),\n                                           end = _thread_affinity_cpus.end ();\n             it != end; it++) {\n            CPU_SET ((int) (*it), &cpuset);\n        }\n        rc =\n          pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);\n        posix_assert (rc);\n    }\n#endif\n#endif\n}\n\nvoid zmq::thread_t::\n  applyThreadName () // to be called in secondary thread context\n{\n    /* The thread name is a cosmetic string, added to ease debugging of\n * multi-threaded applications. It is not a big issue if this value\n * can not be set for any reason (such as Permission denied in some\n * cases where the application changes its EUID, etc.) The value of\n * \"int rc\" is retained where available, to help debuggers stepping\n * through code to see its value - but otherwise it is ignored.\n */\n    if (!_name[0])\n        return;\n\n        /* Fails with permission denied on Android 5/6 */\n#if defined(ZMQ_HAVE_ANDROID)\n    return;\n#endif\n\n#if defined(ZMQ_HAVE_PTHREAD_SETNAME_1)\n    int rc = pthread_setname_np (_name);\n    if (rc)\n        return;\n#elif defined(ZMQ_HAVE_PTHREAD_SETNAME_2)\n    int rc = pthread_setname_np (pthread_self (), _name);\n    if (rc)\n        return;\n#elif defined(ZMQ_HAVE_PTHREAD_SETNAME_3)\n    int rc = pthread_setname_np (pthread_self (), _name, NULL);\n    if (rc)\n        return;\n#elif defined(ZMQ_HAVE_PTHREAD_SET_NAME)\n    pthread_set_name_np (pthread_self (), _name);\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "src/thread.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_THREAD_HPP_INCLUDED__\n#define __ZMQ_THREAD_HPP_INCLUDED__\n\n#if defined ZMQ_HAVE_VXWORKS\n#include <vxWorks.h>\n#include <taskLib.h>\n#elif !defined ZMQ_HAVE_WINDOWS\n#include <pthread.h>\n#endif\n#include <set>\n#include <cstring>\n\nnamespace zmq\n{\ntypedef void (thread_fn) (void *);\n\n//  Class encapsulating OS thread. Thread initiation/termination is done\n//  using special functions rather than in constructor/destructor so that\n//  thread isn't created during object construction by accident, causing\n//  newly created thread to access half-initialised object. Same applies\n//  to the destruction process: Thread should be terminated before object\n//  destruction begins, otherwise it can access half-destructed object.\n\nclass thread_t\n{\n  public:\n    thread_t () :\n        _tfn (NULL),\n        _arg (NULL),\n        _started (false),\n        _thread_priority (ZMQ_THREAD_PRIORITY_DFLT),\n        _thread_sched_policy (ZMQ_THREAD_SCHED_POLICY_DFLT)\n    {\n        memset (_name, 0, sizeof (_name));\n    }\n\n#ifdef ZMQ_HAVE_VXWORKS\n    ~thread_t ()\n    {\n        if (descriptor != NULL || descriptor > 0) {\n            taskDelete (descriptor);\n        }\n    }\n#endif\n\n    //  Creates OS thread. 'tfn' is main thread function. It'll be passed\n    //  'arg' as an argument.\n    //  Name is 16 characters max including terminating NUL. Thread naming is\n    //  implemented only for pthread, and windows when a debugger is attached.\n    void start (thread_fn *tfn_, void *arg_, const char *name_);\n\n    //  Returns whether the thread was started, i.e. start was called.\n    bool get_started () const;\n\n    //  Returns whether the executing thread is the thread represented by the\n    //  thread object.\n    bool is_current_thread () const;\n\n    //  Waits for thread termination.\n    void stop ();\n\n    // Sets the thread scheduling parameters. Only implemented for\n    // pthread. Has no effect on other platforms.\n    void setSchedulingParameters (int priority_,\n                                  int scheduling_policy_,\n                                  const std::set<int> &affinity_cpus_);\n\n    //  These are internal members. They should be private, however then\n    //  they would not be accessible from the main C routine of the thread.\n    void applySchedulingParameters ();\n    void applyThreadName ();\n    thread_fn *_tfn;\n    void *_arg;\n    char _name[16];\n\n  private:\n    bool _started;\n\n#ifdef ZMQ_HAVE_WINDOWS\n    HANDLE _descriptor;\n#if defined _WIN32_WCE\n    DWORD _thread_id;\n#else\n    unsigned int _thread_id;\n#endif\n#elif defined ZMQ_HAVE_VXWORKS\n    int _descriptor;\n    enum\n    {\n        DEFAULT_PRIORITY = 100,\n        DEFAULT_OPTIONS = 0,\n        DEFAULT_STACK_SIZE = 4000\n    };\n#else\n    pthread_t _descriptor;\n#endif\n\n    //  Thread scheduling parameters.\n    int _thread_priority;\n    int _thread_sched_policy;\n    std::set<int> _thread_affinity_cpus;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (thread_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/timers.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"timers.hpp\"\n#include \"err.hpp\"\n\n#include <algorithm>\n\nzmq::timers_t::timers_t () : _tag (0xCAFEDADA), _next_timer_id (0)\n{\n}\n\nzmq::timers_t::~timers_t ()\n{\n    //  Mark the timers as dead\n    _tag = 0xdeadbeef;\n}\n\nbool zmq::timers_t::check_tag () const\n{\n    return _tag == 0xCAFEDADA;\n}\n\nint zmq::timers_t::add (size_t interval_, timers_timer_fn handler_, void *arg_)\n{\n    if (handler_ == NULL) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    uint64_t when = _clock.now_ms () + interval_;\n    timer_t timer = {++_next_timer_id, interval_, handler_, arg_};\n    _timers.insert (timersmap_t::value_type (when, timer));\n\n    return timer.timer_id;\n}\n\nstruct zmq::timers_t::match_by_id\n{\n    match_by_id (int timer_id_) : _timer_id (timer_id_) {}\n\n    bool operator() (timersmap_t::value_type const &entry_) const\n    {\n        return entry_.second.timer_id == _timer_id;\n    }\n\n  private:\n    int _timer_id;\n};\n\nint zmq::timers_t::cancel (int timer_id_)\n{\n    // check first if timer exists at all\n    if (_timers.end ()\n        == std::find_if (_timers.begin (), _timers.end (),\n                         match_by_id (timer_id_))) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    // check if timer was already canceled\n    if (_cancelled_timers.count (timer_id_)) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    _cancelled_timers.insert (timer_id_);\n\n    return 0;\n}\n\nint zmq::timers_t::set_interval (int timer_id_, size_t interval_)\n{\n    const timersmap_t::iterator end = _timers.end ();\n    const timersmap_t::iterator it =\n      std::find_if (_timers.begin (), end, match_by_id (timer_id_));\n    if (it != end) {\n        timer_t timer = it->second;\n        timer.interval = interval_;\n        uint64_t when = _clock.now_ms () + interval_;\n        _timers.erase (it);\n        _timers.insert (timersmap_t::value_type (when, timer));\n\n        return 0;\n    }\n\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::timers_t::reset (int timer_id_)\n{\n    const timersmap_t::iterator end = _timers.end ();\n    const timersmap_t::iterator it =\n      std::find_if (_timers.begin (), end, match_by_id (timer_id_));\n    if (it != end) {\n        timer_t timer = it->second;\n        uint64_t when = _clock.now_ms () + timer.interval;\n        _timers.erase (it);\n        _timers.insert (timersmap_t::value_type (when, timer));\n\n        return 0;\n    }\n\n    errno = EINVAL;\n    return -1;\n}\n\nlong zmq::timers_t::timeout ()\n{\n    const uint64_t now = _clock.now_ms ();\n    long res = -1;\n\n    const timersmap_t::iterator begin = _timers.begin ();\n    const timersmap_t::iterator end = _timers.end ();\n    timersmap_t::iterator it = begin;\n    for (; it != end; ++it) {\n        if (0 == _cancelled_timers.erase (it->second.timer_id)) {\n            //  Live timer, lets return the timeout\n            res = std::max (static_cast<long> (it->first - now), 0l);\n            break;\n        }\n    }\n\n    //  Remove timed-out timers\n    _timers.erase (begin, it);\n\n    return res;\n}\n\nint zmq::timers_t::execute ()\n{\n    const uint64_t now = _clock.now_ms ();\n\n    const timersmap_t::iterator begin = _timers.begin ();\n    const timersmap_t::iterator end = _timers.end ();\n    timersmap_t::iterator it = _timers.begin ();\n    for (; it != end; ++it) {\n        if (0 == _cancelled_timers.erase (it->second.timer_id)) {\n            //  Timer is not cancelled\n\n            //  Map is ordered, if we have to wait for current timer we can stop.\n            if (it->first > now)\n                break;\n\n            const timer_t &timer = it->second;\n\n            timer.handler (timer.timer_id, timer.arg);\n\n            _timers.insert (\n              timersmap_t::value_type (now + timer.interval, timer));\n        }\n    }\n    _timers.erase (begin, it);\n\n    return 0;\n}\n"
  },
  {
    "path": "src/timers.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_TIMERS_HPP_INCLUDED__\n#define __ZMQ_TIMERS_HPP_INCLUDED__\n\n#include <stddef.h>\n#include <map>\n#include <set>\n\n#include \"clock.hpp\"\n\nnamespace zmq\n{\ntypedef void (timers_timer_fn) (int timer_id_, void *arg_);\n\nclass timers_t\n{\n  public:\n    timers_t ();\n    ~timers_t ();\n\n    //  Add timer to the set, timer repeats forever, or until cancel is called.\n    //  Returns a timer_id that is used to cancel the timer.\n    //  Returns -1 if there was an error.\n    int add (size_t interval_, timers_timer_fn handler_, void *arg_);\n\n    //  Set the interval of the timer.\n    //  This method is slow, cancelling exsting and adding a new timer yield better performance.\n    //  Returns 0 on success and -1 on error.\n    int set_interval (int timer_id_, size_t interval_);\n\n    //  Reset the timer.\n    //  This method is slow, cancelling exsting and adding a new timer yield better performance.\n    //  Returns 0 on success and -1 on error.\n    int reset (int timer_id_);\n\n    //  Cancel a timer.\n    //  Returns 0 on success and -1 on error.\n    int cancel (int timer_id_);\n\n    //  Returns the time in millisecond until the next timer.\n    //  Returns -1 if no timer is due.\n    long timeout ();\n\n    //  Execute timers.\n    //  Return 0 if all succeed and -1 if error.\n    int execute ();\n\n    //  Return false if object is not a timers class.\n    bool check_tag () const;\n\n  private:\n    //  Used to check whether the object is a timers class.\n    uint32_t _tag;\n\n    int _next_timer_id;\n\n    //  Clock instance.\n    clock_t _clock;\n\n    typedef struct timer_t\n    {\n        int timer_id;\n        size_t interval;\n        timers_timer_fn *handler;\n        void *arg;\n    } timer_t;\n\n    typedef std::multimap<uint64_t, timer_t> timersmap_t;\n    timersmap_t _timers;\n\n    typedef std::set<int> cancelled_timers_t;\n    cancelled_timers_t _cancelled_timers;\n\n    struct match_by_id;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (timers_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/tipc_address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"tipc_address.hpp\"\n\n#if defined ZMQ_HAVE_TIPC\n\n#include \"err.hpp\"\n\n#include <string>\n#include <sstream>\n\nzmq::tipc_address_t::tipc_address_t ()\n{\n    memset (&address, 0, sizeof address);\n    _random = false;\n}\n\nzmq::tipc_address_t::tipc_address_t (const sockaddr *sa_, socklen_t sa_len_)\n{\n    zmq_assert (sa_ && sa_len_ > 0);\n\n    memset (&address, 0, sizeof address);\n    if (sa_->sa_family == AF_TIPC)\n        memcpy (&address, sa_, sa_len_);\n\n    _random = false;\n}\n\nvoid zmq::tipc_address_t::set_random ()\n{\n    _random = true;\n}\nbool zmq::tipc_address_t::is_random () const\n{\n    return _random;\n}\nbool zmq::tipc_address_t::is_service () const\n{\n    if (address.addrtype == TIPC_ADDR_ID)\n        return false;\n\n    return true;\n}\nint zmq::tipc_address_t::resolve (const char *name_)\n{\n    unsigned int type = 0;\n    unsigned int lower = 0;\n    unsigned int upper = 0;\n    unsigned int ref = 0;\n    unsigned int z = 1, c = 0, n = 0;\n    char eof;\n    const char *domain;\n    int res;\n\n\n    if (strncmp (name_, \"<*>\", 3) == 0) {\n        set_random ();\n        address.family = AF_TIPC;\n        address.addrtype = TIPC_ADDR_ID;\n        address.addr.id.node = 0;\n        address.addr.id.ref = 0;\n        address.scope = 0;\n        return 0;\n    }\n\n    res = sscanf (name_, \"{%u,%u,%u}\", &type, &lower, &upper);\n    /* Fetch optional domain suffix. */\n    if ((domain = strchr (name_, '@'))) {\n        if (sscanf (domain, \"@%u.%u.%u%c\", &z, &c, &n, &eof) != 3)\n            return EINVAL;\n    }\n    if (res == 3) {\n        if (type < TIPC_RESERVED_TYPES || upper < lower)\n            return EINVAL;\n        address.family = AF_TIPC;\n        address.addrtype = TIPC_ADDR_NAMESEQ;\n        address.addr.nameseq.type = type;\n        address.addr.nameseq.lower = lower;\n        address.addr.nameseq.upper = upper;\n        address.scope = TIPC_ZONE_SCOPE;\n        return 0;\n    }\n    if (res == 2 && type > TIPC_RESERVED_TYPES) {\n        address.family = AF_TIPC;\n        address.addrtype = TIPC_ADDR_NAME;\n        address.addr.name.name.type = type;\n        address.addr.name.name.instance = lower;\n        address.addr.name.domain = tipc_addr (z, c, n);\n        address.scope = 0;\n        return 0;\n    } else if (res == 0) {\n        res = sscanf (name_, \"<%u.%u.%u:%u>\", &z, &c, &n, &ref);\n        if (res == 4) {\n            address.family = AF_TIPC;\n            address.addrtype = TIPC_ADDR_ID;\n            address.addr.id.node = tipc_addr (z, c, n);\n            address.addr.id.ref = ref;\n            address.scope = 0;\n            return 0;\n        }\n    }\n    return EINVAL;\n}\n\nint zmq::tipc_address_t::to_string (std::string &addr_) const\n{\n    if (address.family != AF_TIPC) {\n        addr_.clear ();\n        return -1;\n    }\n    std::stringstream s;\n    if (address.addrtype == TIPC_ADDR_NAMESEQ\n        || address.addrtype == TIPC_ADDR_NAME) {\n        s << \"tipc://\" << \"{\" << address.addr.nameseq.type;\n        s << \", \" << address.addr.nameseq.lower;\n        s << \", \" << address.addr.nameseq.upper << \"}\";\n        addr_ = s.str ();\n    } else if (address.addrtype == TIPC_ADDR_ID || is_random ()) {\n        s << \"tipc://\" << \"<\" << tipc_zone (address.addr.id.node);\n        s << \".\" << tipc_cluster (address.addr.id.node);\n        s << \".\" << tipc_node (address.addr.id.node);\n        s << \":\" << address.addr.id.ref << \">\";\n        addr_ = s.str ();\n    } else {\n        addr_.clear ();\n        return -1;\n    }\n    return 0;\n}\n\nconst sockaddr *zmq::tipc_address_t::addr () const\n{\n    return (sockaddr *) &address;\n}\n\nsocklen_t zmq::tipc_address_t::addrlen () const\n{\n    return static_cast<socklen_t> (sizeof address);\n}\n\n#endif\n"
  },
  {
    "path": "src/tipc_address.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_TIPC_ADDRESS_HPP_INCLUDED__\n#define __ZMQ_TIPC_ADDRESS_HPP_INCLUDED__\n\n#include <string>\n\n#include \"platform.hpp\"\n\n#if defined ZMQ_HAVE_TIPC\n\n#include <sys/socket.h>\n#if defined ZMQ_HAVE_VXWORKS\n#include <tipc/tipc.h>\n#else\n#include <linux/tipc.h>\n#endif\n\nnamespace zmq\n{\nclass tipc_address_t\n{\n  public:\n    tipc_address_t ();\n    tipc_address_t (const sockaddr *sa, socklen_t sa_len);\n\n    //  This function sets up the address \"{type, lower, upper}\" for TIPC transport\n    int resolve (const char *name);\n\n    //  The opposite to resolve()\n    int to_string (std::string &addr_) const;\n\n    // Handling different TIPC address types\n    bool is_service () const;\n    bool is_random () const;\n    void set_random ();\n\n    const sockaddr *addr () const;\n    socklen_t addrlen () const;\n\n  private:\n    bool _random;\n    struct sockaddr_tipc address;\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/tipc_connecter.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"tipc_connecter.hpp\"\n\n#if defined ZMQ_HAVE_TIPC\n\n#include <new>\n#include <string>\n\n#include \"io_thread.hpp\"\n#include \"platform.hpp\"\n#include \"random.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"address.hpp\"\n#include \"tipc_address.hpp\"\n#include \"session_base.hpp\"\n\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#ifdef ZMQ_HAVE_VXWORKS\n#include <sockLib.h>\n#endif\n\nzmq::tipc_connecter_t::tipc_connecter_t (class io_thread_t *io_thread_,\n                                         class session_base_t *session_,\n                                         const options_t &options_,\n                                         address_t *addr_,\n                                         bool delayed_start_) :\n    stream_connecter_base_t (\n      io_thread_, session_, options_, addr_, delayed_start_)\n{\n    zmq_assert (_addr->protocol == \"tipc\");\n}\n\nvoid zmq::tipc_connecter_t::out_event ()\n{\n    fd_t fd = connect ();\n    rm_handle ();\n\n    //  Handle the error condition by attempt to reconnect.\n    if (fd == retired_fd) {\n        close ();\n        add_reconnect_timer ();\n        return;\n    }\n\n    create_engine (fd, get_socket_name<tipc_address_t> (fd, socket_end_local));\n}\n\nvoid zmq::tipc_connecter_t::start_connecting ()\n{\n    //  Open the connecting socket.\n    int rc = open ();\n\n    //  Connect may succeed in synchronous manner.\n    if (rc == 0) {\n        _handle = add_fd (_s);\n        out_event ();\n    }\n\n    //  Connection establishment may be delayed. Poll for its completion.\n    else if (rc == -1 && errno == EINPROGRESS) {\n        _handle = add_fd (_s);\n        set_pollout (_handle);\n        _socket->event_connect_delayed (\n          make_unconnected_connect_endpoint_pair (_endpoint), zmq_errno ());\n    }\n\n    //  Handle any other error condition by eventual reconnect.\n    else {\n        if (_s != retired_fd)\n            close ();\n        add_reconnect_timer ();\n    }\n}\n\nint zmq::tipc_connecter_t::open ()\n{\n    zmq_assert (_s == retired_fd);\n\n    // Cannot connect to random tipc addresses\n    if (_addr->resolved.tipc_addr->is_random ()) {\n        errno = EINVAL;\n        return -1;\n    }\n    //  Create the socket.\n    _s = open_socket (AF_TIPC, SOCK_STREAM, 0);\n    if (_s == retired_fd)\n        return -1;\n\n    //  Set the non-blocking flag.\n    unblock_socket (_s);\n    //  Connect to the remote peer.\n#ifdef ZMQ_HAVE_VXWORKS\n    int rc = ::connect (s, (sockaddr *) addr->resolved.tipc_addr->addr (),\n                        addr->resolved.tipc_addr->addrlen ());\n#else\n    int rc = ::connect (_s, _addr->resolved.tipc_addr->addr (),\n                        _addr->resolved.tipc_addr->addrlen ());\n#endif\n    //  Connect was successful immediately.\n    if (rc == 0)\n        return 0;\n\n    //  Translate other error codes indicating asynchronous connect has been\n    //  launched to a uniform EINPROGRESS.\n    if (rc == -1 && errno == EINTR) {\n        errno = EINPROGRESS;\n        return -1;\n    }\n    //  Forward the error.\n    return -1;\n}\n\nzmq::fd_t zmq::tipc_connecter_t::connect ()\n{\n    //  Following code should handle both Berkeley-derived socket\n    //  implementations and Solaris.\n    int err = 0;\n#ifdef ZMQ_HAVE_VXWORKS\n    int len = sizeof (err);\n#else\n    socklen_t len = sizeof (err);\n#endif\n    int rc = getsockopt (_s, SOL_SOCKET, SO_ERROR,\n                         reinterpret_cast<char *> (&err), &len);\n    if (rc == -1)\n        err = errno;\n    if (err != 0) {\n        //  Assert if the error was caused by 0MQ bug.\n        //  Networking problems are OK. No need to assert.\n        errno = err;\n        errno_assert (errno == ECONNREFUSED || errno == ECONNRESET\n                      || errno == ETIMEDOUT || errno == EHOSTUNREACH\n                      || errno == ENETUNREACH || errno == ENETDOWN);\n\n        return retired_fd;\n    }\n    fd_t result = _s;\n    _s = retired_fd;\n    return result;\n}\n\n#endif\n"
  },
  {
    "path": "src/tipc_connecter.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __TIPC_CONNECTER_HPP_INCLUDED__\n#define __TIPC_CONNECTER_HPP_INCLUDED__\n\n#include \"platform.hpp\"\n\n#if defined ZMQ_HAVE_TIPC\n\n#include \"fd.hpp\"\n#include \"stream_connecter_base.hpp\"\n\nnamespace zmq\n{\nclass tipc_connecter_t ZMQ_FINAL : public stream_connecter_base_t\n{\n  public:\n    //  If 'delayed_start' is true connecter first waits for a while,\n    //  then starts connection process.\n    tipc_connecter_t (zmq::io_thread_t *io_thread_,\n                      zmq::session_base_t *session_,\n                      const options_t &options_,\n                      address_t *addr_,\n                      bool delayed_start_);\n\n  private:\n    //  Handlers for I/O events.\n    void out_event () ZMQ_FINAL;\n\n    //  Internal function to start the actual connection establishment.\n    void start_connecting () ZMQ_FINAL;\n\n    //  Get the file descriptor of newly created connection. Returns\n    //  retired_fd if the connection was unsuccessful.\n    fd_t connect ();\n\n    //  Open IPC connecting socket. Returns -1 in case of error,\n    //  0 if connect was successful immediately. Returns -1 with\n    //  EAGAIN errno if async connect was launched.\n    int open ();\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (tipc_connecter_t)\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/tipc_listener.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"tipc_listener.hpp\"\n\n#if defined ZMQ_HAVE_TIPC\n\n#include <new>\n\n#include <string.h>\n\n#include \"tipc_address.hpp\"\n#include \"io_thread.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"socket_base.hpp\"\n#include \"address.hpp\"\n\n#include <unistd.h>\n#include <sys/socket.h>\n#include <fcntl.h>\n#if defined ZMQ_HAVE_VXWORKS\n#include <sockLib.h>\n#include <tipc/tipc.h>\n#else\n#include <linux/tipc.h>\n#endif\n\nzmq::tipc_listener_t::tipc_listener_t (io_thread_t *io_thread_,\n                                       socket_base_t *socket_,\n                                       const options_t &options_) :\n    stream_listener_base_t (io_thread_, socket_, options_)\n{\n}\n\nvoid zmq::tipc_listener_t::in_event ()\n{\n    fd_t fd = accept ();\n\n    //  If connection was reset by the peer in the meantime, just ignore it.\n    //  TODO: Handle specific errors like ENFILE/EMFILE etc.\n    if (fd == retired_fd) {\n        _socket->event_accept_failed (\n          make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());\n        return;\n    }\n\n    //  Create the engine object for this connection.\n    create_engine (fd);\n}\n\nstd::string\nzmq::tipc_listener_t::get_socket_name (zmq::fd_t fd_,\n                                       socket_end_t socket_end_) const\n{\n    return zmq::get_socket_name<tipc_address_t> (fd_, socket_end_);\n}\n\nint zmq::tipc_listener_t::set_local_address (const char *addr_)\n{\n    // Convert str to address struct\n    int rc = _address.resolve (addr_);\n    if (rc != 0)\n        return -1;\n\n    // Cannot bind non-random Port Identity\n    const sockaddr_tipc *const a =\n      reinterpret_cast<const sockaddr_tipc *> (_address.addr ());\n    if (!_address.is_random () && a->addrtype == TIPC_ADDR_ID) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    //  Create a listening socket.\n    _s = open_socket (AF_TIPC, SOCK_STREAM, 0);\n    if (_s == retired_fd)\n        return -1;\n\n    // If random Port Identity, update address object to reflect the assigned address\n    if (_address.is_random ()) {\n        struct sockaddr_storage ss;\n        const zmq_socklen_t sl = get_socket_address (_s, socket_end_local, &ss);\n        if (sl == 0)\n            goto error;\n\n        _address =\n          tipc_address_t (reinterpret_cast<struct sockaddr *> (&ss), sl);\n    }\n\n\n    _address.to_string (_endpoint);\n\n    //  Bind the socket to tipc name\n    if (_address.is_service ()) {\n#ifdef ZMQ_HAVE_VXWORKS\n        rc = bind (_s, (sockaddr *) address.addr (), address.addrlen ());\n#else\n        rc = bind (_s, _address.addr (), _address.addrlen ());\n#endif\n        if (rc != 0)\n            goto error;\n    }\n\n    //  Listen for incoming connections.\n    rc = listen (_s, options.backlog);\n    if (rc != 0)\n        goto error;\n\n    _socket->event_listening (make_unconnected_bind_endpoint_pair (_endpoint),\n                              _s);\n    return 0;\n\nerror:\n    int err = errno;\n    close ();\n    errno = err;\n    return -1;\n}\n\nzmq::fd_t zmq::tipc_listener_t::accept ()\n{\n    //  Accept one connection and deal with different failure modes.\n    //  The situation where connection cannot be accepted due to insufficient\n    //  resources is considered valid and treated by ignoring the connection.\n    struct sockaddr_storage ss = {};\n    socklen_t ss_len = sizeof (ss);\n\n    zmq_assert (_s != retired_fd);\n#ifdef ZMQ_HAVE_VXWORKS\n    fd_t sock = ::accept (_s, (struct sockaddr *) &ss, (int *) &ss_len);\n#else\n    fd_t sock =\n      ::accept (_s, reinterpret_cast<struct sockaddr *> (&ss), &ss_len);\n#endif\n    if (sock == -1) {\n        errno_assert (errno == EAGAIN || errno == EWOULDBLOCK\n                      || errno == ENOBUFS || errno == EINTR\n                      || errno == ECONNABORTED || errno == EPROTO\n                      || errno == EMFILE || errno == ENFILE);\n        return retired_fd;\n    }\n    /*FIXME Accept filters?*/\n    return sock;\n}\n\n#endif\n"
  },
  {
    "path": "src/tipc_listener.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_TIPC_LISTENER_HPP_INCLUDED__\n#define __ZMQ_TIPC_LISTENER_HPP_INCLUDED__\n\n#include \"platform.hpp\"\n\n#if defined ZMQ_HAVE_TIPC\n\n#include <string>\n\n#include \"fd.hpp\"\n#include \"stream_listener_base.hpp\"\n#include \"tipc_address.hpp\"\n\nnamespace zmq\n{\nclass tipc_listener_t ZMQ_FINAL : public stream_listener_base_t\n{\n  public:\n    tipc_listener_t (zmq::io_thread_t *io_thread_,\n                     zmq::socket_base_t *socket_,\n                     const options_t &options_);\n\n    //  Set address to listen on.\n    int set_local_address (const char *addr_);\n\n  protected:\n    std::string get_socket_name (fd_t fd_,\n                                 socket_end_t socket_end_) const ZMQ_FINAL;\n\n  private:\n    //  Handlers for I/O events.\n    void in_event () ZMQ_FINAL;\n\n    //  Accept the new connection. Returns the file descriptor of the\n    //  newly created connection. The function may return retired_fd\n    //  if the connection was dropped while waiting in the listen backlog.\n    fd_t accept ();\n\n    // Address to listen on\n    tipc_address_t _address;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (tipc_listener_t)\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/trie.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n#include \"err.hpp\"\n#include \"trie.hpp\"\n\n#include <stdlib.h>\n\n#include <new>\n#include <algorithm>\n\nzmq::trie_t::trie_t () : _refcnt (0), _min (0), _count (0), _live_nodes (0)\n{\n}\n\nzmq::trie_t::~trie_t ()\n{\n    if (_count == 1) {\n        zmq_assert (_next.node);\n        LIBZMQ_DELETE (_next.node);\n    } else if (_count > 1) {\n        for (unsigned short i = 0; i != _count; ++i) {\n            LIBZMQ_DELETE (_next.table[i]);\n        }\n        free (_next.table);\n    }\n}\n\nbool zmq::trie_t::add (unsigned char *prefix_, size_t size_)\n{\n    //  We are at the node corresponding to the prefix. We are done.\n    if (!size_) {\n        ++_refcnt;\n        return _refcnt == 1;\n    }\n\n    const unsigned char c = *prefix_;\n    if (c < _min || c >= _min + _count) {\n        //  The character is out of range of currently handled\n        //  characters. We have to extend the table.\n        if (!_count) {\n            _min = c;\n            _count = 1;\n            _next.node = NULL;\n        } else if (_count == 1) {\n            const unsigned char oldc = _min;\n            trie_t *oldp = _next.node;\n            _count = (_min < c ? c - _min : _min - c) + 1;\n            _next.table =\n              static_cast<trie_t **> (malloc (sizeof (trie_t *) * _count));\n            alloc_assert (_next.table);\n            for (unsigned short i = 0; i != _count; ++i)\n                _next.table[i] = 0;\n            _min = std::min (_min, c);\n            _next.table[oldc - _min] = oldp;\n        } else if (_min < c) {\n            //  The new character is above the current character range.\n            const unsigned short old_count = _count;\n            _count = c - _min + 1;\n            _next.table = static_cast<trie_t **> (\n              realloc (_next.table, sizeof (trie_t *) * _count));\n            zmq_assert (_next.table);\n            for (unsigned short i = old_count; i != _count; i++)\n                _next.table[i] = NULL;\n        } else {\n            //  The new character is below the current character range.\n            const unsigned short old_count = _count;\n            _count = (_min + old_count) - c;\n            _next.table = static_cast<trie_t **> (\n              realloc (_next.table, sizeof (trie_t *) * _count));\n            zmq_assert (_next.table);\n            memmove (_next.table + _min - c, _next.table,\n                     old_count * sizeof (trie_t *));\n            for (unsigned short i = 0; i != _min - c; i++)\n                _next.table[i] = NULL;\n            _min = c;\n        }\n    }\n\n    //  If next node does not exist, create one.\n    if (_count == 1) {\n        if (!_next.node) {\n            _next.node = new (std::nothrow) trie_t;\n            alloc_assert (_next.node);\n            ++_live_nodes;\n            zmq_assert (_live_nodes == 1);\n        }\n        return _next.node->add (prefix_ + 1, size_ - 1);\n    }\n    if (!_next.table[c - _min]) {\n        _next.table[c - _min] = new (std::nothrow) trie_t;\n        alloc_assert (_next.table[c - _min]);\n        ++_live_nodes;\n        zmq_assert (_live_nodes > 1);\n    }\n    return _next.table[c - _min]->add (prefix_ + 1, size_ - 1);\n}\n\nbool zmq::trie_t::rm (unsigned char *prefix_, size_t size_)\n{\n    //  TODO: Shouldn't an error be reported if the key does not exist?\n    if (!size_) {\n        if (!_refcnt)\n            return false;\n        _refcnt--;\n        return _refcnt == 0;\n    }\n    const unsigned char c = *prefix_;\n    if (!_count || c < _min || c >= _min + _count)\n        return false;\n\n    trie_t *next_node = _count == 1 ? _next.node : _next.table[c - _min];\n\n    if (!next_node)\n        return false;\n\n    const bool ret = next_node->rm (prefix_ + 1, size_ - 1);\n\n    //  Prune redundant nodes\n    if (next_node->is_redundant ()) {\n        LIBZMQ_DELETE (next_node);\n        zmq_assert (_count > 0);\n\n        if (_count == 1) {\n            //  The just pruned node is was the only live node\n            _next.node = 0;\n            _count = 0;\n            --_live_nodes;\n            zmq_assert (_live_nodes == 0);\n        } else {\n            _next.table[c - _min] = 0;\n            zmq_assert (_live_nodes > 1);\n            --_live_nodes;\n\n            //  Compact the table if possible\n            if (_live_nodes == 1) {\n                //  We can switch to using the more compact single-node\n                //  representation since the table only contains one live node\n                trie_t *node = 0;\n                //  Since we always compact the table the pruned node must\n                //  either be the left-most or right-most ptr in the node\n                //  table\n                if (c == _min) {\n                    //  The pruned node is the left-most node ptr in the\n                    //  node table => keep the right-most node\n                    node = _next.table[_count - 1];\n                    _min += _count - 1;\n                } else if (c == _min + _count - 1) {\n                    //  The pruned node is the right-most node ptr in the\n                    //  node table => keep the left-most node\n                    node = _next.table[0];\n                }\n                zmq_assert (node);\n                free (_next.table);\n                _next.node = node;\n                _count = 1;\n            } else if (c == _min) {\n                //  We can compact the table \"from the left\".\n                //  Find the left-most non-null node ptr, which we'll use as\n                //  our new min\n                unsigned char new_min = _min;\n                for (unsigned short i = 1; i < _count; ++i) {\n                    if (_next.table[i]) {\n                        new_min = i + _min;\n                        break;\n                    }\n                }\n                zmq_assert (new_min != _min);\n\n                trie_t **old_table = _next.table;\n                zmq_assert (new_min > _min);\n                zmq_assert (_count > new_min - _min);\n\n                _count = _count - (new_min - _min);\n                _next.table =\n                  static_cast<trie_t **> (malloc (sizeof (trie_t *) * _count));\n                alloc_assert (_next.table);\n\n                memmove (_next.table, old_table + (new_min - _min),\n                         sizeof (trie_t *) * _count);\n                free (old_table);\n\n                _min = new_min;\n            } else if (c == _min + _count - 1) {\n                //  We can compact the table \"from the right\".\n                //  Find the right-most non-null node ptr, which we'll use to\n                //  determine the new table size\n                unsigned short new_count = _count;\n                for (unsigned short i = 1; i < _count; ++i) {\n                    if (_next.table[_count - 1 - i]) {\n                        new_count = _count - i;\n                        break;\n                    }\n                }\n                zmq_assert (new_count != _count);\n                _count = new_count;\n\n                trie_t **old_table = _next.table;\n                _next.table =\n                  static_cast<trie_t **> (malloc (sizeof (trie_t *) * _count));\n                alloc_assert (_next.table);\n\n                memmove (_next.table, old_table, sizeof (trie_t *) * _count);\n                free (old_table);\n            }\n        }\n    }\n    return ret;\n}\n\nbool zmq::trie_t::check (const unsigned char *data_, size_t size_) const\n{\n    //  This function is on critical path. It deliberately doesn't use\n    //  recursion to get a bit better performance.\n    const trie_t *current = this;\n    while (true) {\n        //  We've found a corresponding subscription!\n        if (current->_refcnt)\n            return true;\n\n        //  We've checked all the data and haven't found matching subscription.\n        if (!size_)\n            return false;\n\n        //  If there's no corresponding slot for the first character\n        //  of the prefix, the message does not match.\n        const unsigned char c = *data_;\n        if (c < current->_min || c >= current->_min + current->_count)\n            return false;\n\n        //  Move to the next character.\n        if (current->_count == 1)\n            current = current->_next.node;\n        else {\n            current = current->_next.table[c - current->_min];\n            if (!current)\n                return false;\n        }\n        data_++;\n        size_--;\n    }\n}\n\nvoid zmq::trie_t::apply (\n  void (*func_) (unsigned char *data_, size_t size_, void *arg_), void *arg_)\n{\n    unsigned char *buff = NULL;\n    apply_helper (&buff, 0, 0, func_, arg_);\n    free (buff);\n}\n\nvoid zmq::trie_t::apply_helper (unsigned char **buff_,\n                                size_t buffsize_,\n                                size_t maxbuffsize_,\n                                void (*func_) (unsigned char *data_,\n                                               size_t size_,\n                                               void *arg_),\n                                void *arg_) const\n{\n    //  If this node is a subscription, apply the function.\n    if (_refcnt)\n        func_ (*buff_, buffsize_, arg_);\n\n    //  Adjust the buffer.\n    if (buffsize_ >= maxbuffsize_) {\n        maxbuffsize_ = buffsize_ + 256;\n        *buff_ = static_cast<unsigned char *> (realloc (*buff_, maxbuffsize_));\n        zmq_assert (*buff_);\n    }\n\n    //  If there are no subnodes in the trie, return.\n    if (_count == 0)\n        return;\n\n    //  If there's one subnode (optimisation).\n    if (_count == 1) {\n        (*buff_)[buffsize_] = _min;\n        buffsize_++;\n        _next.node->apply_helper (buff_, buffsize_, maxbuffsize_, func_, arg_);\n        return;\n    }\n\n    //  If there are multiple subnodes.\n    for (unsigned short c = 0; c != _count; c++) {\n        (*buff_)[buffsize_] = _min + c;\n        if (_next.table[c])\n            _next.table[c]->apply_helper (buff_, buffsize_ + 1, maxbuffsize_,\n                                          func_, arg_);\n    }\n}\n\nbool zmq::trie_t::is_redundant () const\n{\n    return _refcnt == 0 && _live_nodes == 0;\n}\n"
  },
  {
    "path": "src/trie.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_TRIE_HPP_INCLUDED__\n#define __ZMQ_TRIE_HPP_INCLUDED__\n\n#include <stddef.h>\n\n#include \"macros.hpp\"\n#include \"stdint.hpp\"\n#include \"atomic_counter.hpp\"\n\nnamespace zmq\n{\nclass trie_t\n{\n  public:\n    trie_t ();\n    ~trie_t ();\n\n    //  Add key to the trie. Returns true if this is a new item in the trie\n    //  rather than a duplicate.\n    bool add (unsigned char *prefix_, size_t size_);\n\n    //  Remove key from the trie. Returns true if the item is actually\n    //  removed from the trie.\n    bool rm (unsigned char *prefix_, size_t size_);\n\n    //  Check whether particular key is in the trie.\n    bool check (const unsigned char *data_, size_t size_) const;\n\n    //  Apply the function supplied to each subscription in the trie.\n    void apply (void (*func_) (unsigned char *data_, size_t size_, void *arg_),\n                void *arg_);\n\n  private:\n    void apply_helper (unsigned char **buff_,\n                       size_t buffsize_,\n                       size_t maxbuffsize_,\n                       void (*func_) (unsigned char *data_,\n                                      size_t size_,\n                                      void *arg_),\n                       void *arg_) const;\n    bool is_redundant () const;\n\n    uint32_t _refcnt;\n    unsigned char _min;\n    unsigned short _count;\n    unsigned short _live_nodes;\n    union\n    {\n        class trie_t *node;\n        class trie_t **table;\n    } _next;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (trie_t)\n};\n\n\n// lightweight wrapper around trie_t adding tracking of total number of prefixes\nclass trie_with_size_t\n{\n  public:\n    trie_with_size_t () {}\n    ~trie_with_size_t () {}\n\n    bool add (unsigned char *prefix_, size_t size_)\n    {\n        if (_trie.add (prefix_, size_)) {\n            _num_prefixes.add (1);\n            return true;\n        } else\n            return false;\n    }\n\n    bool rm (unsigned char *prefix_, size_t size_)\n    {\n        if (_trie.rm (prefix_, size_)) {\n            _num_prefixes.sub (1);\n            return true;\n        } else\n            return false;\n    }\n\n    bool check (const unsigned char *data_, size_t size_) const\n    {\n        return _trie.check (data_, size_);\n    }\n\n    void apply (void (*func_) (unsigned char *data_, size_t size_, void *arg_),\n                void *arg_)\n    {\n        _trie.apply (func_, arg_);\n    }\n\n    //  Retrieve the number of prefixes stored in this trie (added - removed)\n    //  Note this is a multithread safe function.\n    uint32_t num_prefixes () const { return _num_prefixes.get (); }\n\n  private:\n    atomic_counter_t _num_prefixes;\n    trie_t _trie;\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "src/udp_address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string>\n#include <sstream>\n\n#include \"macros.hpp\"\n#include \"udp_address.hpp\"\n#include \"stdint.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <sys/types.h>\n#include <arpa/inet.h>\n#include <netdb.h>\n#include <net/if.h>\n#include <ctype.h>\n#endif\n\nzmq::udp_address_t::udp_address_t () :\n    _bind_interface (-1), _is_multicast (false)\n{\n    _bind_address = ip_addr_t::any (AF_INET);\n    _target_address = ip_addr_t::any (AF_INET);\n}\n\nzmq::udp_address_t::~udp_address_t ()\n{\n}\n\nint zmq::udp_address_t::resolve (const char *name_, bool bind_, bool ipv6_)\n{\n    //  No IPv6 support yet\n    bool has_interface = false;\n\n    _address = name_;\n\n    //  If we have a semicolon then we should have an interface specifier in the\n    //  URL\n    const char *src_delimiter = strrchr (name_, ';');\n    if (src_delimiter) {\n        const std::string src_name (name_, src_delimiter - name_);\n\n        ip_resolver_options_t src_resolver_opts;\n\n        src_resolver_opts\n          .bindable (true)\n          //  Restrict hostname/service to literals to avoid any DNS\n          //  lookups or service-name irregularity due to\n          //  indeterminate socktype.\n          .allow_dns (false)\n          .allow_nic_name (true)\n          .ipv6 (ipv6_)\n          .expect_port (false);\n\n        ip_resolver_t src_resolver (src_resolver_opts);\n\n        const int rc = src_resolver.resolve (&_bind_address, src_name.c_str ());\n\n        if (rc != 0) {\n            return -1;\n        }\n\n        if (_bind_address.is_multicast ()) {\n            //  It doesn't make sense to have a multicast address as a source\n            errno = EINVAL;\n            return -1;\n        }\n\n        //  This is a hack because we need the interface index when binding\n        //  multicast IPv6, we can't do it by address. Unfortunately for the\n        //  time being we don't have a generic platform-independent function to\n        //  resolve an interface index from an address, so we only support it\n        //  when an actual interface name is provided.\n        if (src_name == \"*\") {\n            _bind_interface = 0;\n        } else {\n#ifdef HAVE_IF_NAMETOINDEX\n            _bind_interface = if_nametoindex (src_name.c_str ());\n            if (_bind_interface == 0) {\n                //  Error, probably not an interface name.\n                _bind_interface = -1;\n            }\n#endif\n        }\n\n        has_interface = true;\n        name_ = src_delimiter + 1;\n    }\n\n    ip_resolver_options_t resolver_opts;\n\n    resolver_opts.bindable (bind_)\n      .allow_dns (true)\n      .allow_nic_name (bind_)\n      .expect_port (true)\n      .ipv6 (ipv6_);\n\n    ip_resolver_t resolver (resolver_opts);\n\n    const int rc = resolver.resolve (&_target_address, name_);\n    if (rc != 0) {\n        return -1;\n    }\n\n    _is_multicast = _target_address.is_multicast ();\n    const uint16_t port = _target_address.port ();\n\n    if (has_interface) {\n        //  If we have an interface specifier then the target address must be a\n        //  multicast address\n        if (!_is_multicast) {\n            errno = EINVAL;\n            return -1;\n        }\n\n        _bind_address.set_port (port);\n    } else {\n        //  If we don't have an explicit interface specifier then the URL is\n        //  ambiguous: if the target address is multicast then it's the\n        //  destination address and the bind address is ANY, if it's unicast\n        //  then it's the bind address when 'bind_' is true and the destination\n        //  otherwise\n        if (_is_multicast || !bind_) {\n            _bind_address = ip_addr_t::any (_target_address.family ());\n            _bind_address.set_port (port);\n            _bind_interface = 0;\n        } else {\n            //  If we were asked for a bind socket and the address\n            //  provided was not multicast then it was really meant as\n            //  a bind address and the target_address is useless.\n            _bind_address = _target_address;\n        }\n    }\n\n    if (_bind_address.family () != _target_address.family ()) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    //  For IPv6 multicast we *must* have an interface index since we can't\n    //  bind by address.\n    if (ipv6_ && _is_multicast && _bind_interface < 0) {\n        errno = ENODEV;\n        return -1;\n    }\n\n    return 0;\n}\n\nint zmq::udp_address_t::family () const\n{\n    return _bind_address.family ();\n}\n\nbool zmq::udp_address_t::is_mcast () const\n{\n    return _is_multicast;\n}\n\nconst zmq::ip_addr_t *zmq::udp_address_t::bind_addr () const\n{\n    return &_bind_address;\n}\n\nint zmq::udp_address_t::bind_if () const\n{\n    return _bind_interface;\n}\n\nconst zmq::ip_addr_t *zmq::udp_address_t::target_addr () const\n{\n    return &_target_address;\n}\n\nint zmq::udp_address_t::to_string (std::string &addr_)\n{\n    // XXX what do (factor TCP code?)\n    addr_ = _address;\n    return 0;\n}\n"
  },
  {
    "path": "src/udp_address.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_UDP_ADDRESS_HPP_INCLUDED__\n#define __ZMQ_UDP_ADDRESS_HPP_INCLUDED__\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <sys/socket.h>\n#include <netinet/in.h>\n#endif\n\n#include <string>\n\n#include \"ip_resolver.hpp\"\n\nnamespace zmq\n{\nclass udp_address_t\n{\n  public:\n    udp_address_t ();\n    virtual ~udp_address_t ();\n\n    int resolve (const char *name_, bool bind_, bool ipv6_);\n\n    //  The opposite to resolve()\n    virtual int to_string (std::string &addr_);\n\n\n    int family () const;\n\n    bool is_mcast () const;\n\n    const ip_addr_t *bind_addr () const;\n    int bind_if () const;\n    const ip_addr_t *target_addr () const;\n\n  private:\n    ip_addr_t _bind_address;\n    int _bind_interface;\n    ip_addr_t _target_address;\n    bool _is_multicast;\n    std::string _address;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/udp_engine.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <sys/types.h>\n#include <unistd.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#ifdef ZMQ_HAVE_VXWORKS\n#include <sockLib.h>\n#endif\n#endif\n\n#include \"udp_address.hpp\"\n#include \"udp_engine.hpp\"\n#include \"session_base.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n\n//  OSX uses a different name for this socket option\n#ifndef IPV6_ADD_MEMBERSHIP\n#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP\n#endif\n\n#ifdef __APPLE__\n#include <TargetConditionals.h>\n#endif\n\nzmq::udp_engine_t::udp_engine_t (const options_t &options_) :\n    _plugged (false),\n    _fd (-1),\n    _session (NULL),\n    _handle (static_cast<handle_t> (NULL)),\n    _address (NULL),\n    _options (options_),\n    _send_enabled (false),\n    _recv_enabled (false)\n{\n}\n\nzmq::udp_engine_t::~udp_engine_t ()\n{\n    zmq_assert (!_plugged);\n\n    if (_fd != retired_fd) {\n#ifdef ZMQ_HAVE_WINDOWS\n        const int rc = closesocket (_fd);\n        wsa_assert (rc != SOCKET_ERROR);\n#else\n        int rc = close (_fd);\n        errno_assert (rc == 0);\n#endif\n        _fd = retired_fd;\n    }\n}\n\nint zmq::udp_engine_t::init (address_t *address_, bool send_, bool recv_)\n{\n    zmq_assert (address_);\n    zmq_assert (send_ || recv_);\n    _send_enabled = send_;\n    _recv_enabled = recv_;\n    _address = address_;\n\n    _fd = open_socket (_address->resolved.udp_addr->family (), SOCK_DGRAM,\n                       IPPROTO_UDP);\n    if (_fd == retired_fd)\n        return -1;\n\n    unblock_socket (_fd);\n\n    return 0;\n}\n\nvoid zmq::udp_engine_t::plug (io_thread_t *io_thread_, session_base_t *session_)\n{\n    zmq_assert (!_plugged);\n    _plugged = true;\n\n    zmq_assert (!_session);\n    zmq_assert (session_);\n    _session = session_;\n\n    //  Connect to I/O threads poller object.\n    io_object_t::plug (io_thread_);\n    _handle = add_fd (_fd);\n\n    const udp_address_t *const udp_addr = _address->resolved.udp_addr;\n\n    int rc = 0;\n\n    // Bind the socket to a device if applicable\n    if (!_options.bound_device.empty ()) {\n        rc = rc | bind_to_device (_fd, _options.bound_device);\n        if (rc != 0) {\n            assert_success_or_recoverable (_fd, rc);\n            error (connection_error);\n            return;\n        }\n    }\n\n    if (_send_enabled) {\n        if (!_options.raw_socket) {\n            const ip_addr_t *out = udp_addr->target_addr ();\n            _out_address = out->as_sockaddr ();\n            _out_address_len = out->sockaddr_len ();\n\n            if (out->is_multicast ()) {\n                const bool is_ipv6 = (out->family () == AF_INET6);\n                rc = rc\n                     | set_udp_multicast_loop (_fd, is_ipv6,\n                                               _options.multicast_loop);\n\n                if (_options.multicast_hops > 0) {\n                    rc = rc\n                         | set_udp_multicast_ttl (_fd, is_ipv6,\n                                                  _options.multicast_hops);\n                }\n\n                rc = rc | set_udp_multicast_iface (_fd, is_ipv6, udp_addr);\n            }\n        } else {\n            /// XXX fixme ?\n            _out_address = reinterpret_cast<sockaddr *> (&_raw_address);\n            _out_address_len =\n              static_cast<zmq_socklen_t> (sizeof (sockaddr_in));\n        }\n    }\n\n    if (_recv_enabled) {\n        rc = rc | set_udp_reuse_address (_fd, true);\n\n        const ip_addr_t *bind_addr = udp_addr->bind_addr ();\n        ip_addr_t any = ip_addr_t::any (bind_addr->family ());\n        const ip_addr_t *real_bind_addr;\n\n        const bool multicast = udp_addr->is_mcast ();\n\n        if (multicast) {\n            //  Multicast addresses should be allowed to bind to more than\n            //  one port as all ports should receive the message\n            rc = rc | set_udp_reuse_port (_fd, true);\n\n            //  In multicast we should bind ANY and use the mreq struct to\n            //  specify the interface\n            any.set_port (bind_addr->port ());\n\n            real_bind_addr = &any;\n        } else {\n            real_bind_addr = bind_addr;\n        }\n\n        if (rc != 0) {\n            error (protocol_error);\n            return;\n        }\n\n#ifdef ZMQ_HAVE_VXWORKS\n        rc = rc\n             | bind (_fd, (sockaddr *) real_bind_addr->as_sockaddr (),\n                     real_bind_addr->sockaddr_len ());\n#else\n        rc = rc\n             | bind (_fd, real_bind_addr->as_sockaddr (),\n                     real_bind_addr->sockaddr_len ());\n#endif\n        if (rc != 0) {\n            assert_success_or_recoverable (_fd, rc);\n            error (protocol_error);\n            return;\n        }\n\n        if (multicast) {\n            rc = rc | add_membership (_fd, udp_addr);\n        }\n    }\n\n    if (rc != 0) {\n        error (protocol_error);\n    } else {\n        if (_send_enabled) {\n            set_pollout (_handle);\n        }\n\n        if (_recv_enabled) {\n            set_pollin (_handle);\n\n            //  Call restart output to drop all join/leave commands\n            restart_output ();\n        }\n    }\n}\n\nint zmq::udp_engine_t::set_udp_multicast_loop (fd_t s_,\n                                               bool is_ipv6_,\n                                               bool loop_)\n{\n    int level;\n    int optname;\n\n    if (is_ipv6_) {\n        level = IPPROTO_IPV6;\n        optname = IPV6_MULTICAST_LOOP;\n    } else {\n        level = IPPROTO_IP;\n        optname = IP_MULTICAST_LOOP;\n    }\n\n    int loop = loop_ ? 1 : 0;\n    const int rc = setsockopt (s_, level, optname,\n                               reinterpret_cast<char *> (&loop), sizeof (loop));\n    assert_success_or_recoverable (s_, rc);\n    return rc;\n}\n\nint zmq::udp_engine_t::set_udp_multicast_ttl (fd_t s_, bool is_ipv6_, int hops_)\n{\n    int level;\n\n    if (is_ipv6_) {\n        level = IPPROTO_IPV6;\n    } else {\n        level = IPPROTO_IP;\n    }\n\n    const int rc =\n      setsockopt (s_, level, IP_MULTICAST_TTL,\n                  reinterpret_cast<char *> (&hops_), sizeof (hops_));\n    assert_success_or_recoverable (s_, rc);\n    return rc;\n}\n\nint zmq::udp_engine_t::set_udp_multicast_iface (fd_t s_,\n                                                bool is_ipv6_,\n                                                const udp_address_t *addr_)\n{\n    int rc = 0;\n\n    if (is_ipv6_) {\n        int bind_if = addr_->bind_if ();\n\n        if (bind_if > 0) {\n            //  If a bind interface is provided we tell the\n            //  kernel to use it to send multicast packets\n            rc = setsockopt (s_, IPPROTO_IPV6, IPV6_MULTICAST_IF,\n                             reinterpret_cast<char *> (&bind_if),\n                             sizeof (bind_if));\n        }\n    } else {\n        struct in_addr bind_addr = addr_->bind_addr ()->ipv4.sin_addr;\n\n        if (bind_addr.s_addr != INADDR_ANY) {\n            rc = setsockopt (s_, IPPROTO_IP, IP_MULTICAST_IF,\n                             reinterpret_cast<char *> (&bind_addr),\n                             sizeof (bind_addr));\n        }\n    }\n\n    assert_success_or_recoverable (s_, rc);\n    return rc;\n}\n\nint zmq::udp_engine_t::set_udp_reuse_address (fd_t s_, bool on_)\n{\n    int on = on_ ? 1 : 0;\n    const int rc = setsockopt (s_, SOL_SOCKET, SO_REUSEADDR,\n                               reinterpret_cast<char *> (&on), sizeof (on));\n    assert_success_or_recoverable (s_, rc);\n    return rc;\n}\n\nint zmq::udp_engine_t::set_udp_reuse_port (fd_t s_, bool on_)\n{\n#ifndef SO_REUSEPORT\n    return 0;\n#else\n    int on = on_ ? 1 : 0;\n    int rc = setsockopt (s_, SOL_SOCKET, SO_REUSEPORT,\n                         reinterpret_cast<char *> (&on), sizeof (on));\n    assert_success_or_recoverable (s_, rc);\n    return rc;\n#endif\n}\n\nint zmq::udp_engine_t::add_membership (fd_t s_, const udp_address_t *addr_)\n{\n    const ip_addr_t *mcast_addr = addr_->target_addr ();\n    int rc = 0;\n\n    if (mcast_addr->family () == AF_INET) {\n        struct ip_mreq mreq;\n        mreq.imr_multiaddr = mcast_addr->ipv4.sin_addr;\n        mreq.imr_interface = addr_->bind_addr ()->ipv4.sin_addr;\n\n        rc = setsockopt (s_, IPPROTO_IP, IP_ADD_MEMBERSHIP,\n                         reinterpret_cast<char *> (&mreq), sizeof (mreq));\n\n    } else if (mcast_addr->family () == AF_INET6) {\n        struct ipv6_mreq mreq;\n        const int iface = addr_->bind_if ();\n\n        zmq_assert (iface >= -1);\n\n        mreq.ipv6mr_multiaddr = mcast_addr->ipv6.sin6_addr;\n        mreq.ipv6mr_interface = iface;\n\n        rc = setsockopt (s_, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,\n                         reinterpret_cast<char *> (&mreq), sizeof (mreq));\n    }\n\n    assert_success_or_recoverable (s_, rc);\n    return rc;\n}\n\nvoid zmq::udp_engine_t::error (error_reason_t reason_)\n{\n    zmq_assert (_session);\n    _session->engine_error (false, reason_);\n    terminate ();\n}\n\nvoid zmq::udp_engine_t::terminate ()\n{\n    zmq_assert (_plugged);\n    _plugged = false;\n\n    rm_fd (_handle);\n\n    //  Disconnect from I/O threads poller object.\n    io_object_t::unplug ();\n\n    delete this;\n}\n\nvoid zmq::udp_engine_t::sockaddr_to_msg (zmq::msg_t *msg_,\n                                         const sockaddr_in *addr_)\n{\n    const char *const name = inet_ntoa (addr_->sin_addr);\n\n    char port[6];\n    const int port_len =\n      snprintf (port, 6, \"%d\", static_cast<int> (ntohs (addr_->sin_port)));\n    zmq_assert (port_len > 0 && port_len < 6);\n\n    const size_t name_len = strlen (name);\n    const int size = static_cast<int> (name_len) + 1 /* colon */\n                     + port_len + 1;                 //  terminating NUL\n    const int rc = msg_->init_size (size);\n    errno_assert (rc == 0);\n    msg_->set_flags (msg_t::more);\n\n    //  use memcpy instead of strcpy/strcat, since this is more efficient when\n    //  we already know the lengths, which we calculated above\n    char *address = static_cast<char *> (msg_->data ());\n    memcpy (address, name, name_len);\n    address += name_len;\n    *address++ = ':';\n    memcpy (address, port, static_cast<size_t> (port_len));\n    address += port_len;\n    *address = 0;\n}\n\nint zmq::udp_engine_t::resolve_raw_address (const char *name_, size_t length_)\n{\n    memset (&_raw_address, 0, sizeof _raw_address);\n\n    const char *delimiter = NULL;\n\n    // Find delimiter, cannot use memrchr as it is not supported on windows\n    if (length_ != 0) {\n        int chars_left = static_cast<int> (length_);\n        const char *current_char = name_ + length_;\n        do {\n            if (*(--current_char) == ':') {\n                delimiter = current_char;\n                break;\n            }\n        } while (--chars_left != 0);\n    }\n\n    if (!delimiter) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    const std::string addr_str (name_, delimiter - name_);\n    const std::string port_str (delimiter + 1, name_ + length_ - delimiter - 1);\n\n    //  Parse the port number (0 is not a valid port).\n    const uint16_t port = static_cast<uint16_t> (atoi (port_str.c_str ()));\n    if (port == 0) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    _raw_address.sin_family = AF_INET;\n    _raw_address.sin_port = htons (port);\n    _raw_address.sin_addr.s_addr = inet_addr (addr_str.c_str ());\n\n    if (_raw_address.sin_addr.s_addr == INADDR_NONE) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    return 0;\n}\n\nvoid zmq::udp_engine_t::out_event ()\n{\n    msg_t group_msg;\n    int rc = _session->pull_msg (&group_msg);\n    errno_assert (rc == 0 || (rc == -1 && errno == EAGAIN));\n\n    if (rc == 0) {\n        msg_t body_msg;\n        rc = _session->pull_msg (&body_msg);\n        //  If there's a group, there should also be a body\n        errno_assert (rc == 0);\n\n        const size_t group_size = group_msg.size ();\n        const size_t body_size = body_msg.size ();\n        size_t size;\n\n        if (_options.raw_socket) {\n            rc = resolve_raw_address (static_cast<char *> (group_msg.data ()),\n                                      group_size);\n\n            //  We discard the message if address is not valid\n            if (rc != 0) {\n                rc = group_msg.close ();\n                errno_assert (rc == 0);\n\n                rc = body_msg.close ();\n                errno_assert (rc == 0);\n\n                return;\n            }\n\n            size = body_size;\n\n            memcpy (_out_buffer, body_msg.data (), body_size);\n        } else {\n            size = group_size + body_size + 1;\n\n            // TODO: check if larger than maximum size\n            _out_buffer[0] = static_cast<unsigned char> (group_size);\n            memcpy (_out_buffer + 1, group_msg.data (), group_size);\n            memcpy (_out_buffer + 1 + group_size, body_msg.data (), body_size);\n        }\n\n        rc = group_msg.close ();\n        errno_assert (rc == 0);\n\n        body_msg.close ();\n        errno_assert (rc == 0);\n\n#ifdef ZMQ_HAVE_WINDOWS\n        rc = sendto (_fd, _out_buffer, static_cast<int> (size), 0, _out_address,\n                     _out_address_len);\n#elif defined ZMQ_HAVE_VXWORKS\n        rc = sendto (_fd, reinterpret_cast<caddr_t> (_out_buffer), size, 0,\n                     (sockaddr *) _out_address, _out_address_len);\n#else\n        rc = sendto (_fd, _out_buffer, size, 0, _out_address, _out_address_len);\n#endif\n        if (rc < 0) {\n#ifdef ZMQ_HAVE_WINDOWS\n            if (WSAGetLastError () != WSAEWOULDBLOCK) {\n                assert_success_or_recoverable (_fd, rc);\n                error (connection_error);\n            }\n#else\n            if (rc != EWOULDBLOCK) {\n                assert_success_or_recoverable (_fd, rc);\n                error (connection_error);\n            }\n#endif\n        }\n    } else {\n        reset_pollout (_handle);\n    }\n}\n\nconst zmq::endpoint_uri_pair_t &zmq::udp_engine_t::get_endpoint () const\n{\n    return _empty_endpoint;\n}\n\nvoid zmq::udp_engine_t::restart_output ()\n{\n    //  If we don't support send we just drop all messages\n    if (!_send_enabled) {\n        msg_t msg;\n        while (_session->pull_msg (&msg) == 0)\n            msg.close ();\n    } else {\n        set_pollout (_handle);\n        out_event ();\n    }\n}\n\nvoid zmq::udp_engine_t::in_event ()\n{\n    sockaddr_storage in_address;\n    zmq_socklen_t in_addrlen =\n      static_cast<zmq_socklen_t> (sizeof (sockaddr_storage));\n\n    const int nbytes =\n      recvfrom (_fd, _in_buffer, MAX_UDP_MSG, 0,\n                reinterpret_cast<sockaddr *> (&in_address), &in_addrlen);\n\n    if (nbytes < 0) {\n#ifdef ZMQ_HAVE_WINDOWS\n        if (WSAGetLastError () != WSAEWOULDBLOCK) {\n            assert_success_or_recoverable (_fd, nbytes);\n            error (connection_error);\n        }\n#else\n        if (nbytes != EWOULDBLOCK) {\n            assert_success_or_recoverable (_fd, nbytes);\n            error (connection_error);\n        }\n#endif\n        return;\n    }\n\n    int rc;\n    int body_size;\n    int body_offset;\n    msg_t msg;\n\n    if (_options.raw_socket) {\n        zmq_assert (in_address.ss_family == AF_INET);\n        sockaddr_to_msg (&msg, reinterpret_cast<sockaddr_in *> (&in_address));\n\n        body_size = nbytes;\n        body_offset = 0;\n    } else {\n        // TODO in out_event, the group size is an *unsigned* char. what is\n        // the maximum value?\n        const char *group_buffer = _in_buffer + 1;\n        const int group_size = _in_buffer[0];\n\n        rc = msg.init_size (group_size);\n        errno_assert (rc == 0);\n        msg.set_flags (msg_t::more);\n        memcpy (msg.data (), group_buffer, group_size);\n\n        //  This doesn't fit, just ignore\n        if (nbytes - 1 < group_size)\n            return;\n\n        body_size = nbytes - 1 - group_size;\n        body_offset = 1 + group_size;\n    }\n    // Push group description to session\n    rc = _session->push_msg (&msg);\n    errno_assert (rc == 0 || (rc == -1 && errno == EAGAIN));\n\n    //  Group description message doesn't fit in the pipe, drop\n    if (rc != 0) {\n        rc = msg.close ();\n        errno_assert (rc == 0);\n\n        reset_pollin (_handle);\n        return;\n    }\n\n    rc = msg.close ();\n    errno_assert (rc == 0);\n    rc = msg.init_size (body_size);\n    errno_assert (rc == 0);\n    memcpy (msg.data (), _in_buffer + body_offset, body_size);\n\n    // Push message body to session\n    rc = _session->push_msg (&msg);\n    // Message body doesn't fit in the pipe, drop and reset session state\n    if (rc != 0) {\n        rc = msg.close ();\n        errno_assert (rc == 0);\n\n        _session->reset ();\n        reset_pollin (_handle);\n        return;\n    }\n\n    rc = msg.close ();\n    errno_assert (rc == 0);\n    _session->flush ();\n}\n\nbool zmq::udp_engine_t::restart_input ()\n{\n    if (_recv_enabled) {\n        set_pollin (_handle);\n        in_event ();\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "src/udp_engine.hpp",
    "content": "\n#ifndef __ZMQ_UDP_ENGINE_HPP_INCLUDED__\n#define __ZMQ_UDP_ENGINE_HPP_INCLUDED__\n\n#include \"io_object.hpp\"\n#include \"i_engine.hpp\"\n#include \"address.hpp\"\n#include \"msg.hpp\"\n\n#define MAX_UDP_MSG 8192\n\nnamespace zmq\n{\nclass io_thread_t;\nclass session_base_t;\n\nclass udp_engine_t ZMQ_FINAL : public io_object_t, public i_engine\n{\n  public:\n    udp_engine_t (const options_t &options_);\n    ~udp_engine_t ();\n\n    int init (address_t *address_, bool send_, bool recv_);\n\n    bool has_handshake_stage () ZMQ_FINAL { return false; };\n\n    //  i_engine interface implementation.\n    //  Plug the engine to the session.\n    void plug (zmq::io_thread_t *io_thread_, class session_base_t *session_);\n\n    //  Terminate and deallocate the engine. Note that 'detached'\n    //  events are not fired on termination.\n    void terminate ();\n\n    //  This method is called by the session to signalise that more\n    //  messages can be written to the pipe.\n    bool restart_input ();\n\n    //  This method is called by the session to signalise that there\n    //  are messages to send available.\n    void restart_output ();\n\n    void zap_msg_available () {};\n\n    void in_event ();\n    void out_event ();\n\n    const endpoint_uri_pair_t &get_endpoint () const;\n\n  private:\n    int resolve_raw_address (const char *name_, size_t length_);\n    static void sockaddr_to_msg (zmq::msg_t *msg_, const sockaddr_in *addr_);\n\n    static int set_udp_reuse_address (fd_t s_, bool on_);\n    static int set_udp_reuse_port (fd_t s_, bool on_);\n    // Indicate, if the multicast data being sent should be looped back\n    static int set_udp_multicast_loop (fd_t s_, bool is_ipv6_, bool loop_);\n    // Set multicast TTL\n    static int set_udp_multicast_ttl (fd_t s_, bool is_ipv6_, int hops_);\n    // Set multicast address/interface\n    int set_udp_multicast_iface (fd_t s_,\n                                 bool is_ipv6_,\n                                 const udp_address_t *addr_);\n    // Join a multicast group\n    int add_membership (fd_t s_, const udp_address_t *addr_);\n\n    //  Function to handle network issues.\n    void error (error_reason_t reason_);\n\n    const endpoint_uri_pair_t _empty_endpoint;\n\n    bool _plugged;\n\n    fd_t _fd;\n    session_base_t *_session;\n    handle_t _handle;\n    address_t *_address;\n\n    options_t _options;\n\n    sockaddr_in _raw_address;\n    const struct sockaddr *_out_address;\n    zmq_socklen_t _out_address_len;\n\n    char _out_buffer[MAX_UDP_MSG];\n    char _in_buffer[MAX_UDP_MSG];\n    bool _send_enabled;\n    bool _recv_enabled;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/v1_decoder.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <stdlib.h>\n#include <string.h>\n#include <limits>\n#include <limits.h>\n\n#include \"decoder.hpp\"\n#include \"v1_decoder.hpp\"\n#include \"likely.hpp\"\n#include \"wire.hpp\"\n#include \"err.hpp\"\n\nzmq::v1_decoder_t::v1_decoder_t (size_t bufsize_, int64_t maxmsgsize_) :\n    decoder_base_t<v1_decoder_t> (bufsize_), _max_msg_size (maxmsgsize_)\n{\n    int rc = _in_progress.init ();\n    errno_assert (rc == 0);\n\n    //  At the beginning, read one byte and go to one_byte_size_ready state.\n    next_step (_tmpbuf, 1, &v1_decoder_t::one_byte_size_ready);\n}\n\nzmq::v1_decoder_t::~v1_decoder_t ()\n{\n    const int rc = _in_progress.close ();\n    errno_assert (rc == 0);\n}\n\nint zmq::v1_decoder_t::one_byte_size_ready (unsigned char const *)\n{\n    //  First byte of size is read. If it is UCHAR_MAX (0xff) read 8-byte size.\n    //  Otherwise allocate the buffer for message data and read the\n    //  message data into it.\n    if (*_tmpbuf == UCHAR_MAX)\n        next_step (_tmpbuf, 8, &v1_decoder_t::eight_byte_size_ready);\n    else {\n        //  There has to be at least one byte (the flags) in the message).\n        if (!*_tmpbuf) {\n            errno = EPROTO;\n            return -1;\n        }\n\n        if (_max_msg_size >= 0\n            && static_cast<int64_t> (*_tmpbuf - 1) > _max_msg_size) {\n            errno = EMSGSIZE;\n            return -1;\n        }\n\n        int rc = _in_progress.close ();\n        assert (rc == 0);\n        rc = _in_progress.init_size (*_tmpbuf - 1);\n        if (rc != 0) {\n            errno_assert (errno == ENOMEM);\n            rc = _in_progress.init ();\n            errno_assert (rc == 0);\n            errno = ENOMEM;\n            return -1;\n        }\n\n        next_step (_tmpbuf, 1, &v1_decoder_t::flags_ready);\n    }\n    return 0;\n}\n\nint zmq::v1_decoder_t::eight_byte_size_ready (unsigned char const *)\n{\n    //  8-byte payload length is read. Allocate the buffer\n    //  for message body and read the message data into it.\n    const uint64_t payload_length = get_uint64 (_tmpbuf);\n\n    //  There has to be at least one byte (the flags) in the message).\n    if (payload_length == 0) {\n        errno = EPROTO;\n        return -1;\n    }\n\n    //  Message size must not exceed the maximum allowed size.\n    if (_max_msg_size >= 0\n        && payload_length - 1 > static_cast<uint64_t> (_max_msg_size)) {\n        errno = EMSGSIZE;\n        return -1;\n    }\n\n#ifndef __aarch64__\n    //  Message size must fit within range of size_t data type.\n    if (payload_length - 1 > std::numeric_limits<size_t>::max ()) {\n        errno = EMSGSIZE;\n        return -1;\n    }\n#endif\n\n    const size_t msg_size = static_cast<size_t> (payload_length - 1);\n\n    int rc = _in_progress.close ();\n    assert (rc == 0);\n    rc = _in_progress.init_size (msg_size);\n    if (rc != 0) {\n        errno_assert (errno == ENOMEM);\n        rc = _in_progress.init ();\n        errno_assert (rc == 0);\n        errno = ENOMEM;\n        return -1;\n    }\n\n    next_step (_tmpbuf, 1, &v1_decoder_t::flags_ready);\n    return 0;\n}\n\nint zmq::v1_decoder_t::flags_ready (unsigned char const *)\n{\n    //  Store the flags from the wire into the message structure.\n    _in_progress.set_flags (_tmpbuf[0] & msg_t::more);\n\n    next_step (_in_progress.data (), _in_progress.size (),\n               &v1_decoder_t::message_ready);\n\n    return 0;\n}\n\nint zmq::v1_decoder_t::message_ready (unsigned char const *)\n{\n    //  Message is completely read. Push it further and start reading\n    //  new message. (in_progress is a 0-byte message after this point.)\n    next_step (_tmpbuf, 1, &v1_decoder_t::one_byte_size_ready);\n    return 1;\n}\n"
  },
  {
    "path": "src/v1_decoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_V1_DECODER_HPP_INCLUDED__\n#define __ZMQ_V1_DECODER_HPP_INCLUDED__\n\n#include \"decoder.hpp\"\n\nnamespace zmq\n{\n//  Decoder for ZMTP/1.0 protocol. Converts data batches into messages.\n\nclass v1_decoder_t ZMQ_FINAL : public decoder_base_t<v1_decoder_t>\n{\n  public:\n    v1_decoder_t (size_t bufsize_, int64_t maxmsgsize_);\n    ~v1_decoder_t ();\n\n    msg_t *msg () { return &_in_progress; }\n\n  private:\n    int one_byte_size_ready (unsigned char const *);\n    int eight_byte_size_ready (unsigned char const *);\n    int flags_ready (unsigned char const *);\n    int message_ready (unsigned char const *);\n\n    unsigned char _tmpbuf[8];\n    msg_t _in_progress;\n\n    const int64_t _max_msg_size;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (v1_decoder_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/v1_encoder.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"encoder.hpp\"\n#include \"v1_encoder.hpp\"\n#include \"msg.hpp\"\n#include \"wire.hpp\"\n\n#include <limits.h>\n\nzmq::v1_encoder_t::v1_encoder_t (size_t bufsize_) :\n    encoder_base_t<v1_encoder_t> (bufsize_)\n{\n    //  Write 0 bytes to the batch and go to message_ready state.\n    next_step (NULL, 0, &v1_encoder_t::message_ready, true);\n}\n\nzmq::v1_encoder_t::~v1_encoder_t ()\n{\n}\n\nvoid zmq::v1_encoder_t::size_ready ()\n{\n    //  Write message body into the buffer.\n    next_step (in_progress ()->data (), in_progress ()->size (),\n               &v1_encoder_t::message_ready, true);\n}\n\nvoid zmq::v1_encoder_t::message_ready ()\n{\n    size_t header_size = 2; // flags byte + size byte\n    //  Get the message size.\n    size_t size = in_progress ()->size ();\n\n    //  Account for the 'flags' byte.\n    size++;\n\n    //  Account for the subscribe/cancel byte.\n    if (in_progress ()->is_subscribe () || in_progress ()->is_cancel ())\n        size++;\n\n    //  For messages less than 255 bytes long, write one byte of message size.\n    //  For longer messages write 0xff escape character followed by 8-byte\n    //  message size. In both cases 'flags' field follows.\n    if (size < UCHAR_MAX) {\n        _tmpbuf[0] = static_cast<unsigned char> (size);\n        _tmpbuf[1] = (in_progress ()->flags () & msg_t::more);\n    } else {\n        _tmpbuf[0] = UCHAR_MAX;\n        put_uint64 (_tmpbuf + 1, size);\n        _tmpbuf[9] = (in_progress ()->flags () & msg_t::more);\n        header_size = 10;\n    }\n\n    //  Encode the subscribe/cancel byte. This is done in the encoder as\n    //  opposed to when the subscribe message is created to allow different\n    //  protocol behaviour on the wire in the v3.1 and legacy encoders.\n    //  It results in the work being done multiple times in case the sub\n    //  is sending the subscription/cancel to multiple pubs, but it cannot\n    //  be avoided. This processing can be moved to xsub once support for\n    //  ZMTP < 3.1 is dropped.\n    if (in_progress ()->is_subscribe ())\n        _tmpbuf[header_size++] = 1;\n    else if (in_progress ()->is_cancel ())\n        _tmpbuf[header_size++] = 0;\n\n    next_step (_tmpbuf, header_size, &v1_encoder_t::size_ready, false);\n}\n"
  },
  {
    "path": "src/v1_encoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_V1_ENCODER_HPP_INCLUDED__\n#define __ZMQ_V1_ENCODER_HPP_INCLUDED__\n\n#include \"encoder.hpp\"\n\nnamespace zmq\n{\n//  Encoder for ZMTP/1.0 protocol. Converts messages into data batches.\n\nclass v1_encoder_t ZMQ_FINAL : public encoder_base_t<v1_encoder_t>\n{\n  public:\n    v1_encoder_t (size_t bufsize_);\n    ~v1_encoder_t ();\n\n  private:\n    void size_ready ();\n    void message_ready ();\n\n    unsigned char _tmpbuf[11];\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (v1_encoder_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/v2_decoder.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <stdlib.h>\n#include <string.h>\n#include <cmath>\n\n#include \"v2_protocol.hpp\"\n#include \"v2_decoder.hpp\"\n#include \"likely.hpp\"\n#include \"wire.hpp\"\n#include \"err.hpp\"\n\nzmq::v2_decoder_t::v2_decoder_t (size_t bufsize_,\n                                 int64_t maxmsgsize_,\n                                 bool zero_copy_) :\n    decoder_base_t<v2_decoder_t, shared_message_memory_allocator> (bufsize_),\n    _msg_flags (0),\n    _zero_copy (zero_copy_),\n    _max_msg_size (maxmsgsize_)\n{\n    int rc = _in_progress.init ();\n    errno_assert (rc == 0);\n\n    //  At the beginning, read one byte and go to flags_ready state.\n    next_step (_tmpbuf, 1, &v2_decoder_t::flags_ready);\n}\n\nzmq::v2_decoder_t::~v2_decoder_t ()\n{\n    const int rc = _in_progress.close ();\n    errno_assert (rc == 0);\n}\n\nint zmq::v2_decoder_t::flags_ready (unsigned char const *)\n{\n    _msg_flags = 0;\n    if (_tmpbuf[0] & v2_protocol_t::more_flag)\n        _msg_flags |= msg_t::more;\n    if (_tmpbuf[0] & v2_protocol_t::command_flag)\n        _msg_flags |= msg_t::command;\n\n    //  The payload length is either one or eight bytes,\n    //  depending on whether the 'large' bit is set.\n    if (_tmpbuf[0] & v2_protocol_t::large_flag)\n        next_step (_tmpbuf, 8, &v2_decoder_t::eight_byte_size_ready);\n    else\n        next_step (_tmpbuf, 1, &v2_decoder_t::one_byte_size_ready);\n\n    return 0;\n}\n\nint zmq::v2_decoder_t::one_byte_size_ready (unsigned char const *read_from_)\n{\n    return size_ready (_tmpbuf[0], read_from_);\n}\n\nint zmq::v2_decoder_t::eight_byte_size_ready (unsigned char const *read_from_)\n{\n    //  The payload size is encoded as 64-bit unsigned integer.\n    //  The most significant byte comes first.\n    const uint64_t msg_size = get_uint64 (_tmpbuf);\n\n    return size_ready (msg_size, read_from_);\n}\n\nint zmq::v2_decoder_t::size_ready (uint64_t msg_size_,\n                                   unsigned char const *read_pos_)\n{\n    //  Message size must not exceed the maximum allowed size.\n    if (_max_msg_size >= 0)\n        if (unlikely (msg_size_ > static_cast<uint64_t> (_max_msg_size))) {\n            errno = EMSGSIZE;\n            return -1;\n        }\n\n    //  Message size must fit into size_t data type.\n    if (unlikely (msg_size_ != static_cast<size_t> (msg_size_))) {\n        errno = EMSGSIZE;\n        return -1;\n    }\n\n    int rc = _in_progress.close ();\n    assert (rc == 0);\n\n    // the current message can exceed the current buffer. We have to copy the buffer\n    // data into a new message and complete it in the next receive.\n\n    shared_message_memory_allocator &allocator = get_allocator ();\n    if (unlikely (!_zero_copy\n                  || msg_size_ > static_cast<size_t> (\n                       allocator.data () + allocator.size () - read_pos_))) {\n        // a new message has started, but the size would exceed the pre-allocated arena\n        // this happens every time when a message does not fit completely into the buffer\n        rc = _in_progress.init_size (static_cast<size_t> (msg_size_));\n    } else {\n        // construct message using n bytes from the buffer as storage\n        // increase buffer ref count\n        // if the message will be a large message, pass a valid refcnt memory location as well\n        rc =\n          _in_progress.init (const_cast<unsigned char *> (read_pos_),\n                             static_cast<size_t> (msg_size_),\n                             shared_message_memory_allocator::call_dec_ref,\n                             allocator.buffer (), allocator.provide_content ());\n\n        // For small messages, data has been copied and refcount does not have to be increased\n        if (_in_progress.is_zcmsg ()) {\n            allocator.advance_content ();\n            allocator.inc_ref ();\n        }\n    }\n\n    if (unlikely (rc)) {\n        errno_assert (errno == ENOMEM);\n        rc = _in_progress.init ();\n        errno_assert (rc == 0);\n        errno = ENOMEM;\n        return -1;\n    }\n\n    _in_progress.set_flags (_msg_flags);\n    // this sets read_pos to\n    // the message data address if the data needs to be copied\n    // for small message / messages exceeding the current buffer\n    // or\n    // to the current start address in the buffer because the message\n    // was constructed to use n bytes from the address passed as argument\n    next_step (_in_progress.data (), _in_progress.size (),\n               &v2_decoder_t::message_ready);\n\n    return 0;\n}\n\nint zmq::v2_decoder_t::message_ready (unsigned char const *)\n{\n    //  Message is completely read. Signal this to the caller\n    //  and prepare to decode next message.\n    next_step (_tmpbuf, 1, &v2_decoder_t::flags_ready);\n    return 1;\n}\n"
  },
  {
    "path": "src/v2_decoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_V2_DECODER_HPP_INCLUDED__\n#define __ZMQ_V2_DECODER_HPP_INCLUDED__\n\n#include \"decoder.hpp\"\n#include \"decoder_allocators.hpp\"\n\nnamespace zmq\n{\n//  Decoder for ZMTP/2.x framing protocol. Converts data stream into messages.\n//  The class has to inherit from shared_message_memory_allocator because\n//  the base class calls allocate in its constructor.\nclass v2_decoder_t ZMQ_FINAL\n    : public decoder_base_t<v2_decoder_t, shared_message_memory_allocator>\n{\n  public:\n    v2_decoder_t (size_t bufsize_, int64_t maxmsgsize_, bool zero_copy_);\n    ~v2_decoder_t ();\n\n    //  i_decoder interface.\n    msg_t *msg () { return &_in_progress; }\n\n  private:\n    int flags_ready (unsigned char const *);\n    int one_byte_size_ready (unsigned char const *);\n    int eight_byte_size_ready (unsigned char const *);\n    int message_ready (unsigned char const *);\n\n    int size_ready (uint64_t size_, unsigned char const *);\n\n    unsigned char _tmpbuf[8];\n    unsigned char _msg_flags;\n    msg_t _in_progress;\n\n    const bool _zero_copy;\n    const int64_t _max_msg_size;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (v2_decoder_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/v2_encoder.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"v2_protocol.hpp\"\n#include \"v2_encoder.hpp\"\n#include \"msg.hpp\"\n#include \"likely.hpp\"\n#include \"wire.hpp\"\n\n#include <limits.h>\n\nzmq::v2_encoder_t::v2_encoder_t (size_t bufsize_) :\n    encoder_base_t<v2_encoder_t> (bufsize_)\n{\n    //  Write 0 bytes to the batch and go to message_ready state.\n    next_step (NULL, 0, &v2_encoder_t::message_ready, true);\n}\n\nzmq::v2_encoder_t::~v2_encoder_t ()\n{\n}\n\nvoid zmq::v2_encoder_t::message_ready ()\n{\n    //  Encode flags.\n    size_t size = in_progress ()->size ();\n    size_t header_size = 2; // flags byte + size byte\n    unsigned char &protocol_flags = _tmp_buf[0];\n    protocol_flags = 0;\n    if (in_progress ()->flags () & msg_t::more)\n        protocol_flags |= v2_protocol_t::more_flag;\n    if (in_progress ()->size () > UCHAR_MAX)\n        protocol_flags |= v2_protocol_t::large_flag;\n    if (in_progress ()->flags () & msg_t::command)\n        protocol_flags |= v2_protocol_t::command_flag;\n    if (in_progress ()->is_subscribe () || in_progress ()->is_cancel ())\n        ++size;\n\n    //  Encode the message length. For messages less then 256 bytes,\n    //  the length is encoded as 8-bit unsigned integer. For larger\n    //  messages, 64-bit unsigned integer in network byte order is used.\n    if (unlikely (size > UCHAR_MAX)) {\n        put_uint64 (_tmp_buf + 1, size);\n        header_size = 9; // flags byte + size 8 bytes\n    } else {\n        _tmp_buf[1] = static_cast<uint8_t> (size);\n    }\n\n    //  Encode the subscribe/cancel byte. This is done in the encoder as\n    //  opposed to when the subscribe message is created to allow different\n    //  protocol behaviour on the wire in the v3.1 and legacy encoders.\n    //  It results in the work being done multiple times in case the sub\n    //  is sending the subscription/cancel to multiple pubs, but it cannot\n    //  be avoided. This processing can be moved to xsub once support for\n    //  ZMTP < 3.1 is dropped.\n    if (in_progress ()->is_subscribe ())\n        _tmp_buf[header_size++] = 1;\n    else if (in_progress ()->is_cancel ())\n        _tmp_buf[header_size++] = 0;\n\n    next_step (_tmp_buf, header_size, &v2_encoder_t::size_ready, false);\n}\n\nvoid zmq::v2_encoder_t::size_ready ()\n{\n    //  Write message body into the buffer.\n    next_step (in_progress ()->data (), in_progress ()->size (),\n               &v2_encoder_t::message_ready, true);\n}\n"
  },
  {
    "path": "src/v2_encoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_V2_ENCODER_HPP_INCLUDED__\n#define __ZMQ_V2_ENCODER_HPP_INCLUDED__\n\n#include \"encoder.hpp\"\n\nnamespace zmq\n{\n//  Encoder for 0MQ framing protocol. Converts messages into data stream.\n\nclass v2_encoder_t ZMQ_FINAL : public encoder_base_t<v2_encoder_t>\n{\n  public:\n    v2_encoder_t (size_t bufsize_);\n    ~v2_encoder_t ();\n\n  private:\n    void size_ready ();\n    void message_ready ();\n\n    //  flags byte + size byte (or 8 bytes) + sub/cancel byte\n    unsigned char _tmp_buf[10];\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (v2_encoder_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/v2_protocol.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_V2_PROTOCOL_HPP_INCLUDED__\n#define __ZMQ_V2_PROTOCOL_HPP_INCLUDED__\n\nnamespace zmq\n{\n//  Definition of constants for ZMTP/2.0 transport protocol.\nclass v2_protocol_t\n{\n  public:\n    //  Message flags.\n    enum\n    {\n        more_flag = 1,\n        large_flag = 2,\n        command_flag = 4\n    };\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/v3_1_encoder.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"v2_protocol.hpp\"\n#include \"v3_1_encoder.hpp\"\n#include \"msg.hpp\"\n#include \"likely.hpp\"\n#include \"wire.hpp\"\n\n#include <limits.h>\n\nzmq::v3_1_encoder_t::v3_1_encoder_t (size_t bufsize_) :\n    encoder_base_t<v3_1_encoder_t> (bufsize_)\n{\n    //  Write 0 bytes to the batch and go to message_ready state.\n    next_step (NULL, 0, &v3_1_encoder_t::message_ready, true);\n}\n\nzmq::v3_1_encoder_t::~v3_1_encoder_t ()\n{\n}\n\nvoid zmq::v3_1_encoder_t::message_ready ()\n{\n    //  Encode flags.\n    size_t size = in_progress ()->size ();\n    size_t header_size = 2; // flags byte + size byte\n    unsigned char &protocol_flags = _tmp_buf[0];\n    protocol_flags = 0;\n    if (in_progress ()->flags () & msg_t::more)\n        protocol_flags |= v2_protocol_t::more_flag;\n    if (in_progress ()->flags () & msg_t::command\n        || in_progress ()->is_subscribe () || in_progress ()->is_cancel ()) {\n        protocol_flags |= v2_protocol_t::command_flag;\n        if (in_progress ()->is_subscribe ())\n            size += zmq::msg_t::sub_cmd_name_size;\n        else if (in_progress ()->is_cancel ())\n            size += zmq::msg_t::cancel_cmd_name_size;\n    }\n    // Calculate large_flag after command_flag. Subscribe or cancel commands\n    // increase the message size.\n    if (size > UCHAR_MAX)\n        protocol_flags |= v2_protocol_t::large_flag;\n\n    //  Encode the message length. For messages less then 256 bytes,\n    //  the length is encoded as 8-bit unsigned integer. For larger\n    //  messages, 64-bit unsigned integer in network byte order is used.\n    if (unlikely (size > UCHAR_MAX)) {\n        put_uint64 (_tmp_buf + 1, size);\n        header_size = 9; // flags byte + size 8 bytes\n    } else {\n        _tmp_buf[1] = static_cast<uint8_t> (size);\n    }\n\n    //  Encode the sub/cancel command string. This is done in the encoder as\n    //  opposed to when the subscribe message is created to allow different\n    //  protocol behaviour on the wire in the v3.1 and legacy encoders.\n    //  It results in the work being done multiple times in case the sub\n    //  is sending the subscription/cancel to multiple pubs, but it cannot\n    //  be avoided. This processing can be moved to xsub once support for\n    //  ZMTP < 3.1 is dropped.\n    if (in_progress ()->is_subscribe ()) {\n        memcpy (_tmp_buf + header_size, zmq::sub_cmd_name,\n                zmq::msg_t::sub_cmd_name_size);\n        header_size += zmq::msg_t::sub_cmd_name_size;\n    } else if (in_progress ()->is_cancel ()) {\n        memcpy (_tmp_buf + header_size, zmq::cancel_cmd_name,\n                zmq::msg_t::cancel_cmd_name_size);\n        header_size += zmq::msg_t::cancel_cmd_name_size;\n    }\n\n    next_step (_tmp_buf, header_size, &v3_1_encoder_t::size_ready, false);\n}\n\nvoid zmq::v3_1_encoder_t::size_ready ()\n{\n    //  Write message body into the buffer.\n    next_step (in_progress ()->data (), in_progress ()->size (),\n               &v3_1_encoder_t::message_ready, true);\n}\n"
  },
  {
    "path": "src/v3_1_encoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_V3_1_ENCODER_HPP_INCLUDED__\n#define __ZMQ_V3_1_ENCODER_HPP_INCLUDED__\n\n#include \"encoder.hpp\"\n#include \"msg.hpp\"\n\nnamespace zmq\n{\n//  Encoder for 0MQ framing protocol. Converts messages into data stream.\n\nclass v3_1_encoder_t ZMQ_FINAL : public encoder_base_t<v3_1_encoder_t>\n{\n  public:\n    v3_1_encoder_t (size_t bufsize_);\n    ~v3_1_encoder_t () ZMQ_FINAL;\n\n  private:\n    void size_ready ();\n    void message_ready ();\n\n    unsigned char _tmp_buf[9 + zmq::msg_t::sub_cmd_name_size];\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (v3_1_encoder_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/version.rc.in",
    "content": "/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// VERSIONINFO resource\r\n//\r\n// http://msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx\r\n\r\n// @MAJOR@,@MINOR@,@BUILD@,@PATCH@\r\n#define VER_FILEVERSION\t\t@ZMQ_VERSION_MAJOR@,@ZMQ_VERSION_MINOR@,@ZMQ_VERSION_PATCH@,0\r\n#define VER_FILEVERSION_STR\t\"@ZMQ_VERSION_MAJOR@.@ZMQ_VERSION_MINOR@.@ZMQ_VERSION_PATCH@.0\\0\"\r\n\r\n#define VER_PRODUCTVERSION\tVER_FILEVERSION\r\n#define VER_PRODUCTVERSION_STR\tVER_FILEVERSION_STR\r\n\r\n\r\n// versionID\r\n// Version-information resource identifier.  This value must be 1.\r\n1 VERSIONINFO\r\n\r\n//// fixed-info\r\n// Binary version number for the file.\r\n\tFILEVERSION VER_FILEVERSION\r\n\r\n// Binary version number for the product with which the file is distributed.\r\n\tPRODUCTVERSION VER_PRODUCTVERSION\r\n\r\n// Bits in the FILEFLAGS statement are valid.\r\n\tFILEFLAGSMASK 0x17L\r\n\r\n// Attributes of the file.\r\n// VS_FF_DEBUG        =  1 : File contains debugging information or is compiled with debugging features enabled.\r\n// VS_FF_PATCHED      =  4 : File has been modified and is not identical to the original shipping file of the \r\n//                           same version number.\r\n// VS_FF_PRERELEASE   =  2 : File is a development version, not a commercially released product.\r\n// VS_FF_PRIVATEBUILD =  8 : File was not built using standard release procedures.\r\n// VS_FF_SPECIALBUILD = 20 : File was built by the original company using standard release procedures but is a\r\n//                         : variation of the standard file of the same version number.\r\n#ifdef _DEBUG\r\n\tFILEFLAGS 0x1L\r\n#else\r\n\tFILEFLAGS 0x2L\r\n#endif\r\n\r\n// Operating system for which this file was designed.\r\n// VOS_DOS           = 0x10000 : File was designed for MS-DOS.\r\n// VOS_NT            = 0x40000 : File was designed for 32-bit Windows.\r\n// VOS_WINDOWS16     =     0x1 : File was designed for 16-bit Windows.\r\n// VOS_WINDOWS32     =     0x4 : File was designed for 32-bit Windows.\r\n// VOS_DOS_WINDOWS16 = 0x10001 : File was designed for 16-bit Windows running with MS-DOS.\r\n// VOS_DOS_WINDOWS32 = 0x10004 : File was designed for 32-bit Windows running with MS-DOS.\r\n// VOS_NT_WINDOWS32  = 0x40004 : File was designed for 32-bit Windows.\r\n// NB: appears obsolete, nothing for x64.\r\n\tFILEOS 0x4L\r\n\r\n// General type of file.\r\n// VFT_APP        = 0x1 : File contains an application.\r\n// VFT_DLL        = 0x2 : File contains a dynamic-link library (DLL).\r\n// VFT_DRV        = 0x3 : File contains a device driver.\r\n// VFT_FONT       = 0x4 : File contains a font.\r\n// VFT_VXD        = 0x5 : File contains a virtual device.\r\n// VFT_STATIC_LIB = 0x7 : File contains a static-link library.\r\n\tFILETYPE 0x2L\r\n\r\n// Function of the file.\r\n\tFILESUBTYPE 0x0L\r\n\r\nBEGIN\r\n\tBLOCK \"StringFileInfo\"\r\n\tBEGIN\r\n\t\tBLOCK \"080904b0\"\r\n\t\tBEGIN\r\n\t\t\tVALUE \"CompanyName\",      \"iMatix Corporation\"\r\n\t\t\tVALUE \"FileDescription\",  \"ZeroMQ lightweight messaging kernel\"\r\n\t\t\tVALUE \"FileVersion\",      VER_FILEVERSION_STR\r\n\t\t\tVALUE \"InternalName\",     \"zeromq\"\r\n\t\t\tVALUE \"LegalCopyright\",   \"Copyright (c) 2012 The ZeroMQ Authors.\"\r\n\t\t\tVALUE \"OriginalFilename\", \"libzmq.dll\"\r\n\t\t\tVALUE \"ProductName\",      \"ZeroMQ\"\r\n\t\t\tVALUE \"ProductVersion\",   VER_PRODUCTVERSION_STR\r\n\t\tEND\r\n\tEND\r\n\r\n\tBLOCK \"VarFileInfo\"\r\n\tBEGIN\r\n// langID, one of the following language codes.\r\n// 0x409 : U.S. English\r\n// 0x809 : U.K. English\r\n// charsetID, one of the following character-set identifiers.\r\n// 1200 : Unicode\r\n\t\tVALUE \"Translation\", 0x809, 1200\r\n\tEND\r\nEND\r\n\r\n// end of file.\r\n"
  },
  {
    "path": "src/vmci.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n#include \"precompiled.hpp\"\n\n#include \"ip.hpp\"\n#include \"vmci.hpp\"\n#include \"vmci_address.hpp\"\n\n#if defined ZMQ_HAVE_VMCI\n\n#include <cassert>\n#include <vmci_sockets.h>\n\nvoid zmq::tune_vmci_buffer_size (ctx_t *context_,\n                                 fd_t sockfd_,\n                                 uint64_t default_size_,\n                                 uint64_t min_size_,\n                                 uint64_t max_size_)\n{\n    int family = context_->get_vmci_socket_family ();\n    assert (family != -1);\n\n    if (default_size_ != 0) {\n        int rc = setsockopt (sockfd_, family, SO_VMCI_BUFFER_SIZE,\n                             (char *) &default_size_, sizeof default_size_);\n#if defined ZMQ_HAVE_WINDOWS\n        wsa_assert (rc != SOCKET_ERROR);\n#else\n        errno_assert (rc == 0);\n#endif\n    }\n\n    if (min_size_ != 0) {\n        int rc = setsockopt (sockfd_, family, SO_VMCI_BUFFER_SIZE,\n                             (char *) &min_size_, sizeof min_size_);\n#if defined ZMQ_HAVE_WINDOWS\n        wsa_assert (rc != SOCKET_ERROR);\n#else\n        errno_assert (rc == 0);\n#endif\n    }\n\n    if (max_size_ != 0) {\n        int rc = setsockopt (sockfd_, family, SO_VMCI_BUFFER_SIZE,\n                             (char *) &max_size_, sizeof max_size_);\n#if defined ZMQ_HAVE_WINDOWS\n        wsa_assert (rc != SOCKET_ERROR);\n#else\n        errno_assert (rc == 0);\n#endif\n    }\n}\n\n#if defined ZMQ_HAVE_WINDOWS\nvoid zmq::tune_vmci_connect_timeout (ctx_t *context_,\n                                     fd_t sockfd_,\n                                     DWORD timeout_)\n#else\nvoid zmq::tune_vmci_connect_timeout (ctx_t *context_,\n                                     fd_t sockfd_,\n                                     struct timeval timeout_)\n#endif\n{\n    int family = context_->get_vmci_socket_family ();\n    assert (family != -1);\n\n    int rc = setsockopt (sockfd_, family, SO_VMCI_CONNECT_TIMEOUT,\n                         (char *) &timeout_, sizeof timeout_);\n#if defined ZMQ_HAVE_WINDOWS\n    wsa_assert (rc != SOCKET_ERROR);\n#else\n    errno_assert (rc == 0);\n#endif\n}\n\nzmq::fd_t zmq::vmci_open_socket (const char *address_,\n                                 const zmq::options_t &options_,\n                                 zmq::vmci_address_t *out_vmci_addr_)\n{\n    //  Convert the textual address into address structure.\n    int rc = out_vmci_addr_->resolve (address_);\n    if (rc != 0)\n        return retired_fd;\n\n    //  Create the socket.\n    fd_t s = open_socket (out_vmci_addr_->family (), SOCK_STREAM, 0);\n\n    if (s == retired_fd) {\n        return retired_fd;\n    }\n\n    return s;\n}\n\n#endif\n"
  },
  {
    "path": "src/vmci.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_VMCI_HPP_INCLUDED__\n#define __ZMQ_VMCI_HPP_INCLUDED__\n\n#include <string>\n\n#include \"platform.hpp\"\n#include \"fd.hpp\"\n#include \"ctx.hpp\"\n\n#if defined ZMQ_HAVE_VMCI\n\n#if defined ZMQ_HAVE_WINDOWS\n#include \"windows.hpp\"\n#else\n#include <sys/time.h>\n#endif\n\nnamespace zmq\n{\nvoid tune_vmci_buffer_size (ctx_t *context_,\n                            fd_t sockfd_,\n                            uint64_t default_size_,\n                            uint64_t min_size_,\n                            uint64_t max_size_);\n\n#if defined ZMQ_HAVE_WINDOWS\nvoid tune_vmci_connect_timeout (ctx_t *context_, fd_t sockfd_, DWORD timeout_);\n#else\nvoid tune_vmci_connect_timeout (ctx_t *context_,\n                                fd_t sockfd_,\n                                struct timeval timeout_);\n#endif\n\nfd_t vmci_open_socket (const char *address_,\n                       const options_t &options_,\n                       vmci_address_t *out_vmci_addr_);\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/vmci_address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"vmci_address.hpp\"\n\n#if defined(ZMQ_HAVE_VMCI)\n\n#include <climits>\n#include <string>\n#include <sstream>\n\n#include \"err.hpp\"\n\nzmq::vmci_address_t::vmci_address_t ()\n{\n    memset (&address, 0, sizeof address);\n}\n\nzmq::vmci_address_t::vmci_address_t (ctx_t *parent_) : parent (parent_)\n{\n    memset (&address, 0, sizeof address);\n}\n\nzmq::vmci_address_t::vmci_address_t (const sockaddr *sa,\n                                     socklen_t sa_len,\n                                     ctx_t *parent_) :\n    parent (parent_)\n{\n    zmq_assert (sa && sa_len > 0);\n\n    memset (&address, 0, sizeof address);\n    if (sa->sa_family == parent->get_vmci_socket_family ())\n        memcpy (&address, sa, sa_len);\n}\n\nint zmq::vmci_address_t::resolve (const char *path_)\n{\n    //  Find the ':' at end that separates address from the port number.\n    const char *delimiter = strrchr (path_, ':');\n    if (!delimiter) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    //  Separate the address/port.\n    std::string addr_str (path_, delimiter - path_);\n    std::string port_str (delimiter + 1);\n\n    unsigned int cid = VMADDR_CID_ANY;\n    unsigned int port = VMADDR_PORT_ANY;\n\n    if (!addr_str.length ()) {\n        errno = EINVAL;\n        return -1;\n    } else if (addr_str == \"@\") {\n        cid = VMCISock_GetLocalCID ();\n\n        if (cid == VMADDR_CID_ANY) {\n            errno = ENODEV;\n            return -1;\n        }\n    } else if (addr_str != \"*\" && addr_str != \"-1\") {\n        const char *begin = addr_str.c_str ();\n        char *end = NULL;\n        unsigned long l = strtoul (begin, &end, 10);\n\n        if ((l == 0 && end == begin) || (l == ULONG_MAX && errno == ERANGE)\n            || l > UINT_MAX) {\n            errno = EINVAL;\n            return -1;\n        }\n\n        cid = static_cast<unsigned int> (l);\n    }\n\n    if (!port_str.length ()) {\n        errno = EINVAL;\n        return -1;\n    } else if (port_str != \"*\" && port_str != \"-1\") {\n        const char *begin = port_str.c_str ();\n        char *end = NULL;\n        unsigned long l = strtoul (begin, &end, 10);\n\n        if ((l == 0 && end == begin) || (l == ULONG_MAX && errno == ERANGE)\n            || l > UINT_MAX) {\n            errno = EINVAL;\n            return -1;\n        }\n\n        port = static_cast<unsigned int> (l);\n    }\n\n    address.svm_family =\n      static_cast<sa_family_t> (parent->get_vmci_socket_family ());\n    address.svm_cid = cid;\n    address.svm_port = port;\n\n    return 0;\n}\n\nint zmq::vmci_address_t::to_string (std::string &addr_) const\n{\n    if (address.svm_family != parent->get_vmci_socket_family ()) {\n        addr_.clear ();\n        return -1;\n    }\n\n    std::stringstream s;\n\n    s << \"vmci://\";\n\n    if (address.svm_cid == VMADDR_CID_ANY) {\n        s << \"*\";\n    } else {\n        s << address.svm_cid;\n    }\n\n    s << \":\";\n\n    if (address.svm_port == VMADDR_PORT_ANY) {\n        s << \"*\";\n    } else {\n        s << address.svm_port;\n    }\n\n    addr_ = s.str ();\n    return 0;\n}\n\nconst sockaddr *zmq::vmci_address_t::addr () const\n{\n    return reinterpret_cast<const sockaddr *> (&address);\n}\n\nsocklen_t zmq::vmci_address_t::addrlen () const\n{\n    return static_cast<socklen_t> (sizeof address);\n}\n\n#if defined ZMQ_HAVE_WINDOWS\nunsigned short zmq::vmci_address_t::family () const\n#else\nsa_family_t zmq::vmci_address_t::family () const\n#endif\n{\n    return parent->get_vmci_socket_family ();\n}\n\n#endif\n"
  },
  {
    "path": "src/vmci_address.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_VMCI_ADDRESS_HPP_INCLUDED__\n#define __ZMQ_VMCI_ADDRESS_HPP_INCLUDED__\n\n#include <string>\n\n#include \"platform.hpp\"\n#include \"ctx.hpp\"\n\n#if defined(ZMQ_HAVE_VMCI)\n#include <vmci_sockets.h>\n\nnamespace zmq\n{\nclass vmci_address_t\n{\n  public:\n    vmci_address_t ();\n    vmci_address_t (ctx_t *parent_);\n    vmci_address_t (const sockaddr *sa, socklen_t sa_len, ctx_t *parent_);\n\n    //  This function sets up the address for VMCI transport.\n    int resolve (const char *path_);\n\n    //  The opposite to resolve()\n    int to_string (std::string &addr_) const;\n\n#if defined ZMQ_HAVE_WINDOWS\n    unsigned short family () const;\n#else\n    sa_family_t family () const;\n#endif\n    const sockaddr *addr () const;\n    socklen_t addrlen () const;\n\n  private:\n    struct sockaddr_vm address;\n    ctx_t *parent;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (vmci_address_t)\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/vmci_connecter.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"vmci_connecter.hpp\"\n\n#if defined ZMQ_HAVE_VMCI\n\n#include <new>\n\n#include \"io_thread.hpp\"\n#include \"platform.hpp\"\n#include \"random.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"address.hpp\"\n#include \"vmci_address.hpp\"\n#include \"vmci.hpp\"\n#include \"session_base.hpp\"\n\nzmq::vmci_connecter_t::vmci_connecter_t (class io_thread_t *io_thread_,\n                                         class session_base_t *session_,\n                                         const options_t &options_,\n                                         address_t *addr_,\n                                         bool delayed_start_) :\n    stream_connecter_base_t (\n      io_thread_, session_, options_, addr_, delayed_start_),\n    _connect_timer_started (false)\n{\n    zmq_assert (_addr->protocol == protocol_name::vmci);\n}\n\nzmq::vmci_connecter_t::~vmci_connecter_t ()\n{\n    zmq_assert (!_connect_timer_started);\n}\n\nvoid zmq::vmci_connecter_t::process_term (int linger_)\n{\n    if (_connect_timer_started) {\n        cancel_timer (connect_timer_id);\n        _connect_timer_started = false;\n    }\n\n    stream_connecter_base_t::process_term (linger_);\n}\n\nvoid zmq::vmci_connecter_t::in_event ()\n{\n    //  We are not polling for incoming data, so we are actually called\n    //  because of error here. However, we can get error on out event as well\n    //  on some platforms, so we'll simply handle both events in the same way.\n    out_event ();\n}\n\nvoid zmq::vmci_connecter_t::out_event ()\n{\n    if (_connect_timer_started) {\n        cancel_timer (connect_timer_id);\n        _connect_timer_started = false;\n    }\n\n    //  TODO this is still very similar to (t)ipc_connecter_t, maybe the\n    //  differences can be factored out\n\n    rm_handle ();\n\n    const fd_t fd = connect ();\n\n    if (fd == retired_fd\n        && ((options.reconnect_stop & ZMQ_RECONNECT_STOP_CONN_REFUSED)\n            && errno == ECONNREFUSED)) {\n        send_conn_failed (_session);\n        close ();\n        terminate ();\n        return;\n    }\n\n    //  Handle the error condition by attempt to reconnect.\n    if (fd == retired_fd) {\n        close ();\n        add_reconnect_timer ();\n        return;\n    }\n\n    tune_vmci_buffer_size (this->get_ctx (), fd, options.vmci_buffer_size,\n                           options.vmci_buffer_min_size,\n                           options.vmci_buffer_max_size);\n\n    if (options.vmci_connect_timeout > 0) {\n#if defined ZMQ_HAVE_WINDOWS\n        tune_vmci_connect_timeout (this->get_ctx (), fd,\n                                   options.vmci_connect_timeout);\n#else\n        struct timeval timeout = {0, options.vmci_connect_timeout * 1000};\n        tune_vmci_connect_timeout (this->get_ctx (), fd, timeout);\n#endif\n    }\n\n    create_engine (\n      fd, zmq::vmci_connecter_t::get_socket_name (fd, socket_end_local));\n}\n\nstd::string\nzmq::vmci_connecter_t::get_socket_name (zmq::fd_t fd_,\n                                        socket_end_t socket_end_) const\n{\n    struct sockaddr_storage ss;\n    const zmq_socklen_t sl = get_socket_address (fd_, socket_end_, &ss);\n    if (sl == 0) {\n        return std::string ();\n    }\n\n    const vmci_address_t addr (reinterpret_cast<struct sockaddr *> (&ss), sl,\n                               this->get_ctx ());\n    std::string address_string;\n    addr.to_string (address_string);\n    return address_string;\n}\n\nvoid zmq::vmci_connecter_t::timer_event (int id_)\n{\n    if (id_ == connect_timer_id) {\n        _connect_timer_started = false;\n        rm_handle ();\n        close ();\n        add_reconnect_timer ();\n    } else\n        stream_connecter_base_t::timer_event (id_);\n}\n\nvoid zmq::vmci_connecter_t::start_connecting ()\n{\n    //  Open the connecting socket.\n    const int rc = open ();\n\n    //  Connect may succeed in synchronous manner.\n    if (rc == 0) {\n        _handle = add_fd (_s);\n        out_event ();\n    }\n\n    //  Connection establishment may be delayed. Poll for its completion.\n    else if (rc == -1 && errno == EINPROGRESS) {\n        _handle = add_fd (_s);\n        set_pollout (_handle);\n        _socket->event_connect_delayed (\n          make_unconnected_connect_endpoint_pair (_endpoint), zmq_errno ());\n\n        //  add userspace connect timeout\n        add_connect_timer ();\n    }\n\n    //  Handle any other error condition by eventual reconnect.\n    else {\n        if (_s != retired_fd)\n            close ();\n        add_reconnect_timer ();\n    }\n}\n\nvoid zmq::vmci_connecter_t::add_connect_timer ()\n{\n    if (options.connect_timeout > 0) {\n        add_timer (options.connect_timeout, connect_timer_id);\n        _connect_timer_started = true;\n    }\n}\n\nint zmq::vmci_connecter_t::open ()\n{\n    zmq_assert (_s == retired_fd);\n\n    //  Resolve the address\n    if (_addr->resolved.vmci_addr != NULL) {\n        LIBZMQ_DELETE (_addr->resolved.vmci_addr);\n    }\n\n    _addr->resolved.vmci_addr =\n      new (std::nothrow) vmci_address_t (this->get_ctx ());\n    alloc_assert (_addr->resolved.vmci_addr);\n    _s = vmci_open_socket (_addr->address.c_str (), options,\n                           _addr->resolved.vmci_addr);\n    if (_s == retired_fd) {\n        //  TODO we should emit some event in this case!\n\n        LIBZMQ_DELETE (_addr->resolved.vmci_addr);\n        return -1;\n    }\n    zmq_assert (_addr->resolved.vmci_addr != NULL);\n\n    // Set the socket to non-blocking mode so that we get async connect().\n    unblock_socket (_s);\n\n    const vmci_address_t *const vmci_addr = _addr->resolved.vmci_addr;\n\n    int rc;\n\n    //  Connect to the remote peer.\n#if defined ZMQ_HAVE_VXWORKS\n    rc = ::connect (_s, (sockaddr *) vmci_addr->addr (), vmci_addr->addrlen ());\n#else\n    rc = ::connect (_s, vmci_addr->addr (), vmci_addr->addrlen ());\n#endif\n    //  Connect was successful immediately.\n    if (rc == 0) {\n        return 0;\n    }\n\n    //  Translate error codes indicating asynchronous connect has been\n    //  launched to a uniform EINPROGRESS.\n#ifdef ZMQ_HAVE_WINDOWS\n    const int last_error = WSAGetLastError ();\n    if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK)\n        errno = EINPROGRESS;\n    else\n        errno = wsa_error_to_errno (last_error);\n#else\n    if (errno == EINTR)\n        errno = EINPROGRESS;\n#endif\n    return -1;\n}\n\nzmq::fd_t zmq::vmci_connecter_t::connect ()\n{\n    //  Async connect has finished. Check whether an error occurred\n    int err = 0;\n#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS\n    int len = sizeof err;\n#else\n    socklen_t len = sizeof err;\n#endif\n\n    const int rc = getsockopt (_s, SOL_SOCKET, SO_ERROR,\n                               reinterpret_cast<char *> (&err), &len);\n\n    //  Assert if the error was caused by 0MQ bug.\n    //  Networking problems are OK. No need to assert.\n#ifdef ZMQ_HAVE_WINDOWS\n    zmq_assert (rc == 0);\n    if (err != 0) {\n        if (err == WSAEBADF || err == WSAENOPROTOOPT || err == WSAENOTSOCK\n            || err == WSAENOBUFS) {\n            wsa_assert_no (err);\n        }\n        errno = wsa_error_to_errno (err);\n        return retired_fd;\n    }\n#else\n    //  Following code should handle both Berkeley-derived socket\n    //  implementations and Solaris.\n    if (rc == -1)\n        err = errno;\n    if (err != 0) {\n        errno = err;\n#if !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE\n        errno_assert (errno != EBADF && errno != ENOPROTOOPT\n                      && errno != ENOTSOCK && errno != ENOBUFS);\n#else\n        errno_assert (errno != ENOPROTOOPT && errno != ENOTSOCK\n                      && errno != ENOBUFS);\n#endif\n        return retired_fd;\n    }\n#endif\n\n    //  Return the newly connected socket.\n    const fd_t result = _s;\n    _s = retired_fd;\n    return result;\n}\n\n#endif\n"
  },
  {
    "path": "src/vmci_connecter.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_VMCI_CONNECTER_HPP_INCLUDED__\n#define __ZMQ_VMCI_CONNECTER_HPP_INCLUDED__\n\n#include \"platform.hpp\"\n\n#if defined ZMQ_HAVE_VMCI\n\n#include \"fd.hpp\"\n#include \"own.hpp\"\n#include \"stdint.hpp\"\n#include \"io_object.hpp\"\n#include \"stream_connecter_base.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\nclass session_base_t;\nstruct address_t;\n\nclass vmci_connecter_t ZMQ_FINAL : public stream_connecter_base_t\n{\n  public:\n    //  If 'delayed_start' is true connecter first waits for a while,\n    //  then starts connection process.\n    vmci_connecter_t (zmq::io_thread_t *io_thread_,\n                      zmq::session_base_t *session_,\n                      const options_t &options_,\n                      address_t *addr_,\n                      bool delayed_start_);\n    ~vmci_connecter_t ();\n\n  protected:\n    std::string get_socket_name (fd_t fd_, socket_end_t socket_end_) const;\n\n  private:\n    //  ID of the timer used to check the connect timeout, must be different from stream_connecter_base_t::reconnect_timer_id.\n    enum\n    {\n        connect_timer_id = 2\n    };\n\n    //  Handlers for incoming commands.\n    void process_term (int linger_);\n\n    //  Handlers for I/O events.\n    void in_event ();\n    void out_event ();\n    void timer_event (int id_);\n\n    //  Internal function to start the actual connection establishment.\n    void start_connecting ();\n\n    //  Internal function to add a connect timer\n    void add_connect_timer ();\n\n    //  Internal function to return a reconnect backoff delay.\n    //  Will modify the current_reconnect_ivl used for next call\n    //  Returns the currently used interval\n    int get_new_reconnect_ivl ();\n\n    //  Open VMCI connecting socket. Returns -1 in case of error,\n    //  0 if connect was successful immediately. Returns -1 with\n    //  EAGAIN errno if async connect was launched.\n    int open ();\n\n    //  Get the file descriptor of newly created connection. Returns\n    //  retired_fd if the connection was unsuccessful.\n    fd_t connect ();\n\n    //  True iff a timer has been started.\n    bool _connect_timer_started;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (vmci_connecter_t)\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/vmci_listener.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"vmci_listener.hpp\"\n\n#if defined ZMQ_HAVE_VMCI\n\n#include <new>\n\n//#include \"stream_engine.hpp\"\n#include \"vmci_address.hpp\"\n#include \"io_thread.hpp\"\n#include \"session_base.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"socket_base.hpp\"\n#include \"vmci.hpp\"\n\n#if defined ZMQ_HAVE_WINDOWS\n#include \"windows.hpp\"\n#else\n#include <unistd.h>\n#include <fcntl.h>\n#endif\n\nzmq::vmci_listener_t::vmci_listener_t (io_thread_t *io_thread_,\n                                       socket_base_t *socket_,\n                                       const options_t &options_) :\n    stream_listener_base_t (io_thread_, socket_, options_)\n{\n}\n\nvoid zmq::vmci_listener_t::in_event ()\n{\n    fd_t fd = accept ();\n\n    //  If connection was reset by the peer in the meantime, just ignore it.\n    if (fd == retired_fd) {\n        _socket->event_accept_failed (\n          make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());\n        return;\n    }\n\n    tune_vmci_buffer_size (this->get_ctx (), fd, options.vmci_buffer_size,\n                           options.vmci_buffer_min_size,\n                           options.vmci_buffer_max_size);\n\n    if (options.vmci_connect_timeout > 0) {\n#if defined ZMQ_HAVE_WINDOWS\n        tune_vmci_connect_timeout (this->get_ctx (), fd,\n                                   options.vmci_connect_timeout);\n#else\n        struct timeval timeout = {0, options.vmci_connect_timeout * 1000};\n        tune_vmci_connect_timeout (this->get_ctx (), fd, timeout);\n#endif\n    }\n\n    //  Create the engine object for this connection.\n    create_engine (fd);\n}\n\nstd::string\nzmq::vmci_listener_t::get_socket_name (zmq::fd_t fd_,\n                                       socket_end_t socket_end_) const\n{\n    struct sockaddr_storage ss;\n    const zmq_socklen_t sl = get_socket_address (fd_, socket_end_, &ss);\n    if (sl == 0) {\n        return std::string ();\n    }\n\n    const vmci_address_t addr (reinterpret_cast<struct sockaddr *> (&ss), sl,\n                               this->get_ctx ());\n    std::string address_string;\n    addr.to_string (address_string);\n    return address_string;\n}\n\nint zmq::vmci_listener_t::set_local_address (const char *addr_)\n{\n    //  Create addr on stack for auto-cleanup\n    std::string addr (addr_);\n\n    //  Initialise the address structure.\n    vmci_address_t address (this->get_ctx ());\n    int rc = address.resolve (addr.c_str ());\n    if (rc != 0)\n        return -1;\n\n    //  Create a listening socket.\n    _s =\n      open_socket (this->get_ctx ()->get_vmci_socket_family (), SOCK_STREAM, 0);\n#ifdef ZMQ_HAVE_WINDOWS\n    if (_s == INVALID_SOCKET) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        return -1;\n    }\n#if !defined _WIN32_WCE\n    //  On Windows, preventing sockets to be inherited by child processes.\n    BOOL brc = SetHandleInformation ((HANDLE) _s, HANDLE_FLAG_INHERIT, 0);\n    win_assert (brc);\n#endif\n#else\n    if (_s == -1)\n        return -1;\n#endif\n\n    address.to_string (_endpoint);\n\n    //  Bind the socket.\n    rc = bind (_s, address.addr (), address.addrlen ());\n#ifdef ZMQ_HAVE_WINDOWS\n    if (rc == SOCKET_ERROR) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        goto error;\n    }\n#else\n    if (rc != 0)\n        goto error;\n#endif\n\n    //  Listen for incoming connections.\n    rc = listen (_s, options.backlog);\n#ifdef ZMQ_HAVE_WINDOWS\n    if (rc == SOCKET_ERROR) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        goto error;\n    }\n#else\n    if (rc != 0)\n        goto error;\n#endif\n\n    _socket->event_listening (make_unconnected_bind_endpoint_pair (_endpoint),\n                              _s);\n    return 0;\n\nerror:\n    int err = errno;\n    close ();\n    errno = err;\n    return -1;\n}\n\nzmq::fd_t zmq::vmci_listener_t::accept ()\n{\n    //  Accept one connection and deal with different failure modes.\n    //  The situation where connection cannot be accepted due to insufficient\n    //  resources is considered valid and treated by ignoring the connection.\n    zmq_assert (_s != retired_fd);\n    fd_t sock = ::accept (_s, NULL, NULL);\n\n#ifdef ZMQ_HAVE_WINDOWS\n    if (sock == INVALID_SOCKET) {\n        wsa_assert (WSAGetLastError () == WSAEWOULDBLOCK\n                    || WSAGetLastError () == WSAECONNRESET\n                    || WSAGetLastError () == WSAEMFILE\n                    || WSAGetLastError () == WSAENOBUFS);\n        return retired_fd;\n    }\n#if !defined _WIN32_WCE\n    //  On Windows, preventing sockets to be inherited by child processes.\n    BOOL brc = SetHandleInformation ((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);\n    win_assert (brc);\n#endif\n#else\n    if (sock == -1) {\n        errno_assert (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR\n                      || errno == ECONNABORTED || errno == EPROTO\n                      || errno == ENOBUFS || errno == ENOMEM || errno == EMFILE\n                      || errno == ENFILE);\n        return retired_fd;\n    }\n#endif\n\n    //  Race condition can cause socket not to be closed (if fork happens\n    //  between accept and this point).\n#ifdef FD_CLOEXEC\n    int rc = fcntl (sock, F_SETFD, FD_CLOEXEC);\n    errno_assert (rc != -1);\n#endif\n\n    return sock;\n}\n\n#endif\n"
  },
  {
    "path": "src/vmci_listener.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_VMCI_LISTENER_HPP_INCLUDED__\n#define __ZMQ_VMCI_LISTENER_HPP_INCLUDED__\n\n#include \"platform.hpp\"\n\n#if defined ZMQ_HAVE_VMCI\n\n#include <string>\n\n#include \"fd.hpp\"\n#include \"vmci_address.hpp\"\n#include \"stream_listener_base.hpp\"\n\nnamespace zmq\n{\nclass vmci_listener_t ZMQ_FINAL : public stream_listener_base_t\n{\n  public:\n    vmci_listener_t (zmq::io_thread_t *io_thread_,\n                     zmq::socket_base_t *socket_,\n                     const options_t &options_);\n\n    //  Set address to listen on.\n    int set_local_address (const char *addr_);\n\n  protected:\n    std::string get_socket_name (fd_t fd_, socket_end_t socket_end_) const;\n\n  private:\n    //  Handlers for I/O events.\n    void in_event ();\n\n    //  Accept the new connection. Returns the file descriptor of the\n    //  newly created connection. The function may return retired_fd\n    //  if the connection was dropped while waiting in the listen backlog.\n    fd_t accept ();\n\n    int create_socket (const char *addr_);\n\n    //  Address to listen on.\n    vmci_address_t _address;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (vmci_listener_t)\n};\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/vsock_address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"vsock_address.hpp\"\n\n#if defined ZMQ_HAVE_VSOCK\n\n#include <climits>\n#include <string>\n#include <sstream>\n#include \"err.hpp\"\n\nzmq::vsock_address_t::vsock_address_t ()\n{\n    memset (&address, 0, sizeof address);\n}\n\nzmq::vsock_address_t::vsock_address_t (ctx_t *parent_) : parent (parent_)\n{\n    memset (&address, 0, sizeof address);\n}\n\nzmq::vsock_address_t::vsock_address_t (const sockaddr *sa,\n                                       socklen_t sa_len,\n                                       ctx_t *parent_) :\n    parent (parent_)\n{\n    zmq_assert (sa && sa_len > 0);\n\n    memset (&address, 0, sizeof address);\n    if (sa->sa_family == AF_VSOCK)\n        memcpy (&address, sa, sa_len);\n}\n\nint zmq::vsock_address_t::resolve (const char *path_)\n{\n    //  Find the ':' at end that separates address from the port number.\n    const char *delimiter = strrchr (path_, ':');\n    if (!delimiter) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    //  Separate the address/port.\n    std::string addr_str (path_, delimiter - path_);\n    std::string port_str (delimiter + 1);\n\n    unsigned int cid = VMADDR_CID_ANY;\n    unsigned int port = VMADDR_PORT_ANY;\n\n    if (!addr_str.length ()) {\n        errno = EINVAL;\n        return -1;\n    } else if (addr_str == \"@\") {\n        cid = VMADDR_CID_HOST;\n\n        if (cid == VMADDR_CID_ANY) {\n            errno = ENODEV;\n            return -1;\n        }\n    } else if (addr_str != \"*\" && addr_str != \"-1\") {\n        const char *begin = addr_str.c_str ();\n        char *end = NULL;\n        unsigned long l = strtoul (begin, &end, 10);\n\n        if ((l == 0 && end == begin) || (l == ULONG_MAX && errno == ERANGE)\n            || l > UINT_MAX) {\n            errno = EINVAL;\n            return -1;\n        }\n\n        cid = static_cast<unsigned int> (l);\n    }\n\n    if (!port_str.length ()) {\n        errno = EINVAL;\n        return -1;\n    } else if (port_str != \"*\" && port_str != \"-1\") {\n        const char *begin = port_str.c_str ();\n        char *end = NULL;\n        unsigned long l = strtoul (begin, &end, 10);\n\n        if ((l == 0 && end == begin) || (l == ULONG_MAX && errno == ERANGE)\n            || l > UINT_MAX) {\n            errno = EINVAL;\n            return -1;\n        }\n\n        port = static_cast<unsigned int> (l);\n    }\n\n    address.svm_family = static_cast<sa_family_t> (AF_VSOCK);\n    address.svm_cid = cid;\n    address.svm_port = port;\n\n    return 0;\n}\n\nint zmq::vsock_address_t::to_string (std::string &addr_) const\n{\n    if (address.svm_family != parent->get_vsock_socket_family ()) {\n        addr_.clear ();\n        return -1;\n    }\n\n    std::stringstream s;\n\n    s << \"vsock://\";\n\n    if (address.svm_cid == VMADDR_CID_ANY) {\n        s << \"*\";\n    } else {\n        s << address.svm_cid;\n    }\n\n    s << \":\";\n\n    if (address.svm_port == VMADDR_PORT_ANY) {\n        s << \"*\";\n    } else {\n        s << address.svm_port;\n    }\n\n    addr_ = s.str ();\n    return 0;\n}\n\nconst sockaddr *zmq::vsock_address_t::addr () const\n{\n    return reinterpret_cast<const sockaddr *> (&address);\n}\n\nsocklen_t zmq::vsock_address_t::addrlen () const\n{\n    return static_cast<socklen_t> (sizeof address);\n}\n\nsa_family_t zmq::vsock_address_t::family () const\n{\n    return AF_VSOCK;\n}\n\n\n#endif\n"
  },
  {
    "path": "src/vsock_address.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_VSOCK_ADDRESS_HPP_INCLUDED__\n#define __ZMQ_VSOCK_ADDRESS_HPP_INCLUDED__\n\n#include <string>\n\n#include \"platform.hpp\"\n#include \"ctx.hpp\"\n#if defined ZMQ_HAVE_VSOCK\n#include <sys/socket.h>\n#include <linux/vm_sockets.h>\n\n\nnamespace zmq\n{\nclass vsock_address_t\n{\n  public:\n    vsock_address_t ();\n    vsock_address_t (ctx_t *parent_);\n    vsock_address_t (const sockaddr *sa, socklen_t sa_len, ctx_t *parent_);\n\n    //  This function sets up the address for VSOCK transport.\n    int resolve (const char *path_);\n\n    //  The opposite to resolve()\n    int to_string (std::string &addr_) const;\n\n    sa_family_t family () const;\n    const sockaddr *addr () const;\n    socklen_t addrlen () const;\n\n  private:\n    struct sockaddr_vm address;\n    ctx_t *parent;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (vsock_address_t)\n};\n}\n\n#endif\n#endif\n"
  },
  {
    "path": "src/vsock_connecter.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"vsock_connecter.hpp\"\n#include \"vsock_address.hpp\"\n\n#if defined ZMQ_HAVE_VSOCK\n\n#include <new>\n\n#include \"io_thread.hpp\"\n#include \"platform.hpp\"\n#include \"random.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"address.hpp\"\n#include \"session_base.hpp\"\n#include \"sys/socket.h\"\n#include \"linux/vm_sockets.h\"\n\nzmq::vsock_connecter_t::vsock_connecter_t (class io_thread_t *io_thread_,\n                                           class session_base_t *session_,\n                                           const options_t &options_,\n                                           address_t *addr_,\n                                           bool delayed_start_) :\n    stream_connecter_base_t (\n      io_thread_, session_, options_, addr_, delayed_start_),\n    _connect_timer_started (false)\n{\n    zmq_assert (_addr->protocol == protocol_name::vsock);\n}\n\nzmq::vsock_connecter_t::~vsock_connecter_t ()\n{\n    zmq_assert (!_connect_timer_started);\n}\n\nvoid zmq::vsock_connecter_t::process_term (int linger_)\n{\n    if (_connect_timer_started) {\n        cancel_timer (connect_timer_id);\n        _connect_timer_started = false;\n    }\n\n    stream_connecter_base_t::process_term (linger_);\n}\n\nvoid zmq::vsock_connecter_t::in_event ()\n{\n    //  We are not polling for incoming data, so we are actually called\n    //  because of error here. However, we can get error on out event as well\n    //  on some platforms, so we'll simply handle both events in the same way.\n    out_event ();\n}\n\nvoid zmq::vsock_connecter_t::out_event ()\n{\n    if (_connect_timer_started) {\n        cancel_timer (connect_timer_id);\n        _connect_timer_started = false;\n    }\n\n    //  TODO this is still very similar to (t)ipc_connecter_t, maybe the\n    //  differences can be factored out\n\n    rm_handle ();\n\n    const fd_t fd = connect ();\n\n    if (fd == retired_fd\n        && ((options.reconnect_stop & ZMQ_RECONNECT_STOP_CONN_REFUSED)\n            && errno == ECONNREFUSED)) {\n        send_conn_failed (_session);\n        close ();\n        terminate ();\n        return;\n    }\n\n    //  Handle the error condition by attempt to reconnect.\n    if (fd == retired_fd) {\n        close ();\n        add_reconnect_timer ();\n        return;\n    }\n\n    create_engine (\n      fd, zmq::vsock_connecter_t::get_socket_name (fd, socket_end_local));\n}\n\nstd::string\nzmq::vsock_connecter_t::get_socket_name (zmq::fd_t fd_,\n                                         socket_end_t socket_end_) const\n{\n    struct sockaddr_storage ss;\n    const zmq_socklen_t sl = get_socket_address (fd_, socket_end_, &ss);\n    if (sl == 0) {\n        return std::string ();\n    }\n\n    const vsock_address_t addr (reinterpret_cast<struct sockaddr *> (&ss), sl,\n                                this->get_ctx ());\n    std::string address_string;\n    addr.to_string (address_string);\n    return address_string;\n}\n\nvoid zmq::vsock_connecter_t::timer_event (int id_)\n{\n    if (id_ == connect_timer_id) {\n        _connect_timer_started = false;\n        rm_handle ();\n        close ();\n        add_reconnect_timer ();\n    } else\n        stream_connecter_base_t::timer_event (id_);\n}\n\nvoid zmq::vsock_connecter_t::start_connecting ()\n{\n    //  Open the connecting socket.\n    const int rc = open ();\n\n    //  Connect may succeed in synchronous manner.\n    if (rc == 0) {\n        _handle = add_fd (_s);\n        out_event ();\n    }\n\n    //  Connection establishment may be delayed. Poll for its completion.\n    else if (rc == -1 && errno == EINPROGRESS) {\n        _handle = add_fd (_s);\n        set_pollout (_handle);\n        _socket->event_connect_delayed (\n          make_unconnected_connect_endpoint_pair (_endpoint), zmq_errno ());\n\n        //  add userspace connect timeout\n        add_connect_timer ();\n    }\n\n    //  Handle any other error condition by eventual reconnect.\n    else {\n        if (_s != retired_fd)\n            close ();\n        add_reconnect_timer ();\n    }\n}\n\nvoid zmq::vsock_connecter_t::add_connect_timer ()\n{\n    if (options.connect_timeout > 0) {\n        add_timer (options.connect_timeout, connect_timer_id);\n        _connect_timer_started = true;\n    }\n}\n\nint zmq::vsock_connecter_t::open ()\n{\n    zmq_assert (_s == retired_fd);\n\n    //  Resolve the address\n    if (_addr->resolved.vsock_addr != NULL) {\n        LIBZMQ_DELETE (_addr->resolved.vsock_addr);\n    }\n\n    _addr->resolved.vsock_addr =\n      new (std::nothrow) vsock_address_t (this->get_ctx ());\n    alloc_assert (_addr->resolved.vsock_addr);\n\n    //  Convert the textual address into address structure.\n    _addr->resolved.vsock_addr->resolve (_addr->address.c_str ());\n\n    //  Create the socket.\n    _s = open_socket (AF_VSOCK, SOCK_STREAM, 0);\n\n    if (_s == retired_fd) {\n        //  TODO we should emit some event in this case!\n\n        LIBZMQ_DELETE (_addr->resolved.vsock_addr);\n        return -1;\n    }\n\n    zmq_assert (_addr->resolved.vsock_addr != NULL);\n\n    // Set the socket to non-blocking mode so that we get async connect().\n    unblock_socket (_s);\n\n    const vsock_address_t *const vsock_addr = _addr->resolved.vsock_addr;\n\n    //  Connect to the remote peer.\n    int rc = ::connect (_s, vsock_addr->addr (), vsock_addr->addrlen ());\n    //  Connect was successful immediately.\n    if (rc == 0) {\n        return 0;\n    }\n\n    if (errno == EINTR)\n        errno = EINPROGRESS;\n\n    return -1;\n}\n\nzmq::fd_t zmq::vsock_connecter_t::connect ()\n{\n    //  Async connect has finished. Check whether an error occurred\n    int err = 0;\n    socklen_t len = sizeof err;\n\n    const int rc = getsockopt (_s, SOL_SOCKET, SO_ERROR,\n                               reinterpret_cast<char *> (&err), &len);\n\n    //  Assert if the error was caused by 0MQ bug.\n    //  Networking problems are OK. No need to assert.\n    //  Following code should handle both Berkeley-derived socket\n    //  implementations and Solaris.\n    if (rc == -1)\n        err = errno;\n    if (err != 0) {\n        errno = err;\n        errno_assert (errno != ENOPROTOOPT && errno != ENOTSOCK\n                      && errno != ENOBUFS);\n        return retired_fd;\n    }\n\n    //  Return the newly connected socket.\n    const fd_t result = _s;\n    _s = retired_fd;\n    return result;\n}\n\n#endif\n"
  },
  {
    "path": "src/vsock_connecter.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_VSOCK_CONNECTER_HPP_INCLUDED__\n#define __ZMQ_VSOCK_CONNECTER_HPP_INCLUDED__\n\n#include \"platform.hpp\"\n#if defined ZMQ_HAVE_VSOCK\n\n#include \"fd.hpp\"\n#include \"own.hpp\"\n#include \"stdint.hpp\"\n#include \"io_object.hpp\"\n#include \"stream_connecter_base.hpp\"\n\nnamespace zmq\n{\nclass io_thread_t;\nclass session_base_t;\nstruct address_t;\n\nclass vsock_connecter_t ZMQ_FINAL : public stream_connecter_base_t\n{\n  public:\n    //  If 'delayed_start' is true connecter first waits for a while,\n    //  then starts connection process.\n    vsock_connecter_t (zmq::io_thread_t *io_thread_,\n                       zmq::session_base_t *session_,\n                       const options_t &options_,\n                       address_t *addr_,\n                       bool delayed_start_);\n    ~vsock_connecter_t ();\n\n  protected:\n    std::string get_socket_name (fd_t fd_, socket_end_t socket_end_) const;\n\n  private:\n    //  ID of the timer used to check the connect timeout, must be different from stream_connecter_base_t::reconnect_timer_id.\n    enum\n    {\n        connect_timer_id = 2\n    };\n\n    //  Handlers for incoming commands.\n    void process_term (int linger_);\n\n    //  Handlers for I/O events.\n    void in_event ();\n    void out_event ();\n    void timer_event (int id_);\n\n    //  Internal function to start the actual connection establishment.\n    void start_connecting ();\n\n    //  Internal function to add a connect timer\n    void add_connect_timer ();\n\n    //  Internal function to return a reconnect backoff delay.\n    //  Will modify the current_reconnect_ivl used for next call\n    //  Returns the currently used interval\n    int get_new_reconnect_ivl ();\n\n    //  Open Vsock connecting socket. Returns -1 in case of error,\n    //  0 if connect was successful immediately. Returns -1 with\n    //  EAGAIN errno if async connect was launched.\n    int open ();\n\n    //  Get the file descriptor of newly created connection. Returns\n    //  retired_fd if the connection was unsuccessful.\n    fd_t connect ();\n\n    //  True iff a timer has been started.\n    bool _connect_timer_started;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (vsock_connecter_t)\n};\n}\n\n#endif\n#endif\n"
  },
  {
    "path": "src/vsock_listener.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"vsock_listener.hpp\"\n#if defined ZMQ_HAVE_VSOCK\n\n\n#include <new>\n\n//#include \"stream_engine.hpp\"\n#include \"vsock_address.hpp\"\n#include \"io_thread.hpp\"\n#include \"session_base.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"socket_base.hpp\"\n#include \"sys/socket.h\"\n#include \"linux/vm_sockets.h\"\n#include <unistd.h>\n#include <fcntl.h>\n\nzmq::vsock_listener_t::vsock_listener_t (io_thread_t *io_thread_,\n                                         socket_base_t *socket_,\n                                         const options_t &options_) :\n    stream_listener_base_t (io_thread_, socket_, options_)\n{\n}\n\nvoid zmq::vsock_listener_t::in_event ()\n{\n    fd_t fd = accept ();\n\n    //  If connection was reset by the peer in the meantime, just ignore it.\n    if (fd == retired_fd) {\n        _socket->event_accept_failed (\n          make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());\n        return;\n    }\n\n    //  Create the engine object for this connection.\n    create_engine (fd);\n}\n\nstd::string\nzmq::vsock_listener_t::get_socket_name (zmq::fd_t fd_,\n                                        socket_end_t socket_end_) const\n{\n    struct sockaddr_storage ss;\n    const zmq_socklen_t sl = get_socket_address (fd_, socket_end_, &ss);\n    if (sl == 0) {\n        return std::string ();\n    }\n\n    const vsock_address_t addr (reinterpret_cast<struct sockaddr *> (&ss), sl,\n                                this->get_ctx ());\n    std::string address_string;\n    addr.to_string (address_string);\n    return address_string;\n}\n\nint zmq::vsock_listener_t::set_local_address (const char *addr_)\n{\n    //  Create addr on stack for auto-cleanup\n    std::string addr (addr_);\n\n    //  Initialise the address structure.\n    vsock_address_t address (this->get_ctx ());\n    int rc = address.resolve (addr.c_str ());\n    if (rc != 0)\n        return -1;\n\n    //  Create a listening socket.\n    _s = open_socket (AF_VSOCK, SOCK_STREAM, 0);\n    if (_s == -1)\n        return -1;\n\n    address.to_string (_endpoint);\n\n    //  Bind the socket.\n    rc = bind (_s, address.addr (), address.addrlen ());\n    if (rc != 0)\n        goto error;\n\n    //  Listen for incoming connections.\n    rc = listen (_s, options.backlog);\n    if (rc != 0)\n        goto error;\n\n    _socket->event_listening (make_unconnected_bind_endpoint_pair (_endpoint),\n                              _s);\n    return 0;\n\nerror:\n    int err = errno;\n    close ();\n    errno = err;\n    return -1;\n}\n\nzmq::fd_t zmq::vsock_listener_t::accept ()\n{\n    //  Accept one connection and deal with different failure modes.\n    //  The situation where connection cannot be accepted due to insufficient\n    //  resources is considered valid and treated by ignoring the connection.\n    zmq_assert (_s != retired_fd);\n    fd_t sock = ::accept (_s, NULL, NULL);\n\n    if (sock == -1) {\n        errno_assert (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR\n                      || errno == ECONNABORTED || errno == EPROTO\n                      || errno == ENOBUFS || errno == ENOMEM || errno == EMFILE\n                      || errno == ENFILE);\n        return retired_fd;\n    }\n\n    //  Race condition can cause socket not to be closed (if fork happens\n    //  between accept and this point).\n#ifdef FD_CLOEXEC\n    int rc = fcntl (sock, F_SETFD, FD_CLOEXEC);\n    errno_assert (rc != -1);\n#endif\n\n    return sock;\n}\n\n\n#endif\n"
  },
  {
    "path": "src/vsock_listener.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_VSOCK_LISTENER_HPP_INCLUDED__\n#define __ZMQ_VSOCK_LISTENER_HPP_INCLUDED__\n\n#include \"platform.hpp\"\n\n#if defined ZMQ_HAVE_VSOCK\n\n#include <string>\n\n#include \"fd.hpp\"\n#include \"vsock_address.hpp\"\n#include \"stream_listener_base.hpp\"\n\nnamespace zmq\n{\nclass vsock_listener_t ZMQ_FINAL : public stream_listener_base_t\n{\n  public:\n    vsock_listener_t (zmq::io_thread_t *io_thread_,\n                      zmq::socket_base_t *socket_,\n                      const options_t &options_);\n\n    //  Set address to listen on.\n    int set_local_address (const char *addr_);\n\n  protected:\n    std::string get_socket_name (fd_t fd_, socket_end_t socket_end_) const;\n\n  private:\n    //  Handlers for I/O events.\n    void in_event ();\n\n    //  Accept the new connection. Returns the file descriptor of the\n    //  newly created connection. The function may return retired_fd\n    //  if the connection was dropped while waiting in the listen backlog.\n    fd_t accept ();\n\n    int create_socket (const char *addr_);\n\n    //  Address to listen on.\n    vsock_address_t _address;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (vsock_listener_t)\n};\n}\n\n#endif\n#endif\n"
  },
  {
    "path": "src/windows.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_WINDOWS_HPP_INCLUDED__\n#define __ZMQ_WINDOWS_HPP_INCLUDED__\n\n#ifndef _CRT_SECURE_NO_WARNINGS\n#define _CRT_SECURE_NO_WARNINGS\n#endif\n#ifndef NOMINMAX\n#define NOMINMAX // Macros min(a,b) and max(a,b)\n#endif\n\n//  Set target version to Windows Server 2008, Windows Vista or higher.\n//  Windows XP (0x0501) is supported but without client & server socket types.\n#if !defined _WIN32_WINNT && !defined ZMQ_HAVE_WINDOWS_UWP\n#define _WIN32_WINNT 0x0600\n#endif\n\n#ifdef __MINGW32__\n//  Require Windows XP or higher with MinGW for getaddrinfo().\n#if (_WIN32_WINNT >= 0x0501)\n#else\n#error You need at least Windows XP target\n#endif\n#endif\n\n#include <winsock2.h>\n#include <windows.h>\n#include <mswsock.h>\n#include <iphlpapi.h>\n#include <string>\n#include <vector>\n\n#if !defined __MINGW32__\n#include <mstcpip.h>\n#endif\n\n//  Workaround missing mstcpip.h in mingw32 (MinGW64 provides this)\n//  __MINGW64_VERSION_MAJOR is only defined when using in mingw-w64\n#if defined __MINGW32__ && !defined SIO_KEEPALIVE_VALS                         \\\n  && !defined __MINGW64_VERSION_MAJOR\nstruct tcp_keepalive\n{\n    u_long onoff;\n    u_long keepalivetime;\n    u_long keepaliveinterval;\n};\n#define SIO_KEEPALIVE_VALS _WSAIOW (IOC_VENDOR, 4)\n#endif\n\n#include <ws2tcpip.h>\n#include <ipexport.h>\n#if !defined _WIN32_WCE\n#include <process.h>\n#endif\n\n#if defined ZMQ_IOTHREAD_POLLER_USE_POLL || defined ZMQ_POLL_BASED_ON_POLL\nstatic inline int poll (struct pollfd *pfd, unsigned long nfds, int timeout)\n{\n    return WSAPoll (pfd, nfds, timeout);\n}\n#endif\n\n//  In MinGW environment AI_NUMERICSERV is not defined.\n#ifndef AI_NUMERICSERV\n#define AI_NUMERICSERV 0x0400\n#endif\n\n//  Need unlink() and rmdir() functions that take utf-8 encoded file path.\nstatic inline std::wstring utf8_to_utf16 (const char *utf8_string)\n{\n    std::wstring retVal;\n\n    if (utf8_string && *utf8_string) {\n        const int utf16_length = ::MultiByteToWideChar (\n          CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string,\n          -1, // assume the input string is null-terminated\n          NULL, 0);\n\n        if (utf16_length > 0) {\n            retVal.resize (utf16_length);\n\n            const int conversion_result = ::MultiByteToWideChar (\n              CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string,\n              -1, // assume the input string is null-terminated\n              &retVal[0], static_cast<int> (retVal.size ()));\n\n            if (conversion_result == 0)\n                retVal.clear ();\n        }\n    }\n\n    return retVal;\n}\n\nstatic inline int unlink_utf8 (const char *filename)\n{\n    return _wunlink (utf8_to_utf16 (filename).c_str ());\n}\n\nstatic inline int rmdir_utf8 (const char *filename)\n{\n    return _wrmdir (utf8_to_utf16 (filename).c_str ());\n}\n\n//  In MSVC prior to v14, snprintf is not available\n//  The closest implementation is the _snprintf_s function\n#if defined(_MSC_VER) && _MSC_VER < 1900\n#define snprintf(buffer_, count_, format_, ...)                                \\\n    _snprintf_s (buffer_, count_, _TRUNCATE, format_, __VA_ARGS__)\n#endif\n\n//  Workaround missing struct sockaddr_un in afunix.h.\n//  Fix #3949.\n#if defined(ZMQ_HAVE_IPC) && !defined(ZMQ_HAVE_STRUCT_SOCKADDR_UN)\nstruct sockaddr_un\n{\n    ADDRESS_FAMILY sun_family; /* AF_UNIX */\n    char sun_path[108];        /* pathname */\n};\n#endif\n\n#endif\n"
  },
  {
    "path": "src/wire.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_WIRE_HPP_INCLUDED__\n#define __ZMQ_WIRE_HPP_INCLUDED__\n\n#include \"stdint.hpp\"\n\nnamespace zmq\n{\n//  Helper functions to convert different integer types to/from network\n//  byte order.\n\ninline void put_uint8 (unsigned char *buffer_, uint8_t value_)\n{\n    *buffer_ = value_;\n}\n\ninline uint8_t get_uint8 (const unsigned char *buffer_)\n{\n    return *buffer_;\n}\n\ninline void put_uint16 (unsigned char *buffer_, uint16_t value_)\n{\n    buffer_[0] = static_cast<unsigned char> (((value_) >> 8) & 0xff);\n    buffer_[1] = static_cast<unsigned char> (value_ & 0xff);\n}\n\ninline uint16_t get_uint16 (const unsigned char *buffer_)\n{\n    return ((static_cast<uint16_t> (buffer_[0])) << 8)\n           | (static_cast<uint16_t> (buffer_[1]));\n}\n\ninline void put_uint32 (unsigned char *buffer_, uint32_t value_)\n{\n    buffer_[0] = static_cast<unsigned char> (((value_) >> 24) & 0xff);\n    buffer_[1] = static_cast<unsigned char> (((value_) >> 16) & 0xff);\n    buffer_[2] = static_cast<unsigned char> (((value_) >> 8) & 0xff);\n    buffer_[3] = static_cast<unsigned char> (value_ & 0xff);\n}\n\ninline uint32_t get_uint32 (const unsigned char *buffer_)\n{\n    return ((static_cast<uint32_t> (buffer_[0])) << 24)\n           | ((static_cast<uint32_t> (buffer_[1])) << 16)\n           | ((static_cast<uint32_t> (buffer_[2])) << 8)\n           | (static_cast<uint32_t> (buffer_[3]));\n}\n\ninline void put_uint64 (unsigned char *buffer_, uint64_t value_)\n{\n    buffer_[0] = static_cast<unsigned char> (((value_) >> 56) & 0xff);\n    buffer_[1] = static_cast<unsigned char> (((value_) >> 48) & 0xff);\n    buffer_[2] = static_cast<unsigned char> (((value_) >> 40) & 0xff);\n    buffer_[3] = static_cast<unsigned char> (((value_) >> 32) & 0xff);\n    buffer_[4] = static_cast<unsigned char> (((value_) >> 24) & 0xff);\n    buffer_[5] = static_cast<unsigned char> (((value_) >> 16) & 0xff);\n    buffer_[6] = static_cast<unsigned char> (((value_) >> 8) & 0xff);\n    buffer_[7] = static_cast<unsigned char> (value_ & 0xff);\n}\n\ninline uint64_t get_uint64 (const unsigned char *buffer_)\n{\n    return ((static_cast<uint64_t> (buffer_[0])) << 56)\n           | ((static_cast<uint64_t> (buffer_[1])) << 48)\n           | ((static_cast<uint64_t> (buffer_[2])) << 40)\n           | ((static_cast<uint64_t> (buffer_[3])) << 32)\n           | ((static_cast<uint64_t> (buffer_[4])) << 24)\n           | ((static_cast<uint64_t> (buffer_[5])) << 16)\n           | ((static_cast<uint64_t> (buffer_[6])) << 8)\n           | (static_cast<uint64_t> (buffer_[7]));\n}\n}\n\n#endif\n"
  },
  {
    "path": "src/ws_address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string>\n#include <sstream>\n\n#include \"macros.hpp\"\n#include \"ws_address.hpp\"\n#include \"stdint.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <sys/types.h>\n#include <arpa/inet.h>\n#include <netinet/tcp.h>\n#include <net/if.h>\n#include <netdb.h>\n#include <ctype.h>\n#include <unistd.h>\n#include <stdlib.h>\n#endif\n\n#include <limits.h>\n\nzmq::ws_address_t::ws_address_t ()\n{\n    memset (&_address, 0, sizeof (_address));\n}\n\nzmq::ws_address_t::ws_address_t (const sockaddr *sa_, socklen_t sa_len_)\n{\n    zmq_assert (sa_ && sa_len_ > 0);\n\n    memset (&_address, 0, sizeof (_address));\n    if (sa_->sa_family == AF_INET\n        && sa_len_ >= static_cast<socklen_t> (sizeof (_address.ipv4)))\n        memcpy (&_address.ipv4, sa_, sizeof (_address.ipv4));\n    else if (sa_->sa_family == AF_INET6\n             && sa_len_ >= static_cast<socklen_t> (sizeof (_address.ipv6)))\n        memcpy (&_address.ipv6, sa_, sizeof (_address.ipv6));\n\n    _path = std::string (\"\");\n\n    char hbuf[NI_MAXHOST];\n    const int rc = getnameinfo (addr (), addrlen (), hbuf, sizeof (hbuf), NULL,\n                                0, NI_NUMERICHOST);\n    if (rc != 0) {\n        _host = std::string (\"localhost\");\n        return;\n    }\n\n    std::ostringstream os;\n\n    if (_address.family () == AF_INET6)\n        os << std::string (\"[\");\n\n    os << std::string (hbuf);\n\n    if (_address.family () == AF_INET6)\n        os << std::string (\"]\");\n\n    _host = os.str ();\n}\n\nint zmq::ws_address_t::resolve (const char *name_, bool local_, bool ipv6_)\n{\n    //  find the host part, It's important to use str*r*chr to only get\n    //  the latest colon since IPv6 addresses use colons as delemiters.\n    const char *delim = strrchr (name_, ':');\n    if (delim == NULL) {\n        errno = EINVAL;\n        return -1;\n    }\n    _host = std::string (name_, delim - name_);\n\n    // find the path part, which is optional\n    delim = strrchr (name_, '/');\n    std::string host_name;\n    if (delim) {\n        _path = std::string (delim);\n        // remove the path, otherwise resolving the port will fail with wildcard\n        host_name = std::string (name_, delim - name_);\n    } else {\n        _path = std::string (\"/\");\n        host_name = name_;\n    }\n\n    ip_resolver_options_t resolver_opts;\n    resolver_opts.bindable (local_)\n      .allow_dns (!local_)\n      .allow_nic_name (local_)\n      .ipv6 (ipv6_)\n      .allow_path (true)\n      .expect_port (true);\n\n    ip_resolver_t resolver (resolver_opts);\n\n    return resolver.resolve (&_address, host_name.c_str ());\n}\n\nint zmq::ws_address_t::to_string (std::string &addr_) const\n{\n    std::ostringstream os;\n    os << std::string (\"ws://\") << host () << std::string (\":\")\n       << _address.port () << _path;\n    addr_ = os.str ();\n\n    return 0;\n}\n\nconst sockaddr *zmq::ws_address_t::addr () const\n{\n    return _address.as_sockaddr ();\n}\n\nsocklen_t zmq::ws_address_t::addrlen () const\n{\n    return _address.sockaddr_len ();\n}\n\nconst char *zmq::ws_address_t::host () const\n{\n    return _host.c_str ();\n}\n\nconst char *zmq::ws_address_t::path () const\n{\n    return _path.c_str ();\n}\n\n#if defined ZMQ_HAVE_WINDOWS\nunsigned short zmq::ws_address_t::family () const\n#else\nsa_family_t zmq::ws_address_t::family () const\n#endif\n{\n    return _address.family ();\n}\n"
  },
  {
    "path": "src/ws_address.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_WS_ADDRESS_HPP_INCLUDED__\n#define __ZMQ_WS_ADDRESS_HPP_INCLUDED__\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <sys/socket.h>\n#include <netinet/in.h>\n#endif\n\n#include \"ip_resolver.hpp\"\n\nnamespace zmq\n{\nclass ws_address_t\n{\n  public:\n    ws_address_t ();\n    ws_address_t (const sockaddr *sa_, socklen_t sa_len_);\n\n    //  This function translates textual WS address into an address\n    //  structure. If 'local' is true, names are resolved as local interface\n    //  names. If it is false, names are resolved as remote hostnames.\n    //  If 'ipv6' is true, the name may resolve to IPv6 address.\n    int resolve (const char *name_, bool local_, bool ipv6_);\n\n    //  The opposite to resolve()\n    int to_string (std::string &addr_) const;\n\n#if defined ZMQ_HAVE_WINDOWS\n    unsigned short family () const;\n#else\n    sa_family_t family () const;\n#endif\n    const sockaddr *addr () const;\n    socklen_t addrlen () const;\n\n    const char *host () const;\n    const char *path () const;\n\n  protected:\n    ip_addr_t _address;\n\n  private:\n    std::string _host;\n    std::string _path;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ws_connecter.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <new>\n#include <string>\n\n#include \"macros.hpp\"\n#include \"ws_connecter.hpp\"\n#include \"io_thread.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"tcp.hpp\"\n#include \"address.hpp\"\n#include \"ws_address.hpp\"\n#include \"ws_engine.hpp\"\n#include \"session_base.hpp\"\n\n#ifdef ZMQ_HAVE_WSS\n#include \"wss_engine.hpp\"\n#include \"wss_address.hpp\"\n#endif\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <arpa/inet.h>\n#include <netinet/tcp.h>\n#include <netinet/in.h>\n#include <netdb.h>\n#include <fcntl.h>\n#ifdef ZMQ_HAVE_VXWORKS\n#include <sockLib.h>\n#endif\n#ifdef ZMQ_HAVE_OPENVMS\n#include <ioctl.h>\n#endif\n#endif\n\n#ifdef __APPLE__\n#include <TargetConditionals.h>\n#endif\n\nzmq::ws_connecter_t::ws_connecter_t (class io_thread_t *io_thread_,\n                                     class session_base_t *session_,\n                                     const options_t &options_,\n                                     address_t *addr_,\n                                     bool delayed_start_,\n                                     bool wss_,\n                                     const std::string &tls_hostname_) :\n    stream_connecter_base_t (\n      io_thread_, session_, options_, addr_, delayed_start_),\n    _connect_timer_started (false),\n    _wss (wss_),\n    _hostname (tls_hostname_)\n{\n}\n\nzmq::ws_connecter_t::~ws_connecter_t ()\n{\n    zmq_assert (!_connect_timer_started);\n}\n\nvoid zmq::ws_connecter_t::process_term (int linger_)\n{\n    if (_connect_timer_started) {\n        cancel_timer (connect_timer_id);\n        _connect_timer_started = false;\n    }\n\n    stream_connecter_base_t::process_term (linger_);\n}\n\nvoid zmq::ws_connecter_t::out_event ()\n{\n    if (_connect_timer_started) {\n        cancel_timer (connect_timer_id);\n        _connect_timer_started = false;\n    }\n\n    //  TODO this is still very similar to (t)ipc_connecter_t, maybe the\n    //  differences can be factored out\n\n    rm_handle ();\n\n    const fd_t fd = connect ();\n\n    //  Handle the error condition by attempt to reconnect.\n    if (fd == retired_fd || !tune_socket (fd)) {\n        close ();\n        add_reconnect_timer ();\n        return;\n    }\n\n    if (_wss)\n#ifdef ZMQ_HAVE_WSS\n        create_engine (fd,\n                       get_socket_name<wss_address_t> (fd, socket_end_local));\n#else\n        assert (false);\n#endif\n    else\n        create_engine (fd,\n                       get_socket_name<ws_address_t> (fd, socket_end_local));\n}\n\nvoid zmq::ws_connecter_t::timer_event (int id_)\n{\n    if (id_ == connect_timer_id) {\n        _connect_timer_started = false;\n        rm_handle ();\n        close ();\n        add_reconnect_timer ();\n    } else\n        stream_connecter_base_t::timer_event (id_);\n}\n\nvoid zmq::ws_connecter_t::start_connecting ()\n{\n    //  Open the connecting socket.\n    const int rc = open ();\n\n    //  Connect may succeed in synchronous manner.\n    if (rc == 0) {\n        _handle = add_fd (_s);\n        out_event ();\n    }\n\n    //  Connection establishment may be delayed. Poll for its completion.\n    else if (rc == -1 && errno == EINPROGRESS) {\n        _handle = add_fd (_s);\n        set_pollout (_handle);\n        _socket->event_connect_delayed (\n          make_unconnected_connect_endpoint_pair (_endpoint), zmq_errno ());\n\n        //  add userspace connect timeout\n        add_connect_timer ();\n    }\n\n    //  Handle any other error condition by eventual reconnect.\n    else {\n        if (_s != retired_fd)\n            close ();\n        add_reconnect_timer ();\n    }\n}\n\nvoid zmq::ws_connecter_t::add_connect_timer ()\n{\n    if (options.connect_timeout > 0) {\n        add_timer (options.connect_timeout, connect_timer_id);\n        _connect_timer_started = true;\n    }\n}\n\nint zmq::ws_connecter_t::open ()\n{\n    zmq_assert (_s == retired_fd);\n\n    tcp_address_t tcp_addr;\n    _s = tcp_open_socket (_addr->address.c_str (), options, false, true,\n                          &tcp_addr);\n    if (_s == retired_fd)\n        return -1;\n\n    // Set the socket to non-blocking mode so that we get async connect().\n    unblock_socket (_s);\n\n    //  Connect to the remote peer.\n#ifdef ZMQ_HAVE_VXWORKS\n    int rc = ::connect (_s, (sockaddr *) tcp_addr.addr (), tcp_addr.addrlen ());\n#else\n    const int rc = ::connect (_s, tcp_addr.addr (), tcp_addr.addrlen ());\n#endif\n    //  Connect was successful immediately.\n    if (rc == 0) {\n        return 0;\n    }\n\n    //  Translate error codes indicating asynchronous connect has been\n    //  launched to a uniform EINPROGRESS.\n#ifdef ZMQ_HAVE_WINDOWS\n    const int last_error = WSAGetLastError ();\n    if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK)\n        errno = EINPROGRESS;\n    else\n        errno = wsa_error_to_errno (last_error);\n#else\n    if (errno == EINTR)\n        errno = EINPROGRESS;\n#endif\n    return -1;\n}\n\nzmq::fd_t zmq::ws_connecter_t::connect ()\n{\n    //  Async connect has finished. Check whether an error occurred\n    int err = 0;\n#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS\n    int len = sizeof err;\n#else\n    socklen_t len = sizeof err;\n#endif\n\n    const int rc = getsockopt (_s, SOL_SOCKET, SO_ERROR,\n                               reinterpret_cast<char *> (&err), &len);\n\n    //  Assert if the error was caused by 0MQ bug.\n    //  Networking problems are OK. No need to assert.\n#ifdef ZMQ_HAVE_WINDOWS\n    zmq_assert (rc == 0);\n    if (err != 0) {\n        if (err == WSAEBADF || err == WSAENOPROTOOPT || err == WSAENOTSOCK\n            || err == WSAENOBUFS) {\n            wsa_assert_no (err);\n        }\n        return retired_fd;\n    }\n#else\n    //  Following code should handle both Berkeley-derived socket\n    //  implementations and Solaris.\n    if (rc == -1)\n        err = errno;\n    if (err != 0) {\n        errno = err;\n#if !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE\n        errno_assert (errno != EBADF && errno != ENOPROTOOPT\n                      && errno != ENOTSOCK && errno != ENOBUFS);\n#else\n        errno_assert (errno != ENOPROTOOPT && errno != ENOTSOCK\n                      && errno != ENOBUFS);\n#endif\n        return retired_fd;\n    }\n#endif\n\n    //  Return the newly connected socket.\n    const fd_t result = _s;\n    _s = retired_fd;\n    return result;\n}\n\nbool zmq::ws_connecter_t::tune_socket (const fd_t fd_)\n{\n    const int rc =\n      tune_tcp_socket (fd_) | tune_tcp_maxrt (fd_, options.tcp_maxrt);\n    return rc == 0;\n}\n\nvoid zmq::ws_connecter_t::create_engine (fd_t fd_,\n                                         const std::string &local_address_)\n{\n    const endpoint_uri_pair_t endpoint_pair (local_address_, _endpoint,\n                                             endpoint_type_connect);\n\n    //  Create the engine object for this connection.\n    i_engine *engine = NULL;\n    if (_wss) {\n#ifdef ZMQ_HAVE_WSS\n        engine = new (std::nothrow)\n          wss_engine_t (fd_, options, endpoint_pair, *_addr->resolved.ws_addr,\n                        true, NULL, _hostname);\n#else\n        LIBZMQ_UNUSED (_hostname);\n        assert (false);\n#endif\n    } else\n        engine = new (std::nothrow) ws_engine_t (\n          fd_, options, endpoint_pair, *_addr->resolved.ws_addr, true);\n    alloc_assert (engine);\n\n    //  Attach the engine to the corresponding session object.\n    send_attach (_session, engine);\n\n    //  Shut the connecter down.\n    terminate ();\n\n    _socket->event_connected (endpoint_pair, fd_);\n}\n"
  },
  {
    "path": "src/ws_connecter.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __WS_CONNECTER_HPP_INCLUDED__\n#define __WS_CONNECTER_HPP_INCLUDED__\n\n#include \"fd.hpp\"\n#include \"stdint.hpp\"\n#include \"stream_connecter_base.hpp\"\n\nnamespace zmq\n{\nclass ws_connecter_t ZMQ_FINAL : public stream_connecter_base_t\n{\n  public:\n    //  If 'delayed_start' is true connecter first waits for a while,\n    //  then starts connection process.\n    ws_connecter_t (zmq::io_thread_t *io_thread_,\n                    zmq::session_base_t *session_,\n                    const options_t &options_,\n                    address_t *addr_,\n                    bool delayed_start_,\n                    bool wss_,\n                    const std::string &tls_hostname_);\n    ~ws_connecter_t ();\n\n  protected:\n    void create_engine (fd_t fd, const std::string &local_address_);\n\n  private:\n    //  ID of the timer used to check the connect timeout, must be different from stream_connecter_base_t::reconnect_timer_id.\n    enum\n    {\n        connect_timer_id = 2\n    };\n\n    //  Handlers for incoming commands.\n    void process_term (int linger_);\n\n    //  Handlers for I/O events.\n    void out_event ();\n    void timer_event (int id_);\n\n    //  Internal function to start the actual connection establishment.\n    void start_connecting ();\n\n    //  Internal function to add a connect timer\n    void add_connect_timer ();\n\n    //  Open TCP connecting socket. Returns -1 in case of error,\n    //  0 if connect was successful immediately. Returns -1 with\n    //  EAGAIN errno if async connect was launched.\n    int open ();\n\n    //  Get the file descriptor of newly created connection. Returns\n    //  retired_fd if the connection was unsuccessful.\n    fd_t connect ();\n\n    //  Tunes a connected socket.\n    bool tune_socket (fd_t fd_);\n\n    //  True iff a timer has been started.\n    bool _connect_timer_started;\n\n    bool _wss;\n    const std::string &_hostname;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (ws_connecter_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ws_decoder.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <stdlib.h>\n#include <string.h>\n#include <cmath>\n\n#include \"ws_protocol.hpp\"\n#include \"ws_decoder.hpp\"\n#include \"likely.hpp\"\n#include \"wire.hpp\"\n#include \"err.hpp\"\n\nzmq::ws_decoder_t::ws_decoder_t (size_t bufsize_,\n                                 int64_t maxmsgsize_,\n                                 bool zero_copy_,\n                                 bool must_mask_) :\n    decoder_base_t<ws_decoder_t, shared_message_memory_allocator> (bufsize_),\n    _msg_flags (0),\n    _zero_copy (zero_copy_),\n    _max_msg_size (maxmsgsize_),\n    _must_mask (must_mask_),\n    _size (0)\n{\n    memset (_tmpbuf, 0, sizeof (_tmpbuf));\n    int rc = _in_progress.init ();\n    errno_assert (rc == 0);\n\n    //  At the beginning, read one byte and go to opcode_ready state.\n    next_step (_tmpbuf, 1, &ws_decoder_t::opcode_ready);\n}\n\nzmq::ws_decoder_t::~ws_decoder_t ()\n{\n    const int rc = _in_progress.close ();\n    errno_assert (rc == 0);\n}\n\nint zmq::ws_decoder_t::opcode_ready (unsigned char const *)\n{\n    const bool final = (_tmpbuf[0] & 0x80) != 0; // final bit\n    if (!final)\n        return -1; // non final messages are not supported\n\n    _opcode = static_cast<zmq::ws_protocol_t::opcode_t> (_tmpbuf[0] & 0xF);\n\n    _msg_flags = 0;\n\n    switch (_opcode) {\n        case zmq::ws_protocol_t::opcode_binary:\n            break;\n        case zmq::ws_protocol_t::opcode_close:\n            _msg_flags = msg_t::command | msg_t::close_cmd;\n            break;\n        case zmq::ws_protocol_t::opcode_ping:\n            _msg_flags = msg_t::ping | msg_t::command;\n            break;\n        case zmq::ws_protocol_t::opcode_pong:\n            _msg_flags = msg_t::pong | msg_t::command;\n            break;\n        default:\n            return -1;\n    }\n\n    next_step (_tmpbuf, 1, &ws_decoder_t::size_first_byte_ready);\n\n    return 0;\n}\n\nint zmq::ws_decoder_t::size_first_byte_ready (unsigned char const *read_from_)\n{\n    const bool is_masked = (_tmpbuf[0] & 0x80) != 0;\n\n    if (is_masked != _must_mask) // wrong mask value\n        return -1;\n\n    _size = static_cast<uint64_t> (_tmpbuf[0] & 0x7F);\n\n    if (_size < 126) {\n        if (_must_mask)\n            next_step (_tmpbuf, 4, &ws_decoder_t::mask_ready);\n        else if (_opcode == ws_protocol_t::opcode_binary) {\n            if (_size == 0)\n                return -1;\n            next_step (_tmpbuf, 1, &ws_decoder_t::flags_ready);\n        } else\n            return size_ready (read_from_);\n    } else if (_size == 126)\n        next_step (_tmpbuf, 2, &ws_decoder_t::short_size_ready);\n    else\n        next_step (_tmpbuf, 8, &ws_decoder_t::long_size_ready);\n\n    return 0;\n}\n\n\nint zmq::ws_decoder_t::short_size_ready (unsigned char const *read_from_)\n{\n    _size = (_tmpbuf[0] << 8) | _tmpbuf[1];\n\n    if (_must_mask)\n        next_step (_tmpbuf, 4, &ws_decoder_t::mask_ready);\n    else if (_opcode == ws_protocol_t::opcode_binary) {\n        if (_size == 0)\n            return -1;\n        next_step (_tmpbuf, 1, &ws_decoder_t::flags_ready);\n    } else\n        return size_ready (read_from_);\n\n    return 0;\n}\n\nint zmq::ws_decoder_t::long_size_ready (unsigned char const *read_from_)\n{\n    //  The payload size is encoded as 64-bit unsigned integer.\n    //  The most significant byte comes first.\n    _size = get_uint64 (_tmpbuf);\n\n    if (_must_mask)\n        next_step (_tmpbuf, 4, &ws_decoder_t::mask_ready);\n    else if (_opcode == ws_protocol_t::opcode_binary) {\n        if (_size == 0)\n            return -1;\n        next_step (_tmpbuf, 1, &ws_decoder_t::flags_ready);\n    } else\n        return size_ready (read_from_);\n\n    return 0;\n}\n\nint zmq::ws_decoder_t::mask_ready (unsigned char const *read_from_)\n{\n    memcpy (_mask, _tmpbuf, 4);\n\n    if (_opcode == ws_protocol_t::opcode_binary) {\n        if (_size == 0)\n            return -1;\n\n        next_step (_tmpbuf, 1, &ws_decoder_t::flags_ready);\n    } else\n        return size_ready (read_from_);\n\n    return 0;\n}\n\nint zmq::ws_decoder_t::flags_ready (unsigned char const *read_from_)\n{\n    unsigned char flags;\n\n    if (_must_mask)\n        flags = _tmpbuf[0] ^ _mask[0];\n    else\n        flags = _tmpbuf[0];\n\n    if (flags & ws_protocol_t::more_flag)\n        _msg_flags |= msg_t::more;\n    if (flags & ws_protocol_t::command_flag)\n        _msg_flags |= msg_t::command;\n\n    _size--;\n\n    return size_ready (read_from_);\n}\n\n\nint zmq::ws_decoder_t::size_ready (unsigned char const *read_pos_)\n{\n    //  Message size must not exceed the maximum allowed size.\n    if (_max_msg_size >= 0)\n        if (unlikely (_size > static_cast<uint64_t> (_max_msg_size))) {\n            errno = EMSGSIZE;\n            return -1;\n        }\n\n    //  Message size must fit into size_t data type.\n    if (unlikely (_size != static_cast<size_t> (_size))) {\n        errno = EMSGSIZE;\n        return -1;\n    }\n\n    int rc = _in_progress.close ();\n    assert (rc == 0);\n\n    // the current message can exceed the current buffer. We have to copy the buffer\n    // data into a new message and complete it in the next receive.\n\n    shared_message_memory_allocator &allocator = get_allocator ();\n    if (unlikely (!_zero_copy || allocator.data () > read_pos_\n                  || static_cast<size_t> (read_pos_ - allocator.data ())\n                       > allocator.size ()\n                  || _size > static_cast<size_t> (\n                       allocator.data () + allocator.size () - read_pos_))) {\n        // a new message has started, but the size would exceed the pre-allocated arena\n        // (or read_pos_ is in the initial handshake buffer)\n        // this happens every time when a message does not fit completely into the buffer\n        rc = _in_progress.init_size (static_cast<size_t> (_size));\n    } else {\n        // construct message using n bytes from the buffer as storage\n        // increase buffer ref count\n        // if the message will be a large message, pass a valid refcnt memory location as well\n        rc = _in_progress.init (\n          const_cast<unsigned char *> (read_pos_), static_cast<size_t> (_size),\n          shared_message_memory_allocator::call_dec_ref, allocator.buffer (),\n          allocator.provide_content ());\n\n        // For small messages, data has been copied and refcount does not have to be increased\n        if (_in_progress.is_zcmsg ()) {\n            allocator.advance_content ();\n            allocator.inc_ref ();\n        }\n    }\n\n    if (unlikely (rc)) {\n        errno_assert (errno == ENOMEM);\n        rc = _in_progress.init ();\n        errno_assert (rc == 0);\n        errno = ENOMEM;\n        return -1;\n    }\n\n    _in_progress.set_flags (_msg_flags);\n    // this sets read_pos to\n    // the message data address if the data needs to be copied\n    // for small message / messages exceeding the current buffer\n    // or\n    // to the current start address in the buffer because the message\n    // was constructed to use n bytes from the address passed as argument\n    next_step (_in_progress.data (), _in_progress.size (),\n               &ws_decoder_t::message_ready);\n\n    return 0;\n}\n\nint zmq::ws_decoder_t::message_ready (unsigned char const *)\n{\n    if (_must_mask) {\n        int mask_index = _opcode == ws_protocol_t::opcode_binary ? 1 : 0;\n\n        unsigned char *data =\n          static_cast<unsigned char *> (_in_progress.data ());\n        for (size_t i = 0; i < _size; ++i, mask_index++)\n            data[i] = data[i] ^ _mask[mask_index % 4];\n    }\n\n    //  Message is completely read. Signal this to the caller\n    //  and prepare to decode next message.\n    next_step (_tmpbuf, 1, &ws_decoder_t::opcode_ready);\n    return 1;\n}\n"
  },
  {
    "path": "src/ws_decoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_WS_DECODER_HPP_INCLUDED__\n#define __ZMQ_WS_DECODER_HPP_INCLUDED__\n\n#include \"decoder.hpp\"\n#include \"decoder_allocators.hpp\"\n#include \"ws_protocol.hpp\"\n\nnamespace zmq\n{\n//  Decoder for Web socket framing protocol. Converts data stream into messages.\n//  The class has to inherit from shared_message_memory_allocator because\n//  the base class calls allocate in its constructor.\nclass ws_decoder_t ZMQ_FINAL\n    : public decoder_base_t<ws_decoder_t, shared_message_memory_allocator>\n{\n  public:\n    ws_decoder_t (size_t bufsize_,\n                  int64_t maxmsgsize_,\n                  bool zero_copy_,\n                  bool must_mask_);\n    ~ws_decoder_t ();\n\n    //  i_decoder interface.\n    msg_t *msg () { return &_in_progress; }\n\n  private:\n    int opcode_ready (unsigned char const *);\n    int size_first_byte_ready (unsigned char const *);\n    int short_size_ready (unsigned char const *);\n    int long_size_ready (unsigned char const *);\n    int mask_ready (unsigned char const *);\n    int flags_ready (unsigned char const *);\n    int message_ready (unsigned char const *);\n\n    int size_ready (unsigned char const *);\n\n    unsigned char _tmpbuf[8];\n    unsigned char _msg_flags;\n    msg_t _in_progress;\n\n    const bool _zero_copy;\n    const int64_t _max_msg_size;\n    const bool _must_mask;\n    uint64_t _size;\n    zmq::ws_protocol_t::opcode_t _opcode;\n    unsigned char _mask[4];\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (ws_decoder_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ws_encoder.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"ws_protocol.hpp\"\n#include \"ws_encoder.hpp\"\n#include \"msg.hpp\"\n#include \"likely.hpp\"\n#include \"wire.hpp\"\n#include \"random.hpp\"\n\n#include <limits.h>\n\nzmq::ws_encoder_t::ws_encoder_t (size_t bufsize_, bool must_mask_) :\n    encoder_base_t<ws_encoder_t> (bufsize_), _must_mask (must_mask_)\n{\n    //  Write 0 bytes to the batch and go to message_ready state.\n    next_step (NULL, 0, &ws_encoder_t::message_ready, true);\n    _masked_msg.init ();\n}\n\nzmq::ws_encoder_t::~ws_encoder_t ()\n{\n    _masked_msg.close ();\n}\n\nvoid zmq::ws_encoder_t::message_ready ()\n{\n    int offset = 0;\n\n    _is_binary = false;\n\n    if (in_progress ()->is_ping ())\n        _tmp_buf[offset++] = 0x80 | zmq::ws_protocol_t::opcode_ping;\n    else if (in_progress ()->is_pong ())\n        _tmp_buf[offset++] = 0x80 | zmq::ws_protocol_t::opcode_pong;\n    else if (in_progress ()->is_close_cmd ())\n        _tmp_buf[offset++] = 0x80 | zmq::ws_protocol_t::opcode_close;\n    else {\n        _tmp_buf[offset++] = 0x82; // Final | binary\n        _is_binary = true;\n    }\n\n    _tmp_buf[offset] = _must_mask ? 0x80 : 0x00;\n\n    size_t size = in_progress ()->size ();\n    if (_is_binary)\n        size++;\n    //  TODO: create an opcode for subscribe/cancel\n    if (in_progress ()->is_subscribe () || in_progress ()->is_cancel ())\n        size++;\n\n    if (size <= 125)\n        _tmp_buf[offset++] |= static_cast<unsigned char> (size & 127);\n    else if (size <= 0xFFFF) {\n        _tmp_buf[offset++] |= 126;\n        _tmp_buf[offset++] = static_cast<unsigned char> ((size >> 8) & 0xFF);\n        _tmp_buf[offset++] = static_cast<unsigned char> (size & 0xFF);\n    } else {\n        _tmp_buf[offset++] |= 127;\n        put_uint64 (_tmp_buf + offset, size);\n        offset += 8;\n    }\n\n    if (_must_mask) {\n        const uint32_t random = generate_random ();\n        put_uint32 (_tmp_buf + offset, random);\n        put_uint32 (_mask, random);\n        offset += 4;\n    }\n\n    int mask_index = 0;\n    if (_is_binary) {\n        //  Encode flags.\n        unsigned char protocol_flags = 0;\n        if (in_progress ()->flags () & msg_t::more)\n            protocol_flags |= ws_protocol_t::more_flag;\n        if (in_progress ()->flags () & msg_t::command)\n            protocol_flags |= ws_protocol_t::command_flag;\n\n        _tmp_buf[offset++] =\n          _must_mask ? protocol_flags ^ _mask[mask_index++] : protocol_flags;\n    }\n\n    //  Encode the subscribe/cancel byte.\n    //  TODO: remove once there is an opcode for subscribe/cancel\n    if (in_progress ()->is_subscribe ())\n        _tmp_buf[offset++] = _must_mask ? 1 ^ _mask[mask_index++] : 1;\n    else if (in_progress ()->is_cancel ())\n        _tmp_buf[offset++] = _must_mask ? 0 ^ _mask[mask_index++] : 0;\n\n    next_step (_tmp_buf, offset, &ws_encoder_t::size_ready, false);\n}\n\nvoid zmq::ws_encoder_t::size_ready ()\n{\n    if (_must_mask) {\n        assert (in_progress () != &_masked_msg);\n        const size_t size = in_progress ()->size ();\n\n        unsigned char *src =\n          static_cast<unsigned char *> (in_progress ()->data ());\n        unsigned char *dest = src;\n\n        //  If msg is shared or data is constant we cannot mask in-place, allocate a new msg for it\n        if (in_progress ()->flags () & msg_t::shared\n            || in_progress ()->is_cmsg ()) {\n            _masked_msg.close ();\n            _masked_msg.init_size (size);\n            dest = static_cast<unsigned char *> (_masked_msg.data ());\n        }\n\n        int mask_index = 0;\n        if (_is_binary)\n            ++mask_index;\n        //  TODO: remove once there is an opcode for subscribe/cancel\n        if (in_progress ()->is_subscribe () || in_progress ()->is_cancel ())\n            ++mask_index;\n        for (size_t i = 0; i < size; ++i, mask_index++)\n            dest[i] = src[i] ^ _mask[mask_index % 4];\n\n        next_step (dest, size, &ws_encoder_t::message_ready, true);\n    } else {\n        next_step (in_progress ()->data (), in_progress ()->size (),\n                   &ws_encoder_t::message_ready, true);\n    }\n}\n"
  },
  {
    "path": "src/ws_encoder.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_WS_ENCODER_HPP_INCLUDED__\n#define __ZMQ_WS_ENCODER_HPP_INCLUDED__\n\n#include \"encoder.hpp\"\n\nnamespace zmq\n{\n//  Encoder for web socket framing protocol. Converts messages into data stream.\n\nclass ws_encoder_t ZMQ_FINAL : public encoder_base_t<ws_encoder_t>\n{\n  public:\n    ws_encoder_t (size_t bufsize_, bool must_mask_);\n    ~ws_encoder_t ();\n\n  private:\n    void size_ready ();\n    void message_ready ();\n\n    unsigned char _tmp_buf[16];\n    bool _must_mask;\n    unsigned char _mask[4];\n    msg_t _masked_msg;\n    bool _is_binary;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (ws_encoder_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ws_engine.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#ifdef ZMQ_USE_NSS\n#include <secoid.h>\n#include <sechash.h>\n#define SHA_DIGEST_LENGTH 20\n#elif defined ZMQ_USE_BUILTIN_SHA1\n#include \"../external/sha1/sha1.h\"\n#elif defined ZMQ_USE_GNUTLS\n#define SHA_DIGEST_LENGTH 20\n#include <gnutls/gnutls.h>\n#include <gnutls/crypto.h>\n#endif\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <sys/types.h>\n#include <unistd.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#ifdef ZMQ_HAVE_VXWORKS\n#include <sockLib.h>\n#endif\n#endif\n\n#include <cstring>\n\n#include \"compat.hpp\"\n#include \"tcp.hpp\"\n#include \"ws_engine.hpp\"\n#include \"session_base.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"random.hpp\"\n#include \"ws_decoder.hpp\"\n#include \"ws_encoder.hpp\"\n#include \"null_mechanism.hpp\"\n#include \"plain_server.hpp\"\n#include \"plain_client.hpp\"\n\n#ifdef ZMQ_HAVE_CURVE\n#include \"curve_client.hpp\"\n#include \"curve_server.hpp\"\n#endif\n\n//  OSX uses a different name for this socket option\n#ifndef IPV6_ADD_MEMBERSHIP\n#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP\n#endif\n\n#ifdef __APPLE__\n#include <TargetConditionals.h>\n#endif\n\nstatic int\nencode_base64 (const unsigned char *in_, int in_len_, char *out_, int out_len_);\n\nstatic void compute_accept_key (char *key_,\n                                unsigned char hash_[SHA_DIGEST_LENGTH]);\n\nzmq::ws_engine_t::ws_engine_t (fd_t fd_,\n                               const options_t &options_,\n                               const endpoint_uri_pair_t &endpoint_uri_pair_,\n                               const ws_address_t &address_,\n                               bool client_) :\n    stream_engine_base_t (fd_, options_, endpoint_uri_pair_, true),\n    _client (client_),\n    _address (address_),\n    _client_handshake_state (client_handshake_initial),\n    _server_handshake_state (handshake_initial),\n    _header_name_position (0),\n    _header_value_position (0),\n    _header_upgrade_websocket (false),\n    _header_connection_upgrade (false),\n    _heartbeat_timeout (0)\n{\n    memset (_websocket_key, 0, MAX_HEADER_VALUE_LENGTH + 1);\n    memset (_websocket_accept, 0, MAX_HEADER_VALUE_LENGTH + 1);\n    memset (_websocket_protocol, 0, 256);\n\n    _next_msg = &ws_engine_t::next_handshake_command;\n    _process_msg = &ws_engine_t::process_handshake_command;\n    _close_msg.init ();\n\n    if (_options.heartbeat_interval > 0) {\n        _heartbeat_timeout = _options.heartbeat_timeout;\n        if (_heartbeat_timeout == -1)\n            _heartbeat_timeout = _options.heartbeat_interval;\n    }\n}\n\nzmq::ws_engine_t::~ws_engine_t ()\n{\n    _close_msg.close ();\n}\n\nvoid zmq::ws_engine_t::start_ws_handshake ()\n{\n    if (_client) {\n        const char *protocol;\n        if (_options.mechanism == ZMQ_NULL)\n            protocol = \"ZWS2.0/NULL,ZWS2.0\";\n        else if (_options.mechanism == ZMQ_PLAIN)\n            protocol = \"ZWS2.0/PLAIN\";\n#ifdef ZMQ_HAVE_CURVE\n        else if (_options.mechanism == ZMQ_CURVE)\n            protocol = \"ZWS2.0/CURVE\";\n#endif\n        else {\n            // Avoid uninitialized variable error breaking UWP build\n            protocol = \"\";\n            assert (false);\n        }\n\n        unsigned char nonce[16];\n        int *p = reinterpret_cast<int *> (nonce);\n\n        // The nonce doesn't have to be secure one, it is just use to avoid proxy cache\n        *p = zmq::generate_random ();\n        *(p + 1) = zmq::generate_random ();\n        *(p + 2) = zmq::generate_random ();\n        *(p + 3) = zmq::generate_random ();\n\n        int size =\n          encode_base64 (nonce, 16, _websocket_key, MAX_HEADER_VALUE_LENGTH);\n        assert (size > 0);\n\n        size = snprintf (\n          reinterpret_cast<char *> (_write_buffer), WS_BUFFER_SIZE,\n          \"GET %s HTTP/1.1\\r\\n\"\n          \"Host: %s\\r\\n\"\n          \"Upgrade: websocket\\r\\n\"\n          \"Connection: Upgrade\\r\\n\"\n          \"Sec-WebSocket-Key: %s\\r\\n\"\n          \"Sec-WebSocket-Protocol: %s\\r\\n\"\n          \"Sec-WebSocket-Version: 13\\r\\n\\r\\n\",\n          _address.path (), _address.host (), _websocket_key, protocol);\n        assert (size > 0 && size < WS_BUFFER_SIZE);\n        _outpos = _write_buffer;\n        _outsize = size;\n        set_pollout ();\n    }\n}\n\nvoid zmq::ws_engine_t::plug_internal ()\n{\n    start_ws_handshake ();\n    set_pollin ();\n    in_event ();\n}\n\nint zmq::ws_engine_t::routing_id_msg (msg_t *msg_)\n{\n    const int rc = msg_->init_size (_options.routing_id_size);\n    errno_assert (rc == 0);\n    if (_options.routing_id_size > 0)\n        memcpy (msg_->data (), _options.routing_id, _options.routing_id_size);\n    _next_msg = &ws_engine_t::pull_msg_from_session;\n\n    return 0;\n}\n\nint zmq::ws_engine_t::process_routing_id_msg (msg_t *msg_)\n{\n    if (_options.recv_routing_id) {\n        msg_->set_flags (msg_t::routing_id);\n        const int rc = session ()->push_msg (msg_);\n        errno_assert (rc == 0);\n    } else {\n        int rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n    }\n\n    _process_msg = &ws_engine_t::push_msg_to_session;\n\n    return 0;\n}\n\nbool zmq::ws_engine_t::select_protocol (const char *protocol_)\n{\n    if (_options.mechanism == ZMQ_NULL && (strcmp (\"ZWS2.0\", protocol_) == 0)) {\n        _next_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n          &ws_engine_t::routing_id_msg);\n        _process_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n          &ws_engine_t::process_routing_id_msg);\n\n        // No mechanism in place, enabling heartbeat\n        if (_options.heartbeat_interval > 0 && !_has_heartbeat_timer) {\n            add_timer (_options.heartbeat_interval, heartbeat_ivl_timer_id);\n            _has_heartbeat_timer = true;\n        }\n\n        return true;\n    }\n    if (_options.mechanism == ZMQ_NULL\n        && strcmp (\"ZWS2.0/NULL\", protocol_) == 0) {\n        _mechanism = new (std::nothrow)\n          null_mechanism_t (session (), _peer_address, _options);\n        alloc_assert (_mechanism);\n        return true;\n    } else if (_options.mechanism == ZMQ_PLAIN\n               && strcmp (\"ZWS2.0/PLAIN\", protocol_) == 0) {\n        if (_options.as_server)\n            _mechanism = new (std::nothrow)\n              plain_server_t (session (), _peer_address, _options);\n        else\n            _mechanism =\n              new (std::nothrow) plain_client_t (session (), _options);\n        alloc_assert (_mechanism);\n        return true;\n    }\n#ifdef ZMQ_HAVE_CURVE\n    else if (_options.mechanism == ZMQ_CURVE\n             && strcmp (\"ZWS2.0/CURVE\", protocol_) == 0) {\n        if (_options.as_server)\n            _mechanism = new (std::nothrow)\n              curve_server_t (session (), _peer_address, _options, false);\n        else\n            _mechanism =\n              new (std::nothrow) curve_client_t (session (), _options, false);\n        alloc_assert (_mechanism);\n        return true;\n    }\n#endif\n\n    return false;\n}\n\nbool zmq::ws_engine_t::handshake ()\n{\n    bool complete;\n\n    if (_client)\n        complete = client_handshake ();\n    else\n        complete = server_handshake ();\n\n    if (complete) {\n        _encoder =\n          new (std::nothrow) ws_encoder_t (_options.out_batch_size, _client);\n        alloc_assert (_encoder);\n\n        _decoder = new (std::nothrow)\n          ws_decoder_t (_options.in_batch_size, _options.maxmsgsize,\n                        _options.zero_copy, !_client);\n        alloc_assert (_decoder);\n\n        socket ()->event_handshake_succeeded (_endpoint_uri_pair, 0);\n\n        set_pollout ();\n    }\n\n    return complete;\n}\n\nbool zmq::ws_engine_t::server_handshake ()\n{\n    const int nbytes = read (_read_buffer, WS_BUFFER_SIZE);\n    if (nbytes == -1) {\n        if (errno != EAGAIN)\n            error (zmq::i_engine::connection_error);\n        return false;\n    }\n\n    _inpos = _read_buffer;\n    _insize = nbytes;\n\n    while (_insize > 0) {\n        const char c = static_cast<char> (*_inpos);\n\n        switch (_server_handshake_state) {\n            case handshake_initial:\n                if (c == 'G')\n                    _server_handshake_state = request_line_G;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_G:\n                if (c == 'E')\n                    _server_handshake_state = request_line_GE;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_GE:\n                if (c == 'T')\n                    _server_handshake_state = request_line_GET;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_GET:\n                if (c == ' ')\n                    _server_handshake_state = request_line_GET_space;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_GET_space:\n                if (c == '\\r' || c == '\\n')\n                    _server_handshake_state = handshake_error;\n                // TODO: instead of check what is not allowed check what is allowed\n                if (c != ' ')\n                    _server_handshake_state = request_line_resource;\n                else\n                    _server_handshake_state = request_line_GET_space;\n                break;\n            case request_line_resource:\n                if (c == '\\r' || c == '\\n')\n                    _server_handshake_state = handshake_error;\n                else if (c == ' ')\n                    _server_handshake_state = request_line_resource_space;\n                else\n                    _server_handshake_state = request_line_resource;\n                break;\n            case request_line_resource_space:\n                if (c == 'H')\n                    _server_handshake_state = request_line_H;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_H:\n                if (c == 'T')\n                    _server_handshake_state = request_line_HT;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_HT:\n                if (c == 'T')\n                    _server_handshake_state = request_line_HTT;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_HTT:\n                if (c == 'P')\n                    _server_handshake_state = request_line_HTTP;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_HTTP:\n                if (c == '/')\n                    _server_handshake_state = request_line_HTTP_slash;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_HTTP_slash:\n                if (c == '1')\n                    _server_handshake_state = request_line_HTTP_slash_1;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_HTTP_slash_1:\n                if (c == '.')\n                    _server_handshake_state = request_line_HTTP_slash_1_dot;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_HTTP_slash_1_dot:\n                if (c == '1')\n                    _server_handshake_state = request_line_HTTP_slash_1_dot_1;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_HTTP_slash_1_dot_1:\n                if (c == '\\r')\n                    _server_handshake_state = request_line_cr;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case request_line_cr:\n                if (c == '\\n')\n                    _server_handshake_state = header_field_begin_name;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case header_field_begin_name:\n                switch (c) {\n                    case '\\r':\n                        _server_handshake_state = handshake_end_line_cr;\n                        break;\n                    case '\\n':\n                        _server_handshake_state = handshake_error;\n                        break;\n                    default:\n                        _header_name[0] = c;\n                        _header_name_position = 1;\n                        _server_handshake_state = header_field_name;\n                        break;\n                }\n                break;\n            case header_field_name:\n                if (c == '\\r' || c == '\\n')\n                    _server_handshake_state = handshake_error;\n                else if (c == ':') {\n                    _header_name[_header_name_position] = '\\0';\n                    _server_handshake_state = header_field_colon;\n                } else if (_header_name_position + 1 > MAX_HEADER_NAME_LENGTH)\n                    _server_handshake_state = handshake_error;\n                else {\n                    _header_name[_header_name_position] = c;\n                    _header_name_position++;\n                    _server_handshake_state = header_field_name;\n                }\n                break;\n            case header_field_colon:\n            case header_field_value_trailing_space:\n                if (c == '\\n')\n                    _server_handshake_state = handshake_error;\n                else if (c == '\\r')\n                    _server_handshake_state = header_field_cr;\n                else if (c == ' ')\n                    _server_handshake_state = header_field_value_trailing_space;\n                else {\n                    _header_value[0] = c;\n                    _header_value_position = 1;\n                    _server_handshake_state = header_field_value;\n                }\n                break;\n            case header_field_value:\n                if (c == '\\n')\n                    _server_handshake_state = handshake_error;\n                else if (c == '\\r') {\n                    _header_value[_header_value_position] = '\\0';\n\n                    if (strcasecmp (\"upgrade\", _header_name) == 0)\n                        _header_upgrade_websocket =\n                          strcasecmp (\"websocket\", _header_value) == 0;\n                    else if (strcasecmp (\"connection\", _header_name) == 0) {\n                        char *rest = NULL;\n                        char *element = strtok_r (_header_value, \",\", &rest);\n                        while (element != NULL) {\n                            while (*element == ' ')\n                                element++;\n                            if (strcasecmp (\"upgrade\", element) == 0) {\n                                _header_connection_upgrade = true;\n                                break;\n                            }\n                            element = strtok_r (NULL, \",\", &rest);\n                        }\n                    } else if (strcasecmp (\"Sec-WebSocket-Key\", _header_name)\n                               == 0)\n                        strcpy_s (_websocket_key, _header_value);\n                    else if (strcasecmp (\"Sec-WebSocket-Protocol\", _header_name)\n                             == 0) {\n                        // Currently only the ZWS2.0 is supported\n                        // Sec-WebSocket-Protocol can appear multiple times or be a comma separated list\n                        // if _websocket_protocol is already set we skip the check\n                        if (_websocket_protocol[0] == '\\0') {\n                            char *rest = NULL;\n                            char *p = strtok_r (_header_value, \",\", &rest);\n                            while (p != NULL) {\n                                if (*p == ' ')\n                                    p++;\n\n                                if (select_protocol (p)) {\n                                    strcpy_s (_websocket_protocol, p);\n                                    break;\n                                }\n\n                                p = strtok_r (NULL, \",\", &rest);\n                            }\n                        }\n                    }\n\n                    _server_handshake_state = header_field_cr;\n                } else if (_header_value_position + 1 > MAX_HEADER_VALUE_LENGTH)\n                    _server_handshake_state = handshake_error;\n                else {\n                    _header_value[_header_value_position] = c;\n                    _header_value_position++;\n                    _server_handshake_state = header_field_value;\n                }\n                break;\n            case header_field_cr:\n                if (c == '\\n')\n                    _server_handshake_state = header_field_begin_name;\n                else\n                    _server_handshake_state = handshake_error;\n                break;\n            case handshake_end_line_cr:\n                if (c == '\\n') {\n                    if (_header_connection_upgrade && _header_upgrade_websocket\n                        && _websocket_protocol[0] != '\\0'\n                        && _websocket_key[0] != '\\0') {\n                        _server_handshake_state = handshake_complete;\n\n                        unsigned char hash[SHA_DIGEST_LENGTH];\n                        compute_accept_key (_websocket_key, hash);\n\n                        const int accept_key_len = encode_base64 (\n                          hash, SHA_DIGEST_LENGTH, _websocket_accept,\n                          MAX_HEADER_VALUE_LENGTH);\n                        assert (accept_key_len > 0);\n                        _websocket_accept[accept_key_len] = '\\0';\n\n                        const int written =\n                          snprintf (reinterpret_cast<char *> (_write_buffer),\n                                    WS_BUFFER_SIZE,\n                                    \"HTTP/1.1 101 Switching Protocols\\r\\n\"\n                                    \"Upgrade: websocket\\r\\n\"\n                                    \"Connection: Upgrade\\r\\n\"\n                                    \"Sec-WebSocket-Accept: %s\\r\\n\"\n                                    \"Sec-WebSocket-Protocol: %s\\r\\n\"\n                                    \"\\r\\n\",\n                                    _websocket_accept, _websocket_protocol);\n                        assert (written >= 0 && written < WS_BUFFER_SIZE);\n                        _outpos = _write_buffer;\n                        _outsize = written;\n\n                        _inpos++;\n                        _insize--;\n\n                        return true;\n                    }\n                    _server_handshake_state = handshake_error;\n                } else\n                    _server_handshake_state = handshake_error;\n                break;\n            default:\n                assert (false);\n        }\n\n        _inpos++;\n        _insize--;\n\n        if (_server_handshake_state == handshake_error) {\n            // TODO: send bad request\n\n            socket ()->event_handshake_failed_protocol (\n              _endpoint_uri_pair, ZMQ_PROTOCOL_ERROR_WS_UNSPECIFIED);\n\n            error (zmq::i_engine::protocol_error);\n            return false;\n        }\n    }\n    return false;\n}\n\nbool zmq::ws_engine_t::client_handshake ()\n{\n    const int nbytes = read (_read_buffer, WS_BUFFER_SIZE);\n    if (nbytes == -1) {\n        if (errno != EAGAIN)\n            error (zmq::i_engine::connection_error);\n        return false;\n    }\n\n    _inpos = _read_buffer;\n    _insize = nbytes;\n\n    while (_insize > 0) {\n        const char c = static_cast<char> (*_inpos);\n\n        switch (_client_handshake_state) {\n            case client_handshake_initial:\n                if (c == 'H')\n                    _client_handshake_state = response_line_H;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_H:\n                if (c == 'T')\n                    _client_handshake_state = response_line_HT;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_HT:\n                if (c == 'T')\n                    _client_handshake_state = response_line_HTT;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_HTT:\n                if (c == 'P')\n                    _client_handshake_state = response_line_HTTP;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_HTTP:\n                if (c == '/')\n                    _client_handshake_state = response_line_HTTP_slash;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_HTTP_slash:\n                if (c == '1')\n                    _client_handshake_state = response_line_HTTP_slash_1;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_HTTP_slash_1:\n                if (c == '.')\n                    _client_handshake_state = response_line_HTTP_slash_1_dot;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_HTTP_slash_1_dot:\n                if (c == '1')\n                    _client_handshake_state = response_line_HTTP_slash_1_dot_1;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_HTTP_slash_1_dot_1:\n                if (c == ' ')\n                    _client_handshake_state =\n                      response_line_HTTP_slash_1_dot_1_space;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_HTTP_slash_1_dot_1_space:\n                if (c == ' ')\n                    _client_handshake_state =\n                      response_line_HTTP_slash_1_dot_1_space;\n                else if (c == '1')\n                    _client_handshake_state = response_line_status_1;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_status_1:\n                if (c == '0')\n                    _client_handshake_state = response_line_status_10;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_status_10:\n                if (c == '1')\n                    _client_handshake_state = response_line_status_101;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_status_101:\n                if (c == ' ')\n                    _client_handshake_state = response_line_status_101_space;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_status_101_space:\n                if (c == ' ')\n                    _client_handshake_state = response_line_status_101_space;\n                else if (c == 'S')\n                    _client_handshake_state = response_line_s;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_s:\n                if (c == 'w')\n                    _client_handshake_state = response_line_sw;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_sw:\n                if (c == 'i')\n                    _client_handshake_state = response_line_swi;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_swi:\n                if (c == 't')\n                    _client_handshake_state = response_line_swit;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_swit:\n                if (c == 'c')\n                    _client_handshake_state = response_line_switc;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_switc:\n                if (c == 'h')\n                    _client_handshake_state = response_line_switch;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_switch:\n                if (c == 'i')\n                    _client_handshake_state = response_line_switchi;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_switchi:\n                if (c == 'n')\n                    _client_handshake_state = response_line_switchin;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_switchin:\n                if (c == 'g')\n                    _client_handshake_state = response_line_switching;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_switching:\n                if (c == ' ')\n                    _client_handshake_state = response_line_switching_space;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_switching_space:\n                if (c == 'P')\n                    _client_handshake_state = response_line_p;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_p:\n                if (c == 'r')\n                    _client_handshake_state = response_line_pr;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_pr:\n                if (c == 'o')\n                    _client_handshake_state = response_line_pro;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_pro:\n                if (c == 't')\n                    _client_handshake_state = response_line_prot;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_prot:\n                if (c == 'o')\n                    _client_handshake_state = response_line_proto;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_proto:\n                if (c == 'c')\n                    _client_handshake_state = response_line_protoc;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_protoc:\n                if (c == 'o')\n                    _client_handshake_state = response_line_protoco;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_protoco:\n                if (c == 'l')\n                    _client_handshake_state = response_line_protocol;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_protocol:\n                if (c == 's')\n                    _client_handshake_state = response_line_protocols;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_protocols:\n                if (c == '\\r')\n                    _client_handshake_state = response_line_cr;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case response_line_cr:\n                if (c == '\\n')\n                    _client_handshake_state = client_header_field_begin_name;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case client_header_field_begin_name:\n                switch (c) {\n                    case '\\r':\n                        _client_handshake_state = client_handshake_end_line_cr;\n                        break;\n                    case '\\n':\n                        _client_handshake_state = client_handshake_error;\n                        break;\n                    default:\n                        _header_name[0] = c;\n                        _header_name_position = 1;\n                        _client_handshake_state = client_header_field_name;\n                        break;\n                }\n                break;\n            case client_header_field_name:\n                if (c == '\\r' || c == '\\n')\n                    _client_handshake_state = client_handshake_error;\n                else if (c == ':') {\n                    _header_name[_header_name_position] = '\\0';\n                    _client_handshake_state = client_header_field_colon;\n                } else if (_header_name_position + 1 > MAX_HEADER_NAME_LENGTH)\n                    _client_handshake_state = client_handshake_error;\n                else {\n                    _header_name[_header_name_position] = c;\n                    _header_name_position++;\n                    _client_handshake_state = client_header_field_name;\n                }\n                break;\n            case client_header_field_colon:\n            case client_header_field_value_trailing_space:\n                if (c == '\\n')\n                    _client_handshake_state = client_handshake_error;\n                else if (c == '\\r')\n                    _client_handshake_state = client_header_field_cr;\n                else if (c == ' ')\n                    _client_handshake_state =\n                      client_header_field_value_trailing_space;\n                else {\n                    _header_value[0] = c;\n                    _header_value_position = 1;\n                    _client_handshake_state = client_header_field_value;\n                }\n                break;\n            case client_header_field_value:\n                if (c == '\\n')\n                    _client_handshake_state = client_handshake_error;\n                else if (c == '\\r') {\n                    _header_value[_header_value_position] = '\\0';\n\n                    if (strcasecmp (\"upgrade\", _header_name) == 0)\n                        _header_upgrade_websocket =\n                          strcasecmp (\"websocket\", _header_value) == 0;\n                    else if (strcasecmp (\"connection\", _header_name) == 0)\n                        _header_connection_upgrade =\n                          strcasecmp (\"upgrade\", _header_value) == 0;\n                    else if (strcasecmp (\"Sec-WebSocket-Accept\", _header_name)\n                             == 0)\n                        strcpy_s (_websocket_accept, _header_value);\n                    else if (strcasecmp (\"Sec-WebSocket-Protocol\", _header_name)\n                             == 0) {\n                        if (_mechanism) {\n                            _client_handshake_state = client_handshake_error;\n                            break;\n                        }\n                        if (select_protocol (_header_value))\n                            strcpy_s (_websocket_protocol, _header_value);\n                    }\n                    _client_handshake_state = client_header_field_cr;\n                } else if (_header_value_position + 1 > MAX_HEADER_VALUE_LENGTH)\n                    _client_handshake_state = client_handshake_error;\n                else {\n                    _header_value[_header_value_position] = c;\n                    _header_value_position++;\n                    _client_handshake_state = client_header_field_value;\n                }\n                break;\n            case client_header_field_cr:\n                if (c == '\\n')\n                    _client_handshake_state = client_header_field_begin_name;\n                else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            case client_handshake_end_line_cr:\n                if (c == '\\n') {\n                    if (_header_connection_upgrade && _header_upgrade_websocket\n                        && _websocket_protocol[0] != '\\0'\n                        && _websocket_accept[0] != '\\0') {\n                        _client_handshake_state = client_handshake_complete;\n\n                        // TODO: validate accept key\n\n                        _inpos++;\n                        _insize--;\n\n                        return true;\n                    }\n                    _client_handshake_state = client_handshake_error;\n                } else\n                    _client_handshake_state = client_handshake_error;\n                break;\n            default:\n                assert (false);\n        }\n\n        _inpos++;\n        _insize--;\n\n        if (_client_handshake_state == client_handshake_error) {\n            socket ()->event_handshake_failed_protocol (\n              _endpoint_uri_pair, ZMQ_PROTOCOL_ERROR_WS_UNSPECIFIED);\n\n            error (zmq::i_engine::protocol_error);\n            return false;\n        }\n    }\n\n    return false;\n}\n\nint zmq::ws_engine_t::decode_and_push (msg_t *msg_)\n{\n    zmq_assert (_mechanism != NULL);\n\n    //  with WS engine, ping and pong commands are control messages and should not go through any mechanism\n    if (msg_->is_ping () || msg_->is_pong () || msg_->is_close_cmd ()) {\n        if (process_command_message (msg_) == -1)\n            return -1;\n    } else if (_mechanism->decode (msg_) == -1)\n        return -1;\n\n    if (_has_timeout_timer) {\n        _has_timeout_timer = false;\n        cancel_timer (heartbeat_timeout_timer_id);\n    }\n\n    if (msg_->flags () & msg_t::command && !msg_->is_ping ()\n        && !msg_->is_pong () && !msg_->is_close_cmd ())\n        process_command_message (msg_);\n\n    if (_metadata)\n        msg_->set_metadata (_metadata);\n    if (session ()->push_msg (msg_) == -1) {\n        if (errno == EAGAIN)\n            _process_msg = &ws_engine_t::push_one_then_decode_and_push;\n        return -1;\n    }\n    return 0;\n}\n\nint zmq::ws_engine_t::produce_close_message (msg_t *msg_)\n{\n    int rc = msg_->move (_close_msg);\n    errno_assert (rc == 0);\n\n    _next_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n      &ws_engine_t::produce_no_msg_after_close);\n\n    return rc;\n}\n\nint zmq::ws_engine_t::produce_no_msg_after_close (msg_t *msg_)\n{\n    LIBZMQ_UNUSED (msg_);\n    _next_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n      &ws_engine_t::close_connection_after_close);\n\n    errno = EAGAIN;\n    return -1;\n}\n\nint zmq::ws_engine_t::close_connection_after_close (msg_t *msg_)\n{\n    LIBZMQ_UNUSED (msg_);\n    error (connection_error);\n    errno = ECONNRESET;\n    return -1;\n}\n\nint zmq::ws_engine_t::produce_ping_message (msg_t *msg_)\n{\n    int rc = msg_->init ();\n    errno_assert (rc == 0);\n    msg_->set_flags (msg_t::command | msg_t::ping);\n\n    _next_msg = &ws_engine_t::pull_and_encode;\n    if (!_has_timeout_timer && _heartbeat_timeout > 0) {\n        add_timer (_heartbeat_timeout, heartbeat_timeout_timer_id);\n        _has_timeout_timer = true;\n    }\n\n    return rc;\n}\n\n\nint zmq::ws_engine_t::produce_pong_message (msg_t *msg_)\n{\n    int rc = msg_->init ();\n    errno_assert (rc == 0);\n    msg_->set_flags (msg_t::command | msg_t::pong);\n\n    _next_msg = &ws_engine_t::pull_and_encode;\n    return rc;\n}\n\n\nint zmq::ws_engine_t::process_command_message (msg_t *msg_)\n{\n    if (msg_->is_ping ()) {\n        _next_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n          &ws_engine_t::produce_pong_message);\n        out_event ();\n    } else if (msg_->is_close_cmd ()) {\n        int rc = _close_msg.copy (*msg_);\n        errno_assert (rc == 0);\n        _next_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n          &ws_engine_t::produce_close_message);\n        out_event ();\n    }\n\n    return 0;\n}\n\nstatic int\nencode_base64 (const unsigned char *in_, int in_len_, char *out_, int out_len_)\n{\n    static const unsigned char base64enc_tab[65] =\n      \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\n    int io = 0;\n    uint32_t v = 0;\n    int rem = 0;\n\n    for (int ii = 0; ii < in_len_; ii++) {\n        unsigned char ch;\n        ch = in_[ii];\n        v = (v << 8) | ch;\n        rem += 8;\n        while (rem >= 6) {\n            rem -= 6;\n            if (io >= out_len_)\n                return -1; /* truncation is failure */\n            out_[io++] = base64enc_tab[(v >> rem) & 63];\n        }\n    }\n    if (rem) {\n        v <<= (6 - rem);\n        if (io >= out_len_)\n            return -1; /* truncation is failure */\n        out_[io++] = base64enc_tab[v & 63];\n    }\n    while (io & 3) {\n        if (io >= out_len_)\n            return -1; /* truncation is failure */\n        out_[io++] = '=';\n    }\n    if (io >= out_len_)\n        return -1; /* no room for null terminator */\n    out_[io] = 0;\n    return io;\n}\n\nstatic void compute_accept_key (char *key_, unsigned char *hash_)\n{\n    const char *magic_string = \"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\";\n#ifdef ZMQ_USE_NSS\n    unsigned int len;\n    HASH_HashType type = HASH_GetHashTypeByOidTag (SEC_OID_SHA1);\n    HASHContext *ctx = HASH_Create (type);\n    assert (ctx);\n\n    HASH_Begin (ctx);\n    HASH_Update (ctx, (unsigned char *) key_, (unsigned int) strlen (key_));\n    HASH_Update (ctx, (unsigned char *) magic_string,\n                 (unsigned int) strlen (magic_string));\n    HASH_End (ctx, hash_, &len, SHA_DIGEST_LENGTH);\n    HASH_Destroy (ctx);\n#elif defined ZMQ_USE_BUILTIN_SHA1\n    sha1_ctxt ctx;\n    SHA1_Init (&ctx);\n    SHA1_Update (&ctx, (unsigned char *) key_, strlen (key_));\n    SHA1_Update (&ctx, (unsigned char *) magic_string, strlen (magic_string));\n\n    SHA1_Final (hash_, &ctx);\n#elif defined ZMQ_USE_GNUTLS\n    gnutls_hash_hd_t hd;\n    gnutls_hash_init (&hd, GNUTLS_DIG_SHA1);\n    gnutls_hash (hd, key_, strlen (key_));\n    gnutls_hash (hd, magic_string, strlen (magic_string));\n    gnutls_hash_deinit (hd, hash_);\n#else\n#error \"No sha1 implementation set\"\n#endif\n}\n"
  },
  {
    "path": "src/ws_engine.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_WS_ENGINE_HPP_INCLUDED__\n#define __ZMQ_WS_ENGINE_HPP_INCLUDED__\n\n#include \"io_object.hpp\"\n#include \"address.hpp\"\n#include \"msg.hpp\"\n#include \"stream_engine_base.hpp\"\n#include \"ws_address.hpp\"\n\n#define WS_BUFFER_SIZE 8192\n#define MAX_HEADER_NAME_LENGTH 1024\n#define MAX_HEADER_VALUE_LENGTH 2048\n\nnamespace zmq\n{\nclass io_thread_t;\nclass session_base_t;\n\ntypedef enum\n{\n    handshake_initial = 0,\n    request_line_G,\n    request_line_GE,\n    request_line_GET,\n    request_line_GET_space,\n    request_line_resource,\n    request_line_resource_space,\n    request_line_H,\n    request_line_HT,\n    request_line_HTT,\n    request_line_HTTP,\n    request_line_HTTP_slash,\n    request_line_HTTP_slash_1,\n    request_line_HTTP_slash_1_dot,\n    request_line_HTTP_slash_1_dot_1,\n    request_line_cr,\n    header_field_begin_name,\n    header_field_name,\n    header_field_colon,\n    header_field_value_trailing_space,\n    header_field_value,\n    header_field_cr,\n    handshake_end_line_cr,\n    handshake_complete,\n\n    handshake_error = -1\n} ws_server_handshake_state_t;\n\n\ntypedef enum\n{\n    client_handshake_initial = 0,\n    response_line_H,\n    response_line_HT,\n    response_line_HTT,\n    response_line_HTTP,\n    response_line_HTTP_slash,\n    response_line_HTTP_slash_1,\n    response_line_HTTP_slash_1_dot,\n    response_line_HTTP_slash_1_dot_1,\n    response_line_HTTP_slash_1_dot_1_space,\n    response_line_status_1,\n    response_line_status_10,\n    response_line_status_101,\n    response_line_status_101_space,\n    response_line_s,\n    response_line_sw,\n    response_line_swi,\n    response_line_swit,\n    response_line_switc,\n    response_line_switch,\n    response_line_switchi,\n    response_line_switchin,\n    response_line_switching,\n    response_line_switching_space,\n    response_line_p,\n    response_line_pr,\n    response_line_pro,\n    response_line_prot,\n    response_line_proto,\n    response_line_protoc,\n    response_line_protoco,\n    response_line_protocol,\n    response_line_protocols,\n    response_line_cr,\n    client_header_field_begin_name,\n    client_header_field_name,\n    client_header_field_colon,\n    client_header_field_value_trailing_space,\n    client_header_field_value,\n    client_header_field_cr,\n    client_handshake_end_line_cr,\n    client_handshake_complete,\n\n    client_handshake_error = -1\n} ws_client_handshake_state_t;\n\nclass ws_engine_t : public stream_engine_base_t\n{\n  public:\n    ws_engine_t (fd_t fd_,\n                 const options_t &options_,\n                 const endpoint_uri_pair_t &endpoint_uri_pair_,\n                 const ws_address_t &address_,\n                 bool client_);\n    ~ws_engine_t ();\n\n  protected:\n    int decode_and_push (msg_t *msg_);\n    int process_command_message (msg_t *msg_);\n    int produce_pong_message (msg_t *msg_);\n    int produce_ping_message (msg_t *msg_);\n    bool handshake ();\n    void plug_internal ();\n    void start_ws_handshake ();\n\n  private:\n    int routing_id_msg (msg_t *msg_);\n    int process_routing_id_msg (msg_t *msg_);\n    int produce_close_message (msg_t *msg_);\n    int produce_no_msg_after_close (msg_t *msg_);\n    int close_connection_after_close (msg_t *msg_);\n\n    bool select_protocol (const char *protocol);\n\n    bool client_handshake ();\n    bool server_handshake ();\n\n    bool _client;\n    ws_address_t _address;\n\n    ws_client_handshake_state_t _client_handshake_state;\n    ws_server_handshake_state_t _server_handshake_state;\n\n    unsigned char _read_buffer[WS_BUFFER_SIZE];\n    unsigned char _write_buffer[WS_BUFFER_SIZE];\n    char _header_name[MAX_HEADER_NAME_LENGTH + 1];\n    int _header_name_position;\n    char _header_value[MAX_HEADER_VALUE_LENGTH + 1];\n    int _header_value_position;\n\n    bool _header_upgrade_websocket;\n    bool _header_connection_upgrade;\n    char _websocket_protocol[256];\n    char _websocket_key[MAX_HEADER_VALUE_LENGTH + 1];\n    char _websocket_accept[MAX_HEADER_VALUE_LENGTH + 1];\n\n    int _heartbeat_timeout;\n    msg_t _close_msg;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ws_listener.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <new>\n\n#include <string>\n#include <stdio.h>\n\n#include \"ws_listener.hpp\"\n#include \"io_thread.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"tcp.hpp\"\n#include \"socket_base.hpp\"\n#include \"address.hpp\"\n#include \"ws_engine.hpp\"\n#include \"session_base.hpp\"\n\n#ifdef ZMQ_HAVE_WSS\n#include \"wss_engine.hpp\"\n#include \"wss_address.hpp\"\n#endif\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#include <sys/socket.h>\n#include <arpa/inet.h>\n#include <netinet/tcp.h>\n#include <netinet/in.h>\n#include <netdb.h>\n#include <fcntl.h>\n#ifdef ZMQ_HAVE_VXWORKS\n#include <sockLib.h>\n#endif\n#endif\n\n#ifdef ZMQ_HAVE_OPENVMS\n#include <ioctl.h>\n#endif\n\nzmq::ws_listener_t::ws_listener_t (io_thread_t *io_thread_,\n                                   socket_base_t *socket_,\n                                   const options_t &options_,\n                                   bool wss_) :\n    stream_listener_base_t (io_thread_, socket_, options_), _wss (wss_)\n{\n#ifdef ZMQ_HAVE_WSS\n    if (_wss) {\n        int rc = gnutls_certificate_allocate_credentials (&_tls_cred);\n        zmq_assert (rc == GNUTLS_E_SUCCESS);\n\n        gnutls_datum_t cert = {(unsigned char *) options_.wss_cert_pem.c_str (),\n                               (unsigned int) options_.wss_cert_pem.length ()};\n        gnutls_datum_t key = {(unsigned char *) options_.wss_key_pem.c_str (),\n                              (unsigned int) options_.wss_key_pem.length ()};\n        rc = gnutls_certificate_set_x509_key_mem (_tls_cred, &cert, &key,\n                                                  GNUTLS_X509_FMT_PEM);\n        zmq_assert (rc == GNUTLS_E_SUCCESS);\n    }\n#endif\n}\n\nzmq::ws_listener_t::~ws_listener_t ()\n{\n#ifdef ZMQ_HAVE_WSS\n    if (_wss)\n        gnutls_certificate_free_credentials (_tls_cred);\n#endif\n}\n\nvoid zmq::ws_listener_t::in_event ()\n{\n    const fd_t fd = accept ();\n\n    //  If connection was reset by the peer in the meantime, just ignore it.\n    //  TODO: Handle specific errors like ENFILE/EMFILE etc.\n    if (fd == retired_fd) {\n        _socket->event_accept_failed (\n          make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());\n        return;\n    }\n\n    int rc = tune_tcp_socket (fd);\n    rc = rc | tune_tcp_maxrt (fd, options.tcp_maxrt);\n    if (rc != 0) {\n        _socket->event_accept_failed (\n          make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());\n        return;\n    }\n\n    //  Create the engine object for this connection.\n    create_engine (fd);\n}\n\nstd::string zmq::ws_listener_t::get_socket_name (zmq::fd_t fd_,\n                                                 socket_end_t socket_end_) const\n{\n    std::string socket_name;\n\n#ifdef ZMQ_HAVE_WSS\n    if (_wss)\n        socket_name = zmq::get_socket_name<wss_address_t> (fd_, socket_end_);\n    else\n#endif\n        socket_name = zmq::get_socket_name<ws_address_t> (fd_, socket_end_);\n\n    return socket_name + _address.path ();\n}\n\nint zmq::ws_listener_t::create_socket (const char *addr_)\n{\n    tcp_address_t address;\n    _s = tcp_open_socket (addr_, options, true, true, &address);\n    if (_s == retired_fd) {\n        return -1;\n    }\n\n    //  TODO why is this only done for the listener?\n    make_socket_noninheritable (_s);\n\n    //  Allow reusing of the address.\n    int flag = 1;\n    int rc;\n#ifdef ZMQ_HAVE_WINDOWS\n    //  TODO this was changed for Windows from SO_REUSEADDRE to\n    //  SE_EXCLUSIVEADDRUSE by 0ab65324195ad70205514d465b03d851a6de051c,\n    //  so the comment above is no longer correct; also, now the settings are\n    //  different between listener and connecter with a src address.\n    //  is this intentional?\n    rc = setsockopt (_s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,\n                     reinterpret_cast<const char *> (&flag), sizeof (int));\n    wsa_assert (rc != SOCKET_ERROR);\n#elif defined ZMQ_HAVE_VXWORKS\n    rc =\n      setsockopt (_s, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof (int));\n    errno_assert (rc == 0);\n#else\n    rc = setsockopt (_s, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int));\n    errno_assert (rc == 0);\n#endif\n\n    //  Bind the socket to the network interface and port.\n#if defined ZMQ_HAVE_VXWORKS\n    rc = bind (_s, (sockaddr *) _address.addr (), _address.addrlen ());\n#else\n    rc = bind (_s, address.addr (), address.addrlen ());\n#endif\n#ifdef ZMQ_HAVE_WINDOWS\n    if (rc == SOCKET_ERROR) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        goto error;\n    }\n#else\n    if (rc != 0)\n        goto error;\n#endif\n\n    //  Listen for incoming connections.\n    rc = listen (_s, options.backlog);\n#ifdef ZMQ_HAVE_WINDOWS\n    if (rc == SOCKET_ERROR) {\n        errno = wsa_error_to_errno (WSAGetLastError ());\n        goto error;\n    }\n#else\n    if (rc != 0)\n        goto error;\n#endif\n\n    return 0;\n\nerror:\n    const int err = errno;\n    close ();\n    errno = err;\n    return -1;\n}\n\nint zmq::ws_listener_t::set_local_address (const char *addr_)\n{\n    if (options.use_fd != -1) {\n        //  in this case, the addr_ passed is not used and ignored, since the\n        //  socket was already created by the application\n        _s = options.use_fd;\n    } else {\n        const int rc = _address.resolve (addr_, true, options.ipv6);\n        if (rc != 0)\n            return -1;\n\n        //  remove the path, otherwise resolving the port will fail with wildcard\n        const char *delim = strrchr (addr_, '/');\n        std::string host_address;\n        if (delim) {\n            host_address = std::string (addr_, delim - addr_);\n        } else {\n            host_address = addr_;\n        }\n\n        if (create_socket (host_address.c_str ()) == -1)\n            return -1;\n    }\n\n    _endpoint = get_socket_name (_s, socket_end_local);\n\n    _socket->event_listening (make_unconnected_bind_endpoint_pair (_endpoint),\n                              _s);\n    return 0;\n}\n\nzmq::fd_t zmq::ws_listener_t::accept ()\n{\n    //  The situation where connection cannot be accepted due to insufficient\n    //  resources is considered valid and treated by ignoring the connection.\n    //  Accept one connection and deal with different failure modes.\n    zmq_assert (_s != retired_fd);\n\n    struct sockaddr_storage ss;\n    memset (&ss, 0, sizeof (ss));\n#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS\n    int ss_len = sizeof (ss);\n#else\n    socklen_t ss_len = sizeof (ss);\n#endif\n#if defined ZMQ_HAVE_SOCK_CLOEXEC && defined HAVE_ACCEPT4\n    fd_t sock = ::accept4 (_s, reinterpret_cast<struct sockaddr *> (&ss),\n                           &ss_len, SOCK_CLOEXEC);\n#else\n    const fd_t sock =\n      ::accept (_s, reinterpret_cast<struct sockaddr *> (&ss), &ss_len);\n#endif\n\n    if (sock == retired_fd) {\n#if defined ZMQ_HAVE_WINDOWS\n        const int last_error = WSAGetLastError ();\n        wsa_assert (last_error == WSAEWOULDBLOCK || last_error == WSAECONNRESET\n                    || last_error == WSAEMFILE || last_error == WSAENOBUFS);\n#elif defined ZMQ_HAVE_ANDROID\n        errno_assert (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR\n                      || errno == ECONNABORTED || errno == EPROTO\n                      || errno == ENOBUFS || errno == ENOMEM || errno == EMFILE\n                      || errno == ENFILE || errno == EINVAL);\n#else\n        errno_assert (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR\n                      || errno == ECONNABORTED || errno == EPROTO\n                      || errno == ENOBUFS || errno == ENOMEM || errno == EMFILE\n                      || errno == ENFILE);\n#endif\n        return retired_fd;\n    }\n\n    make_socket_noninheritable (sock);\n\n    if (zmq::set_nosigpipe (sock)) {\n#ifdef ZMQ_HAVE_WINDOWS\n        const int rc = closesocket (sock);\n        wsa_assert (rc != SOCKET_ERROR);\n#else\n        int rc = ::close (sock);\n        errno_assert (rc == 0);\n#endif\n        return retired_fd;\n    }\n\n    // Set the IP Type-Of-Service priority for this client socket\n    if (options.tos != 0)\n        set_ip_type_of_service (sock, options.tos);\n\n    // Set the protocol-defined priority for this client socket\n    if (options.priority != 0)\n        set_socket_priority (sock, options.priority);\n\n    return sock;\n}\n\nvoid zmq::ws_listener_t::create_engine (fd_t fd_)\n{\n    const endpoint_uri_pair_t endpoint_pair (\n      get_socket_name (fd_, socket_end_local),\n      get_socket_name (fd_, socket_end_remote), endpoint_type_bind);\n\n    i_engine *engine = NULL;\n    if (_wss)\n#ifdef ZMQ_HAVE_WSS\n        engine = new (std::nothrow)\n          wss_engine_t (fd_, options, endpoint_pair, _address, false, _tls_cred,\n                        std::string ());\n#else\n        zmq_assert (false);\n#endif\n    else\n        engine = new (std::nothrow)\n          ws_engine_t (fd_, options, endpoint_pair, _address, false);\n\n    alloc_assert (engine);\n\n    //  Choose I/O thread to run connecter in. Given that we are already\n    //  running in an I/O thread, there must be at least one available.\n    io_thread_t *io_thread = choose_io_thread (options.affinity);\n    zmq_assert (io_thread);\n\n    //  Create and launch a session object.\n    session_base_t *session =\n      session_base_t::create (io_thread, false, _socket, options, NULL);\n    errno_assert (session);\n    session->inc_seqnum ();\n    launch_child (session);\n    send_attach (session, engine, false);\n\n    _socket->event_accepted (endpoint_pair, fd_);\n}\n"
  },
  {
    "path": "src/ws_listener.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_WS_LISTENER_HPP_INCLUDED__\n#define __ZMQ_WS_LISTENER_HPP_INCLUDED__\n\n#include \"fd.hpp\"\n#include \"ws_address.hpp\"\n#include \"stream_listener_base.hpp\"\n\n#ifdef ZMQ_USE_GNUTLS\n#include <gnutls/gnutls.h>\n#endif\n\nnamespace zmq\n{\nclass ws_listener_t ZMQ_FINAL : public stream_listener_base_t\n{\n  public:\n    ws_listener_t (zmq::io_thread_t *io_thread_,\n                   zmq::socket_base_t *socket_,\n                   const options_t &options_,\n                   bool wss_);\n\n    ~ws_listener_t ();\n\n    //  Set address to listen on.\n    int set_local_address (const char *addr_);\n\n  protected:\n    std::string get_socket_name (fd_t fd_, socket_end_t socket_end_) const;\n    void create_engine (fd_t fd);\n\n  private:\n    //  Handlers for I/O events.\n    void in_event ();\n\n    //  Accept the new connection. Returns the file descriptor of the\n    //  newly created connection. The function may return retired_fd\n    //  if the connection was dropped while waiting in the listen backlog\n    //  or was denied because of accept filters.\n    fd_t accept ();\n\n    int create_socket (const char *addr_);\n\n    //  Address to listen on.\n    ws_address_t _address;\n\n    bool _wss;\n#ifdef ZMQ_HAVE_WSS\n    gnutls_certificate_credentials_t _tls_cred;\n#endif\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (ws_listener_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ws_protocol.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_WS_PROTOCOL_HPP_INCLUDED__\n#define __ZMQ_WS_PROTOCOL_HPP_INCLUDED__\n\nnamespace zmq\n{\n//  Definition of constants for WS transport protocol.\nclass ws_protocol_t\n{\n  public:\n    //  Message flags.\n    enum opcode_t\n    {\n        opcode_continuation = 0,\n        opcode_text = 0x01,\n        opcode_binary = 0x02,\n        opcode_close = 0x08,\n        opcode_ping = 0x09,\n        opcode_pong = 0xA\n    };\n\n    enum\n    {\n        more_flag = 1,\n        command_flag = 2\n    };\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/wss_address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string>\n#include <sstream>\n\n#include \"wss_address.hpp\"\n\nzmq::wss_address_t::wss_address_t () : ws_address_t ()\n{\n}\n\nzmq::wss_address_t::wss_address_t (const sockaddr *sa_, socklen_t sa_len_) :\n    ws_address_t (sa_, sa_len_)\n{\n}\n\nint zmq::wss_address_t::to_string (std::string &addr_) const\n{\n    std::ostringstream os;\n    os << std::string (\"wss://\") << host () << std::string (\":\")\n       << _address.port () << path ();\n    addr_ = os.str ();\n\n    return 0;\n}\n"
  },
  {
    "path": "src/wss_address.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_WSS_ADDRESS_HPP_INCLUDED__\n#define __ZMQ_WSS_ADDRESS_HPP_INCLUDED__\n\n#include \"ws_address.hpp\"\n\nnamespace zmq\n{\nclass wss_address_t : public ws_address_t\n{\n  public:\n    wss_address_t ();\n    wss_address_t (const sockaddr *sa_, socklen_t sa_len_);\n    //  The opposite to resolve()\n    int to_string (std::string &addr_) const;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/wss_engine.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"wss_engine.hpp\"\n\nstatic int verify_certificate_callback (gnutls_session_t session)\n{\n    unsigned int status;\n    const char *hostname;\n\n    // read hostname\n    hostname = (const char *) gnutls_session_get_ptr (session);\n\n    int rc = gnutls_certificate_verify_peers3 (session, hostname, &status);\n    zmq_assert (rc >= 0);\n\n    if (status != 0) {\n        // TODO: somehow log the error\n        // Certificate is not trusted\n        return GNUTLS_E_CERTIFICATE_ERROR;\n    }\n\n    // notify gnutls to continue handshake normally\n    return 0;\n}\n\n\nzmq::wss_engine_t::wss_engine_t (fd_t fd_,\n                                 const options_t &options_,\n                                 const endpoint_uri_pair_t &endpoint_uri_pair_,\n                                 ws_address_t &address_,\n                                 bool client_,\n                                 void *tls_server_cred_,\n                                 const std::string &hostname_) :\n    ws_engine_t (fd_, options_, endpoint_uri_pair_, address_, client_),\n    _established (false),\n    _tls_client_cred (NULL)\n{\n    int rc = 0;\n\n    if (client_) {\n        // TODO: move to session_base, to allow changing the socket options between connect calls\n        rc = gnutls_certificate_allocate_credentials (&_tls_client_cred);\n        zmq_assert (rc == 0);\n\n        if (options_.wss_trust_system)\n            gnutls_certificate_set_x509_system_trust (_tls_client_cred);\n\n        if (options_.wss_trust_pem.length () > 0) {\n            gnutls_datum_t trust = {\n              (unsigned char *) options_.wss_trust_pem.c_str (),\n              (unsigned int) options_.wss_trust_pem.length ()};\n            rc = gnutls_certificate_set_x509_trust_mem (\n              _tls_client_cred, &trust, GNUTLS_X509_FMT_PEM);\n            zmq_assert (rc >= 0);\n        }\n\n        gnutls_certificate_set_verify_function (_tls_client_cred,\n                                                verify_certificate_callback);\n\n        rc = gnutls_init (&_tls_session, GNUTLS_CLIENT | GNUTLS_NONBLOCK);\n        zmq_assert (rc == GNUTLS_E_SUCCESS);\n\n        if (!hostname_.empty ())\n            gnutls_server_name_set (_tls_session, GNUTLS_NAME_DNS,\n                                    hostname_.c_str (), hostname_.size ());\n\n        gnutls_session_set_ptr (\n          _tls_session,\n          hostname_.empty () ? NULL : const_cast<char *> (hostname_.c_str ()));\n\n        rc = gnutls_credentials_set (_tls_session, GNUTLS_CRD_CERTIFICATE,\n                                     _tls_client_cred);\n        zmq_assert (rc == GNUTLS_E_SUCCESS);\n    } else {\n        zmq_assert (tls_server_cred_);\n\n        rc = gnutls_init (&_tls_session, GNUTLS_SERVER | GNUTLS_NONBLOCK);\n        zmq_assert (rc == GNUTLS_E_SUCCESS);\n\n        rc = gnutls_credentials_set (_tls_session, GNUTLS_CRD_CERTIFICATE,\n                                     tls_server_cred_);\n        zmq_assert (rc == GNUTLS_E_SUCCESS);\n    }\n\n    gnutls_set_default_priority (_tls_session);\n    gnutls_transport_set_int (_tls_session, fd_);\n}\n\nzmq::wss_engine_t::~wss_engine_t ()\n{\n    gnutls_deinit (_tls_session);\n\n    if (_tls_client_cred)\n        gnutls_certificate_free_credentials (_tls_client_cred);\n}\n\nvoid zmq::wss_engine_t::plug_internal ()\n{\n    set_pollin ();\n    in_event ();\n}\n\nvoid zmq::wss_engine_t::out_event ()\n{\n    if (_established)\n        return ws_engine_t::out_event ();\n\n    do_handshake ();\n}\n\nbool zmq::wss_engine_t::do_handshake ()\n{\n    int rc = gnutls_handshake (_tls_session);\n\n    reset_pollout ();\n\n    if (rc == GNUTLS_E_SUCCESS) {\n        start_ws_handshake ();\n        _established = true;\n        return false;\n    } else if (rc == GNUTLS_E_AGAIN) {\n        int direction = gnutls_record_get_direction (_tls_session);\n        if (direction == 1)\n            set_pollout ();\n\n        return false;\n    } else if (rc == GNUTLS_E_INTERRUPTED\n               || rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {\n        return false;\n    } else {\n        error (zmq::i_engine::connection_error);\n        return false;\n    }\n\n    return true;\n}\n\nbool zmq::wss_engine_t::handshake ()\n{\n    if (!_established) {\n        if (!do_handshake ()) {\n            return false;\n        }\n    }\n\n    return ws_engine_t::handshake ();\n}\n\nint zmq::wss_engine_t::read (void *data_, size_t size_)\n{\n    ssize_t rc = gnutls_record_recv (_tls_session, data_, size_);\n\n    if (rc == GNUTLS_E_REHANDSHAKE) {\n        gnutls_alert_send (_tls_session, GNUTLS_AL_WARNING,\n                           GNUTLS_A_NO_RENEGOTIATION);\n        return 0;\n    }\n\n    if (rc == GNUTLS_E_INTERRUPTED) {\n        errno = EINTR;\n        return -1;\n    }\n\n    if (rc == GNUTLS_E_AGAIN) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    if (rc == 0) {\n        errno = EPIPE;\n        return -1;\n    }\n\n    if (rc < 0) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    // TODO: change return type to ssize_t (signed)\n    return rc;\n}\n\nint zmq::wss_engine_t::write (const void *data_, size_t size_)\n{\n    ssize_t rc = gnutls_record_send (_tls_session, data_, size_);\n\n    if (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN) {\n        return 0;\n    }\n\n    if (rc < 0) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    // TODO: change return type to ssize_t (signed)\n    return rc;\n}\n"
  },
  {
    "path": "src/wss_engine.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_WSS_ENGINE_HPP_INCLUDED__\n#define __ZMQ_WSS_ENGINE_HPP_INCLUDED__\n\n#include <gnutls/gnutls.h>\n#include \"ws_engine.hpp\"\n\n#define WSS_BUFFER_SIZE 8192\n\nnamespace zmq\n{\nclass wss_engine_t : public ws_engine_t\n{\n  public:\n    wss_engine_t (fd_t fd_,\n                  const options_t &options_,\n                  const endpoint_uri_pair_t &endpoint_uri_pair_,\n                  ws_address_t &address_,\n                  bool client_,\n                  void *tls_server_cred_,\n                  const std::string &hostname_);\n    ~wss_engine_t ();\n\n    void out_event ();\n\n  protected:\n    bool handshake ();\n    void plug_internal ();\n    int read (void *data, size_t size_);\n    int write (const void *data_, size_t size_);\n\n  private:\n    bool do_handshake ();\n\n    bool _established;\n    gnutls_certificate_credentials_t _tls_client_cred;\n    gnutls_session_t _tls_session;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/xpub.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string.h>\n\n#include \"xpub.hpp\"\n#include \"pipe.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n#include \"macros.hpp\"\n#include \"generic_mtrie_impl.hpp\"\n\nzmq::xpub_t::xpub_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_),\n    _verbose_subs (false),\n    _verbose_unsubs (false),\n    _more_send (false),\n    _more_recv (false),\n    _process_subscribe (false),\n    _only_first_subscribe (false),\n    _lossy (true),\n    _manual (false),\n    _send_last_pipe (false),\n    _pending_pipes (),\n    _welcome_msg ()\n{\n    _last_pipe = NULL;\n    options.type = ZMQ_XPUB;\n    _welcome_msg.init ();\n}\n\nzmq::xpub_t::~xpub_t ()\n{\n    _welcome_msg.close ();\n    for (std::deque<metadata_t *>::iterator it = _pending_metadata.begin (),\n                                            end = _pending_metadata.end ();\n         it != end; ++it)\n        if (*it && (*it)->drop_ref ())\n            LIBZMQ_DELETE (*it);\n}\n\nvoid zmq::xpub_t::xattach_pipe (pipe_t *pipe_,\n                                bool subscribe_to_all_,\n                                bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_);\n    _dist.attach (pipe_);\n\n    //  If subscribe_to_all_ is specified, the caller would like to subscribe\n    //  to all data on this pipe, implicitly.\n    if (subscribe_to_all_)\n        _subscriptions.add (NULL, 0, pipe_);\n\n    // if welcome message exists, send a copy of it\n    if (_welcome_msg.size () > 0) {\n        msg_t copy;\n        copy.init ();\n        const int rc = copy.copy (_welcome_msg);\n        errno_assert (rc == 0);\n        const bool ok = pipe_->write (&copy);\n        zmq_assert (ok);\n        pipe_->flush ();\n    }\n\n    //  The pipe is active when attached. Let's read the subscriptions from\n    //  it, if any.\n    xread_activated (pipe_);\n}\n\nvoid zmq::xpub_t::xread_activated (pipe_t *pipe_)\n{\n    //  There are some subscriptions waiting. Let's process them.\n    msg_t msg;\n    while (pipe_->read (&msg)) {\n        metadata_t *metadata = msg.metadata ();\n        unsigned char *msg_data = static_cast<unsigned char *> (msg.data ()),\n                      *data = NULL;\n        size_t size = 0;\n        bool subscribe = false;\n        bool is_subscribe_or_cancel = false;\n        bool notify = false;\n\n        const bool first_part = !_more_recv;\n        _more_recv = (msg.flags () & msg_t::more) != 0;\n\n        if (first_part || _process_subscribe) {\n            //  Apply the subscription to the trie\n            if (msg.is_subscribe () || msg.is_cancel ()) {\n                data = static_cast<unsigned char *> (msg.command_body ());\n                size = msg.command_body_size ();\n                subscribe = msg.is_subscribe ();\n                is_subscribe_or_cancel = true;\n            } else if (msg.size () > 0 && (*msg_data == 0 || *msg_data == 1)) {\n                data = msg_data + 1;\n                size = msg.size () - 1;\n                subscribe = *msg_data == 1;\n                is_subscribe_or_cancel = true;\n            }\n        }\n\n        if (first_part)\n            _process_subscribe =\n              !_only_first_subscribe || is_subscribe_or_cancel;\n\n        if (is_subscribe_or_cancel) {\n            if (_manual) {\n                // Store manual subscription to use on termination\n                if (!subscribe)\n                    _manual_subscriptions.rm (data, size, pipe_);\n                else\n                    _manual_subscriptions.add (data, size, pipe_);\n\n                _pending_pipes.push_back (pipe_);\n            } else {\n                if (!subscribe) {\n                    const mtrie_t::rm_result rm_result =\n                      _subscriptions.rm (data, size, pipe_);\n                    //  TODO reconsider what to do if rm_result == mtrie_t::not_found\n                    notify =\n                      rm_result != mtrie_t::values_remain || _verbose_unsubs;\n                } else {\n                    const bool first_added =\n                      _subscriptions.add (data, size, pipe_);\n                    notify = first_added || _verbose_subs;\n                }\n            }\n\n            //  If the request was a new subscription, or the subscription\n            //  was removed, or verbose mode or manual mode are enabled, store it\n            //  so that it can be passed to the user on next recv call.\n            if (_manual || (options.type == ZMQ_XPUB && notify)) {\n                //  ZMTP 3.1 hack: we need to support sub/cancel commands, but\n                //  we can't give them back to userspace as it would be an API\n                //  breakage since the payload of the message is completely\n                //  different. Manually craft an old-style message instead.\n                //  Although with other transports it would be possible to simply\n                //  reuse the same buffer and prefix a 0/1 byte to the topic, with\n                //  inproc the subscribe/cancel command string is not present in\n                //  the message, so this optimization is not possible.\n                //  The pushback makes a copy of the data array anyway, so the\n                //  number of buffer copies does not change.\n                blob_t notification (size + 1);\n                if (subscribe)\n                    *notification.data () = 1;\n                else\n                    *notification.data () = 0;\n                memcpy (notification.data () + 1, data, size);\n\n                _pending_data.push_back (ZMQ_MOVE (notification));\n                if (metadata)\n                    metadata->add_ref ();\n                _pending_metadata.push_back (metadata);\n                _pending_flags.push_back (0);\n            }\n        } else if (options.type != ZMQ_PUB) {\n            //  Process user message coming upstream from xsub socket,\n            //  but not if the type is PUB, which never processes user\n            //  messages\n            _pending_data.push_back (blob_t (msg_data, msg.size ()));\n            if (metadata)\n                metadata->add_ref ();\n            _pending_metadata.push_back (metadata);\n            _pending_flags.push_back (msg.flags ());\n        }\n\n        msg.close ();\n    }\n}\n\nvoid zmq::xpub_t::xwrite_activated (pipe_t *pipe_)\n{\n    _dist.activated (pipe_);\n}\n\nint zmq::xpub_t::xsetsockopt (int option_,\n                              const void *optval_,\n                              size_t optvallen_)\n{\n    if (option_ == ZMQ_XPUB_VERBOSE || option_ == ZMQ_XPUB_VERBOSER\n        || option_ == ZMQ_XPUB_MANUAL_LAST_VALUE || option_ == ZMQ_XPUB_NODROP\n        || option_ == ZMQ_XPUB_MANUAL || option_ == ZMQ_ONLY_FIRST_SUBSCRIBE) {\n        if (optvallen_ != sizeof (int)\n            || *static_cast<const int *> (optval_) < 0) {\n            errno = EINVAL;\n            return -1;\n        }\n        if (option_ == ZMQ_XPUB_VERBOSE) {\n            _verbose_subs = (*static_cast<const int *> (optval_) != 0);\n            _verbose_unsubs = false;\n        } else if (option_ == ZMQ_XPUB_VERBOSER) {\n            _verbose_subs = (*static_cast<const int *> (optval_) != 0);\n            _verbose_unsubs = _verbose_subs;\n        } else if (option_ == ZMQ_XPUB_MANUAL_LAST_VALUE) {\n            _manual = (*static_cast<const int *> (optval_) != 0);\n            _send_last_pipe = _manual;\n        } else if (option_ == ZMQ_XPUB_NODROP)\n            _lossy = (*static_cast<const int *> (optval_) == 0);\n        else if (option_ == ZMQ_XPUB_MANUAL)\n            _manual = (*static_cast<const int *> (optval_) != 0);\n        else if (option_ == ZMQ_ONLY_FIRST_SUBSCRIBE)\n            _only_first_subscribe = (*static_cast<const int *> (optval_) != 0);\n    } else if (option_ == ZMQ_SUBSCRIBE && _manual) {\n        if (_last_pipe != NULL)\n            _subscriptions.add ((unsigned char *) optval_, optvallen_,\n                                _last_pipe);\n    } else if (option_ == ZMQ_UNSUBSCRIBE && _manual) {\n        if (_last_pipe != NULL)\n            _subscriptions.rm ((unsigned char *) optval_, optvallen_,\n                               _last_pipe);\n    } else if (option_ == ZMQ_XPUB_WELCOME_MSG) {\n        _welcome_msg.close ();\n\n        if (optvallen_ > 0) {\n            const int rc = _welcome_msg.init_size (optvallen_);\n            errno_assert (rc == 0);\n\n            unsigned char *data =\n              static_cast<unsigned char *> (_welcome_msg.data ());\n            memcpy (data, optval_, optvallen_);\n        } else\n            _welcome_msg.init ();\n    } else {\n        errno = EINVAL;\n        return -1;\n    }\n    return 0;\n}\n\nint zmq::xpub_t::xgetsockopt (int option_, void *optval_, size_t *optvallen_)\n{\n    if (option_ == ZMQ_TOPICS_COUNT) {\n        // make sure to use a multi-thread safe function to avoid race conditions with I/O threads\n        // where subscriptions are processed:\n        return do_getsockopt<int> (optval_, optvallen_,\n                                   (int) _subscriptions.num_prefixes ());\n    }\n\n    // room for future options here\n\n    errno = EINVAL;\n    return -1;\n}\n\nstatic void stub (zmq::mtrie_t::prefix_t data_, size_t size_, void *arg_)\n{\n    LIBZMQ_UNUSED (data_);\n    LIBZMQ_UNUSED (size_);\n    LIBZMQ_UNUSED (arg_);\n}\n\nvoid zmq::xpub_t::xpipe_terminated (pipe_t *pipe_)\n{\n    if (_manual) {\n        //  Remove the pipe from the trie and send corresponding manual\n        //  unsubscriptions upstream.\n        _manual_subscriptions.rm (pipe_, send_unsubscription, this, false);\n        //  Remove pipe without actually sending the message as it was taken\n        //  care of by the manual call above. subscriptions is the real mtrie,\n        //  so the pipe must be removed from there or it will be left over.\n        _subscriptions.rm (pipe_, stub, static_cast<void *> (NULL), false);\n\n        // In case the pipe is currently set as last we must clear it to prevent\n        // subscriptions from being re-added.\n        if (pipe_ == _last_pipe) {\n            _last_pipe = NULL;\n        }\n    } else {\n        //  Remove the pipe from the trie. If there are topics that nobody\n        //  is interested in anymore, send corresponding unsubscriptions\n        //  upstream.\n        _subscriptions.rm (pipe_, send_unsubscription, this, !_verbose_unsubs);\n    }\n\n    _dist.pipe_terminated (pipe_);\n}\n\nvoid zmq::xpub_t::mark_as_matching (pipe_t *pipe_, xpub_t *self_)\n{\n    self_->_dist.match (pipe_);\n}\n\nvoid zmq::xpub_t::mark_last_pipe_as_matching (pipe_t *pipe_, xpub_t *self_)\n{\n    if (self_->_last_pipe == pipe_)\n        self_->_dist.match (pipe_);\n}\n\nint zmq::xpub_t::xsend (msg_t *msg_)\n{\n    const bool msg_more = (msg_->flags () & msg_t::more) != 0;\n\n    //  For the first part of multi-part message, find the matching pipes.\n    if (!_more_send) {\n        // Ensure nothing from previous failed attempt to send is left matched\n        _dist.unmatch ();\n\n        if (unlikely (_manual && _last_pipe && _send_last_pipe)) {\n            _subscriptions.match (static_cast<unsigned char *> (msg_->data ()),\n                                  msg_->size (), mark_last_pipe_as_matching,\n                                  this);\n            _last_pipe = NULL;\n        } else\n            _subscriptions.match (static_cast<unsigned char *> (msg_->data ()),\n                                  msg_->size (), mark_as_matching, this);\n        // If inverted matching is used, reverse the selection now\n        if (options.invert_matching) {\n            _dist.reverse_match ();\n        }\n    }\n\n    int rc = -1; //  Assume we fail\n    if (_lossy || _dist.check_hwm ()) {\n        if (_dist.send_to_matching (msg_) == 0) {\n            //  If we are at the end of multi-part message we can mark\n            //  all the pipes as non-matching.\n            if (!msg_more)\n                _dist.unmatch ();\n            _more_send = msg_more;\n            rc = 0; //  Yay, sent successfully\n        }\n    } else\n        errno = EAGAIN;\n    return rc;\n}\n\nbool zmq::xpub_t::xhas_out ()\n{\n    return _dist.has_out ();\n}\n\nint zmq::xpub_t::xrecv (msg_t *msg_)\n{\n    //  If there is at least one\n    if (_pending_data.empty ()) {\n        errno = EAGAIN;\n        return -1;\n    }\n\n    // User is reading a message, set last_pipe and remove it from the deque\n    if (_manual && !_pending_pipes.empty ()) {\n        _last_pipe = _pending_pipes.front ();\n        _pending_pipes.pop_front ();\n\n        // If the distributor doesn't know about this pipe it must have already\n        // been terminated and thus we can't allow manual subscriptions.\n        if (_last_pipe != NULL && !_dist.has_pipe (_last_pipe)) {\n            _last_pipe = NULL;\n        }\n    }\n\n    int rc = msg_->close ();\n    errno_assert (rc == 0);\n    rc = msg_->init_size (_pending_data.front ().size ());\n    errno_assert (rc == 0);\n    memcpy (msg_->data (), _pending_data.front ().data (),\n            _pending_data.front ().size ());\n\n    // set metadata only if there is some\n    if (metadata_t *metadata = _pending_metadata.front ()) {\n        msg_->set_metadata (metadata);\n        // Remove ref corresponding to vector placement\n        metadata->drop_ref ();\n    }\n\n    msg_->set_flags (_pending_flags.front ());\n    _pending_data.pop_front ();\n    _pending_metadata.pop_front ();\n    _pending_flags.pop_front ();\n    return 0;\n}\n\nbool zmq::xpub_t::xhas_in ()\n{\n    return !_pending_data.empty ();\n}\n\nvoid zmq::xpub_t::send_unsubscription (zmq::mtrie_t::prefix_t data_,\n                                       size_t size_,\n                                       xpub_t *self_)\n{\n    if (self_->options.type != ZMQ_PUB) {\n        //  Place the unsubscription to the queue of pending (un)subscriptions\n        //  to be retrieved by the user later on.\n        blob_t unsub (size_ + 1);\n        *unsub.data () = 0;\n        if (size_ > 0)\n            memcpy (unsub.data () + 1, data_, size_);\n        self_->_pending_data.ZMQ_PUSH_OR_EMPLACE_BACK (ZMQ_MOVE (unsub));\n        self_->_pending_metadata.push_back (NULL);\n        self_->_pending_flags.push_back (0);\n\n        if (self_->_manual) {\n            self_->_last_pipe = NULL;\n            self_->_pending_pipes.push_back (NULL);\n        }\n    }\n}\n"
  },
  {
    "path": "src/xpub.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_XPUB_HPP_INCLUDED__\n#define __ZMQ_XPUB_HPP_INCLUDED__\n\n#include <deque>\n\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n#include \"mtrie.hpp\"\n#include \"dist.hpp\"\n\nnamespace zmq\n{\nclass ctx_t;\nclass msg_t;\nclass pipe_t;\nclass io_thread_t;\n\nclass xpub_t : public socket_base_t\n{\n  public:\n    xpub_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~xpub_t () ZMQ_OVERRIDE;\n\n    //  Implementations of virtual functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_ = false,\n                       bool locally_initiated_ = false) ZMQ_OVERRIDE;\n    int xsend (zmq::msg_t *msg_) ZMQ_FINAL;\n    bool xhas_out () ZMQ_FINAL;\n    int xrecv (zmq::msg_t *msg_) ZMQ_OVERRIDE;\n    bool xhas_in () ZMQ_OVERRIDE;\n    void xread_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    void xwrite_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    int\n    xsetsockopt (int option_, const void *optval_, size_t optvallen_) ZMQ_FINAL;\n    int xgetsockopt (int option_, void *optval_, size_t *optvallen_) ZMQ_FINAL;\n    void xpipe_terminated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n\n  private:\n    //  Function to be applied to the trie to send all the subscriptions\n    //  upstream.\n    static void send_unsubscription (zmq::mtrie_t::prefix_t data_,\n                                     size_t size_,\n                                     xpub_t *self_);\n\n    //  Function to be applied to each matching pipes.\n    static void mark_as_matching (zmq::pipe_t *pipe_, xpub_t *self_);\n\n    //  List of all subscriptions mapped to corresponding pipes.\n    mtrie_t _subscriptions;\n\n    //  List of manual subscriptions mapped to corresponding pipes.\n    mtrie_t _manual_subscriptions;\n\n    //  Distributor of messages holding the list of outbound pipes.\n    dist_t _dist;\n\n    // If true, send all subscription messages upstream, not just\n    // unique ones\n    bool _verbose_subs;\n\n    // If true, send all unsubscription messages upstream, not just\n    // unique ones\n    bool _verbose_unsubs;\n\n    //  True if we are in the middle of sending a multi-part message.\n    bool _more_send;\n\n    //  True if we are in the middle of receiving a multi-part message.\n    bool _more_recv;\n\n    //  If true, subscribe and cancel messages are processed for the rest\n    //  of multipart message.\n    bool _process_subscribe;\n\n    //  This option is enabled with ZMQ_ONLY_FIRST_SUBSCRIBE.\n    //  If true, messages following subscribe/unsubscribe in a multipart\n    //  message are treated as user data regardless of the first byte.\n    bool _only_first_subscribe;\n\n    //  Drop messages if HWM reached, otherwise return with EAGAIN\n    bool _lossy;\n\n    //  Subscriptions will not bed added automatically, only after calling set option with ZMQ_SUBSCRIBE or ZMQ_UNSUBSCRIBE\n    bool _manual;\n\n    //  Send message to the last pipe, only used if xpub is on manual and after calling set option with ZMQ_SUBSCRIBE\n    bool _send_last_pipe;\n\n    //  Function to be applied to match the last pipe.\n    static void mark_last_pipe_as_matching (zmq::pipe_t *pipe_, xpub_t *self_);\n\n    //  Last pipe that sent subscription message, only used if xpub is on manual\n    pipe_t *_last_pipe;\n\n    // Pipes that sent subscriptions messages that have not yet been processed, only used if xpub is on manual\n    std::deque<pipe_t *> _pending_pipes;\n\n    //  Welcome message to send to pipe when attached\n    msg_t _welcome_msg;\n\n    //  List of pending (un)subscriptions, ie. those that were already\n    //  applied to the trie, but not yet received by the user.\n    std::deque<blob_t> _pending_data;\n    std::deque<metadata_t *> _pending_metadata;\n    std::deque<unsigned char> _pending_flags;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (xpub_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/xsub.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include <string.h>\n\n#include \"macros.hpp\"\n#include \"xsub.hpp\"\n#include \"err.hpp\"\n\nzmq::xsub_t::xsub_t (class ctx_t *parent_, uint32_t tid_, int sid_) :\n    socket_base_t (parent_, tid_, sid_),\n    _verbose_unsubs (false),\n    _has_message (false),\n    _more_send (false),\n    _more_recv (false),\n    _process_subscribe (false),\n    _only_first_subscribe (false)\n{\n    options.type = ZMQ_XSUB;\n\n    //  When socket is being closed down we don't want to wait till pending\n    //  subscription commands are sent to the wire.\n    options.linger.store (0);\n\n    const int rc = _message.init ();\n    errno_assert (rc == 0);\n}\n\nzmq::xsub_t::~xsub_t ()\n{\n    const int rc = _message.close ();\n    errno_assert (rc == 0);\n}\n\nvoid zmq::xsub_t::xattach_pipe (pipe_t *pipe_,\n                                bool subscribe_to_all_,\n                                bool locally_initiated_)\n{\n    LIBZMQ_UNUSED (subscribe_to_all_);\n    LIBZMQ_UNUSED (locally_initiated_);\n\n    zmq_assert (pipe_);\n    _fq.attach (pipe_);\n    _dist.attach (pipe_);\n\n    //  Send all the cached subscriptions to the new upstream peer.\n    _subscriptions.apply (send_subscription, pipe_);\n    pipe_->flush ();\n}\n\nvoid zmq::xsub_t::xread_activated (pipe_t *pipe_)\n{\n    _fq.activated (pipe_);\n}\n\nvoid zmq::xsub_t::xwrite_activated (pipe_t *pipe_)\n{\n    _dist.activated (pipe_);\n}\n\nvoid zmq::xsub_t::xpipe_terminated (pipe_t *pipe_)\n{\n    _fq.pipe_terminated (pipe_);\n    _dist.pipe_terminated (pipe_);\n}\n\nvoid zmq::xsub_t::xhiccuped (pipe_t *pipe_)\n{\n    //  Send all the cached subscriptions to the hiccuped pipe.\n    _subscriptions.apply (send_subscription, pipe_);\n    pipe_->flush ();\n}\n\nint zmq::xsub_t::xsetsockopt (int option_,\n                              const void *optval_,\n                              size_t optvallen_)\n{\n    if (option_ == ZMQ_ONLY_FIRST_SUBSCRIBE) {\n        if (optvallen_ != sizeof (int)\n            || *static_cast<const int *> (optval_) < 0) {\n            errno = EINVAL;\n            return -1;\n        }\n        _only_first_subscribe = (*static_cast<const int *> (optval_) != 0);\n        return 0;\n    }\n#ifdef ZMQ_BUILD_DRAFT_API\n    else if (option_ == ZMQ_XSUB_VERBOSE_UNSUBSCRIBE) {\n        _verbose_unsubs = (*static_cast<const int *> (optval_) != 0);\n        return 0;\n    }\n#endif\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::xsub_t::xgetsockopt (int option_, void *optval_, size_t *optvallen_)\n{\n    if (option_ == ZMQ_TOPICS_COUNT) {\n        // make sure to use a multi-thread safe function to avoid race conditions with I/O threads\n        // where subscriptions are processed:\n#ifdef ZMQ_USE_RADIX_TREE\n        uint64_t num_subscriptions = _subscriptions.size ();\n#else\n        uint64_t num_subscriptions = _subscriptions.num_prefixes ();\n#endif\n\n        return do_getsockopt<int> (optval_, optvallen_,\n                                   (int) num_subscriptions);\n    }\n\n    // room for future options here\n\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq::xsub_t::xsend (msg_t *msg_)\n{\n    size_t size = msg_->size ();\n    unsigned char *data = static_cast<unsigned char *> (msg_->data ());\n\n    const bool first_part = !_more_send;\n    _more_send = (msg_->flags () & msg_t::more) != 0;\n\n    if (first_part) {\n        _process_subscribe = !_only_first_subscribe;\n    } else if (!_process_subscribe) {\n        //  User message sent upstream to XPUB socket\n        return _dist.send_to_all (msg_);\n    }\n\n    if (msg_->is_subscribe () || (size > 0 && *data == 1)) {\n        //  Process subscribe message\n        //  This used to filter out duplicate subscriptions,\n        //  however this is already done on the XPUB side and\n        //  doing it here as well breaks ZMQ_XPUB_VERBOSE\n        //  when there are forwarding devices involved.\n        if (!msg_->is_subscribe ()) {\n            data = data + 1;\n            size = size - 1;\n        }\n        _subscriptions.add (data, size);\n        _process_subscribe = true;\n        return _dist.send_to_all (msg_);\n    }\n    if (msg_->is_cancel () || (size > 0 && *data == 0)) {\n        //  Process unsubscribe message\n        if (!msg_->is_cancel ()) {\n            data = data + 1;\n            size = size - 1;\n        }\n        _process_subscribe = true;\n        const bool rm_result = _subscriptions.rm (data, size);\n        if (rm_result || _verbose_unsubs)\n            return _dist.send_to_all (msg_);\n    } else\n        //  User message sent upstream to XPUB socket\n        return _dist.send_to_all (msg_);\n\n    int rc = msg_->close ();\n    errno_assert (rc == 0);\n    rc = msg_->init ();\n    errno_assert (rc == 0);\n\n    return 0;\n}\n\nbool zmq::xsub_t::xhas_out ()\n{\n    //  Subscription can be added/removed anytime.\n    return true;\n}\n\nint zmq::xsub_t::xrecv (msg_t *msg_)\n{\n    //  If there's already a message prepared by a previous call to zmq_poll,\n    //  return it straight ahead.\n    if (_has_message) {\n        const int rc = msg_->move (_message);\n        errno_assert (rc == 0);\n        _has_message = false;\n        _more_recv = (msg_->flags () & msg_t::more) != 0;\n        return 0;\n    }\n\n    //  TODO: This can result in infinite loop in the case of continuous\n    //  stream of non-matching messages which breaks the non-blocking recv\n    //  semantics.\n    while (true) {\n        //  Get a message using fair queueing algorithm.\n        int rc = _fq.recv (msg_);\n\n        //  If there's no message available, return immediately.\n        //  The same when error occurs.\n        if (rc != 0)\n            return -1;\n\n        //  Check whether the message matches at least one subscription.\n        //  Non-initial parts of the message are passed\n        if (_more_recv || !options.filter || match (msg_)) {\n            _more_recv = (msg_->flags () & msg_t::more) != 0;\n            return 0;\n        }\n\n        //  Message doesn't match. Pop any remaining parts of the message\n        //  from the pipe.\n        while (msg_->flags () & msg_t::more) {\n            rc = _fq.recv (msg_);\n            errno_assert (rc == 0);\n        }\n    }\n}\n\nbool zmq::xsub_t::xhas_in ()\n{\n    //  There are subsequent parts of the partly-read message available.\n    if (_more_recv)\n        return true;\n\n    //  If there's already a message prepared by a previous call to zmq_poll,\n    //  return straight ahead.\n    if (_has_message)\n        return true;\n\n    //  TODO: This can result in infinite loop in the case of continuous\n    //  stream of non-matching messages.\n    while (true) {\n        //  Get a message using fair queueing algorithm.\n        int rc = _fq.recv (&_message);\n\n        //  If there's no message available, return immediately.\n        //  The same when error occurs.\n        if (rc != 0) {\n            errno_assert (errno == EAGAIN);\n            return false;\n        }\n\n        //  Check whether the message matches at least one subscription.\n        if (!options.filter || match (&_message)) {\n            _has_message = true;\n            return true;\n        }\n\n        //  Message doesn't match. Pop any remaining parts of the message\n        //  from the pipe.\n        while (_message.flags () & msg_t::more) {\n            rc = _fq.recv (&_message);\n            errno_assert (rc == 0);\n        }\n    }\n}\n\nbool zmq::xsub_t::match (msg_t *msg_)\n{\n    const bool matching = _subscriptions.check (\n      static_cast<unsigned char *> (msg_->data ()), msg_->size ());\n\n    return matching ^ options.invert_matching;\n}\n\nvoid zmq::xsub_t::send_subscription (unsigned char *data_,\n                                     size_t size_,\n                                     void *arg_)\n{\n    pipe_t *pipe = static_cast<pipe_t *> (arg_);\n\n    //  Create the subscription message.\n    msg_t msg;\n    const int rc = msg.init_subscribe (size_, data_);\n    errno_assert (rc == 0);\n\n    //  Send it to the pipe.\n    const bool sent = pipe->write (&msg);\n    //  If we reached the SNDHWM, and thus cannot send the subscription, drop\n    //  the subscription message instead. This matches the behaviour of\n    //  zmq_setsockopt(ZMQ_SUBSCRIBE, ...), which also drops subscriptions\n    //  when the SNDHWM is reached.\n    if (!sent)\n        msg.close ();\n}\n"
  },
  {
    "path": "src/xsub.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_XSUB_HPP_INCLUDED__\n#define __ZMQ_XSUB_HPP_INCLUDED__\n\n#include \"socket_base.hpp\"\n#include \"session_base.hpp\"\n#include \"dist.hpp\"\n#include \"fq.hpp\"\n#ifdef ZMQ_USE_RADIX_TREE\n#include \"radix_tree.hpp\"\n#else\n#include \"trie.hpp\"\n#endif\n\nnamespace zmq\n{\nclass ctx_t;\nclass pipe_t;\nclass io_thread_t;\n\nclass xsub_t : public socket_base_t\n{\n  public:\n    xsub_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);\n    ~xsub_t () ZMQ_OVERRIDE;\n\n  protected:\n    //  Overrides of functions from socket_base_t.\n    void xattach_pipe (zmq::pipe_t *pipe_,\n                       bool subscribe_to_all_,\n                       bool locally_initiated_) ZMQ_FINAL;\n    int xsetsockopt (int option_,\n                     const void *optval_,\n                     size_t optvallen_) ZMQ_OVERRIDE;\n    int xgetsockopt (int option_, void *optval_, size_t *optvallen_) ZMQ_FINAL;\n    int xsend (zmq::msg_t *msg_) ZMQ_OVERRIDE;\n    bool xhas_out () ZMQ_OVERRIDE;\n    int xrecv (zmq::msg_t *msg_) ZMQ_FINAL;\n    bool xhas_in () ZMQ_FINAL;\n    void xread_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    void xwrite_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n    void xhiccuped (pipe_t *pipe_) ZMQ_FINAL;\n    void xpipe_terminated (zmq::pipe_t *pipe_) ZMQ_FINAL;\n\n  private:\n    //  Check whether the message matches at least one subscription.\n    bool match (zmq::msg_t *msg_);\n\n    //  Function to be applied to the trie to send all the subsciptions\n    //  upstream.\n    static void\n    send_subscription (unsigned char *data_, size_t size_, void *arg_);\n\n    //  Fair queueing object for inbound pipes.\n    fq_t _fq;\n\n    //  Object for distributing the subscriptions upstream.\n    dist_t _dist;\n\n    //  The repository of subscriptions.\n#ifdef ZMQ_USE_RADIX_TREE\n    radix_tree_t _subscriptions;\n#else\n    trie_with_size_t _subscriptions;\n#endif\n\n    // If true, send all unsubscription messages upstream, not just\n    // unique ones\n    bool _verbose_unsubs;\n\n    //  If true, 'message' contains a matching message to return on the\n    //  next recv call.\n    bool _has_message;\n    msg_t _message;\n\n    //  If true, part of a multipart message was already sent, but\n    //  there are following parts still waiting.\n    bool _more_send;\n\n    //  If true, part of a multipart message was already received, but\n    //  there are following parts still waiting.\n    bool _more_recv;\n\n    //  If true, subscribe and cancel messages are processed for the rest\n    //  of multipart message.\n    bool _process_subscribe;\n\n    //  This option is enabled with ZMQ_ONLY_FIRST_SUBSCRIBE.\n    //  If true, messages following subscribe/unsubscribe in a multipart\n    //  message are treated as user data regardless of the first byte.\n    bool _only_first_subscribe;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (xsub_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ypipe.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_YPIPE_HPP_INCLUDED__\n#define __ZMQ_YPIPE_HPP_INCLUDED__\n\n#include \"atomic_ptr.hpp\"\n#include \"yqueue.hpp\"\n#include \"ypipe_base.hpp\"\n\nnamespace zmq\n{\n//  Lock-free queue implementation.\n//  Only a single thread can read from the pipe at any specific moment.\n//  Only a single thread can write to the pipe at any specific moment.\n//  T is the type of the object in the queue.\n//  N is granularity of the pipe, i.e. how many items are needed to\n//  perform next memory allocation.\n\ntemplate <typename T, int N> class ypipe_t ZMQ_FINAL : public ypipe_base_t<T>\n{\n  public:\n    //  Initialises the pipe.\n    ypipe_t ()\n    {\n        //  Insert terminator element into the queue.\n        _queue.push ();\n\n        //  Let all the pointers to point to the terminator.\n        //  (unless pipe is dead, in which case c is set to NULL).\n        _r = _w = _f = &_queue.back ();\n        _c.set (&_queue.back ());\n    }\n\n    //  Following function (write) deliberately copies uninitialised data\n    //  when used with zmq_msg. Initialising the VSM body for\n    //  non-VSM messages won't be good for performance.\n\n#ifdef ZMQ_HAVE_OPENVMS\n#pragma message save\n#pragma message disable(UNINIT)\n#endif\n\n    //  Write an item to the pipe.  Don't flush it yet. If incomplete is\n    //  set to true the item is assumed to be continued by items\n    //  subsequently written to the pipe. Incomplete items are never\n    //  flushed down the stream.\n    void write (const T &value_, bool incomplete_)\n    {\n        //  Place the value to the queue, add new terminator element.\n        _queue.back () = value_;\n        _queue.push ();\n\n        //  Move the \"flush up to here\" pointer.\n        if (!incomplete_)\n            _f = &_queue.back ();\n    }\n\n#ifdef ZMQ_HAVE_OPENVMS\n#pragma message restore\n#endif\n\n    //  Pop an incomplete item from the pipe. Returns true if such\n    //  item exists, false otherwise.\n    bool unwrite (T *value_)\n    {\n        if (_f == &_queue.back ())\n            return false;\n        _queue.unpush ();\n        *value_ = _queue.back ();\n        return true;\n    }\n\n    //  Flush all the completed items into the pipe. Returns false if\n    //  the reader thread is sleeping. In that case, caller is obliged to\n    //  wake the reader up before using the pipe again.\n    bool flush ()\n    {\n        //  If there are no un-flushed items, do nothing.\n        if (_w == _f)\n            return true;\n\n        //  Try to set 'c' to 'f'.\n        if (_c.cas (_w, _f) != _w) {\n            //  Compare-and-swap was unsuccessful because 'c' is NULL.\n            //  This means that the reader is asleep. Therefore we don't\n            //  care about thread-safeness and update c in non-atomic\n            //  manner. We'll return false to let the caller know\n            //  that reader is sleeping.\n            _c.set (_f);\n            _w = _f;\n            return false;\n        }\n\n        //  Reader is alive. Nothing special to do now. Just move\n        //  the 'first un-flushed item' pointer to 'f'.\n        _w = _f;\n        return true;\n    }\n\n    //  Check whether item is available for reading.\n    bool check_read ()\n    {\n        //  Was the value prefetched already? If so, return.\n        if (&_queue.front () != _r && _r)\n            return true;\n\n        //  There's no prefetched value, so let us prefetch more values.\n        //  Prefetching is to simply retrieve the\n        //  pointer from c in atomic fashion. If there are no\n        //  items to prefetch, set c to NULL (using compare-and-swap).\n        _r = _c.cas (&_queue.front (), NULL);\n\n        //  If there are no elements prefetched, exit.\n        //  During pipe's lifetime r should never be NULL, however,\n        //  it can happen during pipe shutdown when items\n        //  are being deallocated.\n        if (&_queue.front () == _r || !_r)\n            return false;\n\n        //  There was at least one value prefetched.\n        return true;\n    }\n\n    //  Reads an item from the pipe. Returns false if there is no value.\n    //  available.\n    bool read (T *value_)\n    {\n        //  Try to prefetch a value.\n        if (!check_read ())\n            return false;\n\n        //  There was at least one value prefetched.\n        //  Return it to the caller.\n        *value_ = _queue.front ();\n        _queue.pop ();\n        return true;\n    }\n\n    //  Applies the function fn to the first element in the pipe\n    //  and returns the value returned by the fn.\n    //  The pipe mustn't be empty or the function crashes.\n    bool probe (bool (*fn_) (const T &))\n    {\n        const bool rc = check_read ();\n        zmq_assert (rc);\n\n        return (*fn_) (_queue.front ());\n    }\n\n  protected:\n    //  Allocation-efficient queue to store pipe items.\n    //  Front of the queue points to the first prefetched item, back of\n    //  the pipe points to last un-flushed item. Front is used only by\n    //  reader thread, while back is used only by writer thread.\n    yqueue_t<T, N> _queue;\n\n    //  Points to the first un-flushed item. This variable is used\n    //  exclusively by writer thread.\n    T *_w;\n\n    //  Points to the first un-prefetched item. This variable is used\n    //  exclusively by reader thread.\n    T *_r;\n\n    //  Points to the first item to be flushed in the future.\n    T *_f;\n\n    //  The single point of contention between writer and reader thread.\n    //  Points past the last flushed item. If it is NULL,\n    //  reader is asleep. This pointer should be always accessed using\n    //  atomic operations.\n    atomic_ptr_t<T> _c;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (ypipe_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ypipe_base.hpp",
    "content": "\n/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_YPIPE_BASE_HPP_INCLUDED__\n#define __ZMQ_YPIPE_BASE_HPP_INCLUDED__\n\n#include \"macros.hpp\"\n\nnamespace zmq\n{\n// ypipe_base abstracts ypipe and ypipe_conflate specific\n// classes, one is selected according to a the conflate\n// socket option\n\ntemplate <typename T> class ypipe_base_t\n{\n  public:\n    virtual ~ypipe_base_t () ZMQ_DEFAULT;\n    virtual void write (const T &value_, bool incomplete_) = 0;\n    virtual bool unwrite (T *value_) = 0;\n    virtual bool flush () = 0;\n    virtual bool check_read () = 0;\n    virtual bool read (T *value_) = 0;\n    virtual bool probe (bool (*fn_) (const T &)) = 0;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/ypipe_conflate.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_YPIPE_CONFLATE_HPP_INCLUDED__\n#define __ZMQ_YPIPE_CONFLATE_HPP_INCLUDED__\n\n#include \"platform.hpp\"\n#include \"dbuffer.hpp\"\n#include \"ypipe_base.hpp\"\n\nnamespace zmq\n{\n//  Adapter for dbuffer, to plug it in instead of a queue for the sake\n//  of implementing the conflate socket option, which, if set, makes\n//  the receiving side to discard all incoming messages but the last one.\n//\n//  reader_awake flag is needed here to mimic ypipe delicate behaviour\n//  around the reader being asleep (see 'c' pointer being NULL in ypipe.hpp)\n\ntemplate <typename T> class ypipe_conflate_t ZMQ_FINAL : public ypipe_base_t<T>\n{\n  public:\n    //  Initialises the pipe.\n    ypipe_conflate_t () : reader_awake (false) {}\n\n    //  Following function (write) deliberately copies uninitialised data\n    //  when used with zmq_msg. Initialising the VSM body for\n    //  non-VSM messages won't be good for performance.\n\n#ifdef ZMQ_HAVE_OPENVMS\n#pragma message save\n#pragma message disable(UNINIT)\n#endif\n    void write (const T &value_, bool incomplete_)\n    {\n        (void) incomplete_;\n\n        dbuffer.write (value_);\n    }\n\n#ifdef ZMQ_HAVE_OPENVMS\n#pragma message restore\n#endif\n\n    // There are no incomplete items for conflate ypipe\n    bool unwrite (T *) { return false; }\n\n    //  Flush is no-op for conflate ypipe. Reader asleep behaviour\n    //  is as of the usual ypipe.\n    //  Returns false if the reader thread is sleeping. In that case,\n    //  caller is obliged to wake the reader up before using the pipe again.\n    bool flush () { return reader_awake; }\n\n    //  Check whether item is available for reading.\n    bool check_read ()\n    {\n        const bool res = dbuffer.check_read ();\n        if (!res)\n            reader_awake = false;\n\n        return res;\n    }\n\n    //  Reads an item from the pipe. Returns false if there is no value.\n    //  available.\n    bool read (T *value_)\n    {\n        if (!check_read ())\n            return false;\n\n        return dbuffer.read (value_);\n    }\n\n    //  Applies the function fn to the first element in the pipe\n    //  and returns the value returned by the fn.\n    //  The pipe mustn't be empty or the function crashes.\n    bool probe (bool (*fn_) (const T &)) { return dbuffer.probe (fn_); }\n\n  protected:\n    dbuffer_t<T> dbuffer;\n    bool reader_awake;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (ypipe_conflate_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/yqueue.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_YQUEUE_HPP_INCLUDED__\n#define __ZMQ_YQUEUE_HPP_INCLUDED__\n\n#include <stdlib.h>\n#include <stddef.h>\n\n#include \"err.hpp\"\n#include \"atomic_ptr.hpp\"\n#include \"platform.hpp\"\n\nnamespace zmq\n{\n//  yqueue is an efficient queue implementation. The main goal is\n//  to minimise number of allocations/deallocations needed. Thus yqueue\n//  allocates/deallocates elements in batches of N.\n//\n//  yqueue allows one thread to use push/back function and another one\n//  to use pop/front functions. However, user must ensure that there's no\n//  pop on the empty queue and that both threads don't access the same\n//  element in unsynchronised manner.\n//\n//  T is the type of the object in the queue.\n//  N is granularity of the queue (how many pushes have to be done till\n//  actual memory allocation is required).\n#if defined HAVE_POSIX_MEMALIGN\n// ALIGN is the memory alignment size to use in the case where we have\n// posix_memalign available. Default value is 64, this alignment will\n// prevent two queue chunks from occupying the same CPU cache line on\n// architectures where cache lines are <= 64 bytes (e.g. most things\n// except POWER). It is detected at build time to try to account for other\n// platforms like POWER and s390x.\ntemplate <typename T, int N, size_t ALIGN = ZMQ_CACHELINE_SIZE> class yqueue_t\n#else\ntemplate <typename T, int N> class yqueue_t\n#endif\n{\n  public:\n    //  Create the queue.\n    inline yqueue_t ()\n    {\n        _begin_chunk = allocate_chunk ();\n        alloc_assert (_begin_chunk);\n        _begin_pos = 0;\n        _back_chunk = NULL;\n        _back_pos = 0;\n        _end_chunk = _begin_chunk;\n        _end_pos = 0;\n    }\n\n    //  Destroy the queue.\n    inline ~yqueue_t ()\n    {\n        while (true) {\n            if (_begin_chunk == _end_chunk) {\n                free (_begin_chunk);\n                break;\n            }\n            chunk_t *o = _begin_chunk;\n            _begin_chunk = _begin_chunk->next;\n            free (o);\n        }\n\n        chunk_t *sc = _spare_chunk.xchg (NULL);\n        free (sc);\n    }\n\n    //  Returns reference to the front element of the queue.\n    //  If the queue is empty, behaviour is undefined.\n    inline T &front () { return _begin_chunk->values[_begin_pos]; }\n\n    //  Returns reference to the back element of the queue.\n    //  If the queue is empty, behaviour is undefined.\n    inline T &back () { return _back_chunk->values[_back_pos]; }\n\n    //  Adds an element to the back end of the queue.\n    inline void push ()\n    {\n        _back_chunk = _end_chunk;\n        _back_pos = _end_pos;\n\n        if (++_end_pos != N)\n            return;\n\n        chunk_t *sc = _spare_chunk.xchg (NULL);\n        if (sc) {\n            _end_chunk->next = sc;\n            sc->prev = _end_chunk;\n        } else {\n            _end_chunk->next = allocate_chunk ();\n            alloc_assert (_end_chunk->next);\n            _end_chunk->next->prev = _end_chunk;\n        }\n        _end_chunk = _end_chunk->next;\n        _end_pos = 0;\n    }\n\n    //  Removes element from the back end of the queue. In other words\n    //  it rollbacks last push to the queue. Take care: Caller is\n    //  responsible for destroying the object being unpushed.\n    //  The caller must also guarantee that the queue isn't empty when\n    //  unpush is called. It cannot be done automatically as the read\n    //  side of the queue can be managed by different, completely\n    //  unsynchronised thread.\n    inline void unpush ()\n    {\n        //  First, move 'back' one position backwards.\n        if (_back_pos)\n            --_back_pos;\n        else {\n            _back_pos = N - 1;\n            _back_chunk = _back_chunk->prev;\n        }\n\n        //  Now, move 'end' position backwards. Note that obsolete end chunk\n        //  is not used as a spare chunk. The analysis shows that doing so\n        //  would require free and atomic operation per chunk deallocated\n        //  instead of a simple free.\n        if (_end_pos)\n            --_end_pos;\n        else {\n            _end_pos = N - 1;\n            _end_chunk = _end_chunk->prev;\n            free (_end_chunk->next);\n            _end_chunk->next = NULL;\n        }\n    }\n\n    //  Removes an element from the front end of the queue.\n    inline void pop ()\n    {\n        if (++_begin_pos == N) {\n            chunk_t *o = _begin_chunk;\n            _begin_chunk = _begin_chunk->next;\n            _begin_chunk->prev = NULL;\n            _begin_pos = 0;\n\n            //  'o' has been more recently used than _spare_chunk,\n            //  so for cache reasons we'll get rid of the spare and\n            //  use 'o' as the spare.\n            chunk_t *cs = _spare_chunk.xchg (o);\n            free (cs);\n        }\n    }\n\n  private:\n    //  Individual memory chunk to hold N elements.\n    struct chunk_t\n    {\n        T values[N];\n        chunk_t *prev;\n        chunk_t *next;\n    };\n\n    static inline chunk_t *allocate_chunk ()\n    {\n#if defined HAVE_POSIX_MEMALIGN\n        void *pv;\n        if (posix_memalign (&pv, ALIGN, sizeof (chunk_t)) == 0)\n            return (chunk_t *) pv;\n        return NULL;\n#else\n        return static_cast<chunk_t *> (malloc (sizeof (chunk_t)));\n#endif\n    }\n\n    //  Back position may point to invalid memory if the queue is empty,\n    //  while begin & end positions are always valid. Begin position is\n    //  accessed exclusively be queue reader (front/pop), while back and\n    //  end positions are accessed exclusively by queue writer (back/push).\n    chunk_t *_begin_chunk;\n    int _begin_pos;\n    chunk_t *_back_chunk;\n    int _back_pos;\n    chunk_t *_end_chunk;\n    int _end_pos;\n\n    //  People are likely to produce and consume at similar rates.  In\n    //  this scenario holding onto the most recently freed chunk saves\n    //  us from having to call malloc/free.\n    atomic_ptr_t<chunk_t> _spare_chunk;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (yqueue_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/zap_client.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"zap_client.hpp\"\n#include \"msg.hpp\"\n#include \"session_base.hpp\"\n\nnamespace zmq\n{\nconst char zap_version[] = \"1.0\";\nconst size_t zap_version_len = sizeof (zap_version) - 1;\n\nconst char id[] = \"1\";\nconst size_t id_len = sizeof (id) - 1;\n\nzap_client_t::zap_client_t (session_base_t *const session_,\n                            const std::string &peer_address_,\n                            const options_t &options_) :\n    mechanism_base_t (session_, options_), peer_address (peer_address_)\n{\n}\n\nvoid zap_client_t::send_zap_request (const char *mechanism_,\n                                     size_t mechanism_length_,\n                                     const uint8_t *credentials_,\n                                     size_t credentials_size_)\n{\n    send_zap_request (mechanism_, mechanism_length_, &credentials_,\n                      &credentials_size_, 1);\n}\n\nvoid zap_client_t::send_zap_request (const char *mechanism_,\n                                     size_t mechanism_length_,\n                                     const uint8_t **credentials_,\n                                     size_t *credentials_sizes_,\n                                     size_t credentials_count_)\n{\n    // write_zap_msg cannot fail. It could only fail if the HWM was exceeded,\n    // but on the ZAP socket, the HWM is disabled.\n\n    int rc;\n    msg_t msg;\n\n    //  Address delimiter frame\n    rc = msg.init ();\n    errno_assert (rc == 0);\n    msg.set_flags (msg_t::more);\n    rc = session->write_zap_msg (&msg);\n    errno_assert (rc == 0);\n\n    //  Version frame\n    rc = msg.init_size (zap_version_len);\n    errno_assert (rc == 0);\n    memcpy (msg.data (), zap_version, zap_version_len);\n    msg.set_flags (msg_t::more);\n    rc = session->write_zap_msg (&msg);\n    errno_assert (rc == 0);\n\n    //  Request ID frame\n    rc = msg.init_size (id_len);\n    errno_assert (rc == 0);\n    memcpy (msg.data (), id, id_len);\n    msg.set_flags (msg_t::more);\n    rc = session->write_zap_msg (&msg);\n    errno_assert (rc == 0);\n\n    //  Domain frame\n    rc = msg.init_size (options.zap_domain.length ());\n    errno_assert (rc == 0);\n    memcpy (msg.data (), options.zap_domain.c_str (),\n            options.zap_domain.length ());\n    msg.set_flags (msg_t::more);\n    rc = session->write_zap_msg (&msg);\n    errno_assert (rc == 0);\n\n    //  Address frame\n    rc = msg.init_size (peer_address.length ());\n    errno_assert (rc == 0);\n    memcpy (msg.data (), peer_address.c_str (), peer_address.length ());\n    msg.set_flags (msg_t::more);\n    rc = session->write_zap_msg (&msg);\n    errno_assert (rc == 0);\n\n    //  Routing id frame\n    rc = msg.init_size (options.routing_id_size);\n    errno_assert (rc == 0);\n    memcpy (msg.data (), options.routing_id, options.routing_id_size);\n    msg.set_flags (msg_t::more);\n    rc = session->write_zap_msg (&msg);\n    errno_assert (rc == 0);\n\n    //  Mechanism frame\n    rc = msg.init_size (mechanism_length_);\n    errno_assert (rc == 0);\n    memcpy (msg.data (), mechanism_, mechanism_length_);\n    if (credentials_count_)\n        msg.set_flags (msg_t::more);\n    rc = session->write_zap_msg (&msg);\n    errno_assert (rc == 0);\n\n    //  Credentials frames\n    for (size_t i = 0; i < credentials_count_; ++i) {\n        rc = msg.init_size (credentials_sizes_[i]);\n        errno_assert (rc == 0);\n        if (i < credentials_count_ - 1)\n            msg.set_flags (msg_t::more);\n        memcpy (msg.data (), credentials_[i], credentials_sizes_[i]);\n        rc = session->write_zap_msg (&msg);\n        errno_assert (rc == 0);\n    }\n}\n\nint zap_client_t::receive_and_process_zap_reply ()\n{\n    int rc = 0;\n    const size_t zap_reply_frame_count = 7;\n    msg_t msg[zap_reply_frame_count];\n\n    //  Initialize all reply frames\n    for (size_t i = 0; i < zap_reply_frame_count; i++) {\n        rc = msg[i].init ();\n        errno_assert (rc == 0);\n    }\n\n    for (size_t i = 0; i < zap_reply_frame_count; i++) {\n        rc = session->read_zap_msg (&msg[i]);\n        if (rc == -1) {\n            if (errno == EAGAIN) {\n                return 1;\n            }\n            return close_and_return (msg, -1);\n        }\n        if ((msg[i].flags () & msg_t::more)\n            == (i < zap_reply_frame_count - 1 ? 0 : msg_t::more)) {\n            session->get_socket ()->event_handshake_failed_protocol (\n              session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY);\n            errno = EPROTO;\n            return close_and_return (msg, -1);\n        }\n    }\n\n    //  Address delimiter frame\n    if (msg[0].size () > 0) {\n        //  TODO can a ZAP handler produce such a message at all?\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED);\n        errno = EPROTO;\n        return close_and_return (msg, -1);\n    }\n\n    //  Version frame\n    if (msg[1].size () != zap_version_len\n        || memcmp (msg[1].data (), zap_version, zap_version_len)) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION);\n        errno = EPROTO;\n        return close_and_return (msg, -1);\n    }\n\n    //  Request id frame\n    if (msg[2].size () != id_len || memcmp (msg[2].data (), id, id_len)) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID);\n        errno = EPROTO;\n        return close_and_return (msg, -1);\n    }\n\n    //  Status code frame, only 200, 300, 400 and 500 are valid status codes\n    const char *status_code_data = static_cast<const char *> (msg[3].data ());\n    if (msg[3].size () != 3 || status_code_data[0] < '2'\n        || status_code_data[0] > '5' || status_code_data[1] != '0'\n        || status_code_data[2] != '0') {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE);\n        errno = EPROTO;\n        return close_and_return (msg, -1);\n    }\n\n    //  Save status code\n    status_code.assign (static_cast<char *> (msg[3].data ()), 3);\n\n    //  Save user id\n    set_user_id (msg[5].data (), msg[5].size ());\n\n    //  Process metadata frame\n    rc = parse_metadata (static_cast<const unsigned char *> (msg[6].data ()),\n                         msg[6].size (), true);\n\n    if (rc != 0) {\n        session->get_socket ()->event_handshake_failed_protocol (\n          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA);\n        errno = EPROTO;\n        return close_and_return (msg, -1);\n    }\n\n    //  Close all reply frames\n    for (size_t i = 0; i < zap_reply_frame_count; i++) {\n        const int rc2 = msg[i].close ();\n        errno_assert (rc2 == 0);\n    }\n\n    handle_zap_status_code ();\n\n    return 0;\n}\n\nvoid zap_client_t::handle_zap_status_code ()\n{\n    //  we can assume here that status_code is a valid ZAP status code,\n    //  i.e. 200, 300, 400 or 500\n    int status_code_numeric = 0;\n    switch (status_code[0]) {\n        case '2':\n            return;\n        case '3':\n            status_code_numeric = 300;\n            break;\n        case '4':\n            status_code_numeric = 400;\n            break;\n        case '5':\n            status_code_numeric = 500;\n            break;\n    }\n\n    session->get_socket ()->event_handshake_failed_auth (\n      session->get_endpoint (), status_code_numeric);\n}\n\nzap_client_common_handshake_t::zap_client_common_handshake_t (\n  session_base_t *const session_,\n  const std::string &peer_address_,\n  const options_t &options_,\n  state_t zap_reply_ok_state_) :\n    mechanism_base_t (session_, options_),\n    zap_client_t (session_, peer_address_, options_),\n    state (waiting_for_hello),\n    _zap_reply_ok_state (zap_reply_ok_state_)\n{\n}\n\nzmq::mechanism_t::status_t zap_client_common_handshake_t::status () const\n{\n    if (state == ready)\n        return mechanism_t::ready;\n    if (state == error_sent)\n        return mechanism_t::error;\n\n    return mechanism_t::handshaking;\n}\n\nint zap_client_common_handshake_t::zap_msg_available ()\n{\n    zmq_assert (state == waiting_for_zap_reply);\n    return receive_and_process_zap_reply () == -1 ? -1 : 0;\n}\n\nvoid zap_client_common_handshake_t::handle_zap_status_code ()\n{\n    zap_client_t::handle_zap_status_code ();\n\n    //  we can assume here that status_code is a valid ZAP status code,\n    //  i.e. 200, 300, 400 or 500\n    switch (status_code[0]) {\n        case '2':\n            state = _zap_reply_ok_state;\n            break;\n        case '3':\n            //  a 300 error code (temporary failure)\n            //  should NOT result in an ERROR message, but instead the\n            //  client should be silently disconnected (see CURVEZMQ RFC)\n            //  therefore, go immediately to state error_sent\n            state = error_sent;\n            break;\n        default:\n            state = sending_error;\n    }\n}\n\nint zap_client_common_handshake_t::receive_and_process_zap_reply ()\n{\n    zmq_assert (state == waiting_for_zap_reply);\n    return zap_client_t::receive_and_process_zap_reply ();\n}\n}\n"
  },
  {
    "path": "src/zap_client.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_ZAP_CLIENT_HPP_INCLUDED__\n#define __ZMQ_ZAP_CLIENT_HPP_INCLUDED__\n\n#include \"mechanism_base.hpp\"\n\nnamespace zmq\n{\nclass zap_client_t : public virtual mechanism_base_t\n{\n  public:\n    zap_client_t (session_base_t *session_,\n                  const std::string &peer_address_,\n                  const options_t &options_);\n\n    void send_zap_request (const char *mechanism_,\n                           size_t mechanism_length_,\n                           const uint8_t *credentials_,\n                           size_t credentials_size_);\n\n    void send_zap_request (const char *mechanism_,\n                           size_t mechanism_length_,\n                           const uint8_t **credentials_,\n                           size_t *credentials_sizes_,\n                           size_t credentials_count_);\n\n    virtual int receive_and_process_zap_reply ();\n    virtual void handle_zap_status_code ();\n\n  protected:\n    const std::string peer_address;\n\n    //  Status code as received from ZAP handler\n    std::string status_code;\n};\n\nclass zap_client_common_handshake_t : public zap_client_t\n{\n  protected:\n    enum state_t\n    {\n        waiting_for_hello,\n        sending_welcome,\n        waiting_for_initiate,\n        waiting_for_zap_reply,\n        sending_ready,\n        sending_error,\n        error_sent,\n        ready\n    };\n\n    zap_client_common_handshake_t (session_base_t *session_,\n                                   const std::string &peer_address_,\n                                   const options_t &options_,\n                                   state_t zap_reply_ok_state_);\n\n    //  methods from mechanism_t\n    status_t status () const ZMQ_FINAL;\n    int zap_msg_available () ZMQ_FINAL;\n\n    //  zap_client_t methods\n    int receive_and_process_zap_reply () ZMQ_FINAL;\n    void handle_zap_status_code () ZMQ_FINAL;\n\n    //  Current FSM state\n    state_t state;\n\n  private:\n    const state_t _zap_reply_ok_state;\n};\n}\n\n#endif\n"
  },
  {
    "path": "src/zmq.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n// \"Tell them I was a writer.\n//  A maker of software.\n//  A humanist. A father.\n//  And many things.\n//  But above all, a writer.\n//  Thank You. :)\"\n//  - Pieter Hintjens\n\n#include \"precompiled.hpp\"\n#define ZMQ_TYPE_UNSAFE\n\n#include \"macros.hpp\"\n#include \"poller.hpp\"\n#include \"peer.hpp\"\n\n#if !defined ZMQ_HAVE_POLLER\n//  On AIX platform, poll.h has to be included first to get consistent\n//  definition of pollfd structure (AIX uses 'reqevents' and 'retnevents'\n//  instead of 'events' and 'revents' and defines macros to map from POSIX-y\n//  names to AIX-specific names).\n#if defined ZMQ_POLL_BASED_ON_POLL && !defined ZMQ_HAVE_WINDOWS\n#include <poll.h>\n#endif\n\n#include \"polling_util.hpp\"\n#endif\n\n// TODO: determine if this is an issue, since zmq.h is being loaded from pch.\n// zmq.h must be included *after* poll.h for AIX to build properly\n//#include \"../include/zmq.h\"\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#ifdef ZMQ_HAVE_VXWORKS\n#include <strings.h>\n#endif\n#endif\n\n// XSI vector I/O\n#if defined ZMQ_HAVE_UIO\n#include <sys/uio.h>\n#else\nstruct iovec\n{\n    void *iov_base;\n    size_t iov_len;\n};\n#endif\n\n#include <string.h>\n#include <stdlib.h>\n#include <new>\n#include <climits>\n\n#include \"proxy.hpp\"\n#include \"socket_base.hpp\"\n#include \"stdint.hpp\"\n#include \"config.hpp\"\n#include \"likely.hpp\"\n#include \"clock.hpp\"\n#include \"ctx.hpp\"\n#include \"err.hpp\"\n#include \"msg.hpp\"\n#include \"fd.hpp\"\n#include \"metadata.hpp\"\n#include \"socket_poller.hpp\"\n#include \"timers.hpp\"\n#include \"ip.hpp\"\n#include \"address.hpp\"\n\n#ifdef ZMQ_HAVE_PPOLL\n#include \"polling_util.hpp\"\n#include <sys/select.h>\n#endif\n\n#if defined ZMQ_HAVE_OPENPGM\n#define __PGM_WININT_H__\n#include <pgm/pgm.h>\n#endif\n\n//  Compile time check whether msg_t fits into zmq_msg_t.\ntypedef char\n  check_msg_t_size[sizeof (zmq::msg_t) == sizeof (zmq_msg_t) ? 1 : -1];\n\n\nvoid zmq_version (int *major_, int *minor_, int *patch_)\n{\n    *major_ = ZMQ_VERSION_MAJOR;\n    *minor_ = ZMQ_VERSION_MINOR;\n    *patch_ = ZMQ_VERSION_PATCH;\n}\n\n\nconst char *zmq_strerror (int errnum_)\n{\n    return zmq::errno_to_string (errnum_);\n}\n\nint zmq_errno (void)\n{\n    return errno;\n}\n\n\n//  New context API\n\nvoid *zmq_ctx_new (void)\n{\n    //  We do this before the ctx constructor since its embedded mailbox_t\n    //  object needs the network to be up and running (at least on Windows).\n    if (!zmq::initialize_network ()) {\n        return NULL;\n    }\n\n    //  Create 0MQ context.\n    zmq::ctx_t *ctx = new (std::nothrow) zmq::ctx_t;\n    if (ctx) {\n        if (!ctx->valid ()) {\n            delete ctx;\n            return NULL;\n        }\n    }\n    return ctx;\n}\n\nint zmq_ctx_term (void *ctx_)\n{\n    if (!ctx_ || !(static_cast<zmq::ctx_t *> (ctx_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    const int rc = (static_cast<zmq::ctx_t *> (ctx_))->terminate ();\n    const int en = errno;\n\n    //  Shut down only if termination was not interrupted by a signal.\n    if (!rc || en != EINTR) {\n        zmq::shutdown_network ();\n    }\n\n    errno = en;\n    return rc;\n}\n\nint zmq_ctx_shutdown (void *ctx_)\n{\n    if (!ctx_ || !(static_cast<zmq::ctx_t *> (ctx_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n    return (static_cast<zmq::ctx_t *> (ctx_))->shutdown ();\n}\n\nint zmq_ctx_set (void *ctx_, int option_, int optval_)\n{\n    return zmq_ctx_set_ext (ctx_, option_, &optval_, sizeof (int));\n}\n\nint zmq_ctx_set_ext (void *ctx_,\n                     int option_,\n                     const void *optval_,\n                     size_t optvallen_)\n{\n    if (!ctx_ || !(static_cast<zmq::ctx_t *> (ctx_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n    return (static_cast<zmq::ctx_t *> (ctx_))\n      ->set (option_, optval_, optvallen_);\n}\n\nint zmq_ctx_get (void *ctx_, int option_)\n{\n    if (!ctx_ || !(static_cast<zmq::ctx_t *> (ctx_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n    return (static_cast<zmq::ctx_t *> (ctx_))->get (option_);\n}\n\nint zmq_ctx_get_ext (void *ctx_, int option_, void *optval_, size_t *optvallen_)\n{\n    if (!ctx_ || !(static_cast<zmq::ctx_t *> (ctx_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n    return (static_cast<zmq::ctx_t *> (ctx_))\n      ->get (option_, optval_, optvallen_);\n}\n\n\n//  Stable/legacy context API\n\nvoid *zmq_init (int io_threads_)\n{\n    if (io_threads_ >= 0) {\n        void *ctx = zmq_ctx_new ();\n        zmq_ctx_set (ctx, ZMQ_IO_THREADS, io_threads_);\n        return ctx;\n    }\n    errno = EINVAL;\n    return NULL;\n}\n\nint zmq_term (void *ctx_)\n{\n    return zmq_ctx_term (ctx_);\n}\n\nint zmq_ctx_destroy (void *ctx_)\n{\n    return zmq_ctx_term (ctx_);\n}\n\n\n// Sockets\n\nstatic zmq::socket_base_t *as_socket_base_t (void *s_)\n{\n    zmq::socket_base_t *s = static_cast<zmq::socket_base_t *> (s_);\n    if (!s_ || !s->check_tag ()) {\n        errno = ENOTSOCK;\n        return NULL;\n    }\n    return s;\n}\n\nvoid *zmq_socket (void *ctx_, int type_)\n{\n    if (!ctx_ || !(static_cast<zmq::ctx_t *> (ctx_))->check_tag ()) {\n        errno = EFAULT;\n        return NULL;\n    }\n    zmq::ctx_t *ctx = static_cast<zmq::ctx_t *> (ctx_);\n    zmq::socket_base_t *s = ctx->create_socket (type_);\n    return static_cast<void *> (s);\n}\n\nint zmq_close (void *s_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    s->close ();\n    return 0;\n}\n\nint zmq_setsockopt (void *s_,\n                    int option_,\n                    const void *optval_,\n                    size_t optvallen_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->setsockopt (option_, optval_, optvallen_);\n}\n\nint zmq_getsockopt (void *s_, int option_, void *optval_, size_t *optvallen_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->getsockopt (option_, optval_, optvallen_);\n}\n\nint zmq_socket_monitor_versioned (\n  void *s_, const char *addr_, uint64_t events_, int event_version_, int type_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->monitor (addr_, events_, event_version_, type_);\n}\n\nint zmq_socket_monitor (void *s_, const char *addr_, int events_)\n{\n    return zmq_socket_monitor_versioned (s_, addr_, events_, 1, ZMQ_PAIR);\n}\n\nint zmq_join (void *s_, const char *group_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->join (group_);\n}\n\nint zmq_leave (void *s_, const char *group_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->leave (group_);\n}\n\nint zmq_bind (void *s_, const char *addr_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->bind (addr_);\n}\n\nint zmq_connect (void *s_, const char *addr_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->connect (addr_);\n}\n\nuint32_t zmq_connect_peer (void *s_, const char *addr_)\n{\n    zmq::peer_t *s = static_cast<zmq::peer_t *> (s_);\n    if (!s_ || !s->check_tag ()) {\n        errno = ENOTSOCK;\n        return 0;\n    }\n\n    int socket_type;\n    size_t socket_type_size = sizeof (socket_type);\n    if (s->getsockopt (ZMQ_TYPE, &socket_type, &socket_type_size) != 0)\n        return 0;\n\n    if (socket_type != ZMQ_PEER) {\n        errno = ENOTSUP;\n        return 0;\n    }\n\n    return s->connect_peer (addr_);\n}\n\nint zmq_disconnect_peer (void *s_, uint32_t routing_id_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->disconnect_peer (routing_id_);\n}\n\n\nint zmq_unbind (void *s_, const char *addr_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->term_endpoint (addr_);\n}\n\nint zmq_disconnect (void *s_, const char *addr_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->term_endpoint (addr_);\n}\n\n// Sending functions.\n\nstatic inline int\ns_sendmsg (zmq::socket_base_t *s_, zmq_msg_t *msg_, int flags_)\n{\n    size_t sz = zmq_msg_size (msg_);\n    const int rc = s_->send (reinterpret_cast<zmq::msg_t *> (msg_), flags_);\n    if (unlikely (rc < 0))\n        return -1;\n\n    //  This is what I'd like to do, my C++ fu is too weak -- PH 2016/02/09\n    //  int max_msgsz = s_->parent->get (ZMQ_MAX_MSGSZ);\n    size_t max_msgsz = INT_MAX;\n\n    //  Truncate returned size to INT_MAX to avoid overflow to negative values\n    return static_cast<int> (sz < max_msgsz ? sz : max_msgsz);\n}\n\n/*  To be deprecated once zmq_msg_send() is stable                           */\nint zmq_sendmsg (void *s_, zmq_msg_t *msg_, int flags_)\n{\n    return zmq_msg_send (msg_, s_, flags_);\n}\n\nint zmq_send (void *s_, const void *buf_, size_t len_, int flags_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    zmq_msg_t msg;\n    int rc = zmq_msg_init_buffer (&msg, buf_, len_);\n    if (unlikely (rc < 0))\n        return -1;\n\n    rc = s_sendmsg (s, &msg, flags_);\n    if (unlikely (rc < 0)) {\n        const int err = errno;\n        const int rc2 = zmq_msg_close (&msg);\n        errno_assert (rc2 == 0);\n        errno = err;\n        return -1;\n    }\n    //  Note the optimisation here. We don't close the msg object as it is\n    //  empty anyway. This may change when implementation of zmq_msg_t changes.\n    return rc;\n}\n\nint zmq_send_const (void *s_, const void *buf_, size_t len_, int flags_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    zmq_msg_t msg;\n    int rc =\n      zmq_msg_init_data (&msg, const_cast<void *> (buf_), len_, NULL, NULL);\n    if (rc != 0)\n        return -1;\n\n    rc = s_sendmsg (s, &msg, flags_);\n    if (unlikely (rc < 0)) {\n        const int err = errno;\n        const int rc2 = zmq_msg_close (&msg);\n        errno_assert (rc2 == 0);\n        errno = err;\n        return -1;\n    }\n    //  Note the optimisation here. We don't close the msg object as it is\n    //  empty anyway. This may change when implementation of zmq_msg_t changes.\n    return rc;\n}\n\n\n// Send multiple messages.\n// TODO: this function has no man page\n//\n// If flag bit ZMQ_SNDMORE is set the vector is treated as\n// a single multi-part message, i.e. the last message has\n// ZMQ_SNDMORE bit switched off.\n//\nint zmq_sendiov (void *s_, iovec *a_, size_t count_, int flags_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    if (unlikely (count_ <= 0 || !a_)) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    int rc = 0;\n    zmq_msg_t msg;\n\n    for (size_t i = 0; i < count_; ++i) {\n        rc = zmq_msg_init_size (&msg, a_[i].iov_len);\n        if (rc != 0) {\n            rc = -1;\n            break;\n        }\n        memcpy (zmq_msg_data (&msg), a_[i].iov_base, a_[i].iov_len);\n        if (i == count_ - 1)\n            flags_ = flags_ & ~ZMQ_SNDMORE;\n        rc = s_sendmsg (s, &msg, flags_);\n        if (unlikely (rc < 0)) {\n            const int err = errno;\n            const int rc2 = zmq_msg_close (&msg);\n            errno_assert (rc2 == 0);\n            errno = err;\n            rc = -1;\n            break;\n        }\n    }\n    return rc;\n}\n\n// Receiving functions.\n\nstatic int s_recvmsg (zmq::socket_base_t *s_, zmq_msg_t *msg_, int flags_)\n{\n    const int rc = s_->recv (reinterpret_cast<zmq::msg_t *> (msg_), flags_);\n    if (unlikely (rc < 0))\n        return -1;\n\n    //  Truncate returned size to INT_MAX to avoid overflow to negative values\n    const size_t sz = zmq_msg_size (msg_);\n    return static_cast<int> (sz < INT_MAX ? sz : INT_MAX);\n}\n\n/*  To be deprecated once zmq_msg_recv() is stable                           */\nint zmq_recvmsg (void *s_, zmq_msg_t *msg_, int flags_)\n{\n    return zmq_msg_recv (msg_, s_, flags_);\n}\n\n\nint zmq_recv (void *s_, void *buf_, size_t len_, int flags_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    zmq_msg_t msg;\n    int rc = zmq_msg_init (&msg);\n    errno_assert (rc == 0);\n\n    const int nbytes = s_recvmsg (s, &msg, flags_);\n    if (unlikely (nbytes < 0)) {\n        const int err = errno;\n        rc = zmq_msg_close (&msg);\n        errno_assert (rc == 0);\n        errno = err;\n        return -1;\n    }\n\n    //  An oversized message is silently truncated.\n    const size_t to_copy = size_t (nbytes) < len_ ? size_t (nbytes) : len_;\n\n    //  We explicitly allow a null buffer argument if len is zero\n    if (to_copy) {\n        assert (buf_);\n        memcpy (buf_, zmq_msg_data (&msg), to_copy);\n    }\n    rc = zmq_msg_close (&msg);\n    errno_assert (rc == 0);\n\n    return nbytes;\n}\n\n// Receive a multi-part message\n//\n// Receives up to *count_ parts of a multi-part message.\n// Sets *count_ to the actual number of parts read.\n// ZMQ_RCVMORE is set to indicate if a complete multi-part message was read.\n// Returns number of message parts read, or -1 on error.\n//\n// Note: even if -1 is returned, some parts of the message\n// may have been read. Therefore the client must consult\n// *count_ to retrieve message parts successfully read,\n// even if -1 is returned.\n//\n// The iov_base* buffers of each iovec *a_ filled in by this\n// function may be freed using free().\n// TODO: this function has no man page\n//\nint zmq_recviov (void *s_, iovec *a_, size_t *count_, int flags_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    if (unlikely (!count_ || *count_ <= 0 || !a_)) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    const size_t count = *count_;\n    int nread = 0;\n    bool recvmore = true;\n\n    *count_ = 0;\n\n    for (size_t i = 0; recvmore && i < count; ++i) {\n        zmq_msg_t msg;\n        int rc = zmq_msg_init (&msg);\n        errno_assert (rc == 0);\n\n        const int nbytes = s_recvmsg (s, &msg, flags_);\n        if (unlikely (nbytes < 0)) {\n            const int err = errno;\n            rc = zmq_msg_close (&msg);\n            errno_assert (rc == 0);\n            errno = err;\n            nread = -1;\n            break;\n        }\n\n        a_[i].iov_len = zmq_msg_size (&msg);\n        a_[i].iov_base = static_cast<char *> (malloc (a_[i].iov_len));\n        if (unlikely (!a_[i].iov_base)) {\n            errno = ENOMEM;\n            return -1;\n        }\n        memcpy (a_[i].iov_base, static_cast<char *> (zmq_msg_data (&msg)),\n                a_[i].iov_len);\n        // Assume zmq_socket ZMQ_RVCMORE is properly set.\n        const zmq::msg_t *p_msg = reinterpret_cast<const zmq::msg_t *> (&msg);\n        recvmore = p_msg->flags () & zmq::msg_t::more;\n        rc = zmq_msg_close (&msg);\n        errno_assert (rc == 0);\n        ++*count_;\n        ++nread;\n    }\n    return nread;\n}\n\n// Message manipulators.\n\nint zmq_msg_init (zmq_msg_t *msg_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (msg_))->init ();\n}\n\nint zmq_msg_init_size (zmq_msg_t *msg_, size_t size_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (msg_))->init_size (size_);\n}\n\nint zmq_msg_init_buffer (zmq_msg_t *msg_, const void *buf_, size_t size_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (msg_))->init_buffer (buf_, size_);\n}\n\nint zmq_msg_init_data (\n  zmq_msg_t *msg_, void *data_, size_t size_, zmq_free_fn *ffn_, void *hint_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (msg_))\n      ->init_data (data_, size_, ffn_, hint_);\n}\n\nint zmq_msg_send (zmq_msg_t *msg_, void *s_, int flags_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s_sendmsg (s, msg_, flags_);\n}\n\nint zmq_msg_recv (zmq_msg_t *msg_, void *s_, int flags_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s_recvmsg (s, msg_, flags_);\n}\n\nint zmq_msg_close (zmq_msg_t *msg_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (msg_))->close ();\n}\n\nint zmq_msg_move (zmq_msg_t *dest_, zmq_msg_t *src_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (dest_))\n      ->move (*reinterpret_cast<zmq::msg_t *> (src_));\n}\n\nint zmq_msg_copy (zmq_msg_t *dest_, zmq_msg_t *src_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (dest_))\n      ->copy (*reinterpret_cast<zmq::msg_t *> (src_));\n}\n\nvoid *zmq_msg_data (zmq_msg_t *msg_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (msg_))->data ();\n}\n\nsize_t zmq_msg_size (const zmq_msg_t *msg_)\n{\n    return ((zmq::msg_t *) msg_)->size ();\n}\n\nint zmq_msg_more (const zmq_msg_t *msg_)\n{\n    return zmq_msg_get (msg_, ZMQ_MORE);\n}\n\nint zmq_msg_get (const zmq_msg_t *msg_, int property_)\n{\n    const char *fd_string;\n\n    switch (property_) {\n        case ZMQ_MORE:\n            return (((zmq::msg_t *) msg_)->flags () & zmq::msg_t::more) ? 1 : 0;\n        case ZMQ_SRCFD:\n            fd_string = zmq_msg_gets (msg_, \"__fd\");\n            if (fd_string == NULL)\n                return -1;\n\n            return atoi (fd_string);\n        case ZMQ_SHARED:\n            return (((zmq::msg_t *) msg_)->is_cmsg ())\n                       || (((zmq::msg_t *) msg_)->flags () & zmq::msg_t::shared)\n                     ? 1\n                     : 0;\n        default:\n            errno = EINVAL;\n            return -1;\n    }\n}\n\nint zmq_msg_set (zmq_msg_t *, int, int)\n{\n    //  No properties supported at present\n    errno = EINVAL;\n    return -1;\n}\n\nint zmq_msg_set_routing_id (zmq_msg_t *msg_, uint32_t routing_id_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (msg_))\n      ->set_routing_id (routing_id_);\n}\n\nuint32_t zmq_msg_routing_id (zmq_msg_t *msg_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (msg_))->get_routing_id ();\n}\n\nint zmq_msg_set_group (zmq_msg_t *msg_, const char *group_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (msg_))->set_group (group_);\n}\n\nconst char *zmq_msg_group (zmq_msg_t *msg_)\n{\n    return (reinterpret_cast<zmq::msg_t *> (msg_))->group ();\n}\n\n//  Get message metadata string\n\nconst char *zmq_msg_gets (const zmq_msg_t *msg_, const char *property_)\n{\n    const zmq::metadata_t *metadata =\n      reinterpret_cast<const zmq::msg_t *> (msg_)->metadata ();\n    const char *value = NULL;\n    if (metadata)\n        value = metadata->get (std::string (property_));\n    if (value)\n        return value;\n\n    errno = EINVAL;\n    return NULL;\n}\n\n// Polling.\n\n#if defined ZMQ_HAVE_POLLER\nstatic int zmq_poller_poll (zmq_pollitem_t *items_, int nitems_, long timeout_)\n{\n    // implement zmq_poll on top of zmq_poller\n    int rc;\n    zmq_poller_event_t *events;\n    zmq::socket_poller_t poller;\n    events = new (std::nothrow) zmq_poller_event_t[nitems_];\n    alloc_assert (events);\n\n    bool repeat_items = false;\n    //  Register sockets with poller\n    for (int i = 0; i < nitems_; i++) {\n        items_[i].revents = 0;\n\n        bool modify = false;\n        short e = items_[i].events;\n        if (items_[i].socket) {\n            //  Poll item is a 0MQ socket.\n            for (int j = 0; j < i; ++j) {\n                // Check for repeat entries\n                if (items_[j].socket == items_[i].socket) {\n                    repeat_items = true;\n                    modify = true;\n                    e |= items_[j].events;\n                }\n            }\n            if (modify) {\n                rc = zmq_poller_modify (&poller, items_[i].socket, e);\n            } else {\n                rc = zmq_poller_add (&poller, items_[i].socket, NULL, e);\n            }\n            if (rc < 0) {\n                delete[] events;\n                return rc;\n            }\n        } else {\n            //  Poll item is a raw file descriptor.\n            for (int j = 0; j < i; ++j) {\n                // Check for repeat entries\n                if (!items_[j].socket && items_[j].fd == items_[i].fd) {\n                    repeat_items = true;\n                    modify = true;\n                    e |= items_[j].events;\n                }\n            }\n            if (modify) {\n                rc = zmq_poller_modify_fd (&poller, items_[i].fd, e);\n            } else {\n                rc = zmq_poller_add_fd (&poller, items_[i].fd, NULL, e);\n            }\n            if (rc < 0) {\n                delete[] events;\n                return rc;\n            }\n        }\n    }\n\n    //  Wait for events\n    rc = zmq_poller_wait_all (&poller, events, nitems_, timeout_);\n    if (rc < 0) {\n        delete[] events;\n        if (zmq_errno () == EAGAIN) {\n            return 0;\n        }\n        return rc;\n    }\n\n    //  Transform poller events into zmq_pollitem events.\n    //  items_ contains all items, while events only contains fired events.\n    //  If no sockets are repeated (likely), the two are still co-ordered, so step through the items\n    //  checking for matches only on the first event.\n    //  If there are repeat items, they cannot be assumed to be co-ordered,\n    //  so each pollitem must check fired events from the beginning.\n    int j_start = 0, found_events = rc;\n    for (int i = 0; i < nitems_; i++) {\n        for (int j = j_start; j < found_events; ++j) {\n            if ((items_[i].socket && items_[i].socket == events[j].socket)\n                || (!(items_[i].socket || events[j].socket)\n                    && items_[i].fd == events[j].fd)) {\n                items_[i].revents = events[j].events & items_[i].events;\n                if (!repeat_items) {\n                    // no repeats, we can ignore events we've already seen\n                    j_start++;\n                }\n                break;\n            }\n            if (!repeat_items) {\n                // no repeats, never have to look at j > j_start\n                break;\n            }\n        }\n    }\n\n    //  Cleanup\n    delete[] events;\n    return rc;\n}\n#endif // ZMQ_HAVE_POLLER\n\nint zmq_poll (zmq_pollitem_t *items_, int nitems_, long timeout_)\n{\n#if defined ZMQ_HAVE_POLLER\n    // if poller is present, use that if there is at least 1 thread-safe socket,\n    // otherwise fall back to the previous implementation as it's faster.\n    for (int i = 0; i != nitems_; i++) {\n        if (items_[i].socket) {\n            zmq::socket_base_t *s = as_socket_base_t (items_[i].socket);\n            if (s) {\n                if (s->is_thread_safe ())\n                    return zmq_poller_poll (items_, nitems_, timeout_);\n            } else {\n                //as_socket_base_t returned NULL : socket is invalid\n                return -1;\n            }\n        }\n    }\n#endif // ZMQ_HAVE_POLLER\n#if defined ZMQ_POLL_BASED_ON_POLL || defined ZMQ_POLL_BASED_ON_SELECT\n    if (unlikely (nitems_ < 0)) {\n        errno = EINVAL;\n        return -1;\n    }\n    if (unlikely (nitems_ == 0)) {\n        if (timeout_ == 0)\n            return 0;\n#if defined ZMQ_HAVE_WINDOWS\n        Sleep (timeout_ > 0 ? timeout_ : INFINITE);\n        return 0;\n#elif defined ZMQ_HAVE_VXWORKS\n        struct timespec ns_;\n        ns_.tv_sec = timeout_ / 1000;\n        ns_.tv_nsec = timeout_ % 1000 * 1000000;\n        return nanosleep (&ns_, 0);\n#else\n        return usleep (timeout_ * 1000);\n#endif\n    }\n    if (!items_) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    zmq::clock_t clock;\n    uint64_t now = 0;\n    uint64_t end = 0;\n#if defined ZMQ_POLL_BASED_ON_POLL\n    zmq::fast_vector_t<pollfd, ZMQ_POLLITEMS_DFLT> pollfds (nitems_);\n\n    //  Build pollset for poll () system call.\n    for (int i = 0; i != nitems_; i++) {\n        //  If the poll item is a 0MQ socket, we poll on the file descriptor\n        //  retrieved by the ZMQ_FD socket option.\n        if (items_[i].socket) {\n            size_t zmq_fd_size = sizeof (zmq::fd_t);\n            if (zmq_getsockopt (items_[i].socket, ZMQ_FD, &pollfds[i].fd,\n                                &zmq_fd_size)\n                == -1) {\n                return -1;\n            }\n            pollfds[i].events = items_[i].events ? POLLIN : 0;\n        }\n        //  Else, the poll item is a raw file descriptor. Just convert the\n        //  events to normal POLLIN/POLLOUT for poll ().\n        else {\n            pollfds[i].fd = items_[i].fd;\n            pollfds[i].events =\n              (items_[i].events & ZMQ_POLLIN ? POLLIN : 0)\n              | (items_[i].events & ZMQ_POLLOUT ? POLLOUT : 0)\n              | (items_[i].events & ZMQ_POLLPRI ? POLLPRI : 0);\n        }\n    }\n#else\n    //  Ensure we do not attempt to select () on more than FD_SETSIZE\n    //  file descriptors.\n    //  TODO since this function is called by a client, we could return errno EINVAL/ENOMEM/... here\n    zmq_assert (nitems_ <= FD_SETSIZE);\n\n    zmq::optimized_fd_set_t pollset_in (nitems_);\n    FD_ZERO (pollset_in.get ());\n    zmq::optimized_fd_set_t pollset_out (nitems_);\n    FD_ZERO (pollset_out.get ());\n    zmq::optimized_fd_set_t pollset_err (nitems_);\n    FD_ZERO (pollset_err.get ());\n\n    zmq::fd_t maxfd = 0;\n\n    //  Build the fd_sets for passing to select ().\n    for (int i = 0; i != nitems_; i++) {\n        //  If the poll item is a 0MQ socket we are interested in input on the\n        //  notification file descriptor retrieved by the ZMQ_FD socket option.\n        if (items_[i].socket) {\n            size_t zmq_fd_size = sizeof (zmq::fd_t);\n            zmq::fd_t notify_fd;\n            if (zmq_getsockopt (items_[i].socket, ZMQ_FD, &notify_fd,\n                                &zmq_fd_size)\n                == -1)\n                return -1;\n            if (items_[i].events) {\n                FD_SET (notify_fd, pollset_in.get ());\n                if (maxfd < notify_fd)\n                    maxfd = notify_fd;\n            }\n        }\n        //  Else, the poll item is a raw file descriptor. Convert the poll item\n        //  events to the appropriate fd_sets.\n        else {\n            if (items_[i].events & ZMQ_POLLIN)\n                FD_SET (items_[i].fd, pollset_in.get ());\n            if (items_[i].events & ZMQ_POLLOUT)\n                FD_SET (items_[i].fd, pollset_out.get ());\n            if (items_[i].events & ZMQ_POLLERR)\n                FD_SET (items_[i].fd, pollset_err.get ());\n            if (maxfd < items_[i].fd)\n                maxfd = items_[i].fd;\n        }\n    }\n\n    zmq::optimized_fd_set_t inset (nitems_);\n    zmq::optimized_fd_set_t outset (nitems_);\n    zmq::optimized_fd_set_t errset (nitems_);\n#endif\n\n    bool first_pass = true;\n    int nevents = 0;\n\n    while (true) {\n#if defined ZMQ_POLL_BASED_ON_POLL\n\n        //  Compute the timeout for the subsequent poll.\n        const zmq::timeout_t timeout =\n          zmq::compute_timeout (first_pass, timeout_, now, end);\n\n        //  Wait for events.\n        {\n            const int rc = poll (&pollfds[0], nitems_, timeout);\n            if (rc == -1 && errno == EINTR) {\n                return -1;\n            }\n            errno_assert (rc >= 0);\n        }\n        //  Check for the events.\n        for (int i = 0; i != nitems_; i++) {\n            items_[i].revents = 0;\n\n            //  The poll item is a 0MQ socket. Retrieve pending events\n            //  using the ZMQ_EVENTS socket option.\n            if (items_[i].socket) {\n                size_t zmq_events_size = sizeof (uint32_t);\n                uint32_t zmq_events;\n                if (zmq_getsockopt (items_[i].socket, ZMQ_EVENTS, &zmq_events,\n                                    &zmq_events_size)\n                    == -1) {\n                    return -1;\n                }\n                if ((items_[i].events & ZMQ_POLLOUT)\n                    && (zmq_events & ZMQ_POLLOUT))\n                    items_[i].revents |= ZMQ_POLLOUT;\n                if ((items_[i].events & ZMQ_POLLIN)\n                    && (zmq_events & ZMQ_POLLIN))\n                    items_[i].revents |= ZMQ_POLLIN;\n            }\n            //  Else, the poll item is a raw file descriptor, simply convert\n            //  the events to zmq_pollitem_t-style format.\n            else {\n                if (pollfds[i].revents & POLLIN)\n                    items_[i].revents |= ZMQ_POLLIN;\n                if (pollfds[i].revents & POLLOUT)\n                    items_[i].revents |= ZMQ_POLLOUT;\n                if (pollfds[i].revents & POLLPRI)\n                    items_[i].revents |= ZMQ_POLLPRI;\n                if (pollfds[i].revents & ~(POLLIN | POLLOUT | POLLPRI))\n                    items_[i].revents |= ZMQ_POLLERR;\n            }\n\n            if (items_[i].revents)\n                nevents++;\n        }\n\n#else\n\n        //  Compute the timeout for the subsequent poll.\n        timeval timeout;\n        timeval *ptimeout;\n        if (first_pass) {\n            timeout.tv_sec = 0;\n            timeout.tv_usec = 0;\n            ptimeout = &timeout;\n        } else if (timeout_ < 0)\n            ptimeout = NULL;\n        else {\n            timeout.tv_sec = static_cast<long> ((end - now) / 1000);\n            timeout.tv_usec = static_cast<long> ((end - now) % 1000 * 1000);\n            ptimeout = &timeout;\n        }\n\n        //  Wait for events. Ignore interrupts if there's infinite timeout.\n        while (true) {\n            memcpy (inset.get (), pollset_in.get (),\n                    zmq::valid_pollset_bytes (*pollset_in.get ()));\n            memcpy (outset.get (), pollset_out.get (),\n                    zmq::valid_pollset_bytes (*pollset_out.get ()));\n            memcpy (errset.get (), pollset_err.get (),\n                    zmq::valid_pollset_bytes (*pollset_err.get ()));\n#if defined ZMQ_HAVE_WINDOWS\n            int rc =\n              select (0, inset.get (), outset.get (), errset.get (), ptimeout);\n            if (unlikely (rc == SOCKET_ERROR)) {\n                errno = zmq::wsa_error_to_errno (WSAGetLastError ());\n                wsa_assert (errno == ENOTSOCK);\n                return -1;\n            }\n#else\n            int rc = select (maxfd + 1, inset.get (), outset.get (),\n                             errset.get (), ptimeout);\n            if (unlikely (rc == -1)) {\n                errno_assert (errno == EINTR || errno == EBADF);\n                return -1;\n            }\n#endif\n            break;\n        }\n\n        //  Check for the events.\n        for (int i = 0; i != nitems_; i++) {\n            items_[i].revents = 0;\n\n            //  The poll item is a 0MQ socket. Retrieve pending events\n            //  using the ZMQ_EVENTS socket option.\n            if (items_[i].socket) {\n                size_t zmq_events_size = sizeof (uint32_t);\n                uint32_t zmq_events;\n                if (zmq_getsockopt (items_[i].socket, ZMQ_EVENTS, &zmq_events,\n                                    &zmq_events_size)\n                    == -1)\n                    return -1;\n                if ((items_[i].events & ZMQ_POLLOUT)\n                    && (zmq_events & ZMQ_POLLOUT))\n                    items_[i].revents |= ZMQ_POLLOUT;\n                if ((items_[i].events & ZMQ_POLLIN)\n                    && (zmq_events & ZMQ_POLLIN))\n                    items_[i].revents |= ZMQ_POLLIN;\n            }\n            //  Else, the poll item is a raw file descriptor, simply convert\n            //  the events to zmq_pollitem_t-style format.\n            else {\n                if (FD_ISSET (items_[i].fd, inset.get ()))\n                    items_[i].revents |= ZMQ_POLLIN;\n                if (FD_ISSET (items_[i].fd, outset.get ()))\n                    items_[i].revents |= ZMQ_POLLOUT;\n                if (FD_ISSET (items_[i].fd, errset.get ()))\n                    items_[i].revents |= ZMQ_POLLERR;\n            }\n\n            if (items_[i].revents)\n                nevents++;\n        }\n#endif\n\n        //  If timeout is zero, exit immediately whether there are events or not.\n        if (timeout_ == 0)\n            break;\n\n        //  If there are events to return, we can exit immediately.\n        if (nevents)\n            break;\n\n        //  At this point we are meant to wait for events but there are none.\n        //  If timeout is infinite we can just loop until we get some events.\n        if (timeout_ < 0) {\n            if (first_pass)\n                first_pass = false;\n            continue;\n        }\n\n        //  The timeout is finite and there are no events. In the first pass\n        //  we get a timestamp of when the polling have begun. (We assume that\n        //  first pass have taken negligible time). We also compute the time\n        //  when the polling should time out.\n        if (first_pass) {\n            now = clock.now_ms ();\n            end = now + timeout_;\n            if (now == end)\n                break;\n            first_pass = false;\n            continue;\n        }\n\n        //  Find out whether timeout have expired.\n        now = clock.now_ms ();\n        if (now >= end)\n            break;\n    }\n\n    return nevents;\n#else\n    //  Exotic platforms that support neither poll() nor select().\n    errno = ENOTSUP;\n    return -1;\n#endif\n}\n\n#ifdef ZMQ_HAVE_PPOLL\n// return values of 0 or -1 should be returned from zmq_poll; return value 1 means items passed checks\nint zmq_poll_check_items_ (zmq_pollitem_t *items_, int nitems_, long timeout_)\n{\n    if (unlikely (nitems_ < 0)) {\n        errno = EINVAL;\n        return -1;\n    }\n    if (unlikely (nitems_ == 0)) {\n        if (timeout_ == 0)\n            return 0;\n#if defined ZMQ_HAVE_WINDOWS\n        Sleep (timeout_ > 0 ? timeout_ : INFINITE);\n        return 0;\n#elif defined ZMQ_HAVE_VXWORKS\n        struct timespec ns_;\n        ns_.tv_sec = timeout_ / 1000;\n        ns_.tv_nsec = timeout_ % 1000 * 1000000;\n        return nanosleep (&ns_, 0);\n#else\n        return usleep (timeout_ * 1000);\n#endif\n    }\n    if (!items_) {\n        errno = EFAULT;\n        return -1;\n    }\n    return 1;\n}\n\nstruct zmq_poll_select_fds_t_\n{\n    explicit zmq_poll_select_fds_t_ (int nitems_) :\n        pollset_in (nitems_),\n        pollset_out (nitems_),\n        pollset_err (nitems_),\n        inset (nitems_),\n        outset (nitems_),\n        errset (nitems_),\n        maxfd (0)\n    {\n        FD_ZERO (pollset_in.get ());\n        FD_ZERO (pollset_out.get ());\n        FD_ZERO (pollset_err.get ());\n    }\n\n    zmq::optimized_fd_set_t pollset_in;\n    zmq::optimized_fd_set_t pollset_out;\n    zmq::optimized_fd_set_t pollset_err;\n    zmq::optimized_fd_set_t inset;\n    zmq::optimized_fd_set_t outset;\n    zmq::optimized_fd_set_t errset;\n    zmq::fd_t maxfd;\n};\n\nzmq_poll_select_fds_t_\nzmq_poll_build_select_fds_ (zmq_pollitem_t *items_, int nitems_, int &rc)\n{\n    //  Ensure we do not attempt to select () on more than FD_SETSIZE\n    //  file descriptors.\n    //  TODO since this function is called by a client, we could return errno EINVAL/ENOMEM/... here\n    zmq_assert (nitems_ <= FD_SETSIZE);\n\n    zmq_poll_select_fds_t_ fds (nitems_);\n\n    //  Build the fd_sets for passing to select ().\n    for (int i = 0; i != nitems_; i++) {\n        //  If the poll item is a 0MQ socket we are interested in input on the\n        //  notification file descriptor retrieved by the ZMQ_FD socket option.\n        if (items_[i].socket) {\n            size_t zmq_fd_size = sizeof (zmq::fd_t);\n            zmq::fd_t notify_fd;\n            if (zmq_getsockopt (items_[i].socket, ZMQ_FD, &notify_fd,\n                                &zmq_fd_size)\n                == -1) {\n                rc = -1;\n                return fds;\n            }\n            if (items_[i].events) {\n                FD_SET (notify_fd, fds.pollset_in.get ());\n                if (fds.maxfd < notify_fd)\n                    fds.maxfd = notify_fd;\n            }\n        }\n        //  Else, the poll item is a raw file descriptor. Convert the poll item\n        //  events to the appropriate fd_sets.\n        else {\n            if (items_[i].events & ZMQ_POLLIN)\n                FD_SET (items_[i].fd, fds.pollset_in.get ());\n            if (items_[i].events & ZMQ_POLLOUT)\n                FD_SET (items_[i].fd, fds.pollset_out.get ());\n            if (items_[i].events & ZMQ_POLLERR)\n                FD_SET (items_[i].fd, fds.pollset_err.get ());\n            if (fds.maxfd < items_[i].fd)\n                fds.maxfd = items_[i].fd;\n        }\n    }\n\n    rc = 0;\n    return fds;\n}\n\ntimeval *zmq_poll_select_set_timeout_ (\n  long timeout_, bool first_pass, uint64_t now, uint64_t end, timeval &timeout)\n{\n    timeval *ptimeout;\n    if (first_pass) {\n        timeout.tv_sec = 0;\n        timeout.tv_usec = 0;\n        ptimeout = &timeout;\n    } else if (timeout_ < 0)\n        ptimeout = NULL;\n    else {\n        timeout.tv_sec = static_cast<long> ((end - now) / 1000);\n        timeout.tv_usec = static_cast<long> ((end - now) % 1000 * 1000);\n        ptimeout = &timeout;\n    }\n    return ptimeout;\n}\n\ntimespec *zmq_poll_select_set_timeout_ (\n  long timeout_, bool first_pass, uint64_t now, uint64_t end, timespec &timeout)\n{\n    timespec *ptimeout;\n    if (first_pass) {\n        timeout.tv_sec = 0;\n        timeout.tv_nsec = 0;\n        ptimeout = &timeout;\n    } else if (timeout_ < 0)\n        ptimeout = NULL;\n    else {\n        timeout.tv_sec = static_cast<long> ((end - now) / 1000);\n        timeout.tv_nsec = static_cast<long> ((end - now) % 1000 * 1000000);\n        ptimeout = &timeout;\n    }\n    return ptimeout;\n}\n\nint zmq_poll_select_check_events_ (zmq_pollitem_t *items_,\n                                   int nitems_,\n                                   zmq_poll_select_fds_t_ &fds,\n                                   int &nevents)\n{\n    //  Check for the events.\n    for (int i = 0; i != nitems_; i++) {\n        items_[i].revents = 0;\n\n        //  The poll item is a 0MQ socket. Retrieve pending events\n        //  using the ZMQ_EVENTS socket option.\n        if (items_[i].socket) {\n            size_t zmq_events_size = sizeof (uint32_t);\n            uint32_t zmq_events;\n            if (zmq_getsockopt (items_[i].socket, ZMQ_EVENTS, &zmq_events,\n                                &zmq_events_size)\n                == -1)\n                return -1;\n            if ((items_[i].events & ZMQ_POLLOUT) && (zmq_events & ZMQ_POLLOUT))\n                items_[i].revents |= ZMQ_POLLOUT;\n            if ((items_[i].events & ZMQ_POLLIN) && (zmq_events & ZMQ_POLLIN))\n                items_[i].revents |= ZMQ_POLLIN;\n        }\n        //  Else, the poll item is a raw file descriptor, simply convert\n        //  the events to zmq_pollitem_t-style format.\n        else {\n            if (FD_ISSET (items_[i].fd, fds.inset.get ()))\n                items_[i].revents |= ZMQ_POLLIN;\n            if (FD_ISSET (items_[i].fd, fds.outset.get ()))\n                items_[i].revents |= ZMQ_POLLOUT;\n            if (FD_ISSET (items_[i].fd, fds.errset.get ()))\n                items_[i].revents |= ZMQ_POLLERR;\n        }\n\n        if (items_[i].revents)\n            nevents++;\n    }\n\n    return 0;\n}\n\nbool zmq_poll_must_break_loop_ (long timeout_,\n                                int nevents,\n                                bool &first_pass,\n                                zmq::clock_t &clock,\n                                uint64_t &now,\n                                uint64_t &end)\n{\n    //  If timeout is zero, exit immediately whether there are events or not.\n    if (timeout_ == 0)\n        return true;\n\n    //  If there are events to return, we can exit immediately.\n    if (nevents)\n        return true;\n\n    //  At this point we are meant to wait for events but there are none.\n    //  If timeout is infinite we can just loop until we get some events.\n    if (timeout_ < 0) {\n        if (first_pass)\n            first_pass = false;\n        return false;\n    }\n\n    //  The timeout is finite and there are no events. In the first pass\n    //  we get a timestamp of when the polling have begun. (We assume that\n    //  first pass have taken negligible time). We also compute the time\n    //  when the polling should time out.\n    if (first_pass) {\n        now = clock.now_ms ();\n        end = now + timeout_;\n        if (now == end)\n            return true;\n        first_pass = false;\n        return false;\n    }\n\n    //  Find out whether timeout have expired.\n    now = clock.now_ms ();\n    if (now >= end)\n        return true;\n\n    // finally, in all other cases, we just continue\n    return false;\n}\n#endif // ZMQ_HAVE_PPOLL\n\n#if !defined _WIN32\nint zmq_ppoll (zmq_pollitem_t *items_,\n               int nitems_,\n               long timeout_,\n               const sigset_t *sigmask_)\n#else\n// Windows has no sigset_t\nint zmq_ppoll (zmq_pollitem_t *items_,\n               int nitems_,\n               long timeout_,\n               const void *sigmask_)\n#endif\n{\n#ifdef ZMQ_HAVE_PPOLL\n    int rc = zmq_poll_check_items_ (items_, nitems_, timeout_);\n    if (rc <= 0) {\n        return rc;\n    }\n\n    zmq::clock_t clock;\n    uint64_t now = 0;\n    uint64_t end = 0;\n    zmq_poll_select_fds_t_ fds =\n      zmq_poll_build_select_fds_ (items_, nitems_, rc);\n    if (rc == -1) {\n        return -1;\n    }\n\n    bool first_pass = true;\n    int nevents = 0;\n\n    while (true) {\n        //  Compute the timeout for the subsequent poll.\n        timespec timeout;\n        timespec *ptimeout = zmq_poll_select_set_timeout_ (timeout_, first_pass,\n                                                           now, end, timeout);\n\n        //  Wait for events. Ignore interrupts if there's infinite timeout.\n        while (true) {\n            memcpy (fds.inset.get (), fds.pollset_in.get (),\n                    zmq::valid_pollset_bytes (*fds.pollset_in.get ()));\n            memcpy (fds.outset.get (), fds.pollset_out.get (),\n                    zmq::valid_pollset_bytes (*fds.pollset_out.get ()));\n            memcpy (fds.errset.get (), fds.pollset_err.get (),\n                    zmq::valid_pollset_bytes (*fds.pollset_err.get ()));\n            int rc =\n              pselect (fds.maxfd + 1, fds.inset.get (), fds.outset.get (),\n                       fds.errset.get (), ptimeout, sigmask_);\n            if (unlikely (rc == -1)) {\n                errno_assert (errno == EINTR || errno == EBADF);\n                return -1;\n            }\n            break;\n        }\n\n        rc = zmq_poll_select_check_events_ (items_, nitems_, fds, nevents);\n        if (rc < 0) {\n            return rc;\n        }\n\n        if (zmq_poll_must_break_loop_ (timeout_, nevents, first_pass, clock,\n                                       now, end)) {\n            break;\n        }\n    }\n\n    return nevents;\n#else\n    errno = ENOTSUP;\n    return -1;\n#endif // ZMQ_HAVE_PPOLL\n}\n\n//  The poller functionality\n\nvoid *zmq_poller_new (void)\n{\n    zmq::socket_poller_t *poller = new (std::nothrow) zmq::socket_poller_t;\n    if (!poller) {\n        errno = ENOMEM;\n    }\n    return poller;\n}\n\nint zmq_poller_destroy (void **poller_p_)\n{\n    if (poller_p_) {\n        const zmq::socket_poller_t *const poller =\n          static_cast<const zmq::socket_poller_t *> (*poller_p_);\n        if (poller && poller->check_tag ()) {\n            delete poller;\n            *poller_p_ = NULL;\n            return 0;\n        }\n    }\n    errno = EFAULT;\n    return -1;\n}\n\n\nstatic int check_poller (void *const poller_)\n{\n    if (!poller_\n        || !(static_cast<zmq::socket_poller_t *> (poller_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    return 0;\n}\n\nstatic int check_events (const short events_)\n{\n    if (events_ & ~(ZMQ_POLLIN | ZMQ_POLLOUT | ZMQ_POLLERR | ZMQ_POLLPRI)) {\n        errno = EINVAL;\n        return -1;\n    }\n    return 0;\n}\n\nstatic int check_poller_registration_args (void *const poller_, void *const s_)\n{\n    if (-1 == check_poller (poller_))\n        return -1;\n\n    if (!s_ || !(static_cast<zmq::socket_base_t *> (s_))->check_tag ()) {\n        errno = ENOTSOCK;\n        return -1;\n    }\n\n    return 0;\n}\n\nstatic int check_poller_fd_registration_args (void *const poller_,\n                                              const zmq::fd_t fd_)\n{\n    if (-1 == check_poller (poller_))\n        return -1;\n\n    if (fd_ == zmq::retired_fd) {\n        errno = EBADF;\n        return -1;\n    }\n\n    return 0;\n}\n\nint zmq_poller_size (void *poller_)\n{\n    if (-1 == check_poller (poller_))\n        return -1;\n\n    return (static_cast<zmq::socket_poller_t *> (poller_))->size ();\n}\n\nint zmq_poller_add (void *poller_, void *s_, void *user_data_, short events_)\n{\n    if (-1 == check_poller_registration_args (poller_, s_)\n        || -1 == check_events (events_))\n        return -1;\n\n    zmq::socket_base_t *socket = static_cast<zmq::socket_base_t *> (s_);\n\n    return (static_cast<zmq::socket_poller_t *> (poller_))\n      ->add (socket, user_data_, events_);\n}\n\nint zmq_poller_add_fd (void *poller_,\n                       zmq::fd_t fd_,\n                       void *user_data_,\n                       short events_)\n{\n    if (-1 == check_poller_fd_registration_args (poller_, fd_)\n        || -1 == check_events (events_))\n        return -1;\n\n    return (static_cast<zmq::socket_poller_t *> (poller_))\n      ->add_fd (fd_, user_data_, events_);\n}\n\n\nint zmq_poller_modify (void *poller_, void *s_, short events_)\n{\n    if (-1 == check_poller_registration_args (poller_, s_)\n        || -1 == check_events (events_))\n        return -1;\n\n    const zmq::socket_base_t *const socket =\n      static_cast<const zmq::socket_base_t *> (s_);\n\n    return (static_cast<zmq::socket_poller_t *> (poller_))\n      ->modify (socket, events_);\n}\n\nint zmq_poller_modify_fd (void *poller_, zmq::fd_t fd_, short events_)\n{\n    if (-1 == check_poller_fd_registration_args (poller_, fd_)\n        || -1 == check_events (events_))\n        return -1;\n\n    return (static_cast<zmq::socket_poller_t *> (poller_))\n      ->modify_fd (fd_, events_);\n}\n\nint zmq_poller_remove (void *poller_, void *s_)\n{\n    if (-1 == check_poller_registration_args (poller_, s_))\n        return -1;\n\n    zmq::socket_base_t *socket = static_cast<zmq::socket_base_t *> (s_);\n\n    return (static_cast<zmq::socket_poller_t *> (poller_))->remove (socket);\n}\n\nint zmq_poller_remove_fd (void *poller_, zmq::fd_t fd_)\n{\n    if (-1 == check_poller_fd_registration_args (poller_, fd_))\n        return -1;\n\n    return (static_cast<zmq::socket_poller_t *> (poller_))->remove_fd (fd_);\n}\n\nint zmq_poller_wait (void *poller_, zmq_poller_event_t *event_, long timeout_)\n{\n    const int rc = zmq_poller_wait_all (poller_, event_, 1, timeout_);\n\n    if (rc < 0 && event_) {\n        event_->socket = NULL;\n        event_->fd = zmq::retired_fd;\n        event_->user_data = NULL;\n        event_->events = 0;\n    }\n    // wait_all returns number of events, but we return 0 for any success\n    return rc >= 0 ? 0 : rc;\n}\n\nint zmq_poller_wait_all (void *poller_,\n                         zmq_poller_event_t *events_,\n                         int n_events_,\n                         long timeout_)\n{\n    if (-1 == check_poller (poller_))\n        return -1;\n\n    if (!events_) {\n        errno = EFAULT;\n        return -1;\n    }\n    if (n_events_ < 0) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    const int rc =\n      (static_cast<zmq::socket_poller_t *> (poller_))\n        ->wait (reinterpret_cast<zmq::socket_poller_t::event_t *> (events_),\n                n_events_, timeout_);\n\n    return rc;\n}\n\nint zmq_poller_fd (void *poller_, zmq_fd_t *fd_)\n{\n    if (!poller_\n        || !(static_cast<zmq::socket_poller_t *> (poller_)->check_tag ())) {\n        errno = EFAULT;\n        return -1;\n    }\n    return static_cast<zmq::socket_poller_t *> (poller_)->signaler_fd (fd_);\n}\n\n//  Peer-specific state\n\nint zmq_socket_get_peer_state (void *s_,\n                               const void *routing_id_,\n                               size_t routing_id_size_)\n{\n    const zmq::socket_base_t *const s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n\n    return s->get_peer_state (routing_id_, routing_id_size_);\n}\n\n//  Timers\n\nvoid *zmq_timers_new (void)\n{\n    zmq::timers_t *timers = new (std::nothrow) zmq::timers_t;\n    alloc_assert (timers);\n    return timers;\n}\n\nint zmq_timers_destroy (void **timers_p_)\n{\n    void *timers = *timers_p_;\n    if (!timers || !(static_cast<zmq::timers_t *> (timers))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n    delete (static_cast<zmq::timers_t *> (timers));\n    *timers_p_ = NULL;\n    return 0;\n}\n\nint zmq_timers_add (void *timers_,\n                    size_t interval_,\n                    zmq_timer_fn handler_,\n                    void *arg_)\n{\n    if (!timers_ || !(static_cast<zmq::timers_t *> (timers_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    return (static_cast<zmq::timers_t *> (timers_))\n      ->add (interval_, handler_, arg_);\n}\n\nint zmq_timers_cancel (void *timers_, int timer_id_)\n{\n    if (!timers_ || !(static_cast<zmq::timers_t *> (timers_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    return (static_cast<zmq::timers_t *> (timers_))->cancel (timer_id_);\n}\n\nint zmq_timers_set_interval (void *timers_, int timer_id_, size_t interval_)\n{\n    if (!timers_ || !(static_cast<zmq::timers_t *> (timers_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    return (static_cast<zmq::timers_t *> (timers_))\n      ->set_interval (timer_id_, interval_);\n}\n\nint zmq_timers_reset (void *timers_, int timer_id_)\n{\n    if (!timers_ || !(static_cast<zmq::timers_t *> (timers_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    return (static_cast<zmq::timers_t *> (timers_))->reset (timer_id_);\n}\n\nlong zmq_timers_timeout (void *timers_)\n{\n    if (!timers_ || !(static_cast<zmq::timers_t *> (timers_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    return (static_cast<zmq::timers_t *> (timers_))->timeout ();\n}\n\nint zmq_timers_execute (void *timers_)\n{\n    if (!timers_ || !(static_cast<zmq::timers_t *> (timers_))->check_tag ()) {\n        errno = EFAULT;\n        return -1;\n    }\n\n    return (static_cast<zmq::timers_t *> (timers_))->execute ();\n}\n\n//  The proxy functionality\n\nint zmq_proxy (void *frontend_, void *backend_, void *capture_)\n{\n    if (!frontend_ || !backend_) {\n        errno = EFAULT;\n        return -1;\n    }\n    // Runs zmq::proxy_steerable with a NULL control_.\n    return zmq::proxy (static_cast<zmq::socket_base_t *> (frontend_),\n                       static_cast<zmq::socket_base_t *> (backend_),\n                       static_cast<zmq::socket_base_t *> (capture_));\n}\n\nint zmq_proxy_steerable (void *frontend_,\n                         void *backend_,\n                         void *capture_,\n                         void *control_)\n{\n    if (!frontend_ || !backend_) {\n        errno = EFAULT;\n        return -1;\n    }\n    return zmq::proxy_steerable (static_cast<zmq::socket_base_t *> (frontend_),\n                                 static_cast<zmq::socket_base_t *> (backend_),\n                                 static_cast<zmq::socket_base_t *> (capture_),\n                                 static_cast<zmq::socket_base_t *> (control_));\n}\n\n//  The deprecated device functionality\n\nint zmq_device (int /* type */, void *frontend_, void *backend_)\n{\n    return zmq::proxy (static_cast<zmq::socket_base_t *> (frontend_),\n                       static_cast<zmq::socket_base_t *> (backend_), NULL);\n}\n\n//  Probe library capabilities; for now, reports on transport and security\n\nint zmq_has (const char *capability_)\n{\n#if defined(ZMQ_HAVE_IPC)\n    if (strcmp (capability_, zmq::protocol_name::ipc) == 0)\n        return true;\n#endif\n#if defined(ZMQ_HAVE_OPENPGM)\n    if (strcmp (capability_, zmq::protocol_name::pgm) == 0)\n        return true;\n#endif\n#if defined(ZMQ_HAVE_TIPC)\n    if (strcmp (capability_, zmq::protocol_name::tipc) == 0)\n        return true;\n#endif\n#if defined(ZMQ_HAVE_NORM)\n    if (strcmp (capability_, zmq::protocol_name::norm) == 0)\n        return true;\n#endif\n#if defined(ZMQ_HAVE_CURVE)\n    if (strcmp (capability_, \"curve\") == 0)\n        return true;\n#endif\n#if defined(HAVE_LIBGSSAPI_KRB5)\n    if (strcmp (capability_, \"gssapi\") == 0)\n        return true;\n#endif\n#if defined(ZMQ_HAVE_VMCI)\n    if (strcmp (capability_, zmq::protocol_name::vmci) == 0)\n        return true;\n#endif\n#if defined(ZMQ_BUILD_DRAFT_API)\n    if (strcmp (capability_, \"draft\") == 0)\n        return true;\n#endif\n#if defined(ZMQ_HAVE_WS)\n    if (strcmp (capability_, \"WS\") == 0)\n        return true;\n#endif\n#if defined(ZMQ_HAVE_WSS)\n    if (strcmp (capability_, \"WSS\") == 0)\n        return true;\n#endif\n#if defined(ZMQ_HAVE_VSOCK)\n    if (strcmp (capability_, zmq::protocol_name::vsock) == 0)\n        return true;\n#endif\n    //  Whatever the application asked for, we don't have\n    return false;\n}\n\nint zmq_socket_monitor_pipes_stats (void *s_)\n{\n    zmq::socket_base_t *s = as_socket_base_t (s_);\n    if (!s)\n        return -1;\n    return s->query_pipes_stats ();\n}\n"
  },
  {
    "path": "src/zmq_draft.h",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_DRAFT_H_INCLUDED__\n#define __ZMQ_DRAFT_H_INCLUDED__\n\n/******************************************************************************/\n/*  These functions are DRAFT and disabled in stable releases, and subject to */\n/*  change at ANY time until declared stable.                                 */\n/******************************************************************************/\n\n#ifndef ZMQ_BUILD_DRAFT_API\n\n/*  DRAFT Socket types.                                                       */\n#define ZMQ_SERVER 12\n#define ZMQ_CLIENT 13\n#define ZMQ_RADIO 14\n#define ZMQ_DISH 15\n#define ZMQ_GATHER 16\n#define ZMQ_SCATTER 17\n#define ZMQ_DGRAM 18\n#define ZMQ_PEER 19\n#define ZMQ_CHANNEL 20\n\n/*  DRAFT Socket options.                                                     */\n#define ZMQ_ZAP_ENFORCE_DOMAIN 93\n#define ZMQ_LOOPBACK_FASTPATH 94\n#define ZMQ_METADATA 95\n#define ZMQ_MULTICAST_LOOP 96\n#define ZMQ_ROUTER_NOTIFY 97\n#define ZMQ_XPUB_MANUAL_LAST_VALUE 98\n#define ZMQ_SOCKS_USERNAME 99\n#define ZMQ_SOCKS_PASSWORD 100\n#define ZMQ_IN_BATCH_SIZE 101\n#define ZMQ_OUT_BATCH_SIZE 102\n#define ZMQ_WSS_KEY_PEM 103\n#define ZMQ_WSS_CERT_PEM 104\n#define ZMQ_WSS_TRUST_PEM 105\n#define ZMQ_WSS_HOSTNAME 106\n#define ZMQ_WSS_TRUST_SYSTEM 107\n#define ZMQ_ONLY_FIRST_SUBSCRIBE 108\n#define ZMQ_RECONNECT_STOP 109\n#define ZMQ_HELLO_MSG 110\n#define ZMQ_DISCONNECT_MSG 111\n#define ZMQ_PRIORITY 112\n#define ZMQ_BUSY_POLL 113\n#define ZMQ_HICCUP_MSG 114\n#define ZMQ_XSUB_VERBOSE_UNSUBSCRIBE 115\n#define ZMQ_TOPICS_COUNT 116\n#define ZMQ_NORM_MODE 117\n#define ZMQ_NORM_UNICAST_NACK 118\n#define ZMQ_NORM_BUFFER_SIZE 119\n#define ZMQ_NORM_SEGMENT_SIZE 120\n#define ZMQ_NORM_BLOCK_SIZE 121\n#define ZMQ_NORM_NUM_PARITY 122\n#define ZMQ_NORM_NUM_AUTOPARITY 123\n#define ZMQ_NORM_PUSH 124\n\n/*  DRAFT ZMQ_NORM_MODE options                                               */\n#define ZMQ_NORM_FIXED 0\n#define ZMQ_NORM_CC 1\n#define ZMQ_NORM_CCL 2\n#define ZMQ_NORM_CCE 3\n#define ZMQ_NORM_CCE_ECNONLY 4\n\n/*  DRAFT ZMQ_RECONNECT_STOP options                                          */\n#define ZMQ_RECONNECT_STOP_CONN_REFUSED 0x1\n#define ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED 0x2\n#define ZMQ_RECONNECT_STOP_AFTER_DISCONNECT 0x4\n\n/*  DRAFT Context options                                                     */\n#define ZMQ_ZERO_COPY_RECV 10\n\n/*  DRAFT Context methods.                                                    */\nint zmq_ctx_set_ext (void *context_,\n                     int option_,\n                     const void *optval_,\n                     size_t optvallen_);\nint zmq_ctx_get_ext (void *context_,\n                     int option_,\n                     void *optval_,\n                     size_t *optvallen_);\n\n/*  DRAFT Socket methods.                                                     */\nint zmq_join (void *s_, const char *group_);\nint zmq_leave (void *s_, const char *group_);\n\n/*  DRAFT Msg methods.                                                        */\nint zmq_msg_set_routing_id (zmq_msg_t *msg_, uint32_t routing_id_);\nuint32_t zmq_msg_routing_id (zmq_msg_t *msg_);\nint zmq_msg_set_group (zmq_msg_t *msg_, const char *group_);\nconst char *zmq_msg_group (zmq_msg_t *msg_);\nint zmq_msg_init_buffer (zmq_msg_t *msg_, const void *buf_, size_t size_);\n\n/*  DRAFT Msg property names.                                                 */\n#define ZMQ_MSG_PROPERTY_ROUTING_ID \"Routing-Id\"\n#define ZMQ_MSG_PROPERTY_SOCKET_TYPE \"Socket-Type\"\n#define ZMQ_MSG_PROPERTY_USER_ID \"User-Id\"\n#define ZMQ_MSG_PROPERTY_PEER_ADDRESS \"Peer-Address\"\n\n/*  Router notify options                                                     */\n#define ZMQ_NOTIFY_CONNECT 1\n#define ZMQ_NOTIFY_DISCONNECT 2\n\n/******************************************************************************/\n/*  Poller polling on sockets,fd and thread-safe sockets                      */\n/******************************************************************************/\n\n#if defined _WIN32\ntypedef SOCKET zmq_fd_t;\n#else\ntypedef int zmq_fd_t;\n#endif\n\ntypedef struct zmq_poller_event_t\n{\n    void *socket;\n    zmq_fd_t fd;\n    void *user_data;\n    short events;\n} zmq_poller_event_t;\n\nvoid *zmq_poller_new (void);\nint zmq_poller_destroy (void **poller_p_);\nint zmq_poller_size (void *poller_);\nint zmq_poller_add (void *poller_,\n                    void *socket_,\n                    void *user_data_,\n                    short events_);\nint zmq_poller_modify (void *poller_, void *socket_, short events_);\nint zmq_poller_remove (void *poller_, void *socket_);\nint zmq_poller_wait (void *poller_, zmq_poller_event_t *event_, long timeout_);\nint zmq_poller_wait_all (void *poller_,\n                         zmq_poller_event_t *events_,\n                         int n_events_,\n                         long timeout_);\nzmq_fd_t zmq_poller_fd (void *poller_);\n\nint zmq_poller_add_fd (void *poller_,\n                       zmq_fd_t fd_,\n                       void *user_data_,\n                       short events_);\nint zmq_poller_modify_fd (void *poller_, zmq_fd_t fd_, short events_);\nint zmq_poller_remove_fd (void *poller_, zmq_fd_t fd_);\n\nint zmq_socket_get_peer_state (void *socket_,\n                               const void *routing_id_,\n                               size_t routing_id_size_);\n\n/*  DRAFT Socket monitoring events                                            */\n#define ZMQ_EVENT_PIPES_STATS 0x10000\n\n#define ZMQ_CURRENT_EVENT_VERSION 1\n#define ZMQ_CURRENT_EVENT_VERSION_DRAFT 2\n\n#define ZMQ_EVENT_ALL_V1 ZMQ_EVENT_ALL\n#define ZMQ_EVENT_ALL_V2 ZMQ_EVENT_ALL_V1 | ZMQ_EVENT_PIPES_STATS\n\nint zmq_socket_monitor_versioned (\n  void *s_, const char *addr_, uint64_t events_, int event_version_, int type_);\nint zmq_socket_monitor_pipes_stats (void *s_);\n\n#if !defined _WIN32\nint zmq_ppoll (zmq_pollitem_t *items_,\n               int nitems_,\n               long timeout_,\n               const sigset_t *sigmask_);\n#else\n// Windows has no sigset_t\nint zmq_ppoll (zmq_pollitem_t *items_,\n               int nitems_,\n               long timeout_,\n               const void *sigmask_);\n#endif\n\n#endif // ZMQ_BUILD_DRAFT_API\n\n#endif //ifndef __ZMQ_DRAFT_H_INCLUDED__\n"
  },
  {
    "path": "src/zmq_utils.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n\n#include \"macros.hpp\"\n#include \"clock.hpp\"\n#include \"err.hpp\"\n#include \"thread.hpp\"\n#include \"atomic_counter.hpp\"\n#include \"atomic_ptr.hpp\"\n#include \"random.hpp\"\n#include <assert.h>\n#include <new>\n\n#if !defined ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#endif\n\n#if defined(ZMQ_USE_LIBSODIUM)\n#include \"sodium.h\"\n#endif\n\nvoid zmq_sleep (int seconds_)\n{\n#if defined ZMQ_HAVE_WINDOWS\n    Sleep (seconds_ * 1000);\n#else\n    sleep (seconds_);\n#endif\n}\n\nvoid *zmq_stopwatch_start ()\n{\n    uint64_t *watch = static_cast<uint64_t *> (malloc (sizeof (uint64_t)));\n    alloc_assert (watch);\n    *watch = zmq::clock_t::now_us ();\n    return static_cast<void *> (watch);\n}\n\nunsigned long zmq_stopwatch_intermediate (void *watch_)\n{\n    const uint64_t end = zmq::clock_t::now_us ();\n    const uint64_t start = *static_cast<uint64_t *> (watch_);\n    return static_cast<unsigned long> (end - start);\n}\n\nunsigned long zmq_stopwatch_stop (void *watch_)\n{\n    const unsigned long res = zmq_stopwatch_intermediate (watch_);\n    free (watch_);\n    return res;\n}\n\nvoid *zmq_threadstart (zmq_thread_fn *func_, void *arg_)\n{\n    zmq::thread_t *thread = new (std::nothrow) zmq::thread_t;\n    alloc_assert (thread);\n    thread->start (func_, arg_, \"ZMQapp\");\n    return thread;\n}\n\nvoid zmq_threadclose (void *thread_)\n{\n    zmq::thread_t *p_thread = static_cast<zmq::thread_t *> (thread_);\n    p_thread->stop ();\n    LIBZMQ_DELETE (p_thread);\n}\n\n//  Z85 codec, taken from 0MQ RFC project, implements RFC32 Z85 encoding\n\n//  Maps base 256 to base 85\nstatic char encoder[85 + 1] = {\"0123456789\"\n                               \"abcdefghij\"\n                               \"klmnopqrst\"\n                               \"uvwxyzABCD\"\n                               \"EFGHIJKLMN\"\n                               \"OPQRSTUVWX\"\n                               \"YZ.-:+=^!/\"\n                               \"*?&<>()[]{\"\n                               \"}@%$#\"};\n\n//  Maps base 85 to base 256\n//  We chop off lower 32 and higher 128 ranges\n//  0xFF denotes invalid characters within this range\nstatic uint8_t decoder[96] = {\n  0xFF, 0x44, 0xFF, 0x54, 0x53, 0x52, 0x48, 0xFF, 0x4B, 0x4C, 0x46, 0x41,\n  0xFF, 0x3F, 0x3E, 0x45, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n  0x08, 0x09, 0x40, 0xFF, 0x49, 0x42, 0x4A, 0x47, 0x51, 0x24, 0x25, 0x26,\n  0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,\n  0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x4D,\n  0xFF, 0x4E, 0x43, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,\n  0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,\n  0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x4F, 0xFF, 0x50, 0xFF, 0xFF};\n\n//  --------------------------------------------------------------------------\n//  Encode a binary frame as a string; destination string MUST be at least\n//  size * 5 / 4 bytes long plus 1 byte for the null terminator. Returns\n//  dest. Size must be a multiple of 4.\n//  Returns NULL and sets errno = EINVAL for invalid input.\n\nchar *zmq_z85_encode (char *dest_, const uint8_t *data_, size_t size_)\n{\n    if (size_ % 4 != 0) {\n        errno = EINVAL;\n        return NULL;\n    }\n    unsigned int char_nbr = 0;\n    unsigned int byte_nbr = 0;\n    uint32_t value = 0;\n    while (byte_nbr < size_) {\n        //  Accumulate value in base 256 (binary)\n        value = value * 256 + data_[byte_nbr++];\n        if (byte_nbr % 4 == 0) {\n            //  Output value in base 85\n            unsigned int divisor = 85 * 85 * 85 * 85;\n            while (divisor) {\n                dest_[char_nbr++] = encoder[value / divisor % 85];\n                divisor /= 85;\n            }\n            value = 0;\n        }\n    }\n    assert (char_nbr == size_ * 5 / 4);\n    dest_[char_nbr] = 0;\n    return dest_;\n}\n\n\n//  --------------------------------------------------------------------------\n//  Decode an encoded string into a binary frame; dest must be at least\n//  strlen (string) * 4 / 5 bytes long. Returns dest. strlen (string)\n//  must be a multiple of 5.\n//  Returns NULL and sets errno = EINVAL for invalid input.\n\nuint8_t *zmq_z85_decode (uint8_t *dest_, const char *string_)\n{\n    unsigned int byte_nbr = 0;\n    unsigned int char_nbr = 0;\n    uint32_t value = 0;\n    size_t src_len = strlen (string_);\n\n    if (src_len < 5 || src_len % 5 != 0)\n        goto error_inval;\n\n    while (string_[char_nbr]) {\n        //  Accumulate value in base 85\n        if (UINT32_MAX / 85 < value) {\n            //  Invalid z85 encoding, represented value exceeds 0xffffffff\n            goto error_inval;\n        }\n        value *= 85;\n        const uint8_t index = string_[char_nbr++] - 32;\n        if (index >= sizeof (decoder)) {\n            //  Invalid z85 encoding, character outside range\n            goto error_inval;\n        }\n        const uint32_t summand = decoder[index];\n        if (summand == 0xFF || summand > (UINT32_MAX - value)) {\n            //  Invalid z85 encoding, invalid character or represented value exceeds 0xffffffff\n            goto error_inval;\n        }\n        value += summand;\n        if (char_nbr % 5 == 0) {\n            //  Output value in base 256\n            unsigned int divisor = 256 * 256 * 256;\n            while (divisor) {\n                dest_[byte_nbr++] = value / divisor % 256;\n                divisor /= 256;\n            }\n            value = 0;\n        }\n    }\n    if (char_nbr % 5 != 0) {\n        goto error_inval;\n    }\n    assert (byte_nbr == strlen (string_) * 4 / 5);\n    return dest_;\n\nerror_inval:\n    errno = EINVAL;\n    return NULL;\n}\n\n//  --------------------------------------------------------------------------\n//  Generate a public/private keypair with libsodium.\n//  Generated keys will be 40 byte z85-encoded strings.\n//  Returns 0 on success, -1 on failure, setting errno.\n//  Sets errno = ENOTSUP in the absence of a CURVE library.\n\nint zmq_curve_keypair (char *z85_public_key_, char *z85_secret_key_)\n{\n#if defined(ZMQ_HAVE_CURVE)\n#if crypto_box_PUBLICKEYBYTES != 32 || crypto_box_SECRETKEYBYTES != 32\n#error \"CURVE encryption library not built correctly\"\n#endif\n\n    uint8_t public_key[32];\n    uint8_t secret_key[32];\n\n    zmq::random_open ();\n\n    const int res = crypto_box_keypair (public_key, secret_key);\n    zmq_z85_encode (z85_public_key_, public_key, 32);\n    zmq_z85_encode (z85_secret_key_, secret_key, 32);\n\n    zmq::random_close ();\n\n    return res;\n#else\n    (void) z85_public_key_, (void) z85_secret_key_;\n    errno = ENOTSUP;\n    return -1;\n#endif\n}\n\n//  --------------------------------------------------------------------------\n//  Derive the public key from a private key using libsodium.\n//  Derived key will be 40 byte z85-encoded string.\n//  Returns 0 on success, -1 on failure, setting errno.\n//  Sets errno = ENOTSUP in the absence of a CURVE library.\n\nint zmq_curve_public (char *z85_public_key_, const char *z85_secret_key_)\n{\n#if defined(ZMQ_HAVE_CURVE)\n#if crypto_box_PUBLICKEYBYTES != 32 || crypto_box_SECRETKEYBYTES != 32\n#error \"CURVE encryption library not built correctly\"\n#endif\n\n    uint8_t public_key[32];\n    uint8_t secret_key[32];\n\n    zmq::random_open ();\n\n    if (zmq_z85_decode (secret_key, z85_secret_key_) == NULL)\n        return -1;\n\n    // Return codes are suppressed as none of these can actually fail.\n    crypto_scalarmult_base (public_key, secret_key);\n    zmq_z85_encode (z85_public_key_, public_key, 32);\n\n    zmq::random_close ();\n\n    return 0;\n#else\n    (void) z85_public_key_, (void) z85_secret_key_;\n    errno = ENOTSUP;\n    return -1;\n#endif\n}\n\n\n//  --------------------------------------------------------------------------\n//  Initialize a new atomic counter, which is set to zero\n\nvoid *zmq_atomic_counter_new (void)\n{\n    zmq::atomic_counter_t *counter = new (std::nothrow) zmq::atomic_counter_t;\n    alloc_assert (counter);\n    return counter;\n}\n\n//  Se the value of the atomic counter\n\nvoid zmq_atomic_counter_set (void *counter_, int value_)\n{\n    (static_cast<zmq::atomic_counter_t *> (counter_))->set (value_);\n}\n\n//  Increment the atomic counter, and return the old value\n\nint zmq_atomic_counter_inc (void *counter_)\n{\n    return (static_cast<zmq::atomic_counter_t *> (counter_))->add (1);\n}\n\n//  Decrement the atomic counter and return 1 (if counter >= 1), or\n//  0 if counter hit zero.\n\nint zmq_atomic_counter_dec (void *counter_)\n{\n    return (static_cast<zmq::atomic_counter_t *> (counter_))->sub (1) ? 1 : 0;\n}\n\n//  Return actual value of atomic counter\n\nint zmq_atomic_counter_value (void *counter_)\n{\n    return (static_cast<zmq::atomic_counter_t *> (counter_))->get ();\n}\n\n//  Destroy atomic counter, and set reference to NULL\n\nvoid zmq_atomic_counter_destroy (void **counter_p_)\n{\n    delete (static_cast<zmq::atomic_counter_t *> (*counter_p_));\n    *counter_p_ = NULL;\n}\n"
  },
  {
    "path": "src/zmtp_engine.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"precompiled.hpp\"\n#include \"macros.hpp\"\n\n#include <limits.h>\n#include <string.h>\n\n#ifndef ZMQ_HAVE_WINDOWS\n#include <unistd.h>\n#endif\n\n#include <new>\n#include <sstream>\n\n#include \"zmtp_engine.hpp\"\n#include \"io_thread.hpp\"\n#include \"session_base.hpp\"\n#include \"v1_encoder.hpp\"\n#include \"v1_decoder.hpp\"\n#include \"v2_encoder.hpp\"\n#include \"v2_decoder.hpp\"\n#include \"v3_1_encoder.hpp\"\n#include \"null_mechanism.hpp\"\n#include \"plain_client.hpp\"\n#include \"plain_server.hpp\"\n#include \"gssapi_client.hpp\"\n#include \"gssapi_server.hpp\"\n#include \"curve_client.hpp\"\n#include \"curve_server.hpp\"\n#include \"raw_decoder.hpp\"\n#include \"raw_encoder.hpp\"\n#include \"config.hpp\"\n#include \"err.hpp\"\n#include \"ip.hpp\"\n#include \"likely.hpp\"\n#include \"wire.hpp\"\n\nzmq::zmtp_engine_t::zmtp_engine_t (\n  fd_t fd_,\n  const options_t &options_,\n  const endpoint_uri_pair_t &endpoint_uri_pair_) :\n    stream_engine_base_t (fd_, options_, endpoint_uri_pair_, true),\n    _greeting_size (v2_greeting_size),\n    _greeting_bytes_read (0),\n    _subscription_required (false),\n    _heartbeat_timeout (0)\n{\n    _next_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n      &zmtp_engine_t::routing_id_msg);\n    _process_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n      &zmtp_engine_t::process_routing_id_msg);\n\n    int rc = _pong_msg.init ();\n    errno_assert (rc == 0);\n\n    rc = _routing_id_msg.init ();\n    errno_assert (rc == 0);\n\n    if (_options.heartbeat_interval > 0) {\n        _heartbeat_timeout = _options.heartbeat_timeout;\n        if (_heartbeat_timeout == -1)\n            _heartbeat_timeout = _options.heartbeat_interval;\n    }\n}\n\nzmq::zmtp_engine_t::~zmtp_engine_t ()\n{\n    const int rc = _routing_id_msg.close ();\n    errno_assert (rc == 0);\n}\n\nvoid zmq::zmtp_engine_t::plug_internal ()\n{\n    // start optional timer, to prevent handshake hanging on no input\n    set_handshake_timer ();\n\n    //  Send the 'length' and 'flags' fields of the routing id message.\n    //  The 'length' field is encoded in the long format.\n    _outpos = _greeting_send;\n    _outpos[_outsize++] = UCHAR_MAX;\n    put_uint64 (&_outpos[_outsize], _options.routing_id_size + 1);\n    _outsize += 8;\n    _outpos[_outsize++] = 0x7f;\n\n    set_pollin ();\n    set_pollout ();\n    //  Flush all the data that may have been already received downstream.\n    in_event ();\n}\n\n//  Position of the revision and minor fields in the greeting.\nconst size_t revision_pos = 10;\nconst size_t minor_pos = 11;\n\nbool zmq::zmtp_engine_t::handshake ()\n{\n    zmq_assert (_greeting_bytes_read < _greeting_size);\n    //  Receive the greeting.\n    const int rc = receive_greeting ();\n    if (rc == -1)\n        return false;\n    const bool unversioned = rc != 0;\n\n    if (!(this\n            ->*select_handshake_fun (unversioned, _greeting_recv[revision_pos],\n                                     _greeting_recv[minor_pos])) ())\n        return false;\n\n    // Start polling for output if necessary.\n    if (_outsize == 0)\n        set_pollout ();\n\n    return true;\n}\n\nint zmq::zmtp_engine_t::receive_greeting ()\n{\n    bool unversioned = false;\n    while (_greeting_bytes_read < _greeting_size) {\n        const int n = read (_greeting_recv + _greeting_bytes_read,\n                            _greeting_size - _greeting_bytes_read);\n        if (n == -1) {\n            if (errno != EAGAIN)\n                error (connection_error);\n            return -1;\n        }\n\n        _greeting_bytes_read += n;\n\n        //  We have received at least one byte from the peer.\n        //  If the first byte is not 0xff, we know that the\n        //  peer is using unversioned protocol.\n        if (_greeting_recv[0] != 0xff) {\n            unversioned = true;\n            break;\n        }\n\n        if (_greeting_bytes_read < signature_size)\n            continue;\n\n        //  Inspect the right-most bit of the 10th byte (which coincides\n        //  with the 'flags' field if a regular message was sent).\n        //  Zero indicates this is a header of a routing id message\n        //  (i.e. the peer is using the unversioned protocol).\n        if (!(_greeting_recv[9] & 0x01)) {\n            unversioned = true;\n            break;\n        }\n\n        //  The peer is using versioned protocol.\n        receive_greeting_versioned ();\n    }\n    return unversioned ? 1 : 0;\n}\n\nvoid zmq::zmtp_engine_t::receive_greeting_versioned ()\n{\n    //  Send the major version number.\n    if (_outpos + _outsize == _greeting_send + signature_size) {\n        if (_outsize == 0)\n            set_pollout ();\n        _outpos[_outsize++] = 3; //  Major version number\n    }\n\n    if (_greeting_bytes_read > signature_size) {\n        if (_outpos + _outsize == _greeting_send + signature_size + 1) {\n            if (_outsize == 0)\n                set_pollout ();\n\n            //  Use ZMTP/2.0 to talk to older peers.\n            if (_greeting_recv[revision_pos] == ZMTP_1_0\n                || _greeting_recv[revision_pos] == ZMTP_2_0)\n                _outpos[_outsize++] = _options.type;\n            else {\n                _outpos[_outsize++] = 1; //  Minor version number\n                memset (_outpos + _outsize, 0, 20);\n\n                zmq_assert (_options.mechanism == ZMQ_NULL\n                            || _options.mechanism == ZMQ_PLAIN\n                            || _options.mechanism == ZMQ_CURVE\n                            || _options.mechanism == ZMQ_GSSAPI);\n\n                if (_options.mechanism == ZMQ_NULL)\n                    memcpy (_outpos + _outsize, \"NULL\", 4);\n                else if (_options.mechanism == ZMQ_PLAIN)\n                    memcpy (_outpos + _outsize, \"PLAIN\", 5);\n                else if (_options.mechanism == ZMQ_GSSAPI)\n                    memcpy (_outpos + _outsize, \"GSSAPI\", 6);\n                else if (_options.mechanism == ZMQ_CURVE)\n                    memcpy (_outpos + _outsize, \"CURVE\", 5);\n                _outsize += 20;\n                memset (_outpos + _outsize, 0, 32);\n                _outsize += 32;\n                _greeting_size = v3_greeting_size;\n            }\n        }\n    }\n}\n\nzmq::zmtp_engine_t::handshake_fun_t zmq::zmtp_engine_t::select_handshake_fun (\n  bool unversioned_, unsigned char revision_, unsigned char minor_)\n{\n    //  Is the peer using ZMTP/1.0 with no revision number?\n    if (unversioned_) {\n        return &zmtp_engine_t::handshake_v1_0_unversioned;\n    }\n    switch (revision_) {\n        case ZMTP_1_0:\n            return &zmtp_engine_t::handshake_v1_0;\n        case ZMTP_2_0:\n            return &zmtp_engine_t::handshake_v2_0;\n        case ZMTP_3_x:\n            switch (minor_) {\n                case 0:\n                    return &zmtp_engine_t::handshake_v3_0;\n                default:\n                    return &zmtp_engine_t::handshake_v3_1;\n            }\n        default:\n            return &zmtp_engine_t::handshake_v3_1;\n    }\n}\n\nbool zmq::zmtp_engine_t::handshake_v1_0_unversioned ()\n{\n    //  We send and receive rest of routing id message\n    if (session ()->zap_enabled ()) {\n        // reject ZMTP 1.0 connections if ZAP is enabled\n        error (protocol_error);\n        return false;\n    }\n\n    _encoder = new (std::nothrow) v1_encoder_t (_options.out_batch_size);\n    alloc_assert (_encoder);\n\n    _decoder = new (std::nothrow)\n      v1_decoder_t (_options.in_batch_size, _options.maxmsgsize);\n    alloc_assert (_decoder);\n\n    //  We have already sent the message header.\n    //  Since there is no way to tell the encoder to\n    //  skip the message header, we simply throw that\n    //  header data away.\n    const size_t header_size =\n      _options.routing_id_size + 1 >= UCHAR_MAX ? 10 : 2;\n    unsigned char tmp[10], *bufferp = tmp;\n\n    //  Prepare the routing id message and load it into encoder.\n    //  Then consume bytes we have already sent to the peer.\n    int rc = _routing_id_msg.close ();\n    zmq_assert (rc == 0);\n    rc = _routing_id_msg.init_size (_options.routing_id_size);\n    zmq_assert (rc == 0);\n    memcpy (_routing_id_msg.data (), _options.routing_id,\n            _options.routing_id_size);\n    _encoder->load_msg (&_routing_id_msg);\n    const size_t buffer_size = _encoder->encode (&bufferp, header_size);\n    zmq_assert (buffer_size == header_size);\n\n    //  Make sure the decoder sees the data we have already received.\n    _inpos = _greeting_recv;\n    _insize = _greeting_bytes_read;\n\n    //  To allow for interoperability with peers that do not forward\n    //  their subscriptions, we inject a phantom subscription message\n    //  message into the incoming message stream.\n    if (_options.type == ZMQ_PUB || _options.type == ZMQ_XPUB)\n        _subscription_required = true;\n\n    //  We are sending our routing id now and the next message\n    //  will come from the socket.\n    _next_msg = &zmtp_engine_t::pull_msg_from_session;\n\n    //  We are expecting routing id message.\n    _process_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n      &zmtp_engine_t::process_routing_id_msg);\n\n    return true;\n}\n\nbool zmq::zmtp_engine_t::handshake_v1_0 ()\n{\n    if (session ()->zap_enabled ()) {\n        // reject ZMTP 1.0 connections if ZAP is enabled\n        error (protocol_error);\n        return false;\n    }\n\n    _encoder = new (std::nothrow) v1_encoder_t (_options.out_batch_size);\n    alloc_assert (_encoder);\n\n    _decoder = new (std::nothrow)\n      v1_decoder_t (_options.in_batch_size, _options.maxmsgsize);\n    alloc_assert (_decoder);\n\n    return true;\n}\n\nbool zmq::zmtp_engine_t::handshake_v2_0 ()\n{\n    if (session ()->zap_enabled ()) {\n        // reject ZMTP 2.0 connections if ZAP is enabled\n        error (protocol_error);\n        return false;\n    }\n\n    _encoder = new (std::nothrow) v2_encoder_t (_options.out_batch_size);\n    alloc_assert (_encoder);\n\n    _decoder = new (std::nothrow) v2_decoder_t (\n      _options.in_batch_size, _options.maxmsgsize, _options.zero_copy);\n    alloc_assert (_decoder);\n\n    return true;\n}\n\nbool zmq::zmtp_engine_t::handshake_v3_x (const bool downgrade_sub_)\n{\n    if (_options.mechanism == ZMQ_NULL\n        && memcmp (_greeting_recv + 12, \"NULL\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\",\n                   20)\n             == 0) {\n        _mechanism = new (std::nothrow)\n          null_mechanism_t (session (), _peer_address, _options);\n        alloc_assert (_mechanism);\n    } else if (_options.mechanism == ZMQ_PLAIN\n               && memcmp (_greeting_recv + 12,\n                          \"PLAIN\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 20)\n                    == 0) {\n        if (_options.as_server)\n            _mechanism = new (std::nothrow)\n              plain_server_t (session (), _peer_address, _options);\n        else\n            _mechanism =\n              new (std::nothrow) plain_client_t (session (), _options);\n        alloc_assert (_mechanism);\n    }\n#ifdef ZMQ_HAVE_CURVE\n    else if (_options.mechanism == ZMQ_CURVE\n             && memcmp (_greeting_recv + 12,\n                        \"CURVE\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 20)\n                  == 0) {\n        if (_options.as_server)\n            _mechanism = new (std::nothrow) curve_server_t (\n              session (), _peer_address, _options, downgrade_sub_);\n        else\n            _mechanism = new (std::nothrow)\n              curve_client_t (session (), _options, downgrade_sub_);\n        alloc_assert (_mechanism);\n    }\n#endif\n#ifdef HAVE_LIBGSSAPI_KRB5\n    else if (_options.mechanism == ZMQ_GSSAPI\n             && memcmp (_greeting_recv + 12,\n                        \"GSSAPI\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 20)\n                  == 0) {\n        if (_options.as_server)\n            _mechanism = new (std::nothrow)\n              gssapi_server_t (session (), _peer_address, _options);\n        else\n            _mechanism =\n              new (std::nothrow) gssapi_client_t (session (), _options);\n        alloc_assert (_mechanism);\n    }\n#endif\n    else {\n        socket ()->event_handshake_failed_protocol (\n          session ()->get_endpoint (),\n          ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH);\n        error (protocol_error);\n        return false;\n    }\n#ifndef ZMQ_HAVE_CURVE\n    LIBZMQ_UNUSED (downgrade_sub_);\n#endif\n    _next_msg = &zmtp_engine_t::next_handshake_command;\n    _process_msg = &zmtp_engine_t::process_handshake_command;\n\n    return true;\n}\n\nbool zmq::zmtp_engine_t::handshake_v3_0 ()\n{\n    _encoder = new (std::nothrow) v2_encoder_t (_options.out_batch_size);\n    alloc_assert (_encoder);\n\n    _decoder = new (std::nothrow) v2_decoder_t (\n      _options.in_batch_size, _options.maxmsgsize, _options.zero_copy);\n    alloc_assert (_decoder);\n\n    return zmq::zmtp_engine_t::handshake_v3_x (true);\n}\n\nbool zmq::zmtp_engine_t::handshake_v3_1 ()\n{\n    _encoder = new (std::nothrow) v3_1_encoder_t (_options.out_batch_size);\n    alloc_assert (_encoder);\n\n    _decoder = new (std::nothrow) v2_decoder_t (\n      _options.in_batch_size, _options.maxmsgsize, _options.zero_copy);\n    alloc_assert (_decoder);\n\n    return zmq::zmtp_engine_t::handshake_v3_x (false);\n}\n\nint zmq::zmtp_engine_t::routing_id_msg (msg_t *msg_)\n{\n    const int rc = msg_->init_size (_options.routing_id_size);\n    errno_assert (rc == 0);\n    if (_options.routing_id_size > 0)\n        memcpy (msg_->data (), _options.routing_id, _options.routing_id_size);\n    _next_msg = &zmtp_engine_t::pull_msg_from_session;\n    return 0;\n}\n\nint zmq::zmtp_engine_t::process_routing_id_msg (msg_t *msg_)\n{\n    if (_options.recv_routing_id) {\n        msg_->set_flags (msg_t::routing_id);\n        const int rc = session ()->push_msg (msg_);\n        errno_assert (rc == 0);\n    } else {\n        int rc = msg_->close ();\n        errno_assert (rc == 0);\n        rc = msg_->init ();\n        errno_assert (rc == 0);\n    }\n\n    if (_subscription_required) {\n        msg_t subscription;\n\n        //  Inject the subscription message, so that also\n        //  ZMQ 2.x peers receive published messages.\n        int rc = subscription.init_size (1);\n        errno_assert (rc == 0);\n        *static_cast<unsigned char *> (subscription.data ()) = 1;\n        rc = session ()->push_msg (&subscription);\n        errno_assert (rc == 0);\n    }\n\n    _process_msg = &zmtp_engine_t::push_msg_to_session;\n\n    return 0;\n}\n\nint zmq::zmtp_engine_t::produce_ping_message (msg_t *msg_)\n{\n    // 16-bit TTL + \\4PING == 7\n    const size_t ping_ttl_len = msg_t::ping_cmd_name_size + 2;\n    zmq_assert (_mechanism != NULL);\n\n    int rc = msg_->init_size (ping_ttl_len);\n    errno_assert (rc == 0);\n    msg_->set_flags (msg_t::command);\n    // Copy in the command message\n    memcpy (msg_->data (), \"\\4PING\", msg_t::ping_cmd_name_size);\n\n    uint16_t ttl_val = htons (_options.heartbeat_ttl);\n    memcpy (static_cast<uint8_t *> (msg_->data ()) + msg_t::ping_cmd_name_size,\n            &ttl_val, sizeof (ttl_val));\n\n    rc = _mechanism->encode (msg_);\n    _next_msg = &zmtp_engine_t::pull_and_encode;\n    if (!_has_timeout_timer && _heartbeat_timeout > 0) {\n        add_timer (_heartbeat_timeout, heartbeat_timeout_timer_id);\n        _has_timeout_timer = true;\n    }\n    return rc;\n}\n\nint zmq::zmtp_engine_t::produce_pong_message (msg_t *msg_)\n{\n    zmq_assert (_mechanism != NULL);\n\n    int rc = msg_->move (_pong_msg);\n    errno_assert (rc == 0);\n\n    rc = _mechanism->encode (msg_);\n    _next_msg = &zmtp_engine_t::pull_and_encode;\n    return rc;\n}\n\nint zmq::zmtp_engine_t::process_heartbeat_message (msg_t *msg_)\n{\n    if (msg_->is_ping ()) {\n        // 16-bit TTL + \\4PING == 7\n        const size_t ping_ttl_len = msg_t::ping_cmd_name_size + 2;\n        const size_t ping_max_ctx_len = 16;\n        uint16_t remote_heartbeat_ttl;\n\n        // Get the remote heartbeat TTL to setup the timer\n        memcpy (&remote_heartbeat_ttl,\n                static_cast<uint8_t *> (msg_->data ())\n                  + msg_t::ping_cmd_name_size,\n                ping_ttl_len - msg_t::ping_cmd_name_size);\n        remote_heartbeat_ttl = ntohs (remote_heartbeat_ttl);\n        // The remote heartbeat is in 10ths of a second\n        // so we multiply it by 100 to get the timer interval in ms.\n        remote_heartbeat_ttl *= 100;\n\n        if (!_has_ttl_timer && remote_heartbeat_ttl > 0) {\n            add_timer (remote_heartbeat_ttl, heartbeat_ttl_timer_id);\n            _has_ttl_timer = true;\n        }\n\n        //  As per ZMTP 3.1 the PING command might contain an up to 16 bytes\n        //  context which needs to be PONGed back, so build the pong message\n        //  here and store it. Truncate it if it's too long.\n        //  Given the engine goes straight to out_event, sequential PINGs will\n        //  not be a problem.\n        const size_t context_len =\n          std::min (msg_->size () - ping_ttl_len, ping_max_ctx_len);\n        const int rc =\n          _pong_msg.init_size (msg_t::ping_cmd_name_size + context_len);\n        errno_assert (rc == 0);\n        _pong_msg.set_flags (msg_t::command);\n        memcpy (_pong_msg.data (), \"\\4PONG\", msg_t::ping_cmd_name_size);\n        if (context_len > 0)\n            memcpy (static_cast<uint8_t *> (_pong_msg.data ())\n                      + msg_t::ping_cmd_name_size,\n                    static_cast<uint8_t *> (msg_->data ()) + ping_ttl_len,\n                    context_len);\n\n        _next_msg = static_cast<int (stream_engine_base_t::*) (msg_t *)> (\n          &zmtp_engine_t::produce_pong_message);\n        out_event ();\n    }\n\n    return 0;\n}\n\nint zmq::zmtp_engine_t::process_command_message (msg_t *msg_)\n{\n    const uint8_t cmd_name_size =\n      *(static_cast<const uint8_t *> (msg_->data ()));\n    const size_t ping_name_size = msg_t::ping_cmd_name_size - 1;\n    const size_t sub_name_size = msg_t::sub_cmd_name_size - 1;\n    const size_t cancel_name_size = msg_t::cancel_cmd_name_size - 1;\n    //  Malformed command\n    if (unlikely (msg_->size () < cmd_name_size + sizeof (cmd_name_size)))\n        return -1;\n\n    const uint8_t *const cmd_name =\n      static_cast<const uint8_t *> (msg_->data ()) + 1;\n    if (cmd_name_size == ping_name_size\n        && memcmp (cmd_name, \"PING\", cmd_name_size) == 0)\n        msg_->set_flags (zmq::msg_t::ping);\n    if (cmd_name_size == ping_name_size\n        && memcmp (cmd_name, \"PONG\", cmd_name_size) == 0)\n        msg_->set_flags (zmq::msg_t::pong);\n    if (cmd_name_size == sub_name_size\n        && memcmp (cmd_name, \"SUBSCRIBE\", cmd_name_size) == 0)\n        msg_->set_flags (zmq::msg_t::subscribe);\n    if (cmd_name_size == cancel_name_size\n        && memcmp (cmd_name, \"CANCEL\", cmd_name_size) == 0)\n        msg_->set_flags (zmq::msg_t::cancel);\n\n    if (msg_->is_ping () || msg_->is_pong ())\n        return process_heartbeat_message (msg_);\n\n    return 0;\n}\n"
  },
  {
    "path": "src/zmtp_engine.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __ZMQ_ZMTP_ENGINE_HPP_INCLUDED__\n#define __ZMQ_ZMTP_ENGINE_HPP_INCLUDED__\n\n#include <stddef.h>\n\n#include \"fd.hpp\"\n#include \"i_engine.hpp\"\n#include \"io_object.hpp\"\n#include \"i_encoder.hpp\"\n#include \"i_decoder.hpp\"\n#include \"options.hpp\"\n#include \"socket_base.hpp\"\n#include \"metadata.hpp\"\n#include \"msg.hpp\"\n#include \"stream_engine_base.hpp\"\n\nnamespace zmq\n{\n//  Protocol revisions\nenum\n{\n    ZMTP_1_0 = 0,\n    ZMTP_2_0 = 1,\n    ZMTP_3_x = 3\n};\n\nclass io_thread_t;\nclass session_base_t;\nclass mechanism_t;\n\n//  This engine handles any socket with SOCK_STREAM semantics,\n//  e.g. TCP socket or an UNIX domain socket.\n\nclass zmtp_engine_t ZMQ_FINAL : public stream_engine_base_t\n{\n  public:\n    zmtp_engine_t (fd_t fd_,\n                   const options_t &options_,\n                   const endpoint_uri_pair_t &endpoint_uri_pair_);\n    ~zmtp_engine_t ();\n\n  protected:\n    //  Detects the protocol used by the peer.\n    bool handshake ();\n\n    void plug_internal ();\n\n    int process_command_message (msg_t *msg_);\n    int produce_ping_message (msg_t *msg_);\n    int process_heartbeat_message (msg_t *msg_);\n    int produce_pong_message (msg_t *msg_);\n\n  private:\n    //  Receive the greeting from the peer.\n    int receive_greeting ();\n    void receive_greeting_versioned ();\n\n    typedef bool (zmtp_engine_t::*handshake_fun_t) ();\n    static handshake_fun_t select_handshake_fun (bool unversioned,\n                                                 unsigned char revision,\n                                                 unsigned char minor);\n\n    bool handshake_v1_0_unversioned ();\n    bool handshake_v1_0 ();\n    bool handshake_v2_0 ();\n    bool handshake_v3_x (bool downgrade_sub);\n    bool handshake_v3_0 ();\n    bool handshake_v3_1 ();\n\n    int routing_id_msg (msg_t *msg_);\n    int process_routing_id_msg (msg_t *msg_);\n\n    msg_t _routing_id_msg;\n\n    //  Need to store PING payload for PONG\n    msg_t _pong_msg;\n\n    static const size_t signature_size = 10;\n\n    //  Size of ZMTP/1.0 and ZMTP/2.0 greeting message\n    static const size_t v2_greeting_size = 12;\n\n    //  Size of ZMTP/3.0 greeting message\n    static const size_t v3_greeting_size = 64;\n\n    //  Expected greeting size.\n    size_t _greeting_size;\n\n    //  Greeting received from, and sent to peer\n    unsigned char _greeting_recv[v3_greeting_size];\n    unsigned char _greeting_send[v3_greeting_size];\n\n    //  Size of greeting received so far\n    unsigned int _greeting_bytes_read;\n\n    //  Indicates whether the engine is to inject a phantom\n    //  subscription message into the incoming stream.\n    //  Needed to support old peers.\n    bool _subscription_required;\n\n    int _heartbeat_timeout;\n\n    ZMQ_NON_COPYABLE_NOR_MOVABLE (zmtp_engine_t)\n};\n}\n\n#endif\n"
  },
  {
    "path": "tests/CMakeLists.txt",
    "content": "# CMake build script for ZeroMQ tests\ncmake_minimum_required(VERSION 2.8.1...3.31)\n\n# On Windows: solution file will be called tests.sln\nproject(tests)\n\nset(tests\n  test_ancillaries\n  test_system\n  test_pair_inproc\n  test_pair_tcp\n  test_reqrep_inproc\n  test_reqrep_tcp\n  test_hwm\n  test_hwm_pubsub\n  test_reqrep_device\n  test_sub_forward\n  test_invalid_rep\n  test_msg_flags\n  test_msg_ffn\n  test_connect_resolve\n  test_immediate\n  test_last_endpoint\n  test_term_endpoint\n  test_router_mandatory\n  test_probe_router\n  test_stream\n  test_stream_empty\n  test_stream_disconnect\n  test_disconnect_inproc\n  test_unbind_wildcard\n  test_ctx_options\n  test_ctx_destroy\n  test_security_no_zap_handler\n  test_security_null\n  test_security_plain\n  test_security_zap\n  test_iov\n  test_spec_req\n  test_spec_rep\n  test_spec_dealer\n  test_spec_router\n  test_spec_pushpull\n  test_req_correlate\n  test_req_relaxed\n  test_conflate\n  test_inproc_connect\n  test_issue_566\n  test_shutdown_stress\n  test_timeo\n  test_many_sockets\n  test_diffserv\n  test_connect_rid\n  test_xpub_nodrop\n  test_pub_invert_matching\n  test_setsockopt\n  test_sockopt_hwm\n  test_heartbeats\n  test_atomics\n  test_bind_src_address\n  test_capabilities\n  test_metadata\n  test_router_handover\n  test_srcfd\n  test_stream_timeout\n  test_xpub_manual\n  test_xpub_topic\n  test_xpub_welcome_msg\n  test_xpub_verbose\n  test_base85\n  test_bind_after_connect_tcp\n  test_sodium\n  test_monitor\n  test_socket_null\n  test_reconnect_ivl\n  test_reconnect_options\n  test_tcp_accept_filter\n  test_mock_pub_sub)\n\nif(NOT WIN32)\n  list(APPEND tests test_security_gssapi test_socks test_connect_null_fuzzer test_bind_null_fuzzer test_connect_fuzzer test_bind_fuzzer)\nendif()\n\nif(ZMQ_HAVE_CURVE)\n  # TODO: always fails running under Github Actions via CMake\n  if(NOT CMAKE_SYSTEM_NAME MATCHES \"Linux\")\n    list(APPEND tests test_security_curve)\n  endif()\n\n  if(NOT WIN32)\n    list(APPEND tests test_connect_curve_fuzzer test_bind_curve_fuzzer test_z85_decode_fuzzer)\n  endif()\nendif()\n\noption(ENABLE_CAPSH \"Run tests that require sudo and capsh (for cap_net_admin)\" OFF)\n\nif(ENABLE_CAPSH)\n  find_program(CAPSH_PROGRAM NAMES capsh)\n\n  if(CAPSH_PROGRAM)\n    list(APPEND tests test_pair_tcp_cap_net_admin)\n  else()\n    message(STATUS \"capsh not found, skipping tests that require CAP_NET_ADMIN\")\n  endif()\nendif()\n\nif(ZMQ_HAVE_IPC)\n  list(APPEND tests test_ipc_wildcard test_pair_ipc test_reqrep_ipc test_rebind_ipc)\nendif()\n\nif(NOT WIN32)\n  list(\n    APPEND\n    tests\n    test_proxy\n    test_proxy_hwm\n    test_proxy_single_socket\n    test_proxy_steerable\n    test_proxy_terminate\n    test_getsockopt_memset\n    test_filter_ipc\n    test_stream_exceeds_buffer\n    test_router_mandatory_hwm\n    test_use_fd\n    test_zmq_poll_fd)\n\n  if(HAVE_FORK)\n    list(APPEND tests test_fork)\n  endif()\n\n  if(CMAKE_SYSTEM_NAME MATCHES \"Linux\")\n    list(APPEND tests test_abstract_ipc)\n\n    if(ZMQ_HAVE_TIPC)\n      list(\n        APPEND\n        tests\n        test_address_tipc\n        test_pair_tipc\n        test_reqrep_device_tipc\n        test_reqrep_tipc\n        test_router_mandatory_tipc\n        test_sub_forward_tipc\n        test_connect_delay_tipc\n        test_shutdown_stress_tipc\n        test_term_endpoint_tipc)\n    endif()\n  endif()\nendif()\n\nif(WITH_VMCI)\n  list(APPEND tests test_pair_vmci test_reqrep_vmci)\nendif()\n\nif(ZMQ_HAVE_VSOCK)\n  list(APPEND tests test_pair_vsock test_reqrep_vsock)\nendif()\n\nif(ENABLE_DRAFTS)\n  list(\n    APPEND\n    tests\n    test_poller\n    test_thread_safe\n    test_client_server\n    test_timers\n    test_radio_dish\n    test_scatter_gather\n    test_dgram\n    test_app_meta\n    test_router_notify\n    test_xpub_manual_last_value\n    test_peer\n    test_peer_disconnect\n    test_msg_init\n    test_channel\n    test_hello_msg\n    test_disconnect_msg\n    test_hiccup_msg\n    test_zmq_ppoll_fd\n    test_xsub_verbose\n    test_pubsub_topics_count\n  )\n\n  if(HAVE_FORK)\n    list(APPEND tests test_zmq_ppoll_signals)\n  endif()\n\n  if(ZMQ_HAVE_BUSY_POLL)\n    list(APPEND tests test_busy_poll)\n  endif()\nendif()\n\nif(ZMQ_HAVE_WS)\n  list(APPEND tests test_ws_transport)\n\n  if(ZMQ_HAVE_WSS)\n    list(APPEND tests test_wss_transport)\n  endif()\nendif()\n\n# add location of platform.hpp for Windows builds\nif(WIN32)\n  add_definitions(-DZMQ_CUSTOM_PLATFORM_HPP)\n  add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS)\n\n  # Same name on 64bit systems\n  link_libraries(ws2_32.lib)\nendif()\n\nadd_library(\n  unity STATIC\n  \"${CMAKE_CURRENT_LIST_DIR}/../external/unity/unity.c\" \"${CMAKE_CURRENT_LIST_DIR}/../external/unity/unity.h\"\n  \"${CMAKE_CURRENT_LIST_DIR}/../external/unity/unity_internals.h\")\nset_target_properties(unity PROPERTIES PUBLIC_HEADER \"${CMAKE_CURRENT_LIST_DIR}/../external/unity/unity.h\")\ntarget_compile_definitions(unity PUBLIC \"UNITY_USE_COMMAND_LINE_ARGS\" \"UNITY_EXCLUDE_FLOAT\")\ntarget_include_directories(unity PUBLIC \"${CMAKE_CURRENT_LIST_DIR}/../external/unity\")\n\nset(TESTUTIL_SOURCES\n  testutil.cpp\n  testutil.hpp\n  testutil_monitoring.cpp\n  testutil_monitoring.hpp\n  testutil_security.cpp\n  testutil_security.hpp\n  testutil_unity.cpp\n  testutil_unity.hpp)\n\nif(BUILD_STATIC)\n  add_library(testutil-static STATIC ${TESTUTIL_SOURCES})\n  target_link_libraries(testutil-static libzmq-static ${OPTIONAL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} unity)\nendif()\n\nif(BUILD_SHARED)\n  add_library(testutil STATIC ${TESTUTIL_SOURCES})\n  target_link_libraries(testutil libzmq ${OPTIONAL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} unity)\nendif()\n\nif(BUILD_STATIC AND NOT BUILD_SHARED)\n  # use testutil-static for both tests and unit tests\n  set(TESTUTIL_LIB testutil-static)\nelse()\n  # use testutil for tests and testutil-static for unit tests\n  set(TESTUTIL_LIB testutil)\nendif()\n\nif(MSVC_VERSION LESS 1700)\n  set_source_files_properties(\"${CMAKE_CURRENT_LIST_DIR}/../external/unity/unity.c\" PROPERTIES LANGUAGE CXX)\nendif()\n\nif(MSVC_VERSION LESS 1600)\n  target_compile_definitions(unity PUBLIC \"UNITY_EXCLUDE_STDINT_H\")\nendif()\n\n# add include dirs for all targets\ninclude_directories(\"${ZeroMQ_SOURCE_DIR}/../include\" \"${ZeroMQ_BINARY_DIR}\")\n\nif(WIN32)\n  add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)\nendif()\n\n# Does not work, times out every time\nif(WIN32)\n  list(REMOVE_ITEM tests test_many_sockets)\nendif()\n\nforeach(test ${tests})\n  # target_sources not supported before CMake 3.1\n  if(ZMQ_HAVE_CURVE AND ${test} MATCHES test_security_curve)\n    add_executable(${test} ${test}.cpp \"../src/err.cpp\" \"../src/random.cpp\" \"../src/clock.cpp\")\n  else()\n    add_executable(${test} ${test}.cpp)\n  endif()\n\n  target_link_libraries(${test} ${TESTUTIL_LIB})\n\n  if(WIN32)\n    # This is the output for Debug dynamic builds on Visual Studio 6.0 You should provide the correct directory, don't\n    # know how to do it automatically\n    find_path(LIBZMQ_PATH \"libzmq.lib\" PATHS \"../bin/Win32/Debug/v120/dynamic\")\n\n    if(NOT ${LIBZMQ_PATH} STREQUAL \"LIBZMQ_PATH-NOTFOUND\")\n      set_target_properties(${test} PROPERTIES LINK_FLAGS \"/LIBPATH:${LIBZMQ_PATH}\")\n    endif()\n  else()\n    # per-test directories not generated on OS X / Darwin\n    if(NOT APPLE)\n      link_directories(${test} PRIVATE \"${ZeroMQ_SOURCE_DIR}/../lib\")\n    endif()\n  endif()\n\n  if(RT_LIBRARY)\n    target_link_libraries(${test} ${RT_LIBRARY})\n  endif()\n\n  if (WITH_GSSAPI_KRB5)\n    target_link_libraries(${test} ${GSSAPI_KRB5_LIBRARIES})\n  endif()\n\n  if(CMAKE_SYSTEM_NAME MATCHES \"QNX\")\n    target_link_libraries(${test} socket)\n    target_link_libraries(${test} m)\n  endif()\n\n  if(WIN32)\n    add_test(\n      NAME ${test}\n      WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH}\n      COMMAND ${test})\n  else()\n    if(${test} MATCHES \"_cap_net_admin\")\n      add_test(NAME ${test} COMMAND sh -c \"sudo ${CAPSH_PROGRAM} --caps=cap_net_admin+eip -- -c $<TARGET_FILE:${test}>\")\n    else()\n      add_test(NAME ${test} COMMAND ${test})\n    endif()\n  endif()\n\n  set_tests_properties(${test} PROPERTIES TIMEOUT 10)\n  set_tests_properties(${test} PROPERTIES SKIP_RETURN_CODE 77)\n\n  if(QNX)\n    install(TARGETS ${test} RUNTIME DESTINATION bin/)\n  endif()\nendforeach()\n\n# override timeout for these tests\nset_tests_properties(test_heartbeats PROPERTIES TIMEOUT 60)\n\nif(WIN32 AND ENABLE_DRAFTS)\n  set_tests_properties(test_radio_dish PROPERTIES TIMEOUT 30)\nendif()\n\nif(NOT CMAKE_SYSTEM_NAME MATCHES \"Linux\")\n  if(ZMQ_HAVE_CURVE)\n    set_tests_properties(test_security_curve PROPERTIES TIMEOUT 60)\n  endif()\nendif()\n\nset_tests_properties(test_security_zap PROPERTIES TIMEOUT 60)\nset_tests_properties(test_reconnect_ivl PROPERTIES TIMEOUT 15)\n\n# Check whether all tests in the current folder are present\nfile(READ \"${CMAKE_CURRENT_LIST_FILE}\" CURRENT_LIST_FILE_CONTENT)\nfile(GLOB ALL_TEST_SOURCES \"test_*.cpp\")\n\nforeach(TEST_SOURCE ${ALL_TEST_SOURCES})\n  get_filename_component(TESTNAME \"${TEST_SOURCE}\" NAME_WE)\n  string(REGEX MATCH \"${TESTNAME}\" MATCH_TESTNAME \"${CURRENT_LIST_FILE_CONTENT}\")\n\n  if(NOT MATCH_TESTNAME)\n    message(AUTHOR_WARNING \"Test '${TESTNAME}' is not known to CTest.\")\n  endif()\nendforeach()\n"
  },
  {
    "path": "tests/README.md",
    "content": "#   Guidelines for tests\n\nWrite your test case as if you were writing clean application code. It should be safe to compile on all platforms.\n\nNormally, you should only include the header files from the tests directory, e.g. `testutil.hpp`. Do not include files from src. Do not use the internal libzmq API. Tests for these should be placed in unittests instead.\n\nIf you must write non-portable code, wrap it in #ifdefs to ensure it will compile and run on all systems.\n\nNote that testutil.hpp includes platform.h. Do not include it yourself as it changes location depending on the build system and OS.\n\nAll sources must contain the correct copyright header. Please copy from test_system.cpp if you're not certain.\n\nWrite new tests using the unity test framework. For an example, see test_sockopt_hwm.\n\nPlease use only ANSI C99 in test cases, no C++. This is to make the code more reusable.\n\nOn many slower environments, like embedded systems, VMs or CI systems, tests might\nfail because it takes time for sockets to settle after a connect. If you need\nto add a sleep, please be consistent with all the other tests and use:\n  msleep (SETTLE_TIME);\n  \n#   Ensure proper cleanup\n\nIf a test program uses unity, it will execute test cases individually, and will continue to run further test cases if an assertion in one test case fails. However, the test case that had an assertion failure will be aborted.\nTo ensure that the resources of the test case are properly cleaned up, use appropriate setUp and tearDown functions. These are run by unity before each test case starts resp. after it ended (whether successfully or not).\nThe same setUp and tearDown function is used for all test cases in a test program.\n\nFor many test cases, the following setUp and tearDown functions will be appropriate:\n\tvoid setUp ()\n\t{\n\t\tsetup_test_context ();\n\t}\n\n\tvoid tearDown ()\n\t{\n\t\tteardown_test_context ();\n\t}\n\nWithin the tests, do not use zmq_socket and zmq_close then but test_context_socket and test_context_socket_close instead. These functions will register/unregister sockets with the test_context. \nAll sockets not closed when tearDown is executed, with forcibly be closed with linger=0 before terminating the context. Note that it is a misuse not to close sockets during successful test execution, \nand a warning will be output.\n\n#   Building tests in Windows\n\nThe tests are only built via cmake, not when using the checked-in Visual Studio .sln files.\n"
  },
  {
    "path": "tests/test_abstract_ipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nstatic const char test_endpoint[] = \"ipc://@tmp-tester\";\nstatic const char test_endpoint_empty[] = \"ipc://@\";\n\nvoid test_roundtrip ()\n{\n    void *sb = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, test_endpoint));\n\n    char endpoint[MAX_SOCKET_STRING];\n    size_t size = sizeof (endpoint);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, endpoint, &size));\n    TEST_ASSERT_EQUAL_INT (0, strncmp (endpoint, test_endpoint, size));\n\n    void *sc = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, test_endpoint));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_empty_abstract_name ()\n{\n    void *sb = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_bind (sb, test_endpoint_empty));\n\n    test_context_socket_close (sb);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip);\n    RUN_TEST (test_empty_abstract_name);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_address_tipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_tipc_port_name_and_domain ()\n{\n    // test Port Name addressing\n    void *sb = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"tipc://{5560,0,0}\"));\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, \"tipc://{5560,0}@0.0.0\"));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_tipc_port_identity ()\n{\n    char endpoint[256];\n    unsigned int z, c, n, ref;\n\n    void *sb = test_context_socket (ZMQ_REP);\n    void *sc = test_context_socket (ZMQ_REQ);\n\n    // Test binding to random Port Identity and\n    // test resolving assigned address, should return a properly formatted string\n    bind_loopback_tipc (sb, endpoint, sizeof endpoint);\n\n    int rc = sscanf (&endpoint[0], \"tipc://<%u.%u.%u:%u>\", &z, &c, &n, &ref);\n    TEST_ASSERT_EQUAL_INT (4, rc);\n\n    TEST_ASSERT_NOT_EQUAL_MESSAGE (\n      0, ref, \"tipc port number must not be 0 after random assignment\");\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_tipc_bad_addresses ()\n{\n    // Test Port Name addressing\n    void *sb = test_context_socket (ZMQ_REP);\n\n    // Test binding to a fixed address, should fail\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_bind (sb, \"tipc://<1.2.3:123123>\"));\n\n    // Test connecting to random identity, should fail\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_connect (sb, \"tipc://<*>\"));\n\n    // Clean up\n    test_context_socket_close (sb);\n}\n\n\nint main ()\n{\n    setup_test_environment ();\n\n    if (!is_tipc_available ()) {\n        printf (\"TIPC environment unavailable, skipping test\\n\");\n        return 77;\n    }\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_tipc_port_name_and_domain);\n    RUN_TEST (test_tipc_port_identity);\n    RUN_TEST (test_tipc_bad_addresses);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_ancillaries.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n/*\n * File for adding tests for ancillary API methods and other miscellaenous\n * API internals. Please ensure that when adding such tests into this file,\n * that they are short-lived so they do not trigger timeouts in the\n * CI build environments.\n */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\nvoid test_version ()\n{\n    int major, minor, patch;\n\n    zmq_version (&major, &minor, &patch);\n    TEST_ASSERT_EQUAL_INT (ZMQ_VERSION_MAJOR, major);\n    TEST_ASSERT_EQUAL_INT (ZMQ_VERSION_MINOR, minor);\n    TEST_ASSERT_EQUAL_INT (ZMQ_VERSION_PATCH, patch);\n}\n\nvoid test_strerrror ()\n{\n    TEST_ASSERT_NOT_NULL (zmq_strerror (EINVAL));\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_version);\n    RUN_TEST (test_strerrror);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_app_meta.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n#include <unity.h>\n\n#include <string.h>\n\nvoid setUp ()\n{\n}\nvoid tearDown ()\n{\n}\n\nvoid test_app_meta_reqrep ()\n{\n    void *ctx;\n    zmq_msg_t msg;\n    void *rep_sock, *req_sock;\n    char connect_address[MAX_SOCKET_STRING];\n    const char *req_hello = \"X-hello:hello\";\n    const char *req_connection = \"X-connection:primary\";\n    const char *req_z85 = \"X-bin:009c6\";\n    const char *rep_hello = \"X-hello:world\";\n    const char *rep_connection = \"X-connection:backup\";\n    const char *bad_strings[] = {\n      \":\",\n      \"key:\",\n      \":value\",\n      \"keyvalue\",\n      \"\",\n      \"X-\"\n      \"KeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKe\"\n      \"yTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyT\"\n      \"ooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyToo\"\n      \"LongKeyTooLongKeyTooLongKeyTooLongKeyTooLong:value\"};\n\n    ctx = zmq_ctx_new ();\n    rep_sock = zmq_socket (ctx, ZMQ_REP);\n    TEST_ASSERT_NOT_NULL (rep_sock);\n    req_sock = zmq_socket (ctx, ZMQ_REQ);\n    TEST_ASSERT_NOT_NULL (req_sock);\n\n    int rc =\n      zmq_setsockopt (rep_sock, ZMQ_METADATA, rep_hello, strlen (rep_hello));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    int l = 0;\n    rc = zmq_setsockopt (rep_sock, ZMQ_LINGER, &l, sizeof (l));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    rc = zmq_setsockopt (rep_sock, ZMQ_METADATA, rep_connection,\n                         strlen (rep_connection));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    for (int i = 0; i < 6; i++) {\n        rc = zmq_setsockopt (rep_sock, ZMQ_METADATA, bad_strings[i],\n                             strlen (bad_strings[i]));\n        TEST_ASSERT_EQUAL_INT (-1, rc);\n    }\n\n    bind_loopback_ipv4 (rep_sock, connect_address, sizeof connect_address);\n\n    l = 0;\n    rc = zmq_setsockopt (req_sock, ZMQ_LINGER, &l, sizeof (l));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    rc = zmq_setsockopt (req_sock, ZMQ_METADATA, req_hello, strlen (req_hello));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    rc = zmq_setsockopt (req_sock, ZMQ_METADATA, req_connection,\n                         strlen (req_connection));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    rc = zmq_setsockopt (req_sock, ZMQ_METADATA, req_z85, strlen (req_z85));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    rc = zmq_connect (req_sock, connect_address);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    rc = zmq_msg_init_size (&msg, 1);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    char *data = static_cast<char *> (zmq_msg_data (&msg));\n    data[0] = 1;\n\n    rc = zmq_msg_send (&msg, req_sock, 0);\n    TEST_ASSERT_EQUAL_INT (1, rc);\n\n    rc = zmq_msg_init (&msg);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    rc = zmq_msg_recv (&msg, rep_sock, 0);\n    TEST_ASSERT_EQUAL_INT (1, rc);\n\n    TEST_ASSERT_EQUAL_STRING (\"hello\", zmq_msg_gets (&msg, \"X-hello\"));\n    TEST_ASSERT_EQUAL_STRING (\"primary\", zmq_msg_gets (&msg, \"X-connection\"));\n    const char *const bindata = zmq_msg_gets (&msg, \"X-bin\");\n    TEST_ASSERT_NOT_NULL (bindata);\n    uint8_t rawdata[4];\n    const uint8_t *const ret = zmq_z85_decode (rawdata, bindata);\n    TEST_ASSERT_NOT_NULL (ret);\n    TEST_ASSERT_EQUAL_UINT8 (0, rawdata[0]);\n    TEST_ASSERT_EQUAL_UINT8 (1, rawdata[1]);\n    TEST_ASSERT_EQUAL_UINT8 (2, rawdata[2]);\n    TEST_ASSERT_EQUAL_UINT8 (3, rawdata[3]);\n\n    TEST_ASSERT_NULL (zmq_msg_gets (&msg, \"X-foobar\"));\n    TEST_ASSERT_NULL (zmq_msg_gets (&msg, \"foobar\"));\n\n    rc = zmq_msg_send (&msg, rep_sock, 0);\n    TEST_ASSERT_EQUAL_INT (1, rc);\n\n    rc = zmq_msg_recv (&msg, req_sock, 0);\n    TEST_ASSERT_EQUAL_INT (1, rc);\n\n    TEST_ASSERT_EQUAL_STRING (\"world\", zmq_msg_gets (&msg, \"X-hello\"));\n    TEST_ASSERT_EQUAL_STRING (\"backup\", zmq_msg_gets (&msg, \"X-connection\"));\n\n    rc = zmq_msg_close (&msg);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    rc = zmq_close (req_sock);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    rc = zmq_close (rep_sock);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    zmq_ctx_term (ctx);\n}\n\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_app_meta_reqrep);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_atomics.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <unity.h>\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\nvoid test ()\n{\n    void *counter = zmq_atomic_counter_new ();\n    TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_value (counter));\n    TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_inc (counter));\n    TEST_ASSERT_EQUAL_INT (1, zmq_atomic_counter_inc (counter));\n    TEST_ASSERT_EQUAL_INT (2, zmq_atomic_counter_inc (counter));\n    TEST_ASSERT_EQUAL_INT (3, zmq_atomic_counter_value (counter));\n    TEST_ASSERT_EQUAL_INT (1, zmq_atomic_counter_dec (counter));\n    TEST_ASSERT_EQUAL_INT (1, zmq_atomic_counter_dec (counter));\n    TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_dec (counter));\n    zmq_atomic_counter_set (counter, 2);\n    TEST_ASSERT_EQUAL_INT (1, zmq_atomic_counter_dec (counter));\n    TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_dec (counter));\n    zmq_atomic_counter_destroy (&counter);\n}\n\nint main ()\n{\n    UNITY_BEGIN ();\n    RUN_TEST (test);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_base85.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\n// Test vector: rfc.zeromq.org/spec:32/Z85\nvoid test__zmq_z85_encode__valid__success ()\n{\n    static const size_t size = 8;\n    static const size_t length = size * 5 / 4;\n    static const uint8_t decoded[size] = {0x86, 0x4F, 0xD2, 0x6F,\n                                          0xB5, 0x59, 0xF7, 0x5B};\n    static const char expected[length + 1] = \"HelloWorld\";\n    char out_encoded[length + 1] = {0};\n\n    errno = 0;\n    TEST_ASSERT_NOT_NULL (zmq_z85_encode (out_encoded, decoded, size));\n    TEST_ASSERT_EQUAL_STRING (expected, out_encoded);\n    TEST_ASSERT_EQUAL_INT (0, zmq_errno ());\n}\n\n// Buffer length must be evenly divisible by 4 or must fail with EINVAL.\nvoid test__zmq_z85_encode__invalid__failure (size_t size_)\n{\n    errno = 0;\n    TEST_ASSERT_NULL (zmq_z85_encode (NULL, NULL, size_));\n    TEST_ASSERT_EQUAL_INT (EINVAL, zmq_errno ());\n}\n\n// Test vector: rfc.zeromq.org/spec:32/Z85\nvoid test__zmq_z85_decode__valid__success ()\n{\n    static const size_t size = 10 * 4 / 5;\n    static const uint8_t expected[size] = {0x86, 0x4F, 0xD2, 0x6F,\n                                           0xB5, 0x59, 0xF7, 0x5B};\n    static const char *encoded = \"HelloWorld\";\n    uint8_t out_decoded[size] = {0};\n\n    errno = 0;\n    TEST_ASSERT_NOT_NULL (zmq_z85_decode (out_decoded, encoded));\n    TEST_ASSERT_EQUAL_INT (0, zmq_errno ());\n    TEST_ASSERT_EQUAL_UINT8_ARRAY (expected, out_decoded, size);\n}\n\n// Invalid input data must fail with EINVAL.\ntemplate <size_t SIZE>\nvoid test__zmq_z85_decode__invalid__failure (const char (&encoded_)[SIZE])\n{\n    uint8_t decoded[SIZE * 4 / 5 + 1];\n    errno = 0;\n    TEST_ASSERT_NULL (zmq_z85_decode (decoded, encoded_));\n    TEST_ASSERT_EQUAL_INT (EINVAL, zmq_errno ());\n}\n\n\n// call zmq_z85_encode, then zmq_z85_decode, and compare the results with the original\ntemplate <size_t SIZE>\nvoid test__zmq_z85_encode__zmq_z85_decode__roundtrip (\n  const uint8_t (&test_data_)[SIZE])\n{\n    char test_data_z85[SIZE * 5 / 4 + 1];\n    const char *const res1 = zmq_z85_encode (test_data_z85, test_data_, SIZE);\n    TEST_ASSERT_NOT_NULL (res1);\n\n    uint8_t test_data_decoded[SIZE];\n    const uint8_t *const res2 =\n      zmq_z85_decode (test_data_decoded, test_data_z85);\n    TEST_ASSERT_NOT_NULL (res2);\n\n    TEST_ASSERT_EQUAL_UINT8_ARRAY (test_data_, test_data_decoded, SIZE);\n}\n\n// call zmq_z85_encode, then zmq_z85_decode, and compare the results with the original\ntemplate <size_t SIZE>\nvoid test__zmq_z85_decode__zmq_z85_encode__roundtrip (\n  const char (&test_data_)[SIZE])\n{\n    const size_t decoded_size = (SIZE - 1) * 4 / 5;\n    uint8_t test_data_decoded[decoded_size];\n    const uint8_t *const res1 = zmq_z85_decode (test_data_decoded, test_data_);\n    TEST_ASSERT_NOT_NULL (res1);\n\n    char test_data_z85[SIZE];\n    const char *const res2 =\n      zmq_z85_encode (test_data_z85, test_data_decoded, decoded_size);\n    TEST_ASSERT_NOT_NULL (res2);\n\n    TEST_ASSERT_EQUAL_UINT8_ARRAY (test_data_, test_data_z85, SIZE);\n}\n\n#define def_test__zmq_z85_basename(basename, name, param)                      \\\n    void test__zmq_z85_##basename##_##name ()                                  \\\n    {                                                                          \\\n        test__zmq_z85_##basename (param);                                      \\\n    }\n\n#define def_test__zmq_z85_encode__invalid__failure(name, param)                \\\n    def_test__zmq_z85_basename (encode__invalid__failure, name, param)\n\ndef_test__zmq_z85_encode__invalid__failure (1, 1)\n  def_test__zmq_z85_encode__invalid__failure (42, 42)\n\n#define def_test__zmq_z85_decode__invalid__failure(name, param)                \\\n    def_test__zmq_z85_basename (decode__invalid__failure, name, param)\n\n  // String length must be evenly divisible by 5 or must fail with EINVAL.\n  def_test__zmq_z85_decode__invalid__failure (indivisble_by_5_multiple_chars,\n                                              \"01234567\")\n    def_test__zmq_z85_decode__invalid__failure (indivisble_by_5_one_char, \"0\")\n\n  // decode invalid data with the maximum representable value\n  def_test__zmq_z85_decode__invalid__failure (max, \"#####\")\n\n  // decode invalid data with the minimum value beyond the limit\n  // \"%nSc0\" is 0xffffffff\n  def_test__zmq_z85_decode__invalid__failure (above_limit, \"%nSc1\")\n\n  // decode invalid data with an invalid character in the range of valid\n  // characters\n  def_test__zmq_z85_decode__invalid__failure (char_within, \"####\\0047\")\n\n  // decode invalid data with an invalid character just below the range of valid\n  // characters\n  def_test__zmq_z85_decode__invalid__failure (char_adjacent_below, \"####\\0200\")\n\n  // decode invalid data with an invalid character just above the range of valid\n  // characters\n  def_test__zmq_z85_decode__invalid__failure (char_adjacent_above, \"####\\0037\")\n\n#define def_test__encode__zmq_z85_decode__roundtrip(name, param)               \\\n    def_test__zmq_z85_basename (encode__zmq_z85_decode__roundtrip, name, param)\n\n    const uint8_t test_data_min[] = {0x00, 0x00, 0x00, 0x00};\nconst uint8_t test_data_max[] = {0xff, 0xff, 0xff, 0xff};\n\ndef_test__encode__zmq_z85_decode__roundtrip (min, test_data_min)\n  def_test__encode__zmq_z85_decode__roundtrip (max, test_data_max)\n\n#define def_test__decode__zmq_z85_encode__roundtrip(name, param)               \\\n    def_test__zmq_z85_basename (decode__zmq_z85_encode__roundtrip, name, param)\n\n    const char test_data_regular[] = \"r^/rM9M=rMToK)63O8dCvd9D<PY<7iGlC+{BiSnG\";\n\ndef_test__decode__zmq_z85_encode__roundtrip (regular, test_data_regular)\n\n  int main ()\n{\n    UNITY_BEGIN ();\n    RUN_TEST (test__zmq_z85_encode__valid__success);\n    RUN_TEST (test__zmq_z85_encode__invalid__failure_1);\n    RUN_TEST (test__zmq_z85_encode__invalid__failure_42);\n\n    RUN_TEST (test__zmq_z85_decode__valid__success);\n    RUN_TEST (\n      test__zmq_z85_decode__invalid__failure_indivisble_by_5_multiple_chars);\n    RUN_TEST (test__zmq_z85_decode__invalid__failure_indivisble_by_5_one_char);\n    RUN_TEST (test__zmq_z85_decode__invalid__failure_max);\n    RUN_TEST (test__zmq_z85_decode__invalid__failure_above_limit);\n    RUN_TEST (test__zmq_z85_decode__invalid__failure_char_within);\n    RUN_TEST (test__zmq_z85_decode__invalid__failure_char_adjacent_below);\n    RUN_TEST (test__zmq_z85_decode__invalid__failure_char_adjacent_above);\n\n    RUN_TEST (test__zmq_z85_encode__zmq_z85_decode__roundtrip_min);\n    RUN_TEST (test__zmq_z85_encode__zmq_z85_decode__roundtrip_max);\n\n    RUN_TEST (test__zmq_z85_decode__zmq_z85_encode__roundtrip_regular);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_bind_after_connect_tcp.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_x ()\n{\n    void *sb = test_context_socket (ZMQ_DEALER);\n    void *sc = test_context_socket (ZMQ_DEALER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, ENDPOINT_3));\n\n    send_string_expect_success (sc, \"foobar\", 0);\n    send_string_expect_success (sc, \"baz\", 0);\n    send_string_expect_success (sc, \"buzz\", 0);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, ENDPOINT_3));\n\n    recv_string_expect_success (sb, \"foobar\", 0);\n    recv_string_expect_success (sb, \"baz\", 0);\n    recv_string_expect_success (sb, \"buzz\", 0);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_x);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_bind_curve_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include <string.h>\n\n#include \"testutil.hpp\"\n#include \"testutil_security.hpp\"\n\n// Test that the ZMTP engine handles invalid handshake when binding\n// https://rfc.zeromq.org/spec/37/\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    const char *fixed_client_public =\n      \"{{k*81)yMWEF{/BxdMd[5RL^qRFxBgoL<8m.D^KD\";\n    const char *fixed_client_secret =\n      \"N?Gmik8R[2ACw{b7*[-$S6[4}aO#?DB?#=<OQPc7\";\n    const char *fixed_server_public =\n      \"3.9-xXwy{g*w72TP*3iB9IJJRxlBH<ufTAvPd2>C\";\n    const char *fixed_server_secret =\n      \"T}t5GLq%&Qm1)y3ywu-}pY3KEA//{^Ut!M1ut+B4\";\n    void *handler;\n    void *zap_thread;\n    void *server;\n    void *server_mon;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    setup_test_context ();\n    memcpy (valid_client_public, fixed_client_public, 41);\n    setup_context_and_server_side (\n      &handler, &zap_thread, &server, &server_mon, my_endpoint, &zap_handler,\n      &socket_config_curve_server, (void *) fixed_server_secret);\n    fd_t client = connect_socket (my_endpoint);\n\n    //  If there is not enough data for a full greeting, just send what we can\n    //  Otherwise send greeting first, as expected by the protocol\n    uint8_t buf[512];\n    if (size >= 64) {\n        send (client, (void *) data, 64, MSG_NOSIGNAL);\n        data += 64;\n        size -= 64;\n    }\n    recv (client, buf, 64, 0);\n    // Then send HELLO and expect WELCOME if there's enough data\n    if (size >= 202) {\n        send (client, (void *) data, 202, MSG_NOSIGNAL);\n        data += 202;\n        size -= 202;\n        recv (client, buf, 170, MSG_DONTWAIT);\n    }\n    // Then send READY and expect INITIATE if there's enough data\n    if (size >= 301) {\n        send (client, (void *) data, 301, MSG_NOSIGNAL);\n        data += 301;\n        size -= 301;\n        recv (client, buf, 512, MSG_DONTWAIT);\n    }\n    msleep (250);\n    for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);\n         size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)\n        sent = send (client, (const char *) data, size, MSG_NOSIGNAL);\n    msleep (250);\n\n    //  Drain the queue, if any\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    while (-1 != zmq_msg_recv (&msg, server, ZMQ_DONTWAIT)) {\n        zmq_msg_close (&msg);\n        zmq_msg_init (&msg);\n    }\n\n    //  A well-behaved client should work while the malformed data from the other\n    //  is being received\n    curve_client_data_t curve_client_data = {\n      fixed_server_public, fixed_client_public, fixed_client_secret};\n    void *client_mon;\n    void *client_good = create_and_connect_client (\n      my_endpoint, socket_config_curve_client, &curve_client_data, &client_mon);\n\n    bounce (server, client_good);\n\n    close (client);\n    test_context_socket_close_zero_linger (client_good);\n    test_context_socket_close_zero_linger (client_mon);\n    shutdown_context_and_server_side (zap_thread, server, server_mon, handler);\n    teardown_test_context ();\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_bind_curve_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_bind_curve_fuzzer_seed_corpus\", &data,\n          &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_bind_curve_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_bind_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include <string>\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#ifndef PATH_MAX\n#define PATH_MAX 1024\n#endif\n\n// Test that zmq_bind can handle malformed strings\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    //  This test might create socket files, so move to /tmp to avoid clobbering\n    //  the working directory with random filenames\n    char *pwd = (char *) malloc (PATH_MAX + 1);\n    TEST_ASSERT_NOT_NULL (pwd);\n    TEST_ASSERT_NOT_NULL (getcwd (pwd, PATH_MAX + 1));\n    TEST_ASSERT_SUCCESS_ERRNO (chdir (\"/tmp\"));\n\n    setup_test_context ();\n    std::string my_endpoint (reinterpret_cast<const char *> (data), size);\n    void *socket = test_context_socket (ZMQ_PUB);\n    zmq_bind (socket, my_endpoint.c_str ());\n\n    test_context_socket_close_zero_linger (socket);\n    teardown_test_context ();\n    TEST_ASSERT_SUCCESS_ERRNO (chdir (pwd));\n    free (pwd);\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_bind_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_bind_fuzzer_seed_corpus\", &data, &len,\n          &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    LIBZMQ_UNUSED (argc);\n    LIBZMQ_UNUSED (argv);\n\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_bind_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_bind_null_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n// Test that the ZMTP engine handles invalid handshake when binding\n// https://rfc.zeromq.org/spec/37/\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    setup_test_context ();\n    char my_endpoint[MAX_SOCKET_STRING];\n    void *server = test_context_socket (ZMQ_PUB);\n    //  As per API by default there's no limit to the size of a message,\n    //  but the sanitizer allocator will barf over a gig or so\n    int64_t max_msg_size = 64 * 1024 * 1024;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));\n    bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));\n    fd_t client = connect_socket (my_endpoint);\n\n    void *client_good = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client_good, ZMQ_SUBSCRIBE, \"\", 0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_good, my_endpoint));\n\n    //  If there is not enough data for a full greeting, just send what we can\n    //  Otherwise send greeting first, as expected by the protocol\n    uint8_t buf[64];\n    if (size >= 64) {\n        send (client, (void *) data, 64, MSG_NOSIGNAL);\n        data += 64;\n        size -= 64;\n    }\n    recv (client, buf, 64, 0);\n    msleep (250);\n    for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);\n         size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)\n        sent = send (client, (const char *) data, size, MSG_NOSIGNAL);\n    msleep (250);\n\n    TEST_ASSERT_EQUAL_INT (6, zmq_send_const (server, \"HELLO\", 6, 0));\n    TEST_ASSERT_EQUAL_INT (6, zmq_recv (client_good, buf, 6, 0));\n\n    close (client);\n    test_context_socket_close_zero_linger (client_good);\n    test_context_socket_close_zero_linger (server);\n    teardown_test_context ();\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_bind_null_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_bind_null_fuzzer_seed_corpus\", &data,\n          &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    LIBZMQ_UNUSED (argc);\n    LIBZMQ_UNUSED (argv);\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_bind_null_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_bind_src_address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_x ()\n{\n    void *sock = test_context_socket (ZMQ_PUB);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (sock, \"tcp://127.0.0.1:0;localhost:1234\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (sock, \"tcp://localhost:5555;localhost:1235\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (sock, \"tcp://lo:5555;localhost:1235\"));\n\n    test_context_socket_close (sock);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_x);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_bind_stream_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n// Test that the ZMTP engine handles invalid handshake when binding\n// https://rfc.zeromq.org/spec/37/\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    setup_test_context ();\n    char my_endpoint[MAX_SOCKET_STRING];\n    void *server = test_context_socket (ZMQ_STREAM);\n    //  As per API by default there's no limit to the size of a message,\n    //  but the sanitizer allocator will barf over a gig or so\n    int64_t max_msg_size = 64 * 1024 * 1024;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));\n    bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));\n    fd_t client = connect_socket (my_endpoint);\n\n    //  If there is not enough data for a full greeting, just send what we can\n    //  Otherwise send greeting first, as expected by the protocol\n    uint8_t buf[64];\n    if (size >= 64) {\n        send (client, (void *) data, 64, MSG_NOSIGNAL);\n        data += 64;\n        size -= 64;\n    }\n    recv (client, buf, 64, MSG_DONTWAIT);\n    msleep (250);\n    for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);\n         size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)\n        sent = send (client, (const char *) data, size, MSG_NOSIGNAL);\n    msleep (250);\n\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    while (-1 != zmq_msg_recv (&msg, server, ZMQ_DONTWAIT)) {\n        zmq_msg_close (&msg);\n        zmq_msg_init (&msg);\n    }\n\n    void *client_good = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_good, my_endpoint));\n\n    TEST_ASSERT_EQUAL_INT (6, zmq_send_const (client_good, \"HELLO\", 6, 0));\n    zmq_msg_t routing_id;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&routing_id));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&routing_id, server, 0));\n    TEST_ASSERT_TRUE (zmq_msg_more (&routing_id));\n    char const *peer_address = zmq_msg_gets (&routing_id, \"Peer-Address\");\n    zmq_msg_close (&routing_id);\n    TEST_ASSERT_NOT_NULL (peer_address);\n    TEST_ASSERT_EQUAL_STRING (\"127.0.0.1\", peer_address);\n    TEST_ASSERT_EQUAL_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, buf, 64, 0)));\n    zmq_msg_init (&msg);\n    while (-1 != zmq_msg_recv (&msg, server, ZMQ_DONTWAIT)) {\n        zmq_msg_close (&msg);\n        zmq_msg_init (&msg);\n    }\n\n    close (client);\n    test_context_socket_close_zero_linger (client_good);\n    test_context_socket_close_zero_linger (server);\n    teardown_test_context ();\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_bind_stream_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_bind_stream_fuzzer_seed_corpus\",\n          &data, &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_bind_stream_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_bind_ws_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n// Test that the ZMTP WebSocket engine handles invalid handshake when connecting\n// https://rfc.zeromq.org/spec/45/\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    setup_test_context ();\n    char my_endpoint[MAX_SOCKET_STRING];\n    size_t my_endpoint_size = sizeof (my_endpoint);\n    void *server = test_context_socket (ZMQ_DEALER);\n    //  As per API by default there's no limit to the size of a message,\n    //  but the sanitizer allocator will barf over a gig or so\n    int64_t max_msg_size = 64 * 1024 * 1024;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, \"ws://127.0.0.1:*\"));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (server, ZMQ_LAST_ENDPOINT,\n                                               my_endpoint, &my_endpoint_size));\n    //  Remove trailing /\n    my_endpoint[my_endpoint_size - 2] = '\\0';\n    fd_t client = connect_socket (my_endpoint, AF_INET, IPPROTO_WS);\n\n    void *client_good = test_context_socket (ZMQ_DEALER);\n    my_endpoint[my_endpoint_size - 2] = '/';\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_good, my_endpoint));\n\n    //  If there is not enough data for a full handshake, just send what we can\n    //  Otherwise send websocket handshake first, as expected by the protocol\n    uint8_t buf[256];\n    if (size >= 192) {\n        send (client, (void *) data, 192, MSG_NOSIGNAL);\n        data += 192;\n        size -= 192;\n    }\n    recv (client, buf, 256, MSG_DONTWAIT);\n    msleep (250);\n    for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);\n         size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)\n        sent = send (client, (const char *) data, size, MSG_NOSIGNAL);\n    msleep (250);\n    recv (client, buf, 256, MSG_DONTWAIT);\n\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    while (-1 != zmq_msg_recv (&msg, server, ZMQ_DONTWAIT)) {\n        zmq_msg_close (&msg);\n        zmq_msg_init (&msg);\n    }\n\n    send_string_expect_success (client_good, \"abc\", 0);\n    recv_string_expect_success (server, \"abc\", 0);\n\n    close (client);\n    test_context_socket_close_zero_linger (client_good);\n    test_context_socket_close_zero_linger (server);\n    teardown_test_context ();\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_bind_ws_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_bind_ws_fuzzer_seed_corpus\", &data,\n          &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_bind_ws_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_busy_poll.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_busy_poll ()\n{\n    //  Create a socket\n    void *socket = test_context_socket (ZMQ_DEALER);\n\n    //  set socket ZMQ_BUSY_POLL options\n    int busy_poll = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket, ZMQ_BUSY_POLL, &busy_poll, sizeof (int)));\n\n    //  bind socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (socket, \"tcp://127.0.0.1:*\"));\n\n    //  Clean up.\n    test_context_socket_close (socket);\n}\n\nint main ()\n{\n    setup_test_environment ();\n    UNITY_BEGIN ();\n    RUN_TEST (test_busy_poll);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_capabilities.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\nvoid test_capabilities ()\n{\n#if defined(ZMQ_HAVE_IPC)\n    TEST_ASSERT_TRUE (zmq_has (\"ipc\"));\n#else\n    TEST_ASSERT_TRUE (!zmq_has (\"ipc\"));\n#endif\n\n#if defined(ZMQ_HAVE_OPENPGM)\n    TEST_ASSERT_TRUE (zmq_has (\"pgm\"));\n#else\n    TEST_ASSERT_TRUE (!zmq_has (\"pgm\"));\n#endif\n\n#if defined(ZMQ_HAVE_TIPC)\n    TEST_ASSERT_TRUE (zmq_has (\"tipc\"));\n#else\n    TEST_ASSERT_TRUE (!zmq_has (\"tipc\"));\n#endif\n\n#if defined(ZMQ_HAVE_NORM)\n    TEST_ASSERT_TRUE (zmq_has (\"norm\"));\n#else\n    TEST_ASSERT_TRUE (!zmq_has (\"norm\"));\n#endif\n\n#if defined(ZMQ_HAVE_CURVE)\n    TEST_ASSERT_TRUE (zmq_has (\"curve\"));\n#else\n    TEST_ASSERT_TRUE (!zmq_has (\"curve\"));\n#endif\n\n#if defined(HAVE_LIBGSSAPI_KRB5)\n    TEST_ASSERT_TRUE (zmq_has (\"gssapi\"));\n#else\n    TEST_ASSERT_TRUE (!zmq_has (\"gssapi\"));\n#endif\n\n#if defined(ZMQ_HAVE_VMCI)\n    TEST_ASSERT_TRUE (zmq_has (\"vmci\"));\n#else\n    TEST_ASSERT_TRUE (!zmq_has (\"vmci\"));\n#endif\n\n#if defined(ZMQ_BUILD_DRAFT_API)\n    TEST_ASSERT_TRUE (zmq_has (\"draft\"));\n#else\n    TEST_ASSERT_TRUE (!zmq_has (\"draft\"));\n#endif\n\n#if defined(ZMQ_HAVE_VSOCK)\n    TEST_ASSERT_TRUE (zmq_has (\"vsock\"));\n#else\n    TEST_ASSERT_TRUE (!zmq_has (\"vsock\"));\n#endif\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_capabilities);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_channel.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <unity.h>\n\nvoid *sb;\nvoid *sc;\n\nvoid setUp ()\n{\n    setup_test_context ();\n\n    sb = test_context_socket (ZMQ_CHANNEL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"inproc://a\"));\n\n    sc = test_context_socket (ZMQ_CHANNEL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, \"inproc://a\"));\n}\n\nvoid tearDown ()\n{\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n\n    teardown_test_context ();\n}\n\nvoid test_roundtrip ()\n{\n    send_string_expect_success (sb, \"HELLO\", 0);\n    recv_string_expect_success (sc, \"HELLO\", 0);\n\n    send_string_expect_success (sc, \"WORLD\", 0);\n    recv_string_expect_success (sb, \"WORLD\", 0);\n}\n\nvoid test_sndmore_fails ()\n{\n    int rc = zmq_send (sc, \"X\", 1, ZMQ_SNDMORE);\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (EINVAL, errno);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip);\n    RUN_TEST (test_sndmore_fails);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_client_server.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid create_inproc_client_server_pair (void **server_, void **client_)\n{\n    *server_ = test_context_socket (ZMQ_SERVER);\n    *client_ = test_context_socket (ZMQ_CLIENT);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_bind (*server_, \"inproc://test-client-server\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (*client_, \"inproc://test-client-server\"));\n}\n\nvoid send_sndmore_expect_failure (void *socket_)\n{\n    int rc = zmq_send (socket_, \"X\", 1, ZMQ_SNDMORE);\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (EINVAL, errno);\n}\n\nvoid test_client_sndmore_fails ()\n{\n    void *server, *client;\n    create_inproc_client_server_pair (&server, &client);\n\n    send_sndmore_expect_failure (client);\n\n    test_context_socket_close (server);\n    test_context_socket_close (client);\n}\n\nvoid test_server_sndmore_fails ()\n{\n    void *server, *client;\n    create_inproc_client_server_pair (&server, &client);\n\n    send_sndmore_expect_failure (server);\n\n    test_context_socket_close (server);\n    test_context_socket_close (client);\n}\n\nvoid test_routing_id ()\n{\n    void *server, *client;\n    create_inproc_client_server_pair (&server, &client);\n\n    send_string_expect_success (client, \"X\", 0);\n\n    uint32_t routing_id;\n    {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n        int rc = TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, server, 0));\n        TEST_ASSERT_EQUAL_INT (1, rc);\n\n        routing_id = zmq_msg_routing_id (&msg);\n        TEST_ASSERT_NOT_EQUAL (0, routing_id);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n    }\n\n    {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));\n\n        char *data = static_cast<char *> (zmq_msg_data (&msg));\n        data[0] = 2;\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_set_routing_id (&msg, routing_id));\n\n        int rc = zmq_msg_send (&msg, server, 0);\n        TEST_ASSERT_EQUAL_INT (1, rc);\n    }\n\n    {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n        int rc = zmq_msg_recv (&msg, client, 0);\n        TEST_ASSERT_EQUAL_INT (1, rc);\n\n        routing_id = zmq_msg_routing_id (&msg);\n        TEST_ASSERT_EQUAL_UINT32 (0, routing_id);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n    }\n\n    test_context_socket_close (server);\n    test_context_socket_close (client);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_client_sndmore_fails);\n    RUN_TEST (test_server_sndmore_fails);\n    RUN_TEST (test_routing_id);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_conflate.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_conflate ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    int rc;\n\n    void *s_in = test_context_socket (ZMQ_PULL);\n\n    int conflate = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (s_in, ZMQ_CONFLATE, &conflate, sizeof (conflate)));\n    bind_loopback_ipv4 (s_in, my_endpoint, sizeof my_endpoint);\n\n    void *s_out = test_context_socket (ZMQ_PUSH);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (s_out, my_endpoint));\n\n    int message_count = 20;\n    for (int j = 0; j < message_count; ++j) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_send (s_out, (void *) &j, sizeof (int), 0));\n    }\n    msleep (SETTLE_TIME);\n\n    int payload_recved = 0;\n    rc = TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_recv (s_in, (void *) &payload_recved, sizeof (int), 0));\n    TEST_ASSERT_GREATER_THAN_INT (0, rc);\n    TEST_ASSERT_EQUAL_INT (message_count - 1, payload_recved);\n\n    test_context_socket_close (s_in);\n    test_context_socket_close (s_out);\n}\n\nint main (int, char *[])\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_conflate);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_connect_curve_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include \"testutil.hpp\"\n#include \"testutil_security.hpp\"\n\n// Test that the ZMTP engine handles invalid handshake when connecting\n// https://rfc.zeromq.org/spec/37/\n// https://rfc.zeromq.org/spec/26/\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    const char *fixed_client_public =\n      \"{{k*81)yMWEF{/BxdMd[5RL^qRFxBgoL<8m.D^KD\";\n    const char *fixed_client_secret =\n      \"N?Gmik8R[2ACw{b7*[-$S6[4}aO#?DB?#=<OQPc7\";\n    const char *fixed_server_public =\n      \"3.9-xXwy{g*w72TP*3iB9IJJRxlBH<ufTAvPd2>C\";\n\n    setup_test_context ();\n    char my_endpoint[MAX_SOCKET_STRING];\n    fd_t server = bind_socket_resolve_port (\"127.0.0.1\", \"0\", my_endpoint);\n\n    curve_client_data_t curve_client_data = {\n      fixed_server_public, fixed_client_public, fixed_client_secret};\n    void *client_mon;\n    void *client = create_and_connect_client (\n      my_endpoint, socket_config_curve_client, &curve_client_data, &client_mon);\n\n    fd_t server_accept =\n      TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server, NULL, NULL));\n\n    //  If there is not enough data for a full greeting, just send what we can\n    //  Otherwise send greeting first, as expected by the protocol\n    uint8_t buf[512];\n    if (size >= 64) {\n        send (server_accept, (void *) data, 64, MSG_NOSIGNAL);\n        data += 64;\n        size -= 64;\n    }\n    recv (server_accept, buf, 64, 0);\n    // Then expect HELLO and send WELCOME if there's enough data\n    if (size >= 170) {\n        recv (server_accept, buf, 202, 0);\n        send (server_accept, (void *) data, 170, MSG_NOSIGNAL);\n        data += 170;\n        size -= 170;\n    }\n    // Then expect INITIATE and send READY if there's enough data\n    if (size >= 72) {\n        recv (server_accept, buf, 512, 0);\n        send (server_accept, (void *) data, 72, MSG_NOSIGNAL);\n        data += 72;\n        size -= 72;\n    }\n    msleep (250);\n    for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);\n         size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)\n        sent = send (server_accept, (const char *) data, size, MSG_NOSIGNAL);\n    recv (server_accept, buf, 512, MSG_DONTWAIT);\n    msleep (250);\n\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    while (-1 != zmq_msg_recv (&msg, client, ZMQ_DONTWAIT)) {\n        zmq_msg_close (&msg);\n        zmq_msg_init (&msg);\n    }\n\n    close (server_accept);\n    close (server);\n\n    test_context_socket_close_zero_linger (client);\n    test_context_socket_close_zero_linger (client_mon);\n    teardown_test_context ();\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_connect_curve_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_connect_curve_fuzzer_seed_corpus\",\n          &data, &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_connect_curve_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_connect_delay_tipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n#include \"testutil_security.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_send_one_connected_one_unconnected ()\n{\n    int val;\n    // TEST 1.\n    // First we're going to attempt to send messages to two\n    // pipes, one connected, the other not. We should see\n    // the PUSH load balancing to both pipes, and hence half\n    // of the messages getting queued, as connect() creates a\n    // pipe immediately.\n\n    void *to = test_context_socket (ZMQ_PULL);\n    int timeout = 5000;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (to, ZMQ_LINGER, &timeout, sizeof (timeout)));\n\n    // Bind the one valid receiver\n    val = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (to, ZMQ_LINGER, &val, sizeof (val)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (to, \"tipc://{6555,0,0}\"));\n\n    // Create a socket pushing to two endpoints - only 1 message should arrive.\n    void *from = test_context_socket (ZMQ_PUSH);\n\n    val = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (from, ZMQ_LINGER, &val, sizeof (val)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (from, ZMQ_LINGER, &timeout, sizeof (timeout)));\n    // This pipe will not connect\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, \"tipc://{5556,0}@0.0.0\"));\n    // This pipe will\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, \"tipc://{6555,0}@0.0.0\"));\n\n    // We send 10 messages, 5 should just get stuck in the queue\n    // for the not-yet-connected pipe\n    const int send_count = 10;\n    for (int i = 0; i < send_count; ++i) {\n        send_string_expect_success (from, \"Hello\", 0);\n    }\n\n    // We now consume from the connected pipe\n    // - we should see just 5\n    timeout = SETTLE_TIME;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (to, ZMQ_RCVTIMEO, &timeout, sizeof (int)));\n\n    int seen = 0;\n    while (true) {\n        char buffer[16];\n        int rc = zmq_recv (to, &buffer, sizeof (buffer), 0);\n        if (rc == -1) {\n            TEST_ASSERT_EQUAL_INT (EAGAIN, zmq_errno ());\n            break; //  Break when we didn't get a message\n        }\n        seen++;\n    }\n    TEST_ASSERT_EQUAL_INT (send_count / 2, seen);\n\n    test_context_socket_close (from);\n    test_context_socket_close (to);\n}\n\nvoid test_send_one_connected_one_unconnected_with_delay ()\n{\n    int val;\n\n    // TEST 2\n    // This time we will do the same thing, connect two pipes,\n    // one of which will succeed in connecting to a bound\n    // receiver, the other of which will fail. However, we will\n    // also set the delay attach on connect flag, which should\n    // cause the pipe attachment to be delayed until the connection\n    // succeeds.\n\n    // Bind the valid socket\n    void *to = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (to, \"tipc://{5560,0,0}\"));\n    int timeout = 5000;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (to, ZMQ_LINGER, &timeout, sizeof (timeout)));\n\n    val = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (to, ZMQ_LINGER, &val, sizeof (val)));\n\n    // Create a socket pushing to two endpoints - all messages should arrive.\n    void *from = test_context_socket (ZMQ_PUSH);\n\n    val = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (from, ZMQ_LINGER, &val, sizeof (val)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (from, ZMQ_LINGER, &timeout, sizeof (timeout)));\n\n    // Set the key flag\n    val = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (from, ZMQ_DELAY_ATTACH_ON_CONNECT, &val, sizeof (val)));\n\n    // Connect to the invalid socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, \"tipc://{5561,0}@0.0.0\"));\n    // Connect to the valid socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, \"tipc://{5560,0}@0.0.0\"));\n\n    // Send 10 messages, all should be routed to the connected pipe\n    const int send_count = 10;\n    for (int i = 0; i < send_count; ++i) {\n        send_string_expect_success (from, \"Hello\", 0);\n    }\n    timeout = SETTLE_TIME;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (to, ZMQ_RCVTIMEO, &timeout, sizeof (int)));\n\n    int seen = 0;\n    while (true) {\n        char buffer[16];\n        int rc = zmq_recv (to, &buffer, sizeof (buffer), 0);\n        if (rc == -1) {\n            TEST_ASSERT_EQUAL_INT (EAGAIN, zmq_errno ());\n            break; //  Break when we didn't get a message\n        }\n        seen++;\n    }\n    TEST_ASSERT_EQUAL_INT (send_count, seen);\n\n    test_context_socket_close (from);\n    test_context_socket_close (to);\n}\n\nvoid test_send_disconnected_with_delay ()\n{\n    // TEST 3\n    // This time we want to validate that the same blocking behaviour\n    // occurs with an existing connection that is broken. We will send\n    // messages to a connected pipe, disconnect and verify the messages\n    // block. Then we reconnect and verify messages flow again.\n    void *backend = test_context_socket (ZMQ_DEALER);\n    void *frontend = test_context_socket (ZMQ_DEALER);\n    void *monitor = test_context_socket (ZMQ_PAIR);\n    int rc;\n    int zero = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (backend, ZMQ_LINGER, &zero, sizeof (zero)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (frontend, ZMQ_LINGER, &zero, sizeof (zero)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (frontend, \"inproc://monitor\",\n                                                   ZMQ_EVENT_DISCONNECTED));\n    int timeout = 5000;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (backend, ZMQ_LINGER, &timeout, sizeof (timeout)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (frontend, ZMQ_LINGER, &timeout, sizeof (timeout)));\n\n    //  Frontend connects to backend using DELAY_ATTACH_ON_CONNECT\n    int on = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (frontend, ZMQ_DELAY_ATTACH_ON_CONNECT, &on, sizeof (on)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, \"tipc://{5560,0,0}\"));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (monitor, \"inproc://monitor\"));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (frontend, \"tipc://{5560,0}@0.0.0\"));\n\n    //  Ping backend to frontend so we know when the connection is up\n    send_string_expect_success (backend, \"Hello\", 0);\n    recv_string_expect_success (frontend, \"Hello\", 0);\n\n    // Send message from frontend to backend\n    send_string_expect_success (frontend, \"Hello\", ZMQ_DONTWAIT);\n\n    test_context_socket_close (backend);\n\n    // Wait for disconnect to happen\n    expect_monitor_event (monitor, ZMQ_EVENT_DISCONNECTED);\n\n    // Send a message, might succeed depending on scheduling of the I/O thread\n    do {\n        rc = zmq_send (frontend, \"Hello\", 5, ZMQ_DONTWAIT);\n        TEST_ASSERT_TRUE (rc == 5 || (rc == -1 && zmq_errno () == EAGAIN));\n    } while (rc == 5);\n\n    //  Recreate backend socket\n    backend = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (backend, ZMQ_LINGER, &zero, sizeof (zero)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, \"tipc://{5560,0,0}\"));\n\n    //  Ping backend to frontend so we know when the connection is up\n    send_string_expect_success (backend, \"Hello\", 0);\n    recv_string_expect_success (frontend, \"Hello\", 0);\n\n    // After the reconnect, should succeed\n    send_string_expect_success (frontend, \"Hello\", ZMQ_DONTWAIT);\n\n    test_context_socket_close (monitor);\n    test_context_socket_close (backend);\n    test_context_socket_close (frontend);\n}\n\nint main (void)\n{\n    if (!is_tipc_available ()) {\n        printf (\"TIPC environment unavailable, skipping test\\n\");\n        return 77;\n    }\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_send_one_connected_one_unconnected);\n    RUN_TEST (test_send_one_connected_one_unconnected_with_delay);\n    RUN_TEST (test_send_disconnected_with_delay);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_connect_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include <string>\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n// Test that zmq_connect can handle malformed strings\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    setup_test_context ();\n    std::string my_endpoint (reinterpret_cast<const char *> (data), size);\n    void *socket = test_context_socket (ZMQ_PUB);\n    zmq_connect (socket, my_endpoint.c_str ());\n\n    test_context_socket_close_zero_linger (socket);\n    teardown_test_context ();\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_connect_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_connect_fuzzer_seed_corpus\", &data,\n          &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    LIBZMQ_UNUSED (argc);\n    LIBZMQ_UNUSED (argv);\n\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_connect_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_connect_null_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n// Test that the ZMTP engine handles invalid handshake when connecting\n// https://rfc.zeromq.org/spec/37/\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    setup_test_context ();\n    char my_endpoint[MAX_SOCKET_STRING];\n    fd_t server = bind_socket_resolve_port (\"127.0.0.1\", \"0\", my_endpoint);\n\n    void *client = test_context_socket (ZMQ_SUB);\n    //  As per API by default there's no limit to the size of a message,\n    //  but the sanitizer allocator will barf over a gig or so\n    int64_t max_msg_size = 64 * 1024 * 1024;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_SUBSCRIBE, \"\", 0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    fd_t server_accept =\n      TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server, NULL, NULL));\n\n    //  If there is not enough data for a full greeting, just send what we can\n    //  Otherwise send greeting first, as expected by the protocol\n    uint8_t buf[64];\n    if (size >= 64) {\n        send (server_accept, (void *) data, 64, MSG_NOSIGNAL);\n        data += 64;\n        size -= 64;\n    }\n    recv (server_accept, buf, 64, 0);\n    msleep (250);\n    for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);\n         size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)\n        sent = send (server_accept, (const char *) data, size, MSG_NOSIGNAL);\n    msleep (250);\n\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    while (-1 != zmq_msg_recv (&msg, client, ZMQ_DONTWAIT)) {\n        zmq_msg_close (&msg);\n        zmq_msg_init (&msg);\n    }\n\n    close (server_accept);\n    close (server);\n\n    test_context_socket_close_zero_linger (client);\n    teardown_test_context ();\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_connect_null_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_connect_null_fuzzer_seed_corpus\",\n          &data, &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    LIBZMQ_UNUSED (argc);\n    LIBZMQ_UNUSED (argv);\n\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_connect_null_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_connect_resolve.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n\n#include \"testutil_unity.hpp\"\n\n#include <unity.h>\n\nvoid *sock;\n\nvoid setUp ()\n{\n    setup_test_context ();\n    sock = test_context_socket (ZMQ_PUB);\n}\n\nvoid tearDown ()\n{\n    test_context_socket_close (sock);\n    sock = NULL;\n    teardown_test_context ();\n}\n\nvoid test_hostname_ipv4 ()\n{\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sock, \"tcp://localhost:1234\"));\n}\n\nvoid test_loopback_ipv6 ()\n{\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sock, \"tcp://[::1]:1234\"));\n}\n\nvoid test_invalid_service_fails ()\n{\n    int rc = zmq_connect (sock, \"tcp://localhost:invalid\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n}\n\nvoid test_hostname_with_spaces_fails ()\n{\n    int rc = zmq_connect (sock, \"tcp://in val id:1234\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n}\n\nvoid test_no_hostname_fails ()\n{\n    int rc = zmq_connect (sock, \"tcp://\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n}\n\nvoid test_x ()\n{\n    int rc = zmq_connect (sock, \"tcp://192.168.0.200:*\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n}\n\nvoid test_invalid_proto_fails ()\n{\n    int rc = zmq_connect (sock, \"invalid://localhost:1234\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (EPROTONOSUPPORT, errno);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_hostname_ipv4);\n    RUN_TEST (test_loopback_ipv6);\n    RUN_TEST (test_hostname_with_spaces_fails);\n    RUN_TEST (test_no_hostname_fails);\n    RUN_TEST (test_invalid_service_fails);\n    RUN_TEST (test_invalid_proto_fails);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_connect_rid.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nconst char *rconn1routing_id = \"conn1\";\nconst char *x_routing_id = \"X\";\nconst char *y_routing_id = \"Y\";\nconst char *z_routing_id = \"Z\";\n\nvoid test_stream_2_stream ()\n{\n    char buff[256];\n    const char msg[] = \"hi 1\";\n    const int disabled = 0;\n    const int zero = 0;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  Set up listener STREAM.\n    void *rbind = test_context_socket (ZMQ_STREAM);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (rbind, ZMQ_STREAM_NOTIFY, &disabled, sizeof (disabled)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (rbind, ZMQ_LINGER, &zero, sizeof zero));\n    bind_loopback_ipv4 (rbind, my_endpoint, sizeof my_endpoint);\n\n    //  Set up connection stream.\n    void *rconn1 = test_context_socket (ZMQ_STREAM);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (rconn1, ZMQ_LINGER, &zero, sizeof zero));\n\n    //  Do the connection.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID,\n                                               rconn1routing_id,\n                                               strlen (rconn1routing_id)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rconn1, my_endpoint));\n\n    /*  Uncomment to test assert on duplicate routing id.\n    //  Test duplicate connect attempt.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID, rconn1routing_id, strlen(rconn1routing_id)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rconn1, bindip));\n*/\n    //  Send data to the bound stream.\n    send_string_expect_success (rconn1, rconn1routing_id, ZMQ_SNDMORE);\n    send_string_expect_success (rconn1, msg, 0);\n\n    //  Accept data on the bound stream.\n    TEST_ASSERT_GREATER_THAN (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (rbind, buff, 256, 0)));\n    TEST_ASSERT_EQUAL (0, buff[0]); // an auto-generated routing id\n    recv_string_expect_success (rbind, msg, 0);\n\n    // Handle close of the socket.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (rbind, my_endpoint));\n    test_context_socket_close (rbind);\n    test_context_socket_close (rconn1);\n}\n\nvoid test_router_2_router (bool named_)\n{\n    char buff[256];\n    const char msg[] = \"hi 1\";\n    const int zero = 0;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  Create bind socket.\n    void *rbind = test_context_socket (ZMQ_ROUTER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (rbind, ZMQ_LINGER, &zero, sizeof (zero)));\n    bind_loopback_ipv4 (rbind, my_endpoint, sizeof my_endpoint);\n\n    //  Create connection socket.\n    void *rconn1 = test_context_socket (ZMQ_ROUTER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (rconn1, ZMQ_LINGER, &zero, sizeof (zero)));\n\n    //  If we're in named mode, set some identities.\n    if (named_) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (rbind, ZMQ_ROUTING_ID, x_routing_id, 1));\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (rconn1, ZMQ_ROUTING_ID, y_routing_id, 1));\n    }\n\n    //  Make call to connect using a connect_routing_id.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID,\n                                               rconn1routing_id,\n                                               strlen (rconn1routing_id)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rconn1, my_endpoint));\n    /*  Uncomment to test assert on duplicate routing id\n    //  Test duplicate connect attempt.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID, rconn1routing_id, strlen (rconn1routing_id)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rconn1, bindip));\n*/\n    //  Send some data.\n\n    send_string_expect_success (rconn1, rconn1routing_id, ZMQ_SNDMORE);\n    send_string_expect_success (rconn1, msg, 0);\n\n    //  Receive the name.\n    const int routing_id_len = zmq_recv (rbind, buff, 256, 0);\n    if (named_) {\n        TEST_ASSERT_EQUAL_INT (strlen (y_routing_id), routing_id_len);\n        TEST_ASSERT_EQUAL_STRING_LEN (y_routing_id, buff, routing_id_len);\n    } else {\n        TEST_ASSERT_TRUE (routing_id_len && 0 == buff[0]);\n    }\n\n    //  Receive the data.\n    recv_string_expect_success (rbind, msg, 0);\n\n    //  Send some data back.\n    const int ret = zmq_send (rbind, buff, routing_id_len, ZMQ_SNDMORE);\n    TEST_ASSERT_EQUAL_INT (routing_id_len, ret);\n    send_string_expect_success (rbind, \"ok\", 0);\n\n    //  If bound socket identity naming a problem, we'll likely see something funky here.\n    recv_string_expect_success (rconn1, rconn1routing_id, 0);\n    recv_string_expect_success (rconn1, \"ok\", 0);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (rbind, my_endpoint));\n    test_context_socket_close (rbind);\n    test_context_socket_close (rconn1);\n}\n\nvoid test_router_2_router_while_receiving ()\n{\n    char buff[256];\n    const char msg[] = \"hi 1\";\n    const int zero = 0;\n    char x_endpoint[MAX_SOCKET_STRING];\n    char z_endpoint[MAX_SOCKET_STRING];\n\n    //  Create xbind socket.\n    void *xbind = test_context_socket (ZMQ_ROUTER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xbind, ZMQ_LINGER, &zero, sizeof (zero)));\n    bind_loopback_ipv4 (xbind, x_endpoint, sizeof x_endpoint);\n\n    //  Create zbind socket.\n    void *zbind = test_context_socket (ZMQ_ROUTER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (zbind, ZMQ_LINGER, &zero, sizeof (zero)));\n    bind_loopback_ipv4 (zbind, z_endpoint, sizeof z_endpoint);\n\n    //  Create connection socket.\n    void *yconn = test_context_socket (ZMQ_ROUTER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (yconn, ZMQ_LINGER, &zero, sizeof (zero)));\n\n    // set identities for each socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      xbind, ZMQ_ROUTING_ID, x_routing_id, strlen (x_routing_id)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (yconn, ZMQ_ROUTING_ID, y_routing_id, 2));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      zbind, ZMQ_ROUTING_ID, z_routing_id, strlen (z_routing_id)));\n\n    //  Connect Y to X using a routing id\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      yconn, ZMQ_CONNECT_ROUTING_ID, x_routing_id, strlen (x_routing_id)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (yconn, x_endpoint));\n\n    //  Send some data from Y to X.\n    send_string_expect_success (yconn, x_routing_id, ZMQ_SNDMORE);\n    send_string_expect_success (yconn, msg, 0);\n\n    // wait for the Y->X message to be received\n    msleep (SETTLE_TIME);\n\n    // Now X tries to connect to Z and send a message\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      xbind, ZMQ_CONNECT_ROUTING_ID, z_routing_id, strlen (z_routing_id)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (xbind, z_endpoint));\n\n    //  Try to send some data from X to Z.\n    send_string_expect_success (xbind, z_routing_id, ZMQ_SNDMORE);\n    send_string_expect_success (xbind, msg, 0);\n\n    // wait for the X->Z message to be received (so that our non-blocking check will actually\n    // fail if the message is routed to Y)\n    msleep (SETTLE_TIME);\n\n    // nothing should have been received on the Y socket\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN,\n                               zmq_recv (yconn, buff, 256, ZMQ_DONTWAIT));\n\n    // the message should have been received on the Z socket\n    recv_string_expect_success (zbind, x_routing_id, 0);\n    recv_string_expect_success (zbind, msg, 0);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (xbind, x_endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (zbind, z_endpoint));\n\n    test_context_socket_close (yconn);\n    test_context_socket_close (xbind);\n    test_context_socket_close (zbind);\n}\n\nvoid test_router_2_router_unnamed ()\n{\n    test_router_2_router (false);\n}\n\nvoid test_router_2_router_named ()\n{\n    test_router_2_router (true);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_stream_2_stream);\n    RUN_TEST (test_router_2_router_unnamed);\n    RUN_TEST (test_router_2_router_named);\n    RUN_TEST (test_router_2_router_while_receiving);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_connect_stream_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n// Test that the ZMTP engine handles invalid handshake when connecting\n// https://rfc.zeromq.org/spec/37/\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    setup_test_context ();\n    char my_endpoint[MAX_SOCKET_STRING];\n    fd_t server = bind_socket_resolve_port (\"127.0.0.1\", \"0\", my_endpoint);\n\n    void *client = test_context_socket (ZMQ_STREAM);\n    //  As per API by default there's no limit to the size of a message,\n    //  but the sanitizer allocator will barf over a gig or so\n    int64_t max_msg_size = 64 * 1024 * 1024;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    fd_t server_accept =\n      TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server, NULL, NULL));\n\n    //  If there is not enough data for a full greeting, just send what we can\n    //  Otherwise send greeting first, as expected by the protocol\n    uint8_t buf[64];\n    if (size >= 64) {\n        send (server_accept, (void *) data, 64, MSG_NOSIGNAL);\n        data += 64;\n        size -= 64;\n    }\n    recv (server_accept, buf, 64, MSG_DONTWAIT);\n    msleep (250);\n    for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);\n         size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)\n        sent = send (server_accept, (const char *) data, size, MSG_NOSIGNAL);\n    msleep (250);\n\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    while (-1 != zmq_msg_recv (&msg, client, ZMQ_DONTWAIT)) {\n        zmq_msg_close (&msg);\n        zmq_msg_init (&msg);\n    }\n\n    close (server_accept);\n    close (server);\n\n    test_context_socket_close_zero_linger (client);\n    teardown_test_context ();\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_connect_null_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_connect_null_fuzzer_seed_corpus\",\n          &data, &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_connect_null_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_connect_ws_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n// Test that the ZMTP WebSocket engine handles invalid handshake when connecting\n// https://rfc.zeromq.org/spec/45/\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    setup_test_context ();\n    char my_endpoint[MAX_SOCKET_STRING];\n    fd_t server = bind_socket_resolve_port (\"127.0.0.1\", \"0\", my_endpoint,\n                                            AF_INET, IPPROTO_WS);\n\n    void *client = test_context_socket (ZMQ_PULL);\n    //  As per API by default there's no limit to the size of a message,\n    //  but the sanitizer allocator will barf over a gig or so\n    int64_t max_msg_size = 64 * 1024 * 1024;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    fd_t server_accept =\n      TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server, NULL, NULL));\n\n    //  If there is not enough data for a full handshake, just send what we can\n    //  Otherwise send websocket handshake first, as expected by the protocol\n    uint8_t buf[256];\n    recv (server_accept, buf, 256, 0);\n    if (size >= 166) {\n        send (server_accept, (void *) data, 166, MSG_NOSIGNAL);\n        data += 166;\n        size -= 166;\n    }\n    recv (server_accept, buf, 256, MSG_DONTWAIT);\n    //  Then send the READY command\n    if (size >= 29) {\n        send (server_accept, (void *) data, 29, MSG_NOSIGNAL);\n        data += 29;\n        size -= 29;\n    }\n    msleep (250);\n    for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);\n         size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)\n        sent = send (server_accept, (const char *) data, size, MSG_NOSIGNAL);\n    msleep (250);\n\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    while (-1 != zmq_msg_recv (&msg, client, ZMQ_DONTWAIT)) {\n        zmq_msg_close (&msg);\n        zmq_msg_init (&msg);\n    }\n\n    close (server_accept);\n    close (server);\n\n    test_context_socket_close_zero_linger (client);\n    teardown_test_context ();\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_connect_ws_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_connect_ws_fuzzer_seed_corpus\", &data,\n          &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_connect_ws_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_ctx_destroy.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <unity.h>\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\nstatic void receiver (void *socket_)\n{\n    char buffer[16];\n    int rc = zmq_recv (socket_, &buffer, sizeof (buffer), 0);\n    // TODO which error is expected here? use TEST_ASSERT_FAILURE_ERRNO instead\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n}\n\nvoid test_ctx_destroy ()\n{\n    //  Set up our context and sockets\n    void *ctx = zmq_ctx_new ();\n    TEST_ASSERT_NOT_NULL (ctx);\n\n    void *socket = zmq_socket (ctx, ZMQ_PULL);\n    TEST_ASSERT_NOT_NULL (socket);\n\n    // Close the socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));\n\n    // Destroy the context\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));\n}\n\nvoid test_ctx_shutdown ()\n{\n    //  Set up our context and sockets\n    void *ctx = zmq_ctx_new ();\n    TEST_ASSERT_NOT_NULL (ctx);\n\n    void *socket = zmq_socket (ctx, ZMQ_PULL);\n    TEST_ASSERT_NOT_NULL (socket);\n\n    // Spawn a thread to receive on socket\n    void *receiver_thread = zmq_threadstart (&receiver, socket);\n\n    // Wait for thread to start up and block\n    msleep (SETTLE_TIME);\n\n    // Shutdown context, if we used destroy here we would deadlock.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_shutdown (ctx));\n\n    // Wait for thread to finish\n    zmq_threadclose (receiver_thread);\n\n    // Close the socket.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));\n\n    // Destroy the context, will now not hang as we have closed the socket.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));\n}\n\nvoid test_ctx_shutdown_socket_opened_after ()\n{\n    //  Set up our context.\n    void *ctx = zmq_ctx_new ();\n    TEST_ASSERT_NOT_NULL (ctx);\n\n    // Open a socket to start context, and close it immediately again.\n    void *socket = zmq_socket (ctx, ZMQ_PULL);\n    TEST_ASSERT_NOT_NULL (socket);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));\n\n    // Shutdown context.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_shutdown (ctx));\n\n    // Opening socket should now fail.\n    TEST_ASSERT_NULL (zmq_socket (ctx, ZMQ_PULL));\n    TEST_ASSERT_FAILURE_ERRNO (ETERM, -1);\n\n    // Destroy the context.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));\n}\n\nvoid test_ctx_shutdown_only_socket_opened_after ()\n{\n    //  Set up our context.\n    void *ctx = zmq_ctx_new ();\n    TEST_ASSERT_NOT_NULL (ctx);\n\n    // Shutdown context.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_shutdown (ctx));\n\n    // Opening socket should now fail.\n    TEST_ASSERT_NULL (zmq_socket (ctx, ZMQ_PULL));\n    TEST_ASSERT_FAILURE_ERRNO (ETERM, -1);\n\n    // Destroy the context.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));\n}\n\nvoid test_zmq_ctx_term_null_fails ()\n{\n    int rc = zmq_ctx_term (NULL);\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (EFAULT, errno);\n}\n\nvoid test_zmq_term_null_fails ()\n{\n    int rc = zmq_term (NULL);\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (EFAULT, errno);\n}\n\nvoid test_zmq_ctx_shutdown_null_fails ()\n{\n    int rc = zmq_ctx_shutdown (NULL);\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (EFAULT, errno);\n}\n\n#ifdef ZMQ_HAVE_POLLER\nstruct poller_test_data_t\n{\n    int socket_type;\n    void *ctx;\n    void *counter;\n};\n\nvoid run_poller (void *data_)\n{\n    const poller_test_data_t *const poller_test_data =\n      static_cast<const poller_test_data_t *> (data_);\n\n    void *socket =\n      zmq_socket (poller_test_data->ctx, poller_test_data->socket_type);\n    TEST_ASSERT_NOT_NULL (socket);\n\n    void *poller = zmq_poller_new ();\n    TEST_ASSERT_NOT_NULL (poller);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add (poller, socket, NULL, ZMQ_POLLIN));\n\n    zmq_atomic_counter_set (poller_test_data->counter, 1);\n\n    zmq_poller_event_t event;\n    TEST_ASSERT_FAILURE_ERRNO (ETERM, zmq_poller_wait (poller, &event, -1));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));\n\n    // Close the socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));\n}\n#endif\n\nvoid test_poller_exists_with_socket_on_zmq_ctx_term (const int socket_type_)\n{\n#ifdef ZMQ_HAVE_POLLER\n    struct poller_test_data_t poller_test_data;\n\n    poller_test_data.socket_type = socket_type_;\n\n    //  Set up our context and sockets\n    poller_test_data.ctx = zmq_ctx_new ();\n    TEST_ASSERT_NOT_NULL (poller_test_data.ctx);\n\n    poller_test_data.counter = zmq_atomic_counter_new ();\n    TEST_ASSERT_NOT_NULL (poller_test_data.counter);\n\n    void *thread = zmq_threadstart (run_poller, &poller_test_data);\n    TEST_ASSERT_NOT_NULL (thread);\n\n    while (zmq_atomic_counter_value (poller_test_data.counter) == 0) {\n        msleep (10);\n    }\n\n    // Destroy the context\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (poller_test_data.ctx));\n\n    zmq_threadclose (thread);\n\n    zmq_atomic_counter_destroy (&poller_test_data.counter);\n#else\n    TEST_IGNORE_MESSAGE (\"libzmq without zmq_poller_* support, ignoring test\");\n#endif\n}\n\nvoid test_poller_exists_with_socket_on_zmq_ctx_term_thread_safe_socket ()\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n    test_poller_exists_with_socket_on_zmq_ctx_term (ZMQ_CLIENT);\n#else\n    TEST_IGNORE_MESSAGE (\"libzmq without DRAFT support, ignoring test\");\n#endif\n}\n\nvoid test_poller_exists_with_socket_on_zmq_ctx_term_non_thread_safe_socket ()\n{\n    test_poller_exists_with_socket_on_zmq_ctx_term (ZMQ_DEALER);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_ctx_destroy);\n    RUN_TEST (test_ctx_shutdown);\n    RUN_TEST (test_ctx_shutdown_socket_opened_after);\n    RUN_TEST (test_ctx_shutdown_only_socket_opened_after);\n    RUN_TEST (test_zmq_ctx_term_null_fails);\n    RUN_TEST (test_zmq_term_null_fails);\n    RUN_TEST (test_zmq_ctx_shutdown_null_fails);\n\n    RUN_TEST (\n      test_poller_exists_with_socket_on_zmq_ctx_term_non_thread_safe_socket);\n    RUN_TEST (\n      test_poller_exists_with_socket_on_zmq_ctx_term_thread_safe_socket);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_ctx_options.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include <limits>\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n#define WAIT_FOR_BACKGROUND_THREAD_INSPECTION (0)\n\n#ifdef ZMQ_HAVE_LINUX\n#include <sys/time.h>\n#include <sys/resource.h>\n#include <unistd.h> // for sleep()\n#include <sched.h>\n\n#define TEST_POLICY                                                            \\\n    (SCHED_OTHER) // NOTE: SCHED_OTHER is the default Linux scheduler\n\nbool is_allowed_to_raise_priority ()\n{\n    // NOTE1: if setrlimit() fails with EPERM, this means that current user has not enough permissions.\n    // NOTE2: even for privileged users (e.g., root) getrlimit() would usually return 0 as nice limit; the only way to\n    //        discover if the user is able to increase the nice value is to actually try to change the rlimit:\n    struct rlimit rlim;\n    rlim.rlim_cur = 40;\n    rlim.rlim_max = 40;\n    if (setrlimit (RLIMIT_NICE, &rlim) == 0) {\n        // rlim_cur == 40 means that this process is allowed to set a nice value of -20\n        if (WAIT_FOR_BACKGROUND_THREAD_INSPECTION)\n            printf (\"This process has enough permissions to raise ZMQ \"\n                    \"background thread priority!\\n\");\n        return true;\n    }\n\n    if (WAIT_FOR_BACKGROUND_THREAD_INSPECTION)\n        printf (\"This process has NOT enough permissions to raise ZMQ \"\n                \"background thread priority.\\n\");\n    return false;\n}\n\n#else\n\n#define TEST_POLICY (0)\n\nbool is_allowed_to_raise_priority ()\n{\n    return false;\n}\n\n#endif\n\n\nvoid test_ctx_thread_opts ()\n{\n    // verify that setting negative values (e.g., default values) fail:\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_ctx_set (get_test_context (), ZMQ_THREAD_SCHED_POLICY,\n                           ZMQ_THREAD_SCHED_POLICY_DFLT));\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_ctx_set (get_test_context (),\n                                                    ZMQ_THREAD_PRIORITY,\n                                                    ZMQ_THREAD_PRIORITY_DFLT));\n\n\n    // test scheduling policy:\n\n    // set context options that alter the background thread CPU scheduling/affinity settings;\n    // as of ZMQ 4.2.3 this has an effect only on POSIX systems (nothing happens on Windows, but still it should return success):\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_ctx_set (get_test_context (), ZMQ_THREAD_SCHED_POLICY, TEST_POLICY));\n    TEST_ASSERT_EQUAL_INT (\n      TEST_POLICY, zmq_ctx_get (get_test_context (), ZMQ_THREAD_SCHED_POLICY));\n\n    // test priority:\n\n    // in theory SCHED_OTHER supports only the static priority 0 but quoting the docs\n    //     http://man7.org/linux/man-pages/man7/sched.7.html\n    // \"The thread to run is chosen from the static priority 0 list based on\n    // a dynamic priority that is determined only inside this list.  The\n    // dynamic priority is based on the nice value [...]\n    // The nice value can be modified using nice(2), setpriority(2), or sched_setattr(2).\"\n    // ZMQ will internally use nice(2) to set the nice value when using SCHED_OTHER.\n    // However changing the nice value of a process requires appropriate permissions...\n    // check that the current effective user is able to do that:\n    if (is_allowed_to_raise_priority ()) {\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_set (\n          get_test_context (), ZMQ_THREAD_PRIORITY,\n          1 /* any positive value different than the default will be ok */));\n    }\n\n\n    // test affinity:\n\n    // this should result in background threads being placed only on the\n    // first CPU available on this system; try experimenting with other values\n    // (e.g., 5 to use CPU index 5) and use \"top -H\" or \"taskset -pc\" to see the result\n\n    int cpus_add[] = {0, 1};\n    for (unsigned int idx = 0; idx < sizeof (cpus_add) / sizeof (cpus_add[0]);\n         idx++) {\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_set (\n          get_test_context (), ZMQ_THREAD_AFFINITY_CPU_ADD, cpus_add[idx]));\n    }\n\n    // you can also remove CPUs from list of affinities:\n    int cpus_remove[] = {1};\n    for (unsigned int idx = 0;\n         idx < sizeof (cpus_remove) / sizeof (cpus_remove[0]); idx++) {\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_set (get_test_context (),\n                                                ZMQ_THREAD_AFFINITY_CPU_REMOVE,\n                                                cpus_remove[idx]));\n    }\n\n\n    // test INTEGER thread name prefix:\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_ctx_set (get_test_context (), ZMQ_THREAD_NAME_PREFIX, 1234));\n    TEST_ASSERT_EQUAL_INT (\n      1234, zmq_ctx_get (get_test_context (), ZMQ_THREAD_NAME_PREFIX));\n\n#ifdef ZMQ_BUILD_DRAFT_API\n    // test STRING thread name prefix:\n\n    const char prefix[] = \"MyPrefix9012345\"; // max len is 16 chars\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_ctx_set_ext (get_test_context (), ZMQ_THREAD_NAME_PREFIX, prefix,\n                       sizeof (prefix) / sizeof (char)));\n\n    char buf[16];\n    size_t buflen = sizeof (buf) / sizeof (char);\n    zmq_ctx_get_ext (get_test_context (), ZMQ_THREAD_NAME_PREFIX, buf, &buflen);\n    TEST_ASSERT_EQUAL_STRING (prefix, buf);\n#endif\n}\n\nvoid test_ctx_zero_copy ()\n{\n#ifdef ZMQ_ZERO_COPY_RECV\n    int zero_copy;\n    // Default value is 1.\n    zero_copy = zmq_ctx_get (get_test_context (), ZMQ_ZERO_COPY_RECV);\n    TEST_ASSERT_EQUAL_INT (1, zero_copy);\n\n    // Test we can set it to 0.\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_ctx_set (get_test_context (), ZMQ_ZERO_COPY_RECV, 0));\n    zero_copy = zmq_ctx_get (get_test_context (), ZMQ_ZERO_COPY_RECV);\n    TEST_ASSERT_EQUAL_INT (0, zero_copy);\n\n    // Create a TCP socket pair using the context and test that messages can be\n    // received. Note that inproc sockets cannot be used for this test.\n    void *pull = zmq_socket (get_test_context (), ZMQ_PULL);\n    char endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (pull, endpoint, sizeof endpoint);\n\n    void *push = zmq_socket (get_test_context (), ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (push, endpoint));\n\n    const char *small_str = \"abcd\";\n    const char *large_str =\n      \"01234567890123456789012345678901234567890123456789\";\n\n    send_string_expect_success (push, small_str, 0);\n    send_string_expect_success (push, large_str, 0);\n\n    recv_string_expect_success (pull, small_str, 0);\n    recv_string_expect_success (pull, large_str, 0);\n\n    // Clean up.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (push));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (pull));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_ctx_set (get_test_context (), ZMQ_ZERO_COPY_RECV, 1));\n    TEST_ASSERT_EQUAL_INT (\n      1, zmq_ctx_get (get_test_context (), ZMQ_ZERO_COPY_RECV));\n#endif\n}\n\nvoid test_ctx_option_max_sockets ()\n{\n    TEST_ASSERT_EQUAL_INT (ZMQ_MAX_SOCKETS_DFLT,\n                           zmq_ctx_get (get_test_context (), ZMQ_MAX_SOCKETS));\n}\n\nvoid test_ctx_option_socket_limit ()\n{\n#if defined(ZMQ_USE_SELECT)\n    TEST_ASSERT_EQUAL_INT (FD_SETSIZE - 1, zmq_ctx_get (ctx, ZMQ_SOCKET_LIMIT));\n#elif defined(ZMQ_USE_POLL) || defined(ZMQ_USE_EPOLL)                          \\\n  || defined(ZMQ_USE_DEVPOLL) || defined(ZMQ_USE_KQUEUE)\n    TEST_ASSERT_EQUAL_INT (65535, zmq_ctx_get (ctx, ZMQ_SOCKET_LIMIT));\n#endif\n}\n\nvoid test_ctx_option_io_threads ()\n{\n    TEST_ASSERT_EQUAL_INT (ZMQ_IO_THREADS_DFLT,\n                           zmq_ctx_get (get_test_context (), ZMQ_IO_THREADS));\n}\n\nvoid test_ctx_option_ipv6 ()\n{\n    TEST_ASSERT_EQUAL_INT (0, zmq_ctx_get (get_test_context (), ZMQ_IPV6));\n}\n\nvoid test_ctx_option_msg_t_size ()\n{\n#if defined(ZMQ_MSG_T_SIZE)\n    TEST_ASSERT_EQUAL_INT (sizeof (zmq_msg_t),\n                           zmq_ctx_get (get_test_context (), ZMQ_MSG_T_SIZE));\n#endif\n}\n\nvoid test_ctx_option_ipv6_set ()\n{\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_ctx_set (get_test_context (), ZMQ_IPV6, true));\n    TEST_ASSERT_EQUAL_INT (1, zmq_ctx_get (get_test_context (), ZMQ_IPV6));\n}\n\nvoid test_ctx_option_blocky ()\n{\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_ctx_set (get_test_context (), ZMQ_IPV6, true));\n\n    void *router = test_context_socket (ZMQ_ROUTER);\n    int value;\n    size_t optsize = sizeof (int);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (router, ZMQ_IPV6, &value, &optsize));\n    TEST_ASSERT_EQUAL_INT (1, value);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (router, ZMQ_LINGER, &value, &optsize));\n    TEST_ASSERT_EQUAL_INT (-1, value);\n    test_context_socket_close (router);\n\n#if WAIT_FOR_BACKGROUND_THREAD_INSPECTION\n    // this is useful when you want to use an external tool (like top or taskset) to view\n    // properties of the background threads\n    printf (\"Sleeping for 100sec. You can now use 'top -H -p $(pgrep -f \"\n            \"test_ctx_options)' and 'taskset -pc <ZMQ background thread PID>' \"\n            \"to view ZMQ background thread properties.\\n\");\n    sleep (100);\n#endif\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_ctx_set (get_test_context (), ZMQ_BLOCKY, false));\n    TEST_ASSERT_EQUAL_INT (0, TEST_ASSERT_SUCCESS_ERRNO ((zmq_ctx_get (\n                                get_test_context (), ZMQ_BLOCKY))));\n    router = test_context_socket (ZMQ_ROUTER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (router, ZMQ_LINGER, &value, &optsize));\n    TEST_ASSERT_EQUAL_INT (0, value);\n    test_context_socket_close (router);\n}\n\nvoid test_ctx_option_invalid ()\n{\n    TEST_ASSERT_EQUAL_INT (-1, zmq_ctx_set (get_test_context (), -1, 0));\n    TEST_ASSERT_EQUAL_INT (EINVAL, errno);\n    TEST_ASSERT_EQUAL_INT (-1, zmq_ctx_get (get_test_context (), -1));\n    TEST_ASSERT_EQUAL_INT (EINVAL, errno);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_ctx_option_max_sockets);\n    RUN_TEST (test_ctx_option_socket_limit);\n    RUN_TEST (test_ctx_option_io_threads);\n    RUN_TEST (test_ctx_option_ipv6);\n    RUN_TEST (test_ctx_option_msg_t_size);\n    RUN_TEST (test_ctx_option_ipv6_set);\n    RUN_TEST (test_ctx_thread_opts);\n    RUN_TEST (test_ctx_zero_copy);\n    RUN_TEST (test_ctx_option_blocky);\n    RUN_TEST (test_ctx_option_invalid);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_dgram.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid str_send_to (void *s_, const char *content_, const char *address_)\n{\n    send_string_expect_success (s_, address_, ZMQ_SNDMORE);\n    send_string_expect_success (s_, content_, 0);\n}\n\nvoid str_recv_from (void *s_, char **ptr_content_, char **ptr_address_)\n{\n    *ptr_address_ = s_recv (s_);\n    TEST_ASSERT_NOT_NULL (ptr_address_);\n\n    *ptr_content_ = s_recv (s_);\n    TEST_ASSERT_NOT_NULL (ptr_content_);\n}\n\nstatic const char test_question[] = \"Is someone there ?\";\nstatic const char test_answer[] = \"Yes, there is !\";\n\nvoid test_connect_fails ()\n{\n    void *socket = test_context_socket (ZMQ_DGRAM);\n\n    //  Connecting dgram should fail\n    TEST_ASSERT_FAILURE_ERRNO (ENOCOMPATPROTO,\n                               zmq_connect (socket, ENDPOINT_4));\n\n    test_context_socket_close (socket);\n}\n\nvoid test_roundtrip ()\n{\n    char *message_string;\n    char *address;\n\n    void *sender = test_context_socket (ZMQ_DGRAM);\n    void *listener = test_context_socket (ZMQ_DGRAM);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (listener, ENDPOINT_4));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sender, ENDPOINT_5));\n\n    str_send_to (sender, test_question, strrchr (ENDPOINT_4, '/') + 1);\n\n    str_recv_from (listener, &message_string, &address);\n    TEST_ASSERT_EQUAL_STRING (test_question, message_string);\n    TEST_ASSERT_EQUAL_STRING (strrchr (ENDPOINT_5, '/') + 1, address);\n    free (message_string);\n\n    str_send_to (listener, test_answer, address);\n    free (address);\n\n    str_recv_from (sender, &message_string, &address);\n    TEST_ASSERT_EQUAL_STRING (test_answer, message_string);\n    TEST_ASSERT_EQUAL_STRING (strrchr (ENDPOINT_4, '/') + 1, address);\n    free (message_string);\n    free (address);\n\n    test_context_socket_close (sender);\n    test_context_socket_close (listener);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_connect_fails);\n    RUN_TEST (test_roundtrip);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_diffserv.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_diffserv ()\n{\n    int tos = 0x28;\n    int o_tos;\n    size_t tos_size = sizeof (tos);\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *sb = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sb, ZMQ_TOS, &tos, tos_size));\n    bind_loopback_ipv4 (sb, my_endpoint, sizeof (my_endpoint));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (sb, ZMQ_TOS, &o_tos, &tos_size));\n    TEST_ASSERT_EQUAL (tos, o_tos);\n\n    void *sc = test_context_socket (ZMQ_PAIR);\n    tos = 0x58;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sc, ZMQ_TOS, &tos, tos_size));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (sc, ZMQ_TOS, &o_tos, &tos_size));\n    TEST_ASSERT_EQUAL (tos, o_tos);\n\n    // Wireshark can be used to verify that the server socket is\n    // using DSCP 0x28 in packets to the client while the client\n    // is using 0x58 in packets to the server.\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_diffserv);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_disconnect_inproc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n/// Initialize a zeromq message with a given null-terminated string\n#define ZMQ_PREPARE_STRING(msg, data, size)                                    \\\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));                           \\\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, size + 1));            \\\n    memcpy (zmq_msg_data (&msg), data, size + 1);\n\nstatic int publicationsReceived = 0;\nstatic bool isSubscribed = false;\n\nvoid test_disconnect_inproc ()\n{\n    void *pub_socket = test_context_socket (ZMQ_XPUB);\n    void *sub_socket = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, \"foo\", 3));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_bind (pub_socket, \"inproc://someInProcDescriptor\"));\n\n    int more;\n    size_t more_size = sizeof (more);\n\n    for (int iteration = 0;; ++iteration) {\n        zmq_pollitem_t items[] = {\n          {sub_socket, 0, ZMQ_POLLIN, 0}, // read publications\n          {pub_socket, 0, ZMQ_POLLIN, 0}, // read subscriptions\n        };\n        int rc = zmq_poll (items, 2, 100);\n\n        if (items[1].revents & ZMQ_POLLIN) {\n            for (more = 1; more;) {\n                zmq_msg_t msg;\n                zmq_msg_init (&msg);\n                TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, pub_socket, 0));\n                const char *const buffer =\n                  static_cast<const char *> (zmq_msg_data (&msg));\n\n                if (buffer[0] == 0) {\n                    TEST_ASSERT_TRUE (isSubscribed);\n                    isSubscribed = false;\n                } else {\n                    TEST_ASSERT_FALSE (isSubscribed);\n                    isSubscribed = true;\n                }\n\n                TEST_ASSERT_SUCCESS_ERRNO (\n                  zmq_getsockopt (pub_socket, ZMQ_RCVMORE, &more, &more_size));\n                TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n            }\n        }\n\n        if (items[0].revents & ZMQ_POLLIN) {\n            more = 1;\n            for (more = 1; more;) {\n                zmq_msg_t msg;\n                TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n                TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sub_socket, 0));\n                TEST_ASSERT_SUCCESS_ERRNO (\n                  zmq_getsockopt (sub_socket, ZMQ_RCVMORE, &more, &more_size));\n                TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n            }\n            publicationsReceived++;\n        }\n        if (iteration == 1) {\n            TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_connect (sub_socket, \"inproc://someInProcDescriptor\"));\n            msleep (SETTLE_TIME);\n        }\n        if (iteration == 4) {\n            TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_disconnect (sub_socket, \"inproc://someInProcDescriptor\"));\n        }\n        if (iteration > 4 && rc == 0)\n            break;\n\n        zmq_msg_t channel_envlp;\n        ZMQ_PREPARE_STRING (channel_envlp, \"foo\", 3);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_msg_send (&channel_envlp, pub_socket, ZMQ_SNDMORE));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&channel_envlp));\n\n        zmq_msg_t message;\n        ZMQ_PREPARE_STRING (message, \"this is foo!\", 12);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&message, pub_socket, 0));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&message));\n    }\n    TEST_ASSERT_EQUAL_INT (3, publicationsReceived);\n    TEST_ASSERT_FALSE (isSubscribed);\n\n    test_context_socket_close (pub_socket);\n    test_context_socket_close (sub_socket);\n}\n\nint main (int, char **)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_disconnect_inproc);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_disconnect_msg.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test (const char *address)\n{\n    //  Create a server\n    void *server = test_context_socket (ZMQ_SERVER);\n\n    //  set server socket options\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_DISCONNECT_MSG, \"D\", 1));\n\n    //  bind server\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, address));\n\n    //  Create a client\n    void *client = test_context_socket (ZMQ_CLIENT);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_HELLO_MSG, \"H\", 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, address));\n\n    // Receive the hello message from client\n    recv_string_expect_success (server, \"H\", 0);\n\n    // Kill the client\n    test_context_socket_close (client);\n\n    // Receive the disconnect message\n    recv_string_expect_success (server, \"D\", 0);\n\n    //  Clean up.\n    test_context_socket_close (server);\n}\n\nvoid test_tcp ()\n{\n    test (\"tcp://127.0.0.1:5569\");\n}\n\nvoid test_inproc ()\n{\n    test (\"inproc://disconnect-msg\");\n}\n\n\nvoid test_inproc_disconnect ()\n{\n    const char *address = \"inproc://disconnect-msg\";\n\n    //  Create a server\n    void *server = test_context_socket (ZMQ_SERVER);\n\n    //  set server socket options\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_DISCONNECT_MSG, \"D\", 1));\n\n    //  bind server\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, address));\n\n    //  Create a client\n    void *client = test_context_socket (ZMQ_CLIENT);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_HELLO_MSG, \"H\", 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, address));\n\n    // Receive the hello message from client\n    recv_string_expect_success (server, \"H\", 0);\n\n    // disconnect the client\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (client, address));\n\n    // Receive the disconnect message\n    recv_string_expect_success (server, \"D\", 0);\n\n    //  Clean up.\n    test_context_socket_close (client);\n    test_context_socket_close (server);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_tcp);\n    RUN_TEST (test_inproc);\n    RUN_TEST (test_inproc_disconnect);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_filter_ipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <unistd.h>\n#include <grp.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nstatic void bounce_fail (void *server_, void *client_)\n{\n    const char *content = \"12345678ABCDEFGH12345678abcdefgh\";\n    char buffer[32];\n\n    //  Send message from client to server\n    int rc = zmq_send (client_, content, 32, ZMQ_SNDMORE);\n    TEST_ASSERT_TRUE (rc == 32 || rc == -1);\n    rc = zmq_send (client_, content, 32, 0);\n    TEST_ASSERT_TRUE (rc == 32 || rc == -1);\n\n    //  Receive message at server side (should not succeed)\n    int timeout = SETTLE_TIME;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server_, ZMQ_RCVTIMEO, &timeout, sizeof (int)));\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (server_, buffer, 32, 0));\n\n    //  Send message from server to client to test other direction\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server_, ZMQ_SNDTIMEO, &timeout, sizeof (int)));\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN,\n                               zmq_send (server_, content, 32, ZMQ_SNDMORE));\n}\n\ntemplate <class T>\nstatic void\nrun_test (int opt_, T optval_, int expected_error_, int bounce_test_)\n{\n    void *sb = test_context_socket (ZMQ_PAIR);\n\n    if (opt_) {\n        const int rc = zmq_setsockopt (sb, opt_, &optval_, sizeof (optval_));\n        if (expected_error_) {\n            TEST_ASSERT_FAILURE_ERRNO (expected_error_, rc);\n        } else {\n            TEST_ASSERT_SUCCESS_ERRNO (rc);\n        }\n    }\n\n    void *sc = test_context_socket (ZMQ_PAIR);\n\n    // If a test fails, don't hang for too long\n    int timeout = 2500;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sb, ZMQ_RCVTIMEO, &timeout, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sb, ZMQ_SNDTIMEO, &timeout, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_RCVTIMEO, &timeout, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_SNDTIMEO, &timeout, sizeof (int)));\n    int interval = -1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_RECONNECT_IVL, &interval, sizeof (int)));\n\n    if (bounce_test_) {\n        char my_endpoint[256];\n        bind_loopback_ipc (sb, my_endpoint, sizeof my_endpoint);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));\n\n        if (bounce_test_ > 0)\n            bounce (sb, sc);\n        else\n            bounce_fail (sb, sc);\n    }\n\n    // TODO only use zero linger when bounce_test_ < 0?\n    test_context_socket_close_zero_linger (sc);\n    test_context_socket_close_zero_linger (sb);\n}\n\n#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\ngid_t group, supgroup, notgroup;\n\nvoid init_groups ()\n{\n    // Get the group and supplemental groups of the process owner\n    gid_t groups[100];\n    int ngroups = getgroups (100, groups);\n    TEST_ASSERT_NOT_EQUAL (-1, ngroups);\n    group = getgid ();\n    supgroup = group;\n    notgroup = group + 1;\n    for (int i = 0; i < ngroups; i++) {\n        if (supgroup == group && group != groups[i]) {\n            if (getgrgid (groups[i]))\n                supgroup = groups[i];\n        }\n        if (notgroup <= groups[i])\n            notgroup = groups[i] + 1;\n    }\n}\n#endif\n\nvoid test_no_filters ()\n{\n    run_test<int> (0, 0, 0, 1);\n}\n\n#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\nvoid test_filter_with_process_owner_uid ()\n{\n    run_test<uid_t> (ZMQ_IPC_FILTER_UID, getuid (), 0, 1);\n}\nvoid test_filter_with_possibly_nonexistent_uid ()\n{\n    run_test<uid_t> (ZMQ_IPC_FILTER_UID, getuid () + 1, 0, -1);\n}\nvoid test_filter_with_process_owner_gid ()\n{\n    run_test<gid_t> (ZMQ_IPC_FILTER_GID, group, 0, 1);\n}\nvoid test_filter_with_supplemental_process_owner_gid ()\n{\n    run_test<gid_t> (ZMQ_IPC_FILTER_GID, supgroup, 0, 1);\n}\nvoid test_filter_with_possibly_nonexistent_gid ()\n{\n    run_test<gid_t> (ZMQ_IPC_FILTER_GID, notgroup, 0, -1);\n}\n#if defined ZMQ_HAVE_SO_PEERCRED\nvoid test_filter_with_current_process_pid ()\n{\n    run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid (), 0, 1);\n}\nvoid test_filter_with_possibly_nonexistent_pid ()\n{\n    run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid () + 1, 0, -1);\n}\n#else\nvoid test_filter_with_pid_fails ()\n{\n    // Setup of PID filter should fail with operation not supported error\n    // TODO EINVAL is not ENOTSUP (!)\n    run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid (), EINVAL, 0);\n}\n#endif\n#else\nvoid test_filter_with_zero_uid_fails ()\n{\n    run_test<uid_t> (ZMQ_IPC_FILTER_UID, 0, EINVAL, 0);\n}\nvoid test_filter_with_zero_gid_fails ()\n{\n    run_test<gid_t> (ZMQ_IPC_FILTER_GID, 0, EINVAL, 0);\n}\nvoid test_filter_with_zero_pid_fails ()\n{\n    run_test<pid_t> (ZMQ_IPC_FILTER_PID, 0, EINVAL, 0);\n}\n#endif // defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\n\nint main (void)\n{\n#if !defined(ZMQ_HAVE_WINDOWS)\n    setup_test_environment ();\n\n#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\n    init_groups ();\n#endif\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_no_filters);\n#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\n    RUN_TEST (test_filter_with_process_owner_uid);\n    RUN_TEST (test_filter_with_possibly_nonexistent_uid);\n    RUN_TEST (test_filter_with_process_owner_gid);\n    RUN_TEST (test_filter_with_supplemental_process_owner_gid);\n    RUN_TEST (test_filter_with_possibly_nonexistent_gid);\n#if defined ZMQ_HAVE_SO_PEERCRED\n    RUN_TEST (test_filter_with_current_process_pid);\n    RUN_TEST (test_filter_with_possibly_nonexistent_pid);\n#else\n    RUN_TEST (test_filter_with_pid_fails);\n#endif\n#else\n    RUN_TEST (test_filter_with_zero_uid_fails);\n    RUN_TEST (test_filter_with_zero_gid_fails);\n    RUN_TEST (test_filter_with_zero_pid_fails);\n#endif // defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED\n    return UNITY_END ();\n#else\n    return 0;\n#endif\n}\n"
  },
  {
    "path": "tests/test_fork.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <assert.h>\n\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/wait.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nchar connect_address[MAX_SOCKET_STRING];\n\n#define NUM_MESSAGES 5\n\nvoid test_fork ()\n{\n#if !defined(ZMQ_HAVE_WINDOWS)\n    //  Create and bind pull socket to receive messages\n    void *pull = test_context_socket (ZMQ_PULL);\n    bind_loopback_ipv4 (pull, connect_address, sizeof connect_address);\n\n    int pid = fork ();\n    if (pid == 0) {\n        // use regular assertions in the child process\n\n        //  Child process\n        //  Immediately close parent sockets and context\n        zmq_close (pull);\n        zmq_ctx_term (get_test_context ());\n\n        //  Create new context, socket, connect and send some messages\n        void *child_ctx = zmq_ctx_new ();\n        assert (child_ctx);\n        void *push = zmq_socket (child_ctx, ZMQ_PUSH);\n        assert (push);\n        int rc = zmq_connect (push, connect_address);\n        assert (rc == 0);\n        int count;\n        for (count = 0; count < NUM_MESSAGES; count++)\n            zmq_send (push, \"Hello\", 5, 0);\n\n        zmq_close (push);\n        zmq_ctx_destroy (child_ctx);\n        exit (0);\n    } else {\n        //  Parent process\n        int count;\n        for (count = 0; count < NUM_MESSAGES; count++) {\n            recv_string_expect_success (pull, \"Hello\", 0);\n        }\n        int child_status;\n        while (true) {\n            int rc = waitpid (pid, &child_status, 0);\n            if (rc == -1 && errno == EINTR)\n                continue;\n            TEST_ASSERT_GREATER_THAN (0, rc);\n            //  Verify the status code of the child was zero\n            TEST_ASSERT_EQUAL (0, WEXITSTATUS (child_status));\n            break;\n        }\n        test_context_socket_close (pull);\n    }\n#endif\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_fork);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_getsockopt_memset.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_getsockopt_memset ()\n{\n    int64_t more;\n    size_t more_size = sizeof (more);\n\n    void *sb = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"inproc://a\"));\n\n    void *sc = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, \"inproc://a\"));\n\n    memset (&more, 0xFF, sizeof (int64_t));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sc, ZMQ_RCVMORE, &more, &more_size));\n    TEST_ASSERT_EQUAL_INT (sizeof (int), more_size);\n    TEST_ASSERT_EQUAL_INT (0, more);\n\n    // Cleanup\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_getsockopt_memset);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_heartbeats.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#if defined(ZMQ_HAVE_WINDOWS)\n#include <winsock2.h>\n#include <ws2tcpip.h>\n#include <stdexcept>\n#define close closesocket\ntypedef SOCKET raw_socket;\n#else\n#include <arpa/inet.h>\n#include <unistd.h>\ntypedef int raw_socket;\n#endif\n\n#include <limits.h>\n#include <stdlib.h>\n#include <string.h>\n\n// TODO remove this here, either ensure that UINT16_MAX is always properly\n// defined or handle this at a more central location\n#ifndef UINT16_MAX\n#define UINT16_MAX 65535\n#endif\n\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n//  Read one event off the monitor socket; return value and address\n//  by reference, if not null, and event number by value. Returns -1\n//  in case of error.\n\nstatic int get_monitor_event (void *monitor_)\n{\n    for (int i = 0; i < 10; i++) {\n        //  First frame in message contains event number and value\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n        if (zmq_msg_recv (&msg, monitor_, ZMQ_DONTWAIT) == -1) {\n            msleep (SETTLE_TIME);\n            continue; //  Interrupted, presumably\n        }\n        TEST_ASSERT_TRUE (zmq_msg_more (&msg));\n\n        uint8_t *data = static_cast<uint8_t *> (zmq_msg_data (&msg));\n        uint16_t event = *reinterpret_cast<uint16_t *> (data);\n\n        //  Second frame in message contains event address\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n        if (zmq_msg_recv (&msg, monitor_, 0) == -1) {\n            return -1; //  Interrupted, presumably\n        }\n        TEST_ASSERT_FALSE (zmq_msg_more (&msg));\n\n        return event;\n    }\n    return -1;\n}\n\nstatic void recv_with_retry (raw_socket fd_, char *buffer_, int bytes_)\n{\n    int received = 0;\n    while (true) {\n        int rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (\n          recv (fd_, buffer_ + received, bytes_ - received, 0));\n        TEST_ASSERT_GREATER_THAN_INT (0, rc);\n        received += rc;\n        TEST_ASSERT_LESS_OR_EQUAL_INT (bytes_, received);\n        if (received == bytes_)\n            break;\n    }\n}\n\nstatic void mock_handshake (raw_socket fd_, int mock_ping_)\n{\n    char buffer[128];\n    memset (buffer, 0, sizeof (buffer));\n    memcpy (buffer, zmtp_greeting_null, sizeof (zmtp_greeting_null));\n\n    int rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (\n      send (fd_, buffer, sizeof (zmtp_greeting_null), 0));\n    TEST_ASSERT_EQUAL_INT (sizeof (zmtp_greeting_null), rc);\n\n    recv_with_retry (fd_, buffer, sizeof (zmtp_greeting_null));\n\n    memset (buffer, 0, sizeof (buffer));\n    memcpy (buffer, zmtp_ready_dealer, sizeof (zmtp_ready_dealer));\n    rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (\n      send (fd_, buffer, sizeof (zmtp_ready_dealer), 0));\n    TEST_ASSERT_EQUAL_INT (sizeof (zmtp_ready_dealer), rc);\n\n    //  greeting\n    recv_with_retry (fd_, buffer, sizeof (zmtp_ready_dealer));\n\n    if (mock_ping_) {\n        //  test PING context - should be replicated in the PONG\n        //  to avoid timeouts, do a bulk send\n        const uint8_t zmtp_ping[12] = {4,   10, 4, 'P', 'I', 'N',\n                                       'G', 0,  0, 'L', 'O', 'L'};\n        uint8_t zmtp_pong[10] = {4, 8, 4, 'P', 'O', 'N', 'G', 'L', 'O', 'L'};\n        memset (buffer, 0, sizeof (buffer));\n        memcpy (buffer, zmtp_ping, 12);\n        rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (fd_, buffer, 12, 0));\n        TEST_ASSERT_EQUAL_INT (12, rc);\n\n        //  test a larger body that won't fit in a small message and should get\n        //  truncated\n        memset (buffer, 'z', sizeof (buffer));\n        memcpy (buffer, zmtp_ping, 12);\n        buffer[1] = 65;\n        rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (fd_, buffer, 67, 0));\n        TEST_ASSERT_EQUAL_INT (67, rc);\n\n        //  small pong\n        recv_with_retry (fd_, buffer, 10);\n        TEST_ASSERT_EQUAL_INT (0, memcmp (zmtp_pong, buffer, 10));\n        //  large pong\n        recv_with_retry (fd_, buffer, 23);\n        uint8_t zmtp_pooong[65] = {4, 21, 4, 'P', 'O', 'N', 'G', 'L', 'O', 'L'};\n        memset (zmtp_pooong + 10, 'z', 55);\n        TEST_ASSERT_EQUAL_INT (0, memcmp (zmtp_pooong, buffer, 23));\n    }\n}\n\nstatic void setup_curve (void *socket_, int is_server_)\n{\n    const char *secret_key;\n    const char *public_key;\n    const char *server_key;\n\n    if (is_server_) {\n        secret_key = \"JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6\";\n        public_key = \"rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7\";\n        server_key = NULL;\n    } else {\n        secret_key = \"D:)Q[IlAW!ahhC2ac:9*A}h:p?([4%wOTJ%JR%cs\";\n        public_key = \"Yne@$w-vo<fVvi]a<NY6T1ed:M$fCG*[IaLV{hID\";\n        server_key = \"rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7\";\n    }\n\n    zmq_setsockopt (socket_, ZMQ_CURVE_SECRETKEY, secret_key,\n                    strlen (secret_key));\n    zmq_setsockopt (socket_, ZMQ_CURVE_PUBLICKEY, public_key,\n                    strlen (public_key));\n    if (is_server_)\n        zmq_setsockopt (socket_, ZMQ_CURVE_SERVER, &is_server_,\n                        sizeof (is_server_));\n    else\n        zmq_setsockopt (socket_, ZMQ_CURVE_SERVERKEY, server_key,\n                        strlen (server_key));\n}\n\nstatic void prep_server_socket (int set_heartbeats_,\n                                int is_curve_,\n                                void **server_out_,\n                                void **mon_out_,\n                                char *endpoint_,\n                                size_t ep_length_,\n                                int socket_type_)\n{\n    //  We'll be using this socket in raw mode\n    void *server = test_context_socket (socket_type_);\n\n    int value = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_LINGER, &value, sizeof (value)));\n\n    if (set_heartbeats_) {\n        value = 50;\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (server, ZMQ_HEARTBEAT_IVL, &value, sizeof (value)));\n    }\n\n    if (is_curve_)\n        setup_curve (server, 1);\n\n    bind_loopback_ipv4 (server, endpoint_, ep_length_);\n\n    //  Create and connect a socket for collecting monitor events on dealer\n    void *server_mon = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (\n      server, \"inproc://monitor-dealer\",\n      ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_ACCEPTED));\n\n    //  Connect to the inproc endpoint so we'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (server_mon, \"inproc://monitor-dealer\"));\n\n    *server_out_ = server;\n    *mon_out_ = server_mon;\n}\n\n// This checks for a broken TCP connection (or, in this case a stuck one\n// where the peer never responds to PINGS). There should be an accepted event\n// then a disconnect event.\nstatic void test_heartbeat_timeout (int server_type_, int mock_ping_)\n{\n    int rc;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *server, *server_mon;\n    prep_server_socket (!mock_ping_, 0, &server, &server_mon, my_endpoint,\n                        MAX_SOCKET_STRING, server_type_);\n\n    fd_t s = connect_socket (my_endpoint);\n\n    // Mock a ZMTP 3 client so we can forcibly time out a connection\n    mock_handshake (s, mock_ping_);\n\n    // By now everything should report as connected\n    rc = get_monitor_event (server_mon);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_ACCEPTED, rc);\n\n    if (!mock_ping_) {\n        // We should have been disconnected\n        rc = get_monitor_event (server_mon);\n        TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_DISCONNECTED, rc);\n    }\n\n    close (s);\n\n    test_context_socket_close (server);\n    test_context_socket_close (server_mon);\n}\n\n// This checks that peers respect the TTL value in ping messages\n// We set up a mock ZMTP 3 client and send a ping message with a TLL\n// to a server that is not doing any heartbeating. Then we sleep,\n// if the server disconnects the client, then we know the TTL did\n// its thing correctly.\nstatic void test_heartbeat_ttl (int client_type_, int server_type_)\n{\n    int rc, value;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *server, *server_mon, *client;\n    prep_server_socket (0, 0, &server, &server_mon, my_endpoint,\n                        MAX_SOCKET_STRING, server_type_);\n\n    client = test_context_socket (client_type_);\n\n    // Set the heartbeat TTL to 0.1 seconds\n    value = 100;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_HEARTBEAT_TTL, &value, sizeof (value)));\n\n    // Set the heartbeat interval to much longer than the TTL so that\n    // the socket times out oon the remote side.\n    value = 250;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_HEARTBEAT_IVL, &value, sizeof (value)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    // By now everything should report as connected\n    rc = get_monitor_event (server_mon);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_ACCEPTED, rc);\n\n    msleep (SETTLE_TIME);\n\n    // We should have been disconnected\n    rc = get_monitor_event (server_mon);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_DISCONNECTED, rc);\n\n    test_context_socket_close (server);\n    test_context_socket_close (server_mon);\n    test_context_socket_close (client);\n}\n\n// This checks for normal operation - that is pings and pongs being\n// exchanged normally. There should be an accepted event on the server,\n// and then no event afterwards.\nstatic void\ntest_heartbeat_notimeout (int is_curve_, int client_type_, int server_type_)\n{\n    int rc;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *server, *server_mon;\n    prep_server_socket (1, is_curve_, &server, &server_mon, my_endpoint,\n                        MAX_SOCKET_STRING, server_type_);\n\n    void *client = test_context_socket (client_type_);\n    if (is_curve_)\n        setup_curve (client, 0);\n    rc = zmq_connect (client, my_endpoint);\n\n    // Give it a sec to connect and handshake\n    msleep (SETTLE_TIME);\n\n    // By now everything should report as connected\n    rc = get_monitor_event (server_mon);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_ACCEPTED, rc);\n\n    // We should still be connected because pings and pongs are happenin'\n    rc = get_monitor_event (server_mon);\n    // TODO: this fails ~1% of the runs on OBS but it does not seem to be reproducible anywhere else\n    if (rc == 512)\n        TEST_IGNORE_MESSAGE (\n          \"Unreliable test occasionally fails on slow CIs, ignoring\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n\n    test_context_socket_close (client);\n    test_context_socket_close (server);\n    test_context_socket_close (server_mon);\n}\n\nvoid test_heartbeat_timeout_router ()\n{\n    test_heartbeat_timeout (ZMQ_ROUTER, 0);\n}\n\nvoid test_heartbeat_timeout_router_mock_ping ()\n{\n    test_heartbeat_timeout (ZMQ_ROUTER, 1);\n}\n\n#define DEFINE_TESTS(first, second, first_define, second_define)               \\\n    void test_heartbeat_ttl_##first##_##second ()                              \\\n    {                                                                          \\\n        test_heartbeat_ttl (first_define, second_define);                      \\\n    }                                                                          \\\n    void test_heartbeat_notimeout_##first##_##second ()                        \\\n    {                                                                          \\\n        test_heartbeat_notimeout (0, first_define, second_define);             \\\n    }                                                                          \\\n    void test_heartbeat_notimeout_##first##_##second##_with_curve ()           \\\n    {                                                                          \\\n        test_heartbeat_notimeout (1, first_define, second_define);             \\\n    }\n\nDEFINE_TESTS (dealer, router, ZMQ_DEALER, ZMQ_ROUTER)\nDEFINE_TESTS (req, rep, ZMQ_REQ, ZMQ_REP)\nDEFINE_TESTS (pull, push, ZMQ_PULL, ZMQ_PUSH)\nDEFINE_TESTS (sub, pub, ZMQ_SUB, ZMQ_PUB)\nDEFINE_TESTS (pair, pair, ZMQ_PAIR, ZMQ_PAIR)\n\n#ifdef ZMQ_BUILD_DRAFT_API\nDEFINE_TESTS (gather, scatter, ZMQ_GATHER, ZMQ_SCATTER)\nDEFINE_TESTS (client, server, ZMQ_CLIENT, ZMQ_SERVER)\n#endif\n\nconst int deciseconds_per_millisecond = 100;\nconst int heartbeat_ttl_max =\n  (UINT16_MAX + 1) * deciseconds_per_millisecond - 1;\n\nvoid test_setsockopt_heartbeat_success (const int value_)\n{\n    void *const socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket, ZMQ_HEARTBEAT_TTL, &value_, sizeof (value_)));\n\n    int value_read;\n    size_t value_read_size = sizeof (value_read);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (socket, ZMQ_HEARTBEAT_TTL,\n                                               &value_read, &value_read_size));\n\n    TEST_ASSERT_EQUAL_INT (value_ - value_ % deciseconds_per_millisecond,\n                           value_read);\n\n    test_context_socket_close (socket);\n}\n\nvoid test_setsockopt_heartbeat_ttl_max ()\n{\n    test_setsockopt_heartbeat_success (heartbeat_ttl_max);\n}\n\nvoid test_setsockopt_heartbeat_ttl_more_than_max_fails ()\n{\n    void *const socket = test_context_socket (ZMQ_PAIR);\n    const int value = heartbeat_ttl_max + 1;\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL,\n      zmq_setsockopt (socket, ZMQ_HEARTBEAT_TTL, &value, sizeof (value)));\n\n    test_context_socket_close (socket);\n}\n\nvoid test_setsockopt_heartbeat_ttl_near_zero ()\n{\n    test_setsockopt_heartbeat_success (deciseconds_per_millisecond - 1);\n}\n\nint main (void)\n{\n    //  The test cases are very long-running. The default timeout of 60 seconds\n    //  is not always enough.\n    setup_test_environment (90);\n\n    UNITY_BEGIN ();\n\n    RUN_TEST (test_heartbeat_timeout_router);\n    RUN_TEST (test_heartbeat_timeout_router_mock_ping);\n\n    RUN_TEST (test_heartbeat_ttl_dealer_router);\n    RUN_TEST (test_heartbeat_ttl_req_rep);\n    RUN_TEST (test_heartbeat_ttl_pull_push);\n    RUN_TEST (test_heartbeat_ttl_sub_pub);\n    RUN_TEST (test_heartbeat_ttl_pair_pair);\n\n    RUN_TEST (test_setsockopt_heartbeat_ttl_max);\n    RUN_TEST (test_setsockopt_heartbeat_ttl_more_than_max_fails);\n    RUN_TEST (test_setsockopt_heartbeat_ttl_near_zero);\n\n    RUN_TEST (test_heartbeat_notimeout_dealer_router);\n    RUN_TEST (test_heartbeat_notimeout_req_rep);\n    RUN_TEST (test_heartbeat_notimeout_pull_push);\n    RUN_TEST (test_heartbeat_notimeout_sub_pub);\n    RUN_TEST (test_heartbeat_notimeout_pair_pair);\n\n    RUN_TEST (test_heartbeat_notimeout_dealer_router_with_curve);\n    RUN_TEST (test_heartbeat_notimeout_req_rep_with_curve);\n    RUN_TEST (test_heartbeat_notimeout_pull_push_with_curve);\n    RUN_TEST (test_heartbeat_notimeout_sub_pub_with_curve);\n    RUN_TEST (test_heartbeat_notimeout_pair_pair_with_curve);\n\n#ifdef ZMQ_BUILD_DRAFT_API\n    RUN_TEST (test_heartbeat_ttl_client_server);\n    RUN_TEST (test_heartbeat_ttl_gather_scatter);\n\n    RUN_TEST (test_heartbeat_notimeout_client_server);\n    RUN_TEST (test_heartbeat_notimeout_gather_scatter);\n\n    RUN_TEST (test_heartbeat_notimeout_client_server_with_curve);\n    RUN_TEST (test_heartbeat_notimeout_gather_scatter_with_curve);\n#endif\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_hello_msg.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test (const char *address)\n{\n    //  Create a router\n    void *router = test_context_socket (ZMQ_ROUTER);\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  set router socket options\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_HELLO_MSG, \"H\", 1));\n\n    //  bind router\n    test_bind (router, address, my_endpoint, MAX_SOCKET_STRING);\n\n    //  Create a dealer\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));\n\n    // Receive the hello message\n    recv_string_expect_success (dealer, \"H\", 0);\n\n    //  Clean up.\n    test_context_socket_close (dealer);\n    test_context_socket_close (router);\n}\n\nvoid test_tcp ()\n{\n    test (\"tcp://127.0.0.1:*\");\n}\n\nvoid test_inproc ()\n{\n    test (\"inproc://hello-msg\");\n}\n\nvoid test_inproc_late_bind ()\n{\n    char address[] = \"inproc://late-hello-msg\";\n\n    //  Create a server\n    void *server = test_context_socket (ZMQ_SERVER);\n\n    //  set server socket options\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (server, ZMQ_HELLO_MSG, \"W\", 1));\n\n    //  Create a dealer\n    void *client = test_context_socket (ZMQ_CLIENT);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_HELLO_MSG, \"H\", 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, address));\n\n    //  bind server after the dealer\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, address));\n\n    // Receive the welcome message from server\n    recv_string_expect_success (client, \"W\", 0);\n\n    // Receive the hello message from client\n    recv_string_expect_success (server, \"H\", 0);\n\n    //  Clean up.\n    test_context_socket_close (client);\n    test_context_socket_close (server);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_tcp);\n    RUN_TEST (test_inproc);\n    RUN_TEST (test_inproc_late_bind);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_hiccup_msg.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test ()\n{\n    char address[MAX_SOCKET_STRING];\n    size_t addr_length = sizeof (address);\n\n    //  Create a server\n    void *server = test_context_socket (ZMQ_SERVER);\n\n    //  bind server\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, \"tcp://127.0.0.1:*\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (server, ZMQ_LAST_ENDPOINT, address, &addr_length));\n\n    //  Create a client\n    void *client = test_context_socket (ZMQ_CLIENT);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_HELLO_MSG, \"HELLO\", 5));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_HICCUP_MSG, \"HICCUP\", 6));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, address));\n\n    // Receive the hello message from client\n    recv_string_expect_success (server, \"HELLO\", 0);\n\n    // Kill the server\n    test_context_socket_close (server);\n\n    // Receive the hiccup message\n    recv_string_expect_success (client, \"HICCUP\", 0);\n\n    //  Clean up.\n    test_context_socket_close (client);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_hwm.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nconst int MAX_SENDS = 10000;\n\nenum TestType\n{\n    BIND_FIRST,\n    CONNECT_FIRST\n};\n\nvoid test_defaults ()\n{\n    // Set up bind socket\n    void *bind_socket = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, \"inproc://a\"));\n\n    // Set up connect socket\n    void *connect_socket = test_context_socket (ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://a\"));\n\n    // Send until we block\n    int send_count = 0;\n    while (send_count < MAX_SENDS\n           && zmq_send (connect_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++send_count;\n\n    msleep (SETTLE_TIME);\n\n    // Now receive all sent messages\n    int recv_count = 0;\n    while (zmq_recv (bind_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++recv_count;\n\n    TEST_ASSERT_EQUAL_INT (send_count, recv_count);\n\n    // Clean up\n    test_context_socket_close (connect_socket);\n    test_context_socket_close (bind_socket);\n\n    // Default values are 1000 on send and 1000 one receive, so 2000 total\n    TEST_ASSERT_EQUAL_INT (2000, send_count);\n}\n\nint count_msg (int send_hwm_, int recv_hwm_, TestType test_type_)\n{\n    void *bind_socket;\n    void *connect_socket;\n    if (test_type_ == BIND_FIRST) {\n        // Set up bind socket\n        bind_socket = test_context_socket (ZMQ_PULL);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n          bind_socket, ZMQ_RCVHWM, &recv_hwm_, sizeof (recv_hwm_)));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, \"inproc://a\"));\n\n        // Set up connect socket\n        connect_socket = test_context_socket (ZMQ_PUSH);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n          connect_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_)));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://a\"));\n\n        //  we must wait for the connect to succeed here, unfortunately we don't\n        //  have monitoring events for inproc, so we just hope SETTLE_TIME suffices\n        msleep (SETTLE_TIME);\n    } else {\n        // Set up connect socket\n        connect_socket = test_context_socket (ZMQ_PUSH);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n          connect_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_)));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://a\"));\n\n        // Set up bind socket\n        bind_socket = test_context_socket (ZMQ_PULL);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n          bind_socket, ZMQ_RCVHWM, &recv_hwm_, sizeof (recv_hwm_)));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, \"inproc://a\"));\n    }\n\n    // Send until we block\n    int send_count = 0;\n    while (send_count < MAX_SENDS\n           && zmq_send (connect_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++send_count;\n\n    // Now receive all sent messages\n    int recv_count = 0;\n    while (zmq_recv (bind_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++recv_count;\n\n    TEST_ASSERT_EQUAL_INT (send_count, recv_count);\n\n    // Now it should be possible to send one more.\n    send_string_expect_success (connect_socket, NULL, 0);\n\n    //  Consume the remaining message.\n    recv_string_expect_success (bind_socket, NULL, 0);\n\n    // Clean up\n    test_context_socket_close (connect_socket);\n    test_context_socket_close (bind_socket);\n\n    return send_count;\n}\n\nint test_inproc_bind_first (int send_hwm_, int recv_hwm_)\n{\n    return count_msg (send_hwm_, recv_hwm_, BIND_FIRST);\n}\n\nint test_inproc_connect_first (int send_hwm_, int recv_hwm_)\n{\n    return count_msg (send_hwm_, recv_hwm_, CONNECT_FIRST);\n}\n\nint test_inproc_connect_and_close_first (int send_hwm_, int recv_hwm_)\n{\n    // Set up connect socket\n    void *connect_socket = test_context_socket (ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (connect_socket, ZMQ_SNDHWM,\n                                               &send_hwm_, sizeof (send_hwm_)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://a\"));\n\n    // Send until we block\n    int send_count = 0;\n    while (send_count < MAX_SENDS\n           && zmq_send (connect_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++send_count;\n\n    // Close connect\n    test_context_socket_close (connect_socket);\n\n    // Set up bind socket\n    void *bind_socket = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (bind_socket, ZMQ_RCVHWM, &recv_hwm_, sizeof (recv_hwm_)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, \"inproc://a\"));\n\n    // Now receive all sent messages\n    int recv_count = 0;\n    while (zmq_recv (bind_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++recv_count;\n\n    TEST_ASSERT_EQUAL_INT (send_count, recv_count);\n\n    // Clean up\n    test_context_socket_close (bind_socket);\n\n    return send_count;\n}\n\nint test_inproc_bind_and_close_first (int send_hwm_, int /* recv_hwm */)\n{\n    // Set up bind socket\n    void *bind_socket = test_context_socket (ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (bind_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, \"inproc://a\"));\n\n    // Send until we block\n    int send_count = 0;\n    while (send_count < MAX_SENDS\n           && zmq_send (bind_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++send_count;\n\n    // Close bind\n    test_context_socket_close (bind_socket);\n\n    /* TODO Can't currently do connect without then wiring up a bind as things hang, this needs top be fixed.\n    // Set up connect socket\n    void *connect_socket = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (connect_socket, ZMQ_RCVHWM, &recv_hwm, sizeof (recv_hwm)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://a\"));\n\n    // Now receive all sent messages\n    int recv_count = 0;\n    while (zmq_recv (connect_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++recv_count;\n\n    TEST_ASSERT_EQUAL_INT(send_count, recv_count);\n    */\n\n    // Clean up\n    //test_context_socket_close (connect_socket);\n\n    return send_count;\n}\n\nvoid test_infinite_both_inproc_bind_first ()\n{\n    int count = test_inproc_bind_first (0, 0);\n    TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);\n}\n\nvoid test_infinite_both_inproc_connect_first ()\n{\n    int count = test_inproc_connect_first (0, 0);\n    TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);\n}\n\nvoid test_infinite_receive_inproc_bind_first ()\n{\n    int count = test_inproc_bind_first (1, 0);\n    TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);\n}\n\nvoid test_infinite_receive_inproc_connect_first ()\n{\n    int count = test_inproc_connect_first (1, 0);\n    TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);\n}\n\nvoid test_infinite_send_inproc_bind_first ()\n{\n    int count = test_inproc_bind_first (0, 1);\n    TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);\n}\n\nvoid test_infinite_send_inproc_connect_first ()\n{\n    int count = test_inproc_connect_first (0, 1);\n    TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);\n}\n\nvoid test_finite_both_bind_first ()\n{\n    // Send and recv buffers hwm 1, so total that can be queued is 2\n    int count = test_inproc_bind_first (1, 1);\n    TEST_ASSERT_EQUAL_INT (2, count);\n}\nvoid test_finite_both_connect_first ()\n{\n    // Send and recv buffers hwm 1, so total that can be queued is 2\n    int count = test_inproc_connect_first (1, 1);\n    TEST_ASSERT_EQUAL_INT (2, count);\n}\n\nvoid test_infinite_recv_connect_and_close_first ()\n{\n    // Send hwm of 1, send before bind so total that can be queued is 1\n    int count = test_inproc_connect_and_close_first (1, 0);\n    TEST_ASSERT_EQUAL_INT (1, count);\n}\n\nvoid test_infinite_recv_bind_and_close_first ()\n{\n    // Send hwm of 1, send from bind side before connect so total that can be queued should be 1,\n    // however currently all messages get thrown away before the connect.  BUG?\n    /*int count = */ test_inproc_bind_and_close_first (1, 0);\n    // TEST_ASSERT_EQUAL_INT (1, count);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_defaults);\n\n    RUN_TEST (test_infinite_both_inproc_bind_first);\n    RUN_TEST (test_infinite_both_inproc_connect_first);\n\n    RUN_TEST (test_infinite_receive_inproc_bind_first);\n    RUN_TEST (test_infinite_receive_inproc_connect_first);\n\n    RUN_TEST (test_infinite_send_inproc_bind_first);\n    RUN_TEST (test_infinite_send_inproc_connect_first);\n\n    RUN_TEST (test_finite_both_bind_first);\n    RUN_TEST (test_finite_both_connect_first);\n\n    RUN_TEST (test_infinite_recv_connect_and_close_first);\n    RUN_TEST (test_infinite_recv_bind_and_close_first);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_hwm_pubsub.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\n// NOTE: on OSX the endpoint returned by ZMQ_LAST_ENDPOINT may be quite long,\n//       ensure we have extra space for that:\n#define SOCKET_STRING_LEN (MAX_SOCKET_STRING * 4)\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nint test_defaults (int send_hwm_, int msg_cnt_, const char *endpoint_)\n{\n    char pub_endpoint[SOCKET_STRING_LEN];\n\n    // Set up and bind XPUB socket\n    void *pub_socket = test_context_socket (ZMQ_XPUB);\n    test_bind (pub_socket, endpoint_, pub_endpoint, sizeof pub_endpoint);\n\n    // Set up and connect SUB socket\n    void *sub_socket = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, pub_endpoint));\n\n    //set a hwm on publisher\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, 0, 0));\n\n    // Wait before starting TX operations till 1 subscriber has subscribed\n    // (in this test there's 1 subscriber only)\n    const char subscription_to_all_topics[] = {1, 0};\n    recv_string_expect_success (pub_socket, subscription_to_all_topics, 0);\n\n    // Send until we reach \"mute\" state\n    int send_count = 0;\n    while (send_count < msg_cnt_\n           && zmq_send (pub_socket, \"test message\", 13, ZMQ_DONTWAIT) == 13)\n        ++send_count;\n\n    TEST_ASSERT_EQUAL_INT (send_hwm_, send_count);\n    msleep (SETTLE_TIME);\n\n    // Now receive all sent messages\n    int recv_count = 0;\n    char dummybuff[64];\n    while (13 == zmq_recv (sub_socket, &dummybuff, 64, ZMQ_DONTWAIT)) {\n        ++recv_count;\n    }\n\n    TEST_ASSERT_EQUAL_INT (send_hwm_, recv_count);\n\n    // Clean up\n    test_context_socket_close (sub_socket);\n    test_context_socket_close (pub_socket);\n\n    return recv_count;\n}\n\nint receive (void *socket_, int *is_termination_)\n{\n    int recv_count = 0;\n    *is_termination_ = 0;\n\n    // Now receive all sent messages\n    char buffer[255];\n    int len;\n    while ((len = zmq_recv (socket_, buffer, sizeof (buffer), 0)) >= 0) {\n        ++recv_count;\n\n        if (len == 3 && strncmp (buffer, \"end\", len) == 0) {\n            *is_termination_ = 1;\n            return recv_count;\n        }\n    }\n\n    return recv_count;\n}\n\nint test_blocking (int send_hwm_, int msg_cnt_, const char *endpoint_)\n{\n    char pub_endpoint[SOCKET_STRING_LEN];\n\n    // Set up bind socket\n    void *pub_socket = test_context_socket (ZMQ_XPUB);\n    test_bind (pub_socket, endpoint_, pub_endpoint, sizeof pub_endpoint);\n\n    // Set up connect socket\n    void *sub_socket = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, pub_endpoint));\n\n    //set a hwm on publisher\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_)));\n    int wait = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub_socket, ZMQ_XPUB_NODROP, &wait, sizeof (wait)));\n    int timeout_ms = 10;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      sub_socket, ZMQ_RCVTIMEO, &timeout_ms, sizeof (timeout_ms)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, 0, 0));\n\n    // Wait before starting TX operations till 1 subscriber has subscribed\n    // (in this test there's 1 subscriber only)\n    const uint8_t subscription_to_all_topics[] = {1};\n    recv_array_expect_success (pub_socket, subscription_to_all_topics, 0);\n\n    // Send until we block\n    int send_count = 0;\n    int recv_count = 0;\n    int blocked_count = 0;\n    int is_termination = 0;\n    while (send_count < msg_cnt_) {\n        const int rc = zmq_send (pub_socket, NULL, 0, ZMQ_DONTWAIT);\n        if (rc == 0) {\n            ++send_count;\n        } else if (-1 == rc) {\n            // if the PUB socket blocks due to HWM, errno should be EAGAIN:\n            blocked_count++;\n            TEST_ASSERT_FAILURE_ERRNO (EAGAIN, -1);\n            recv_count += receive (sub_socket, &is_termination);\n        }\n    }\n\n    // if send_hwm_ < msg_cnt_, we should block at least once:\n    char counts_string[128];\n    snprintf (counts_string, sizeof counts_string - 1,\n              \"sent = %i, received = %i\", send_count, recv_count);\n    TEST_ASSERT_GREATER_THAN_INT_MESSAGE (0, blocked_count, counts_string);\n\n    // dequeue SUB socket again, to make sure XPUB has space to send the termination message\n    recv_count += receive (sub_socket, &is_termination);\n\n    // send termination message\n    send_string_expect_success (pub_socket, \"end\", 0);\n\n    // now block on the SUB side till we get the termination message\n    while (is_termination == 0)\n        recv_count += receive (sub_socket, &is_termination);\n\n    // remove termination message from the count:\n    recv_count--;\n\n    TEST_ASSERT_EQUAL_INT (send_count, recv_count);\n\n    // Clean up\n    test_context_socket_close (sub_socket);\n    test_context_socket_close (pub_socket);\n\n    return recv_count;\n}\n\n// hwm should apply to the messages that have already been received\n// with hwm 11024: send 9999 msg, receive 9999, send 1100, receive 1100\nvoid test_reset_hwm ()\n{\n    const int first_count = 9999;\n    const int second_count = 1100;\n    int hwm = 11024;\n    char my_endpoint[SOCKET_STRING_LEN];\n\n    // Set up bind socket\n    void *pub_socket = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub_socket, ZMQ_SNDHWM, &hwm, sizeof (hwm)));\n    bind_loopback_ipv4 (pub_socket, my_endpoint, MAX_SOCKET_STRING);\n\n    // Set up connect socket\n    void *sub_socket = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub_socket, ZMQ_RCVHWM, &hwm, sizeof (hwm)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, my_endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, 0, 0));\n\n    msleep (SETTLE_TIME);\n\n    // Send messages\n    int send_count = 0;\n    while (send_count < first_count\n           && zmq_send (pub_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++send_count;\n    TEST_ASSERT_EQUAL_INT (first_count, send_count);\n\n    msleep (SETTLE_TIME);\n\n    // Now receive all sent messages\n    int recv_count = 0;\n    while (0 == zmq_recv (sub_socket, NULL, 0, ZMQ_DONTWAIT)) {\n        ++recv_count;\n    }\n    TEST_ASSERT_EQUAL_INT (first_count, recv_count);\n\n    msleep (SETTLE_TIME);\n\n    // Send messages\n    send_count = 0;\n    while (send_count < second_count\n           && zmq_send (pub_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++send_count;\n    TEST_ASSERT_EQUAL_INT (second_count, send_count);\n\n    msleep (SETTLE_TIME);\n\n    // Now receive all sent messages\n    recv_count = 0;\n    while (0 == zmq_recv (sub_socket, NULL, 0, ZMQ_DONTWAIT)) {\n        ++recv_count;\n    }\n    TEST_ASSERT_EQUAL_INT (second_count, recv_count);\n\n    // Clean up\n    test_context_socket_close (sub_socket);\n    test_context_socket_close (pub_socket);\n}\n\nvoid test_defaults_large (const char *bind_endpoint_)\n{\n    // send 1000 msg on hwm 1000, receive 1000\n    TEST_ASSERT_EQUAL_INT (1000, test_defaults (1000, 1000, bind_endpoint_));\n}\n\nvoid test_defaults_small (const char *bind_endpoint_)\n{\n    // send 1000 msg on hwm 100, receive 100\n    TEST_ASSERT_EQUAL_INT (100, test_defaults (100, 100, bind_endpoint_));\n}\n\nvoid test_blocking (const char *bind_endpoint_)\n{\n    // send 6000 msg on hwm 2000, drops above hwm, only receive hwm:\n    TEST_ASSERT_EQUAL_INT (6000, test_blocking (2000, 6000, bind_endpoint_));\n}\n\n#define DEFINE_REGULAR_TEST_CASES(name, bind_endpoint)                         \\\n    void test_defaults_large_##name ()                                         \\\n    {                                                                          \\\n        test_defaults_large (bind_endpoint);                                   \\\n    }                                                                          \\\n                                                                               \\\n    void test_defaults_small_##name ()                                         \\\n    {                                                                          \\\n        test_defaults_small (bind_endpoint);                                   \\\n    }                                                                          \\\n                                                                               \\\n    void test_blocking_##name ()                                               \\\n    {                                                                          \\\n        test_blocking (bind_endpoint);                                         \\\n    }\n\n#define RUN_REGULAR_TEST_CASES(name)                                           \\\n    RUN_TEST (test_defaults_large_##name);                                     \\\n    RUN_TEST (test_defaults_small_##name);                                     \\\n    RUN_TEST (test_blocking_##name)\n\nDEFINE_REGULAR_TEST_CASES (tcp, \"tcp://127.0.0.1:*\")\nDEFINE_REGULAR_TEST_CASES (inproc, \"inproc://a\")\n\n#if !defined(ZMQ_HAVE_WINDOWS) && !defined(ZMQ_HAVE_GNU)\nDEFINE_REGULAR_TEST_CASES (ipc, \"ipc://*\")\n#endif\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n\n    RUN_REGULAR_TEST_CASES (tcp);\n    RUN_REGULAR_TEST_CASES (inproc);\n\n#if !defined(ZMQ_HAVE_WINDOWS) && !defined(ZMQ_HAVE_GNU)\n    RUN_REGULAR_TEST_CASES (ipc);\n#endif\n    RUN_TEST (test_reset_hwm);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_immediate.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_immediate_1 ()\n{\n    int val;\n    int rc;\n    char buffer[16];\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n    // TEST 1.\n    // First we're going to attempt to send messages to two\n    // pipes, one connected, the other not. We should see\n    // the PUSH load balancing to both pipes, and hence half\n    // of the messages getting queued, as connect() creates a\n    // pipe immediately.\n\n    void *to = test_context_socket (ZMQ_PULL);\n\n    // Bind the one valid receiver\n    val = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (to, ZMQ_LINGER, &val, sizeof (val)));\n    bind_loopback_ipv4 (to, my_endpoint, len);\n\n    // Create a socket pushing to two endpoints - only 1 message should arrive.\n    void *from = test_context_socket (ZMQ_PUSH);\n\n    val = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (from, ZMQ_LINGER, &val, sizeof (val)));\n    // This pipe will not connect (provided the ephemeral port is not 5556)\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, \"tcp://localhost:5556\"));\n    // This pipe will\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, my_endpoint));\n\n    msleep (SETTLE_TIME);\n\n    // We send 10 messages, 5 should just get stuck in the queue\n    // for the not-yet-connected pipe\n    for (int i = 0; i < 10; ++i) {\n        send_string_expect_success (from, \"Hello\", 0);\n    }\n\n    // We now consume from the connected pipe\n    // - we should see just 5\n    int timeout = 250;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (to, ZMQ_RCVTIMEO, &timeout, sizeof (int)));\n\n    int seen = 0;\n    while (true) {\n        rc = zmq_recv (to, &buffer, sizeof (buffer), 0);\n        if (rc == -1)\n            break; //  Break when we didn't get a message\n        seen++;\n    }\n    // TODO: this fails ~1% of the runs on OBS but it does not seem to be reproducible anywhere else\n    if (seen == 0)\n        TEST_IGNORE_MESSAGE (\n          \"Unreliable test occasionally fails on slow CIs, ignoring\");\n    TEST_ASSERT_EQUAL_INT (5, seen);\n\n    test_context_socket_close (from);\n    test_context_socket_close (to);\n}\n\n\nvoid test_immediate_2 ()\n{\n    // This time we will do the same thing, connect two pipes,\n    // one of which will succeed in connecting to a bound\n    // receiver, the other of which will fail. However, we will\n    // also set the delay attach on connect flag, which should\n    // cause the pipe attachment to be delayed until the connection\n    // succeeds.\n\n    // Bind the valid socket\n    void *to = test_context_socket (ZMQ_PULL);\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (to, my_endpoint, len);\n\n    int val = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (to, ZMQ_LINGER, &val, sizeof (val)));\n\n    // Create a socket pushing to two endpoints - all messages should arrive.\n    void *from = test_context_socket (ZMQ_PUSH);\n\n    val = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (from, ZMQ_LINGER, &val, sizeof (val)));\n\n    // Set the key flag\n    val = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (from, ZMQ_IMMEDIATE, &val, sizeof (val)));\n\n    // Connect to the invalid socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, \"tcp://localhost:5561\"));\n    // Connect to the valid socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, my_endpoint));\n\n    // Send 10 messages, all should be routed to the connected pipe\n    for (int i = 0; i < 10; ++i) {\n        send_string_expect_success (from, \"Hello\", 0);\n    }\n    int timeout = 250;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (to, ZMQ_RCVTIMEO, &timeout, sizeof (int)));\n\n    int seen = 0;\n    while (true) {\n        char buffer[16];\n        int rc = zmq_recv (to, &buffer, sizeof (buffer), 0);\n        if (rc == -1)\n            break; //  Break when we didn't get a message\n        seen++;\n    }\n    TEST_ASSERT_EQUAL_INT (10, seen);\n\n    test_context_socket_close (from);\n    test_context_socket_close (to);\n}\n\nvoid test_immediate_3 ()\n{\n    // This time we want to validate that the same blocking behaviour\n    // occurs with an existing connection that is broken. We will send\n    // messages to a connected pipe, disconnect and verify the messages\n    // block. Then we reconnect and verify messages flow again.\n    void *backend = test_context_socket (ZMQ_DEALER);\n    void *frontend = test_context_socket (ZMQ_DEALER);\n\n    int zero = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (backend, ZMQ_LINGER, &zero, sizeof (zero)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (frontend, ZMQ_LINGER, &zero, sizeof (zero)));\n\n    //  Frontend connects to backend using IMMEDIATE\n    int on = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (frontend, ZMQ_IMMEDIATE, &on, sizeof (on)));\n\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (backend, my_endpoint, len);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (frontend, my_endpoint));\n\n    //  Ping backend to frontend so we know when the connection is up\n    send_string_expect_success (backend, \"Hello\", 0);\n    recv_string_expect_success (frontend, \"Hello\", 0);\n\n    // Send message from frontend to backend\n    send_string_expect_success (frontend, \"Hello\", ZMQ_DONTWAIT);\n\n    test_context_socket_close (backend);\n\n    //  Give time to process disconnect\n    msleep (SETTLE_TIME * 10);\n\n    // Send a message, should fail\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN,\n                               zmq_send (frontend, \"Hello\", 5, ZMQ_DONTWAIT));\n\n    //  Recreate backend socket\n    backend = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (backend, ZMQ_LINGER, &zero, sizeof (zero)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, my_endpoint));\n\n    //  Ping backend to frontend so we know when the connection is up\n    send_string_expect_success (backend, \"Hello\", 0);\n    recv_string_expect_success (frontend, \"Hello\", 0);\n\n    // After the reconnect, should succeed\n    send_string_expect_success (frontend, \"Hello\", ZMQ_DONTWAIT);\n\n    test_context_socket_close (backend);\n    test_context_socket_close (frontend);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n    UNITY_BEGIN ();\n    RUN_TEST (test_immediate_1);\n    RUN_TEST (test_immediate_2);\n    RUN_TEST (test_immediate_3);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_inproc_connect.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nstatic void pusher (void * /*unused*/)\n{\n    // Connect first\n    // do not use test_context_socket here, as it is not thread-safe\n    void *connect_socket = zmq_socket (get_test_context (), ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://sink\"));\n\n    // Queue up some data\n    send_string_expect_success (connect_socket, \"foobar\", 0);\n\n    // Cleanup\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (connect_socket));\n}\n\nstatic void simult_conn (void *endpt_)\n{\n    // Pull out arguments - endpoint string\n    const char *endpt = static_cast<const char *> (endpt_);\n\n    // Connect\n    // do not use test_context_socket here, as it is not thread-safe\n    void *connect_socket = zmq_socket (get_test_context (), ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, endpt));\n    recv_string_expect_success (connect_socket, \"foobar\", 0);\n\n    // Cleanup\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (connect_socket));\n}\n\nstatic void simult_bind (void *endpt_)\n{\n    // Pull out arguments - context followed by endpoint string\n    const char *endpt = static_cast<const char *> (endpt_);\n\n    // Bind\n    // do not use test_context_socket here, as it is not thread-safe\n    void *bind_socket = zmq_socket (get_test_context (), ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, endpt));\n    send_string_expect_success (bind_socket, \"foobar\", 0);\n\n    // Cleanup\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (bind_socket));\n}\n\nvoid test_bind_before_connect ()\n{\n    // Bind first\n    void *bind_socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, \"inproc://bbc\"));\n\n    // Now connect\n    void *connect_socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://bbc\"));\n\n    // Queue up some data\n    send_string_expect_success (connect_socket, \"foobar\", 0);\n\n    // Read pending message\n    recv_string_expect_success (bind_socket, \"foobar\", 0);\n\n    // Cleanup\n    test_context_socket_close (connect_socket);\n    test_context_socket_close (bind_socket);\n}\n\nvoid test_connect_before_bind ()\n{\n    // Connect first\n    void *connect_socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://cbb\"));\n\n    // Queue up some data\n    send_string_expect_success (connect_socket, \"foobar\", 0);\n\n    // Now bind\n    void *bind_socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, \"inproc://cbb\"));\n\n    // Read pending message\n    recv_string_expect_success (bind_socket, \"foobar\", 0);\n\n    // Cleanup\n    test_context_socket_close (connect_socket);\n    test_context_socket_close (bind_socket);\n}\n\nvoid test_connect_before_bind_pub_sub ()\n{\n    // Connect first\n    void *connect_socket = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://cbbps\"));\n\n    // Queue up some data, this will be dropped\n    send_string_expect_success (connect_socket, \"before\", 0);\n\n    // Now bind\n    void *bind_socket = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (bind_socket, ZMQ_SUBSCRIBE, \"\", 0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, \"inproc://cbbps\"));\n\n    // Wait for pub-sub connection to happen\n    msleep (SETTLE_TIME);\n\n    // Queue up some data, this not will be dropped\n    send_string_expect_success (connect_socket, \"after\", 0);\n\n    // Read pending message\n    recv_string_expect_success (bind_socket, \"after\", 0);\n\n    // Cleanup\n    test_context_socket_close (connect_socket);\n    test_context_socket_close (bind_socket);\n}\n\nvoid test_connect_before_bind_ctx_term ()\n{\n    for (int i = 0; i < 20; ++i) {\n        // Connect first\n        void *connect_socket = test_context_socket (ZMQ_ROUTER);\n\n        char ep[32];\n        snprintf (ep, 32 * sizeof (char), \"inproc://cbbrr%d\", i);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, ep));\n\n        // Cleanup\n        test_context_socket_close (connect_socket);\n    }\n}\n\nvoid test_multiple_connects ()\n{\n    const unsigned int no_of_connects = 10;\n\n    void *connect_socket[no_of_connects];\n\n    // Connect first\n    for (unsigned int i = 0; i < no_of_connects; ++i) {\n        connect_socket[i] = test_context_socket (ZMQ_PUSH);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_connect (connect_socket[i], \"inproc://multiple\"));\n\n        // Queue up some data\n        send_string_expect_success (connect_socket[i], \"foobar\", 0);\n    }\n\n    // Now bind\n    void *bind_socket = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, \"inproc://multiple\"));\n\n    for (unsigned int i = 0; i < no_of_connects; ++i) {\n        recv_string_expect_success (bind_socket, \"foobar\", 0);\n    }\n\n    // Cleanup\n    for (unsigned int i = 0; i < no_of_connects; ++i) {\n        test_context_socket_close (connect_socket[i]);\n    }\n\n    test_context_socket_close (bind_socket);\n}\n\nvoid test_multiple_threads ()\n{\n    const unsigned int no_of_threads = 30;\n\n    void *threads[no_of_threads];\n\n    // Connect first\n    for (unsigned int i = 0; i < no_of_threads; ++i) {\n        threads[i] = zmq_threadstart (&pusher, NULL);\n    }\n\n    // Now bind\n    void *bind_socket = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, \"inproc://sink\"));\n\n    for (unsigned int i = 0; i < no_of_threads; ++i) {\n        // Read pending message\n        recv_string_expect_success (bind_socket, \"foobar\", 0);\n    }\n\n    // Cleanup\n    for (unsigned int i = 0; i < no_of_threads; ++i) {\n        zmq_threadclose (threads[i]);\n    }\n\n    test_context_socket_close (bind_socket);\n}\n\nvoid test_simultaneous_connect_bind_threads ()\n{\n    const unsigned int no_of_times = 50;\n    void *threads[no_of_times * 2];\n    void *thr_args[no_of_times];\n    char endpts[no_of_times][20];\n\n    // Set up thread arguments: context followed by endpoint string\n    for (unsigned int i = 0; i < no_of_times; ++i) {\n        thr_args[i] = (void *) endpts[i];\n        snprintf (endpts[i], 20 * sizeof (char), \"inproc://foo_%d\", i);\n    }\n\n    // Spawn all threads as simultaneously as possible\n    for (unsigned int i = 0; i < no_of_times; ++i) {\n        threads[i * 2 + 0] = zmq_threadstart (&simult_conn, thr_args[i]);\n        threads[i * 2 + 1] = zmq_threadstart (&simult_bind, thr_args[i]);\n    }\n\n    // Close all threads\n    for (unsigned int i = 0; i < no_of_times; ++i) {\n        zmq_threadclose (threads[i * 2 + 0]);\n        zmq_threadclose (threads[i * 2 + 1]);\n    }\n}\n\nvoid test_routing_id ()\n{\n    //  Create the infrastructure\n    void *sc = test_context_socket (ZMQ_DEALER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, \"inproc://routing_id\"));\n\n    void *sb = test_context_socket (ZMQ_ROUTER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"inproc://routing_id\"));\n\n    //  Send 2-part message.\n    TEST_ASSERT_EQUAL_INT (\n      1, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (sc, \"A\", 1, ZMQ_SNDMORE)));\n    TEST_ASSERT_EQUAL_INT (\n      1, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (sc, \"B\", 1, 0)));\n\n    //  Routing id comes first.\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0));\n    TEST_ASSERT_EQUAL_INT (1, zmq_msg_more (&msg));\n\n    //  Then the first part of the message body.\n    TEST_ASSERT_EQUAL_INT (\n      1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0)));\n    TEST_ASSERT_EQUAL_INT (1, zmq_msg_more (&msg));\n\n    //  And finally, the second part of the message body.\n    TEST_ASSERT_EQUAL_INT (\n      1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0)));\n    TEST_ASSERT_EQUAL_INT (0, zmq_msg_more (&msg));\n\n    //  Deallocate the infrastructure.\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_connect_only ()\n{\n    void *connect_socket = test_context_socket (ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://a\"));\n\n    test_context_socket_close (connect_socket);\n}\n\n\nvoid test_unbind ()\n{\n    // Bind and unbind socket 1\n    void *bind_socket1 = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket1, \"inproc://unbind\"));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (bind_socket1, \"inproc://unbind\"));\n\n    // Bind socket 2\n    void *bind_socket2 = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket2, \"inproc://unbind\"));\n\n    // Now connect\n    void *connect_socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://unbind\"));\n\n    // Queue up some data\n    send_string_expect_success (connect_socket, \"foobar\", 0);\n\n    // Read pending message\n    recv_string_expect_success (bind_socket2, \"foobar\", 0);\n\n    // Cleanup\n    test_context_socket_close (connect_socket);\n    test_context_socket_close (bind_socket1);\n    test_context_socket_close (bind_socket2);\n}\n\nvoid test_shutdown_during_pend ()\n{\n    // Connect first\n    void *connect_socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, \"inproc://cbb\"));\n\n    zmq_ctx_shutdown (get_test_context ());\n\n    // Cleanup\n    test_context_socket_close (connect_socket);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_bind_before_connect);\n    RUN_TEST (test_connect_before_bind);\n    RUN_TEST (test_connect_before_bind_pub_sub);\n    RUN_TEST (test_connect_before_bind_ctx_term);\n    RUN_TEST (test_multiple_connects);\n    RUN_TEST (test_multiple_threads);\n    RUN_TEST (test_simultaneous_connect_bind_threads);\n    RUN_TEST (test_routing_id);\n    RUN_TEST (test_connect_only);\n    RUN_TEST (test_unbind);\n    RUN_TEST (test_shutdown_during_pend);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_invalid_rep.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_invalid_rep ()\n{\n    //  Create REQ/ROUTER wiring.\n    void *router_socket = test_context_socket (ZMQ_ROUTER);\n    void *req_socket = test_context_socket (ZMQ_REQ);\n\n    int linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (router_socket, ZMQ_LINGER, &linger, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (req_socket, ZMQ_LINGER, &linger, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router_socket, \"inproc://hi\"));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req_socket, \"inproc://hi\"));\n\n    //  Initial request.\n    send_string_expect_success (req_socket, \"r\", 0);\n\n    //  Receive the request.\n    char addr[32];\n    int addr_size;\n    char bottom[1];\n    char body[1];\n    TEST_ASSERT_SUCCESS_ERRNO (\n      addr_size = zmq_recv (router_socket, addr, sizeof (addr), 0));\n    TEST_ASSERT_EQUAL_INT (0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (\n                                router_socket, bottom, sizeof (bottom), 0)));\n    TEST_ASSERT_EQUAL_INT (1, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (\n                                router_socket, body, sizeof (body), 0)));\n\n    //  Send invalid reply.\n    TEST_ASSERT_EQUAL_INT (addr_size, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (\n                                        router_socket, addr, addr_size, 0)));\n\n    //  Send valid reply.\n    TEST_ASSERT_EQUAL_INT (\n      addr_size, TEST_ASSERT_SUCCESS_ERRNO (\n                   zmq_send (router_socket, addr, addr_size, ZMQ_SNDMORE)));\n    TEST_ASSERT_EQUAL_INT (0, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (\n                                router_socket, bottom, 0, ZMQ_SNDMORE)));\n    send_string_expect_success (router_socket, \"b\", 0);\n\n    //  Check whether we've got the valid reply.\n    recv_string_expect_success (req_socket, \"b\", 0);\n\n    //  Tear down the wiring.\n    test_context_socket_close (router_socket);\n    test_context_socket_close (req_socket);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_invalid_rep);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_iov.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n// XSI vector I/O\n#if defined ZMQ_HAVE_UIO\n#include <sys/uio.h>\n#else\nstruct iovec\n{\n    void *iov_base;\n    size_t iov_len;\n};\n#endif\n\nstatic void do_check (void *sb_, void *sc_, size_t msg_size_)\n{\n    TEST_ASSERT_NOT_NULL (sb_);\n    TEST_ASSERT_NOT_NULL (sc_);\n    TEST_ASSERT_GREATER_THAN (0, msg_size_);\n\n    const char msg_val = '1';\n    const int num_messages = 10;\n    size_t send_count, recv_count;\n\n    send_count = recv_count = num_messages;\n\n    char *ref_msg = static_cast<char *> (malloc (msg_size_));\n    TEST_ASSERT_NOT_NULL (ref_msg);\n    memset (ref_msg, msg_val, msg_size_);\n\n    // zmq_sendiov(3) as a single multi-part send\n    struct iovec send_iov[num_messages];\n    char *buf = static_cast<char *> (malloc (msg_size_ * num_messages));\n\n    for (int i = 0; i < num_messages; i++) {\n        send_iov[i].iov_base = &buf[i * msg_size_];\n        send_iov[i].iov_len = msg_size_;\n        memcpy (send_iov[i].iov_base, ref_msg, msg_size_);\n\n        // TODO: this assertion only checks if memcpy behaves as expected... remove this or assert something else?\n        TEST_ASSERT_EQUAL_HEX8_ARRAY (ref_msg, send_iov[i].iov_base, msg_size_);\n    }\n\n    // Test errors - zmq_recviov - null socket\n    TEST_ASSERT_FAILURE_ERRNO (\n      ENOTSOCK, zmq_sendiov (NULL, send_iov, send_count, ZMQ_SNDMORE));\n    // Test errors - zmq_recviov - invalid send count\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_sendiov (sc_, send_iov, 0, 0));\n    // Test errors - zmq_recviov - null iovec\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_sendiov (sc_, NULL, send_count, 0));\n\n    // Test success\n\n    // The zmq_sendiov(3) API method does not follow the same semantics as\n    // zmq_recviov(3); the latter returns the count of messages sent, rightly\n    // so, whilst the former sends the number of bytes successfully sent from\n    // the last message, which does not hold much sense from a batch send\n    // perspective; hence the assert checks if the result is same as msg_size.\n    TEST_ASSERT_EQUAL_INT (\n      (int) msg_size_, TEST_ASSERT_SUCCESS_ERRNO (\n                         zmq_sendiov (sc_, send_iov, send_count, ZMQ_SNDMORE)));\n\n    // zmq_recviov(3) single-shot\n    struct iovec recv_iov[num_messages];\n\n    // Test errors - zmq_recviov - null socket\n    TEST_ASSERT_FAILURE_ERRNO (ENOTSOCK,\n                               zmq_recviov (NULL, recv_iov, &recv_count, 0));\n    // Test error - zmq_recviov - invalid receive count\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_recviov (sb_, recv_iov, NULL, 0));\n    size_t invalid_recv_count = 0;\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_recviov (sb_, recv_iov, &invalid_recv_count, 0));\n    // Test error - zmq_recviov - null iovec\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_recviov (sb_, NULL, &recv_count, 0));\n\n    // Test success\n    TEST_ASSERT_EQUAL_INT (\n      num_messages,\n      TEST_ASSERT_SUCCESS_ERRNO (zmq_recviov (sb_, recv_iov, &recv_count, 0)));\n\n    for (int i = 0; i < num_messages; i++) {\n        TEST_ASSERT_NOT_NULL (recv_iov[i].iov_base);\n        TEST_ASSERT_EQUAL_STRING_LEN (ref_msg, recv_iov[i].iov_base, msg_size_);\n        free (recv_iov[i].iov_base);\n    }\n\n    TEST_ASSERT_EQUAL_INT (send_count, recv_count);\n    free (ref_msg);\n    free (buf);\n}\n\nvoid test_iov ()\n{\n    void *sb = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"inproc://a\"));\n\n    msleep (SETTLE_TIME);\n\n    void *sc = test_context_socket (ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, \"inproc://a\"));\n\n    // message bigger than VSM max\n    do_check (sb, sc, 100);\n\n    // message smaller than VSM max\n    do_check (sb, sc, 10);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_iov);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_ipc_wildcard.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_ipc_wildcard ()\n{\n    void *sb = test_context_socket (ZMQ_PAIR);\n    char endpoint[200];\n    bind_loopback_ipc (sb, endpoint, sizeof endpoint);\n\n    void *sc = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_ipc_wildcard);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_issue_566.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n//  Issue 566 describes a problem in libzmq v4.0.0 where a dealer to router\n//  connection would fail randomly. The test works when the two sockets are\n//  on the same context, and failed when they were on separate contexts.\n//  Fixed by https://github.com/zeromq/libzmq/commit/be25cf.\nvoid test_issue_566 ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n    void *ctx1 = zmq_ctx_new ();\n    TEST_ASSERT_NOT_NULL (ctx1);\n\n    void *ctx2 = zmq_ctx_new ();\n    TEST_ASSERT_NOT_NULL (ctx2);\n\n    void *router = zmq_socket (ctx1, ZMQ_ROUTER);\n    int on = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY, &on, sizeof (on)));\n    bind_loopback_ipv4 (router, my_endpoint, sizeof (my_endpoint));\n\n    //  Repeat often enough to be sure this works as it should\n    for (int cycle = 0; cycle < 100; cycle++) {\n        //  Create dealer with unique explicit routing id\n        //  We assume the router learns this out-of-band\n        void *dealer = zmq_socket (ctx2, ZMQ_DEALER);\n        //  Leave space for NULL char from sprintf, gcc warning\n        char routing_id[11];\n        snprintf (routing_id, 11 * sizeof (char), \"%09d\", cycle);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (dealer, ZMQ_ROUTING_ID, routing_id, 10));\n        int rcvtimeo = 1000;\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (dealer, ZMQ_RCVTIMEO, &rcvtimeo, sizeof (int)));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));\n\n        //  Router will try to send to dealer, at short intervals.\n        //  It typically takes 2-5 msec for the connection to establish\n        //  on a loopback interface, but we'll allow up to one second\n        //  before failing the test (e.g. for running on a debugger or\n        //  a very slow system).\n        for (int attempt = 0; attempt < 500; attempt++) {\n            zmq_poll (NULL, 0, 2);\n            int rc = zmq_send (router, routing_id, 10, ZMQ_SNDMORE);\n            if (rc == -1 && errno == EHOSTUNREACH)\n                continue;\n            TEST_ASSERT_EQUAL (10, rc);\n            send_string_expect_success (router, \"HELLO\", 0);\n            break;\n        }\n        recv_string_expect_success (dealer, \"HELLO\", 0);\n        close_zero_linger (dealer);\n    }\n    zmq_close (router);\n    zmq_ctx_destroy (ctx1);\n    zmq_ctx_destroy (ctx2);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_issue_566);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_last_endpoint.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nstatic void do_bind_and_verify (void *s_, const char *endpoint_)\n{\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (s_, endpoint_));\n    char reported[255];\n    size_t size = 255;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (s_, ZMQ_LAST_ENDPOINT, reported, &size));\n    TEST_ASSERT_EQUAL_STRING (endpoint_, reported);\n}\n\nvoid test_last_endpoint ()\n{\n    void *sb = test_context_socket (ZMQ_ROUTER);\n    int val = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sb, ZMQ_LINGER, &val, sizeof (val)));\n\n    do_bind_and_verify (sb, ENDPOINT_1);\n    do_bind_and_verify (sb, ENDPOINT_2);\n\n    test_context_socket_close (sb);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_last_endpoint);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_many_sockets.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <vector>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_system_max ()\n{\n    // Keep allocating sockets until we run out of system resources\n    const int no_of_sockets = 2 * 65536;\n    zmq_ctx_set (get_test_context (), ZMQ_MAX_SOCKETS, no_of_sockets);\n    std::vector<void *> sockets;\n\n    while (true) {\n        void *socket = zmq_socket (get_test_context (), ZMQ_PAIR);\n        if (!socket)\n            break;\n        sockets.push_back (socket);\n    }\n    TEST_ASSERT_LESS_OR_EQUAL (no_of_sockets,\n                               static_cast<int> (sockets.size ()));\n    printf (\"Socket creation failed after %i sockets\\n\",\n            static_cast<int> (sockets.size ()));\n\n    //  System is out of resources, further calls to zmq_socket should return NULL\n    for (unsigned int i = 0; i < 10; ++i) {\n        TEST_ASSERT_NULL (zmq_socket (get_test_context (), ZMQ_PAIR));\n    }\n    // Clean up.\n    for (unsigned int i = 0; i < sockets.size (); ++i)\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_close (sockets[i]));\n}\n\nvoid test_zmq_default_max ()\n{\n    //  Keep allocating sockets until we hit the default limit\n    std::vector<void *> sockets;\n\n    while (true) {\n        void *socket = zmq_socket (get_test_context (), ZMQ_PAIR);\n        if (!socket)\n            break;\n        sockets.push_back (socket);\n    }\n    //  We may stop sooner if system has fewer available sockets\n    TEST_ASSERT_LESS_OR_EQUAL (ZMQ_MAX_SOCKETS_DFLT, sockets.size ());\n\n    //  Further calls to zmq_socket should return NULL\n    for (unsigned int i = 0; i < 10; ++i) {\n        TEST_ASSERT_NULL (zmq_socket (get_test_context (), ZMQ_PAIR));\n    }\n\n    //  Clean up\n    for (unsigned int i = 0; i < sockets.size (); ++i)\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_close (sockets[i]));\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_system_max);\n    RUN_TEST (test_zmq_default_max);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_metadata.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <unity.h>\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\nstatic void zap_handler (void *handler_)\n{\n    uint8_t metadata[] = {5, 'H', 'e', 'l', 'l', 'o', 0,  0,\n                          0, 5,   'W', 'o', 'r', 'l', 'd'};\n\n    //  Process ZAP requests forever\n    while (true) {\n        char *version = s_recv (handler_);\n        if (!version)\n            break; //  Terminating\n\n        char *sequence = s_recv (handler_);\n        char *domain = s_recv (handler_);\n        char *address = s_recv (handler_);\n        char *routing_id = s_recv (handler_);\n        char *mechanism = s_recv (handler_);\n\n        TEST_ASSERT_EQUAL_STRING (\"1.0\", version);\n        TEST_ASSERT_EQUAL_STRING (\"NULL\", mechanism);\n\n        send_string_expect_success (handler_, version, ZMQ_SNDMORE);\n        send_string_expect_success (handler_, sequence, ZMQ_SNDMORE);\n        if (streq (domain, \"DOMAIN\")) {\n            send_string_expect_success (handler_, \"200\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"OK\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"anonymous\", ZMQ_SNDMORE);\n            zmq_send (handler_, metadata, sizeof (metadata), 0);\n        } else {\n            send_string_expect_success (handler_, \"400\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"BAD DOMAIN\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"\", 0);\n        }\n        free (version);\n        free (sequence);\n        free (domain);\n        free (address);\n        free (routing_id);\n        free (mechanism);\n    }\n    close_zero_linger (handler_);\n}\n\nvoid test_metadata ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n    setup_test_context ();\n\n    //  Spawn ZAP handler\n    //  We create and bind ZAP socket in main thread to avoid case\n    //  where child thread does not start up fast enough.\n    void *handler = zmq_socket (get_test_context (), ZMQ_REP);\n    TEST_ASSERT_NOT_NULL (handler);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, \"inproc://zeromq.zap.01\"));\n    void *zap_thread = zmq_threadstart (&zap_handler, handler);\n\n    void *server = test_context_socket (ZMQ_DEALER);\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, \"DOMAIN\", 6));\n    bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    send_string_expect_success (client, \"This is a message\", 0);\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, server, 0));\n    TEST_ASSERT_EQUAL_STRING (\"World\", zmq_msg_gets (&msg, \"Hello\"));\n    TEST_ASSERT_EQUAL_STRING (\"DEALER\", zmq_msg_gets (&msg, \"Socket-Type\"));\n    TEST_ASSERT_EQUAL_STRING (\"anonymous\", zmq_msg_gets (&msg, \"User-Id\"));\n    TEST_ASSERT_EQUAL_STRING (\"127.0.0.1\", zmq_msg_gets (&msg, \"Peer-Address\"));\n\n    TEST_ASSERT_NULL (zmq_msg_gets (&msg, \"No Such\"));\n    TEST_ASSERT_EQUAL_INT (EINVAL, zmq_errno ());\n    zmq_msg_close (&msg);\n\n    test_context_socket_close_zero_linger (client);\n    test_context_socket_close_zero_linger (server);\n\n    //  Shutdown\n    teardown_test_context ();\n\n    //  Wait until ZAP handler terminates\n    zmq_threadclose (zap_thread);\n}\n\nvoid test_router_prefetch_metadata ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n    setup_test_context ();\n\n    //  Spawn ZAP handler\n    //  We create and bind ZAP socket in main thread to avoid case\n    //  where child thread does not start up fast enough.\n    void *handler = zmq_socket (get_test_context (), ZMQ_REP);\n    TEST_ASSERT_NOT_NULL (handler);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, \"inproc://zeromq.zap.01\"));\n    void *zap_thread = zmq_threadstart (&zap_handler, handler);\n\n    void *server = test_context_socket (ZMQ_ROUTER);\n    void *client = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, \"DOMAIN\", 6));\n    bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    send_string_expect_success (client, \"This is a message\", 0);\n\n    msleep (SETTLE_TIME);\n\n    // Check for messages in the ROUTER socket which will trigger a prefetch\n    unsigned long int dummy;\n    size_t dummy_size = sizeof (dummy);\n    zmq_getsockopt (server, ZMQ_EVENTS, &dummy, &dummy_size);\n\n    zmq_msg_t msg;\n\n    // Ensure all frames in the message contain metadata\n    for (int i = 0; i < 3; i++) {\n        zmq_msg_init (&msg);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, server, 0));\n        TEST_ASSERT_EQUAL_STRING (\"World\", zmq_msg_gets (&msg, \"Hello\"));\n        zmq_msg_close (&msg);\n    }\n\n    test_context_socket_close_zero_linger (client);\n    test_context_socket_close_zero_linger (server);\n\n    //  Shutdown\n    teardown_test_context ();\n\n    //  Wait until ZAP handler terminates\n    zmq_threadclose (zap_thread);\n}\n\n\nint main ()\n{\n    setup_test_environment ();\n    UNITY_BEGIN ();\n    RUN_TEST (test_metadata);\n    RUN_TEST (test_router_prefetch_metadata);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_mock_pub_sub.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n//  Read one event off the monitor socket; return value and address\n//  by reference, if not null, and event number by value. Returns -1\n//  in case of error.\n\nstatic int get_monitor_event (void *monitor_)\n{\n    for (int i = 0; i < 2; i++) {\n        //  First frame in message contains event number and value\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n        if (zmq_msg_recv (&msg, monitor_, ZMQ_DONTWAIT) == -1) {\n            msleep (SETTLE_TIME);\n            continue; //  Interrupted, presumably\n        }\n        TEST_ASSERT_TRUE (zmq_msg_more (&msg));\n\n        uint8_t *data = static_cast<uint8_t *> (zmq_msg_data (&msg));\n        uint16_t event = *reinterpret_cast<uint16_t *> (data);\n\n        //  Second frame in message contains event address\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n        if (zmq_msg_recv (&msg, monitor_, 0) == -1) {\n            return -1; //  Interrupted, presumably\n        }\n        TEST_ASSERT_FALSE (zmq_msg_more (&msg));\n\n        return event;\n    }\n    return -1;\n}\n\nstatic void recv_with_retry (fd_t fd_, char *buffer_, int bytes_)\n{\n    int received = 0;\n    while (true) {\n        int rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (\n          recv (fd_, buffer_ + received, bytes_ - received, 0));\n        TEST_ASSERT_GREATER_THAN_INT (0, rc);\n        received += rc;\n        TEST_ASSERT_LESS_OR_EQUAL_INT (bytes_, received);\n        if (received == bytes_)\n            break;\n    }\n}\n\nstatic void mock_handshake (fd_t fd_, bool sub_command, bool mock_pub)\n{\n    char buffer[128];\n    memset (buffer, 0, sizeof (buffer));\n    memcpy (buffer, zmtp_greeting_null, sizeof (zmtp_greeting_null));\n\n    //  Mock ZMTP 3.1 which uses commands\n    if (sub_command) {\n        buffer[11] = 1;\n    }\n    int rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (fd_, buffer, 64, 0));\n    TEST_ASSERT_EQUAL_INT (64, rc);\n\n    recv_with_retry (fd_, buffer, 64);\n\n    if (!mock_pub) {\n        rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (\n          fd_, (const char *) zmtp_ready_sub, sizeof (zmtp_ready_sub), 0));\n        TEST_ASSERT_EQUAL_INT (sizeof (zmtp_ready_sub), rc);\n    } else {\n        rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (\n          fd_, (const char *) zmtp_ready_xpub, sizeof (zmtp_ready_xpub), 0));\n        TEST_ASSERT_EQUAL_INT (sizeof (zmtp_ready_xpub), rc);\n    }\n\n    //  greeting - XPUB has one extra byte\n    memset (buffer, 0, sizeof (buffer));\n    recv_with_retry (fd_, buffer,\n                     mock_pub ? sizeof (zmtp_ready_sub)\n                              : sizeof (zmtp_ready_xpub));\n}\n\nstatic void prep_server_socket (void **server_out_,\n                                void **mon_out_,\n                                char *endpoint_,\n                                size_t ep_length_,\n                                int socket_type)\n{\n    //  We'll be using this socket in raw mode\n    void *server = test_context_socket (socket_type);\n\n    int value = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_LINGER, &value, sizeof (value)));\n\n    bind_loopback_ipv4 (server, endpoint_, ep_length_);\n\n    //  Create and connect a socket for collecting monitor events on xpub\n    void *server_mon = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (\n      server, \"inproc://monitor-dealer\",\n      ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_ACCEPTED));\n\n    //  Connect to the inproc endpoint so we'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (server_mon, \"inproc://monitor-dealer\"));\n\n    *server_out_ = server;\n    *mon_out_ = server_mon;\n}\n\nstatic void test_mock_pub_sub (bool sub_command_, bool mock_pub_)\n{\n    int rc;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *server, *server_mon;\n    prep_server_socket (&server, &server_mon, my_endpoint, MAX_SOCKET_STRING,\n                        mock_pub_ ? ZMQ_SUB : ZMQ_XPUB);\n\n    fd_t s = connect_socket (my_endpoint);\n\n    // Mock a ZMTP 3 client so we can forcibly try sub commands\n    mock_handshake (s, sub_command_, mock_pub_);\n\n    // By now everything should report as connected\n    rc = get_monitor_event (server_mon);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_ACCEPTED, rc);\n\n    char buffer[32];\n    memset (buffer, 0, sizeof (buffer));\n\n    if (mock_pub_) {\n        rc = zmq_setsockopt (server, ZMQ_SUBSCRIBE, \"A\", 1);\n        TEST_ASSERT_EQUAL_INT (0, rc);\n        //  SUB binds, let its state machine run\n        //  Because zeromq attach the pipe after the handshake, we need more time here before we can run the state-machine\n        msleep (10);\n        zmq_recv (server, buffer, 16, ZMQ_DONTWAIT);\n\n        if (sub_command_) {\n            recv_with_retry (s, buffer, 13);\n            TEST_ASSERT_EQUAL_INT (0,\n                                   memcmp (buffer, \"\\4\\xb\\x9SUBSCRIBEA\", 13));\n        } else {\n            recv_with_retry (s, buffer, 4);\n            TEST_ASSERT_EQUAL_INT (0, memcmp (buffer, \"\\0\\2\\1A\", 4));\n        }\n\n        memcpy (buffer, \"\\0\\4ALOL\", 6);\n        rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (s, buffer, 6, 0));\n        TEST_ASSERT_EQUAL_INT (6, rc);\n\n        memset (buffer, 0, sizeof (buffer));\n        rc = zmq_recv (server, buffer, 4, 0);\n        TEST_ASSERT_EQUAL_INT (4, rc);\n        TEST_ASSERT_EQUAL_INT (0, memcmp (buffer, \"ALOL\", 4));\n    } else {\n        if (sub_command_) {\n            const uint8_t sub[13] = {4,   11,  9,   'S', 'U', 'B', 'S',\n                                     'C', 'R', 'I', 'B', 'E', 'A'};\n            rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (\n              send (s, (const char *) sub, 13, 0));\n            TEST_ASSERT_EQUAL_INT (13, rc);\n        } else {\n            const uint8_t sub[4] = {0, 2, 1, 'A'};\n            rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (\n              send (s, (const char *) sub, 4, 0));\n            TEST_ASSERT_EQUAL_INT (4, rc);\n        }\n        rc = zmq_recv (server, buffer, 2, 0);\n        TEST_ASSERT_EQUAL_INT (2, rc);\n        TEST_ASSERT_EQUAL_INT (0, memcmp (buffer, \"\\1A\", 2));\n\n        rc = zmq_send (server, \"ALOL\", 4, 0);\n        TEST_ASSERT_EQUAL_INT (4, rc);\n\n        memset (buffer, 0, sizeof (buffer));\n        recv_with_retry (s, buffer, 6);\n        TEST_ASSERT_EQUAL_INT (0, memcmp (buffer, \"\\0\\4ALOL\", 6));\n    }\n\n    close (s);\n\n    test_context_socket_close (server);\n    test_context_socket_close (server_mon);\n}\n\nvoid test_mock_sub_command ()\n{\n    test_mock_pub_sub (true, false);\n}\n\nvoid test_mock_sub_legacy ()\n{\n    test_mock_pub_sub (false, false);\n}\n\nvoid test_mock_pub_command ()\n{\n    test_mock_pub_sub (true, true);\n}\n\nvoid test_mock_pub_legacy ()\n{\n    test_mock_pub_sub (false, true);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n\n    RUN_TEST (test_mock_sub_command);\n    RUN_TEST (test_mock_sub_legacy);\n    RUN_TEST (test_mock_pub_command);\n    RUN_TEST (test_mock_pub_legacy);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_monitor.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_monitoring.hpp\"\n\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_monitor_invalid_protocol_fails ()\n{\n    void *client = test_context_socket (ZMQ_DEALER);\n\n    //  Socket monitoring only works over inproc://\n    TEST_ASSERT_FAILURE_ERRNO (\n      EPROTONOSUPPORT, zmq_socket_monitor (client, \"tcp://127.0.0.1:*\", 0));\n\n#ifdef ZMQ_EVENT_PIPES_STATS\n    //  Stats command needs to be called on a valid socket with monitoring\n    //  enabled\n    TEST_ASSERT_FAILURE_ERRNO (ENOTSOCK, zmq_socket_monitor_pipes_stats (NULL));\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_socket_monitor_pipes_stats (client));\n#endif\n\n    test_context_socket_close_zero_linger (client);\n}\n\nvoid test_monitor_basic ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  We'll monitor these two sockets\n    void *client = test_context_socket (ZMQ_DEALER);\n    void *server = test_context_socket (ZMQ_DEALER);\n\n    //  Monitor all events on client and server sockets\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_socket_monitor (client, \"inproc://monitor-client\", ZMQ_EVENT_ALL));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_socket_monitor (server, \"inproc://monitor-server\", ZMQ_EVENT_ALL));\n\n    //  Create two sockets for collecting monitor events\n    void *client_mon = test_context_socket (ZMQ_PAIR);\n    void *server_mon = test_context_socket (ZMQ_PAIR);\n\n    //  Connect these to the inproc endpoints so they'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (client_mon, \"inproc://monitor-client\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (server_mon, \"inproc://monitor-server\"));\n\n    //  Now do a basic ping test\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    bounce (server, client);\n\n    //  Close client and server\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (client);\n    test_context_socket_close_zero_linger (server);\n\n    //  Now collect and check events from both sockets\n    int event = get_monitor_event (client_mon, NULL, NULL);\n    if (event == ZMQ_EVENT_CONNECT_DELAYED)\n        event = get_monitor_event (client_mon, NULL, NULL);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_CONNECTED, event);\n    expect_monitor_event (client_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n    event = get_monitor_event (client_mon, NULL, NULL);\n    if (event == ZMQ_EVENT_DISCONNECTED) {\n        expect_monitor_event (client_mon, ZMQ_EVENT_CONNECT_RETRIED);\n        expect_monitor_event (client_mon, ZMQ_EVENT_MONITOR_STOPPED);\n    } else\n        TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_MONITOR_STOPPED, event);\n\n    //  This is the flow of server events\n    expect_monitor_event (server_mon, ZMQ_EVENT_LISTENING);\n    expect_monitor_event (server_mon, ZMQ_EVENT_ACCEPTED);\n    expect_monitor_event (server_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n    event = get_monitor_event (server_mon, NULL, NULL);\n    //  Sometimes the server sees the client closing before it gets closed.\n    if (event != ZMQ_EVENT_DISCONNECTED) {\n        TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_CLOSED, event);\n        event = get_monitor_event (server_mon, NULL, NULL);\n    }\n    if (event != ZMQ_EVENT_DISCONNECTED) {\n        TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_MONITOR_STOPPED, event);\n    }\n    //  TODO: When not waiting until the monitor stopped, the I/O thread runs\n    //  into some deadlock. This must be fixed, but until it is fixed, we wait\n    //  here in order to have more reliable test execution.\n    while (event != ZMQ_EVENT_MONITOR_STOPPED) {\n        event = get_monitor_event (server_mon, NULL, NULL);\n    }\n\n    //  Close down the sockets\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (client_mon);\n    test_context_socket_close_zero_linger (server_mon);\n}\n\n#if (defined ZMQ_CURRENT_EVENT_VERSION && ZMQ_CURRENT_EVENT_VERSION >= 2)      \\\n  || (defined ZMQ_CURRENT_EVENT_VERSION                                        \\\n      && ZMQ_CURRENT_EVENT_VERSION_DRAFT >= 2)\nvoid test_monitor_versioned_invalid_socket_type ()\n{\n    void *client = test_context_socket (ZMQ_DEALER);\n\n    //  Socket monitoring only works with ZMQ_PAIR, ZMQ_PUB and ZMQ_PUSH.\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_socket_monitor_versioned (\n                client, \"inproc://invalid-socket-type\", 0, 2, ZMQ_CLIENT));\n\n    test_context_socket_close_zero_linger (client);\n}\n\nvoid test_monitor_versioned_basic (bind_function_t bind_function_,\n                                   const char *expected_prefix_,\n                                   int type_)\n{\n    char server_endpoint[MAX_SOCKET_STRING];\n    char client_mon_endpoint[MAX_SOCKET_STRING];\n    char server_mon_endpoint[MAX_SOCKET_STRING];\n\n    //  Create a unique endpoint for each call so we don't have\n    //  to wait for the sockets to unbind.\n    snprintf (client_mon_endpoint, MAX_SOCKET_STRING, \"inproc://client%s%d\",\n              expected_prefix_, type_);\n    snprintf (server_mon_endpoint, MAX_SOCKET_STRING, \"inproc://server%s%d\",\n              expected_prefix_, type_);\n\n    //  We'll monitor these two sockets\n    void *client = test_context_socket (ZMQ_DEALER);\n    void *server = test_context_socket (ZMQ_DEALER);\n\n    //  Monitor all events on client and server sockets\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor_versioned (\n      client, client_mon_endpoint, ZMQ_EVENT_ALL_V2, 2, type_));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor_versioned (\n      server, server_mon_endpoint, ZMQ_EVENT_ALL_V2, 2, type_));\n\n    //  Choose the appropriate consumer socket type.\n    int mon_type = ZMQ_PAIR;\n    switch (type_) {\n        case ZMQ_PAIR:\n            mon_type = ZMQ_PAIR;\n            break;\n        case ZMQ_PUSH:\n            mon_type = ZMQ_PULL;\n            break;\n        case ZMQ_PUB:\n            mon_type = ZMQ_SUB;\n            break;\n    }\n\n    //  Create two sockets for collecting monitor events\n    void *client_mon = test_context_socket (mon_type);\n    void *server_mon = test_context_socket (mon_type);\n\n    //  Additionally subscribe to all events if a PUB socket is used.\n    if (type_ == ZMQ_PUB) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (client_mon, ZMQ_SUBSCRIBE, \"\", 0));\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (server_mon, ZMQ_SUBSCRIBE, \"\", 0));\n    }\n\n    //  Connect these to the inproc endpoints so they'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_mon, client_mon_endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (server_mon, server_mon_endpoint));\n\n    //  Now do a basic ping test\n    bind_function_ (server, server_endpoint, sizeof server_endpoint);\n\n    int ipv6;\n    size_t ipv6_size = sizeof (ipv6);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (server, ZMQ_IPV6, &ipv6, &ipv6_size));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_IPV6, &ipv6, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, server_endpoint));\n    bounce (server, client);\n\n    //  Close client and server\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (client);\n    test_context_socket_close_zero_linger (server);\n\n    char *client_local_address = NULL;\n    char *client_remote_address = NULL;\n\n    //  Now collect and check events from both sockets\n    int64_t event = get_monitor_event_v2 (\n      client_mon, NULL, &client_local_address, &client_remote_address);\n    if (event == ZMQ_EVENT_CONNECT_DELAYED) {\n        free (client_local_address);\n        free (client_remote_address);\n        event = get_monitor_event_v2 (client_mon, NULL, &client_local_address,\n                                      &client_remote_address);\n    }\n    TEST_ASSERT_EQUAL (ZMQ_EVENT_CONNECTED, event);\n    TEST_ASSERT_EQUAL_STRING (server_endpoint, client_remote_address);\n    TEST_ASSERT_EQUAL_STRING_LEN (expected_prefix_, client_local_address,\n                                  strlen (expected_prefix_));\n    TEST_ASSERT_NOT_EQUAL (\n      0, strcmp (client_local_address, client_remote_address));\n\n    expect_monitor_event_v2 (client_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED,\n                             client_local_address, client_remote_address);\n    event = get_monitor_event_v2 (client_mon, NULL, NULL, NULL);\n    if (event == ZMQ_EVENT_DISCONNECTED) {\n        expect_monitor_event_v2 (client_mon, ZMQ_EVENT_CONNECT_RETRIED,\n                                 client_local_address, client_remote_address);\n        expect_monitor_event_v2 (client_mon, ZMQ_EVENT_MONITOR_STOPPED, \"\", \"\");\n    } else\n        TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_MONITOR_STOPPED, event);\n\n    //  This is the flow of server events\n    expect_monitor_event_v2 (server_mon, ZMQ_EVENT_LISTENING,\n                             client_remote_address, \"\");\n    expect_monitor_event_v2 (server_mon, ZMQ_EVENT_ACCEPTED,\n                             client_remote_address, client_local_address);\n    expect_monitor_event_v2 (server_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED,\n                             client_remote_address, client_local_address);\n    event = get_monitor_event_v2 (server_mon, NULL, NULL, NULL);\n    //  Sometimes the server sees the client closing before it gets closed.\n    if (event != ZMQ_EVENT_DISCONNECTED) {\n        TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_CLOSED, event);\n        event = get_monitor_event_v2 (server_mon, NULL, NULL, NULL);\n    }\n    if (event != ZMQ_EVENT_DISCONNECTED) {\n        TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_MONITOR_STOPPED, event);\n    }\n    //  TODO: When not waiting until the monitor stopped, the I/O thread runs\n    //  into some deadlock. This must be fixed, but until it is fixed, we wait\n    //  here in order to have more reliable test execution.\n    while (event != ZMQ_EVENT_MONITOR_STOPPED) {\n        event = get_monitor_event_v2 (server_mon, NULL, NULL, NULL);\n    }\n    free (client_local_address);\n    free (client_remote_address);\n\n    //  Close down the sockets\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (client_mon);\n    test_context_socket_close_zero_linger (server_mon);\n}\n\nvoid test_monitor_versioned_basic_tcp_ipv4 ()\n{\n    static const char prefix[] = \"tcp://127.0.0.1:\";\n    test_monitor_versioned_basic (bind_loopback_ipv4, prefix, ZMQ_PAIR);\n    test_monitor_versioned_basic (bind_loopback_ipv4, prefix, ZMQ_PUB);\n    test_monitor_versioned_basic (bind_loopback_ipv4, prefix, ZMQ_PUSH);\n}\n\nvoid test_monitor_versioned_basic_tcp_ipv6 ()\n{\n    static const char prefix[] = \"tcp://[::1]:\";\n    test_monitor_versioned_basic (bind_loopback_ipv6, prefix, ZMQ_PAIR);\n    test_monitor_versioned_basic (bind_loopback_ipv6, prefix, ZMQ_PUB);\n    test_monitor_versioned_basic (bind_loopback_ipv6, prefix, ZMQ_PUSH);\n}\n\nvoid test_monitor_versioned_basic_ipc ()\n{\n    static const char prefix[] = \"ipc://\";\n    test_monitor_versioned_basic (bind_loopback_ipc, prefix, ZMQ_PAIR);\n    test_monitor_versioned_basic (bind_loopback_ipc, prefix, ZMQ_PUB);\n    test_monitor_versioned_basic (bind_loopback_ipc, prefix, ZMQ_PUSH);\n}\n\nvoid test_monitor_versioned_basic_tipc ()\n{\n    static const char prefix[] = \"tipc://\";\n    test_monitor_versioned_basic (bind_loopback_tipc, prefix, ZMQ_PAIR);\n    test_monitor_versioned_basic (bind_loopback_tipc, prefix, ZMQ_PUB);\n    test_monitor_versioned_basic (bind_loopback_tipc, prefix, ZMQ_PUSH);\n}\n\n#ifdef ZMQ_EVENT_PIPES_STATS\nvoid test_monitor_versioned_stats (bind_function_t bind_function_,\n                                   const char *expected_prefix_)\n{\n    char server_endpoint[MAX_SOCKET_STRING];\n    const int pulls_count = 4;\n    void *pulls[pulls_count];\n\n    //  We'll monitor these two sockets\n    void *push = test_context_socket (ZMQ_PUSH);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor_versioned (\n      push, \"inproc://monitor-push\", ZMQ_EVENT_PIPES_STATS, 2, ZMQ_PAIR));\n\n    //  Should fail if there are no pipes to monitor\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_socket_monitor_pipes_stats (push));\n\n    void *push_mon = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (push_mon, \"inproc://monitor-push\"));\n\n    //  Set lower HWM - queues will be filled so we should see it in the stats\n    int send_hwm = 500;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (push, ZMQ_SNDHWM, &send_hwm, sizeof (send_hwm)));\n    //  Set very low TCP buffers so that messages cannot be stored in-flight\n    const int tcp_buffer_size = 4096;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      push, ZMQ_SNDBUF, &tcp_buffer_size, sizeof (tcp_buffer_size)));\n    bind_function_ (push, server_endpoint, sizeof (server_endpoint));\n\n    int ipv6;\n    size_t ipv6_size = sizeof (ipv6);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (push, ZMQ_IPV6, &ipv6, &ipv6_size));\n    for (int i = 0; i < pulls_count; ++i) {\n        pulls[i] = test_context_socket (ZMQ_PULL);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (pulls[i], ZMQ_IPV6, &ipv6, sizeof (int)));\n        int timeout_ms = 10;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n          pulls[i], ZMQ_RCVTIMEO, &timeout_ms, sizeof (timeout_ms)));\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (pulls[i], ZMQ_RCVHWM, &send_hwm, sizeof (send_hwm)));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n          pulls[i], ZMQ_RCVBUF, &tcp_buffer_size, sizeof (tcp_buffer_size)));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pulls[i], server_endpoint));\n    }\n\n    //  Send until we block\n    int send_count = 0;\n    //  Saturate the TCP buffers too\n    char data[tcp_buffer_size * 2];\n    memset (data, 0, sizeof (data));\n    //  Saturate all pipes - send + receive - on all connections\n    while (send_count < send_hwm * 2 * pulls_count) {\n        TEST_ASSERT_EQUAL_INT (sizeof (data),\n                               zmq_send (push, data, sizeof (data), 0));\n        ++send_count;\n    }\n\n    //  Drain one of the pulls - doesn't matter how many messages, at least one\n    send_count = send_count / 4;\n    do {\n        zmq_recv (pulls[0], data, sizeof (data), 0);\n        --send_count;\n    } while (send_count > 0);\n\n    //  To kick the application thread, do a dummy getsockopt - users here\n    //  should use the monitor and the other sockets in a poll.\n    unsigned long int dummy;\n    size_t dummy_size = sizeof (dummy);\n    msleep (SETTLE_TIME);\n    //  Note that the pipe stats on the sender will not get updated until the\n    //  receiver has processed at least lwm ((hwm + 1) / 2) messages AND until\n    //  the application thread has ran through the mailbox, as the update is\n    //  delivered via a message (send_activate_write)\n    zmq_getsockopt (push, ZMQ_EVENTS, &dummy, &dummy_size);\n\n    //  Ask for stats and check that they match\n    zmq_socket_monitor_pipes_stats (push);\n\n    msleep (SETTLE_TIME);\n    zmq_getsockopt (push, ZMQ_EVENTS, &dummy, &dummy_size);\n\n    for (int i = 0; i < pulls_count; ++i) {\n        char *push_local_address = NULL;\n        char *push_remote_address = NULL;\n        uint64_t *queue_stat = NULL;\n        int64_t event = get_monitor_event_v2 (\n          push_mon, &queue_stat, &push_local_address, &push_remote_address);\n        TEST_ASSERT_EQUAL_STRING (server_endpoint, push_local_address);\n        TEST_ASSERT_EQUAL_STRING_LEN (expected_prefix_, push_remote_address,\n                                      strlen (expected_prefix_));\n        TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_PIPES_STATS, event);\n        TEST_ASSERT_NOT_NULL (queue_stat);\n        TEST_ASSERT_EQUAL_INT (i == 0 ? 0 : send_hwm, queue_stat[0]);\n        TEST_ASSERT_EQUAL_INT (0, queue_stat[1]);\n        free (push_local_address);\n        free (push_remote_address);\n        free (queue_stat);\n    }\n\n    //  Close client and server\n    test_context_socket_close_zero_linger (push_mon);\n    test_context_socket_close_zero_linger (push);\n    for (int i = 0; i < pulls_count; ++i)\n        test_context_socket_close_zero_linger (pulls[i]);\n}\n\nvoid test_monitor_versioned_stats_tcp_ipv4 ()\n{\n    static const char prefix[] = \"tcp://127.0.0.1:\";\n    test_monitor_versioned_stats (bind_loopback_ipv4, prefix);\n}\n\nvoid test_monitor_versioned_stats_tcp_ipv6 ()\n{\n    static const char prefix[] = \"tcp://[::1]:\";\n    test_monitor_versioned_stats (bind_loopback_ipv6, prefix);\n}\n\nvoid test_monitor_versioned_stats_ipc ()\n{\n    static const char prefix[] = \"ipc://\";\n    test_monitor_versioned_stats (bind_loopback_ipc, prefix);\n}\n#endif // ZMQ_EVENT_PIPES_STATS\n#endif\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_monitor_invalid_protocol_fails);\n    RUN_TEST (test_monitor_basic);\n\n#if (defined ZMQ_CURRENT_EVENT_VERSION && ZMQ_CURRENT_EVENT_VERSION >= 2)      \\\n  || (defined ZMQ_CURRENT_EVENT_VERSION                                        \\\n      && ZMQ_CURRENT_EVENT_VERSION_DRAFT >= 2)\n    RUN_TEST (test_monitor_versioned_invalid_socket_type);\n    RUN_TEST (test_monitor_versioned_basic_tcp_ipv4);\n    RUN_TEST (test_monitor_versioned_basic_tcp_ipv6);\n    RUN_TEST (test_monitor_versioned_basic_ipc);\n    RUN_TEST (test_monitor_versioned_basic_tipc);\n#ifdef ZMQ_EVENT_PIPES_STATS\n    RUN_TEST (test_monitor_versioned_stats_tcp_ipv4);\n    RUN_TEST (test_monitor_versioned_stats_tcp_ipv6);\n    RUN_TEST (test_monitor_versioned_stats_ipc);\n#endif\n#endif\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_msg_ffn.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid ffn (void *data_, void *hint_)\n{\n    // Signal that ffn has been called by writing \"freed\" to hint\n    (void) data_; //  Suppress 'unused' warnings at compile time\n    memcpy (hint_, (void *) \"freed\", 5);\n}\n\nvoid test_msg_init_ffn ()\n{\n    //  Create the infrastructure\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *router = test_context_socket (ZMQ_ROUTER);\n    bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);\n\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));\n\n    // Test that creating and closing a message triggers ffn\n    zmq_msg_t msg;\n    char hint[5];\n    char data[255];\n    memset (data, 0, 255);\n    memcpy (data, (void *) \"data\", 4);\n    memcpy (hint, (void *) \"hint\", 4);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_init_data (&msg, (void *) data, 255, ffn, (void *) hint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    msleep (SETTLE_TIME);\n    TEST_ASSERT_EQUAL_STRING_LEN (\"freed\", hint, 5);\n    memcpy (hint, (void *) \"hint\", 4);\n\n    // Making and closing a copy triggers ffn\n    zmq_msg_t msg2;\n    zmq_msg_init (&msg2);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_init_data (&msg, (void *) data, 255, ffn, (void *) hint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_copy (&msg2, &msg));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg2));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    msleep (SETTLE_TIME);\n    TEST_ASSERT_EQUAL_STRING_LEN (\"freed\", hint, 5);\n    memcpy (hint, (void *) \"hint\", 4);\n\n    // Test that sending a message triggers ffn\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_init_data (&msg, (void *) data, 255, ffn, (void *) hint));\n\n    zmq_msg_send (&msg, dealer, 0);\n    char buf[255];\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (router, buf, 255, 0));\n    TEST_ASSERT_EQUAL_INT (255, zmq_recv (router, buf, 255, 0));\n    TEST_ASSERT_EQUAL_STRING_LEN (data, buf, 4);\n\n    msleep (SETTLE_TIME);\n    TEST_ASSERT_EQUAL_STRING_LEN (\"freed\", hint, 5);\n    memcpy (hint, (void *) \"hint\", 4);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    // Sending a copy of a message triggers ffn\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg2));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_init_data (&msg, (void *) data, 255, ffn, (void *) hint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_copy (&msg2, &msg));\n\n    zmq_msg_send (&msg, dealer, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (router, buf, 255, 0));\n    TEST_ASSERT_EQUAL_INT (255, zmq_recv (router, buf, 255, 0));\n    TEST_ASSERT_EQUAL_STRING_LEN (data, buf, 4);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg2));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    msleep (SETTLE_TIME);\n    TEST_ASSERT_EQUAL_STRING_LEN (\"freed\", hint, 5);\n\n    //  Deallocate the infrastructure.\n    test_context_socket_close (router);\n    test_context_socket_close (dealer);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_msg_init_ffn);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_msg_flags.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_more ()\n{\n    //  Create the infrastructure\n    void *sb = test_context_socket (ZMQ_ROUTER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"inproc://a\"));\n\n    void *sc = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, \"inproc://a\"));\n\n    //  Send 2-part message.\n    send_string_expect_success (sc, \"A\", ZMQ_SNDMORE);\n    send_string_expect_success (sc, \"B\", 0);\n\n    //  Routing id comes first.\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0));\n    TEST_ASSERT_EQUAL_INT (1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_more (&msg)));\n\n    //  Then the first part of the message body.\n    TEST_ASSERT_EQUAL_INT (\n      1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0)));\n    TEST_ASSERT_EQUAL_INT (1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_more (&msg)));\n\n    //  And finally, the second part of the message body.\n    TEST_ASSERT_EQUAL_INT (\n      1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0)));\n    TEST_ASSERT_EQUAL_INT (0, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_more (&msg)));\n\n    //  Deallocate the infrastructure.\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_shared_refcounted ()\n{\n    // Test ZMQ_SHARED property (case 1, refcounted messages)\n    zmq_msg_t msg_a;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_init_size (&msg_a, 1024)); // large enough to be a type_lmsg\n\n    // Message is not shared\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_get (&msg_a, ZMQ_SHARED));\n\n    zmq_msg_t msg_b;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg_b));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_copy (&msg_b, &msg_a));\n\n    // Message is now shared\n    TEST_ASSERT_EQUAL_INT (\n      1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_get (&msg_b, ZMQ_SHARED)));\n\n    // cleanup\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg_a));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg_b));\n}\n\nvoid test_shared_const ()\n{\n    zmq_msg_t msg_a;\n    // Test ZMQ_SHARED property (case 2, constant data messages)\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_init_data (&msg_a, (void *) \"TEST\", 5, 0, 0));\n\n    // Message reports as shared\n    TEST_ASSERT_EQUAL_INT (\n      1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_get (&msg_a, ZMQ_SHARED)));\n\n    // cleanup\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg_a));\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_more);\n    RUN_TEST (test_shared_refcounted);\n    RUN_TEST (test_shared_const);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_msg_init.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_msg_init ()\n{\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n    TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&msg));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n}\n\nvoid test_msg_init_size ()\n{\n    const char *data = \"foobar\";\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 6));\n    TEST_ASSERT_EQUAL_INT (6, zmq_msg_size (&msg));\n    memcpy (zmq_msg_data (&msg), data, 6);\n    TEST_ASSERT_EQUAL_STRING_LEN (data, zmq_msg_data (&msg), 6);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    zmq_msg_t msg2;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg2, 0));\n    TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&msg2));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg2));\n}\n\nvoid test_msg_init_buffer ()\n{\n    const char *data = \"foobar\";\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_buffer (&msg, data, 6));\n    TEST_ASSERT_EQUAL_INT (6, zmq_msg_size (&msg));\n    TEST_ASSERT (data != zmq_msg_data (&msg));\n    TEST_ASSERT_EQUAL_STRING_LEN (data, zmq_msg_data (&msg), 6);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    zmq_msg_t msg2;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_buffer (&msg2, NULL, 0));\n    TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&msg2));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg2));\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_msg_init);\n    RUN_TEST (test_msg_init_size);\n    RUN_TEST (test_msg_init_buffer);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_pair_inproc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <unity.h>\n\nvoid *sb;\nvoid *sc;\n\nvoid setUp ()\n{\n    setup_test_context ();\n\n    sb = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"inproc://a\"));\n\n    sc = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, \"inproc://a\"));\n}\n\nvoid tearDown ()\n{\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n\n    teardown_test_context ();\n}\n\nvoid test_roundtrip ()\n{\n    bounce (sb, sc);\n}\n\n// TODO it appears that this has nothing to do with pair or inproc, and belongs somewhere else\nvoid test_zmq_send_const ()\n{\n    TEST_ASSERT_EQUAL_INT (3, TEST_ASSERT_SUCCESS_ERRNO (\n                                zmq_send_const (sb, \"foo\", 3, ZMQ_SNDMORE)));\n    TEST_ASSERT_EQUAL_INT (\n      6, TEST_ASSERT_SUCCESS_ERRNO (zmq_send_const (sb, \"foobar\", 6, 0)));\n\n    recv_string_expect_success (sc, \"foo\", 0);\n    recv_string_expect_success (sc, \"foobar\", 0);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip);\n    RUN_TEST (test_zmq_send_const);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_pair_ipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_roundtrip ()\n{\n    char my_endpoint[256];\n\n    void *sb = test_context_socket (ZMQ_PAIR);\n    bind_loopback_ipc (sb, my_endpoint, sizeof my_endpoint);\n\n    void *sc = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nstatic const char prefix[] = \"ipc://\";\n\nvoid test_endpoint_too_long ()\n{\n    std::string endpoint_too_long;\n    endpoint_too_long.append (prefix);\n    for (size_t i = 0; i < 108; ++i) {\n        endpoint_too_long.append (\"a\");\n    }\n\n    void *sb = test_context_socket (ZMQ_PAIR);\n    // TODO ENAMETOOLONG is not listed in the errors returned by zmq_bind,\n    // should this be EINVAL?\n    TEST_ASSERT_FAILURE_ERRNO (ENAMETOOLONG,\n                               zmq_bind (sb, endpoint_too_long.data ()));\n\n    test_context_socket_close (sb);\n}\n\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip);\n    RUN_TEST (test_endpoint_too_long);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_pair_tcp.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\n#if defined _WIN32\n#include \"../src/windows.hpp\"\n#endif\n\nSETUP_TEARDOWN_TESTCONTEXT\n\ntypedef void (*extra_func_t) (void *socket_);\n\n#ifdef ZMQ_BUILD_DRAFT\nvoid set_sockopt_fastpath (void *socket)\n{\n    int value = 1;\n    int rc =\n      zmq_setsockopt (socket, ZMQ_LOOPBACK_FASTPATH, &value, sizeof value);\n    assert (rc == 0);\n}\n#endif\n\nvoid test_pair_tcp (extra_func_t extra_func_ = NULL)\n{\n    void *sb = test_context_socket (ZMQ_PAIR);\n\n    if (extra_func_)\n        extra_func_ (sb);\n\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (sb, my_endpoint, sizeof my_endpoint);\n\n    void *sc = test_context_socket (ZMQ_PAIR);\n    if (extra_func_)\n        extra_func_ (sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_pair_tcp_regular ()\n{\n    test_pair_tcp ();\n}\n\nvoid test_pair_tcp_connect_by_name ()\n{\n    // all other tcp test cases bind to a loopback wildcard address, then\n    // retrieve the bound endpoint, which is numerical, and use that to\n    // connect. this test cases specifically uses \"localhost\" to connect\n    // to ensure that names are correctly resolved\n    void *sb = test_context_socket (ZMQ_PAIR);\n\n    char bound_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (sb, bound_endpoint, sizeof bound_endpoint);\n\n    // extract the bound port number\n    const char *pos = strrchr (bound_endpoint, ':');\n    TEST_ASSERT_NOT_NULL (pos);\n    const char connect_endpoint_prefix[] = \"tcp://localhost\";\n    char connect_endpoint[MAX_SOCKET_STRING];\n    strcpy (connect_endpoint, connect_endpoint_prefix);\n    strcat (connect_endpoint, pos);\n\n    void *sc = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_endpoint));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\n\n#ifdef ZMQ_BUILD_DRAFT\nvoid test_pair_tcp_fastpath ()\n{\n    test_pair_tcp (set_sockopt_fastpath);\n}\n#endif\n\n#ifdef _WIN32\nvoid test_io_completion_port ()\n{\n    void *const s = test_context_socket (ZMQ_PAIR);\n    SOCKET fd;\n    size_t fd_size = sizeof fd;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (s, ZMQ_FD, &fd, &fd_size));\n\n    ::WSAPROTOCOL_INFO pi;\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (\n      ::WSADuplicateSocket (fd, ::GetCurrentProcessId (), &pi));\n    const SOCKET socket = ::WSASocket (pi.iAddressFamily /*AF_INET*/,\n                                       pi.iSocketType /*SOCK_STREAM*/,\n                                       pi.iProtocol /*IPPROTO_TCP*/, &pi, 0, 0);\n\n    const HANDLE iocp =\n      ::CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, 0, 0);\n    TEST_ASSERT_NOT_EQUAL (NULL, iocp);\n    const HANDLE res =\n      ::CreateIoCompletionPort (reinterpret_cast<HANDLE> (socket), iocp, 0, 0);\n    TEST_ASSERT_NOT_EQUAL (NULL, res);\n\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (closesocket (socket));\n    TEST_ASSERT_TRUE (CloseHandle (iocp));\n\n    test_context_socket_close (s);\n}\n#endif\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_pair_tcp_regular);\n    RUN_TEST (test_pair_tcp_connect_by_name);\n#ifdef ZMQ_BUILD_DRAFT\n    RUN_TEST (test_pair_tcp_fastpath);\n#endif\n#ifdef _WIN32\n    RUN_TEST (test_io_completion_port);\n#endif\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_pair_tcp_cap_net_admin.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\ntypedef void (*extra_func_t) (void *socket_);\n\nvoid set_sockopt_bind_to_device (void *socket)\n{\n    const char device[] = \"lo\";\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket, ZMQ_BINDTODEVICE, &device, sizeof (device) - 1));\n}\n\n//  TODO this is duplicated from test_pair_tcp\nvoid test_pair_tcp (extra_func_t extra_func_ = NULL)\n{\n    void *sb = test_context_socket (ZMQ_PAIR);\n\n    if (extra_func_)\n        extra_func_ (sb);\n\n    char my_endpoint[MAX_SOCKET_STRING];\n    size_t my_endpoint_length = sizeof my_endpoint;\n    int rc = zmq_bind (sb, \"tcp://127.0.0.1:*\");\n    if (rc < 0 && errno == EOPNOTSUPP)\n        TEST_IGNORE_MESSAGE (\"SO_BINDTODEVICE not supported\");\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, my_endpoint, &my_endpoint_length));\n\n    void *sc = test_context_socket (ZMQ_PAIR);\n    if (extra_func_)\n        extra_func_ (sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_pair_tcp_bind_to_device ()\n{\n    test_pair_tcp (set_sockopt_bind_to_device);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_pair_tcp_bind_to_device);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_pair_tipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include <stdio.h>\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_roundtrip ()\n{\n    void *sb = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"tipc://{5560,0,0}\"));\n\n    void *sc = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, \"tipc://{5560,0}@0.0.0\"));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main ()\n{\n    if (!is_tipc_available ()) {\n        printf (\"TIPC environment unavailable, skipping test\\n\");\n        return 77;\n    }\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_pair_vmci.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include <string>\n#include <sstream>\n#include <vmci_sockets.h>\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_pair_vmci ()\n{\n    unsigned int cid = VMCISock_GetLocalCID ();\n    if (cid == VMADDR_CID_ANY)\n        TEST_IGNORE_MESSAGE (\"VMCI environment unavailable, skipping test\");\n    std::stringstream s;\n    s << \"vmci://\" << cid << \":\" << 5560;\n    std::string endpoint = s.str ();\n\n    void *sb = test_context_socket (ZMQ_PAIR);\n    int rc = zmq_bind (sb, endpoint.c_str ());\n    if (rc < 0 && (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT))\n        TEST_IGNORE_MESSAGE (\"VMCI not supported\");\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n\n    void *sc = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint.c_str ()));\n\n    bounce (sb, sc);\n\n    test_context_socket_close_zero_linger (sc);\n    test_context_socket_close_zero_linger (sb);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_pair_vmci);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_pair_vsock.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string>\n#include <sstream>\n#include \"sys/socket.h\"\n#include \"linux/vm_sockets.h\"\n#include <sys/ioctl.h>\n#include <fcntl.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_pair_vsock ()\n{\n    unsigned int cid = VMADDR_CID_ANY;\n    int vsock = -1;\n\n    if ((vsock = open (\"/dev/vsock\", O_RDONLY, 0)) < 0) {\n        TEST_IGNORE_MESSAGE (\"failed to open /dev/vsock, skipping test\");\n    } else if (ioctl (vsock, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &cid) < 0) {\n        TEST_IGNORE_MESSAGE (\"failed to get local cid, skipping test\");\n    }\n\n    if (vsock >= 0) {\n        close (vsock);\n    }\n\n    if (cid == VMADDR_CID_ANY)\n        TEST_IGNORE_MESSAGE (\"vsock environment unavailable, skipping test\");\n\n    std::stringstream s;\n    s << \"vsock://\" << cid << \":\" << 5561;\n    std::string endpoint = s.str ();\n\n    void *sb = test_context_socket (ZMQ_PAIR);\n    int rc = zmq_bind (sb, endpoint.c_str ());\n    if (rc < 0 && (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT))\n        TEST_IGNORE_MESSAGE (\"VSOCK not supported\");\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n\n    void *sc = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint.c_str ()));\n\n    bounce (sb, sc);\n\n    test_context_socket_close_zero_linger (sc);\n    test_context_socket_close_zero_linger (sb);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_pair_vsock);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_peer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_peer ()\n{\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *peer1 = test_context_socket (ZMQ_PEER);\n    bind_loopback (peer1, false, my_endpoint, len);\n\n    void *peer2 = test_context_socket (ZMQ_PEER);\n    uint32_t peer1_routing_id = zmq_connect_peer (peer2, my_endpoint);\n    TEST_ASSERT_NOT_EQUAL (0, peer1_routing_id);\n\n    {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));\n\n        char *data = static_cast<char *> (zmq_msg_data (&msg));\n        data[0] = 1;\n\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_msg_set_routing_id (&msg, peer1_routing_id));\n\n        int rc = zmq_msg_send (&msg, peer2, 0);\n        TEST_ASSERT_EQUAL_INT (1, rc);\n    }\n\n    uint32_t peer2_routing_id;\n    {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n        int rc = TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, peer1, 0));\n        TEST_ASSERT_EQUAL_INT (1, rc);\n\n        peer2_routing_id = zmq_msg_routing_id (&msg);\n        TEST_ASSERT_NOT_EQUAL (0, peer2_routing_id);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n    }\n\n    {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));\n\n        char *data = static_cast<char *> (zmq_msg_data (&msg));\n        data[0] = 2;\n\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_msg_set_routing_id (&msg, peer2_routing_id));\n\n        int rc = zmq_msg_send (&msg, peer1, 0);\n        TEST_ASSERT_EQUAL_INT (1, rc);\n    }\n\n    {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n        int rc = zmq_msg_recv (&msg, peer2, 0);\n        TEST_ASSERT_EQUAL_INT (1, rc);\n\n        uint32_t routing_id = zmq_msg_routing_id (&msg);\n        TEST_ASSERT_EQUAL_UINT32 (peer1_routing_id, routing_id);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n    }\n\n    test_context_socket_close (peer1);\n    test_context_socket_close (peer2);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_peer);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_peer_disconnect.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_peer_disconnect ()\n{\n    size_t len = MAX_SOCKET_STRING;\n    char endpoint[MAX_SOCKET_STRING];\n\n    // Create first peer and bind\n    void *peer1 = test_context_socket (ZMQ_PEER);\n    bind_loopback (peer1, false, endpoint, len);\n\n    // Create second peer and connect atomically to get routing id\n    void *peer2 = test_context_socket (ZMQ_PEER);\n    uint32_t peer1_routing_id = zmq_connect_peer (peer2, endpoint);\n    TEST_ASSERT_NOT_EQUAL (0, peer1_routing_id);\n\n    // Send one byte from peer2 to peer1 with peer1's routing id\n    {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));\n        static_cast<char *> (zmq_msg_data (&msg))[0] = 'X';\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_msg_set_routing_id (&msg, peer1_routing_id));\n        int rc = zmq_msg_send (&msg, peer2, 0);\n        TEST_ASSERT_EQUAL_INT (1, rc);\n    }\n\n    // Receive on peer1; capture peer2's routing id\n    uint32_t peer2_routing_id = 0;\n    {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n        int rc = TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, peer1, 0));\n        TEST_ASSERT_EQUAL_INT (1, rc);\n        peer2_routing_id = zmq_msg_routing_id (&msg);\n        TEST_ASSERT_NOT_EQUAL (0, peer2_routing_id);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n    }\n\n    // Disconnect peer2 by its routing id on peer1\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect_peer (peer1, peer2_routing_id));\n\n    // Attempt to send back to peer2 should fail with EHOSTUNREACH\n    {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 5));\n        memcpy (zmq_msg_data (&msg), \"HELLO\", 5);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_msg_set_routing_id (&msg, peer2_routing_id));\n\n        int rc = zmq_msg_send (&msg, peer1, 0);\n        TEST_ASSERT_EQUAL_INT (-1, rc);\n        TEST_ASSERT_EQUAL_INT (EHOSTUNREACH, errno);\n        // On failure, close the message\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n    }\n\n    test_context_socket_close (peer2);\n    test_context_socket_close (peer1);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_peer_disconnect);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_poller.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <limits.h>\n\n#ifndef _WIN32\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <unistd.h>\n#endif\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nfd_t get_fd (void *socket_)\n{\n    fd_t fd;\n    size_t fd_size = sizeof fd;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (socket_, ZMQ_FD, &fd, &fd_size));\n    return fd;\n}\n\nvoid test_null_poller_pointers_destroy_direct ()\n{\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_destroy (NULL));\n}\n\nvoid test_null_poller_pointers_destroy_indirect ()\n{\n    void *null_poller = NULL;\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_destroy (&null_poller));\n}\n\nvoid test_null_poller_pointers_size_direct ()\n{\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_size (NULL));\n}\n\nvoid test_null_poller_pointers_size_indirect ()\n{\n    void *null_poller = NULL;\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_size (&null_poller));\n}\n\nvoid test_null_poller_pointers_add_direct ()\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_poller_add (NULL, socket, NULL, ZMQ_POLLIN));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_add_indirect ()\n{\n    void *null_poller = NULL;\n    void *socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_FAILURE_ERRNO (\n      EFAULT, zmq_poller_add (&null_poller, socket, NULL, ZMQ_POLLIN));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_modify_direct ()\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_poller_modify (NULL, socket, ZMQ_POLLIN));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_modify_indirect ()\n{\n    void *null_poller = NULL;\n    void *socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_FAILURE_ERRNO (\n      EFAULT, zmq_poller_modify (&null_poller, socket, ZMQ_POLLIN));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_remove_direct ()\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_remove (NULL, socket));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_remove_indirect ()\n{\n    void *null_poller = NULL;\n    void *socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_poller_remove (&null_poller, socket));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_add_fd_direct ()\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n    const fd_t fd = get_fd (socket);\n\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_poller_add_fd (NULL, fd, NULL, ZMQ_POLLIN));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_add_fd_indirect ()\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n    const fd_t fd = get_fd (socket);\n    void *null_poller = NULL;\n    TEST_ASSERT_FAILURE_ERRNO (\n      EFAULT, zmq_poller_add_fd (&null_poller, fd, NULL, ZMQ_POLLIN));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_modify_fd_direct ()\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n    const fd_t fd = get_fd (socket);\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_poller_modify_fd (NULL, fd, ZMQ_POLLIN));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_modify_fd_indirect ()\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n    const fd_t fd = get_fd (socket);\n    void *null_poller = NULL;\n    TEST_ASSERT_FAILURE_ERRNO (\n      EFAULT, zmq_poller_modify_fd (&null_poller, fd, ZMQ_POLLIN));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_remove_fd_direct ()\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n    const fd_t fd = get_fd (socket);\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_remove_fd (NULL, fd));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_remove_fd_indirect ()\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n    const fd_t fd = get_fd (socket);\n    void *null_poller = NULL;\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_remove_fd (&null_poller, fd));\n    test_context_socket_close (socket);\n}\n\nvoid test_null_poller_pointers_wait_direct ()\n{\n    zmq_poller_event_t event;\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_wait (NULL, &event, 0));\n}\n\nvoid test_null_poller_pointers_wait_indirect ()\n{\n    zmq_poller_event_t event;\n    void *null_poller = NULL;\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_poller_wait (&null_poller, &event, 0));\n}\n\nvoid test_null_poller_pointers_wait_all_direct ()\n{\n    zmq_poller_event_t event;\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_poller_wait_all (NULL, &event, 1, 0));\n}\n\nvoid test_null_poller_pointers_wait_all_indirect ()\n{\n    zmq_poller_event_t event;\n    void *null_poller = NULL;\n    TEST_ASSERT_FAILURE_ERRNO (\n      EFAULT, zmq_poller_wait_all (&null_poller, &event, 1, 0));\n}\n\nvoid test_null_poller_pointer_poller_fd ()\n{\n    void *null_poller = NULL;\n    fd_t fd;\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_fd (&null_poller, &fd));\n}\n\nvoid test_null_socket_pointers ()\n{\n    void *poller = zmq_poller_new ();\n    TEST_ASSERT_NOT_NULL (poller);\n\n    TEST_ASSERT_FAILURE_ERRNO (ENOTSOCK,\n                               zmq_poller_add (poller, NULL, NULL, ZMQ_POLLIN));\n\n    TEST_ASSERT_FAILURE_ERRNO (ENOTSOCK,\n                               zmq_poller_modify (poller, NULL, ZMQ_POLLIN));\n\n    TEST_ASSERT_FAILURE_ERRNO (ENOTSOCK, zmq_poller_remove (poller, NULL));\n\n    fd_t null_socket_fd = retired_fd;\n\n    TEST_ASSERT_FAILURE_ERRNO (\n      EBADF, zmq_poller_add_fd (poller, null_socket_fd, NULL, ZMQ_POLLIN));\n\n    TEST_ASSERT_FAILURE_ERRNO (\n      EBADF, zmq_poller_modify_fd (poller, null_socket_fd, ZMQ_POLLIN));\n\n    TEST_ASSERT_FAILURE_ERRNO (EBADF,\n                               zmq_poller_remove_fd (poller, null_socket_fd));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));\n}\n\ntypedef void (*extra_poller_socket_func_t) (void *poller_, void *socket_);\n\nvoid test_with_empty_poller (extra_poller_socket_func_t extra_func_)\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n\n    void *poller = zmq_poller_new ();\n    TEST_ASSERT_NOT_NULL (poller);\n\n    extra_func_ (poller, socket);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));\n\n    test_context_socket_close (socket);\n}\n\ntypedef void (*extra_poller_func_t) (void *poller_);\n\nvoid test_with_valid_poller (extra_poller_func_t extra_func_)\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n\n    void *poller = zmq_poller_new ();\n    TEST_ASSERT_NOT_NULL (poller);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add (poller, socket, NULL, ZMQ_POLLIN));\n\n    extra_func_ (poller);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));\n\n    test_context_socket_close (socket);\n}\n\nvoid test_call_poller_fd_no_signaler ()\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n\n    void *poller = zmq_poller_new ();\n    TEST_ASSERT_NOT_NULL (poller);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add (poller, socket, NULL, ZMQ_POLLIN));\n\n    fd_t fd;\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_poller_fd (poller, &fd));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));\n\n    test_context_socket_close (socket);\n}\n\nvoid test_call_poller_fd ()\n{\n    void *socket = test_context_socket (ZMQ_CLIENT);\n\n    void *poller = zmq_poller_new ();\n    TEST_ASSERT_NOT_NULL (poller);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add (poller, socket, NULL, ZMQ_POLLIN));\n\n    fd_t fd;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_fd (poller, &fd));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));\n\n    test_context_socket_close (socket);\n}\n\nvoid call_poller_wait_null_event_fails (void *poller_)\n{\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_wait (poller_, NULL, 0));\n}\n\nvoid call_poller_wait_all_null_event_fails_event_count_nonzero (void *poller_)\n{\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_poller_wait_all (poller_, NULL, 1, 0));\n}\n\nvoid call_poller_wait_all_null_event_fails_event_count_zero (void *poller_)\n{\n    LIBZMQ_UNUSED (poller_);\n#if 0\n    //  TODO this causes an assertion, which is not consistent if the number\n    //  of events may be 0, the pointer should be allowed to by NULL in that\n    //  case too\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_wait_all (poller, NULL, 0, 0));\n#endif\n}\n\n#define TEST_CASE_FUNC_PARAM(name, func)                                       \\\n    void test_##name ()                                                        \\\n    {                                                                          \\\n        func (name);                                                           \\\n    }\n\nTEST_CASE_FUNC_PARAM (call_poller_wait_null_event_fails, test_with_valid_poller)\nTEST_CASE_FUNC_PARAM (call_poller_wait_all_null_event_fails_event_count_nonzero,\n                      test_with_valid_poller)\nTEST_CASE_FUNC_PARAM (call_poller_wait_all_null_event_fails_event_count_zero,\n                      test_with_valid_poller)\n\nvoid call_poller_size (void *poller_, void *socket_)\n{\n    int rc = zmq_poller_size (poller_);\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n    TEST_ASSERT_EQUAL (rc, 0);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add (poller_, socket_, NULL, ZMQ_POLLIN));\n    rc = zmq_poller_size (poller_);\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n    TEST_ASSERT_EQUAL (rc, 1);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_modify (poller_, socket_, 0));\n    rc = zmq_poller_size (poller_);\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n    TEST_ASSERT_EQUAL (rc, 1);\n\n    fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add_fd (poller_, plain_socket, NULL, ZMQ_POLLOUT));\n    rc = zmq_poller_size (poller_);\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n    TEST_ASSERT_EQUAL (rc, 2);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove (poller_, socket_));\n    rc = zmq_poller_size (poller_);\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n    TEST_ASSERT_EQUAL (rc, 1);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove_fd (poller_, plain_socket));\n    TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));\n    rc = zmq_poller_size (poller_);\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n    TEST_ASSERT_EQUAL (rc, 0);\n}\n\nvoid call_poller_add_twice_fails (void *poller_, void *socket_)\n{\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add (poller_, socket_, NULL, ZMQ_POLLIN));\n\n    //  attempt to add the same socket twice\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_poller_add (poller_, socket_, NULL, ZMQ_POLLIN));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove (poller_, socket_));\n}\n\nvoid call_poller_remove_unregistered_fails (void *poller_, void *socket_)\n{\n    //  attempt to remove socket that is not present\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_poller_remove (poller_, socket_));\n}\n\nvoid call_poller_modify_unregistered_fails (void *poller_, void *socket_)\n{\n    //  attempt to modify socket that is not present\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_poller_modify (poller_, socket_, ZMQ_POLLIN));\n}\n\nvoid call_poller_add_no_events (void *poller_, void *socket_)\n{\n    //  add a socket with no events initially (may be activated later with\n    //  zmq_poller_modify)\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_add (poller_, socket_, NULL, 0));\n    //  TODO test that no events are signalled\n}\n\nvoid call_poller_modify_no_events (void *poller_, void *socket_)\n{\n    //  deactivates all events for a socket temporarily (may be activated again\n    //  later with zmq_poller_modify)\n    zmq_poller_add (poller_, socket_, NULL, ZMQ_POLLIN);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_modify (poller_, socket_, 0));\n    //  TODO test that no events are signalled\n}\n\nvoid call_poller_add_fd_twice_fails (void *poller_, void * /*zeromq_socket*/)\n{\n    fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add_fd (poller_, plain_socket, NULL, ZMQ_POLLIN));\n\n    //  attempt to add the same plain socket twice\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_poller_add_fd (poller_, plain_socket, NULL, ZMQ_POLLIN));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove_fd (poller_, plain_socket));\n\n    TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));\n}\n\nvoid call_poller_remove_fd_unregistered_fails (void *poller_,\n                                               void * /*zeromq_socket*/)\n{\n    fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\n\n    //  attempt to remove plain socket that is not present\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL,\n                               zmq_poller_remove_fd (poller_, plain_socket));\n\n    TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));\n}\n\nvoid call_poller_modify_fd_unregistered_fails (void *poller_,\n                                               void * /*zeromq_socket*/)\n{\n    fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\n\n    //  attempt to remove plain socket that is not present\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_poller_modify_fd (poller_, plain_socket, ZMQ_POLLIN));\n\n    TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));\n}\n\nvoid call_poller_add_invalid_events_fails (void *poller_, void *zeromq_socket_)\n{\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_poller_add (poller_, zeromq_socket_, NULL, SHRT_MAX));\n}\n\nvoid call_poller_modify_invalid_events_fails (void *poller_,\n                                              void *zeromq_socket_)\n{\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add (poller_, zeromq_socket_, NULL, 0));\n\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_poller_modify (poller_, zeromq_socket_, SHRT_MAX));\n}\n\nvoid call_poller_add_fd_invalid_events_fails (void *poller_,\n                                              void * /*zeromq_socket*/)\n{\n    fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_poller_add_fd (poller_, plain_socket, NULL, SHRT_MAX));\n\n    TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));\n}\n\nvoid call_poller_modify_fd_invalid_events_fails (void *poller_,\n                                                 void * /*zeromq_socket*/)\n{\n    fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add_fd (poller_, plain_socket, NULL, 0));\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_poller_modify_fd (poller_, plain_socket, SHRT_MAX));\n\n    TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));\n}\n\nTEST_CASE_FUNC_PARAM (call_poller_size, test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_add_twice_fails, test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_remove_unregistered_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_modify_unregistered_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_add_no_events, test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_modify_no_events, test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_add_fd_twice_fails, test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_remove_fd_unregistered_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_modify_fd_unregistered_fails,\n                      test_with_empty_poller)\n\nTEST_CASE_FUNC_PARAM (call_poller_add_invalid_events_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_modify_invalid_events_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_add_fd_invalid_events_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_modify_fd_invalid_events_fails,\n                      test_with_empty_poller)\n\nvoid call_poller_wait_empty_with_timeout_fails (void *poller_,\n                                                void * /*socket*/)\n{\n    zmq_poller_event_t event;\n    // waiting on poller with no registered sockets should report error\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_poller_wait (poller_, &event, 0));\n}\n\nvoid call_poller_wait_empty_without_timeout_fails (void *poller_,\n                                                   void * /*socket*/)\n{\n    zmq_poller_event_t event;\n    //  this would never be able to return since no socket was registered, and should yield an error\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_wait (poller_, &event, -1));\n}\n\nvoid call_poller_wait_all_empty_negative_count_fails (void *poller_,\n                                                      void * /*socket*/)\n{\n    zmq_poller_event_t event;\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL,\n                               zmq_poller_wait_all (poller_, &event, -1, 0));\n}\n\nvoid call_poller_wait_all_empty_without_timeout_fails (void *poller_,\n                                                       void * /*socket*/)\n{\n    zmq_poller_event_t event;\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN,\n                               zmq_poller_wait_all (poller_, &event, 0, 0));\n}\n\nvoid call_poller_wait_all_empty_with_timeout_fails (void *poller_,\n                                                    void * /*socket*/)\n{\n    zmq_poller_event_t event;\n    //  this would never be able to return since no socket was registered, and should yield an error\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_poller_wait_all (poller_, &event, 0, -1));\n}\n\nvoid call_poller_wait_all_inf_disabled_fails (void *poller_, void *socket_)\n{\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_add (poller_, socket_, NULL, 0));\n\n    zmq_poller_event_t events[1];\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN,\n                               zmq_poller_wait_all (poller_, events, 1, 0));\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_poller_wait_all (poller_, events, 1, -1));\n}\n\nTEST_CASE_FUNC_PARAM (call_poller_wait_empty_with_timeout_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_wait_empty_without_timeout_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_wait_all_empty_negative_count_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_wait_all_empty_without_timeout_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_wait_all_empty_with_timeout_fails,\n                      test_with_empty_poller)\nTEST_CASE_FUNC_PARAM (call_poller_wait_all_inf_disabled_fails,\n                      test_with_empty_poller)\n\nvoid test_poll_basic ()\n{\n    //  Create few sockets\n    void *vent = test_context_socket (ZMQ_PUSH);\n\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (vent, my_endpoint, len);\n\n    void *sink = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sink, my_endpoint));\n\n    //  Set up poller\n    void *poller = zmq_poller_new ();\n\n    // register sink\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_add (poller, sink, sink, ZMQ_POLLIN));\n\n    //  Send a message\n    const char *vent_sink_msg = \"H\";\n    send_string_expect_success (vent, vent_sink_msg, 0);\n\n    //  We expect a message only on the sink\n    zmq_poller_event_t event;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_wait (poller, &event, -1));\n    TEST_ASSERT_EQUAL_PTR (sink, event.socket);\n    TEST_ASSERT_EQUAL_PTR (sink, event.user_data);\n    recv_string_expect_success (sink, vent_sink_msg, 0);\n\n    //  We expect timed out\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_poller_wait (poller, &event, 0));\n\n    //  Stop polling sink\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove (poller, sink));\n\n    //  Clean up\n    test_context_socket_close (vent);\n    test_context_socket_close (sink);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));\n}\n\nvoid test_poll_fd ()\n{\n    //  Create sockets\n    void *vent = test_context_socket (ZMQ_PUSH);\n\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (vent, my_endpoint, len);\n\n    void *bowl = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (bowl, my_endpoint));\n\n    //  Set up poller\n    void *poller = zmq_poller_new ();\n\n    //  Check we can poll an FD\n    const fd_t fd = get_fd (bowl);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add_fd (poller, fd, bowl, ZMQ_POLLIN));\n\n    zmq_poller_event_t event;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_wait (poller, &event, 500));\n    TEST_ASSERT_NULL (event.socket);\n    TEST_ASSERT_EQUAL (fd, event.fd);\n    TEST_ASSERT_EQUAL_PTR (bowl, event.user_data);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove_fd (poller, fd));\n\n    //  Clean up\n    test_context_socket_close (vent);\n    test_context_socket_close (bowl);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));\n}\n\nvoid test_poll_client_server ()\n{\n#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)\n    //  Create sockets\n    void *server = test_context_socket (ZMQ_SERVER);\n\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (server, my_endpoint, len);\n\n    void *client = test_context_socket (ZMQ_CLIENT);\n\n    //  Set up poller\n    void *poller = zmq_poller_new ();\n\n    //  Polling on thread safe sockets\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add (poller, server, NULL, ZMQ_POLLIN));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    const char *client_server_msg = \"I\";\n    send_string_expect_success (client, client_server_msg, 0);\n\n    zmq_poller_event_t event;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_wait (poller, &event, 500));\n    TEST_ASSERT_EQUAL_PTR (server, event.socket);\n    TEST_ASSERT_NULL (event.user_data);\n#ifndef _WIN32\n    TEST_ASSERT (event.fd == -1);\n#endif\n    recv_string_expect_success (server, client_server_msg, 0);\n\n    //  Polling on pollout\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_modify (poller, server, ZMQ_POLLOUT | ZMQ_POLLIN));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_wait (poller, &event, 0));\n    TEST_ASSERT_EQUAL_PTR (server, event.socket);\n    TEST_ASSERT_NULL (event.user_data);\n#ifndef _WIN32\n    TEST_ASSERT (event.fd == -1);\n#endif\n    TEST_ASSERT_EQUAL_INT (ZMQ_POLLOUT, event.events);\n\n    //  Stop polling server\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove (poller, server));\n\n    //  Clean up\n    test_context_socket_close (server);\n    test_context_socket_close (client);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));\n#endif\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_null_poller_pointers_destroy_direct);\n    RUN_TEST (test_null_poller_pointers_destroy_indirect);\n    RUN_TEST (test_null_poller_pointers_size_direct);\n    RUN_TEST (test_null_poller_pointers_size_indirect);\n    RUN_TEST (test_null_poller_pointers_add_direct);\n    RUN_TEST (test_null_poller_pointers_add_indirect);\n    RUN_TEST (test_null_poller_pointers_modify_direct);\n    RUN_TEST (test_null_poller_pointers_modify_indirect);\n    RUN_TEST (test_null_poller_pointers_remove_direct);\n    RUN_TEST (test_null_poller_pointers_remove_indirect);\n    RUN_TEST (test_null_poller_pointers_add_fd_direct);\n    RUN_TEST (test_null_poller_pointers_add_fd_indirect);\n    RUN_TEST (test_null_poller_pointers_modify_fd_direct);\n    RUN_TEST (test_null_poller_pointers_modify_fd_indirect);\n    RUN_TEST (test_null_poller_pointers_remove_fd_direct);\n    RUN_TEST (test_null_poller_pointers_remove_fd_indirect);\n    RUN_TEST (test_null_poller_pointers_wait_direct);\n    RUN_TEST (test_null_poller_pointers_wait_indirect);\n    RUN_TEST (test_null_poller_pointers_wait_all_direct);\n    RUN_TEST (test_null_poller_pointers_wait_all_indirect);\n    RUN_TEST (test_null_poller_pointer_poller_fd);\n\n    RUN_TEST (test_null_socket_pointers);\n\n    RUN_TEST (test_call_poller_wait_null_event_fails);\n    RUN_TEST (test_call_poller_wait_all_null_event_fails_event_count_nonzero);\n    RUN_TEST (test_call_poller_wait_all_null_event_fails_event_count_zero);\n\n    RUN_TEST (test_call_poller_size);\n    RUN_TEST (test_call_poller_add_twice_fails);\n    RUN_TEST (test_call_poller_remove_unregistered_fails);\n    RUN_TEST (test_call_poller_modify_unregistered_fails);\n    RUN_TEST (test_call_poller_add_no_events);\n    RUN_TEST (test_call_poller_modify_no_events);\n    RUN_TEST (test_call_poller_add_fd_twice_fails);\n    RUN_TEST (test_call_poller_remove_fd_unregistered_fails);\n    RUN_TEST (test_call_poller_modify_fd_unregistered_fails);\n    RUN_TEST (test_call_poller_add_invalid_events_fails);\n    RUN_TEST (test_call_poller_modify_invalid_events_fails);\n    RUN_TEST (test_call_poller_add_fd_invalid_events_fails);\n    RUN_TEST (test_call_poller_modify_fd_invalid_events_fails);\n\n    RUN_TEST (test_call_poller_wait_empty_with_timeout_fails);\n    RUN_TEST (test_call_poller_wait_empty_without_timeout_fails);\n    RUN_TEST (test_call_poller_wait_all_empty_negative_count_fails);\n    RUN_TEST (test_call_poller_wait_all_empty_without_timeout_fails);\n    RUN_TEST (test_call_poller_wait_all_empty_with_timeout_fails);\n    RUN_TEST (test_call_poller_wait_all_inf_disabled_fails);\n\n    RUN_TEST (test_call_poller_fd_no_signaler);\n    RUN_TEST (test_call_poller_fd);\n\n    RUN_TEST (test_poll_basic);\n    RUN_TEST (test_poll_fd);\n    RUN_TEST (test_poll_client_server);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_probe_router.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_probe_router_router ()\n{\n    //  Create server and bind to endpoint\n    void *server = test_context_socket (ZMQ_ROUTER);\n\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));\n\n    //  Create client and connect to server, doing a probe\n    void *client = test_context_socket (ZMQ_ROUTER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_ROUTING_ID, \"X\", 1));\n    int probe = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PROBE_ROUTER, &probe, sizeof (probe)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    //  We expect a routing id=X + empty message from client\n    recv_string_expect_success (server, \"X\", 0);\n    unsigned char buffer[255];\n    TEST_ASSERT_EQUAL_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, buffer, 255, 0)));\n\n    //  Send a message to client now\n    send_string_expect_success (server, \"X\", ZMQ_SNDMORE);\n    send_string_expect_success (server, \"Hello\", 0);\n\n    // receive the routing ID, which is auto-generated in this case, since the\n    // peer did not set one explicitly\n    TEST_ASSERT_EQUAL_INT (\n      5, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (client, buffer, 255, 0)));\n\n    recv_string_expect_success (client, \"Hello\", 0);\n\n    test_context_socket_close (server);\n    test_context_socket_close (client);\n}\n\nvoid test_probe_router_dealer ()\n{\n    //  Create server and bind to endpoint\n    void *server = test_context_socket (ZMQ_ROUTER);\n\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));\n\n    //  Create client and connect to server, doing a probe\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_ROUTING_ID, \"X\", 1));\n    int probe = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PROBE_ROUTER, &probe, sizeof (probe)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    //  We expect a routing id=X + empty message from client\n    recv_string_expect_success (server, \"X\", 0);\n    unsigned char buffer[255];\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, buffer, 255, 0));\n\n    //  Send a message to client now\n    send_string_expect_success (server, \"X\", ZMQ_SNDMORE);\n    send_string_expect_success (server, \"Hello\", 0);\n\n    recv_string_expect_success (client, \"Hello\", 0);\n\n    test_context_socket_close (server);\n    test_context_socket_close (client);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n\n    RUN_TEST (test_probe_router_router);\n    RUN_TEST (test_probe_router_dealer);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_proxy.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\n#define CONTENT_SIZE 13\n#define CONTENT_SIZE_MAX 32\n#define ROUTING_ID_SIZE 10\n#define ROUTING_ID_SIZE_MAX 32\n#define QT_WORKERS 5\n#define QT_CLIENTS 3\n#define is_verbose 0\n\nstruct thread_data\n{\n    int id;\n};\n\nvoid *g_clients_pkts_out = NULL;\nvoid *g_workers_pkts_out = NULL;\nvoid *control_context = NULL;\n\nvoid setUp ()\n{\n    setup_test_context ();\n}\n\n\n// Asynchronous client-to-server (DEALER to ROUTER) - pure libzmq\n//\n// While this example runs in a single process, that is to make\n// it easier to start and stop the example. Each task may have its own\n// context and conceptually acts as a separate process. To have this\n// behaviour, it is necessary to replace the inproc transport of the\n// control socket by a tcp transport.\n\n// This is our client task\n// It connects to the server, and then sends a request once per second\n// It collects responses as they arrive, and it prints them out. We will\n// run several client tasks in parallel, each with a different random ID.\n\nstatic void client_task (void *db_)\n{\n    const thread_data *const databag = static_cast<const thread_data *> (db_);\n    // Endpoint socket gets random port to avoid test failing when port in use\n    void *endpoint = zmq_socket (get_test_context (), ZMQ_PAIR);\n    TEST_ASSERT_NOT_NULL (endpoint);\n    int linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (endpoint, ZMQ_LINGER, &linger, sizeof (linger)));\n    char endpoint_source[256];\n    snprintf (endpoint_source, 256 * sizeof (char), \"inproc://endpoint%d\",\n              databag->id);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (endpoint, endpoint_source));\n    char *my_endpoint = s_recv (endpoint);\n    TEST_ASSERT_NOT_NULL (my_endpoint);\n\n    void *client = zmq_socket (get_test_context (), ZMQ_DEALER);\n    TEST_ASSERT_NOT_NULL (client);\n\n    // Control socket receives terminate command from main over inproc\n    void *control = zmq_socket (control_context, ZMQ_SUB);\n    TEST_ASSERT_NOT_NULL (control);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (control, ZMQ_SUBSCRIBE, \"\", 0));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (control, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, \"inproc://control\"));\n\n    char content[CONTENT_SIZE_MAX] = {};\n    // Set random routing id to make tracing easier\n    char routing_id[ROUTING_ID_SIZE] = {};\n    snprintf (routing_id, ROUTING_ID_SIZE * sizeof (char), \"%04X-%04X\",\n              rand () % 0xFFFF, rand () % 0xFFFF);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      client, ZMQ_ROUTING_ID, routing_id,\n      ROUTING_ID_SIZE)); // includes '\\0' as an helper for printf\n    linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    zmq_pollitem_t items[] = {{client, 0, ZMQ_POLLIN, 0},\n                              {control, 0, ZMQ_POLLIN, 0}};\n    int request_nbr = 0;\n    bool run = true;\n    bool keep_sending = true;\n    while (run) {\n        // Tick once per 200 ms, pulling in arriving messages\n        int centitick;\n        for (centitick = 0; centitick < 20; centitick++) {\n            zmq_poll (items, 2, 10);\n            if (items[0].revents & ZMQ_POLLIN) {\n                int rcvmore;\n                size_t sz = sizeof (rcvmore);\n                int rc = TEST_ASSERT_SUCCESS_ERRNO (\n                  zmq_recv (client, content, CONTENT_SIZE_MAX, 0));\n                TEST_ASSERT_EQUAL_INT (CONTENT_SIZE, rc);\n                if (is_verbose)\n                    printf (\n                      \"client receive - routing_id = %s    content = %s\\n\",\n                      routing_id, content);\n                //  Check that message is still the same\n                TEST_ASSERT_EQUAL_STRING_LEN (\"request #\", content, 9);\n                TEST_ASSERT_SUCCESS_ERRNO (\n                  zmq_getsockopt (client, ZMQ_RCVMORE, &rcvmore, &sz));\n                TEST_ASSERT_FALSE (rcvmore);\n            }\n            if (items[1].revents & ZMQ_POLLIN) {\n                int rc = zmq_recv (control, content, CONTENT_SIZE_MAX, 0);\n\n                if (rc > 0) {\n                    content[rc] = 0; // NULL-terminate the command string\n                    if (is_verbose)\n                        printf (\n                          \"client receive - routing_id = %s    command = %s\\n\",\n                          routing_id, content);\n                    if (memcmp (content, \"TERMINATE\", 9) == 0) {\n                        run = false;\n                        break;\n                    }\n                    if (memcmp (content, \"STOP\", 4) == 0) {\n                        keep_sending = false;\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (keep_sending) {\n            snprintf (content, CONTENT_SIZE_MAX * sizeof (char),\n                      \"request #%03d\", ++request_nbr); // CONTENT_SIZE\n            if (is_verbose)\n                printf (\"client send - routing_id = %s    request #%03d\\n\",\n                        routing_id, request_nbr);\n            zmq_atomic_counter_inc (g_clients_pkts_out);\n\n            TEST_ASSERT_EQUAL_INT (CONTENT_SIZE,\n                                   zmq_send (client, content, CONTENT_SIZE, 0));\n        }\n    }\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (client));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (endpoint));\n    free (my_endpoint);\n}\n\n// This is our server task.\n// It uses the multithreaded server model to deal requests out to a pool\n// of workers and route replies back to clients. One worker can handle\n// one request at a time but one client can talk to multiple workers at\n// once.\n\nstatic void server_worker (void * /*unused_*/);\n\nvoid server_task (void * /*unused_*/)\n{\n    // Frontend socket talks to clients over TCP\n    char my_endpoint[MAX_SOCKET_STRING];\n    void *frontend = zmq_socket (get_test_context (), ZMQ_ROUTER);\n    TEST_ASSERT_NOT_NULL (frontend);\n    int linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (frontend, ZMQ_LINGER, &linger, sizeof (linger)));\n    bind_loopback_ipv4 (frontend, my_endpoint, sizeof my_endpoint);\n\n    // Backend socket talks to workers over inproc\n    void *backend = zmq_socket (get_test_context (), ZMQ_DEALER);\n    TEST_ASSERT_NOT_NULL (backend);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (backend, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, \"inproc://backend\"));\n\n    // Launch pool of worker threads, precise number is not critical\n    int thread_nbr;\n    void *threads[5];\n    for (thread_nbr = 0; thread_nbr < QT_WORKERS; thread_nbr++)\n        threads[thread_nbr] = zmq_threadstart (&server_worker, NULL);\n\n    // Endpoint socket sends random port to avoid test failing when port in use\n    void *endpoint_receivers[QT_CLIENTS];\n    char endpoint_source[256];\n    for (int i = 0; i < QT_CLIENTS; ++i) {\n        endpoint_receivers[i] = zmq_socket (get_test_context (), ZMQ_PAIR);\n        TEST_ASSERT_NOT_NULL (endpoint_receivers[i]);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n          endpoint_receivers[i], ZMQ_LINGER, &linger, sizeof (linger)));\n        snprintf (endpoint_source, 256 * sizeof (char), \"inproc://endpoint%d\",\n                  i);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_bind (endpoint_receivers[i], endpoint_source));\n    }\n\n    for (int i = 0; i < QT_CLIENTS; ++i) {\n        send_string_expect_success (endpoint_receivers[i], my_endpoint, 0);\n    }\n\n    // Connect backend to frontend via a proxy\n    zmq_proxy (frontend, backend, NULL);\n\n    for (thread_nbr = 0; thread_nbr < QT_WORKERS; thread_nbr++)\n        zmq_threadclose (threads[thread_nbr]);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (frontend));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (backend));\n    for (int i = 0; i < QT_CLIENTS; ++i) {\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_close (endpoint_receivers[i]));\n    }\n}\n\n// Each worker task works on one request at a time and sends a random number\n// of replies back, with random delays between replies:\n// The comments in the first column, if suppressed, makes it a poller version\n\nstatic void server_worker (void * /*unused_*/)\n{\n    void *worker = zmq_socket (get_test_context (), ZMQ_DEALER);\n    TEST_ASSERT_NOT_NULL (worker);\n    int linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (worker, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (worker, \"inproc://backend\"));\n\n    // Control socket receives terminate command from main over inproc\n    void *control = zmq_socket (control_context, ZMQ_SUB);\n    TEST_ASSERT_NOT_NULL (control);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (control, ZMQ_SUBSCRIBE, \"\", 0));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (control, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, \"inproc://control\"));\n\n    char content[CONTENT_SIZE_MAX] =\n      {}; // bigger than what we need to check that\n    char routing_id[ROUTING_ID_SIZE_MAX] =\n      {}; // the size received is the size sent\n\n    bool run = true;\n    bool keep_sending = true;\n    while (run) {\n        int rc = zmq_recv (control, content, CONTENT_SIZE_MAX,\n                           ZMQ_DONTWAIT); // usually, rc == -1 (no message)\n        if (rc > 0) {\n            content[rc] = 0; // NULL-terminate the command string\n            if (is_verbose)\n                printf (\"server_worker receives command = %s\\n\", content);\n            if (memcmp (content, \"TERMINATE\", 9) == 0)\n                run = false;\n            if (memcmp (content, \"STOP\", 4) == 0)\n                keep_sending = false;\n        }\n        // The DEALER socket gives us the reply envelope and message\n        // if we don't poll, we have to use ZMQ_DONTWAIT, if we poll, we can block-receive with 0\n        rc = zmq_recv (worker, routing_id, ROUTING_ID_SIZE_MAX, ZMQ_DONTWAIT);\n        if (rc == ROUTING_ID_SIZE) {\n            rc = zmq_recv (worker, content, CONTENT_SIZE_MAX, 0);\n            TEST_ASSERT_EQUAL_INT (CONTENT_SIZE, rc);\n            if (is_verbose)\n                printf (\"server receive - routing_id = %s    content = %s\\n\",\n                        routing_id, content);\n\n            // Send 0..4 replies back\n            if (keep_sending) {\n                int reply, replies = rand () % 5;\n                for (reply = 0; reply < replies; reply++) {\n                    // Sleep for some fraction of a second\n                    msleep (rand () % 10 + 1);\n\n                    //  Send message from server to client\n                    if (is_verbose)\n                        printf (\"server send - routing_id = %s    reply\\n\",\n                                routing_id);\n                    zmq_atomic_counter_inc (g_workers_pkts_out);\n\n                    rc = zmq_send (worker, routing_id, ROUTING_ID_SIZE,\n                                   ZMQ_SNDMORE);\n                    TEST_ASSERT_EQUAL_INT (ROUTING_ID_SIZE, rc);\n                    rc = zmq_send (worker, content, CONTENT_SIZE, 0);\n                    TEST_ASSERT_EQUAL_INT (CONTENT_SIZE, rc);\n                }\n            }\n        }\n    }\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (worker));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));\n}\n\n// The main thread simply starts several clients and a server, and then\n// waits for the server to finish.\n\nvoid test_proxy ()\n{\n    g_clients_pkts_out = zmq_atomic_counter_new ();\n    g_workers_pkts_out = zmq_atomic_counter_new ();\n    control_context = zmq_ctx_new ();\n    TEST_ASSERT_NOT_NULL (control_context);\n\n    // Control socket receives terminate command from main over inproc\n    void *control = zmq_socket (control_context, ZMQ_PUB);\n    int linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (control, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (control, \"inproc://control\"));\n\n    void *threads[QT_CLIENTS + 1];\n    struct thread_data databags[QT_CLIENTS + 1];\n    for (int i = 0; i < QT_CLIENTS; i++) {\n        databags[i].id = i;\n        threads[i] = zmq_threadstart (&client_task, &databags[i]);\n    }\n    threads[QT_CLIENTS] = zmq_threadstart (&server_task, NULL);\n    msleep (500); // Run for 500 ms then quit\n\n    if (is_verbose)\n        printf (\"stopping all clients and server workers\\n\");\n    send_string_expect_success (control, \"STOP\", 0);\n\n    msleep (500); // Wait for all clients and workers to STOP\n\n    if (is_verbose)\n        printf (\"shutting down all clients and server workers\\n\");\n    send_string_expect_success (control, \"TERMINATE\", 0);\n\n    msleep (500); // Wait for all clients and workers to terminate\n\n    teardown_test_context ();\n\n    for (int i = 0; i < QT_CLIENTS + 1; i++)\n        zmq_threadclose (threads[i]);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (control_context));\n}\n\nint main (void)\n{\n    setup_test_environment (360);\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_proxy);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_proxy_hwm.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n#include <string.h>\n#include <unity.h>\n#include <assert.h>\n#include <unistd.h>\n\n//\n// Asynchronous proxy test using ZMQ_XPUB_NODROP and HWM:\n//\n// Topology:\n//\n//   XPUB                      SUB\n//    |                         |\n//    \\-----> XSUB -> XPUB -----/\n//           ^^^^^^^^^^^^^^\n//             ZMQ proxy\n//\n// All connections use \"inproc\" transport and have artificially-low HWMs set.\n// Then the PUB socket starts flooding the Proxy. The SUB is artificially slow\n// at receiving messages.\n// This scenario simulates what happens when a SUB is slower than\n// its (X)PUB: since ZMQ_XPUB_NODROP=1, the XPUB will block and then\n// also the (X)PUB socket will block.\n// The exact number of the messages that go through before (X)PUB blocks depends\n// on ZeroMQ internals and how the OS will schedule the different threads.\n// In the meanwhile asking statistics to the Proxy must NOT be blocking.\n//\n\n\n#define HWM 10\n#define NUM_BYTES_PER_MSG 50000\n\n\ntypedef struct\n{\n    void *context;\n    const char *frontend_endpoint;\n    const char *backend_endpoint;\n    const char *control_endpoint;\n\n    void *subscriber_received_all;\n} proxy_hwm_cfg_t;\n\nstatic void lower_hwm (void *skt_)\n{\n    int send_hwm = HWM;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (skt_, ZMQ_SNDHWM, &send_hwm, sizeof (send_hwm)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (skt_, ZMQ_RCVHWM, &send_hwm, sizeof (send_hwm)));\n}\n\nstatic void publisher_thread_main (void *pvoid_)\n{\n    const proxy_hwm_cfg_t *const cfg =\n      static_cast<const proxy_hwm_cfg_t *> (pvoid_);\n\n    void *pubsocket = zmq_socket (cfg->context, ZMQ_XPUB);\n    assert (pubsocket);\n\n    lower_hwm (pubsocket);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pubsocket, cfg->frontend_endpoint));\n\n    int optval = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pubsocket, ZMQ_XPUB_NODROP, &optval, sizeof (optval)));\n\n    // Wait before starting TX operations till 1 subscriber has subscribed\n    // (in this test there's 1 subscriber only)\n    const char subscription_to_all_topics[] = {1, 0};\n    recv_string_expect_success (pubsocket, subscription_to_all_topics, 0);\n\n    uint64_t send_count = 0;\n    while (true) {\n        zmq_msg_t msg;\n        int rc = zmq_msg_init_size (&msg, NUM_BYTES_PER_MSG);\n        assert (rc == 0);\n\n        /* Fill in message content with 'AAAAAA' */\n        memset (zmq_msg_data (&msg), 'A', NUM_BYTES_PER_MSG);\n\n        /* Send the message to the socket */\n        rc = zmq_msg_send (&msg, pubsocket, ZMQ_DONTWAIT);\n        if (rc != -1) {\n            send_count++;\n        } else {\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n            break;\n        }\n    }\n\n    // VERIFY EXPECTED RESULTS\n    // EXPLANATION FOR TX TO BE CONSIDERED SUCCESSFUL:\n    // this test has 3 threads doing I/O across 2 queues. Depending on the scheduling,\n    // it might happen that 20, 30 or 40 messages go through before the pub blocks.\n    // That's because the receiver thread gets kicked once every (hwm_ + 1) / 2 sent\n    // messages (search for zeromq sources compute_lwm function).\n    // So depending on the scheduling of the second thread, the publisher might get one,\n    // two or three more batches in. The ceiling is 40 as there's 2 queues.\n    //\n    assert (4 * HWM >= send_count && 2 * HWM <= send_count);\n\n    // CLEANUP\n\n    zmq_close (pubsocket);\n}\n\nstatic void subscriber_thread_main (void *pvoid_)\n{\n    const proxy_hwm_cfg_t *const cfg =\n      static_cast<const proxy_hwm_cfg_t *> (pvoid_);\n\n    void *subsocket = zmq_socket (cfg->context, ZMQ_SUB);\n    assert (subsocket);\n\n    lower_hwm (subsocket);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (subsocket, ZMQ_SUBSCRIBE, 0, 0));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (subsocket, cfg->backend_endpoint));\n\n\n    // receive all sent messages\n    uint64_t rxsuccess = 0;\n    bool success = true;\n    while (success) {\n        zmq_msg_t msg;\n        int rc = zmq_msg_init (&msg);\n        assert (rc == 0);\n\n        rc = zmq_msg_recv (&msg, subsocket, 0);\n        if (rc != -1) {\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n            rxsuccess++;\n\n            // after receiving 1st message, set a finite timeout (default is infinite)\n            int timeout_ms = 100;\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n              subsocket, ZMQ_RCVTIMEO, &timeout_ms, sizeof (timeout_ms)));\n        } else {\n            break;\n        }\n\n        msleep (100);\n    }\n\n\n    // VERIFY EXPECTED RESULTS\n    // EXPLANATION FOR RX TO BE CONSIDERED SUCCESSFUL:\n    // see publisher thread why we have 3 possible outcomes as number of RX messages\n\n    assert (4 * HWM >= rxsuccess && 2 * HWM <= rxsuccess);\n\n    // INFORM THAT WE COMPLETED:\n\n    zmq_atomic_counter_inc (cfg->subscriber_received_all);\n\n    // CLEANUP\n\n    zmq_close (subsocket);\n}\n\nstatic void proxy_stats_asker_thread_main (void *pvoid_)\n{\n    const proxy_hwm_cfg_t *const cfg =\n      static_cast<const proxy_hwm_cfg_t *> (pvoid_);\n\n    // CONTROL REQ\n\n    void *control_req =\n      zmq_socket (cfg->context,\n                  ZMQ_REQ); // this one can be used to send command to the proxy\n    assert (control_req);\n\n    // connect CONTROL-REQ: a socket to which send commands\n    int rc = zmq_connect (control_req, cfg->control_endpoint);\n    assert (rc == 0);\n\n\n    // IMPORTANT: by setting the tx/rx timeouts, we avoid getting blocked when interrogating a proxy which is\n    //            itself blocked in a zmq_msg_send() on its XPUB socket having ZMQ_XPUB_NODROP=1!\n\n    int optval = 10;\n    rc = zmq_setsockopt (control_req, ZMQ_SNDTIMEO, &optval, sizeof (optval));\n    assert (rc == 0);\n    rc = zmq_setsockopt (control_req, ZMQ_RCVTIMEO, &optval, sizeof (optval));\n    assert (rc == 0);\n\n    optval = 10;\n    rc =\n      zmq_setsockopt (control_req, ZMQ_REQ_CORRELATE, &optval, sizeof (optval));\n    assert (rc == 0);\n\n    rc =\n      zmq_setsockopt (control_req, ZMQ_REQ_RELAXED, &optval, sizeof (optval));\n    assert (rc == 0);\n\n\n    // Start!\n\n    while (!zmq_atomic_counter_value (cfg->subscriber_received_all)) {\n        usleep (1000); // 1ms -> in best case we will get 1000updates/second\n    }\n\n    zmq_close (control_req);\n}\n\nstatic void proxy_thread_main (void *pvoid_)\n{\n    const proxy_hwm_cfg_t *const cfg =\n      static_cast<const proxy_hwm_cfg_t *> (pvoid_);\n    int rc;\n\n    // FRONTEND SUB\n\n    void *frontend_xsub = zmq_socket (\n      cfg->context,\n      ZMQ_XSUB); // the frontend is the one exposed to internal threads (INPROC)\n    assert (frontend_xsub);\n\n    lower_hwm (frontend_xsub);\n\n    // bind FRONTEND\n    rc = zmq_bind (frontend_xsub, cfg->frontend_endpoint);\n    assert (rc == 0);\n\n\n    // BACKEND PUB\n\n    void *backend_xpub = zmq_socket (\n      cfg->context,\n      ZMQ_XPUB); // the backend is the one exposed to the external world (TCP)\n    assert (backend_xpub);\n\n    int optval = 1;\n    rc =\n      zmq_setsockopt (backend_xpub, ZMQ_XPUB_NODROP, &optval, sizeof (optval));\n    assert (rc == 0);\n\n    lower_hwm (backend_xpub);\n\n    // bind BACKEND\n    rc = zmq_bind (backend_xpub, cfg->backend_endpoint);\n    assert (rc == 0);\n\n\n    // CONTROL REP\n\n    void *control_rep = zmq_socket (\n      cfg->context,\n      ZMQ_REP); // this one is used by the proxy to receive&reply to commands\n    assert (control_rep);\n\n    // bind CONTROL\n    rc = zmq_bind (control_rep, cfg->control_endpoint);\n    assert (rc == 0);\n\n\n    // start proxying!\n\n    zmq_proxy (frontend_xsub, backend_xpub, NULL);\n\n    zmq_close (frontend_xsub);\n    zmq_close (backend_xpub);\n    zmq_close (control_rep);\n}\n\n\n// The main thread simply starts several clients and a server, and then\n// waits for the server to finish.\n\nint main (void)\n{\n    setup_test_environment ();\n\n    void *context = zmq_ctx_new ();\n    assert (context);\n\n\n    // START ALL SECONDARY THREADS\n\n    proxy_hwm_cfg_t cfg;\n    cfg.context = context;\n    cfg.frontend_endpoint = \"inproc://frontend\";\n    cfg.backend_endpoint = \"inproc://backend\";\n    cfg.control_endpoint = \"inproc://ctrl\";\n    cfg.subscriber_received_all = zmq_atomic_counter_new ();\n\n    void *proxy = zmq_threadstart (&proxy_thread_main, (void *) &cfg);\n    assert (proxy != 0);\n    void *publisher = zmq_threadstart (&publisher_thread_main, (void *) &cfg);\n    assert (publisher != 0);\n    void *subscriber = zmq_threadstart (&subscriber_thread_main, (void *) &cfg);\n    assert (subscriber != 0);\n    void *asker =\n      zmq_threadstart (&proxy_stats_asker_thread_main, (void *) &cfg);\n    assert (asker != 0);\n\n\n    // CLEANUP\n\n    zmq_threadclose (publisher);\n    zmq_threadclose (subscriber);\n    zmq_threadclose (asker);\n\n    int rc = zmq_ctx_term (context);\n    assert (rc == 0);\n\n    zmq_threadclose (proxy);\n\n    zmq_atomic_counter_destroy (&cfg.subscriber_received_all);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/test_proxy_single_socket.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n\nvoid setUp ()\n{\n    setup_test_context ();\n}\n\n// This is our server task.\n// It runs a proxy with a single REP socket as both frontend and backend.\n\nvoid server_task (void * /*unused_*/)\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n    void *rep = zmq_socket (get_test_context (), ZMQ_REP);\n    TEST_ASSERT_NOT_NULL (rep);\n    bind_loopback_ipv4 (rep, my_endpoint, sizeof my_endpoint);\n\n    // Control socket receives terminate command from main over inproc\n    void *control = zmq_socket (get_test_context (), ZMQ_REQ);\n    TEST_ASSERT_NOT_NULL (control);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, \"inproc://control\"));\n    send_string_expect_success (control, my_endpoint, 0);\n\n    // Use rep as both frontend and backend\n    zmq_proxy (rep, rep, NULL);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (rep));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));\n}\n\n\n// The main thread simply starts several clients and a server, and then\n// waits for the server to finish.\nvoid test_proxy_single_socket ()\n{\n    void *server_thread = zmq_threadstart (&server_task, NULL);\n\n    // Control socket receives terminate command from main over inproc\n    void *control = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_NOT_NULL (control);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (control, \"inproc://control\"));\n    char *my_endpoint = s_recv (control);\n    TEST_ASSERT_NOT_NULL (my_endpoint);\n\n    // client socket pings proxy over tcp\n    void *req = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_NOT_NULL (req);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, my_endpoint));\n\n    send_string_expect_success (req, \"msg1\", 0);\n    recv_string_expect_success (req, \"msg1\", 0);\n\n    send_string_expect_success (req, \"msg22\", 0);\n    recv_string_expect_success (req, \"msg22\", 0);\n\n    test_context_socket_close (control);\n    test_context_socket_close (req);\n    teardown_test_context ();\n    free (my_endpoint);\n\n    zmq_threadclose (server_thread);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_proxy_single_socket);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_proxy_steerable.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n#include <inttypes.h>\n\n#define CONTENT_SIZE 13\n#define CONTENT_SIZE_MAX 32\n#define ROUTING_ID_SIZE 10\n#define ROUTING_ID_SIZE_MAX 32\n#define QT_WORKERS 3\n#define QT_CLIENTS 3\n#define is_verbose 0\n#define TEST_SLEEP_MS 500\n\nconst char *proxy_control_address = \"inproc://proxy_control\";\n\nstruct thread_data\n{\n    int id;\n};\n\nvoid *g_clients_pkts_out = NULL;\nvoid *g_workers_pkts_out = NULL;\nvoid *control_context = NULL; // worker control, not proxy control\n\nint g_proxy_control_socktype =\n  ZMQ_PAIR; //or ZMQ_PAIR, ZMQ_SUB (without statistics)\n\nvoid setUp ()\n{\n    setup_test_context ();\n}\n\n\n// Asynchronous client-to-server (DEALER to ROUTER) - pure libzmq\n//\n// While this example runs in a single process, that is to make\n// it easier to start and stop the example. Each task may have its own\n// context and conceptually acts as a separate process. To have this\n// behaviour, it is necessary to replace the inproc transport of the\n// control socket by a tcp transport.\n\n// This is our client task\n// It connects to the server, and then sends a request once per second\n// It collects responses as they arrive, and it prints them out. We will\n// run several client tasks in parallel, each with a different random ID.\n\nstatic void client_task (void *db_)\n{\n    const thread_data *const databag = static_cast<const thread_data *> (db_);\n    // Endpoint socket gets random port to avoid test failing when port in use\n    void *endpoint = zmq_socket (get_test_context (), ZMQ_PAIR);\n    TEST_ASSERT_NOT_NULL (endpoint);\n    int linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (endpoint, ZMQ_LINGER, &linger, sizeof (linger)));\n    char endpoint_source[256];\n    snprintf (endpoint_source, 256 * sizeof (char), \"inproc://endpoint%d\",\n              databag->id);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (endpoint, endpoint_source));\n    char *my_endpoint = s_recv (endpoint);\n    TEST_ASSERT_NOT_NULL (my_endpoint);\n\n    void *client = zmq_socket (get_test_context (), ZMQ_DEALER);\n    TEST_ASSERT_NOT_NULL (client);\n\n    // Control socket receives terminate command from main over inproc\n    void *control = zmq_socket (control_context, ZMQ_SUB);\n    TEST_ASSERT_NOT_NULL (control);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (control, ZMQ_SUBSCRIBE, \"\", 0));\n    linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (control, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, \"inproc://control\"));\n\n    char content[CONTENT_SIZE_MAX] = {};\n    // Set random routing id to make tracing easier\n    char routing_id[ROUTING_ID_SIZE] = {};\n    snprintf (routing_id, ROUTING_ID_SIZE * sizeof (char), \"%04X-%04X\",\n              rand () % 0xFFFF, rand () % 0xFFFF);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      client, ZMQ_ROUTING_ID, routing_id,\n      ROUTING_ID_SIZE)); // includes '\\0' as an helper for printf\n    linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    zmq_pollitem_t items[] = {{client, 0, ZMQ_POLLIN, 0},\n                              {control, 0, ZMQ_POLLIN, 0}};\n\n    int request_nbr = 0;\n    bool run = true;\n    bool enable_send = false;\n    while (run) {\n        // Tick once per 200 ms, pulling in arriving messages\n        int centitick;\n        for (centitick = 0; centitick < 20; centitick++) {\n            zmq_poll (items, 2, 10);\n            if (items[0].revents & ZMQ_POLLIN) {\n                int rcvmore;\n                size_t sz = sizeof (rcvmore);\n                int rc = TEST_ASSERT_SUCCESS_ERRNO (\n                  zmq_recv (client, content, CONTENT_SIZE_MAX, 0));\n                TEST_ASSERT_EQUAL_INT (CONTENT_SIZE, rc);\n                if (is_verbose)\n                    printf (\n                      \"client receive - routing_id = %s    content = %s\\n\",\n                      routing_id, content);\n                //  Check that message is still the same\n                TEST_ASSERT_EQUAL_STRING_LEN (\"request #\", content, 9);\n                TEST_ASSERT_SUCCESS_ERRNO (\n                  zmq_getsockopt (client, ZMQ_RCVMORE, &rcvmore, &sz));\n                TEST_ASSERT_FALSE (rcvmore);\n            }\n            if (items[1].revents & ZMQ_POLLIN) {\n                int rc = zmq_recv (control, content, CONTENT_SIZE_MAX, 0);\n\n                if (rc > 0) {\n                    content[rc] = 0; // NULL-terminate the command string\n                    if (is_verbose)\n                        printf (\n                          \"client receive - routing_id = %s    command = %s\\n\",\n                          routing_id, content);\n                    if (memcmp (content, \"TERMINATE\", 9) == 0) {\n                        run = false;\n                    } else if (memcmp (content, \"STOP\", 4) == 0) {\n                        enable_send = false;\n                    } else if (memcmp (content, \"START\", 5) == 0) {\n                        enable_send = true;\n                    }\n                    break;\n                }\n            }\n        }\n\n        if (enable_send) {\n            snprintf (content, CONTENT_SIZE_MAX * sizeof (char),\n                      \"request #%03d\", ++request_nbr); // CONTENT_SIZE\n            if (is_verbose)\n                printf (\"client send - routing_id = %s    request #%03d\\n\",\n                        routing_id, request_nbr);\n            zmq_atomic_counter_inc (g_clients_pkts_out);\n\n            TEST_ASSERT_EQUAL_INT (CONTENT_SIZE,\n                                   zmq_send (client, content, CONTENT_SIZE, 0));\n        }\n    }\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (client));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (endpoint));\n    free (my_endpoint);\n}\n\n// This is our server task.\n// It uses the multithreaded server model to deal requests out to a pool\n// of workers and route replies back to clients. One worker can handle\n// one request at a time but one client can talk to multiple workers at\n// once.\n\nstatic void server_worker (void * /*unused_*/);\n\nvoid server_task (void * /*unused_*/)\n{\n    // Frontend socket talks to clients over TCP\n    char my_endpoint[MAX_SOCKET_STRING];\n    void *frontend = zmq_socket (get_test_context (), ZMQ_ROUTER);\n    TEST_ASSERT_NOT_NULL (frontend);\n    int linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (frontend, ZMQ_LINGER, &linger, sizeof (linger)));\n    bind_loopback_ipv4 (frontend, my_endpoint, sizeof my_endpoint);\n\n    // Backend socket talks to workers over inproc\n    void *backend = zmq_socket (get_test_context (), ZMQ_DEALER);\n    TEST_ASSERT_NOT_NULL (backend);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (backend, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, \"inproc://backend\"));\n\n    // Launch pool of worker threads, precise number is not critical\n    int thread_nbr;\n    void *threads[QT_WORKERS];\n    for (thread_nbr = 0; thread_nbr < QT_WORKERS; thread_nbr++)\n        threads[thread_nbr] = zmq_threadstart (&server_worker, NULL);\n\n    // Endpoint socket sends random port to avoid test failing when port in use\n    void *endpoint_receivers[QT_CLIENTS];\n    char endpoint_source[256];\n    for (int i = 0; i < QT_CLIENTS; ++i) {\n        endpoint_receivers[i] = zmq_socket (get_test_context (), ZMQ_PAIR);\n        TEST_ASSERT_NOT_NULL (endpoint_receivers[i]);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n          endpoint_receivers[i], ZMQ_LINGER, &linger, sizeof (linger)));\n        snprintf (endpoint_source, 256 * sizeof (char), \"inproc://endpoint%d\",\n                  i);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_bind (endpoint_receivers[i], endpoint_source));\n    }\n\n    for (int i = 0; i < QT_CLIENTS; ++i) {\n        send_string_expect_success (endpoint_receivers[i], my_endpoint, 0);\n    }\n\n    // Proxy control socket\n    void *proxy_control =\n      zmq_socket (get_test_context (), g_proxy_control_socktype);\n    TEST_ASSERT_NOT_NULL (proxy_control);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (proxy_control, proxy_control_address));\n    if (g_proxy_control_socktype == ZMQ_SUB) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (proxy_control, ZMQ_SUBSCRIBE, \"\", 0));\n    }\n\n    // Connect backend to frontend via a steerable proxy\n    int rc = zmq_proxy_steerable (frontend, backend, NULL, proxy_control);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    for (thread_nbr = 0; thread_nbr < QT_WORKERS; thread_nbr++) {\n        zmq_threadclose (threads[thread_nbr]);\n    }\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (frontend));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (backend));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (proxy_control));\n    for (int i = 0; i < QT_CLIENTS; ++i) {\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_close (endpoint_receivers[i]));\n    }\n}\n\n// Each worker task works on one request at a time and sends a random number\n// of replies back, with random delays between replies:\n// The comments in the first column, if suppressed, makes it a poller version\n\nstatic void server_worker (void * /*unused_*/)\n{\n    void *worker = zmq_socket (get_test_context (), ZMQ_DEALER);\n    TEST_ASSERT_NOT_NULL (worker);\n    int linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (worker, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (worker, \"inproc://backend\"));\n\n    // Control socket receives terminate command from main over inproc\n    void *control = zmq_socket (control_context, ZMQ_SUB);\n    TEST_ASSERT_NOT_NULL (control);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (control, ZMQ_SUBSCRIBE, \"\", 0));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (control, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, \"inproc://control\"));\n\n    char content[CONTENT_SIZE_MAX] =\n      {}; // bigger than what we need to check that\n    char routing_id[ROUTING_ID_SIZE_MAX] =\n      {}; // the size received is the size sent\n\n    zmq_pollitem_t items[] = {{control, 0, ZMQ_POLLIN, 0},\n                              {worker, 0, ZMQ_POLLIN, 0}};\n    bool keep_sending = true;\n    while (true) {\n        zmq_poll (items, 2, 100);\n        if (items[0].revents & ZMQ_POLLIN) {\n            //Commands over the worker control socket\n            int rc = zmq_recv (control, content, CONTENT_SIZE_MAX, 0);\n            if (rc > 0) {\n                content[rc] = 0; // NULL-terminate the command string\n                if (is_verbose)\n                    printf (\"server_worker receives command = %s\\n\", content);\n                if (memcmp (content, \"TERMINATE\", 9) == 0)\n                    break;\n                if (memcmp (content, \"STOP\", 4) == 0)\n                    keep_sending = false;\n            }\n        }\n        if (items[1].revents & ZMQ_POLLIN) {\n            // The DEALER socket gives us the reply envelope and message\n            int rc = zmq_recv (worker, routing_id, ROUTING_ID_SIZE_MAX, 0);\n            if (rc != ROUTING_ID_SIZE) {\n                continue;\n            }\n            routing_id[rc] = 0; //null terminate\n            rc = zmq_recv (worker, content, CONTENT_SIZE_MAX, 0);\n            TEST_ASSERT_EQUAL_INT (CONTENT_SIZE, rc);\n            content[rc] = 0; //null terminate\n            if (is_verbose)\n                printf (\"server receive - routing_id = %s    content = %s\\n\",\n                        routing_id, content);\n\n            // Send 0..4 replies back\n            if (keep_sending) {\n                int reply, replies = rand () % 5;\n                for (reply = 0; reply < replies; reply++) {\n                    // Sleep for some fraction of a second\n                    msleep (rand () % 10 + 1);\n\n                    //  Send message from server to client\n                    if (is_verbose)\n                        printf (\"server send - routing_id = %s    reply\\n\",\n                                routing_id);\n                    zmq_atomic_counter_inc (g_workers_pkts_out);\n\n                    rc = zmq_send (worker, routing_id, ROUTING_ID_SIZE,\n                                   ZMQ_SNDMORE);\n                    TEST_ASSERT_EQUAL_INT (ROUTING_ID_SIZE, rc);\n                    rc = zmq_send (worker, content, CONTENT_SIZE, 0);\n                    TEST_ASSERT_EQUAL_INT (CONTENT_SIZE, rc);\n                }\n            }\n        }\n    }\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (worker));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));\n}\n\n// If STATISTICS is received, the proxy will reply on the control socket\n// sending a multipart message with 8 frames, each with an unsigned integer\n// 64-bit wide that provide in the following order:\n//\n// - 0/frn: number of messages received by the frontend socket\n//\n// - 1/frb: number of bytes received by the frontend socket\n//\n// - 2/fsn: number of messages sent out the frontend socket\n//\n// - 3/fsb: number of bytes sent out the frontend socket\n//\n// - 4/brn: number of messages received by the backend socket\n//\n// - 5/brb: number of bytes received by the backend socket\n//\n// - 6/bsn: number of messages sent out the backend socket\n//\n// - 7/bsb: number of bytes sent out the backend socket\n\nuint64_t read_stat_value (void *proxy_control)\n{\n    zmq_msg_t stats_msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&stats_msg));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&stats_msg, proxy_control, 0));\n    TEST_ASSERT_EQUAL_INT (sizeof (uint64_t), zmq_msg_size (&stats_msg));\n    uint64_t val = *(uint64_t *) zmq_msg_data (&stats_msg);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&stats_msg));\n    return val;\n}\n\n//return total bytes proxied, so we can test PAUSE/RESUME\nuint64_t statistics (void *proxy_control, const char *runctx)\n{\n    if (is_verbose) {\n        printf (\"steer: sending STATISTICS - %s\\n\", runctx);\n    }\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_send (proxy_control, \"STATISTICS\", 10, 0));\n\n    uint64_t total_bytes_proxied = 0;\n    for (int count = 0; count < 8; ++count) {\n        uint64_t val = read_stat_value (proxy_control);\n        if (is_verbose) {\n            if (count == 0) {\n                printf (\"stats: client pkts out: %d worker pkts out: %d { \",\n                        zmq_atomic_counter_value (g_clients_pkts_out),\n                        zmq_atomic_counter_value (g_workers_pkts_out));\n            }\n            printf (\"%\" PRIu64 \" \", val);\n            if (count == 7) {\n                printf (\"}\\n\");\n            }\n        }\n        switch (count) {\n            case 3: //bytes sent on frontend\n            case 7: //bytes sent on backend\n                total_bytes_proxied += val;\n        }\n    }\n\n    int rcvmore;\n    size_t sz = sizeof (rcvmore);\n    zmq_getsockopt (proxy_control, ZMQ_RCVMORE, &rcvmore, &sz);\n    TEST_ASSERT_EQUAL_INT (rcvmore, 0);\n    return total_bytes_proxied;\n}\n\n\n// The main thread simply starts several clients and a server, and then\n// waits for the server to finish.\n\nvoid steer (void *proxy_control, const char *command, const char *runctx)\n{\n    if (is_verbose) {\n        printf (\"steer: sending %s - %s\\n\", command, runctx);\n    }\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_send (proxy_control, command, strlen (command), 0));\n\n    if (g_proxy_control_socktype == ZMQ_REP) {\n        //expect an empty reply from REP for commands that need no response\n        zmq_msg_t stats_msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&stats_msg));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&stats_msg, proxy_control, 0));\n        TEST_ASSERT_EQUAL_INT (zmq_msg_size (&stats_msg), 0);\n        TEST_ASSERT (!zmq_msg_get (&stats_msg, ZMQ_MORE));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&stats_msg));\n    }\n}\n\nvoid test_proxy_steerable ()\n{\n    int linger = 0;\n    void *threads[QT_CLIENTS + 1];\n\n    g_clients_pkts_out = zmq_atomic_counter_new ();\n    g_workers_pkts_out = zmq_atomic_counter_new ();\n    control_context = zmq_ctx_new ();\n    TEST_ASSERT_NOT_NULL (control_context);\n\n    // Worker control socket receives terminate command from main over inproc\n    void *control = zmq_socket (control_context, ZMQ_PUB);\n    linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (control, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (control, \"inproc://control\"));\n\n    struct thread_data databags[QT_CLIENTS + 1];\n    for (int i = 0; i < QT_CLIENTS; i++) {\n        databags[i].id = i;\n        threads[i] = zmq_threadstart (&client_task, &databags[i]);\n    }\n    threads[QT_CLIENTS] = zmq_threadstart (&server_task, NULL);\n    msleep (TEST_SLEEP_MS); // setup time\n\n    // Proxy control socket\n    int control_socktype = ZMQ_PAIR;\n    switch (g_proxy_control_socktype) {\n        case ZMQ_REP:\n            control_socktype = ZMQ_REQ;\n            break;\n        case ZMQ_SUB:\n            control_socktype = ZMQ_PUB;\n            break;\n        default:\n            break;\n    }\n    void *proxy_control = zmq_socket (get_test_context (), control_socktype);\n    TEST_ASSERT_NOT_NULL (proxy_control);\n    linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (proxy_control, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (proxy_control, proxy_control_address));\n\n    TEST_ASSERT (\n      statistics (proxy_control, \"should be all 0s before clients start\") == 0);\n\n    send_string_expect_success (control, \"START\", 0);\n\n    msleep (TEST_SLEEP_MS); // Run for some time\n\n    TEST_ASSERT (statistics (proxy_control, \"started clients\") > 0);\n    steer (proxy_control, \"PAUSE\", \"pausing proxying after 500ms\");\n    uint64_t bytes = statistics (proxy_control, \"post-pause\");\n\n    msleep (TEST_SLEEP_MS); // Paused for some time\n\n    //check no more bytes have been proxied while paused\n    TEST_ASSERT (statistics (proxy_control, \"post-pause\") == bytes);\n\n    steer (proxy_control, \"RESUME\", \"resuming proxying after another 500ms\");\n\n    msleep (TEST_SLEEP_MS); // Resumed for a while\n\n    TEST_ASSERT (statistics (proxy_control, \"ran for a while\") > bytes);\n\n    if (is_verbose)\n        printf (\"stopping all clients and server workers\\n\");\n    send_string_expect_success (control, \"STOP\", 0);\n\n    statistics (proxy_control, \"stopped clients and workers\");\n\n    msleep (TEST_SLEEP_MS); // Wait for all clients and workers to STOP\n\n    if (is_verbose)\n        printf (\"shutting down all clients and server workers\\n\");\n    send_string_expect_success (control, \"TERMINATE\", 0);\n\n    msleep (TEST_SLEEP_MS);\n    statistics (proxy_control, \"terminate clients and server workers\");\n\n    msleep (TEST_SLEEP_MS); // Wait for all clients and workers to terminate\n    steer (proxy_control, \"TERMINATE\", \"terminate proxy\");\n\n    for (int i = 0; i < QT_CLIENTS + 1; i++)\n        zmq_threadclose (threads[i]);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (control_context));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (proxy_control));\n\n    teardown_test_context ();\n}\n\nint main (void)\n{\n    setup_test_environment (360);\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_proxy_steerable);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_proxy_terminate.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n\nvoid setUp ()\n{\n    setup_test_context ();\n}\n\n// This is a test for issue #1382. The server thread creates a SUB-PUSH\n// steerable proxy. The main process then sends messages to the SUB\n// but there is no pull on the other side, previously the proxy blocks\n// in writing to the backend, preventing the proxy from terminating\n\nvoid server_task (void * /*unused_*/)\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n    // Frontend socket talks to main process\n    void *frontend = zmq_socket (get_test_context (), ZMQ_SUB);\n    TEST_ASSERT_NOT_NULL (frontend);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (frontend, ZMQ_SUBSCRIBE, \"\", 0));\n    bind_loopback_ipv4 (frontend, my_endpoint, sizeof my_endpoint);\n\n    // Nice socket which is never read\n    void *backend = zmq_socket (get_test_context (), ZMQ_PUSH);\n    TEST_ASSERT_NOT_NULL (backend);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, \"tcp://127.0.0.1:*\"));\n\n    // Control socket receives terminate command from main over inproc\n    void *control = zmq_socket (get_test_context (), ZMQ_REQ);\n    TEST_ASSERT_NOT_NULL (control);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, \"inproc://control\"));\n    send_string_expect_success (control, my_endpoint, 0);\n\n    // Connect backend to frontend via a proxy\n    zmq_proxy (frontend, backend, NULL);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (frontend));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (backend));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));\n}\n\n\n// The main thread simply starts a basic steerable proxy server, publishes some messages, and then\n// waits for the server to terminate.\nvoid test_proxy_terminate ()\n{\n    void *thread = zmq_threadstart (&server_task, NULL);\n\n    // Control socket receives terminate command from main over inproc\n    void *control = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_NOT_NULL (control);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (control, \"inproc://control\"));\n    char *my_endpoint = s_recv (control);\n    TEST_ASSERT_NOT_NULL (my_endpoint);\n\n    msleep (500); // Run for 500 ms\n\n    // Start a secondary publisher which writes data to the SUB-PUSH server socket\n    void *publisher = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_NOT_NULL (publisher);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (publisher, my_endpoint));\n\n    msleep (SETTLE_TIME);\n    send_string_expect_success (publisher, \"This is a test\", 0);\n\n    msleep (50);\n    send_string_expect_success (publisher, \"This is a test\", 0);\n\n    msleep (50);\n    send_string_expect_success (publisher, \"This is a test\", 0);\n\n    test_context_socket_close (publisher);\n    test_context_socket_close (control);\n    teardown_test_context ();\n    free (my_endpoint);\n\n    zmq_threadclose (thread);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_proxy_terminate);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_pub_invert_matching.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test ()\n{\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, \"inproc://soname\"));\n\n    //  Create two subscribers\n    void *sub1 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub1, \"inproc://soname\"));\n\n    void *sub2 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub2, \"inproc://soname\"));\n\n    //  Subscribe pub1 to one prefix\n    //  and pub2 to another prefix.\n    const char prefi_x1[] = \"prefix1\";\n    const char prefi_x2[] = \"p2\";\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, prefi_x1, strlen (prefi_x1)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub2, ZMQ_SUBSCRIBE, prefi_x2, strlen (prefi_x2)));\n\n    //  Send a message with the first prefix\n    send_string_expect_success (pub, prefi_x1, 0);\n    msleep (SETTLE_TIME);\n\n    //  sub1 should receive it, but not sub2\n    recv_string_expect_success (sub1, prefi_x1, ZMQ_DONTWAIT);\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (sub2, NULL, 0, ZMQ_DONTWAIT));\n\n    //  Send a message with the second prefix\n    send_string_expect_success (pub, prefi_x2, 0);\n    msleep (SETTLE_TIME);\n\n    //  sub2 should receive it, but not sub1\n    recv_string_expect_success (sub2, prefi_x2, ZMQ_DONTWAIT);\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (sub1, NULL, 0, ZMQ_DONTWAIT));\n\n    //  Now invert the matching\n    int invert = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_INVERT_MATCHING, &invert, sizeof (invert)));\n\n    //  ... on both sides, otherwise the SUB socket will filter the messages out\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub1, ZMQ_INVERT_MATCHING, &invert, sizeof (invert)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub2, ZMQ_INVERT_MATCHING, &invert, sizeof (invert)));\n\n    //  Send a message with the first prefix\n    send_string_expect_success (pub, prefi_x1, 0);\n    msleep (SETTLE_TIME);\n\n    //  sub2 should receive it, but not sub1\n    recv_string_expect_success (sub2, prefi_x1, ZMQ_DONTWAIT);\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (sub1, NULL, 0, ZMQ_DONTWAIT));\n\n    //  Send a message with the second prefix\n    send_string_expect_success (pub, prefi_x2, 0);\n    msleep (SETTLE_TIME);\n\n    //  sub1 should receive it, but not sub2\n    recv_string_expect_success (sub1, prefi_x2, ZMQ_DONTWAIT);\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (sub2, NULL, 0, ZMQ_DONTWAIT));\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub1);\n    test_context_socket_close (sub2);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_pubsub.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test (const char *address)\n{\n    //  Create a publisher\n    void *publisher = test_context_socket (ZMQ_PUB);\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  Bind publisher\n    test_bind (publisher, address, my_endpoint, MAX_SOCKET_STRING);\n\n    //  Create a subscriber\n    void *subscriber = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (subscriber, my_endpoint));\n\n    //  Subscribe to all messages.\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, \"\", 0));\n\n    //  Wait a bit till the subscription gets to the publisher\n    msleep (SETTLE_TIME);\n\n    //  Send an empty message\n    send_string_expect_success (publisher, \"test\", 0);\n\n    //  Receive the message in the subscriber\n    recv_string_expect_success (subscriber, \"test\", 0);\n\n    //  Clean up.\n    test_context_socket_close (publisher);\n    test_context_socket_close (subscriber);\n}\n\nvoid test_norm ()\n{\n#if defined ZMQ_HAVE_NORM\n    test (\"norm://224.1.2.3:5556\");\n#else\n    TEST_IGNORE_MESSAGE (\"libzmq without NORM, ignoring test\");\n#endif\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_norm);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_pubsub_topics_count.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n\nvoid settle_subscriptions (void *skt)\n{\n    //  To kick the application thread, do a dummy getsockopt - users here\n    //  should use the monitor and the other sockets in a poll.\n    unsigned long int dummy;\n    size_t dummy_size = sizeof (dummy);\n    msleep (SETTLE_TIME);\n    zmq_getsockopt (skt, ZMQ_EVENTS, &dummy, &dummy_size);\n}\n\nint get_subscription_count (void *skt)\n{\n    int num_subs = 0;\n    size_t num_subs_len = sizeof (num_subs);\n\n    settle_subscriptions (skt);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (skt, ZMQ_TOPICS_COUNT, &num_subs, &num_subs_len));\n\n    return num_subs;\n}\n\nvoid test_independent_topic_prefixes ()\n{\n    //  Create a publisher\n    void *publisher = test_context_socket (ZMQ_PUB);\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  Bind publisher\n    test_bind (publisher, \"inproc://soname\", my_endpoint, MAX_SOCKET_STRING);\n\n    //  Create a subscriber\n    void *subscriber = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (subscriber, my_endpoint));\n\n    //  Subscribe to 3 topics\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      subscriber, ZMQ_SUBSCRIBE, \"topicprefix1\", strlen (\"topicprefix1\")));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      subscriber, ZMQ_SUBSCRIBE, \"topicprefix2\", strlen (\"topicprefix2\")));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      subscriber, ZMQ_SUBSCRIBE, \"topicprefix3\", strlen (\"topicprefix3\")));\n    TEST_ASSERT_EQUAL_INT (get_subscription_count (subscriber), 3);\n    TEST_ASSERT_EQUAL_INT (get_subscription_count (publisher), 3);\n\n    // Remove first subscription and check subscriptions went 3 -> 2\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      subscriber, ZMQ_UNSUBSCRIBE, \"topicprefix3\", strlen (\"topicprefix3\")));\n    TEST_ASSERT_EQUAL_INT (get_subscription_count (subscriber), 2);\n    TEST_ASSERT_EQUAL_INT (get_subscription_count (publisher), 2);\n\n    // Remove other 2 subscriptions and check we're back to 0 subscriptions\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      subscriber, ZMQ_UNSUBSCRIBE, \"topicprefix1\", strlen (\"topicprefix1\")));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      subscriber, ZMQ_UNSUBSCRIBE, \"topicprefix2\", strlen (\"topicprefix2\")));\n    TEST_ASSERT_EQUAL_INT (get_subscription_count (subscriber), 0);\n    TEST_ASSERT_EQUAL_INT (get_subscription_count (publisher), 0);\n\n    //  Clean up.\n    test_context_socket_close (publisher);\n    test_context_socket_close (subscriber);\n}\n\nvoid test_nested_topic_prefixes ()\n{\n    //  Create a publisher\n    void *publisher = test_context_socket (ZMQ_PUB);\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  Bind publisher\n    test_bind (publisher, \"inproc://soname\", my_endpoint, MAX_SOCKET_STRING);\n\n    //  Create a subscriber\n    void *subscriber = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (subscriber, my_endpoint));\n\n    //  Subscribe to 3 (nested) topics\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, \"a\", strlen (\"a\")));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, \"ab\", strlen (\"ab\")));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, \"abc\", strlen (\"abc\")));\n\n    // Even if the subscriptions are nested one into the other, the number of subscriptions\n    // received on the subscriber/publisher socket will be 3:\n    TEST_ASSERT_EQUAL_INT (get_subscription_count (subscriber), 3);\n    TEST_ASSERT_EQUAL_INT (get_subscription_count (publisher), 3);\n\n    //  Subscribe to other 3 (nested) topics\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, \"xyz\", strlen (\"xyz\")));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, \"xy\", strlen (\"xy\")));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, \"x\", strlen (\"x\")));\n\n    TEST_ASSERT_EQUAL_INT (get_subscription_count (subscriber), 6);\n    TEST_ASSERT_EQUAL_INT (get_subscription_count (publisher), 6);\n\n    //  Clean up.\n    test_context_socket_close (publisher);\n    test_context_socket_close (subscriber);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_independent_topic_prefixes);\n    RUN_TEST (test_nested_topic_prefixes);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_radio_dish.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\n#ifndef _WIN32\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <unistd.h>\n#endif\n\n// Helper macro to define the v4/v6 function pairs\n#define MAKE_TEST_V4V6(_test)                                                  \\\n    static void _test##_ipv4 ()                                                \\\n    {                                                                          \\\n        _test (false);                                                         \\\n    }                                                                          \\\n                                                                               \\\n    static void _test##_ipv6 ()                                                \\\n    {                                                                          \\\n        if (!is_ipv6_available ()) {                                           \\\n            TEST_IGNORE_MESSAGE (\"ipv6 is not available\");                     \\\n        }                                                                      \\\n        _test (true);                                                          \\\n    }\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid msg_send_expect_success (void *s_, const char *group_, const char *body_)\n{\n    zmq_msg_t msg;\n    const size_t len = strlen (body_);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, len));\n\n    memcpy (zmq_msg_data (&msg), body_, len);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_set_group (&msg, group_));\n\n    int rc = zmq_msg_send (&msg, s_, 0);\n    TEST_ASSERT_EQUAL_INT ((int) len, rc);\n\n    // TODO isn't the msg closed by zmq_msg_send?\n    zmq_msg_close (&msg);\n}\n\nvoid msg_recv_cmp (void *s_, const char *group_, const char *body_)\n{\n    zmq_msg_t msg;\n    const size_t len = strlen (body_);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n    int recv_rc = TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, s_, 0));\n    TEST_ASSERT_EQUAL_INT (len, recv_rc);\n\n    TEST_ASSERT_EQUAL_STRING (group_, zmq_msg_group (&msg));\n\n    TEST_ASSERT_EQUAL_STRING_LEN (body_, zmq_msg_data (&msg), len);\n\n    zmq_msg_close (&msg);\n}\n\nvoid test_leave_unjoined_fails ()\n{\n    void *dish = test_context_socket (ZMQ_DISH);\n\n    //  Leaving a group which we didn't join\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_leave (dish, \"Movies\"));\n\n    test_context_socket_close (dish);\n}\n\nvoid test_long_group ()\n{\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *radio = test_context_socket (ZMQ_RADIO);\n    bind_loopback (radio, false, my_endpoint, len);\n\n    void *dish = test_context_socket (ZMQ_DISH);\n\n    // Joining to a long group, over 14 chars\n    char group[19] = \"0123456789ABCDEFGH\";\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, group));\n\n    // Connecting\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dish, my_endpoint));\n\n    msleep (SETTLE_TIME);\n\n    //  This is going to be sent to the dish\n    msg_send_expect_success (radio, group, \"HELLO\");\n\n    //  Check the correct message arrived\n    msg_recv_cmp (dish, group, \"HELLO\");\n\n    test_context_socket_close (dish);\n    test_context_socket_close (radio);\n}\n\nvoid test_join_too_long_fails ()\n{\n    void *dish = test_context_socket (ZMQ_DISH);\n\n    //  Joining too long group\n    char too_long_group[ZMQ_GROUP_MAX_LENGTH + 2];\n    for (int index = 0; index < ZMQ_GROUP_MAX_LENGTH + 2; index++)\n        too_long_group[index] = 'A';\n    too_long_group[ZMQ_GROUP_MAX_LENGTH + 1] = '\\0';\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_join (dish, too_long_group));\n\n    test_context_socket_close (dish);\n}\n\nvoid test_join_twice_fails ()\n{\n    void *dish = test_context_socket (ZMQ_DISH);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, \"Movies\"));\n\n    // Duplicate Joining\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_join (dish, \"Movies\"));\n\n    test_context_socket_close (dish);\n}\n\nvoid test_radio_dish_tcp_poll (int ipv6_)\n{\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *radio = test_context_socket (ZMQ_RADIO);\n    bind_loopback (radio, ipv6_, my_endpoint, len);\n\n    void *dish = test_context_socket (ZMQ_DISH);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));\n\n    // Joining\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, \"Movies\"));\n\n    // Connecting\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dish, my_endpoint));\n\n    msleep (SETTLE_TIME);\n\n    //  This is not going to be sent as dish only subscribe to \"Movies\"\n    msg_send_expect_success (radio, \"TV\", \"Friends\");\n\n    //  This is going to be sent to the dish\n    msg_send_expect_success (radio, \"Movies\", \"Godfather\");\n\n    //  Check the correct message arrived\n    msg_recv_cmp (dish, \"Movies\", \"Godfather\");\n\n    //  Join group during connection optvallen\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, \"TV\"));\n\n    zmq_sleep (1);\n\n    //  This should arrive now as we joined the group\n    msg_send_expect_success (radio, \"TV\", \"Friends\");\n\n    //  Check the correct message arrived\n    msg_recv_cmp (dish, \"TV\", \"Friends\");\n\n    //  Leaving group\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_leave (dish, \"TV\"));\n\n    zmq_sleep (1);\n\n    //  This is not going to be sent as dish only subscribe to \"Movies\"\n    msg_send_expect_success (radio, \"TV\", \"Friends\");\n\n    //  This is going to be sent to the dish\n    msg_send_expect_success (radio, \"Movies\", \"Godfather\");\n\n    // test zmq_poll with dish\n    zmq_pollitem_t items[] = {\n      {radio, 0, ZMQ_POLLIN, 0}, // read publications\n      {dish, 0, ZMQ_POLLIN, 0},  // read subscriptions\n    };\n    int rc = zmq_poll (items, 2, 2000);\n    TEST_ASSERT_EQUAL_INT (1, rc);\n    TEST_ASSERT_EQUAL_INT (ZMQ_POLLIN, items[1].revents);\n\n    //  Check the correct message arrived\n    msg_recv_cmp (dish, \"Movies\", \"Godfather\");\n\n    test_context_socket_close (dish);\n    test_context_socket_close (radio);\n}\nMAKE_TEST_V4V6 (test_radio_dish_tcp_poll)\n\nvoid test_dish_connect_fails (int ipv6_)\n{\n    void *dish = test_context_socket (ZMQ_DISH);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));\n\n    const char *url = ipv6_ ? \"udp://[::1]:5556\" : \"udp://127.0.0.1:5556\";\n\n    //  Connecting dish should fail\n    TEST_ASSERT_FAILURE_ERRNO (ENOCOMPATPROTO, zmq_connect (dish, url));\n\n    test_context_socket_close (dish);\n}\nMAKE_TEST_V4V6 (test_dish_connect_fails)\n\nvoid test_radio_bind_fails (int ipv6_)\n{\n    void *radio = test_context_socket (ZMQ_RADIO);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (radio, ZMQ_IPV6, &ipv6_, sizeof (int)));\n\n    //  Connecting dish should fail\n    //  Bind radio should fail\n    TEST_ASSERT_FAILURE_ERRNO (ENOCOMPATPROTO,\n                               zmq_bind (radio, \"udp://*:5556\"));\n\n    test_context_socket_close (radio);\n}\nMAKE_TEST_V4V6 (test_radio_bind_fails)\n\nvoid test_radio_dish_udp (int ipv6_)\n{\n    void *radio = test_context_socket (ZMQ_RADIO);\n    void *dish = test_context_socket (ZMQ_DISH);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (radio, ZMQ_IPV6, &ipv6_, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));\n\n    const char *radio_url = ipv6_ ? \"udp://[::1]:5556\" : \"udp://127.0.0.1:5556\";\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dish, \"udp://*:5556\"));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (radio, radio_url));\n\n    msleep (SETTLE_TIME);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, \"TV\"));\n\n    msg_send_expect_success (radio, \"TV\", \"Friends\");\n    msg_recv_cmp (dish, \"TV\", \"Friends\");\n\n    test_context_socket_close (dish);\n    test_context_socket_close (radio);\n}\nMAKE_TEST_V4V6 (test_radio_dish_udp)\n\n#define MCAST_IPV4 \"226.8.5.5\"\n#define MCAST_IPV6 \"ff02::7a65:726f:6df1:0a01\"\n\nstatic const char *mcast_url (int ipv6_)\n{\n    if (ipv6_) {\n        return \"udp://[\" MCAST_IPV6 \"]:5555\";\n    }\n    return \"udp://\" MCAST_IPV4 \":5555\";\n}\n\n//  OSX uses a different name for this socket option\n#ifndef IPV6_ADD_MEMBERSHIP\n#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP\n#endif\n\nunion sa_u\n{\n    struct sockaddr generic;\n    struct sockaddr_in ipv4;\n    struct sockaddr_in6 ipv6;\n};\n\n//  Test if multicast is available on this machine by attempting to\n//  send a receive a multicast datagram\nstatic bool is_multicast_available (int ipv6_)\n{\n    int family = ipv6_ ? AF_INET6 : AF_INET;\n    fd_t bind_sock = retired_fd;\n    fd_t send_sock = retired_fd;\n    int port = 5555;\n    bool success = false;\n    const char *msg = \"it works\";\n    char buf[32];\n    union sa_u any;\n    union sa_u mcast;\n    socklen_t sl;\n    int rc;\n\n    if (ipv6_) {\n        struct sockaddr_in6 *any_ipv6 = &any.ipv6;\n        struct sockaddr_in6 *mcast_ipv6 = &mcast.ipv6;\n\n        any_ipv6->sin6_family = AF_INET6;\n        any_ipv6->sin6_port = htons (port);\n        any_ipv6->sin6_flowinfo = 0;\n        any_ipv6->sin6_scope_id = 0;\n\n        rc = test_inet_pton (AF_INET6, \"::\", &any_ipv6->sin6_addr);\n        if (rc == 0) {\n            goto out;\n        }\n\n        *mcast_ipv6 = *any_ipv6;\n\n        rc = test_inet_pton (AF_INET6, MCAST_IPV6, &mcast_ipv6->sin6_addr);\n        if (rc == 0) {\n            goto out;\n        }\n\n        sl = sizeof (*any_ipv6);\n    } else {\n        struct sockaddr_in *any_ipv4 = &any.ipv4;\n        struct sockaddr_in *mcast_ipv4 = &mcast.ipv4;\n\n        any_ipv4->sin_family = AF_INET;\n        any_ipv4->sin_port = htons (port);\n\n        rc = test_inet_pton (AF_INET, \"0.0.0.0\", &any_ipv4->sin_addr);\n        if (rc == 0) {\n            goto out;\n        }\n\n        *mcast_ipv4 = *any_ipv4;\n\n        rc = test_inet_pton (AF_INET, MCAST_IPV4, &mcast_ipv4->sin_addr);\n        if (rc == 0) {\n            goto out;\n        }\n\n        sl = sizeof (*any_ipv4);\n    }\n\n    bind_sock = socket (family, SOCK_DGRAM, IPPROTO_UDP);\n    if (bind_sock < 0) {\n        goto out;\n    }\n\n    send_sock = socket (family, SOCK_DGRAM, IPPROTO_UDP);\n    if (bind_sock < 0) {\n        goto out;\n    }\n\n    rc = bind (bind_sock, &any.generic, sl);\n    if (rc < 0) {\n        goto out;\n    }\n\n    if (ipv6_) {\n        struct ipv6_mreq mreq;\n        const sockaddr_in6 *const mcast_ipv6 = &mcast.ipv6;\n\n        mreq.ipv6mr_multiaddr = mcast_ipv6->sin6_addr;\n        mreq.ipv6mr_interface = 0;\n\n        rc = setsockopt (bind_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,\n                         as_setsockopt_opt_t (&mreq), sizeof (mreq));\n        if (rc < 0) {\n            goto out;\n        }\n\n        int loop = 1;\n        rc = setsockopt (send_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,\n                         as_setsockopt_opt_t (&loop), sizeof (loop));\n        if (rc < 0) {\n            goto out;\n        }\n    } else {\n        struct ip_mreq mreq;\n        const sockaddr_in *const mcast_ipv4 = &mcast.ipv4;\n\n        mreq.imr_multiaddr = mcast_ipv4->sin_addr;\n        mreq.imr_interface.s_addr = htonl (INADDR_ANY);\n\n        rc = setsockopt (bind_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,\n                         as_setsockopt_opt_t (&mreq), sizeof (mreq));\n        if (rc < 0) {\n            goto out;\n        }\n\n        int loop = 1;\n        rc = setsockopt (send_sock, IPPROTO_IP, IP_MULTICAST_LOOP,\n                         as_setsockopt_opt_t (&loop), sizeof (loop));\n        if (rc < 0) {\n            goto out;\n        }\n    }\n\n    msleep (SETTLE_TIME);\n\n#ifdef ZMQ_HAVE_WINDOWS\n    rc = sendto (send_sock, msg, static_cast<int> (strlen (msg)), 0,\n                 &mcast.generic, sl);\n#else\n    rc = sendto (send_sock, msg, strlen (msg), 0, &mcast.generic, sl);\n#endif\n    if (rc < 0) {\n        goto out;\n    }\n\n    msleep (SETTLE_TIME);\n\n#ifdef ZMQ_HAVE_WINDOWS\n    rc = recvfrom (bind_sock, buf, sizeof (buf) - 1, 0, NULL, 0);\n#else\n    rc = recvfrom (bind_sock, buf, sizeof (buf) - 1, MSG_DONTWAIT, NULL, 0);\n#endif\n    if (rc < 0) {\n        goto out;\n    }\n\n    buf[rc] = '\\0';\n\n    success = (strcmp (msg, buf) == 0);\n\nout:\n    if (bind_sock >= 0) {\n        close (bind_sock);\n    }\n\n    if (send_sock >= 0) {\n        close (send_sock);\n    }\n\n    return success;\n}\n\nstatic void ignore_if_unavailable (int ipv6_)\n{\n    if (ipv6_ && !is_ipv6_available ())\n        TEST_IGNORE_MESSAGE (\"No IPV6 available\");\n    if (!is_multicast_available (ipv6_))\n        TEST_IGNORE_MESSAGE (\"No multicast available\");\n}\n\nstatic void test_radio_dish_mcast (int ipv6_)\n{\n    ignore_if_unavailable (ipv6_);\n\n    void *radio = test_context_socket (ZMQ_RADIO);\n    void *dish = test_context_socket (ZMQ_DISH);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (radio, ZMQ_IPV6, &ipv6_, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));\n\n    const char *url = mcast_url (ipv6_);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dish, url));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (radio, url));\n\n    msleep (SETTLE_TIME);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, \"TV\"));\n\n    msg_send_expect_success (radio, \"TV\", \"Friends\");\n    msg_recv_cmp (dish, \"TV\", \"Friends\");\n\n    test_context_socket_close (dish);\n    test_context_socket_close (radio);\n}\nMAKE_TEST_V4V6 (test_radio_dish_mcast)\n\nstatic void test_radio_dish_no_loop (int ipv6_)\n{\n#ifdef _WIN32\n    TEST_IGNORE_MESSAGE (\n      \"ZMQ_MULTICAST_LOOP=false does not appear to work on Windows (TODO)\");\n#endif\n    ignore_if_unavailable (ipv6_);\n\n    void *radio = test_context_socket (ZMQ_RADIO);\n    void *dish = test_context_socket (ZMQ_DISH);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (radio, ZMQ_IPV6, &ipv6_, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));\n\n    //  Disable multicast loop for radio\n    int loop = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (radio, ZMQ_MULTICAST_LOOP, &loop, sizeof (int)));\n\n    const char *url = mcast_url (ipv6_);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dish, url));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (radio, url));\n\n    msleep (SETTLE_TIME);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, \"TV\"));\n\n    msg_send_expect_success (radio, \"TV\", \"Friends\");\n\n    // Looping is disabled, we shouldn't receive anything\n    msleep (SETTLE_TIME);\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (dish, NULL, 0, ZMQ_DONTWAIT));\n\n    test_context_socket_close (dish);\n    test_context_socket_close (radio);\n}\nMAKE_TEST_V4V6 (test_radio_dish_no_loop)\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_leave_unjoined_fails);\n    RUN_TEST (test_join_too_long_fails);\n    RUN_TEST (test_long_group);\n    RUN_TEST (test_join_twice_fails);\n    RUN_TEST (test_radio_bind_fails_ipv4);\n    RUN_TEST (test_radio_bind_fails_ipv6);\n    RUN_TEST (test_dish_connect_fails_ipv4);\n    RUN_TEST (test_dish_connect_fails_ipv6);\n    RUN_TEST (test_radio_dish_tcp_poll_ipv4);\n    RUN_TEST (test_radio_dish_tcp_poll_ipv6);\n    RUN_TEST (test_radio_dish_udp_ipv4);\n    RUN_TEST (test_radio_dish_udp_ipv6);\n\n    RUN_TEST (test_radio_dish_mcast_ipv4);\n    RUN_TEST (test_radio_dish_no_loop_ipv4);\n\n    RUN_TEST (test_radio_dish_mcast_ipv6);\n    RUN_TEST (test_radio_dish_no_loop_ipv6);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_rebind_ipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_rebind_ipc ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n    make_random_ipc_endpoint (my_endpoint);\n\n    void *sb0 = test_context_socket (ZMQ_PUSH);\n    void *sb1 = test_context_socket (ZMQ_PUSH);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb0, my_endpoint));\n\n    void *sc = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));\n\n    send_string_expect_success (sb0, \"42\", 0);\n    recv_string_expect_success (sc, \"42\", 0);\n\n    test_context_socket_close (sb0);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb1, my_endpoint));\n\n    send_string_expect_success (sb1, \"42\", 0);\n    recv_string_expect_success (sc, \"42\", 0);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb1);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_rebind_ipc);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_reconnect_ivl.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_reconnect_ivl_against_pair_socket (const char *my_endpoint_,\n                                             void *sb_)\n{\n    void *sc = test_context_socket (ZMQ_PAIR);\n    int interval = -1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_RECONNECT_IVL, &interval, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_));\n\n    bounce (sb_, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb_, my_endpoint_));\n\n    expect_bounce_fail (sb_, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb_, my_endpoint_));\n\n    expect_bounce_fail (sb_, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_));\n\n    bounce (sb_, sc);\n\n    test_context_socket_close (sc);\n}\n\n#if defined(ZMQ_HAVE_IPC) && !defined(ZMQ_HAVE_GNU)\nvoid test_reconnect_ivl_ipc (void)\n{\n    char my_endpoint[256];\n    make_random_ipc_endpoint (my_endpoint);\n\n    void *sb = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, my_endpoint));\n\n    test_reconnect_ivl_against_pair_socket (my_endpoint, sb);\n    test_context_socket_close (sb);\n}\n#endif\n\nvoid test_reconnect_ivl_tcp (bind_function_t bind_function_)\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *sb = test_context_socket (ZMQ_PAIR);\n    bind_function_ (sb, my_endpoint, sizeof my_endpoint);\n\n    test_reconnect_ivl_against_pair_socket (my_endpoint, sb);\n    test_context_socket_close (sb);\n}\n\nvoid test_reconnect_ivl_tcp_ipv4 ()\n{\n    test_reconnect_ivl_tcp (bind_loopback_ipv4);\n}\n\nvoid test_reconnect_ivl_tcp_ipv6 ()\n{\n    if (is_ipv6_available ()) {\n        zmq_ctx_set (get_test_context (), ZMQ_IPV6, 1);\n        test_reconnect_ivl_tcp (bind_loopback_ipv6);\n    }\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n#if defined(ZMQ_HAVE_IPC) && !defined(ZMQ_HAVE_GNU)\n    RUN_TEST (test_reconnect_ivl_ipc);\n#endif\n    RUN_TEST (test_reconnect_ivl_tcp_ipv4);\n    RUN_TEST (test_reconnect_ivl_tcp_ipv6);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_reconnect_options.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n#include <assert.h>\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n#include \"testutil_monitoring.hpp\"\n\n#include <unity.h>\n\n// test behavior with (mostly) default values\nvoid reconnect_default ()\n{\n    // setup pub socket\n    void *pub = test_context_socket (ZMQ_PUB);\n    //  Bind pub socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));\n\n    // setup sub socket\n    void *sub = test_context_socket (ZMQ_SUB);\n    //  Monitor all events on sub\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_socket_monitor (sub, \"inproc://monitor-sub\", ZMQ_EVENT_ALL));\n    //  Create socket for collecting monitor events\n    void *sub_mon = test_context_socket (ZMQ_PAIR);\n    //  Connect so they'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, \"inproc://monitor-sub\"));\n    // set reconnect interval so only a single reconnect is tried\n    int interval = 60 * 1000;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_RECONNECT_IVL, &interval, sizeof (interval)));\n    // connect to pub\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, ENDPOINT_0));\n\n    //  confirm that we get following events\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n\n    // close the pub socket\n    test_context_socket_close_zero_linger (pub);\n\n    //  confirm that we get following events\n    expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_RETRIED);\n\n    // ZMQ_EVENT_CONNECT_RETRIED should be last event, because of timeout set above\n    int event;\n    char *event_address;\n    int rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,\n                                             2 * 1000);\n    assert (rc == -1);\n    LIBZMQ_UNUSED (rc);\n\n    //  Close sub\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (sub);\n\n    //  Close monitor\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (sub_mon);\n}\n\n\n// test successful reconnect\nvoid reconnect_success ()\n{\n    // setup pub socket\n    void *pub = test_context_socket (ZMQ_PUB);\n    //  Bind pub socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));\n\n    // setup sub socket\n    void *sub = test_context_socket (ZMQ_SUB);\n    //  Monitor all events on sub\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_socket_monitor (sub, \"inproc://monitor-sub\", ZMQ_EVENT_ALL));\n    //  Create socket for collecting monitor events\n    void *sub_mon = test_context_socket (ZMQ_PAIR);\n    //  Connect so they'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, \"inproc://monitor-sub\"));\n    // set reconnect interval so only a single reconnect is tried\n    int interval = 1 * 1000;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_RECONNECT_IVL, &interval, sizeof (interval)));\n    // connect to pub\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, ENDPOINT_0));\n\n    //  confirm that we get following events\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n\n    // close the pub socket\n    test_context_socket_close_zero_linger (pub);\n\n    //  confirm that we get following events\n    expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_RETRIED);\n\n    // ZMQ_EVENT_CONNECT_RETRIED should be last event, because of timeout set above\n    int event;\n    char *event_address;\n    int rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,\n                                             SETTLE_TIME);\n    assert (rc == -1);\n    LIBZMQ_UNUSED (rc);\n\n    //  Now re-bind pub socket and wait for re-connect\n    pub = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));\n    msleep (SETTLE_TIME);\n\n    //  confirm that we get following events\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n\n    // ZMQ_EVENT_HANDSHAKE_SUCCEEDED should be last event\n    rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,\n                                         SETTLE_TIME);\n    assert (rc == -1);\n\n    //  Close sub\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (sub);\n    test_context_socket_close_zero_linger (pub);\n\n    //  Close monitor\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (sub_mon);\n}\n\n\n#ifdef ZMQ_BUILD_DRAFT_API\n// test stopping reconnect on connection refused\nvoid reconnect_stop_on_refused ()\n{\n    // setup pub socket\n    void *pub = test_context_socket (ZMQ_PUB);\n    //  Bind pub socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));\n\n    // setup sub socket\n    void *sub = test_context_socket (ZMQ_SUB);\n    //  Monitor all events on sub\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_socket_monitor (sub, \"inproc://monitor-sub\", ZMQ_EVENT_ALL));\n    //  Create socket for collecting monitor events\n    void *sub_mon = test_context_socket (ZMQ_PAIR);\n    //  Connect so they'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, \"inproc://monitor-sub\"));\n    // set option to stop reconnecting on error\n    int stopReconnectOnError = ZMQ_RECONNECT_STOP_CONN_REFUSED;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_RECONNECT_STOP,\n                                               &stopReconnectOnError,\n                                               sizeof (stopReconnectOnError)));\n    // connect to pub\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, ENDPOINT_0));\n\n    //  confirm that we get following events\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n\n    // close the pub socket\n    test_context_socket_close_zero_linger (pub);\n\n    //  confirm that we get following events\n    expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_RETRIED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CLOSED);\n\n    // ZMQ_EVENT_CLOSED should be last event, because of ZMQ_RECONNECT_STOP set above\n    int event = 0;\n    char *event_address;\n    int rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,\n                                             2 * 1000);\n    int limit = 0;\n    while ((rc != -1) && (++limit < 1000)) {\n        print_unexpected_event_stderr (event, rc, 0, -1);\n        rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,\n                                             2 * 1000);\n    }\n\n    //  Close sub\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (sub);\n\n    //  Close monitor\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (sub_mon);\n}\n#endif\n\n#ifdef ZMQ_BUILD_DRAFT_API\n// test stopping reconnect on connection refused\nvoid reconnect_stop_on_handshake_failed ()\n{\n    char bind_address[MAX_SOCKET_STRING];\n    size_t addr_length = sizeof (bind_address);\n    void *dummy = test_context_socket (ZMQ_STREAM);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dummy, \"tcp://127.0.0.1:0\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (dummy, ZMQ_LAST_ENDPOINT, bind_address, &addr_length));\n\n    // setup sub socket\n    void *sub = test_context_socket (ZMQ_SUB);\n    //  Monitor all events on sub\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_socket_monitor (sub, \"inproc://monitor-sub\", ZMQ_EVENT_ALL));\n    //  Create socket for collecting monitor events\n    void *sub_mon = test_context_socket (ZMQ_PAIR);\n    //  Connect so they'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, \"inproc://monitor-sub\"));\n    // set handshake interval (i.e., timeout) to a more reasonable value\n    int handshakeInterval = 1000;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      sub, ZMQ_HANDSHAKE_IVL, &handshakeInterval, sizeof (handshakeInterval)));\n    // set option to stop reconnecting on failed handshake\n    int stopReconnectOnError = ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_RECONNECT_STOP,\n                                               &stopReconnectOnError,\n                                               sizeof (stopReconnectOnError)));\n    // connect to dummy stream socket above\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, bind_address));\n\n#if 1\n    // ZMQ_EVENT_DISCONNECTED should be last event, because of ZMQ_RECONNECT_STOP set above\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);\n#else\n    print_events (sub_mon, 2 * 1000, 1000);\n#endif\n\n    //  Close sub\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (sub);\n    test_context_socket_close_zero_linger (dummy);\n\n    //  Close monitor\n    //  TODO why does this use zero_linger?\n    test_context_socket_close_zero_linger (sub_mon);\n}\n#endif\n\n#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_HAVE_IPC)\n// test stopping reconnect after disconnect\nvoid reconnect_stop_after_disconnect ()\n{\n    // Setup sub socket\n    void *sub = test_context_socket (ZMQ_SUB);\n    // Monitor all events on sub\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_socket_monitor (sub, \"inproc://monitor-sub\", ZMQ_EVENT_ALL));\n    // Create socket for collecting monitor events\n    void *sub_mon = test_context_socket (ZMQ_PAIR);\n    // Connect so they'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, \"inproc://monitor-sub\"));\n    // Set option to stop reconnecting after disconnect\n    int stopReconnectAfterDisconnect = ZMQ_RECONNECT_STOP_AFTER_DISCONNECT;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_RECONNECT_STOP, &stopReconnectAfterDisconnect,\n                      sizeof (stopReconnectAfterDisconnect)));\n\n    // Connect to a dummy that cannot be connected\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"ipc://@dummy\"));\n\n    // Confirm that connect failed and reconnect\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CLOSED);\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_RETRIED);\n\n    // Disconnect the sub socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sub, \"ipc://@dummy\"));\n\n    // Confirm that connect failed and will not reconnect\n    expect_monitor_event (sub_mon, ZMQ_EVENT_CLOSED);\n\n    // Close sub\n    test_context_socket_close_zero_linger (sub);\n\n    // Close monitor\n    test_context_socket_close_zero_linger (sub_mon);\n}\n#endif\n\nvoid setUp ()\n{\n    setup_test_context ();\n}\n\nvoid tearDown ()\n{\n    teardown_test_context ();\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n\n    RUN_TEST (reconnect_default);\n    RUN_TEST (reconnect_success);\n#ifdef ZMQ_BUILD_DRAFT_API\n    RUN_TEST (reconnect_stop_on_refused);\n    RUN_TEST (reconnect_stop_on_handshake_failed);\n#endif\n#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_HAVE_IPC)\n    RUN_TEST (reconnect_stop_after_disconnect);\n#endif\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_req_correlate.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_req_correlate ()\n{\n    void *req = test_context_socket (ZMQ_REQ);\n    void *router = test_context_socket (ZMQ_ROUTER);\n\n    int enabled = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (req, ZMQ_REQ_CORRELATE, &enabled, sizeof (int)));\n\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, my_endpoint));\n\n    // Send a multi-part request.\n    s_send_seq (req, \"ABC\", \"DEF\", SEQ_END);\n\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n\n    // Receive peer routing id\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, router, 0));\n    TEST_ASSERT_GREATER_THAN_INT (0, zmq_msg_size (&msg));\n    zmq_msg_t peer_id_msg;\n    zmq_msg_init (&peer_id_msg);\n    zmq_msg_copy (&peer_id_msg, &msg);\n\n    int more = 0;\n    size_t more_size = sizeof (more);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (router, ZMQ_RCVMORE, &more, &more_size));\n    TEST_ASSERT_TRUE (more);\n\n    // Receive request id 1\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, router, 0));\n    TEST_ASSERT_EQUAL_UINT (sizeof (uint32_t), zmq_msg_size (&msg));\n    const uint32_t req_id = *static_cast<uint32_t *> (zmq_msg_data (&msg));\n    zmq_msg_t req_id_msg;\n    zmq_msg_init (&req_id_msg);\n    zmq_msg_copy (&req_id_msg, &msg);\n\n    more = 0;\n    more_size = sizeof (more);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (router, ZMQ_RCVMORE, &more, &more_size));\n    TEST_ASSERT_TRUE (more);\n\n    // Receive the rest.\n    s_recv_seq (router, 0, \"ABC\", \"DEF\", SEQ_END);\n\n    uint32_t bad_req_id = req_id + 1;\n\n    // Send back a bad reply: wrong req id, 0, data\n    zmq_msg_copy (&msg, &peer_id_msg);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&msg, router, ZMQ_SNDMORE));\n    zmq_msg_init_data (&msg, &bad_req_id, sizeof (uint32_t), NULL, NULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&msg, router, ZMQ_SNDMORE));\n    s_send_seq (router, 0, \"DATA\", SEQ_END);\n\n    // Send back a good reply: good req id, 0, data\n    zmq_msg_copy (&msg, &peer_id_msg);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&msg, router, ZMQ_SNDMORE));\n    zmq_msg_copy (&msg, &req_id_msg);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&msg, router, ZMQ_SNDMORE));\n    s_send_seq (router, 0, \"GHI\", SEQ_END);\n\n    // Receive reply. If bad reply got through, we wouldn't see\n    // this particular data.\n    s_recv_seq (req, \"GHI\", SEQ_END);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&peer_id_msg));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&req_id_msg));\n\n    test_context_socket_close_zero_linger (req);\n    test_context_socket_close_zero_linger (router);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_req_correlate);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_req_relaxed.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <unity.h>\n\nconst size_t services = 5;\n\nvoid *req;\nvoid *rep[services];\n\nvoid setUp ()\n{\n    setup_test_context ();\n\n    char my_endpoint[MAX_SOCKET_STRING];\n    req = test_context_socket (ZMQ_REQ);\n\n    int enabled = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (req, ZMQ_REQ_RELAXED, &enabled, sizeof (int)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (req, ZMQ_REQ_CORRELATE, &enabled, sizeof (int)));\n\n    bind_loopback_ipv4 (req, my_endpoint, sizeof (my_endpoint));\n\n    for (size_t peer = 0; peer < services; peer++) {\n        rep[peer] = test_context_socket (ZMQ_REP);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rep[peer], my_endpoint));\n\n        //  These tests require strict ordering, so wait for the connections to\n        //  happen before opening the next, so that messages flow in the\n        //  expected direction\n        msleep (SETTLE_TIME);\n    }\n}\n\nvoid tearDown ()\n{\n    test_context_socket_close_zero_linger (req);\n    for (size_t peer = 0; peer < services; peer++)\n        test_context_socket_close_zero_linger (rep[peer]);\n\n    teardown_test_context ();\n}\n\nstatic void bounce (void *socket_)\n{\n    int more;\n    size_t more_size = sizeof (more);\n    do {\n        zmq_msg_t recv_part, sent_part;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&recv_part));\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&recv_part, socket_, 0));\n\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_getsockopt (socket_, ZMQ_RCVMORE, &more, &more_size));\n\n        zmq_msg_init (&sent_part);\n        zmq_msg_copy (&sent_part, &recv_part);\n\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_msg_send (&sent_part, socket_, more ? ZMQ_SNDMORE : 0));\n\n        zmq_msg_close (&recv_part);\n    } while (more);\n}\n\nstatic int get_events (void *socket_)\n{\n    int events;\n    size_t events_size = sizeof (events);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket_, ZMQ_EVENTS, &events, &events_size));\n    return events;\n}\n\nvoid test_case_1 ()\n{\n    //  Case 1: Second send() before a reply arrives in a pipe.\n\n    int events = get_events (req);\n    TEST_ASSERT_EQUAL_INT (ZMQ_POLLOUT, events);\n\n    //  Send a request, ensure it arrives, don't send a reply\n    s_send_seq (req, \"A\", \"B\", SEQ_END);\n    s_recv_seq (rep[0], \"A\", \"B\", SEQ_END);\n\n    events = get_events (req);\n    TEST_ASSERT_EQUAL_INT (ZMQ_POLLOUT, events);\n\n    //  Send another request on the REQ socket\n    s_send_seq (req, \"C\", \"D\", SEQ_END);\n    s_recv_seq (rep[1], \"C\", \"D\", SEQ_END);\n\n    events = get_events (req);\n    TEST_ASSERT_EQUAL_INT (ZMQ_POLLOUT, events);\n\n    //  Send a reply to the first request - that should be discarded by the REQ\n    s_send_seq (rep[0], \"WRONG\", SEQ_END);\n\n    //  Send the expected reply\n    s_send_seq (rep[1], \"OK\", SEQ_END);\n    s_recv_seq (req, \"OK\", SEQ_END);\n\n    //  Another standard req-rep cycle, just to check\n    s_send_seq (req, \"E\", SEQ_END);\n    s_recv_seq (rep[2], \"E\", SEQ_END);\n    s_send_seq (rep[2], \"F\", \"G\", SEQ_END);\n    s_recv_seq (req, \"F\", \"G\", SEQ_END);\n}\n\nvoid test_case_2 ()\n{\n    //  Case 2: Second send() after a reply is already in a pipe on the REQ.\n\n    // TODO instead of rerunning the previous test cases, only do the relevant parts (or change the peer)\n    test_case_1 ();\n\n    //  Send a request, ensure it arrives, send a reply\n    s_send_seq (req, \"H\", SEQ_END);\n    s_recv_seq (rep[3], \"H\", SEQ_END);\n    s_send_seq (rep[3], \"BAD\", SEQ_END);\n\n    //  Wait for message to be there.\n    msleep (SETTLE_TIME);\n\n    //  Without receiving that reply, send another request on the REQ socket\n    s_send_seq (req, \"I\", SEQ_END);\n    s_recv_seq (rep[4], \"I\", SEQ_END);\n\n    //  Send the expected reply\n    s_send_seq (rep[4], \"GOOD\", SEQ_END);\n    s_recv_seq (req, \"GOOD\", SEQ_END);\n}\n\nvoid test_case_3 ()\n{\n    //  Case 3: Check issue #1690. Two send() in a row should not close the\n    //  communication pipes. For example pipe from req to rep[0] should not be\n    //  closed after executing Case 1. So rep[0] should be the next to receive,\n    //  not rep[1].\n\n    // TODO instead of rerunning the previous test cases, only do the relevant parts (or change the peer)\n    test_case_2 ();\n\n    s_send_seq (req, \"J\", SEQ_END);\n    s_recv_seq (rep[0], \"J\", SEQ_END);\n}\n\nvoid test_case_4 ()\n{\n    // TODO this test case does not use the sockets from setUp\n\n    //  Case 4: Check issue #1695. As messages may pile up before a responder\n    //  is available, we check that responses to messages other than the last\n    //  sent one are correctly discarded by the REQ pipe\n\n    //  Setup REQ socket as client\n    void *req = test_context_socket (ZMQ_REQ);\n\n    int enabled = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (req, ZMQ_REQ_RELAXED, &enabled, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (req, ZMQ_REQ_CORRELATE, &enabled, sizeof (int)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, ENDPOINT_0));\n\n    //  Setup ROUTER socket as server but do not bind it just yet\n    void *router = test_context_socket (ZMQ_ROUTER);\n\n    //  Send two requests\n    s_send_seq (req, \"TO_BE_DISCARDED\", SEQ_END);\n    s_send_seq (req, \"TO_BE_ANSWERED\", SEQ_END);\n\n    //  Bind server allowing it to receive messages\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router, ENDPOINT_0));\n\n    //  Read the two messages and send them back as is\n    bounce (router);\n    bounce (router);\n\n    //  Read the expected correlated reply. As the ZMQ_REQ_CORRELATE is active,\n    //  the expected answer is \"TO_BE_ANSWERED\", not \"TO_BE_DISCARDED\".\n    s_recv_seq (req, \"TO_BE_ANSWERED\", SEQ_END);\n\n    test_context_socket_close_zero_linger (req);\n    test_context_socket_close_zero_linger (router);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_case_1);\n    RUN_TEST (test_case_2);\n    RUN_TEST (test_case_3);\n    RUN_TEST (test_case_4);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_reqrep_device.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_roundtrip ()\n{\n    char endpoint1[MAX_SOCKET_STRING];\n    char endpoint2[MAX_SOCKET_STRING];\n\n    //  Create a req/rep device.\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    bind_loopback_ipv4 (dealer, endpoint1, sizeof (endpoint1));\n\n    void *router = test_context_socket (ZMQ_ROUTER);\n    bind_loopback_ipv4 (router, endpoint2, sizeof (endpoint2));\n\n    //  Create a worker.\n    void *rep = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rep, endpoint1));\n\n    //  Create a client.\n    void *req = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, endpoint2));\n\n    //  Send a request.\n    send_string_expect_success (req, \"ABC\", ZMQ_SNDMORE);\n    send_string_expect_success (req, \"DEF\", 0);\n\n    //  Pass the request through the device.\n    for (int i = 0; i != 4; i++) {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, router, 0));\n        int rcvmore;\n        size_t sz = sizeof (rcvmore);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_getsockopt (router, ZMQ_RCVMORE, &rcvmore, &sz));\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_msg_send (&msg, dealer, rcvmore ? ZMQ_SNDMORE : 0));\n    }\n\n    //  Receive the request.\n    recv_string_expect_success (rep, \"ABC\", 0);\n    int rcvmore;\n    size_t sz = sizeof (rcvmore);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (rep, ZMQ_RCVMORE, &rcvmore, &sz));\n    TEST_ASSERT_TRUE (rcvmore);\n    recv_string_expect_success (rep, \"DEF\", 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (rep, ZMQ_RCVMORE, &rcvmore, &sz));\n    TEST_ASSERT_FALSE (rcvmore);\n\n    //  Send the reply.\n    send_string_expect_success (rep, \"GHI\", ZMQ_SNDMORE);\n    send_string_expect_success (rep, \"JKL\", 0);\n\n    //  Pass the reply through the device.\n    for (int i = 0; i != 4; i++) {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, dealer, 0));\n        int rcvmore;\n        size_t sz = sizeof (rcvmore);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_getsockopt (dealer, ZMQ_RCVMORE, &rcvmore, &sz));\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_msg_send (&msg, router, rcvmore ? ZMQ_SNDMORE : 0));\n    }\n\n    //  Receive the reply.\n    recv_string_expect_success (req, \"GHI\", 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (req, ZMQ_RCVMORE, &rcvmore, &sz));\n    TEST_ASSERT_TRUE (rcvmore);\n    recv_string_expect_success (req, \"JKL\", 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (req, ZMQ_RCVMORE, &rcvmore, &sz));\n    TEST_ASSERT_FALSE (rcvmore);\n\n    //  Clean up.\n    test_context_socket_close (req);\n    test_context_socket_close (rep);\n    test_context_socket_close (router);\n    test_context_socket_close (dealer);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_reqrep_device_tipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n// TODO this is heavily duplicated with test_reqrep_device.cpp\nvoid test_roundtrip ()\n{\n    //  Create a req/rep device.\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dealer, \"tipc://{5560,0,0}\"));\n    void *router = test_context_socket (ZMQ_ROUTER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router, \"tipc://{5561,0,0}\"));\n\n    //  Create a worker.\n    void *rep = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rep, \"tipc://{5560,0}@0.0.0\"));\n\n    //  Create a client.\n    void *req = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, \"tipc://{5561,0}@0.0.0\"));\n\n    //  Send a request.\n    send_string_expect_success (req, \"ABC\", ZMQ_SNDMORE);\n    send_string_expect_success (req, \"DEF\", 0);\n\n    //  Pass the request through the device.\n    for (int i = 0; i != 4; i++) {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, router, 0));\n        int rcvmore;\n        size_t sz = sizeof (rcvmore);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_getsockopt (router, ZMQ_RCVMORE, &rcvmore, &sz));\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_msg_send (&msg, dealer, rcvmore ? ZMQ_SNDMORE : 0));\n    }\n\n    //  Receive the request.\n    recv_string_expect_success (rep, \"ABC\", 0);\n    int rcvmore;\n    size_t sz = sizeof (rcvmore);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (rep, ZMQ_RCVMORE, &rcvmore, &sz));\n    TEST_ASSERT_TRUE (rcvmore);\n    recv_string_expect_success (rep, \"DEF\", 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (rep, ZMQ_RCVMORE, &rcvmore, &sz));\n    TEST_ASSERT_FALSE (rcvmore);\n\n    //  Send the reply.\n    send_string_expect_success (rep, \"GHI\", ZMQ_SNDMORE);\n    send_string_expect_success (rep, \"JKL\", 0);\n\n    //  Pass the reply through the device.\n    for (int i = 0; i != 4; i++) {\n        zmq_msg_t msg;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, dealer, 0));\n        int rcvmore;\n        size_t sz = sizeof (rcvmore);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_getsockopt (dealer, ZMQ_RCVMORE, &rcvmore, &sz));\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_msg_send (&msg, router, rcvmore ? ZMQ_SNDMORE : 0));\n    }\n\n    //  Receive the reply.\n    recv_string_expect_success (req, \"GHI\", 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (req, ZMQ_RCVMORE, &rcvmore, &sz));\n    TEST_ASSERT_TRUE (rcvmore);\n    recv_string_expect_success (req, \"JKL\", 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (req, ZMQ_RCVMORE, &rcvmore, &sz));\n    TEST_ASSERT_FALSE (rcvmore);\n\n    //  Clean up.\n    test_context_socket_close (req);\n    test_context_socket_close (rep);\n    test_context_socket_close (router);\n    test_context_socket_close (dealer);\n}\n\nint main ()\n{\n    if (!is_tipc_available ()) {\n        printf (\"TIPC environment unavailable, skipping test\\n\");\n        return 77;\n    }\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_reqrep_inproc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_roundtrip ()\n{\n    void *sb = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"inproc://a\"));\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, \"inproc://a\"));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_reqrep_ipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_leak ()\n{\n    char my_endpoint[256];\n\n    void *sb = test_context_socket (ZMQ_REP);\n    bind_loopback_ipc (sb, my_endpoint, sizeof my_endpoint);\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));\n\n    static const char leakymsg[] = \"leakymsg\";\n    send_string_expect_success (sc, leakymsg, 0);\n\n    char *buf = s_recv (sb);\n    free (buf);\n\n    test_context_socket_close (sc);\n\n    msleep (SETTLE_TIME);\n\n    send_string_expect_success (sb, leakymsg, 0);\n\n    test_context_socket_close (sb);\n}\n\nvoid test_simple (void)\n{\n    char my_endpoint[256];\n\n    void *sb = test_context_socket (ZMQ_REP);\n    bind_loopback_ipc (sb, my_endpoint, sizeof my_endpoint);\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_simple);\n    RUN_TEST (test_leak);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_reqrep_tcp.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_single_connect (int ipv6_)\n{\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *sb = test_context_socket (ZMQ_REP);\n    bind_loopback (sb, ipv6_, my_endpoint, len);\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_IPV6, &ipv6_, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));\n\n    bounce (sb, sc);\n\n    // the sockets are disconnected and unbound explicitly in this test case\n    // to check that this can be done successfully with the expected\n    // endpoints/addresses\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, my_endpoint));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb, my_endpoint));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid make_connect_address (char *connect_address_,\n                           const int ipv6_,\n                           const int port_,\n                           const char *bind_address_)\n{\n    if (ipv6_)\n        snprintf (connect_address_, 30 * sizeof (char), \"tcp://[::1]:%i;%s\",\n                  port_, strrchr (bind_address_, '/') + 1);\n    else\n        snprintf (connect_address_, 38 * sizeof (char), \"tcp://127.0.0.1:%i;%s\",\n                  port_, strrchr (bind_address_, '/') + 1);\n}\n\nvoid test_multi_connect (int ipv6_)\n{\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint_0[MAX_SOCKET_STRING];\n    char my_endpoint_1[MAX_SOCKET_STRING];\n    char my_endpoint_2[MAX_SOCKET_STRING];\n    char my_endpoint_3[MAX_SOCKET_STRING * 2];\n\n    void *sb0 = test_context_socket (ZMQ_REP);\n    bind_loopback (sb0, ipv6_, my_endpoint_0, len);\n\n    void *sb1 = test_context_socket (ZMQ_REP);\n    bind_loopback (sb1, ipv6_, my_endpoint_1, len);\n\n    void *sb2 = test_context_socket (ZMQ_REP);\n    bind_loopback (sb2, ipv6_, my_endpoint_2, len);\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_IPV6, &ipv6_, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_1));\n    make_connect_address (my_endpoint_3, ipv6_, 5564, my_endpoint_2);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_3));\n\n    bounce (sb0, sc);\n    bounce (sb1, sc);\n    bounce (sb2, sc);\n    bounce (sb0, sc);\n    bounce (sb1, sc);\n    bounce (sb2, sc);\n    bounce (sb0, sc);\n\n    /// see comment on zmq_disconnect/zmq_unbind in test_single_connect\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, my_endpoint_0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, my_endpoint_3));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, my_endpoint_1));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb0, my_endpoint_0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb1, my_endpoint_1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb2, my_endpoint_2));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb0);\n    test_context_socket_close (sb1);\n    test_context_socket_close (sb2);\n}\n\nvoid test_multi_connect_same_port (int ipv6_)\n{\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint_0[MAX_SOCKET_STRING];\n    char my_endpoint_1[MAX_SOCKET_STRING];\n    char my_endpoint_2[MAX_SOCKET_STRING * 2];\n    char my_endpoint_3[MAX_SOCKET_STRING * 2];\n    char my_endpoint_4[MAX_SOCKET_STRING * 2];\n    char my_endpoint_5[MAX_SOCKET_STRING * 2];\n\n    void *sb0 = test_context_socket (ZMQ_REP);\n    bind_loopback (sb0, ipv6_, my_endpoint_0, len);\n\n    void *sb1 = test_context_socket (ZMQ_REP);\n    bind_loopback (sb1, ipv6_, my_endpoint_1, len);\n\n    void *sc0 = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc0, ZMQ_IPV6, &ipv6_, sizeof (int)));\n    make_connect_address (my_endpoint_2, ipv6_, 5564, my_endpoint_0);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc0, my_endpoint_2));\n    make_connect_address (my_endpoint_3, ipv6_, 5565, my_endpoint_1);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc0, my_endpoint_3));\n\n    void *sc1 = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc1, ZMQ_IPV6, &ipv6_, sizeof (int)));\n    make_connect_address (my_endpoint_4, ipv6_, 5565, my_endpoint_0);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc1, my_endpoint_4));\n    make_connect_address (my_endpoint_5, ipv6_, 5564, my_endpoint_1);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc1, my_endpoint_5));\n\n    bounce (sb0, sc0);\n    bounce (sb1, sc0);\n    bounce (sb0, sc1);\n    bounce (sb1, sc1);\n    bounce (sb0, sc0);\n    bounce (sb1, sc0);\n\n    /// see comment on zmq_disconnect/zmq_unbind in test_single_connect\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc1, my_endpoint_4));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc1, my_endpoint_5));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc0, my_endpoint_2));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc0, my_endpoint_3));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb0, my_endpoint_0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb1, my_endpoint_1));\n\n    test_context_socket_close (sc0);\n    test_context_socket_close (sc1);\n    test_context_socket_close (sb0);\n    test_context_socket_close (sb1);\n}\n\nvoid test_single_connect_ipv4 ()\n{\n    test_single_connect (false);\n}\n\nvoid test_multi_connect_ipv4 ()\n{\n    test_multi_connect (false);\n}\n\nvoid test_multi_connect_same_port_ipv4 ()\n{\n    test_multi_connect_same_port (false);\n}\n\nvoid test_single_connect_ipv6 ()\n{\n    test_single_connect (true);\n}\n\nvoid test_multi_connect_ipv6 ()\n{\n    test_multi_connect (true);\n}\n\nvoid test_multi_connect_same_port_ipv6 ()\n{\n    test_multi_connect_same_port (true);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_single_connect_ipv4);\n    RUN_TEST (test_multi_connect_ipv4);\n    RUN_TEST (test_multi_connect_same_port_ipv4);\n    RUN_TEST (test_single_connect_ipv6);\n    RUN_TEST (test_multi_connect_ipv6);\n    RUN_TEST (test_multi_connect_same_port_ipv6);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_reqrep_tipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_roundtrip ()\n{\n    void *sb = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"tipc://{5560,0,0}\"));\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, \"tipc://{5560,0}@0.0.0\"));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main (void)\n{\n    if (!is_tipc_available ()) {\n        printf (\"TIPC environment unavailable, skipping test\\n\");\n        return 77;\n    }\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_reqrep_vmci.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include <string>\n#include <sstream>\n#include <vmci_sockets.h>\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_reqrep_vmci ()\n{\n    unsigned int cid = VMCISock_GetLocalCID ();\n    if (cid == VMADDR_CID_ANY)\n        TEST_IGNORE_MESSAGE (\"VMCI environment unavailable, skipping test\");\n    std::stringstream s;\n    s << \"vmci://\" << cid << \":\" << 5560;\n    std::string endpoint = s.str ();\n\n    void *sb = test_context_socket (ZMQ_DEALER);\n    int rc = zmq_bind (sb, endpoint.c_str ());\n    if (rc < 0 && (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT))\n        TEST_IGNORE_MESSAGE (\"VMCI not supported\");\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n\n    void *sc = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint.c_str ()));\n\n    bounce (sb, sc);\n\n    test_context_socket_close_zero_linger (sc);\n    test_context_socket_close_zero_linger (sb);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_reqrep_vmci);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_reqrep_vsock.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string>\n#include <sstream>\n#include \"sys/socket.h\"\n#include \"linux/vm_sockets.h\"\n#include <sys/ioctl.h>\n#include <fcntl.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_reqrep_vsock ()\n{\n    unsigned int cid = VMADDR_CID_ANY;\n    int vsock = -1;\n\n    if ((vsock = open (\"/dev/vsock\", O_RDONLY, 0)) < 0) {\n        TEST_IGNORE_MESSAGE (\"failed to open /dev/vsock, skipping test\");\n    } else if (ioctl (vsock, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &cid) < 0) {\n        TEST_IGNORE_MESSAGE (\"failed to get local cid, skipping test\");\n    }\n\n    if (vsock >= 0) {\n        close (vsock);\n    }\n\n    if (cid == VMADDR_CID_ANY)\n        TEST_IGNORE_MESSAGE (\"vsock environment unavailable, skipping test\");\n\n    std::stringstream s;\n    s << \"vsock://\" << cid << \":\" << 5561;\n    std::string endpoint = s.str ();\n\n    void *sb = test_context_socket (ZMQ_DEALER);\n    int rc = zmq_bind (sb, endpoint.c_str ());\n    if (rc < 0 && (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT))\n        TEST_IGNORE_MESSAGE (\"VSOCK not supported\");\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n\n    void *sc = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint.c_str ()));\n\n    bounce (sb, sc);\n\n    test_context_socket_close_zero_linger (sc);\n    test_context_socket_close_zero_linger (sb);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_reqrep_vsock);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_router_handover.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_with_handover ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n    void *router = test_context_socket (ZMQ_ROUTER);\n    bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);\n\n    // Enable the handover flag\n    int handover = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_HANDOVER,\n                                               &handover, sizeof (handover)));\n\n    //  Create dealer called \"X\" and connect it to our router\n    void *dealer_one = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer_one, ZMQ_ROUTING_ID, \"X\", 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer_one, my_endpoint));\n\n    //  Get message from dealer to know when connection is ready\n    char buffer[255];\n    send_string_expect_success (dealer_one, \"Hello\", 0);\n\n    recv_string_expect_success (router, \"X\", 0);\n    recv_string_expect_success (router, \"Hello\", 0);\n\n    // Now create a second dealer that uses the same routing id\n    void *dealer_two = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer_two, ZMQ_ROUTING_ID, \"X\", 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer_two, my_endpoint));\n\n    //  Get message from dealer to know when connection is ready\n    send_string_expect_success (dealer_two, \"Hello\", 0);\n\n    recv_string_expect_success (router, \"X\", 0);\n    recv_string_expect_success (router, \"Hello\", 0);\n\n    //  Send a message to 'X' routing id. This should be delivered\n    //  to the second dealer, instead of the first because of the handover.\n    send_string_expect_success (router, \"X\", ZMQ_SNDMORE);\n    send_string_expect_success (router, \"Hello\", 0);\n\n    //  Ensure that the first dealer doesn't receive the message\n    //  but the second one does\n    const int timeout = SETTLE_TIME;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer_one, ZMQ_RCVTIMEO, &timeout, sizeof timeout));\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (dealer_one, buffer, 255, 0));\n\n    recv_string_expect_success (dealer_two, \"Hello\", 0);\n\n    test_context_socket_close (router);\n    test_context_socket_close (dealer_one);\n    test_context_socket_close (dealer_two);\n}\n\nvoid test_without_handover ()\n{\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n    void *router = test_context_socket (ZMQ_ROUTER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router, \"tcp://127.0.0.1:*\"));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (router, ZMQ_LAST_ENDPOINT, my_endpoint, &len));\n\n    //  Create dealer called \"X\" and connect it to our router\n    void *dealer_one = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer_one, ZMQ_ROUTING_ID, \"X\", 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer_one, my_endpoint));\n\n    //  Get message from dealer to know when connection is ready\n    char buffer[255];\n    send_string_expect_success (dealer_one, \"Hello\", 0);\n\n    recv_string_expect_success (router, \"X\", 0);\n    recv_string_expect_success (router, \"Hello\", 0);\n\n    // Now create a second dealer that uses the same routing id\n    void *dealer_two = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer_two, ZMQ_ROUTING_ID, \"X\", 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer_two, my_endpoint));\n\n    //  Send message from second dealer\n    send_string_expect_success (dealer_two, \"Hello\", 0);\n\n    //  This should be ignored by the router\n    const int timeout = SETTLE_TIME;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (router, ZMQ_RCVTIMEO, &timeout, sizeof timeout));\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (router, buffer, 255, 0));\n\n    //  Send a message to 'X' routing id. This should be delivered\n    //  to the second dealer, instead of the first because of the handover.\n    send_string_expect_success (router, \"X\", ZMQ_SNDMORE);\n    send_string_expect_success (router, \"Hello\", 0);\n\n    //  Ensure that the second dealer doesn't receive the message\n    //  but the first one does\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer_two, ZMQ_RCVTIMEO, &timeout, sizeof timeout));\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (dealer_two, buffer, 255, 0));\n\n    recv_string_expect_success (dealer_one, \"Hello\", 0);\n\n    test_context_socket_close (router);\n    test_context_socket_close (dealer_one);\n    test_context_socket_close (dealer_two);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_with_handover);\n    RUN_TEST (test_without_handover);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_router_mandatory.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n#ifdef ZMQ_BUILD_DRAFT_API\nbool send_msg_to_peer_if_ready (void *router_, const char *peer_routing_id_)\n{\n    int rc = TEST_ASSERT_SUCCESS_MESSAGE_ERRNO (\n      zmq_socket_get_peer_state (router_, peer_routing_id_, 1),\n      peer_routing_id_);\n    if (rc & ZMQ_POLLOUT) {\n        send_string_expect_success (router_, peer_routing_id_,\n                                    ZMQ_SNDMORE | ZMQ_DONTWAIT);\n        send_string_expect_success (router_, \"Hello\", ZMQ_DONTWAIT);\n\n        return true;\n    }\n    return false;\n}\n#endif\n\nvoid test_get_peer_state ()\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n    void *router = test_context_socket (ZMQ_ROUTER);\n\n    int mandatory = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY,\n                                               &mandatory, sizeof (mandatory)));\n\n    const char *my_endpoint = \"inproc://test_get_peer_state\";\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router, my_endpoint));\n\n    void *dealer1 = test_context_socket (ZMQ_DEALER);\n    void *dealer2 = test_context_socket (ZMQ_DEALER);\n\n    //  Lower HWMs to allow doing the test with fewer messages\n    const int hwm = 100;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (router, ZMQ_SNDHWM, &hwm, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer1, ZMQ_RCVHWM, &hwm, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer2, ZMQ_RCVHWM, &hwm, sizeof (int)));\n\n    const char *dealer1_routing_id = \"X\";\n    const char *dealer2_routing_id = \"Y\";\n\n    //  Name dealer1 \"X\" and connect it to our router\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer1, ZMQ_ROUTING_ID, dealer1_routing_id, 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer1, my_endpoint));\n\n    //  Name dealer2 \"Y\" and connect it to our router\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer2, ZMQ_ROUTING_ID, dealer2_routing_id, 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer2, my_endpoint));\n\n    //  Get message from both dealers to know when connection is ready\n    send_string_expect_success (dealer1, \"Hello\", 0);\n    recv_string_expect_success (router, dealer1_routing_id, 0);\n    recv_string_expect_success (router, \"Hello\", 0);\n\n    send_string_expect_success (dealer2, \"Hello\", 0);\n    recv_string_expect_success (router, dealer2_routing_id, 0);\n    recv_string_expect_success (router, \"Hello\", 0);\n\n    void *poller = zmq_poller_new ();\n    TEST_ASSERT_NOT_NULL (poller);\n\n    //  Poll on router and dealer1, but not on dealer2\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add (poller, router, NULL, ZMQ_POLLOUT));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_poller_add (poller, dealer1, NULL, ZMQ_POLLIN));\n\n    const unsigned int count = 10000;\n    const unsigned int event_size = 2;\n    bool dealer2_blocked = false;\n    unsigned int dealer1_sent = 0, dealer2_sent = 0, dealer1_received = 0;\n    zmq_poller_event_t events[event_size];\n    for (unsigned int iteration = 0; iteration < count; ++iteration) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_poller_wait_all (poller, events, event_size, -1));\n        for (unsigned int event_no = 0; event_no < event_size; ++event_no) {\n            const zmq_poller_event_t &current_event = events[event_no];\n            if (current_event.socket == router\n                && current_event.events & ZMQ_POLLOUT) {\n                if (send_msg_to_peer_if_ready (router, dealer1_routing_id))\n                    ++dealer1_sent;\n\n                if (send_msg_to_peer_if_ready (router, dealer2_routing_id))\n                    ++dealer2_sent;\n                else\n                    dealer2_blocked = true;\n            }\n            if (current_event.socket == dealer1\n                && current_event.events & ZMQ_POLLIN) {\n                recv_string_expect_success (dealer1, \"Hello\", ZMQ_DONTWAIT);\n                int more;\n                size_t more_size = sizeof (more);\n                TEST_ASSERT_SUCCESS_ERRNO (\n                  zmq_getsockopt (dealer1, ZMQ_RCVMORE, &more, &more_size));\n                TEST_ASSERT_FALSE (more);\n\n                ++dealer1_received;\n            }\n            // never read from dealer2, so its pipe becomes full eventually\n        }\n    }\n    printf (\"dealer1_sent = %u, dealer2_sent = %u, dealer1_received = %u\\n\",\n            dealer1_sent, dealer2_sent, dealer1_received);\n    TEST_ASSERT_TRUE (dealer2_blocked);\n    zmq_poller_destroy (&poller);\n\n    test_context_socket_close (router);\n    test_context_socket_close (dealer1);\n    test_context_socket_close (dealer2);\n#endif\n}\n\nvoid test_get_peer_state_corner_cases ()\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n    const char peer_routing_id[] = \"foo\";\n\n    //  call get_peer_state with NULL socket\n    int rc = zmq_socket_get_peer_state (NULL, peer_routing_id,\n                                        strlen (peer_routing_id));\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno);\n\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    void *router = test_context_socket (ZMQ_ROUTER);\n\n    //  call get_peer_state with a non-ROUTER socket\n    rc = zmq_socket_get_peer_state (dealer, peer_routing_id,\n                                    strlen (peer_routing_id));\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSUP, errno);\n\n    //  call get_peer_state for an unknown routing id\n    rc = zmq_socket_get_peer_state (router, peer_routing_id,\n                                    strlen (peer_routing_id));\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (EHOSTUNREACH, errno);\n\n    test_context_socket_close (router);\n    test_context_socket_close (dealer);\n#endif\n}\n\nvoid test_basic ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n    void *router = test_context_socket (ZMQ_ROUTER);\n    bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);\n\n    //  Send a message to an unknown peer with the default setting\n    //  This will not report any error\n    send_string_expect_success (router, \"UNKNOWN\", ZMQ_SNDMORE);\n    send_string_expect_success (router, \"DATA\", 0);\n\n    //  Send a message to an unknown peer with mandatory routing\n    //  This will fail\n    int mandatory = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY,\n                                               &mandatory, sizeof (mandatory)));\n    int rc = zmq_send (router, \"UNKNOWN\", 7, ZMQ_SNDMORE);\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (EHOSTUNREACH, errno);\n\n    //  Create dealer called \"X\" and connect it to our router\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (dealer, ZMQ_ROUTING_ID, \"X\", 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));\n\n    //  Get message from dealer to know when connection is ready\n    send_string_expect_success (dealer, \"Hello\", 0);\n    recv_string_expect_success (router, \"X\", 0);\n\n    //  Send a message to connected dealer now\n    //  It should work\n    send_string_expect_success (router, \"X\", ZMQ_SNDMORE);\n    send_string_expect_success (router, \"Hello\", 0);\n\n    test_context_socket_close (router);\n    test_context_socket_close (dealer);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_basic);\n    RUN_TEST (test_get_peer_state);\n    RUN_TEST (test_get_peer_state_corner_cases);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_router_mandatory_hwm.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n// DEBUG shouldn't be defined in sources as it will cause a redefined symbol\n// error when it is defined in the build configuration. It appears that the\n// intent here is to semi-permanently disable DEBUG tracing statements, so the\n// implementation is changed to accommodate that intent.\n//#define DEBUG 0\n#define TRACE_ENABLED 0\n\nvoid test_router_mandatory_hwm ()\n{\n    if (TRACE_ENABLED)\n        fprintf (stderr, \"Staring router mandatory HWM test ...\\n\");\n    char my_endpoint[MAX_SOCKET_STRING];\n    void *router = test_context_socket (ZMQ_ROUTER);\n\n    // Configure router socket to mandatory routing and set HWM and linger\n    int mandatory = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY,\n                                               &mandatory, sizeof (mandatory)));\n    int sndhwm = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (router, ZMQ_SNDHWM, &sndhwm, sizeof (sndhwm)));\n    int linger = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (router, ZMQ_LINGER, &linger, sizeof (linger)));\n\n    bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);\n\n    //  Create dealer called \"X\" and connect it to our router, configure HWM\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (dealer, ZMQ_ROUTING_ID, \"X\", 1));\n    int rcvhwm = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer, ZMQ_RCVHWM, &rcvhwm, sizeof (rcvhwm)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));\n\n    //  Get message from dealer to know when connection is ready\n    send_string_expect_success (dealer, \"Hello\", 0);\n    recv_string_expect_success (router, \"X\", 0);\n\n    int i;\n    const int buf_size = 65536;\n    const uint8_t buf[buf_size] = {0};\n    // Send first batch of messages\n    for (i = 0; i < 100000; ++i) {\n        if (TRACE_ENABLED)\n            fprintf (stderr, \"Sending message %d ...\\n\", i);\n        const int rc = zmq_send (router, \"X\", 1, ZMQ_DONTWAIT | ZMQ_SNDMORE);\n        if (rc == -1 && zmq_errno () == EAGAIN)\n            break;\n        TEST_ASSERT_EQUAL_INT (1, rc);\n        send_array_expect_success (router, buf, ZMQ_DONTWAIT);\n    }\n    // This should fail after one message but kernel buffering could\n    // skew results\n    TEST_ASSERT_LESS_THAN_INT (10, i);\n    msleep (1000);\n    // Send second batch of messages\n    for (; i < 100000; ++i) {\n        if (TRACE_ENABLED)\n            fprintf (stderr, \"Sending message %d (part 2) ...\\n\", i);\n        const int rc = zmq_send (router, \"X\", 1, ZMQ_DONTWAIT | ZMQ_SNDMORE);\n        if (rc == -1 && zmq_errno () == EAGAIN)\n            break;\n        TEST_ASSERT_EQUAL_INT (1, rc);\n        send_array_expect_success (router, buf, ZMQ_DONTWAIT);\n    }\n    // This should fail after two messages but kernel buffering could\n    // skew results\n    TEST_ASSERT_LESS_THAN_INT (20, i);\n\n    if (TRACE_ENABLED)\n        fprintf (stderr, \"Done sending messages.\\n\");\n\n    test_context_socket_close (router);\n    test_context_socket_close (dealer);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_router_mandatory_hwm);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_router_mandatory_tipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include <stdio.h>\n#include \"testutil.hpp\"\n\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_router_mandatory_tipc ()\n{\n    if (!is_tipc_available ()) {\n        TEST_IGNORE_MESSAGE (\"TIPC environment unavailable, skipping test\");\n    }\n\n    // Creating the first socket.\n    void *sa = test_context_socket (ZMQ_ROUTER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sa, \"tipc://{15560,0,0}\"));\n\n    // Sending a message to an unknown peer with the default setting\n    send_string_expect_success (sa, \"UNKNOWN\", ZMQ_SNDMORE);\n    send_string_expect_success (sa, \"DATA\", 0);\n\n    int mandatory = 1;\n\n    // Set mandatory routing on socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sa, ZMQ_ROUTER_MANDATORY,\n                                               &mandatory, sizeof (mandatory)));\n\n    // Send a message and check that it fails\n    TEST_ASSERT_FAILURE_ERRNO (\n      EHOSTUNREACH, zmq_send (sa, \"UNKNOWN\", 7, ZMQ_SNDMORE | ZMQ_DONTWAIT));\n\n    test_context_socket_close (sa);\n}\n\nint main (void)\n{\n    UNITY_BEGIN ();\n    RUN_TEST (test_router_mandatory_tipc);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_router_notify.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_sockopt_router_notify ()\n{\n    void *router = test_context_socket (ZMQ_ROUTER);\n    int opt_notify;\n\n    int opt_notify_read;\n    size_t opt_notify_read_size = sizeof (opt_notify_read);\n\n\n    // default value is off when socket is constructed\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));\n\n    TEST_ASSERT_EQUAL (0, opt_notify_read);\n\n\n    // valid value - Connect\n    opt_notify = ZMQ_NOTIFY_CONNECT;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));\n\n    TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);\n\n\n    // valid value - Disconnect\n    opt_notify = ZMQ_NOTIFY_DISCONNECT;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));\n\n    TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);\n\n\n    // valid value - Off\n    opt_notify = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));\n\n    TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);\n\n\n    // valid value - Both\n    opt_notify = ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));\n\n    TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);\n\n\n    // value boundary\n    opt_notify = -1;\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_setsockopt (router, ZMQ_ROUTER_NOTIFY, &opt_notify,\n                              sizeof (opt_notify)));\n\n    opt_notify = (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT) + 1;\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_setsockopt (router, ZMQ_ROUTER_NOTIFY, &opt_notify,\n                              sizeof (opt_notify)));\n\n    // failures don't update the value\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));\n\n    TEST_ASSERT_EQUAL (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT,\n                       opt_notify_read);\n\n\n    test_context_socket_close (router);\n\n\n    // check a non-router socket type\n    void *dealer = test_context_socket (ZMQ_DEALER);\n\n    // setsockopt fails for non-router sockets\n    opt_notify = ZMQ_NOTIFY_CONNECT;\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_setsockopt (dealer, ZMQ_ROUTER_NOTIFY, &opt_notify,\n                              sizeof (opt_notify)));\n\n    // getsockopts returns off for any non-router socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (\n      dealer, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));\n\n    TEST_ASSERT_EQUAL (0, opt_notify_read);\n\n\n    test_context_socket_close (dealer);\n}\n\n\nvoid test_router_notify_helper (int opt_notify_)\n{\n    void *router = test_context_socket (ZMQ_ROUTER);\n    int opt_more;\n    size_t opt_more_length = sizeof (opt_more);\n    int opt_events;\n    size_t opt_events_length = sizeof (opt_events);\n    char connect_address[MAX_SOCKET_STRING];\n\n\n    // valid values\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify_, sizeof (opt_notify_)));\n\n    bind_loopback_ipv4 (router, connect_address, sizeof connect_address);\n\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    const char *dealer_routing_id = \"X\";\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer, ZMQ_ROUTING_ID, dealer_routing_id, 1));\n\n    // dealer connects\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, connect_address));\n\n    // connection notification msg\n    if (opt_notify_ & ZMQ_NOTIFY_CONNECT) {\n        // routing-id only message of the connect\n        recv_string_expect_success (router, dealer_routing_id,\n                                    0);             // 1st part: routing-id\n        recv_string_expect_success (router, \"\", 0); // 2nd part: empty\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));\n        TEST_ASSERT_EQUAL (0, opt_more);\n    }\n\n    // test message from the dealer\n    send_string_expect_success (dealer, \"Hello\", 0);\n    recv_string_expect_success (router, dealer_routing_id, 0);\n    recv_string_expect_success (router, \"Hello\", 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));\n    TEST_ASSERT_EQUAL (0, opt_more);\n\n    // dealer disconnects\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (dealer, connect_address));\n\n    // need one more process_commands() (???)\n    msleep (SETTLE_TIME);\n    zmq_getsockopt (dealer, ZMQ_EVENTS, &opt_events, &opt_events_length);\n\n    // connection notification msg\n    if (opt_notify_ & ZMQ_NOTIFY_DISCONNECT) {\n        // routing-id only message of the connect\n        recv_string_expect_success (router, dealer_routing_id,\n                                    0);             // 1st part: routing-id\n        recv_string_expect_success (router, \"\", 0); // 2nd part: empty\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));\n        TEST_ASSERT_EQUAL (0, opt_more);\n    }\n\n    test_context_socket_close (dealer);\n    test_context_socket_close (router);\n}\n\n\nvoid test_router_notify_connect ()\n{\n    test_router_notify_helper (ZMQ_NOTIFY_CONNECT);\n}\n\n\nvoid test_router_notify_disconnect ()\n{\n    test_router_notify_helper (ZMQ_NOTIFY_DISCONNECT);\n}\n\n\nvoid test_router_notify_both ()\n{\n    test_router_notify_helper (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT);\n}\n\n\nvoid test_handshake_fail ()\n{\n    // setup router socket\n    void *router = test_context_socket (ZMQ_ROUTER);\n    int opt_timeout = 200;\n    int opt_notify = ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT;\n    char connect_address[MAX_SOCKET_STRING];\n\n    // valid values\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      router, ZMQ_RCVTIMEO, &opt_timeout, sizeof (opt_timeout)));\n\n    bind_loopback_ipv4 (router, connect_address, sizeof connect_address);\n\n    // send something on raw tcp\n    void *stream = test_context_socket (ZMQ_STREAM);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (stream, connect_address));\n\n    send_string_expect_success (stream, \"not-a-handshake\", 0);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (stream, connect_address));\n    test_context_socket_close (stream);\n\n    // no notification delivered\n    char buffer[255];\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN,\n                               zmq_recv (router, buffer, sizeof (buffer), 0));\n\n    test_context_socket_close (router);\n}\n\n\nvoid test_error_during_multipart ()\n{\n    /*\n     * If the disconnect occurs in the middle of the multipart\n     * message, the socket should not add the notification at the\n     * end of the incomplete message. It must discard the incomplete\n     * message, and delivert the notification as a new message.\n     */\n\n    char connect_address[MAX_SOCKET_STRING];\n    char long_str[128] = {0};\n    memset (long_str, '*', sizeof (long_str) - 1);\n\n    // setup router\n    void *router = test_context_socket (ZMQ_ROUTER);\n\n    int opt_notify = ZMQ_NOTIFY_DISCONNECT;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));\n\n    int64_t opt_maxmsgsize = 64; // the handshake fails if this is too small\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      router, ZMQ_MAXMSGSIZE, &opt_maxmsgsize, sizeof (opt_maxmsgsize)));\n\n    bind_loopback_ipv4 (router, connect_address, sizeof connect_address);\n\n    // setup dealer\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    const char *dealer_routing_id = \"X\";\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer, ZMQ_ROUTING_ID, dealer_routing_id, 1));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, connect_address));\n\n\n    // send multipart message, the 2nd part causes a disconnect.\n    send_string_expect_success (dealer, \"Hello2\", ZMQ_SNDMORE);\n    send_string_expect_success (dealer, long_str, 0);\n\n    // disconnect notification\n    recv_string_expect_success (router, dealer_routing_id, 0);\n    recv_string_expect_success (router, \"\", 0);\n\n\n    test_context_socket_close (dealer);\n    test_context_socket_close (router);\n}\n\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_sockopt_router_notify);\n    RUN_TEST (test_router_notify_connect);\n    RUN_TEST (test_router_notify_disconnect);\n    RUN_TEST (test_router_notify_both);\n    RUN_TEST (test_handshake_fail);\n    RUN_TEST (test_error_during_multipart);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_scatter_gather.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_scatter_gather_multipart_fails ()\n{\n    void *scatter = test_context_socket (ZMQ_SCATTER);\n    void *gather = test_context_socket (ZMQ_GATHER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_bind (scatter, \"inproc://test-scatter-gather\"));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (gather, \"inproc://test-scatter-gather\"));\n\n    //  Should fail, multipart is not supported\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL,\n                               zmq_send_const (scatter, \"1\", 1, ZMQ_SNDMORE));\n\n    test_context_socket_close (scatter);\n    test_context_socket_close (gather);\n}\n\nvoid test_scatter_gather ()\n{\n    void *scatter = test_context_socket (ZMQ_SCATTER);\n    void *gather = test_context_socket (ZMQ_GATHER);\n    void *gather2 = test_context_socket (ZMQ_GATHER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_bind (scatter, \"inproc://test-scatter-gather\"));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (gather, \"inproc://test-scatter-gather\"));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (gather2, \"inproc://test-scatter-gather\"));\n\n    send_string_expect_success (scatter, \"1\", 0);\n    send_string_expect_success (scatter, \"2\", 0);\n\n    recv_string_expect_success (gather, \"1\", 0);\n    recv_string_expect_success (gather2, \"2\", 0);\n\n    test_context_socket_close (scatter);\n    test_context_socket_close (gather);\n    test_context_socket_close (gather2);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_scatter_gather);\n    RUN_TEST (test_scatter_gather_multipart_fails);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_security_curve.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n// TODO remove this workaround for handling libsodium\n\n//  To define SIZE_MAX with older compilers\n#define __STDC_LIMIT_MACROS\n\n#if defined ZMQ_CUSTOM_PLATFORM_HPP\n#include \"platform.hpp\"\n#else\n#include \"../src/platform.hpp\"\n#endif\n\n#ifndef ZMQ_USE_LIBSODIUM\n#define ZMQ_USE_LIBSODIUM\n#endif\n\n#include \"testutil.hpp\"\n#include \"testutil_security.hpp\"\n#include <unity.h>\n\n#include \"../src/curve_client_tools.hpp\"\n#include \"../src/random.hpp\"\n\nchar error_message_buffer[256];\n\nvoid *handler;\nvoid *zap_thread;\nvoid *server;\nvoid *server_mon;\nchar my_endpoint[MAX_SOCKET_STRING];\n\nvoid setUp ()\n{\n    setup_test_context ();\n    setup_context_and_server_side (&handler, &zap_thread, &server, &server_mon,\n                                   my_endpoint);\n}\n\nvoid tearDown ()\n{\n    shutdown_context_and_server_side (zap_thread, server, server_mon, handler);\n    teardown_test_context ();\n}\n\nconst int timeout = 250;\n\nconst char large_routing_id[] = \"0123456789012345678901234567890123456789\"\n                                \"0123456789012345678901234567890123456789\"\n                                \"0123456789012345678901234567890123456789\"\n                                \"0123456789012345678901234567890123456789\"\n                                \"0123456789012345678901234567890123456789\"\n                                \"0123456789012345678901234567890123456789\"\n                                \"012345678901234\";\n\nstatic void zap_handler_large_routing_id (void * /*unused_*/)\n{\n    zap_handler_generic (zap_ok, large_routing_id);\n}\n\nvoid expect_new_client_curve_bounce_fail (const char *server_public_,\n                                          const char *client_public_,\n                                          const char *client_secret_,\n                                          char *my_endpoint_,\n                                          void *server_,\n                                          void **client_mon_ = NULL,\n                                          int expected_client_event_ = 0,\n                                          int expected_client_value_ = 0)\n{\n    curve_client_data_t curve_client_data = {server_public_, client_public_,\n                                             client_secret_};\n    expect_new_client_bounce_fail (\n      my_endpoint_, server_, socket_config_curve_client, &curve_client_data,\n      client_mon_, expected_client_event_, expected_client_value_);\n}\n\nvoid test_null_key (void *server_,\n                    void *server_mon_,\n                    char *my_endpoint_,\n                    char *server_public_,\n                    char *client_public_,\n                    char *client_secret_)\n{\n    expect_new_client_curve_bounce_fail (server_public_, client_public_,\n                                         client_secret_, my_endpoint_, server_);\n\n    int handshake_failed_encryption_event_count =\n      expect_monitor_event_multiple (server_mon_,\n                                     ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,\n                                     ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n\n    // handshake_failed_encryption_event_count should be at least two because\n    // expect_bounce_fail involves two exchanges\n    // however, with valgrind we see only one event (maybe the next one takes\n    // very long, or does not happen at all because something else takes very\n    // long)\n\n    fprintf (stderr,\n             \"count of \"\n             \"ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL/\"\n             \"ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC events: %i\\n\",\n             handshake_failed_encryption_event_count);\n}\n\nvoid test_curve_security_with_valid_credentials ()\n{\n    curve_client_data_t curve_client_data = {\n      valid_server_public, valid_client_public, valid_client_secret};\n    void *client_mon;\n    void *client = create_and_connect_client (\n      my_endpoint, socket_config_curve_client, &curve_client_data, &client_mon);\n    bounce (server, client);\n    test_context_socket_close (client);\n\n    int event = get_monitor_event_with_timeout (server_mon, NULL, NULL, -1);\n    assert (event == ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n\n    assert_no_more_monitor_events_with_timeout (server_mon, timeout);\n\n    event = get_monitor_event_with_timeout (client_mon, NULL, NULL, -1);\n    assert (event == ZMQ_EVENT_HANDSHAKE_SUCCEEDED);\n\n    assert_no_more_monitor_events_with_timeout (client_mon, timeout);\n\n    test_context_socket_close (client_mon);\n}\n\nvoid test_curve_security_with_bogus_client_credentials ()\n{\n    //  This must be caught by the ZAP handler\n    char bogus_public[41];\n    char bogus_secret[41];\n    zmq_curve_keypair (bogus_public, bogus_secret);\n\n    expect_new_client_curve_bounce_fail (\n      valid_server_public, bogus_public, bogus_secret, my_endpoint, server,\n      NULL, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 400);\n\n    int server_event_count = 0;\n    server_event_count = expect_monitor_event_multiple (\n      server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 400);\n    TEST_ASSERT_LESS_OR_EQUAL_INT (1, server_event_count);\n\n    // there may be more than one ZAP request due to repeated attempts by the client\n    TEST_ASSERT (0 == server_event_count\n                 || 1 <= zmq_atomic_counter_value (zap_requests_handled));\n}\n\nvoid expect_zmtp_mechanism_mismatch (void *client_,\n                                     char *my_endpoint_,\n                                     void *server_,\n                                     void *server_mon_)\n{\n    //  This must be caught by the curve_server class, not passed to ZAP\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_, my_endpoint_));\n    expect_bounce_fail (server_, client_);\n    test_context_socket_close_zero_linger (client_);\n\n    expect_monitor_event_multiple (server_mon_,\n                                   ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,\n                                   ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH);\n\n    TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_value (zap_requests_handled));\n}\n\nvoid test_curve_security_with_null_client_credentials ()\n{\n    void *client = test_context_socket (ZMQ_DEALER);\n\n    expect_zmtp_mechanism_mismatch (client, my_endpoint, server, server_mon);\n}\n\nvoid test_curve_security_with_plain_client_credentials ()\n{\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, \"admin\", 5));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, \"password\", 8));\n\n    expect_zmtp_mechanism_mismatch (client, my_endpoint, server, server_mon);\n}\n\nvoid test_curve_security_unauthenticated_message ()\n{\n    // Unauthenticated messages from a vanilla socket shouldn't be received\n    fd_t s = connect_socket (my_endpoint);\n    // send anonymous ZMTP/1.0 greeting\n    send (s, \"\\x01\\x00\", 2, 0);\n    // send sneaky message that shouldn't be received\n    send (s, \"\\x08\\x00sneaky\\0\", 9, 0);\n\n    zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));\n    char *buf = s_recv (server);\n    TEST_ASSERT_NULL_MESSAGE (buf, \"Received unauthenticated message\");\n    close (s);\n}\n\nvoid send_all (fd_t fd_, const char *data_, socket_size_t size_)\n{\n    while (size_ > 0) {\n        int res = send (fd_, data_, size_, 0);\n        TEST_ASSERT_GREATER_THAN_INT (0, res);\n        size_ -= res;\n        data_ += res;\n    }\n}\n\ntemplate <size_t N> void send (fd_t fd_, const char (&data_)[N])\n{\n    send_all (fd_, data_, N - 1);\n}\n\ntemplate <size_t N> void send (fd_t fd_, const uint8_t (&data_)[N])\n{\n    send_all (fd_, reinterpret_cast<const char *> (&data_), N);\n}\n\nvoid test_curve_security_invalid_hello_wrong_length ()\n{\n    fd_t s = connect_socket (my_endpoint);\n\n    send (s, zmtp_greeting_curve);\n\n    // send CURVE HELLO of wrong size\n    send (s, \"\\x04\\x06\\x05HELLO\");\n\n    expect_monitor_event_multiple (\n      server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,\n      ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);\n\n    close (s);\n}\n\nconst size_t hello_length = 200;\nconst size_t welcome_length = 168;\n\nzmq::curve_client_tools_t make_curve_client_tools ()\n{\n    uint8_t valid_client_secret_decoded[32];\n    uint8_t valid_client_public_decoded[32];\n\n    zmq_z85_decode (valid_client_public_decoded, valid_client_public);\n    zmq_z85_decode (valid_client_secret_decoded, valid_client_secret);\n\n    uint8_t valid_server_public_decoded[32];\n    zmq_z85_decode (valid_server_public_decoded, valid_server_public);\n\n    return zmq::curve_client_tools_t (valid_client_public_decoded,\n                                      valid_client_secret_decoded,\n                                      valid_server_public_decoded);\n}\n\n// same as htonll, which is only available on few platforms (recent Windows, but not on Linux, e.g.(\nstatic uint64_t host_to_network (uint64_t value_)\n{\n    // The answer is 42\n    static const int num = 42;\n\n    // Check the endianness\n    if (*reinterpret_cast<const char *> (&num) == num) {\n        const uint32_t high_part = htonl (static_cast<uint32_t> (value_ >> 32));\n        const uint32_t low_part =\n          htonl (static_cast<uint32_t> (value_ & 0xFFFFFFFFLL));\n\n        return (static_cast<uint64_t> (low_part) << 32) | high_part;\n    }\n    return value_;\n}\n\ntemplate <size_t N> void send_command (fd_t s_, char (&command_)[N])\n{\n    if (N < 256) {\n        send (s_, \"\\x04\");\n        char len = (char) N;\n        send_all (s_, &len, 1);\n    } else {\n        send (s_, \"\\x06\");\n        uint64_t len = host_to_network (N);\n        send_all (s_, reinterpret_cast<char *> (&len), 8);\n    }\n    send_all (s_, command_, N);\n}\n\nvoid test_curve_security_invalid_hello_command_name ()\n{\n    fd_t s = connect_socket (my_endpoint);\n\n    send (s, zmtp_greeting_curve);\n\n    zmq::curve_client_tools_t tools = make_curve_client_tools ();\n\n    // send CURVE HELLO with a misspelled command name (but otherwise correct)\n    char hello[hello_length];\n    TEST_ASSERT_SUCCESS_ERRNO (tools.produce_hello (hello, 0));\n    hello[5] = 'X';\n\n    send_command (s, hello);\n\n    expect_monitor_event_multiple (server_mon,\n                                   ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,\n                                   ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n\n    close (s);\n}\n\nvoid test_curve_security_invalid_hello_version ()\n{\n    fd_t s = connect_socket (my_endpoint);\n\n    send (s, zmtp_greeting_curve);\n\n    zmq::curve_client_tools_t tools = make_curve_client_tools ();\n\n    // send CURVE HELLO with a wrong version number (but otherwise correct)\n    char hello[hello_length];\n    TEST_ASSERT_SUCCESS_ERRNO (tools.produce_hello (hello, 0));\n    hello[6] = 2;\n\n    send_command (s, hello);\n\n    expect_monitor_event_multiple (\n      server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,\n      ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);\n\n    close (s);\n}\n\nvoid flush_read (fd_t fd_)\n{\n    int res;\n    char buf[256];\n\n    while ((res = recv (fd_, buf, 256, 0)) == 256) {\n    }\n    TEST_ASSERT_NOT_EQUAL (-1, res);\n}\n\nvoid recv_all (fd_t fd_, uint8_t *data_, socket_size_t len_)\n{\n    socket_size_t received = 0;\n    while (received < len_) {\n        int res = recv (fd_, reinterpret_cast<char *> (data_), len_, 0);\n        TEST_ASSERT_GREATER_THAN_INT (0, res);\n\n        data_ += res;\n        received += res;\n    }\n}\n\nvoid recv_greeting (fd_t fd_)\n{\n    uint8_t greeting[64];\n    recv_all (fd_, greeting, 64);\n    //  TODO assert anything about the greeting received from the server?\n}\n\nfd_t connect_exchange_greeting_and_send_hello (\n  char *my_endpoint_, zmq::curve_client_tools_t &tools_)\n{\n    fd_t s = connect_socket (my_endpoint_);\n\n    send (s, zmtp_greeting_curve);\n    recv_greeting (s);\n\n    // send valid CURVE HELLO\n    char hello[hello_length];\n    TEST_ASSERT_SUCCESS_ERRNO (tools_.produce_hello (hello, 0));\n\n    send_command (s, hello);\n    return s;\n}\n\nvoid test_curve_security_invalid_initiate_wrong_length ()\n{\n    zmq::curve_client_tools_t tools = make_curve_client_tools ();\n\n    fd_t s = connect_exchange_greeting_and_send_hello (my_endpoint, tools);\n\n    // receive but ignore WELCOME\n    flush_read (s);\n\n    int res = get_monitor_event_with_timeout (server_mon, NULL, NULL, timeout);\n    TEST_ASSERT_EQUAL_INT (-1, res);\n\n    send (s, \"\\x04\\x09\\x08INITIATE\");\n\n    expect_monitor_event_multiple (\n      server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,\n      ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);\n\n    close (s);\n}\n\nfd_t connect_exchange_greeting_and_hello_welcome (\n  char *my_endpoint_,\n  void *server_mon_,\n  int timeout_,\n  zmq::curve_client_tools_t &tools_)\n{\n    fd_t s = connect_exchange_greeting_and_send_hello (my_endpoint_, tools_);\n\n    // receive but ignore WELCOME\n    uint8_t welcome[welcome_length + 2];\n    recv_all (s, welcome, welcome_length + 2);\n\n    uint8_t cn_precom[crypto_box_BEFORENMBYTES];\n    TEST_ASSERT_SUCCESS_ERRNO (\n      tools_.process_welcome (welcome + 2, welcome_length, cn_precom));\n\n    const int res =\n      get_monitor_event_with_timeout (server_mon_, NULL, NULL, timeout_);\n    TEST_ASSERT_EQUAL_INT (-1, res);\n\n    return s;\n}\n\nvoid test_curve_security_invalid_initiate_command_name ()\n{\n    zmq::curve_client_tools_t tools = make_curve_client_tools ();\n    fd_t s = connect_exchange_greeting_and_hello_welcome (\n      my_endpoint, server_mon, timeout, tools);\n\n    char initiate[257];\n    tools.produce_initiate (initiate, 257, 1, NULL, 0);\n    // modify command name\n    initiate[5] = 'X';\n\n    send_command (s, initiate);\n\n    expect_monitor_event_multiple (server_mon,\n                                   ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,\n                                   ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);\n\n    close (s);\n}\n\nvoid test_curve_security_invalid_initiate_command_encrypted_cookie ()\n{\n    zmq::curve_client_tools_t tools = make_curve_client_tools ();\n    fd_t s = connect_exchange_greeting_and_hello_welcome (\n      my_endpoint, server_mon, timeout, tools);\n\n    char initiate[257];\n    tools.produce_initiate (initiate, 257, 1, NULL, 0);\n    // make garbage from encrypted cookie\n    initiate[30] = !initiate[30];\n\n    send_command (s, initiate);\n\n    expect_monitor_event_multiple (server_mon,\n                                   ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,\n                                   ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n\n    close (s);\n}\n\nvoid test_curve_security_invalid_initiate_command_encrypted_content ()\n{\n    zmq::curve_client_tools_t tools = make_curve_client_tools ();\n    fd_t s = connect_exchange_greeting_and_hello_welcome (\n      my_endpoint, server_mon, timeout, tools);\n\n    char initiate[257];\n    tools.produce_initiate (initiate, 257, 1, NULL, 0);\n    // make garbage from encrypted content\n    initiate[150] = !initiate[150];\n\n    send_command (s, initiate);\n\n    expect_monitor_event_multiple (server_mon,\n                                   ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,\n                                   ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);\n\n    close (s);\n}\n\nvoid test_curve_security_invalid_keysize (void *ctx_)\n{\n    //  Check return codes for invalid buffer sizes\n    void *client = zmq_socket (ctx_, ZMQ_DEALER);\n    TEST_ASSERT_NOT_NULL (client);\n    errno = 0;\n    int rc =\n      zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, valid_server_public, 123);\n    assert (rc == -1 && errno == EINVAL);\n    errno = 0;\n    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, valid_client_public, 123);\n    assert (rc == -1 && errno == EINVAL);\n    errno = 0;\n    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, valid_client_secret, 123);\n    assert (rc == -1 && errno == EINVAL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (client));\n}\n\n// TODO why isn't this const?\nchar null_key[] = \"0000000000000000000000000000000000000000\";\n\nvoid test_null_server_key ()\n{\n    //  Check CURVE security with a null server key\n    //  This will be caught by the curve_server class, not passed to ZAP\n    test_null_key (server, server_mon, my_endpoint, null_key,\n                   valid_client_public, valid_client_secret);\n}\n\nvoid test_null_client_public_key ()\n{\n    //  Check CURVE security with a null client public key\n    //  This will be caught by the curve_server class, not passed to ZAP\n    test_null_key (server, server_mon, my_endpoint, valid_server_public,\n                   null_key, valid_client_secret);\n}\n\nvoid test_null_client_secret_key ()\n{\n    //  Check CURVE security with a null client public key\n    //  This will be caught by the curve_server class, not passed to ZAP\n    test_null_key (server, server_mon, my_endpoint, valid_server_public,\n                   valid_client_public, null_key);\n}\n\n\nint main (void)\n{\n    if (!zmq_has (\"curve\")) {\n        printf (\"CURVE encryption not installed, skipping test\\n\");\n        return 0;\n    }\n\n    zmq::random_open ();\n\n    setup_testutil_security_curve ();\n\n\n    setup_test_environment (180);\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_curve_security_with_valid_credentials);\n    RUN_TEST (test_null_server_key);\n    RUN_TEST (test_null_client_public_key);\n    RUN_TEST (test_null_client_secret_key);\n    RUN_TEST (test_curve_security_with_bogus_client_credentials);\n    RUN_TEST (test_curve_security_with_null_client_credentials);\n    RUN_TEST (test_curve_security_with_plain_client_credentials);\n    RUN_TEST (test_curve_security_unauthenticated_message);\n\n    //  tests with misbehaving CURVE client\n    RUN_TEST (test_curve_security_invalid_hello_wrong_length);\n    RUN_TEST (test_curve_security_invalid_hello_command_name);\n    RUN_TEST (test_curve_security_invalid_hello_version);\n    RUN_TEST (test_curve_security_invalid_initiate_wrong_length);\n    RUN_TEST (test_curve_security_invalid_initiate_command_name);\n    RUN_TEST (test_curve_security_invalid_initiate_command_encrypted_cookie);\n    RUN_TEST (test_curve_security_invalid_initiate_command_encrypted_content);\n\n    // TODO this requires a deviating test setup, must be moved to a separate executable/fixture\n    //  test with a large routing id (resulting in large metadata)\n    fprintf (stderr,\n             \"test_curve_security_with_valid_credentials (large routing id)\\n\");\n    setup_test_context ();\n    setup_context_and_server_side (&handler, &zap_thread, &server, &server_mon,\n                                   my_endpoint, &zap_handler_large_routing_id,\n                                   &socket_config_curve_server,\n                                   &valid_server_secret, large_routing_id);\n    test_curve_security_with_valid_credentials ();\n    shutdown_context_and_server_side (zap_thread, server, server_mon, handler);\n    teardown_test_context ();\n\n    void *ctx = zmq_ctx_new ();\n    test_curve_security_invalid_keysize (ctx);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_term (ctx));\n\n    zmq::random_close ();\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_security_gssapi.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_monitoring.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\n//  This test requires a KRB5 environment with the following\n//  service principal (substitute your host.domain and REALM):\n//\n//    zmqtest2/host.domain@REALM   (host.domain should be host running test)\n//\n//  Export keys for this principal to a keytab file and set the environment\n//  variables KRB5_KTNAME and KRB5_CLIENT_KTNAME to FILE:/path/to/your/keytab.\n//  The test will use it both for client and server roles.\n//\n//  The test is derived in large part from test_security_curve.cpp\n\nconst char *name = \"zmqtest2\";\n\nstatic volatile int zap_deny_all = 0;\n\n//  --------------------------------------------------------------------------\n//  This methods receives and validates ZAP requests (allowing or denying\n//  each client connection).\n//  N.B. on failure, each crypto type in keytab will be tried\n\nstatic void zap_handler (void *handler_)\n{\n    //  Process ZAP requests forever\n    while (true) {\n        char *version = s_recv (handler_);\n        if (!version)\n            break; //  Terminating\n\n        char *sequence = s_recv (handler_);\n        char *domain = s_recv (handler_);\n        char *address = s_recv (handler_);\n        char *routing_id = s_recv (handler_);\n        char *mechanism = s_recv (handler_);\n        char *principal = s_recv (handler_);\n\n        TEST_ASSERT_EQUAL_STRING (\"1.0\", version);\n        TEST_ASSERT_EQUAL_STRING (\"GSSAPI\", mechanism);\n\n        send_string_expect_success (handler_, version, ZMQ_SNDMORE);\n        send_string_expect_success (handler_, sequence, ZMQ_SNDMORE);\n\n        if (!zap_deny_all) {\n            send_string_expect_success (handler_, \"200\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"OK\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"anonymous\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"\", 0);\n            //fprintf (stderr, \"ALLOW %s\\n\", principal);\n        } else {\n            send_string_expect_success (handler_, \"400\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"Denied\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"\", 0);\n            //fprintf (stderr, \"DENY %s\\n\", principal);\n        }\n        free (version);\n        free (sequence);\n        free (domain);\n        free (address);\n        free (routing_id);\n        free (mechanism);\n        free (principal);\n    }\n    zmq_close (handler_);\n}\n\nstatic char my_endpoint[MAX_SOCKET_STRING];\nstatic void *zap_thread;\nstatic void *server;\nstatic void *server_mon;\n\nvoid check_krb_available ()\n{\n    if (!getenv (\"KRB5_KTNAME\") || !getenv (\"KRB5_CLIENT_KTNAME\")) {\n        TEST_IGNORE_MESSAGE (\"KRB5 environment unavailable, skipping test\");\n    }\n}\n\nvoid setUp ()\n{\n    setup_test_context ();\n\n    zap_thread = 0;\n    server = NULL;\n    server_mon = NULL;\n\n    check_krb_available ();\n\n    //  Spawn ZAP handler\n    //  We create and bind ZAP socket in main thread to avoid case\n    //  where child thread does not start up fast enough.\n    void *handler = zmq_socket (get_test_context (), ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, \"inproc://zeromq.zap.01\"));\n    zap_thread = zmq_threadstart (&zap_handler, handler);\n\n    //  Server socket will accept connections\n    server = test_context_socket (ZMQ_DEALER);\n    int as_server = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_GSSAPI_SERVER, &as_server, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_GSSAPI_PRINCIPAL, name, strlen (name) + 1));\n    int name_type = ZMQ_GSSAPI_NT_HOSTBASED;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      server, ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, &name_type, sizeof (name_type)));\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n\n    //  Monitor handshake events on the server\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (\n      server, \"inproc://monitor-server\",\n      ZMQ_EVENT_HANDSHAKE_SUCCEEDED | ZMQ_EVENT_HANDSHAKE_FAILED_AUTH\n        | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL));\n\n    //  Create socket for collecting monitor events\n    server_mon = test_context_socket (ZMQ_PAIR);\n\n    //  Connect it to the inproc endpoints so they'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (server_mon, \"inproc://monitor-server\"));\n}\n\nvoid tearDown ()\n{\n    //  Shutdown\n    if (server_mon)\n        test_context_socket_close_zero_linger (server_mon);\n    if (server)\n        test_context_socket_close (server);\n    teardown_test_context ();\n\n    //  Wait until ZAP handler terminates\n    if (zap_thread)\n        zmq_threadclose (zap_thread);\n}\n\nvoid test_valid_creds ()\n{\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      client, ZMQ_GSSAPI_SERVICE_PRINCIPAL, name, strlen (name) + 1));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_GSSAPI_PRINCIPAL, name, strlen (name) + 1));\n    int name_type = ZMQ_GSSAPI_NT_HOSTBASED;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      client, ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, &name_type, sizeof (name_type)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    bounce (server, client);\n    test_context_socket_close (client);\n\n    int event = get_monitor_event (server_mon, NULL, NULL);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_HANDSHAKE_SUCCEEDED, event);\n}\n\n//  Check security with valid but unauthorized credentials\n//  Note: ZAP may see multiple requests - after a failure, client will\n//  fall back to other crypto types for principal, if available.\nvoid test_unauth_creds ()\n{\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      client, ZMQ_GSSAPI_SERVICE_PRINCIPAL, name, strlen (name) + 1));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_GSSAPI_PRINCIPAL, name, strlen (name) + 1));\n    int name_type = ZMQ_GSSAPI_NT_HOSTBASED;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      client, ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, &name_type, sizeof (name_type)));\n    zap_deny_all = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    expect_bounce_fail (server, client);\n    test_context_socket_close_zero_linger (client);\n\n    int event = get_monitor_event (server_mon, NULL, NULL);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, event);\n}\n\n//  Check GSSAPI security with NULL client credentials\n//  This must be caught by the gssapi_server class, not passed to ZAP\nvoid test_null_creds ()\n{\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    expect_bounce_fail (server, client);\n    test_context_socket_close_zero_linger (client);\n\n    int error = 0;\n    int event = get_monitor_event (server_mon, &error, NULL);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, event);\n    TEST_ASSERT_EQUAL_INT (ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH, error);\n}\n\n//  Check GSSAPI security with PLAIN client credentials\n//  This must be caught by the curve_server class, not passed to ZAP\nvoid test_plain_creds ()\n{\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, \"admin\", 5));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, \"password\", 8));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    expect_bounce_fail (server, client);\n    test_context_socket_close_zero_linger (client);\n}\n\n// Unauthenticated messages from a vanilla socket shouldn't be received\nvoid test_vanilla_socket ()\n{\n    fd_t s = connect_socket (my_endpoint);\n    // send anonymous ZMTP/1.0 greeting\n    send (s, \"\\x01\\x00\", 2, 0);\n    // send sneaky message that shouldn't be received\n    send (s, \"\\x08\\x00sneaky\\0\", 9, 0);\n    int timeout = 250;\n    zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));\n    char *buf = s_recv (server);\n    if (buf != NULL) {\n        printf (\"Received unauthenticated message: %s\\n\", buf);\n        TEST_ASSERT_NULL (buf);\n    }\n    close (s);\n}\n\nint main (void)\n{\n    // Avoid entanglements with user's credential cache\n    setenv (\"KRB5CCNAME\", \"MEMORY\", 1);\n\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_valid_creds);\n    RUN_TEST (test_null_creds);\n    RUN_TEST (test_plain_creds);\n    RUN_TEST (test_vanilla_socket);\n    RUN_TEST (test_unauth_creds);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_security_no_zap_handler.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_no_zap_handler ()\n{\n    //  We first test client/server with a ZAP domain but with no handler\n    //  If there is no handler, libzmq should ignore the ZAP option unless\n    //  ZMQ_ZAP_ENFORCE_DOMAIN is set\n    void *server = test_context_socket (ZMQ_DEALER);\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, \"TEST\", 5));\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    bounce (server, client);\n    test_context_socket_close_zero_linger (client);\n    test_context_socket_close_zero_linger (server);\n}\n\nvoid test_no_zap_handler_enforce_domain ()\n{\n#ifdef ZMQ_ZAP_ENFORCE_DOMAIN\n    //  Now set ZMQ_ZAP_ENFORCE_DOMAIN which strictly enforces the ZAP\n    //  RFC but is backward-incompatible, now it should fail\n    void *server = test_context_socket (ZMQ_DEALER);\n    void *client = test_context_socket (ZMQ_DEALER);\n    int required = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_ZAP_ENFORCE_DOMAIN, &required, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, \"TEST\", 5));\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    expect_bounce_fail (server, client);\n    test_context_socket_close_zero_linger (client);\n    test_context_socket_close_zero_linger (server);\n#endif\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_no_zap_handler);\n    RUN_TEST (test_no_zap_handler_enforce_domain);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_security_null.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#if defined(ZMQ_HAVE_WINDOWS)\n#include <winsock2.h>\n#include <ws2tcpip.h>\n#include <stdexcept>\n#define close closesocket\n#else\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <unistd.h>\n#endif\n\n#include <stdlib.h>\n\nstatic void zap_handler (void *handler_)\n{\n    //  Process ZAP requests forever\n    while (true) {\n        char *version = s_recv (handler_);\n        if (!version)\n            break; //  Terminating\n\n        char *sequence = s_recv (handler_);\n        char *domain = s_recv (handler_);\n        char *address = s_recv (handler_);\n        char *routing_id = s_recv (handler_);\n        char *mechanism = s_recv (handler_);\n\n        TEST_ASSERT_EQUAL_STRING (\"1.0\", version);\n        TEST_ASSERT_EQUAL_STRING (\"NULL\", mechanism);\n\n        send_string_expect_success (handler_, version, ZMQ_SNDMORE);\n        send_string_expect_success (handler_, sequence, ZMQ_SNDMORE);\n        if (streq (domain, \"TEST\")) {\n            send_string_expect_success (handler_, \"200\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"OK\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"anonymous\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"\", 0);\n        } else {\n            send_string_expect_success (handler_, \"400\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"BAD DOMAIN\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"\", ZMQ_SNDMORE);\n            send_string_expect_success (handler_, \"\", 0);\n        }\n        free (version);\n        free (sequence);\n        free (domain);\n        free (address);\n        free (routing_id);\n        free (mechanism);\n    }\n    close_zero_linger (handler_);\n}\n\nvoid *zap_thread;\n\nstatic void setup_zap_handler ()\n{\n    //  Spawn ZAP handler\n    //  We create and bind ZAP socket in main thread to avoid case\n    //  where child thread does not start up fast enough.\n    void *handler = zmq_socket (get_test_context (), ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, \"inproc://zeromq.zap.01\"));\n    zap_thread = zmq_threadstart (&zap_handler, handler);\n}\n\nstatic void teardown_zap_handler ()\n{\n    //  Wait until ZAP handler terminates\n    zmq_threadclose (zap_thread);\n}\n\nvoid setUp ()\n{\n    setup_test_context ();\n    setup_zap_handler ();\n}\n\nvoid tearDown ()\n{\n    teardown_test_context ();\n    teardown_zap_handler ();\n}\n\nvoid test_no_domain ()\n{\n    //  We first test client/server with no ZAP domain\n    //  Libzmq does not call our ZAP handler, the connect must succeed\n    void *server = test_context_socket (ZMQ_DEALER);\n    void *client = test_context_socket (ZMQ_DEALER);\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    bounce (server, client);\n    test_context_socket_close_zero_linger (client);\n    test_context_socket_close_zero_linger (server);\n}\n\nvoid test_wrong_domain_fails ()\n{\n    //  Now define a ZAP domain for the server; this enables\n    //  authentication. We're using the wrong domain so this test\n    //  must fail.\n    void *server = test_context_socket (ZMQ_DEALER);\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, \"WRONG\", 5));\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    expect_bounce_fail (server, client);\n    test_context_socket_close_zero_linger (client);\n    test_context_socket_close_zero_linger (server);\n}\n\nvoid test_success ()\n{\n    //  Now use the right domain, the test must pass\n    void *server = test_context_socket (ZMQ_DEALER);\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, \"TEST\", 4));\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    bounce (server, client);\n    test_context_socket_close_zero_linger (client);\n    test_context_socket_close_zero_linger (server);\n}\n\nvoid test_vanilla_socket ()\n{\n    // Unauthenticated messages from a vanilla socket shouldn't be received\n    void *server = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, \"WRONG\", 5));\n    char my_endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n\n    fd_t s = connect_socket (my_endpoint);\n\n    // send anonymous ZMTP/1.0 greeting\n    send (s, \"\\x01\\x00\", 2, 0);\n    // send sneaky message that shouldn't be received\n    send (s, \"\\x08\\x00sneaky\\0\", 9, 0);\n    int timeout = 250;\n    zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));\n    char *buf = s_recv (server);\n    if (buf != NULL) {\n        printf (\"Received unauthenticated message: %s\\n\", buf);\n        TEST_ASSERT_NULL (buf);\n    }\n    close (s);\n    test_context_socket_close_zero_linger (server);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_no_domain);\n    RUN_TEST (test_wrong_domain_fails);\n    RUN_TEST (test_success);\n    RUN_TEST (test_vanilla_socket);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_security_plain.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\nstatic void zap_handler (void *zap_)\n{\n    //  Process ZAP requests forever\n    while (true) {\n        char *version = s_recv (zap_);\n        if (!version)\n            break; //  Terminating\n        char *sequence = s_recv (zap_);\n        char *domain = s_recv (zap_);\n        char *address = s_recv (zap_);\n        char *routing_id = s_recv (zap_);\n        char *mechanism = s_recv (zap_);\n        char *username = s_recv (zap_);\n        char *password = s_recv (zap_);\n\n        TEST_ASSERT_EQUAL_STRING (\"1.0\", version);\n        TEST_ASSERT_EQUAL_STRING (\"PLAIN\", mechanism);\n        TEST_ASSERT_EQUAL_STRING (\"IDENT\", routing_id);\n\n        send_string_expect_success (zap_, version, ZMQ_SNDMORE);\n        send_string_expect_success (zap_, sequence, ZMQ_SNDMORE);\n        if (streq (username, \"admin\") && streq (password, \"password\")) {\n            send_string_expect_success (zap_, \"200\", ZMQ_SNDMORE);\n            send_string_expect_success (zap_, \"OK\", ZMQ_SNDMORE);\n            send_string_expect_success (zap_, \"anonymous\", ZMQ_SNDMORE);\n            send_string_expect_success (zap_, \"\", 0);\n        } else {\n            send_string_expect_success (zap_, \"400\", ZMQ_SNDMORE);\n            send_string_expect_success (zap_, \"Invalid username or password\",\n                                        ZMQ_SNDMORE);\n            send_string_expect_success (zap_, \"\", ZMQ_SNDMORE);\n            send_string_expect_success (zap_, \"\", 0);\n        }\n        free (version);\n        free (sequence);\n        free (domain);\n        free (address);\n        free (routing_id);\n        free (mechanism);\n        free (username);\n        free (password);\n    }\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (zap_));\n}\n\nvoid *zap_thread;\n\nchar my_endpoint[MAX_SOCKET_STRING];\n\nstatic void setup_zap_handler ()\n{\n    //  Spawn ZAP handler\n    //  We create and bind ZAP socket in main thread to avoid case\n    //  where child thread does not start up fast enough.\n    void *handler = zmq_socket (get_test_context (), ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, \"inproc://zeromq.zap.01\"));\n    zap_thread = zmq_threadstart (&zap_handler, handler);\n}\n\nstatic void teardown_zap_handler ()\n{\n    //  Wait until ZAP handler terminates\n    zmq_threadclose (zap_thread);\n}\n\nconst char domain[] = \"test\";\n\nvoid *server;\n\nstatic void setup_server ()\n{\n    //  Server socket will accept connections\n    server = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_ROUTING_ID, \"IDENT\", 6));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, domain, strlen (domain)));\n    const int as_server = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_PLAIN_SERVER, &as_server, sizeof (int)));\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n}\n\nstatic void teardown_server ()\n{\n    test_context_socket_close (server);\n}\n\nvoid setUp ()\n{\n    setup_test_context ();\n    setup_zap_handler ();\n    setup_server ();\n}\n\nvoid tearDown ()\n{\n    teardown_server ();\n    teardown_test_context ();\n    teardown_zap_handler ();\n}\n\nvoid test_plain_success ()\n{\n    //  Check PLAIN security with correct username/password\n    void *client = test_context_socket (ZMQ_DEALER);\n    const char username[] = \"admin\";\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, username, strlen (username)));\n    const char password[] = \"password\";\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, password, strlen (password)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    bounce (server, client);\n    test_context_socket_close (client);\n}\n\nvoid test_plain_client_as_server_fails ()\n{\n    //  Check PLAIN security with badly configured client (as_server)\n    //  This will be caught by the plain_server class, not passed to ZAP\n    void *client = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_ZAP_DOMAIN, domain, strlen (domain)));\n    const int as_server = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PLAIN_SERVER, &as_server, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    expect_bounce_fail (server, client);\n    test_context_socket_close_zero_linger (client);\n}\n\nvoid test_plain_wrong_credentials_fails ()\n{\n    //  Check PLAIN security -- failed authentication\n    void *client = test_context_socket (ZMQ_DEALER);\n    const char username[] = \"wronguser\";\n    const char password[] = \"wrongpass\";\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, username, strlen (username)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, password, strlen (password)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    expect_bounce_fail (server, client);\n    test_context_socket_close_zero_linger (client);\n}\n\nvoid test_plain_vanilla_socket ()\n{\n    // Unauthenticated messages from a vanilla socket shouldn't be received\n    fd_t s = connect_socket (my_endpoint);\n    // send anonymous ZMTP/1.0 greeting\n    send (s, \"\\x01\\x00\", 2, 0);\n    // send sneaky message that shouldn't be received\n    send (s, \"\\x08\\x00sneaky\\0\", 9, 0);\n    int timeout = 250;\n    zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));\n    char *buf = s_recv (server);\n    if (buf != NULL) {\n        printf (\"Received unauthenticated message: %s\\n\", buf);\n        TEST_ASSERT_NULL (buf);\n    }\n    close (s);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_plain_success);\n    RUN_TEST (test_plain_client_as_server_fails);\n    RUN_TEST (test_plain_wrong_credentials_fails);\n    RUN_TEST (test_plain_vanilla_socket);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_security_zap.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil_security.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nstatic void zap_handler_wrong_version (void * /*unused_*/)\n{\n    zap_handler_generic (zap_wrong_version);\n}\n\nstatic void zap_handler_wrong_request_id (void * /*unused_*/)\n{\n    zap_handler_generic (zap_wrong_request_id);\n}\n\nstatic void zap_handler_wrong_status_invalid (void * /*unused_*/)\n{\n    zap_handler_generic (zap_status_invalid);\n}\n\nstatic void zap_handler_wrong_status_temporary_failure (void * /*unused_*/)\n{\n    zap_handler_generic (zap_status_temporary_failure);\n}\n\nstatic void zap_handler_wrong_status_internal_error (void * /*unused_*/)\n{\n    zap_handler_generic (zap_status_internal_error);\n}\n\nstatic void zap_handler_too_many_parts (void * /*unused_*/)\n{\n    zap_handler_generic (zap_too_many_parts);\n}\n\nstatic void zap_handler_disconnect (void * /*unused_*/)\n{\n    zap_handler_generic (zap_disconnect);\n}\n\nstatic void zap_handler_do_not_recv (void * /*unused_*/)\n{\n    zap_handler_generic (zap_do_not_recv);\n}\n\nstatic void zap_handler_do_not_send (void * /*unused_*/)\n{\n    zap_handler_generic (zap_do_not_send);\n}\n\nint expect_new_client_bounce_fail_and_count_monitor_events (\n  char *my_endpoint_,\n  void *server_,\n  socket_config_fn socket_config_,\n  void *socket_config_data_,\n  void **client_mon_,\n  void *server_mon_,\n  int expected_server_event_,\n  int expected_server_value_,\n  int expected_client_event_ = 0,\n  int expected_client_value_ = 0)\n{\n    expect_new_client_bounce_fail (\n      my_endpoint_, server_, socket_config_, socket_config_data_, client_mon_,\n      expected_client_event_, expected_client_value_);\n\n    int events_received = 0;\n    events_received = expect_monitor_event_multiple (\n      server_mon_, expected_server_event_, expected_server_value_);\n\n    return events_received;\n}\n\nvoid test_zap_unsuccessful (char *my_endpoint_,\n                            void *server_,\n                            void *server_mon_,\n                            int expected_server_event_,\n                            int expected_server_value_,\n                            socket_config_fn socket_config_,\n                            void *socket_config_data_,\n                            void **client_mon_ = NULL,\n                            int expected_client_event_ = 0,\n                            int expected_client_value_ = 0)\n{\n    int server_events_received =\n      expect_new_client_bounce_fail_and_count_monitor_events (\n        my_endpoint_, server_, socket_config_, socket_config_data_, client_mon_,\n        server_mon_, expected_server_event_, expected_server_value_,\n        expected_client_event_, expected_client_value_);\n\n    //  there may be more than one ZAP request due to repeated attempts by the\n    //  client (actually only in case if ZAP status code 300)\n    TEST_ASSERT_TRUE (server_events_received == 0\n                      || 1 <= zmq_atomic_counter_value (zap_requests_handled));\n}\n\nvoid test_zap_unsuccessful_no_handler (char *my_endpoint_,\n                                       void *server_,\n                                       void *server_mon_,\n                                       int expected_event_,\n                                       int expected_err_,\n                                       socket_config_fn socket_config_,\n                                       void *socket_config_data_,\n                                       void **client_mon_ = NULL)\n{\n    const int events_received =\n      expect_new_client_bounce_fail_and_count_monitor_events (\n        my_endpoint_, server_, socket_config_, socket_config_data_, client_mon_,\n        server_mon_, expected_event_, expected_err_);\n\n    //  there may be more than one ZAP request due to repeated attempts by the\n    //  client\n    TEST_ASSERT_GREATER_THAN_INT (0, events_received);\n}\n\nvoid test_zap_protocol_error (char *my_endpoint_,\n                              void *server_,\n                              void *server_mon_,\n                              socket_config_fn socket_config_,\n                              void *socket_config_data_,\n                              int expected_error_)\n{\n    test_zap_unsuccessful (my_endpoint_, server_, server_mon_,\n                           ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, expected_error_,\n                           socket_config_, socket_config_data_);\n}\n\nvoid test_zap_unsuccessful_status_300 (char *my_endpoint_,\n                                       void *server_,\n                                       void *server_mon_,\n                                       socket_config_fn client_socket_config_,\n                                       void *client_socket_config_data_)\n{\n    void *client_mon;\n    test_zap_unsuccessful (\n      my_endpoint_, server_, server_mon_, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 300,\n      client_socket_config_, client_socket_config_data_, &client_mon);\n\n    // we can use a 0 timeout here, since the client socket is already closed\n    assert_no_more_monitor_events_with_timeout (client_mon, 0);\n\n    test_context_socket_close (client_mon);\n}\n\nvoid test_zap_unsuccessful_status_500 (char *my_endpoint_,\n                                       void *server_,\n                                       void *server_mon_,\n                                       socket_config_fn client_socket_config_,\n                                       void *client_socket_config_data_)\n{\n    test_zap_unsuccessful (my_endpoint_, server_, server_mon_,\n                           ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 500,\n                           client_socket_config_, client_socket_config_data_,\n                           NULL, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 500);\n}\n\nstatic void\ntest_zap_protocol_error_closure (socket_config_fn server_socket_config_,\n                                 socket_config_fn client_socket_config_,\n                                 void *client_socket_config_data_,\n                                 void *server_socket_config_data_,\n                                 zmq_thread_fn zap_handler_,\n                                 int expected_failure_)\n{\n    void *handler, *zap_thread, *server, *server_mon;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    setup_context_and_server_side (\n      &handler, &zap_thread, &server, &server_mon, my_endpoint, zap_handler_,\n      server_socket_config_, server_socket_config_data_);\n    test_zap_protocol_error (my_endpoint, server, server_mon,\n                             client_socket_config_, client_socket_config_data_,\n                             expected_failure_);\n    shutdown_context_and_server_side (zap_thread, server, server_mon, handler);\n}\n\nstatic void\ntest_zap_protocol_error_wrong_version (socket_config_fn server_socket_config_,\n                                       socket_config_fn client_socket_config_,\n                                       void *client_socket_config_data_,\n                                       void *server_socket_config_data_)\n{\n    test_zap_protocol_error_closure (\n      server_socket_config_, client_socket_config_, client_socket_config_data_,\n      server_socket_config_data_, &zap_handler_wrong_version,\n      ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION);\n}\n\nstatic void test_zap_protocol_error_wrong_request_id (\n  socket_config_fn server_socket_config_,\n  socket_config_fn client_socket_config_,\n  void *client_socket_config_data_,\n  void *server_socket_config_data_)\n{\n    test_zap_protocol_error_closure (\n      server_socket_config_, client_socket_config_, client_socket_config_data_,\n      server_socket_config_data_, &zap_handler_wrong_request_id,\n      ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID);\n}\n\nstatic void test_zap_protocol_error_wrong_status_invalid (\n  socket_config_fn server_socket_config_,\n  socket_config_fn client_socket_config_,\n  void *client_socket_config_data_,\n  void *server_socket_config_data_)\n{\n    test_zap_protocol_error_closure (\n      server_socket_config_, client_socket_config_, client_socket_config_data_,\n      server_socket_config_data_, &zap_handler_wrong_status_invalid,\n      ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE);\n}\n\nstatic void\ntest_zap_protocol_error_too_many_parts (socket_config_fn server_socket_config_,\n                                        socket_config_fn client_socket_config_,\n                                        void *client_socket_config_data_,\n                                        void *server_socket_config_data_)\n{\n    test_zap_protocol_error_closure (\n      server_socket_config_, client_socket_config_, client_socket_config_data_,\n      server_socket_config_data_, &zap_handler_too_many_parts,\n      ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY);\n}\n\n//  TODO the failed status (300/500) should be observable as monitoring events on the client side as well (they are\n//  already transmitted as an ERROR message)\n\nstatic void\ntest_zap_wrong_status_temporary_failure (socket_config_fn server_socket_config_,\n                                         socket_config_fn client_socket_config_,\n                                         void *client_socket_config_data_,\n                                         void *server_socket_config_data_)\n{\n    void *handler, *zap_thread, *server, *server_mon;\n    char my_endpoint[MAX_SOCKET_STRING];\n    setup_context_and_server_side (\n      &handler, &zap_thread, &server, &server_mon, my_endpoint,\n      &zap_handler_wrong_status_temporary_failure, server_socket_config_,\n      server_socket_config_data_);\n    test_zap_unsuccessful_status_300 (my_endpoint, server, server_mon,\n                                      client_socket_config_,\n                                      client_socket_config_data_);\n    shutdown_context_and_server_side (zap_thread, server, server_mon, handler);\n}\n\nstatic void\ntest_zap_wrong_status_internal_error (socket_config_fn server_socket_config_,\n                                      socket_config_fn client_socket_config_,\n                                      void *client_socket_config_data_)\n{\n    void *handler, *zap_thread, *server, *server_mon;\n    char my_endpoint[MAX_SOCKET_STRING];\n    setup_context_and_server_side (\n      &handler, &zap_thread, &server, &server_mon, my_endpoint,\n      &zap_handler_wrong_status_internal_error, server_socket_config_);\n    test_zap_unsuccessful_status_500 (my_endpoint, server, server_mon,\n                                      client_socket_config_,\n                                      client_socket_config_data_);\n    shutdown_context_and_server_side (zap_thread, server, server_mon, handler);\n}\n\nstatic void\ntest_zap_unsuccesful_no_handler_started (socket_config_fn server_socket_config_,\n                                         socket_config_fn client_socket_config_,\n                                         void *client_socket_config_data_,\n                                         void *server_socket_config_data_)\n{\n#ifdef ZMQ_ZAP_ENFORCE_DOMAIN\n    void *handler, *zap_thread, *server, *server_mon;\n    char my_endpoint[MAX_SOCKET_STRING];\n    // TODO this looks wrong, where will the enforce value be used?\n\n    //  no ZAP handler\n    int enforce = 1;\n    setup_context_and_server_side (\n      &handler, &zap_thread, &server, &server_mon, my_endpoint, NULL,\n      server_socket_config_,\n      server_socket_config_data_ ? server_socket_config_data_ : &enforce);\n    test_zap_unsuccessful_no_handler (\n      my_endpoint, server, server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL,\n      EFAULT, client_socket_config_, client_socket_config_data_);\n    shutdown_context_and_server_side (zap_thread, server, server_mon, handler);\n#endif\n}\n\nstatic void\ntest_zap_unsuccesful_no_handler_closure (socket_config_fn server_socket_config_,\n                                         socket_config_fn client_socket_config_,\n                                         void *client_socket_config_data_,\n                                         zmq_thread_fn zap_handler_func_,\n                                         bool zap_handler_disconnected_ = false)\n{\n    void *handler, *zap_thread, *server, *server_mon;\n    char my_endpoint[MAX_SOCKET_STRING];\n    setup_context_and_server_side (&handler, &zap_thread, &server, &server_mon,\n                                   my_endpoint, zap_handler_func_,\n                                   server_socket_config_);\n    test_zap_unsuccessful_no_handler (\n      my_endpoint, server, server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL,\n      EPIPE, client_socket_config_, client_socket_config_data_);\n    shutdown_context_and_server_side (zap_thread, server, server_mon, handler,\n                                      zap_handler_disconnected_);\n}\n\nstatic void\ntest_zap_unsuccesful_disconnect (socket_config_fn server_socket_config_,\n                                 socket_config_fn client_socket_config_,\n                                 void *client_socket_config_data_)\n{\n    test_zap_unsuccesful_no_handler_closure (\n      server_socket_config_, client_socket_config_, client_socket_config_data_,\n      &zap_handler_disconnect, true);\n}\n\nstatic void\ntest_zap_unsuccesful_do_not_recv (socket_config_fn server_socket_config_,\n                                  socket_config_fn client_socket_config_,\n                                  void *client_socket_config_data_)\n{\n    test_zap_unsuccesful_no_handler_closure (\n      server_socket_config_, client_socket_config_, client_socket_config_data_,\n      &zap_handler_do_not_recv);\n}\n\nstatic void\ntest_zap_unsuccesful_do_not_send (socket_config_fn server_socket_config_,\n                                  socket_config_fn client_socket_config_,\n                                  void *client_socket_config_data_)\n{\n    test_zap_unsuccesful_no_handler_closure (\n      server_socket_config_, client_socket_config_, client_socket_config_data_,\n      &zap_handler_do_not_send);\n}\n\n#define DEFINE_ZAP_ERROR_TESTS(                                                \\\n  name_, server_socket_config_, server_socket_config_data_,                    \\\n  client_socket_config_, client_socket_config_data_)                           \\\n    void test_zap_protocol_error_wrong_version_##name_ ()                      \\\n    {                                                                          \\\n        test_zap_protocol_error_wrong_version (                                \\\n          server_socket_config_, client_socket_config_,                        \\\n          client_socket_config_data_, server_socket_config_data_);             \\\n    }                                                                          \\\n    void test_zap_protocol_error_wrong_request_id_##name_ ()                   \\\n    {                                                                          \\\n        test_zap_protocol_error_wrong_request_id (                             \\\n          server_socket_config_, client_socket_config_,                        \\\n          client_socket_config_data_, server_socket_config_data_);             \\\n    }                                                                          \\\n    void test_zap_protocol_error_wrong_status_invalid_##name_ ()               \\\n    {                                                                          \\\n        test_zap_protocol_error_wrong_status_invalid (                         \\\n          server_socket_config_, client_socket_config_,                        \\\n          client_socket_config_data_, server_socket_config_data_);             \\\n    }                                                                          \\\n    void test_zap_protocol_error_too_many_parts_##name_ ()                     \\\n    {                                                                          \\\n        test_zap_protocol_error_too_many_parts (                               \\\n          server_socket_config_, client_socket_config_,                        \\\n          client_socket_config_data_, server_socket_config_data_);             \\\n    }                                                                          \\\n    void test_zap_wrong_status_temporary_failure_##name_ ()                    \\\n    {                                                                          \\\n        test_zap_wrong_status_temporary_failure (                              \\\n          server_socket_config_, client_socket_config_,                        \\\n          client_socket_config_data_, server_socket_config_data_);             \\\n    }                                                                          \\\n    void test_zap_wrong_status_internal_error_##name_ ()                       \\\n    {                                                                          \\\n        test_zap_wrong_status_internal_error (server_socket_config_,           \\\n                                              client_socket_config_,           \\\n                                              client_socket_config_data_);     \\\n    }                                                                          \\\n    void test_zap_unsuccessful_no_handler_started_##name_ ()                   \\\n    {                                                                          \\\n        test_zap_unsuccesful_no_handler_started (                              \\\n          server_socket_config_, client_socket_config_,                        \\\n          client_socket_config_data_, server_socket_config_data_);             \\\n    }                                                                          \\\n    void test_zap_unsuccessful_disconnect_##name_ ()                           \\\n    {                                                                          \\\n        test_zap_unsuccesful_disconnect (server_socket_config_,                \\\n                                         client_socket_config_,                \\\n                                         client_socket_config_data_);          \\\n    }                                                                          \\\n    void test_zap_unsuccessful_do_not_recv_##name_ ()                          \\\n    {                                                                          \\\n        test_zap_unsuccesful_do_not_recv (server_socket_config_,               \\\n                                          client_socket_config_,               \\\n                                          client_socket_config_data_);         \\\n    }                                                                          \\\n    void test_zap_unsuccessful_do_not_send_##name_ ()                          \\\n    {                                                                          \\\n        test_zap_unsuccesful_do_not_send (server_socket_config_,               \\\n                                          client_socket_config_,               \\\n                                          client_socket_config_data_);         \\\n    }\n\nDEFINE_ZAP_ERROR_TESTS (\n  null, &socket_config_null_server, NULL, &socket_config_null_client, NULL)\n\nDEFINE_ZAP_ERROR_TESTS (\n  plain, &socket_config_plain_server, NULL, &socket_config_plain_client, NULL)\n\nstatic curve_client_data_t curve_client_data = {\n  valid_server_public, valid_client_public, valid_client_secret};\n\nDEFINE_ZAP_ERROR_TESTS (curve,\n                        &socket_config_curve_server,\n                        valid_server_secret,\n                        &socket_config_curve_client,\n                        &curve_client_data)\n\n#define RUN_ZAP_ERROR_TESTS(name_)                                             \\\n    {                                                                          \\\n        RUN_TEST (test_zap_protocol_error_wrong_version_##name_);              \\\n        RUN_TEST (test_zap_protocol_error_wrong_request_id_##name_);           \\\n        RUN_TEST (test_zap_protocol_error_wrong_status_invalid_##name_);       \\\n        RUN_TEST (test_zap_protocol_error_too_many_parts_##name_);             \\\n        RUN_TEST (test_zap_wrong_status_temporary_failure_##name_);            \\\n        RUN_TEST (test_zap_wrong_status_internal_error_##name_);               \\\n        RUN_TEST (test_zap_unsuccessful_no_handler_started_##name_);           \\\n        RUN_TEST (test_zap_unsuccessful_disconnect_##name_);                   \\\n        RUN_TEST (test_zap_unsuccessful_do_not_recv_##name_);                  \\\n        RUN_TEST (test_zap_unsuccessful_do_not_send_##name_);                  \\\n    }\n\nint main ()\n{\n    setup_test_environment ();\n\n    if (zmq_has (\"curve\")) {\n        setup_testutil_security_curve ();\n    }\n\n    UNITY_BEGIN ();\n    RUN_ZAP_ERROR_TESTS (null);\n    RUN_ZAP_ERROR_TESTS (plain);\n    if (zmq_has (\"curve\")) {\n        RUN_ZAP_ERROR_TESTS (curve);\n    }\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_setsockopt.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_setsockopt_tcp_recv_buffer ()\n{\n    void *socket = test_context_socket (ZMQ_PUSH);\n\n    int val = 0;\n    size_t placeholder = sizeof (val);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket, ZMQ_RCVBUF, &val, &placeholder));\n    TEST_ASSERT_EQUAL_INT (-1, val);\n\n    val = 16384;\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket, ZMQ_RCVBUF, &val, sizeof (val)));\n    TEST_ASSERT_EQUAL_INT (16384, val);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket, ZMQ_RCVBUF, &val, &placeholder));\n    TEST_ASSERT_EQUAL_INT (16384, val);\n\n    test_context_socket_close (socket);\n}\n\nvoid test_setsockopt_tcp_send_buffer ()\n{\n    void *socket = test_context_socket (ZMQ_PUSH);\n\n    int val = 0;\n    size_t placeholder = sizeof (val);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket, ZMQ_SNDBUF, &val, &placeholder));\n    TEST_ASSERT_EQUAL_INT (-1, val);\n\n    val = 16384;\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket, ZMQ_SNDBUF, &val, sizeof (val)));\n    TEST_ASSERT_EQUAL_INT (16384, val);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket, ZMQ_SNDBUF, &val, &placeholder));\n    TEST_ASSERT_EQUAL_INT (16384, val);\n\n    test_context_socket_close (socket);\n}\n\nvoid test_setsockopt_use_fd ()\n{\n    void *socket = test_context_socket (ZMQ_PUSH);\n\n    int val = 0;\n    size_t placeholder = sizeof (val);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket, ZMQ_USE_FD, &val, &placeholder));\n    TEST_ASSERT_EQUAL_INT (-1, val);\n\n    val = 3;\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket, ZMQ_USE_FD, &val, sizeof (val)));\n    TEST_ASSERT_EQUAL_INT (3, val);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket, ZMQ_USE_FD, &val, &placeholder));\n    TEST_ASSERT_EQUAL_INT (3, val);\n\n    test_context_socket_close (socket);\n}\n\n#define BOUNDDEVBUFSZ 16\nvoid test_setsockopt_bindtodevice ()\n{\n    void *socket = test_context_socket (ZMQ_PUSH);\n\n#ifdef ZMQ_BINDTODEVICE\n    char devname[BOUNDDEVBUFSZ];\n    size_t buflen = BOUNDDEVBUFSZ;\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket, ZMQ_BINDTODEVICE, devname, &buflen));\n    TEST_ASSERT_EQUAL_INT8 ('\\0', devname[0]);\n    TEST_ASSERT_EQUAL_UINT (1, buflen);\n\n    snprintf (devname, BOUNDDEVBUFSZ * sizeof (char), \"testdev\");\n    buflen = strlen (devname);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket, ZMQ_BINDTODEVICE, devname, buflen));\n\n    buflen = BOUNDDEVBUFSZ;\n    memset (devname, 0, buflen);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket, ZMQ_BINDTODEVICE, devname, &buflen));\n    TEST_ASSERT_EQUAL_STRING_LEN (\"testdev\", devname, buflen);\n#endif\n\n    test_context_socket_close (socket);\n}\n\nvoid test_setsockopt_priority ()\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n#ifdef ZMQ_HAVE_SO_PRIORITY\n    void *socket = test_context_socket (ZMQ_PUSH);\n\n    int val = 5;\n    size_t placeholder = sizeof (val);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket, ZMQ_PRIORITY, &val, &placeholder));\n    TEST_ASSERT_EQUAL_INT (0, val);\n\n    val = 3;\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket, ZMQ_PRIORITY, &val, sizeof (val)));\n    TEST_ASSERT_EQUAL_INT (3, val);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket, ZMQ_PRIORITY, &val, &placeholder));\n    TEST_ASSERT_EQUAL_INT (3, val);\n\n    test_context_socket_close (socket);\n#else\n    TEST_IGNORE_MESSAGE (\"libzmq without ZMQ_PRIORITY support, \"\n                         \"ignoring setsockopt_priority test\");\n#endif\n#else\n    TEST_IGNORE_MESSAGE (\"libzmq without DRAFT support, ignoring \"\n                         \"setsockopt_priority test\");\n#endif\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_setsockopt_tcp_recv_buffer);\n    RUN_TEST (test_setsockopt_tcp_send_buffer);\n    RUN_TEST (test_setsockopt_use_fd);\n    RUN_TEST (test_setsockopt_bindtodevice);\n    RUN_TEST (test_setsockopt_priority);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_shutdown_stress.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\n#define THREAD_COUNT 100\n\nstruct thread_data\n{\n    char endpoint[MAX_SOCKET_STRING];\n};\n\nextern \"C\" {\nstatic void worker (void *data_)\n{\n    const thread_data *const tdata = static_cast<const thread_data *> (data_);\n\n    void *socket = zmq_socket (get_test_context (), ZMQ_SUB);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (socket, tdata->endpoint));\n\n    //  Start closing the socket while the connecting process is underway.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));\n}\n}\n\nvoid test_shutdown_stress ()\n{\n    void *threads[THREAD_COUNT];\n\n    for (int j = 0; j != 10; j++) {\n        //  Check the shutdown with many parallel I/O threads.\n        struct thread_data tdata;\n        setup_test_context ();\n        zmq_ctx_set (get_test_context (), ZMQ_IO_THREADS, 7);\n\n        void *socket = test_context_socket (ZMQ_PUB);\n\n        bind_loopback_ipv4 (socket, tdata.endpoint, sizeof (tdata.endpoint));\n\n        for (int i = 0; i != THREAD_COUNT; i++) {\n            threads[i] = zmq_threadstart (&worker, &tdata);\n        }\n\n        for (int i = 0; i != THREAD_COUNT; i++) {\n            zmq_threadclose (threads[i]);\n        }\n\n        test_context_socket_close (socket);\n\n        teardown_test_context ();\n    }\n}\n\nint main ()\n{\n    setup_test_environment (180);\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_shutdown_stress);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_shutdown_stress_tipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <pthread.h>\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\n#define THREAD_COUNT 100\n\nextern \"C\" {\nstatic void *worker (void *ctx)\n{\n    void *s = zmq_socket (ctx, ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (s, \"tipc://{5560,0}@0.0.0\"));\n\n    //  Start closing the socket while the connecting process is underway.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (s));\n\n    return NULL;\n}\n}\n\nvoid test_shutdown_stress_tipc ()\n{\n    void *s1;\n    int i;\n    int j;\n    pthread_t threads[THREAD_COUNT];\n\n    for (j = 0; j != 10; j++) {\n        //  Check the shutdown with many parallel I/O threads.\n        setup_test_context ();\n        zmq_ctx_set (get_test_context (), ZMQ_IO_THREADS, 7);\n\n        s1 = test_context_socket (ZMQ_PUB);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (s1, \"tipc://{5560,0,0}\"));\n\n        for (i = 0; i != THREAD_COUNT; i++) {\n            TEST_ASSERT_SUCCESS_RAW_ERRNO (\n              pthread_create (&threads[i], NULL, worker, get_test_context ()));\n        }\n\n        for (i = 0; i != THREAD_COUNT; i++) {\n            TEST_ASSERT_SUCCESS_RAW_ERRNO (pthread_join (threads[i], NULL));\n        }\n\n        test_context_socket_close (s1);\n\n        teardown_test_context ();\n    }\n}\n\nint main ()\n{\n    if (!is_tipc_available ()) {\n        printf (\"TIPC environment unavailable, skipping test\\n\");\n        return 77;\n    }\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_shutdown_stress_tipc);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_socket_null.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n\n#include <unity.h>\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\n//  tests all socket-related functions with a NULL socket argument\nvoid test_zmq_socket_null_context ()\n{\n    TEST_ASSERT_NULL (zmq_socket (NULL, ZMQ_PAIR));\n    TEST_ASSERT_EQUAL_INT (EFAULT, errno); // TODO use EINVAL instead?\n}\n\nvoid test_zmq_close_null_socket ()\n{\n    int rc = zmq_close (NULL);\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?\n}\n\nvoid test_zmq_setsockopt_null_socket ()\n{\n    int hwm = 100;\n    size_t hwm_size = sizeof hwm;\n    int rc = zmq_setsockopt (NULL, ZMQ_SNDHWM, &hwm, hwm_size);\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?\n}\n\nvoid test_zmq_getsockopt_null_socket ()\n{\n    int hwm;\n    size_t hwm_size = sizeof hwm;\n    int rc = zmq_getsockopt (NULL, ZMQ_SNDHWM, &hwm, &hwm_size);\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?\n}\n\nvoid test_zmq_socket_monitor_null_socket ()\n{\n    int rc = zmq_socket_monitor (NULL, \"inproc://monitor\", ZMQ_EVENT_ALL);\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?\n}\n\n#ifdef ZMQ_BUILD_DRAFT_API\nvoid test_zmq_join_null_socket ()\n{\n    int rc = zmq_join (NULL, \"group\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?\n}\n\nvoid test_zmq_leave_null_socket ()\n{\n    int rc = zmq_leave (NULL, \"group\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?\n}\n#endif\n\n\nvoid test_zmq_bind_null_socket ()\n{\n    int rc = zmq_bind (NULL, \"inproc://socket\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?\n}\n\nvoid test_zmq_connect_null_socket ()\n{\n    int rc = zmq_connect (NULL, \"inproc://socket\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?\n}\n\nvoid test_zmq_unbind_null_socket ()\n{\n    int rc = zmq_unbind (NULL, \"inproc://socket\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?\n}\n\nvoid test_zmq_disconnect_null_socket ()\n{\n    int rc = zmq_disconnect (NULL, \"inproc://socket\");\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n    TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?\n}\n\nint main (void)\n{\n    UNITY_BEGIN ();\n    RUN_TEST (test_zmq_socket_null_context);\n    RUN_TEST (test_zmq_close_null_socket);\n    RUN_TEST (test_zmq_setsockopt_null_socket);\n    RUN_TEST (test_zmq_getsockopt_null_socket);\n    RUN_TEST (test_zmq_socket_monitor_null_socket);\n    RUN_TEST (test_zmq_bind_null_socket);\n    RUN_TEST (test_zmq_connect_null_socket);\n    RUN_TEST (test_zmq_unbind_null_socket);\n    RUN_TEST (test_zmq_disconnect_null_socket);\n\n#ifdef ZMQ_BUILD_DRAFT_API\n    RUN_TEST (test_zmq_join_null_socket);\n    RUN_TEST (test_zmq_leave_null_socket);\n#endif\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_socket_options_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#ifdef ZMQ_DISCONNECT_MSG\n#define LAST_OPTION ZMQ_DISCONNECT_MSG\n#else\n#define LAST_OPTION ZMQ_BINDTODEVICE\n#endif\n\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    int option;\n    void *ctx = zmq_ctx_new ();\n    TEST_ASSERT_NOT_NULL (ctx);\n    void *server = zmq_socket (ctx, ZMQ_XPUB);\n    TEST_ASSERT_NOT_NULL (server);\n\n    if (!size)\n        return 0;\n\n    for (option = ZMQ_AFFINITY; option <= LAST_OPTION; ++option) {\n        uint8_t out[8192];\n        size_t out_size = 8192;\n\n        zmq_setsockopt (server, option, data, size);\n        zmq_getsockopt (server, option, out, &out_size);\n    }\n\n    zmq_close (server);\n    zmq_ctx_term (ctx);\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_socket_options_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_socket_options_fuzzer_seed_corpus\",\n          &data, &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_socket_options_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_sockopt_hwm.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nconst int MAX_SENDS = 10000;\n\nvoid test_change_before_connected ()\n{\n    int rc;\n\n    void *bind_socket = test_context_socket (ZMQ_PUSH);\n    void *connect_socket = test_context_socket (ZMQ_PULL);\n\n    int val = 2;\n    rc = zmq_setsockopt (connect_socket, ZMQ_RCVHWM, &val, sizeof (val));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n    rc = zmq_setsockopt (bind_socket, ZMQ_SNDHWM, &val, sizeof (val));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    zmq_connect (connect_socket, \"inproc://a\");\n    zmq_bind (bind_socket, \"inproc://a\");\n\n    size_t placeholder = sizeof (val);\n    val = 0;\n    rc = zmq_getsockopt (bind_socket, ZMQ_SNDHWM, &val, &placeholder);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n    TEST_ASSERT_EQUAL_INT (2, val);\n\n    int send_count = 0;\n    while (send_count < MAX_SENDS\n           && zmq_send (bind_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++send_count;\n\n    TEST_ASSERT_EQUAL_INT (4, send_count);\n\n    test_context_socket_close (bind_socket);\n    test_context_socket_close (connect_socket);\n}\n\nvoid test_change_after_connected ()\n{\n    int rc;\n\n    void *bind_socket = test_context_socket (ZMQ_PUSH);\n    void *connect_socket = test_context_socket (ZMQ_PULL);\n\n    int val = 1;\n    rc = zmq_setsockopt (connect_socket, ZMQ_RCVHWM, &val, sizeof (val));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n    rc = zmq_setsockopt (bind_socket, ZMQ_SNDHWM, &val, sizeof (val));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    zmq_connect (connect_socket, \"inproc://a\");\n    zmq_bind (bind_socket, \"inproc://a\");\n\n    val = 5;\n    rc = zmq_setsockopt (bind_socket, ZMQ_SNDHWM, &val, sizeof (val));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    size_t placeholder = sizeof (val);\n    val = 0;\n    rc = zmq_getsockopt (bind_socket, ZMQ_SNDHWM, &val, &placeholder);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n    TEST_ASSERT_EQUAL_INT (5, val);\n\n    int send_count = 0;\n    while (send_count < MAX_SENDS\n           && zmq_send (bind_socket, NULL, 0, ZMQ_DONTWAIT) == 0)\n        ++send_count;\n\n    TEST_ASSERT_EQUAL_INT (6, send_count);\n\n    test_context_socket_close (bind_socket);\n    test_context_socket_close (connect_socket);\n}\n\nint send_until_wouldblock (void *socket_)\n{\n    int send_count = 0;\n    while (send_count < MAX_SENDS\n           && zmq_send (socket_, &send_count, sizeof (send_count), ZMQ_DONTWAIT)\n                == sizeof (send_count)) {\n        ++send_count;\n    }\n    return send_count;\n}\n\nint test_fill_up_to_hwm (void *socket_, int sndhwm_)\n{\n    int send_count = send_until_wouldblock (socket_);\n    fprintf (stderr, \"sndhwm==%i, send_count==%i\\n\", sndhwm_, send_count);\n    TEST_ASSERT_LESS_OR_EQUAL_INT (sndhwm_ + 1, send_count);\n    TEST_ASSERT_GREATER_THAN_INT (sndhwm_ / 10, send_count);\n    return send_count;\n}\n\nvoid test_decrease_when_full ()\n{\n    int rc;\n\n    void *bind_socket = test_context_socket (ZMQ_PUSH);\n    void *connect_socket = test_context_socket (ZMQ_PULL);\n\n    int val = 1;\n    rc = zmq_setsockopt (connect_socket, ZMQ_RCVHWM, &val, sizeof (val));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    int sndhwm = 100;\n    rc = zmq_setsockopt (bind_socket, ZMQ_SNDHWM, &sndhwm, sizeof (sndhwm));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    zmq_bind (bind_socket, \"inproc://a\");\n    zmq_connect (connect_socket, \"inproc://a\");\n\n    //  we must wait for the connect to succeed here, unfortunately we don't\n    //  have monitoring events for inproc, so we just hope SETTLE_TIME suffices\n    msleep (SETTLE_TIME);\n\n    // Fill up to hwm\n    int send_count = test_fill_up_to_hwm (bind_socket, sndhwm);\n\n    // Decrease snd hwm\n    sndhwm = 70;\n    rc = zmq_setsockopt (bind_socket, ZMQ_SNDHWM, &sndhwm, sizeof (sndhwm));\n    TEST_ASSERT_EQUAL_INT (0, rc);\n\n    int sndhwm_read = 0;\n    size_t sndhwm_read_size = sizeof (sndhwm_read);\n    rc =\n      zmq_getsockopt (bind_socket, ZMQ_SNDHWM, &sndhwm_read, &sndhwm_read_size);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n    TEST_ASSERT_EQUAL_INT (sndhwm, sndhwm_read);\n\n    msleep (SETTLE_TIME);\n\n    // Read out all data (should get up to previous hwm worth so none were dropped)\n    int read_count = 0;\n    int read_data = 0;\n    while (\n      read_count < MAX_SENDS\n      && zmq_recv (connect_socket, &read_data, sizeof (read_data), ZMQ_DONTWAIT)\n           == sizeof (read_data)) {\n        TEST_ASSERT_EQUAL_INT (read_data, read_count);\n        ++read_count;\n    }\n\n    TEST_ASSERT_EQUAL_INT (send_count, read_count);\n\n    // Give io thread some time to catch up\n    msleep (SETTLE_TIME);\n\n    // Fill up to new hwm\n    test_fill_up_to_hwm (bind_socket, sndhwm);\n\n    test_context_socket_close (bind_socket);\n    test_context_socket_close (connect_socket);\n}\n\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_change_before_connected);\n    RUN_TEST (test_change_after_connected);\n    RUN_TEST (test_decrease_when_full);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_socks.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef _WIN32\n#include \"../src/windows.hpp\"\n#else\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <unistd.h>\n#endif\n\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n#include <fcntl.h>\n#include <errno.h>\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid recvall (int sock_fd, char *buffer, int len)\n{\n    int res;\n    int total = 0;\n    while (len - total > 0) {\n        res = recv (sock_fd, buffer + total, len - total, 0);\n        if (res == -1)\n            fprintf (stderr, \"socks_server: error receiving %d bytes: %d %d\\n\",\n                     len, res, errno);\n        TEST_ASSERT_SUCCESS_RAW_ERRNO (res);\n        TEST_ASSERT (res != 0);\n        total += res;\n    }\n    TEST_ASSERT (total == len);\n}\n\nint recvonce (int sock_fd, char *buffer, int len)\n{\n    int res;\n    res = recv (sock_fd, buffer, len, 0);\n    if (res == -1)\n        fprintf (stderr, \"socks_server: error receiving bytes: %d %d\\n\", res,\n                 errno);\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (res);\n    return res;\n}\n\nvoid sendall (int sock_fd, char *buffer, int len)\n{\n    int res;\n    int total = 0;\n    while (len - total > 0) {\n        res = send (sock_fd, buffer + total, len - total, 0);\n        if (res == -1)\n            fprintf (stderr, \"socks_server: error sending %d bytes: %d %d\\n\",\n                     len, res, errno);\n        TEST_ASSERT_SUCCESS_RAW_ERRNO (res);\n        TEST_ASSERT (res != 0);\n        total += res;\n    }\n}\n\nint remote_connect (int socket, uint32_t addr, uint16_t port)\n{\n    int res;\n    struct sockaddr_in ip4addr;\n    ip4addr.sin_family = AF_INET;\n    ip4addr.sin_addr.s_addr = htonl (addr);\n    ip4addr.sin_port = htons (port);\n    res = connect (socket, (struct sockaddr *) &ip4addr, sizeof ip4addr);\n    return res;\n}\n\nvoid *setup_socks_server (char *socks_server_address,\n                          int socks_server_address_len)\n{\n    LIBZMQ_UNUSED (socks_server_address_len);\n    fprintf (stderr, \"socks_server: setup socks server\\n\");\n    int server_fd =\n      bind_socket_resolve_port (\"127.0.0.1\", \"0\", socks_server_address);\n    memmove (socks_server_address, strchr (socks_server_address, '/') + 2,\n             strlen (strchr (socks_server_address, '/') + 1));\n    fprintf (stderr, \"socks_server: bound to: tcp://%s\\n\",\n             socks_server_address);\n    return (void *) (intptr_t) server_fd;\n}\n\nvoid socks_server_task (void *socks_server,\n                        const char *username,\n                        const char *password,\n                        int max_client_connect)\n{\n    int server_fd = (int) (intptr_t) socks_server;\n    fprintf (stderr, \"socks_server: starting server thread\\n\");\n\n    int res;\n    res = listen (server_fd, max_client_connect);\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (res);\n\n    int auth_method;\n    if (username == NULL || username[0] == '\\0') {\n        auth_method = 0x0; /* No auth */\n    } else {\n        auth_method = 0x2; /* Basic auth */\n        if (password == NULL)\n            password = \"\";\n    }\n\n    int count = 0;\n    while (count < max_client_connect) {\n        int client = -1;\n        do {\n            char buffer[4096];\n            fprintf (stderr, \"socks_server: waiting for connection\\n\");\n            client = accept (server_fd, NULL, NULL);\n            TEST_ASSERT_SUCCESS_RAW_ERRNO (client);\n            count++;\n            fprintf (stderr, \"socks_server: accepted client connection %d/%d\\n\",\n                     count, max_client_connect);\n\n            /* Greetings [version, nmethods, methods...]. */\n            recvall (client, buffer, 2);\n            TEST_ASSERT (buffer[0] == 0x5);\n            int nmethods = buffer[1];\n            int method = 0xff;\n            recvall (client, buffer, nmethods);\n            for (int i = 0; i < nmethods; i++) {\n                if (buffer[i] == auth_method)\n                    method = auth_method;\n            }\n            fprintf (stderr, \"socks_server: received greetings\\n\");\n\n            /* Greetings response [version, method]. */\n            buffer[0] = 0x5;\n            buffer[1] = method;\n            sendall (client, buffer, 2);\n            fprintf (stderr,\n                     \"socks_server: answered greetings (method: 0x%x)\\n\",\n                     method);\n\n            if (method == 0xff)\n                break; /* Out of client connection */\n\n            if (method == 0x2) {\n                int len;\n                int err = 0;\n                recvall (client, buffer, 1);\n                if (buffer[0] != 0x1) {\n                    err = 1;\n                } else {\n                    recvall (client, buffer, 1);\n                    len = (unsigned char) buffer[0];\n                    recvall (client, buffer, len);\n                    buffer[len] = '\\0';\n                    if (strcmp (username, buffer) != 0) {\n                        fprintf (stderr,\n                                 \"socks_server: error on username check: '%s', \"\n                                 \"expected: '%s'\\n\",\n                                 buffer, username);\n                        err = 1;\n                    }\n                    recvall (client, buffer, 1);\n                    len = (unsigned char) buffer[0];\n                    recvall (client, buffer, len);\n                    buffer[len] = '\\0';\n                    if (strcmp (password, buffer) != 0) {\n                        fprintf (stderr,\n                                 \"socks_server: error on password check: '%s', \"\n                                 \"expected: '%s'\\n\",\n                                 buffer, password);\n                        err = 1;\n                    }\n                }\n                fprintf (stderr, \"socks_server: received credentials\\n\");\n                buffer[0] = 0x1;\n                buffer[1] = err;\n                sendall (client, buffer, 2);\n                fprintf (stderr,\n                         \"socks_server: answered credentials (err: 0x%x)\\n\",\n                         err);\n                if (err != 0)\n                    break; /* Out of client connection. */\n            }\n\n            /* Request [version, cmd, rsv, atype, dst.addr, dst.port */\n            /* Test only tcp connect on top of IPV4 */\n            recvall (client, buffer, 4);\n            TEST_ASSERT (buffer[0] == 0x5);\n            TEST_ASSERT (buffer[1] == 0x1); /* CONNECT cmd */\n            TEST_ASSERT (buffer[2] == 0x0); /* reserved, ensure we send 0 */\n            fprintf (stderr,\n                     \"socks_server: received command (cmd: %d, atype: %d)\\n\",\n                     buffer[1], buffer[3]);\n            /* IPv4 ADDR & PORT */\n            uint32_t naddr = 0, bind_naddr = 0;\n            uint16_t nport = 0, bind_nport = 0;\n            int remote = -1;\n            int err = 0;\n            int request_atype = buffer[3];\n            if (request_atype == 0x1) /* ATYPE IPv4 */ {\n                recvall (client, (char *) &naddr, 4);\n                fprintf (stderr,\n                         \"socks_server: received address (addr: 0x%x)\\n\",\n                         ntohl (naddr));\n            } else if (request_atype == 0x3) /* ATYPE DOMAINNAME */ {\n                int len;\n                recvall (client, buffer, 1);\n                len = (unsigned char) buffer[0];\n                recvall (client, buffer, len);\n                buffer[len] = '\\0';\n                fprintf (stderr,\n                         \"socks_server: received domainname (hostname: %s)\\n\",\n                         buffer);\n                /* For the test we support static resolution of\n                   hostname \"somedomainnmame.org\" to localhost */\n                if (strcmp (\"somedomainname.org\", buffer) == 0) {\n                    naddr = htonl (0x7f000001); /* 127.0.0.1 */\n                } else {\n                    err = 0x4; /* Host unreachable */\n                }\n            } else if (request_atype == 0x4) {\n                /* For the test we simulate IPV6 connection request ::1, but connect to IPv4 localhost */\n                unsigned char nipv6local[16] = {0};\n                nipv6local[15] = 1;\n                recvall (client, buffer, 16);\n                fprintf (stderr,\n                         \"socks_server: received ipv6 address (buffer:\");\n                for (int i = 0; i < 16; i++)\n                    fprintf (stderr, \" 0x%x\", (unsigned char) buffer[i]);\n                fprintf (stderr, \")\\n\");\n                if (memcmp (buffer, nipv6local, 16) == 0) {\n                    naddr = htonl (0x7f000001); /* 127.0.0.1 */\n                } else {\n                    err = 0x4; /* Host unreachable */\n                }\n            } else {\n                err = 0x8; /* ATYPE not supported */\n            }\n            recvall (client, (char *) &nport, 2);\n            fprintf (stderr, \"socks_server: received port (port: %d)\\n\",\n                     ntohs (nport));\n            if (err == 0) {\n                fprintf (stderr, \"socks_server: trying to connect to %x:%d\\n\",\n                         ntohl (naddr), ntohs (nport));\n                remote = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\n                res = remote_connect (remote, ntohl (naddr), ntohs (nport));\n                if (res != 0) {\n                    err = 0x5; /* Connection refused */\n                } else {\n                    struct sockaddr_in ip4addr;\n                    socklen_t len = sizeof (ip4addr);\n                    res =\n                      getsockname (remote, (struct sockaddr *) &ip4addr, &len);\n                    TEST_ASSERT_SUCCESS_RAW_ERRNO (res);\n                    fprintf (stderr,\n                             \"socks_server: connected and bound at: %x:%d\\n\",\n                             ntohl (ip4addr.sin_addr.s_addr),\n                             ntohs (ip4addr.sin_port));\n                    bind_naddr = ip4addr.sin_addr.s_addr;\n                    bind_nport = ip4addr.sin_port;\n                }\n            }\n\n            /* Reply request */\n            buffer[0] = 0x5;\n            buffer[1] = err;\n            buffer[2] = 0;\n            buffer[3] = request_atype;\n            sendall (client, buffer, 4);\n            if (request_atype == 0x1) /* ATYPE IPv4 */ {\n                sendall (client, (char *) &bind_naddr, 4);\n            } else if (request_atype == 0x3) {\n                /* This is just for testing reply with a hostname,\n                   normally a resolved address is passed in return to connect. */\n                buffer[0] = strlen (\"localhost\");\n                sendall (client, buffer, 1);\n                strcpy (buffer, \"localhost\");\n                sendall (client, buffer, strlen (\"localhost\"));\n            } else if (request_atype == 0x4) {\n                /* We simulate a bind to ::1, though the actual connection is IPv4 */\n                char nipv6local[16] = {0};\n                nipv6local[15] = 1;\n                sendall (client, nipv6local, sizeof nipv6local);\n            }\n            sendall (client, (char *) &bind_nport, 2);\n            fprintf (stderr, \"socks_server: replied to request (err: 0x%x)\\n\",\n                     err);\n            if (err != 0)\n                break; /* Out of client connection. */\n\n            /* Communication loop */\n            zmq_pollitem_t items[] = {\n              {NULL, client, ZMQ_POLLIN, 0},\n              {NULL, remote, ZMQ_POLLIN, 0},\n            };\n            fprintf (stderr,\n                     \"socks_server: waiting for input (client fd: %d, remote \"\n                     \"fd: %d)\\n\",\n                     client, remote);\n            while (1) {\n                if (client == -1 || remote == -1)\n                    break;\n                if (zmq_poll (items, 2, -1) < 0)\n                    break;\n                int nbytes;\n                for (int i = 0; i < 2; i++) {\n                    if ((items[i].revents & ZMQ_POLLIN) == 0)\n                        continue;\n                    fprintf (stderr, \"socks_server: ready to read from fd %d\\n\",\n                             items[i].fd);\n                    int write_fd, read_fd = items[i].fd;\n                    if (read_fd == client) {\n                        write_fd = remote;\n                    } else {\n                        write_fd = client;\n                    }\n                    nbytes = recvonce (read_fd, buffer, sizeof buffer);\n                    fprintf (stderr, \"socks_server: read returned: %d\\n\",\n                             nbytes);\n                    if (nbytes == 0 || nbytes == -1) {\n                        /* End of stream or error */\n                        if (read_fd == client) {\n                            close (client);\n                            client = -1;\n                        }\n                        if (read_fd == remote) {\n                            close (remote);\n                            remote = -1;\n                        }\n                        break;\n                    }\n                    sendall (write_fd, buffer, nbytes);\n                }\n            }\n            if (remote != -1) {\n                close (remote);\n                remote = -1;\n            }\n            fprintf (stderr, \"socks_server: closed remote connection %d/%d\\n\",\n                     count, max_client_connect);\n        } while (0); /* Client socket scope. */\n        if (client != -1) {\n            close (client);\n            client = -1;\n        }\n        fprintf (stderr, \"socks_server: closed client connection %d/%d\\n\",\n                 count, max_client_connect);\n    }\n    close (server_fd);\n    fprintf (stderr, \"socks_server: closed server\\n\");\n}\n\nvoid socks_server_no_auth (void *socks_server)\n{\n    socks_server_task (socks_server, NULL, NULL, 1);\n}\n\nvoid socks_server_no_auth_delay (void *socks_server)\n{\n    fprintf (stderr, \"socks_server: delay no auth socks server start\\n\");\n    // Enough delay to have client connecting before proxy listens\n    msleep (SETTLE_TIME * 10);\n    socks_server_task (socks_server, NULL, NULL, 1);\n}\n\nvoid socks_server_basic_auth (void *socks_server)\n{\n    socks_server_task (socks_server, \"someuser\", \"somepass\", 1);\n}\n\nvoid socks_server_basic_auth_delay (void *socks_server)\n{\n    fprintf (stderr, \"socks_server: delay basic auth socks server start\\n\");\n    // Enough delay to have client connecting before proxy listens\n    msleep (SETTLE_TIME * 10);\n    socks_server_task (socks_server, \"someuser\", \"somepass\", 1);\n}\n\nvoid socks_server_basic_auth_no_pass (void *socks_server)\n{\n    socks_server_task (socks_server, \"someuser\", NULL, 1);\n}\n\nvoid *setup_push_server (char *connect_address, int connect_address_size)\n{\n    int res;\n    const char *bind_address = \"tcp://127.0.0.1:*\";\n    void *push = test_context_socket (ZMQ_PUSH);\n    res = zmq_bind (push, bind_address);\n    TEST_ASSERT_SUCCESS_ERRNO (res);\n    size_t len = connect_address_size;\n    res = zmq_getsockopt (push, ZMQ_LAST_ENDPOINT, connect_address, &len);\n    TEST_ASSERT_SUCCESS_ERRNO (res);\n    fprintf (stderr, \"push_server: bound to: %s\\n\", connect_address);\n    return push;\n}\n\nvoid *setup_pull_client (const char *connect_address, const char *socks_proxy)\n{\n    int res;\n    void *pull = test_context_socket (ZMQ_PULL);\n    if (socks_proxy != NULL) {\n        res = zmq_setsockopt (pull, ZMQ_SOCKS_PROXY, socks_proxy,\n                              strlen (socks_proxy));\n        TEST_ASSERT_SUCCESS_ERRNO (res);\n        fprintf (stderr, \"pull_client: use socks proxy: tcp://%s\\n\",\n                 socks_proxy);\n    }\n    res = zmq_connect (pull, connect_address);\n    TEST_ASSERT_SUCCESS_ERRNO (res);\n    fprintf (stderr, \"pull_client: connected to: %s\\n\", connect_address);\n    return pull;\n}\n\n#ifdef ZMQ_BUILD_DRAFT_API\nvoid *setup_pull_client_with_auth (const char *connect_address,\n                                   const char *socks_proxy,\n                                   const char *username,\n                                   const char *password)\n{\n    int res;\n    void *pull = test_context_socket (ZMQ_PULL);\n\n    if (socks_proxy != NULL) {\n        res = zmq_setsockopt (pull, ZMQ_SOCKS_PROXY, socks_proxy,\n                              strlen (socks_proxy));\n        TEST_ASSERT_SUCCESS_ERRNO (res);\n        fprintf (stderr, \"pull_client: use socks proxy: tcp://%s\\n\",\n                 socks_proxy);\n    }\n\n    res = zmq_setsockopt (pull, ZMQ_SOCKS_USERNAME, username,\n                          username == NULL ? 0 : strlen (username));\n    TEST_ASSERT_SUCCESS_ERRNO (res);\n\n    res = zmq_setsockopt (pull, ZMQ_SOCKS_PASSWORD, password,\n                          password == NULL ? 0 : strlen (password));\n    TEST_ASSERT_SUCCESS_ERRNO (res);\n\n    res = zmq_connect (pull, connect_address);\n    TEST_ASSERT_SUCCESS_ERRNO (res);\n    fprintf (stderr, \"pull_client: connected to: %s\\n\", connect_address);\n    return pull;\n}\n#endif\n\nvoid communicate (void *push, void *pull)\n{\n    fprintf (stderr, \"push_server: sending 2 messages\\n\");\n    s_send_seq (push, \"ABC\", SEQ_END);\n    s_send_seq (push, \"DEF\", SEQ_END);\n\n    fprintf (stderr, \"pull_client: receiving 2 messages\\n\");\n    s_recv_seq (pull, \"ABC\", SEQ_END);\n    s_recv_seq (pull, \"DEF\", SEQ_END);\n}\n\nvoid test_socks_no_socks (void)\n{\n    char connect_address[MAX_SOCKET_STRING];\n\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    void *pull = setup_pull_client (connect_address, NULL);\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n}\n\nvoid test_socks (void)\n{\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    void *pull = setup_pull_client (connect_address, socks_server_address);\n    void *thread = zmq_threadstart (&socks_server_no_auth, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n}\n\nvoid test_socks_delay (void)\n{\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    void *pull = setup_pull_client (connect_address, socks_server_address);\n    void *thread = zmq_threadstart (&socks_server_no_auth_delay, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n}\n\nvoid test_socks_domainname (void)\n{\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n    char connect_address_hostname[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    // Will be resolved by the proxy test server to 127.0.0.1\n    strcpy (connect_address_hostname, \"tcp://somedomainname.org\");\n    strcat (connect_address_hostname, strrchr (connect_address, ':'));\n    void *pull =\n      setup_pull_client (connect_address_hostname, socks_server_address);\n    void *thread = zmq_threadstart (&socks_server_no_auth, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n}\n\nvoid test_socks_ipv6 (void)\n{\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n    char connect_address_hostname[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    // Will be resolved by the proxy test server to 127.0.0.1\n    strcpy (connect_address_hostname, \"tcp://::1\");\n    strcat (connect_address_hostname, strrchr (connect_address, ':'));\n    void *pull =\n      setup_pull_client (connect_address_hostname, socks_server_address);\n    void *thread = zmq_threadstart (&socks_server_no_auth, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n}\n\nvoid test_socks_ipv6_sb (void)\n{\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n    char connect_address_hostname[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    // Will be resolved by the proxy test server to 127.0.0.1\n    strcpy (connect_address_hostname, \"tcp://[::1]\");\n    strcat (connect_address_hostname, strrchr (connect_address, ':'));\n    void *pull =\n      setup_pull_client (connect_address_hostname, socks_server_address);\n    void *thread = zmq_threadstart (&socks_server_no_auth, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n}\n\nvoid test_socks_bind_before_connect (void)\n{\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n    char socks_address_bind_before_connect[MAX_SOCKET_STRING * 2];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    // Will do a bind before connect when connecting to proxy\n    strcpy (socks_address_bind_before_connect, \"127.0.0.1:0;\");\n    strcat (socks_address_bind_before_connect, socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    void *pull =\n      setup_pull_client (connect_address, socks_address_bind_before_connect);\n    void *thread = zmq_threadstart (&socks_server_no_auth, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n}\n\nvoid test_socks_basic_auth (void)\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    void *pull = setup_pull_client_with_auth (\n      connect_address, socks_server_address, \"someuser\", \"somepass\");\n    void *thread = zmq_threadstart (&socks_server_basic_auth, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n#else\n    TEST_IGNORE_MESSAGE (\n      \"libzmq without DRAFT support, ignoring socks basic auth test\");\n#endif\n}\n\nvoid test_socks_basic_auth_delay (void)\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    void *pull = setup_pull_client_with_auth (\n      connect_address, socks_server_address, \"someuser\", \"somepass\");\n    void *thread = zmq_threadstart (&socks_server_basic_auth_delay, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n#else\n    TEST_IGNORE_MESSAGE (\n      \"libzmq without DRAFT support, ignoring socks basic auth test\");\n#endif\n}\n\nvoid test_socks_basic_auth_empty_user (void)\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    void *pull = setup_pull_client_with_auth (connect_address,\n                                              socks_server_address, \"\", NULL);\n    void *thread = zmq_threadstart (&socks_server_no_auth, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n#else\n    TEST_IGNORE_MESSAGE (\n      \"libzmq without DRAFT support, ignoring socks basic auth test\");\n#endif\n}\n\nvoid test_socks_basic_auth_null_user (void)\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    void *pull = setup_pull_client_with_auth (connect_address,\n                                              socks_server_address, NULL, NULL);\n    void *thread = zmq_threadstart (&socks_server_no_auth, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n#else\n    TEST_IGNORE_MESSAGE (\n      \"libzmq without DRAFT support, ignoring socks basic auth test\");\n#endif\n}\n\nvoid test_socks_basic_auth_empty_pass (void)\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    void *pull = setup_pull_client_with_auth (\n      connect_address, socks_server_address, \"someuser\", \"\");\n    void *thread = zmq_threadstart (&socks_server_basic_auth_no_pass, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n#else\n    TEST_IGNORE_MESSAGE (\n      \"libzmq without DRAFT support, ignoring socks basic auth test\");\n#endif\n}\n\nvoid test_socks_basic_auth_null_pass (void)\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n    char socks_server_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n\n    void *socks =\n      setup_socks_server (socks_server_address, sizeof socks_server_address);\n    void *push = setup_push_server (connect_address, sizeof connect_address);\n    void *pull = setup_pull_client_with_auth (\n      connect_address, socks_server_address, \"someuser\", NULL);\n    void *thread = zmq_threadstart (&socks_server_basic_auth_no_pass, socks);\n\n    communicate (push, pull);\n\n    test_context_socket_close_zero_linger (push);\n    test_context_socket_close_zero_linger (pull);\n\n    zmq_threadclose (thread);\n#else\n    TEST_IGNORE_MESSAGE (\n      \"libzmq without DRAFT support, ignoring socks basic auth test\");\n#endif\n}\n\n\nvoid test_string_opt_ok (const char *msg, int opt, const char *value)\n{\n    int res;\n    void *sub = test_context_socket (ZMQ_SUB);\n    fprintf (stderr, \"test_string_opt_ok: testing %s\\n\", msg);\n    res = zmq_setsockopt (sub, opt, value, strlen (value));\n    TEST_ASSERT_SUCCESS_ERRNO (res);\n    char buffer[1024];\n    size_t res_len = (size_t) sizeof buffer;\n    res = zmq_getsockopt (sub, opt, buffer, &res_len);\n    TEST_ASSERT_SUCCESS_ERRNO (res);\n    TEST_ASSERT_EQUAL (strlen (value) + 1, res_len);\n    TEST_ASSERT (strcmp (buffer, value) == 0);\n    test_context_socket_close_zero_linger (sub);\n}\n\nvoid test_opt_ok (const char *msg,\n                  int opt,\n                  const char *value,\n                  size_t len,\n                  const char *expected_value,\n                  size_t expected_len)\n{\n    int res;\n    void *sub = test_context_socket (ZMQ_SUB);\n    fprintf (stderr, \"test_opt_ok: testing %s\\n\", msg);\n    res = zmq_setsockopt (sub, opt, value, len);\n    TEST_ASSERT_SUCCESS_ERRNO (res);\n    char buffer[1024];\n    size_t res_len = (size_t) sizeof buffer;\n    res = zmq_getsockopt (sub, opt, buffer, &res_len);\n    TEST_ASSERT_SUCCESS_ERRNO (res);\n    TEST_ASSERT_EQUAL (expected_len + 1, res_len);\n    TEST_ASSERT_EQUAL (expected_len, strlen (buffer));\n    TEST_ASSERT (strncmp (buffer, expected_value, expected_len) == 0);\n    test_context_socket_close_zero_linger (sub);\n}\n\nvoid test_opt_invalid (const char *msg, int opt, const char *value, int len)\n{\n    int res;\n    void *sub = test_context_socket (ZMQ_SUB);\n    fprintf (stderr, \"test_opt_invalid: testing %s\\n\", msg);\n    res = zmq_setsockopt (sub, opt, value, len);\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, res);\n    test_context_socket_close_zero_linger (sub);\n}\n\nvoid test_socks_proxy_options (void)\n{\n    // NULL is equivalent to not set and returns empty string\n    test_opt_ok (\"NULL proxy\", ZMQ_SOCKS_PROXY, NULL, 0, \"\", 0);\n    test_string_opt_ok (\"valid proxy\", ZMQ_SOCKS_PROXY, \"somehost:1080\");\n    // Empty value not allowed for proxy server\n    test_opt_invalid (\"empty proxy\", ZMQ_SOCKS_PROXY, \"\", 0);\n}\n\nvoid test_socks_userpass_options (void)\n{\n#ifdef ZMQ_BUILD_DRAFT_API\n    char buffer[1024];\n    for (int i = 0; i < (int) sizeof buffer; i++) {\n        buffer[i] = 'a' + i % 26;\n    }\n\n    // NULL is equivalent to not-set or \"\"\n    test_opt_ok (\"NULL username\", ZMQ_SOCKS_USERNAME, NULL, 0, \"\", 0);\n    // Empty value is allowed for username, means no authentication\n    test_string_opt_ok (\"empty username\", ZMQ_SOCKS_USERNAME, \"\");\n    test_string_opt_ok (\"valid username\", ZMQ_SOCKS_USERNAME, \"someuser\");\n    test_opt_ok (\"255 bytes username\", ZMQ_SOCKS_USERNAME, buffer, 255, buffer,\n                 255);\n    test_opt_invalid (\"too long username\", ZMQ_SOCKS_USERNAME, buffer, 256);\n\n    // NULL is equivalent to not-set or \"\"\n    test_opt_ok (\"NULL password\", ZMQ_SOCKS_PASSWORD, NULL, 0, \"\", 0);\n    // Empty value allowed for password\n    test_string_opt_ok (\"empty password\", ZMQ_SOCKS_PASSWORD, \"\");\n    test_string_opt_ok (\"valid password\", ZMQ_SOCKS_PASSWORD, \"someuser\");\n    test_opt_ok (\"255 bytes password\", ZMQ_SOCKS_PASSWORD, buffer, 255, buffer,\n                 255);\n    test_opt_invalid (\"too long password\", ZMQ_SOCKS_PASSWORD, buffer, 256);\n#else\n    TEST_IGNORE_MESSAGE (\"libzmq without DRAFT support, ignoring socks setopt \"\n                         \"username/password test\");\n#endif\n}\n\nint main ()\n{\n    setup_test_environment (180);\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_socks_proxy_options);\n    RUN_TEST (test_socks_userpass_options);\n    RUN_TEST (test_socks_no_socks);\n    RUN_TEST (test_socks);\n    RUN_TEST (test_socks_delay);\n    RUN_TEST (test_socks_domainname);\n    RUN_TEST (test_socks_ipv6);\n    RUN_TEST (test_socks_ipv6_sb);\n    RUN_TEST (test_socks_bind_before_connect);\n    RUN_TEST (test_socks_basic_auth);\n    RUN_TEST (test_socks_basic_auth_delay);\n    RUN_TEST (test_socks_basic_auth_empty_user);\n    RUN_TEST (test_socks_basic_auth_null_user);\n    RUN_TEST (test_socks_basic_auth_empty_pass);\n    RUN_TEST (test_socks_basic_auth_null_pass);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_sodium.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\n// There is no way to test for correctness because of the embedded RNG.\nvoid test__zmq_curve_keypair__always__success (void)\n{\n    errno = 0;\n    char public_key[41] = {0};\n    char secret_key[41] = {0};\n\n    const int rc = zmq_curve_keypair (public_key, secret_key);\n\n#if defined(ZMQ_HAVE_CURVE)\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n#else\n    TEST_ASSERT_FAILURE_ERRNO (ENOTSUP, rc);\n#endif\n}\n\nvoid test__zmq_curve_public__valid__success ()\n{\n    // These are paired according to hintjens.com/blog:45\n    static const char public_key[] = \"Yne@$w-vo<fVvi]a<NY6T1ed:M$fCG*[IaLV{hID\";\n    static const char secret_key[] = \"D:)Q[IlAW!ahhC2ac:9*A}h:p?([4%wOTJ%JR%cs\";\n\n    errno = 0;\n    char out_public[41] = {0};\n\n    const int rc = zmq_curve_public (out_public, secret_key);\n\n#if defined(ZMQ_HAVE_CURVE)\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n    TEST_ASSERT_EQUAL_STRING (public_key, out_public);\n#else\n    TEST_ASSERT_FAILURE_ERRNO (ENOTSUP, rc);\n    (void) public_key;\n#endif\n}\n\n// The key length must be evenly divisible by 5 or must fail with EINVAL.\nvoid test__zmq_curve_public__invalid__failure (const char *secret_)\n{\n    errno = 0;\n    char out_public[41] = {0};\n\n    const int rc = zmq_curve_public (out_public, secret_);\n\n#if defined(ZMQ_HAVE_CURVE)\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, rc);\n    TEST_ASSERT_EQUAL_STRING (\"\", out_public);\n#else\n    TEST_ASSERT_FAILURE_ERRNO (ENOTSUP, rc);\n#endif\n}\n\nvoid test__zmq_curve_public__invalid__failure_short ()\n{\n    test__zmq_curve_public__invalid__failure (\"42\");\n}\n\nvoid test__zmq_curve_public__invalid__failure_long ()\n{\n    test__zmq_curve_public__invalid__failure (\n      \"0123456789012345678901234567890123456789.\");\n}\n\nint main ()\n{\n    UNITY_BEGIN ();\n    RUN_TEST (test__zmq_curve_keypair__always__success);\n\n    RUN_TEST (test__zmq_curve_public__valid__success);\n    RUN_TEST (test__zmq_curve_public__invalid__failure_short);\n    RUN_TEST (test__zmq_curve_public__invalid__failure_long);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_spec_dealer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n// SHALL route outgoing messages to available peers using a round-robin\n// strategy.\nvoid test_round_robin_out (const char *bind_address_)\n{\n    void *dealer = test_context_socket (ZMQ_DEALER);\n\n    char connect_address[MAX_SOCKET_STRING];\n    test_bind (dealer, bind_address_, connect_address,\n               sizeof (connect_address));\n\n    const size_t services = 5;\n    void *rep[services];\n    for (size_t peer = 0; peer < services; ++peer) {\n        rep[peer] = test_context_socket (ZMQ_REP);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rep[peer], connect_address));\n    }\n\n    // Wait for connections.\n    msleep (SETTLE_TIME);\n\n    // Send all requests\n    for (size_t i = 0; i < services; ++i)\n        s_send_seq (dealer, 0, \"ABC\", SEQ_END);\n\n    // Expect every REP got one message\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n\n    for (size_t peer = 0; peer < services; ++peer)\n        s_recv_seq (rep[peer], \"ABC\", SEQ_END);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    test_context_socket_close_zero_linger (dealer);\n\n    for (size_t peer = 0; peer < services; ++peer)\n        test_context_socket_close_zero_linger (rep[peer]);\n}\n\n// SHALL receive incoming messages from its peers using a fair-queuing\n// strategy.\nvoid test_fair_queue_in (const char *bind_address_)\n{\n    void *receiver = test_context_socket (ZMQ_DEALER);\n\n    char connect_address[MAX_SOCKET_STRING];\n    test_bind (receiver, bind_address_, connect_address,\n               sizeof (connect_address));\n\n    const size_t services = 5;\n    void *senders[services];\n    for (size_t peer = 0; peer < services; ++peer) {\n        senders[peer] = test_context_socket (ZMQ_DEALER);\n\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_connect (senders[peer], connect_address));\n    }\n\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n    s_send_seq (senders[0], \"A\", SEQ_END);\n    s_recv_seq (receiver, \"A\", SEQ_END);\n\n    s_send_seq (senders[0], \"A\", SEQ_END);\n    s_recv_seq (receiver, \"A\", SEQ_END);\n\n    // send our requests\n    for (size_t peer = 0; peer < services; ++peer)\n        s_send_seq (senders[peer], \"B\", SEQ_END);\n\n    // Wait for data.\n    msleep (SETTLE_TIME);\n\n    // handle the requests\n    for (size_t peer = 0; peer < services; ++peer)\n        s_recv_seq (receiver, \"B\", SEQ_END);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    test_context_socket_close_zero_linger (receiver);\n\n    for (size_t peer = 0; peer < services; ++peer)\n        test_context_socket_close_zero_linger (senders[peer]);\n}\n\n// SHALL create a double queue when a peer connects to it. If this peer\n// disconnects, the DEALER socket SHALL destroy its double queue and SHALL\n// discard any messages it contains.\nvoid test_destroy_queue_on_disconnect (const char *bind_address_)\n{\n    void *a = test_context_socket (ZMQ_DEALER);\n\n    char connect_address[MAX_SOCKET_STRING];\n    test_bind (a, bind_address_, connect_address, sizeof (connect_address));\n\n    void *b = test_context_socket (ZMQ_DEALER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (b, connect_address));\n\n    // Send a message in both directions\n    s_send_seq (a, \"ABC\", SEQ_END);\n    s_send_seq (b, \"DEF\", SEQ_END);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (b, connect_address));\n\n    // Disconnect may take time and need command processing.\n    zmq_pollitem_t poller[2] = {{a, 0, 0, 0}, {b, 0, 0, 0}};\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poll (poller, 2, 100));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poll (poller, 2, 100));\n\n    // No messages should be available, sending should fail.\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (a, 0, 0, ZMQ_DONTWAIT));\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_msg_recv (&msg, a, ZMQ_DONTWAIT));\n\n    // After a reconnect of B, the messages should still be gone\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (b, connect_address));\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_msg_recv (&msg, a, ZMQ_DONTWAIT));\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_msg_recv (&msg, b, ZMQ_DONTWAIT));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    test_context_socket_close_zero_linger (a);\n    test_context_socket_close_zero_linger (b);\n}\n\n// SHALL block on sending, or return a suitable error, when it has no connected peers.\nvoid test_block_on_send_no_peers (const char *bind_address_)\n{\n    LIBZMQ_UNUSED (bind_address_);\n    void *sc = test_context_socket (ZMQ_DEALER);\n\n    int timeout = 250;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_SNDTIMEO, &timeout, sizeof (timeout)));\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (sc, 0, 0, ZMQ_DONTWAIT));\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (sc, 0, 0, 0));\n\n    test_context_socket_close (sc);\n}\n\n#define TEST_CASES(name, bind_address)                                         \\\n    void test_round_robin_out_##name ()                                        \\\n    {                                                                          \\\n        test_round_robin_out (bind_address);                                   \\\n    }                                                                          \\\n    void test_fair_queue_in_##name ()                                          \\\n    {                                                                          \\\n        test_fair_queue_in (bind_address);                                     \\\n    }                                                                          \\\n    void test_block_on_send_no_peers_##name ()                                 \\\n    {                                                                          \\\n        test_block_on_send_no_peers (bind_address);                            \\\n    }\n\nTEST_CASES (inproc, \"inproc://a\")\nTEST_CASES (tcp, \"tcp://127.0.0.1:*\")\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n\n    RUN_TEST (test_round_robin_out_inproc);\n    RUN_TEST (test_fair_queue_in_inproc);\n    RUN_TEST (test_block_on_send_no_peers_inproc);\n\n    RUN_TEST (test_round_robin_out_tcp);\n    RUN_TEST (test_fair_queue_in_tcp);\n    RUN_TEST (test_block_on_send_no_peers_tcp);\n\n    // TODO *** Test disabled until libzmq does this properly ***\n    // test_destroy_queue_on_disconnect (ctx);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_spec_pushpull.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nchar connect_address[MAX_SOCKET_STRING];\n\n// PUSH: SHALL route outgoing messages to connected peers using a\n// round-robin strategy.\nvoid test_push_round_robin_out (const char *bind_address_)\n{\n    void *push = test_context_socket (ZMQ_PUSH);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (push, bind_address_));\n    size_t len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (push, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    const size_t services = 5;\n    void *pulls[services];\n    for (size_t peer = 0; peer < services; ++peer) {\n        pulls[peer] = test_context_socket (ZMQ_PULL);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pulls[peer], connect_address));\n    }\n\n    // Wait for connections.\n    msleep (SETTLE_TIME);\n\n    // Send 2N messages\n    for (size_t peer = 0; peer < services; ++peer)\n        s_send_seq (push, \"ABC\", SEQ_END);\n    for (size_t peer = 0; peer < services; ++peer)\n        s_send_seq (push, \"DEF\", SEQ_END);\n\n    // Expect every PULL got one of each\n    for (size_t peer = 0; peer < services; ++peer) {\n        s_recv_seq (pulls[peer], \"ABC\", SEQ_END);\n        s_recv_seq (pulls[peer], \"DEF\", SEQ_END);\n    }\n\n    test_context_socket_close_zero_linger (push);\n\n    for (size_t peer = 0; peer < services; ++peer)\n        test_context_socket_close_zero_linger (pulls[peer]);\n}\n\n// PULL: SHALL receive incoming messages from its peers using a fair-queuing\n// strategy.\nvoid test_pull_fair_queue_in (const char *bind_address_)\n{\n    void *pull = test_context_socket (ZMQ_PULL);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pull, bind_address_));\n    size_t len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (pull, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    const unsigned char services = 5;\n    void *pushs[services];\n    for (unsigned char peer = 0; peer < services; ++peer) {\n        pushs[peer] = test_context_socket (ZMQ_PUSH);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pushs[peer], connect_address));\n    }\n\n    // Wait for connections.\n    msleep (SETTLE_TIME);\n\n    int first_half = 0;\n    int second_half = 0;\n\n    // Send 2N messages\n    for (unsigned char peer = 0; peer < services; ++peer) {\n        char *str = strdup (\"A\");\n\n        str[0] += peer;\n        s_send_seq (pushs[peer], str, SEQ_END);\n        first_half += str[0];\n\n        str[0] += services;\n        s_send_seq (pushs[peer], str, SEQ_END);\n        second_half += str[0];\n\n        free (str);\n    }\n\n    // Wait for data.\n    msleep (SETTLE_TIME);\n\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n    // Expect to pull one from each first\n    for (size_t peer = 0; peer < services; ++peer) {\n        TEST_ASSERT_EQUAL_INT (\n          2, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, pull, 0)));\n        const char *str = static_cast<const char *> (zmq_msg_data (&msg));\n        first_half -= str[0];\n    }\n    TEST_ASSERT_EQUAL_INT (0, first_half);\n\n    // And then get the second batch\n    for (size_t peer = 0; peer < services; ++peer) {\n        TEST_ASSERT_EQUAL_INT (\n          2, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, pull, 0)));\n        const char *str = static_cast<const char *> (zmq_msg_data (&msg));\n        second_half -= str[0];\n    }\n    TEST_ASSERT_EQUAL_INT (0, second_half);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    test_context_socket_close_zero_linger (pull);\n\n    for (size_t peer = 0; peer < services; ++peer)\n        test_context_socket_close_zero_linger (pushs[peer]);\n}\n\n// PUSH: SHALL block on sending, or return a suitable error, when it has no\n// available peers.\nvoid test_push_block_on_send_no_peers (const char *bind_address_)\n{\n    LIBZMQ_UNUSED (bind_address_);\n    void *sc = test_context_socket (ZMQ_PUSH);\n\n    int timeout = 250;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_SNDTIMEO, &timeout, sizeof (timeout)));\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (sc, 0, 0, ZMQ_DONTWAIT));\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (sc, 0, 0, 0));\n\n    test_context_socket_close (sc);\n}\n\n// PUSH and PULL: SHALL create this queue when a peer connects to it. If\n// this peer disconnects, the socket SHALL destroy its queue and SHALL\n// discard any messages it contains.\nvoid test_destroy_queue_on_disconnect (const char *bind_address_)\n{\n    void *a = test_context_socket (ZMQ_PUSH);\n\n    int hwm = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (a, ZMQ_SNDHWM, &hwm, sizeof (hwm)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (a, bind_address_));\n    size_t len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (a, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    void *b = test_context_socket (ZMQ_PULL);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (b, ZMQ_RCVHWM, &hwm, sizeof (hwm)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (b, connect_address));\n\n    // Send two messages, one should be stuck in A's outgoing queue, the other\n    // arrives at B.\n    s_send_seq (a, \"ABC\", SEQ_END);\n    s_send_seq (a, \"DEF\", SEQ_END);\n\n    // Both queues should now be full, indicated by A blocking on send.\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (a, 0, 0, ZMQ_DONTWAIT));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (b, connect_address));\n\n    // Disconnect may take time and need command processing.\n    zmq_pollitem_t poller[2] = {{a, 0, 0, 0}, {b, 0, 0, 0}};\n    TEST_ASSERT_EQUAL_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_poll (poller, 2, 100)));\n    TEST_ASSERT_EQUAL_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_poll (poller, 2, 100)));\n\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n    // Can't receive old data on B.\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_msg_recv (&msg, b, ZMQ_DONTWAIT));\n\n    // Sending fails.\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (a, 0, 0, ZMQ_DONTWAIT));\n\n    // Reconnect B\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (b, connect_address));\n\n    // Still can't receive old data on B.\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_msg_recv (&msg, b, ZMQ_DONTWAIT));\n\n    // two messages should be sendable before the queues are filled up.\n    s_send_seq (a, \"ABC\", SEQ_END);\n    s_send_seq (a, \"DEF\", SEQ_END);\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (a, 0, 0, ZMQ_DONTWAIT));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    test_context_socket_close_zero_linger (a);\n    test_context_socket_close_zero_linger (b);\n}\n\n// PUSH and PULL: SHALL either receive or drop multipart messages atomically.\nvoid test_push_multipart_atomic_drop (const char *bind_address_,\n                                      const bool block_)\n{\n    int linger = 0;\n    int hwm = 1;\n\n    void *push = test_context_socket (ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (push, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (push, ZMQ_SNDHWM, &hwm, sizeof (hwm)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (push, bind_address_));\n    size_t addr_len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (push, ZMQ_LAST_ENDPOINT, connect_address, &addr_len));\n\n    void *pull = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pull, ZMQ_LINGER, &linger, sizeof (linger)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pull, ZMQ_RCVHWM, &hwm, sizeof (hwm)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pull, connect_address));\n\n    // Wait for connections.\n    msleep (SETTLE_TIME);\n\n    int rc;\n    zmq_msg_t msg_data;\n    // A large message is needed to overrun the TCP buffers\n    const size_t len = 16 * 1024 * 1024;\n    size_t zmq_events_size = sizeof (int);\n    int zmq_events;\n\n    // Normal case - exercise the queues\n    send_string_expect_success (push, \"0\", ZMQ_SNDMORE);\n    send_string_expect_success (push, \"0\", ZMQ_SNDMORE);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg_data, len));\n    memset (zmq_msg_data (&msg_data), 'a', len);\n    TEST_ASSERT_EQUAL_INT (len, zmq_msg_send (&msg_data, push, 0));\n\n    recv_string_expect_success (pull, \"0\", 0);\n    recv_string_expect_success (pull, \"0\", 0);\n    zmq_msg_init (&msg_data);\n    TEST_ASSERT_EQUAL_INT (len, zmq_msg_recv (&msg_data, pull, 0));\n    zmq_msg_close (&msg_data);\n\n    // Fill the HWMs of sender and receiver, one message each\n    send_string_expect_success (push, \"1\", 0);\n\n    send_string_expect_success (push, \"2\", ZMQ_SNDMORE);\n    send_string_expect_success (push, \"2\", ZMQ_SNDMORE);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg_data, len));\n    memset (zmq_msg_data (&msg_data), 'b', len);\n    TEST_ASSERT_EQUAL_INT (len, zmq_msg_send (&msg_data, push, 0));\n\n    // Disconnect and simulate a poll (doesn't work on Windows) to\n    // let the commands run and let the pipes start to be deallocated\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (pull, connect_address));\n\n    zmq_getsockopt (push, ZMQ_EVENTS, &zmq_events, &zmq_events_size);\n    zmq_getsockopt (pull, ZMQ_EVENTS, &zmq_events, &zmq_events_size);\n    msleep (SETTLE_TIME);\n    zmq_getsockopt (push, ZMQ_EVENTS, &zmq_events, &zmq_events_size);\n    zmq_getsockopt (pull, ZMQ_EVENTS, &zmq_events, &zmq_events_size);\n\n    // Reconnect and immediately push a large message into the pipe,\n    // if the problem is reproduced the pipe is in the process of being\n    // terminated but still exists (state term_ack_sent) and had already\n    // accepted the frame, so with the first frames already gone and\n    // unreachable only the last is left, and is stuck in the lb.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pull, connect_address));\n\n    send_string_expect_success (push, \"3\", ZMQ_SNDMORE);\n    send_string_expect_success (push, \"3\", ZMQ_SNDMORE);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg_data, len));\n    memset (zmq_msg_data (&msg_data), 'c', len);\n    if (block_) {\n        TEST_ASSERT_EQUAL_INT (len,\n                               zmq_msg_send (&msg_data, push, ZMQ_SNDMORE));\n    } else {\n        rc = zmq_msg_send (&msg_data, push, ZMQ_SNDMORE | ZMQ_DONTWAIT);\n        // inproc won't fail, much faster to connect/disconnect pipes than TCP\n        if (rc == -1) {\n            // at this point the new pipe is there and it works\n            send_string_expect_success (push, \"3\", ZMQ_SNDMORE);\n            send_string_expect_success (push, \"3\", ZMQ_SNDMORE);\n            TEST_ASSERT_EQUAL_INT (len,\n                                   zmq_msg_send (&msg_data, push, ZMQ_SNDMORE));\n        }\n    }\n    send_string_expect_success (push, \"3b\", 0);\n\n    zmq_getsockopt (push, ZMQ_EVENTS, &zmq_events, &zmq_events_size);\n    zmq_getsockopt (pull, ZMQ_EVENTS, &zmq_events, &zmq_events_size);\n    msleep (SETTLE_TIME);\n    zmq_getsockopt (push, ZMQ_EVENTS, &zmq_events, &zmq_events_size);\n    zmq_getsockopt (pull, ZMQ_EVENTS, &zmq_events, &zmq_events_size);\n\n    send_string_expect_success (push, \"5\", ZMQ_SNDMORE);\n    send_string_expect_success (push, \"5\", ZMQ_SNDMORE);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg_data, len));\n    memset (zmq_msg_data (&msg_data), 'd', len);\n    TEST_ASSERT_EQUAL_INT (len, zmq_msg_send (&msg_data, push, 0));\n\n    // On very slow machines the message will not be lost, as it will\n    // be sent when the new pipe is already in place, so avoid failing\n    // and simply carry on as it would be very noisy otherwise.\n    // Receive both to avoid leaking metadata.\n    // If only the \"5\" message is received, the problem is reproduced, and\n    // without the fix the first message received would be the last large\n    // frame of \"3\".\n    char buffer[2];\n    rc =\n      TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (pull, buffer, sizeof (buffer), 0));\n    TEST_ASSERT_EQUAL_INT (1, rc);\n    TEST_ASSERT_TRUE (buffer[0] == '3' || buffer[0] == '5');\n    if (buffer[0] == '3') {\n        recv_string_expect_success (pull, \"3\", 0);\n        zmq_msg_init (&msg_data);\n        TEST_ASSERT_EQUAL_INT (len, zmq_msg_recv (&msg_data, pull, 0));\n        zmq_msg_close (&msg_data);\n        recv_string_expect_success (pull, \"3b\", 0);\n        recv_string_expect_success (pull, \"5\", 0);\n    }\n    recv_string_expect_success (pull, \"5\", 0);\n    zmq_msg_init (&msg_data);\n    TEST_ASSERT_EQUAL_INT (len, zmq_msg_recv (&msg_data, pull, 0));\n    zmq_msg_close (&msg_data);\n\n    test_context_socket_close_zero_linger (pull);\n    test_context_socket_close_zero_linger (push);\n}\n\n#define def_test_spec_pushpull(name, bind_address_)                            \\\n    void test_spec_pushpull_##name##_push_round_robin_out ()                   \\\n    {                                                                          \\\n        test_push_round_robin_out (bind_address_);                             \\\n    }                                                                          \\\n    void test_spec_pushpull_##name##_pull_fair_queue_in ()                     \\\n    {                                                                          \\\n        test_pull_fair_queue_in (bind_address_);                               \\\n    }                                                                          \\\n    void test_spec_pushpull_##name##_push_block_on_send_no_peers ()            \\\n    {                                                                          \\\n        test_push_block_on_send_no_peers (bind_address_);                      \\\n    }                                                                          \\\n    void test_spec_pushpull_##name##_destroy_queue_on_disconnect ()            \\\n    {                                                                          \\\n        test_destroy_queue_on_disconnect (bind_address_);                      \\\n    }                                                                          \\\n    void test_spec_pushpull_##name##_push_multipart_atomic_drop_block ()       \\\n    {                                                                          \\\n        test_push_multipart_atomic_drop (bind_address_, true);                 \\\n    }                                                                          \\\n    void test_spec_pushpull_##name##_push_multipart_atomic_drop_non_block ()   \\\n    {                                                                          \\\n        test_push_multipart_atomic_drop (bind_address_, false);                \\\n    }\n\ndef_test_spec_pushpull (inproc, \"inproc://a\")\n\n  def_test_spec_pushpull (tcp, \"tcp://127.0.0.1:*\")\n\n    int main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_spec_pushpull_inproc_push_round_robin_out);\n    RUN_TEST (test_spec_pushpull_tcp_push_round_robin_out);\n    RUN_TEST (test_spec_pushpull_inproc_pull_fair_queue_in);\n    RUN_TEST (test_spec_pushpull_tcp_pull_fair_queue_in);\n    RUN_TEST (test_spec_pushpull_inproc_push_block_on_send_no_peers);\n    RUN_TEST (test_spec_pushpull_tcp_push_block_on_send_no_peers);\n    // TODO Tests disabled until libzmq does this properly\n    //RUN_TEST (test_spec_pushpull_inproc_destroy_queue_on_disconnect);\n    //RUN_TEST (test_spec_pushpull_tcp_destroy_queue_on_disconnect);\n    RUN_TEST (test_spec_pushpull_inproc_push_multipart_atomic_drop_block);\n    RUN_TEST (test_spec_pushpull_inproc_push_multipart_atomic_drop_non_block);\n    RUN_TEST (test_spec_pushpull_tcp_push_multipart_atomic_drop_block);\n    RUN_TEST (test_spec_pushpull_tcp_push_multipart_atomic_drop_non_block);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_spec_rep.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nchar connect_address[MAX_SOCKET_STRING];\n\nvoid test_fair_queue_in (const char *bind_address_)\n{\n    void *rep = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (rep, bind_address_));\n    size_t len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (rep, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    const size_t services = 5;\n    void *reqs[services];\n    for (size_t peer = 0; peer < services; ++peer) {\n        reqs[peer] = test_context_socket (ZMQ_REQ);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (reqs[peer], connect_address));\n    }\n\n    msleep (SETTLE_TIME);\n\n    s_send_seq (reqs[0], \"A\", SEQ_END);\n    s_recv_seq (rep, \"A\", SEQ_END);\n    s_send_seq (rep, \"A\", SEQ_END);\n    s_recv_seq (reqs[0], \"A\", SEQ_END);\n\n    s_send_seq (reqs[0], \"A\", SEQ_END);\n    s_recv_seq (rep, \"A\", SEQ_END);\n    s_send_seq (rep, \"A\", SEQ_END);\n    s_recv_seq (reqs[0], \"A\", SEQ_END);\n\n    // TODO: following test fails randomly on some boxes\n#ifdef SOMEONE_FIXES_THIS\n    // send N requests\n    for (size_t peer = 0; peer < services; ++peer) {\n        char *str = strdup (\"A\");\n        str[0] += peer;\n        s_send_seq (reqs[peer], str, SEQ_END);\n        free (str);\n    }\n\n    // handle N requests\n    for (size_t peer = 0; peer < services; ++peer) {\n        char *str = strdup (\"A\");\n        str[0] += peer;\n        //  Test fails here\n        s_recv_seq (rep, str, SEQ_END);\n        s_send_seq (rep, str, SEQ_END);\n        s_recv_seq (reqs[peer], str, SEQ_END);\n        free (str);\n    }\n#endif\n    test_context_socket_close_zero_linger (rep);\n\n    for (size_t peer = 0; peer < services; ++peer)\n        test_context_socket_close_zero_linger (reqs[peer]);\n}\n\nvoid test_envelope (const char *bind_address_)\n{\n    void *rep = test_context_socket (ZMQ_REP);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (rep, bind_address_));\n    size_t len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (rep, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    void *dealer = test_context_socket (ZMQ_DEALER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, connect_address));\n\n    // minimal envelope\n    s_send_seq (dealer, 0, \"A\", SEQ_END);\n    s_recv_seq (rep, \"A\", SEQ_END);\n    s_send_seq (rep, \"A\", SEQ_END);\n    s_recv_seq (dealer, 0, \"A\", SEQ_END);\n\n    // big envelope\n    s_send_seq (dealer, \"X\", \"Y\", 0, \"A\", SEQ_END);\n    s_recv_seq (rep, \"A\", SEQ_END);\n    s_send_seq (rep, \"A\", SEQ_END);\n    s_recv_seq (dealer, \"X\", \"Y\", 0, \"A\", SEQ_END);\n\n    test_context_socket_close_zero_linger (rep);\n    test_context_socket_close_zero_linger (dealer);\n}\n\nconst char bind_inproc[] = \"inproc://a\";\nconst char bind_tcp[] = \"tcp://127.0.0.1:*\";\n\nvoid test_fair_queue_in_inproc ()\n{\n    test_fair_queue_in (bind_inproc);\n}\n\nvoid test_fair_queue_in_tcp ()\n{\n    test_fair_queue_in (bind_tcp);\n}\n\nvoid test_envelope_inproc ()\n{\n    test_envelope (bind_inproc);\n}\n\nvoid test_envelope_tcp ()\n{\n    test_envelope (bind_tcp);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n\n    // SHALL receive incoming messages from its peers using a fair-queuing\n    // strategy.\n    RUN_TEST (test_fair_queue_in_inproc);\n    RUN_TEST (test_fair_queue_in_tcp);\n\n    // For an incoming message:\n    // SHALL remove and store the address envelope, including the delimiter.\n    // SHALL pass the remaining data frames to its calling application.\n    // SHALL wait for a single reply message from its calling application.\n    // SHALL prepend the address envelope and delimiter.\n    // SHALL deliver this message back to the originating peer.\n    RUN_TEST (test_envelope_inproc);\n    RUN_TEST (test_envelope_tcp);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_spec_req.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nchar connect_address[MAX_SOCKET_STRING];\n\nvoid test_round_robin_out (const char *bind_address_)\n{\n    void *req = test_context_socket (ZMQ_REQ);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (req, bind_address_));\n    size_t len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (req, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    const size_t services = 5;\n    void *rep[services];\n    for (size_t peer = 0; peer < services; peer++) {\n        rep[peer] = test_context_socket (ZMQ_REP);\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rep[peer], connect_address));\n    }\n    //  We have to give the connects time to finish otherwise the requests\n    //  will not properly round-robin. We could alternatively connect the\n    //  REQ sockets to the REP sockets.\n    msleep (SETTLE_TIME * services);\n\n    // Send our peer-replies, and expect every REP it used once in order\n    for (size_t peer = 0; peer < services; peer++) {\n        s_send_seq (req, \"ABC\", SEQ_END);\n        s_recv_seq (rep[peer], \"ABC\", SEQ_END);\n        s_send_seq (rep[peer], \"DEF\", SEQ_END);\n        s_recv_seq (req, \"DEF\", SEQ_END);\n    }\n\n    test_context_socket_close_zero_linger (req);\n    for (size_t peer = 0; peer < services; peer++)\n        test_context_socket_close_zero_linger (rep[peer]);\n}\n\nvoid test_req_only_listens_to_current_peer (const char *bind_address_)\n{\n    void *req = test_context_socket (ZMQ_REQ);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (req, ZMQ_ROUTING_ID, \"A\", 2));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (req, bind_address_));\n    size_t len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (req, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    const size_t services = 3;\n    void *router[services];\n\n    for (size_t i = 0; i < services; ++i) {\n        router[i] = test_context_socket (ZMQ_ROUTER);\n\n        int enabled = 1;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n          router[i], ZMQ_ROUTER_MANDATORY, &enabled, sizeof (enabled)));\n\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (router[i], connect_address));\n    }\n\n    // Wait for connects to finish.\n    msleep (SETTLE_TIME);\n\n    for (size_t i = 0; i < services; ++i) {\n        // There still is a race condition when a stale peer's message\n        // arrives at the REQ just after a request was sent to that peer.\n        // To avoid that happening in the test, sleep for a bit.\n        TEST_ASSERT_EQUAL_INT (1,\n                               TEST_ASSERT_SUCCESS_ERRNO (zmq_poll (0, 0, 10)));\n\n        s_send_seq (req, \"ABC\", SEQ_END);\n\n        // Receive on router i\n        s_recv_seq (router[i], \"A\", 0, \"ABC\", SEQ_END);\n\n        // Send back replies on all routers\n        for (size_t j = 0; j < services; ++j) {\n            const char *replies[] = {\"WRONG\", \"GOOD\"};\n            const char *reply = replies[i == j ? 1 : 0];\n            s_send_seq (router[j], \"A\", 0, reply, SEQ_END);\n        }\n\n        // Receive only the good reply\n        s_recv_seq (req, \"GOOD\", SEQ_END);\n    }\n\n    test_context_socket_close_zero_linger (req);\n    for (size_t i = 0; i < services; ++i)\n        test_context_socket_close_zero_linger (router[i]);\n}\n\nvoid test_req_message_format (const char *bind_address_)\n{\n    void *req = test_context_socket (ZMQ_REQ);\n    void *router = test_context_socket (ZMQ_ROUTER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (req, bind_address_));\n    size_t len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (req, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (router, connect_address));\n\n    // Send a multi-part request.\n    s_send_seq (req, \"ABC\", \"DEF\", SEQ_END);\n\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n\n    // Receive peer routing id\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, router, 0));\n    TEST_ASSERT_GREATER_THAN_INT (0, zmq_msg_size (&msg));\n    zmq_msg_t peer_id_msg;\n    zmq_msg_init (&peer_id_msg);\n    zmq_msg_copy (&peer_id_msg, &msg);\n\n    int more = 0;\n    size_t more_size = sizeof (more);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (router, ZMQ_RCVMORE, &more, &more_size));\n    TEST_ASSERT_TRUE (more);\n\n    // Receive the rest.\n    s_recv_seq (router, 0, \"ABC\", \"DEF\", SEQ_END);\n\n    // Send back a single-part reply.\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_send (&peer_id_msg, router, ZMQ_SNDMORE));\n    s_send_seq (router, 0, \"GHI\", SEQ_END);\n\n    // Receive reply.\n    s_recv_seq (req, \"GHI\", SEQ_END);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&peer_id_msg));\n\n    test_context_socket_close_zero_linger (req);\n    test_context_socket_close_zero_linger (router);\n}\n\nvoid test_block_on_send_no_peers ()\n{\n    void *sc = test_context_socket (ZMQ_REQ);\n\n    int timeout = 250;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_SNDTIMEO, &timeout, sizeof (timeout)));\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (sc, 0, 0, ZMQ_DONTWAIT));\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (sc, 0, 0, 0));\n\n    test_context_socket_close (sc);\n}\n\nconst char bind_inproc[] = \"inproc://a\";\nconst char bind_tcp[] = \"tcp://127.0.0.1:*\";\n\nvoid test_round_robin_out_inproc ()\n{\n    test_round_robin_out (bind_inproc);\n}\n\nvoid test_round_robin_out_tcp ()\n{\n    test_round_robin_out (bind_tcp);\n}\n\nvoid test_req_message_format_inproc ()\n{\n    test_req_message_format (bind_inproc);\n}\n\nvoid test_req_message_format_tcp ()\n{\n    test_req_message_format (bind_tcp);\n}\n\nvoid test_req_only_listens_to_current_peer_inproc ()\n{\n    test_req_only_listens_to_current_peer (bind_inproc);\n}\n\nvoid test_req_only_listens_to_current_peer_tcp ()\n{\n    test_req_only_listens_to_current_peer (bind_tcp);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n\n    // SHALL route outgoing messages to connected peers using a round-robin\n    // strategy.\n    RUN_TEST (test_round_robin_out_inproc);\n    RUN_TEST (test_round_robin_out_tcp);\n\n    // The request and reply messages SHALL have this format on the wire:\n    // * A delimiter, consisting of an empty frame, added by the REQ socket.\n    // * One or more data frames, comprising the message visible to the\n    //   application.\n    RUN_TEST (test_req_message_format_inproc);\n    RUN_TEST (test_req_message_format_tcp);\n\n    // SHALL block on sending, or return a suitable error, when it has no\n    // connected peers.\n    RUN_TEST (test_block_on_send_no_peers);\n\n    // SHALL accept an incoming message only from the last peer that it sent a\n    // request to.\n    // SHALL discard silently any messages received from other peers.\n    // TODO PH: this test is still failing; disabled for now to allow build to\n    // complete.\n    // RUN_TEST (test_req_only_listens_to_current_peer_inproc);\n    // RUN_TEST (test_req_only_listens_to_current_peer_tcp);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_spec_router.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n// SHALL receive incoming messages from its peers using a fair-queuing\n// strategy.\nvoid test_fair_queue_in (const char *bind_address_)\n{\n    char connect_address[MAX_SOCKET_STRING];\n    void *receiver = test_context_socket (ZMQ_ROUTER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (receiver, bind_address_));\n    size_t len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (receiver, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    const unsigned char services = 5;\n    void *senders[services];\n    for (unsigned char peer = 0; peer < services; ++peer) {\n        senders[peer] = test_context_socket (ZMQ_DEALER);\n\n        char *str = strdup (\"A\");\n        str[0] += peer;\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_setsockopt (senders[peer], ZMQ_ROUTING_ID, str, 2));\n        free (str);\n\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_connect (senders[peer], connect_address));\n    }\n\n    msleep (SETTLE_TIME);\n\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n    s_send_seq (senders[0], \"M\", SEQ_END);\n    s_recv_seq (receiver, \"A\", \"M\", SEQ_END);\n\n    s_send_seq (senders[0], \"M\", SEQ_END);\n    s_recv_seq (receiver, \"A\", \"M\", SEQ_END);\n\n    int sum = 0;\n\n    // send N requests\n    for (unsigned char peer = 0; peer < services; ++peer) {\n        s_send_seq (senders[peer], \"M\", SEQ_END);\n        sum += 'A' + peer;\n    }\n\n    TEST_ASSERT_EQUAL_INT (services * 'A' + services * (services - 1) / 2, sum);\n\n    // handle N requests\n    for (unsigned char peer = 0; peer < services; ++peer) {\n        TEST_ASSERT_EQUAL_INT (\n          2, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, receiver, 0)));\n        const char *id = static_cast<const char *> (zmq_msg_data (&msg));\n        sum -= id[0];\n\n        s_recv_seq (receiver, \"M\", SEQ_END);\n    }\n\n    TEST_ASSERT_EQUAL_INT (0, sum);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    test_context_socket_close_zero_linger (receiver);\n\n    for (size_t peer = 0; peer < services; ++peer)\n        test_context_socket_close_zero_linger (senders[peer]);\n\n    // Wait for disconnects.\n    msleep (SETTLE_TIME);\n}\n\n// SHALL create a double queue when a peer connects to it. If this peer\n// disconnects, the ROUTER socket SHALL destroy its double queue and SHALL\n// discard any messages it contains.\nvoid test_destroy_queue_on_disconnect (const char *bind_address_)\n{\n    void *a = test_context_socket (ZMQ_ROUTER);\n\n    int enabled = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (a, ZMQ_ROUTER_MANDATORY, &enabled, sizeof (enabled)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (a, bind_address_));\n    size_t len = MAX_SOCKET_STRING;\n    char connect_address[MAX_SOCKET_STRING];\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (a, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    void *b = test_context_socket (ZMQ_DEALER);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (b, ZMQ_ROUTING_ID, \"B\", 2));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (b, connect_address));\n\n    // Wait for connection.\n    msleep (SETTLE_TIME);\n\n    // Send a message in both directions\n    s_send_seq (a, \"B\", \"ABC\", SEQ_END);\n    s_send_seq (b, \"DEF\", SEQ_END);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (b, connect_address));\n\n    // Disconnect may take time and need command processing.\n    zmq_pollitem_t poller[2] = {{a, 0, 0, 0}, {b, 0, 0, 0}};\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poll (poller, 2, 100));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_poll (poller, 2, 100));\n\n    // No messages should be available, sending should fail.\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n\n    TEST_ASSERT_FAILURE_ERRNO (\n      EHOSTUNREACH, zmq_send (a, \"B\", 2, ZMQ_SNDMORE | ZMQ_DONTWAIT));\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_msg_recv (&msg, a, ZMQ_DONTWAIT));\n\n    // After a reconnect of B, the messages should still be gone\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (b, connect_address));\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_msg_recv (&msg, a, ZMQ_DONTWAIT));\n\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_msg_recv (&msg, b, ZMQ_DONTWAIT));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    test_context_socket_close_zero_linger (a);\n    test_context_socket_close_zero_linger (b);\n\n    // Wait for disconnects.\n    msleep (SETTLE_TIME);\n}\n\n#define TEST_SUITE(name, bind_address)                                         \\\n    void test_fair_queue_in_##name ()                                          \\\n    {                                                                          \\\n        test_fair_queue_in (bind_address);                                     \\\n    }                                                                          \\\n    void test_destroy_queue_on_disconnect_##name ()                            \\\n    {                                                                          \\\n        test_destroy_queue_on_disconnect (bind_address);                       \\\n    }\n\nTEST_SUITE (inproc, \"inproc://a\")\nTEST_SUITE (tcp, \"tcp://127.0.0.1:*\")\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_fair_queue_in_tcp);\n    RUN_TEST (test_fair_queue_in_inproc);\n    // TODO commented out until libzmq implements this properly\n    // RUN_TEST (test_destroy_queue_on_disconnect_tcp);\n    // RUN_TEST (test_destroy_queue_on_disconnect_inproc);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_srcfd.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n#define MSG_SIZE 20\n\n#ifdef _WIN32\n#include <winsock2.h>\n#include <ws2tcpip.h>\n#else\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netdb.h>\n#endif\n\nvoid test_srcfd ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  Create the infrastructure\n\n    void *rep = test_context_socket (ZMQ_REP);\n    void *req = test_context_socket (ZMQ_REQ);\n\n    bind_loopback_ipv4 (rep, my_endpoint, sizeof (my_endpoint));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, my_endpoint));\n\n    char tmp[MSG_SIZE];\n    memset (tmp, 0, MSG_SIZE);\n    zmq_send (req, tmp, MSG_SIZE, 0);\n\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n    zmq_recvmsg (rep, &msg, 0);\n    TEST_ASSERT_EQUAL_UINT (MSG_SIZE, zmq_msg_size (&msg));\n\n    // get the messages source file descriptor\n    int src_fd = zmq_msg_get (&msg, ZMQ_SRCFD);\n    TEST_ASSERT_GREATER_OR_EQUAL (0, src_fd);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    // get the remote endpoint\n    struct sockaddr_storage ss;\n#ifdef ZMQ_HAVE_HPUX\n    int addrlen = sizeof ss;\n#else\n    socklen_t addrlen = sizeof ss;\n#endif\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (\n      getpeername (src_fd, (struct sockaddr *) &ss, &addrlen));\n\n    char host[NI_MAXHOST];\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (getnameinfo ((struct sockaddr *) &ss,\n                                                addrlen, host, sizeof host,\n                                                NULL, 0, NI_NUMERICHOST));\n\n    // assert it is localhost which connected\n    TEST_ASSERT_EQUAL_STRING (\"127.0.0.1\", host);\n\n    test_context_socket_close (rep);\n    test_context_socket_close (req);\n\n    // sleep a bit for the socket to be freed\n    msleep (SETTLE_TIME);\n\n    // getting name from closed socket will fail\n#ifdef ZMQ_HAVE_WINDOWS\n    const int expected_errno = WSAENOTSOCK;\n#else\n    const int expected_errno = EBADF;\n#endif\n    TEST_ASSERT_FAILURE_RAW_ERRNO (\n      expected_errno, getpeername (src_fd, (struct sockaddr *) &ss, &addrlen));\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_srcfd);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_stream.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n//  ZMTP protocol greeting structure\n\ntypedef uint8_t byte;\ntypedef struct\n{\n    byte signature[10]; //  0xFF 8*0x00 0x7F\n    byte version[2];    //  0x03 0x01 for ZMTP/3.1\n    byte mechanism[20]; //  \"NULL\"\n    byte as_server;\n    byte filler[31];\n} zmtp_greeting_t;\n\n#define ZMTP_DEALER 5 //  Socket type constants\n\n//  This is a greeting matching what 0MQ will send us; note the\n//  8-byte size is set to 1 for backwards compatibility\n\nstatic zmtp_greeting_t greeting = {\n  {0xFF, 0, 0, 0, 0, 0, 0, 0, 1, 0x7F}, {3, 1}, {'N', 'U', 'L', 'L'}, 0, {0}};\n\nstatic void test_stream_to_dealer ()\n{\n    int rc;\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  We'll be using this socket in raw mode\n    void *stream = test_context_socket (ZMQ_STREAM);\n\n    int zero = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (stream, ZMQ_LINGER, &zero, sizeof (zero)));\n    int enabled = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (stream, ZMQ_STREAM_NOTIFY, &enabled, sizeof (enabled)));\n    bind_loopback_ipv4 (stream, my_endpoint, sizeof my_endpoint);\n\n    //  We'll be using this socket as the other peer\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer, ZMQ_LINGER, &zero, sizeof (zero)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));\n\n    //  Send a message on the dealer socket\n    send_string_expect_success (dealer, \"Hello\", 0);\n\n    //  Connecting sends a zero message\n    //  First frame is routing id\n    zmq_msg_t routing_id;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&routing_id));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&routing_id, stream, 0));\n    TEST_ASSERT_TRUE (zmq_msg_more (&routing_id));\n\n    //  Verify the existence of Peer-Address metadata\n    char const *peer_address = zmq_msg_gets (&routing_id, \"Peer-Address\");\n    TEST_ASSERT_NOT_NULL (peer_address);\n    TEST_ASSERT_EQUAL_STRING (\"127.0.0.1\", peer_address);\n\n    //  Second frame is zero\n    byte buffer[255];\n    TEST_ASSERT_EQUAL_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (stream, buffer, 255, 0)));\n\n    //  Verify the existence of Peer-Address metadata\n    peer_address = zmq_msg_gets (&routing_id, \"Peer-Address\");\n    TEST_ASSERT_NOT_NULL (peer_address);\n    TEST_ASSERT_EQUAL_STRING (\"127.0.0.1\", peer_address);\n\n    //  Real data follows\n    //  First frame is routing id\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&routing_id, stream, 0));\n    TEST_ASSERT_TRUE (zmq_msg_more (&routing_id));\n\n    //  Verify the existence of Peer-Address metadata\n    peer_address = zmq_msg_gets (&routing_id, \"Peer-Address\");\n    TEST_ASSERT_NOT_NULL (peer_address);\n    TEST_ASSERT_EQUAL_STRING (\"127.0.0.1\", peer_address);\n\n    //  Second frame is greeting signature\n    recv_array_expect_success (stream, greeting.signature, 0);\n\n    //  Send our own protocol greeting\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&routing_id, stream, ZMQ_SNDMORE));\n    TEST_ASSERT_EQUAL_INT (\n      sizeof (greeting), TEST_ASSERT_SUCCESS_ERRNO (\n                           zmq_send (stream, &greeting, sizeof (greeting), 0)));\n\n    //  Now we expect the data from the DEALER socket\n    //  We want the rest of greeting along with the Ready command\n    int bytes_read = 0;\n    while (bytes_read < 97) {\n        //  First frame is the routing id of the connection (each time)\n        TEST_ASSERT_GREATER_THAN_INT (\n          0, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&routing_id, stream, 0)));\n        TEST_ASSERT_TRUE (zmq_msg_more (&routing_id));\n        //  Second frame contains the next chunk of data\n        TEST_ASSERT_SUCCESS_ERRNO (\n          rc = zmq_recv (stream, buffer + bytes_read, 255 - bytes_read, 0));\n        bytes_read += rc;\n    }\n\n    //  First two bytes are major and minor version numbers.\n    TEST_ASSERT_EQUAL_INT (3, buffer[0]); //  ZMTP/3.1\n    TEST_ASSERT_EQUAL_INT (1, buffer[1]);\n\n    //  Mechanism is \"NULL\"\n    TEST_ASSERT_EQUAL_INT8_ARRAY (buffer + 2,\n                                  \"NULL\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 20);\n    TEST_ASSERT_EQUAL_INT8_ARRAY (buffer + 54, \"\\4\\51\\5READY\", 8);\n    TEST_ASSERT_EQUAL_INT8_ARRAY (buffer + 62, \"\\13Socket-Type\\0\\0\\0\\6DEALER\",\n                                  22);\n    TEST_ASSERT_EQUAL_INT8_ARRAY (buffer + 84, \"\\10Identity\\0\\0\\0\\0\", 13);\n\n    //  Announce we are ready\n    memcpy (buffer, \"\\4\\51\\5READY\", 8);\n    memcpy (buffer + 8, \"\\13Socket-Type\\0\\0\\0\\6ROUTER\", 22);\n    memcpy (buffer + 30, \"\\10Identity\\0\\0\\0\\0\", 13);\n\n    //  Send Ready command\n    TEST_ASSERT_GREATER_THAN_INT (0, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (\n                                       &routing_id, stream, ZMQ_SNDMORE)));\n    TEST_ASSERT_EQUAL_INT (\n      43, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (stream, buffer, 43, 0)));\n\n    //  Now we expect the data from the DEALER socket\n    //  First frame is, again, the routing id of the connection\n    TEST_ASSERT_GREATER_THAN_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&routing_id, stream, 0)));\n    TEST_ASSERT_TRUE (zmq_msg_more (&routing_id));\n\n    //  Third frame contains Hello message from DEALER\n    TEST_ASSERT_EQUAL_INT (7, TEST_ASSERT_SUCCESS_ERRNO (\n                                zmq_recv (stream, buffer, sizeof buffer, 0)));\n\n    //  Then we have a 5-byte message \"Hello\"\n    TEST_ASSERT_EQUAL_INT (0, buffer[0]); //  Flags = 0\n    TEST_ASSERT_EQUAL_INT (5, buffer[1]); //  Size = 5\n    TEST_ASSERT_EQUAL_INT8_ARRAY (buffer + 2, \"Hello\", 5);\n\n    //  Send \"World\" back to DEALER\n    TEST_ASSERT_GREATER_THAN_INT (0, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (\n                                       &routing_id, stream, ZMQ_SNDMORE)));\n    byte world[] = {0, 5, 'W', 'o', 'r', 'l', 'd'};\n    TEST_ASSERT_EQUAL_INT (\n      sizeof (world),\n      TEST_ASSERT_SUCCESS_ERRNO (zmq_send (stream, world, sizeof (world), 0)));\n\n    //  Expect response on DEALER socket\n    recv_string_expect_success (dealer, \"World\", 0);\n\n    //  Test large messages over STREAM socket\n#define size 64000\n    uint8_t msgout[size];\n    memset (msgout, 0xAB, size);\n    zmq_send (dealer, msgout, size, 0);\n\n    uint8_t msgin[9 + size];\n    memset (msgin, 0, 9 + size);\n    bytes_read = 0;\n    while (bytes_read < 9 + size) {\n        //  Get routing id frame\n        TEST_ASSERT_GREATER_THAN_INT (\n          0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (stream, buffer, 256, 0)));\n        //  Get next chunk\n        TEST_ASSERT_GREATER_THAN_INT (\n          0,\n          TEST_ASSERT_SUCCESS_ERRNO (rc = zmq_recv (stream, msgin + bytes_read,\n                                                    9 + size - bytes_read, 0)));\n        bytes_read += rc;\n    }\n    for (int byte_nbr = 0; byte_nbr < size; byte_nbr++) {\n        TEST_ASSERT_EQUAL_UINT8 (0xAB, msgin[9 + byte_nbr]);\n    }\n    test_context_socket_close (dealer);\n    test_context_socket_close (stream);\n}\n\n\nstatic void test_stream_to_stream ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n    //  Set-up our context and sockets\n\n    void *server = test_context_socket (ZMQ_STREAM);\n    int enabled = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_STREAM_NOTIFY, &enabled, sizeof (enabled)));\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n\n    void *client = test_context_socket (ZMQ_STREAM);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_STREAM_NOTIFY, &enabled, sizeof (enabled)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n    uint8_t id[256];\n    uint8_t buffer[256];\n\n    //  Connecting sends a zero message\n    //  Server: First frame is routing id, second frame is zero\n    TEST_ASSERT_GREATER_THAN_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, id, 256, 0)));\n    TEST_ASSERT_EQUAL_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, buffer, 256, 0)));\n    //  Client: First frame is routing id, second frame is zero\n    TEST_ASSERT_GREATER_THAN_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (client, id, 256, 0)));\n    TEST_ASSERT_EQUAL_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (client, buffer, 256, 0)));\n\n    //  Sent HTTP request on client socket\n    //  Get server routing id\n    size_t id_size = sizeof id;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (client, ZMQ_ROUTING_ID, id, &id_size));\n    //  First frame is server routing id\n    TEST_ASSERT_EQUAL_INT ((int) id_size, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (\n                                            client, id, id_size, ZMQ_SNDMORE)));\n    //  Second frame is HTTP GET request\n    TEST_ASSERT_EQUAL_INT (\n      7, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (client, \"GET /\\n\\n\", 7, 0)));\n\n    //  Get HTTP request; ID frame and then request\n    TEST_ASSERT_GREATER_THAN_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, id, 256, 0)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, buffer, 256, 0));\n    TEST_ASSERT_EQUAL_INT8_ARRAY (buffer, \"GET /\\n\\n\", 7);\n\n    //  Send reply back to client\n    char http_response[] = \"HTTP/1.0 200 OK\\r\\n\"\n                           \"Content-Type: text/plain\\r\\n\"\n                           \"\\r\\n\"\n                           \"Hello, World!\";\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_send (server, id, id_size, ZMQ_SNDMORE));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_send (server, http_response, sizeof (http_response), ZMQ_SNDMORE));\n\n    //  Send zero to close connection to client\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_send (server, id, id_size, ZMQ_SNDMORE));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_send (server, NULL, 0, ZMQ_SNDMORE));\n\n    //  Get reply at client and check that it's complete\n    TEST_ASSERT_GREATER_THAN_INT (\n      0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (client, id, 256, 0)));\n    TEST_ASSERT_EQUAL_INT (\n      sizeof http_response,\n      TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (client, buffer, 256, 0)));\n    TEST_ASSERT_EQUAL_INT8_ARRAY (buffer, http_response,\n                                  sizeof (http_response));\n\n    // //  Get disconnection notification\n    // FIXME: why does this block? Bug in STREAM disconnect notification?\n    // id_size = zmq_recv (client, id, 256, 0);\n    // assert (id_size > 0);\n    // rc = zmq_recv (client, buffer, 256, 0);\n    // assert (rc == 0);\n\n    test_context_socket_close (server);\n    test_context_socket_close (client);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_stream_to_dealer);\n    RUN_TEST (test_stream_to_stream);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_stream_disconnect.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nstatic const int SERVER = 0;\nstatic const int CLIENT = 1;\n\nstruct test_message_t\n{\n    int turn;\n    const char *text;\n};\n\n// NOTE: messages are sent without null terminator.\nconst test_message_t dialog[] = {\n  {CLIENT, \"i can haz cheez burger?\"},\n  {SERVER, \"y u no disonnect?\"},\n  {CLIENT, \"\"},\n};\nconst int steps = sizeof (dialog) / sizeof (dialog[0]);\n\nbool has_more (void *socket_)\n{\n    int more = 0;\n    size_t more_size = sizeof (more);\n    int rc = zmq_getsockopt (socket_, ZMQ_RCVMORE, &more, &more_size);\n    if (rc != 0)\n        return false;\n    return more != 0;\n}\n\nvoid test_stream_disconnect ()\n{\n    size_t len = MAX_SOCKET_STRING;\n    char bind_endpoint[MAX_SOCKET_STRING];\n    char connect_endpoint[MAX_SOCKET_STRING];\n    void *sockets[2];\n\n    sockets[SERVER] = test_context_socket (ZMQ_STREAM);\n    int enabled = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      sockets[SERVER], ZMQ_STREAM_NOTIFY, &enabled, sizeof (enabled)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sockets[SERVER], \"tcp://0.0.0.0:*\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sockets[SERVER], ZMQ_LAST_ENDPOINT, bind_endpoint, &len));\n\n    //  Apparently Windows can't connect to 0.0.0.0. A better fix would be welcome.\n#ifdef ZMQ_HAVE_WINDOWS\n    snprintf (connect_endpoint, MAX_SOCKET_STRING * sizeof (char),\n              \"tcp://127.0.0.1:%s\", strrchr (bind_endpoint, ':') + 1);\n#else\n    strcpy (connect_endpoint, bind_endpoint);\n#endif\n\n    sockets[CLIENT] = test_context_socket (ZMQ_STREAM);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      sockets[CLIENT], ZMQ_STREAM_NOTIFY, &enabled, sizeof (enabled)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sockets[CLIENT], connect_endpoint));\n\n    // wait for connect notification\n    // Server: Grab the 1st frame (peer routing id).\n    zmq_msg_t peer_frame;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&peer_frame));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&peer_frame, sockets[SERVER], 0));\n    TEST_ASSERT_GREATER_THAN_INT (0, zmq_msg_size (&peer_frame));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&peer_frame));\n    TEST_ASSERT_TRUE (has_more (sockets[SERVER]));\n\n    // Server: Grab the 2nd frame (actual payload).\n    zmq_msg_t data_frame;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&data_frame));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&data_frame, sockets[SERVER], 0));\n    TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&data_frame));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&data_frame));\n\n    // Client: Grab the 1st frame (peer routing id).\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&peer_frame));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&peer_frame, sockets[CLIENT], 0));\n    TEST_ASSERT_GREATER_THAN_INT (0, zmq_msg_size (&peer_frame));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&peer_frame));\n    TEST_ASSERT_TRUE (has_more (sockets[CLIENT]));\n\n    // Client: Grab the 2nd frame (actual payload).\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&data_frame));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&data_frame, sockets[CLIENT], 0));\n    TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&data_frame));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&data_frame));\n\n    // Send initial message.\n    char blob_data[256];\n    size_t blob_size = sizeof (blob_data);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sockets[CLIENT], ZMQ_ROUTING_ID, blob_data, &blob_size));\n    TEST_ASSERT_GREATER_THAN (0, blob_size);\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, blob_size));\n    memcpy (zmq_msg_data (&msg), blob_data, blob_size);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_send (&msg, sockets[dialog[0].turn], ZMQ_SNDMORE));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_init_size (&msg, strlen (dialog[0].text)));\n    memcpy (zmq_msg_data (&msg), dialog[0].text, strlen (dialog[0].text));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_send (&msg, sockets[dialog[0].turn], ZMQ_SNDMORE));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    // TODO: make sure this loop doesn't loop forever if something is wrong\n    //       with the test (or the implementation).\n\n    int step = 0;\n    while (step < steps) {\n        // Wait until something happens.\n        zmq_pollitem_t items[] = {\n          {sockets[SERVER], 0, ZMQ_POLLIN, 0},\n          {sockets[CLIENT], 0, ZMQ_POLLIN, 0},\n        };\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_poll (items, 2, 100));\n\n        // Check for data received by the server.\n        if (items[SERVER].revents & ZMQ_POLLIN) {\n            TEST_ASSERT_EQUAL_INT (CLIENT, dialog[step].turn);\n\n            // Grab the 1st frame (peer routing id).\n            zmq_msg_t peer_frame;\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&peer_frame));\n            TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_msg_recv (&peer_frame, sockets[SERVER], 0));\n            TEST_ASSERT_GREATER_THAN_INT (0, zmq_msg_size (&peer_frame));\n            TEST_ASSERT_TRUE (has_more (sockets[SERVER]));\n\n            // Grab the 2nd frame (actual payload).\n            zmq_msg_t data_frame;\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&data_frame));\n            TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_msg_recv (&data_frame, sockets[SERVER], 0));\n\n            // Make sure payload matches what we expect.\n            const char *const data =\n              static_cast<const char *> (zmq_msg_data (&data_frame));\n            const size_t size = zmq_msg_size (&data_frame);\n            // 0-length frame is a disconnection notification.  The server\n            // should receive it as the last step in the dialogue.\n            if (size == 0) {\n                ++step;\n                TEST_ASSERT_EQUAL_INT (steps, step);\n            } else {\n                TEST_ASSERT_EQUAL_INT (strlen (dialog[step].text), size);\n                TEST_ASSERT_EQUAL_STRING_LEN (dialog[step].text, data, size);\n\n                ++step;\n\n                TEST_ASSERT_LESS_THAN_INT (steps, step);\n\n                // Prepare the response.\n                TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&data_frame));\n                TEST_ASSERT_SUCCESS_ERRNO (\n                  zmq_msg_init_size (&data_frame, strlen (dialog[step].text)));\n                memcpy (zmq_msg_data (&data_frame), dialog[step].text,\n                        zmq_msg_size (&data_frame));\n\n                // Send the response.\n                TEST_ASSERT_SUCCESS_ERRNO (\n                  zmq_msg_send (&peer_frame, sockets[SERVER], ZMQ_SNDMORE));\n                TEST_ASSERT_SUCCESS_ERRNO (\n                  zmq_msg_send (&data_frame, sockets[SERVER], ZMQ_SNDMORE));\n            }\n\n            // Release resources.\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&peer_frame));\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&data_frame));\n        }\n\n        // Check for data received by the client.\n        if (items[CLIENT].revents & ZMQ_POLLIN) {\n            TEST_ASSERT_EQUAL_INT (SERVER, dialog[step].turn);\n\n            // Grab the 1st frame (peer routing id).\n            zmq_msg_t peer_frame;\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&peer_frame));\n            TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_msg_recv (&peer_frame, sockets[CLIENT], 0));\n            TEST_ASSERT_GREATER_THAN_INT (0, zmq_msg_size (&peer_frame));\n            TEST_ASSERT_TRUE (has_more (sockets[CLIENT]));\n\n            // Grab the 2nd frame (actual payload).\n            zmq_msg_t data_frame;\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&data_frame));\n            TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_msg_recv (&data_frame, sockets[CLIENT], 0));\n            TEST_ASSERT_GREATER_THAN_INT (0, zmq_msg_size (&data_frame));\n\n            // Make sure payload matches what we expect.\n            const char *const data =\n              static_cast<const char *> (zmq_msg_data (&data_frame));\n            const size_t size = zmq_msg_size (&data_frame);\n            TEST_ASSERT_EQUAL_INT (strlen (dialog[step].text), size);\n            TEST_ASSERT_EQUAL_STRING_LEN (dialog[step].text, data, size);\n\n            ++step;\n\n            // Prepare the response (next line in the dialog).\n            TEST_ASSERT_LESS_THAN_INT (steps, step);\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&data_frame));\n            TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_msg_init_size (&data_frame, strlen (dialog[step].text)));\n            memcpy (zmq_msg_data (&data_frame), dialog[step].text,\n                    zmq_msg_size (&data_frame));\n\n            // Send the response.\n            TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_msg_send (&peer_frame, sockets[CLIENT], ZMQ_SNDMORE));\n            TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_msg_send (&data_frame, sockets[CLIENT], ZMQ_SNDMORE));\n\n            // Release resources.\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&peer_frame));\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&data_frame));\n        }\n    }\n    TEST_ASSERT_EQUAL_INT (steps, step);\n    test_context_socket_close (sockets[CLIENT]);\n    test_context_socket_close (sockets[SERVER]);\n}\n\nint main (int, char **)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_stream_disconnect);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_stream_empty.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_stream_empty ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *stream = test_context_socket (ZMQ_STREAM);\n    void *dealer = test_context_socket (ZMQ_DEALER);\n\n    bind_loopback_ipv4 (stream, my_endpoint, sizeof my_endpoint);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));\n    send_string_expect_success (dealer, \"\", 0);\n\n    zmq_msg_t ident, empty;\n    zmq_msg_init (&ident);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&ident, stream, 0));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_msg_init_data (&empty, (void *) \"\", 0, NULL, NULL));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&ident, stream, ZMQ_SNDMORE));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&ident));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&empty, stream, 0));\n\n    //  This close used to fail with Bad Address\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&empty));\n\n    test_context_socket_close_zero_linger (dealer);\n    test_context_socket_close_zero_linger (stream);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_stream_empty);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_stream_exceeds_buffer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_stream_exceeds_buffer ()\n{\n    const int msgsize = 8193;\n    char sndbuf[msgsize] = \"\\xde\\xad\\xbe\\xef\";\n    unsigned char rcvbuf[msgsize];\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    int server_sock = bind_socket_resolve_port (\"127.0.0.1\", \"0\", my_endpoint);\n\n    void *zsock = test_context_socket (ZMQ_STREAM);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (zsock, my_endpoint));\n\n    int client_sock =\n      TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server_sock, NULL, NULL));\n\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (close (server_sock));\n\n    TEST_ASSERT_EQUAL_INT (msgsize, send (client_sock, sndbuf, msgsize, 0));\n\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n\n    int rcvbytes = 0;\n    while (rcvbytes == 0) // skip connection notification, if any\n    {\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, zsock, 0)); // peerid\n        TEST_ASSERT_TRUE (zmq_msg_more (&msg));\n        rcvbytes = TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, zsock, 0));\n        TEST_ASSERT_FALSE (zmq_msg_more (&msg));\n    }\n\n    // for this test, we only collect the first chunk\n    // since the corruption already occurs in the first chunk\n    memcpy (rcvbuf, zmq_msg_data (&msg), zmq_msg_size (&msg));\n\n    zmq_msg_close (&msg);\n    test_context_socket_close (zsock);\n    close (client_sock);\n\n    TEST_ASSERT_GREATER_OR_EQUAL (4, rcvbytes);\n\n    // notice that only the 1st byte gets corrupted\n    TEST_ASSERT_EQUAL_UINT (0xef, rcvbuf[3]);\n    TEST_ASSERT_EQUAL_UINT (0xbe, rcvbuf[2]);\n    TEST_ASSERT_EQUAL_UINT (0xad, rcvbuf[1]);\n    TEST_ASSERT_EQUAL_UINT (0xde, rcvbuf[0]);\n}\n\nint main ()\n{\n    UNITY_BEGIN ();\n    RUN_TEST (test_stream_exceeds_buffer);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_stream_timeout.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_monitoring.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nstatic void test_stream_handshake_timeout_accept ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  We use this socket in raw mode, to make a connection and send nothing\n    void *stream = test_context_socket (ZMQ_STREAM);\n\n    int zero = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (stream, ZMQ_LINGER, &zero, sizeof (zero)));\n\n    //  We'll be using this socket to test TCP stream handshake timeout\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer, ZMQ_LINGER, &zero, sizeof (zero)));\n    int val, tenth = 100;\n    size_t vsize = sizeof (val);\n\n    // check for the expected default handshake timeout value - 30 sec\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (dealer, ZMQ_HANDSHAKE_IVL, &val, &vsize));\n    TEST_ASSERT_EQUAL (sizeof (val), vsize);\n    TEST_ASSERT_EQUAL_INT (30000, val);\n    // make handshake timeout faster - 1/10 sec\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer, ZMQ_HANDSHAKE_IVL, &tenth, sizeof (tenth)));\n    vsize = sizeof (val);\n    // make sure zmq_setsockopt changed the value\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (dealer, ZMQ_HANDSHAKE_IVL, &val, &vsize));\n    TEST_ASSERT_EQUAL (sizeof (val), vsize);\n    TEST_ASSERT_EQUAL_INT (tenth, val);\n\n    //  Create and connect a socket for collecting monitor events on dealer\n    void *dealer_mon = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (\n      dealer, \"inproc://monitor-dealer\",\n      ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_ACCEPTED));\n\n    //  Connect to the inproc endpoint so we'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (dealer_mon, \"inproc://monitor-dealer\"));\n\n    // bind dealer socket to accept connection from non-sending stream socket\n    bind_loopback_ipv4 (dealer, my_endpoint, sizeof my_endpoint);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (stream, my_endpoint));\n\n    // we should get ZMQ_EVENT_ACCEPTED and then ZMQ_EVENT_DISCONNECTED\n    int event = get_monitor_event (dealer_mon, NULL, NULL);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_ACCEPTED, event);\n    event = get_monitor_event (dealer_mon, NULL, NULL);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_DISCONNECTED, event);\n\n    test_context_socket_close (dealer);\n    test_context_socket_close (dealer_mon);\n    test_context_socket_close (stream);\n}\n\nstatic void test_stream_handshake_timeout_connect ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  We use this socket in raw mode, to accept a connection and send nothing\n    void *stream = test_context_socket (ZMQ_STREAM);\n\n    int zero = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (stream, ZMQ_LINGER, &zero, sizeof (zero)));\n\n    bind_loopback_ipv4 (stream, my_endpoint, sizeof my_endpoint);\n\n    //  We'll be using this socket to test TCP stream handshake timeout\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer, ZMQ_LINGER, &zero, sizeof (zero)));\n    int val, tenth = 100;\n    size_t vsize = sizeof (val);\n\n    // check for the expected default handshake timeout value - 30 sec\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (dealer, ZMQ_HANDSHAKE_IVL, &val, &vsize));\n    TEST_ASSERT_EQUAL (sizeof (val), vsize);\n    TEST_ASSERT_EQUAL_INT (30000, val);\n    // make handshake timeout faster - 1/10 sec\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (dealer, ZMQ_HANDSHAKE_IVL, &tenth, sizeof (tenth)));\n    vsize = sizeof (val);\n    // make sure zmq_setsockopt changed the value\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (dealer, ZMQ_HANDSHAKE_IVL, &val, &vsize));\n    TEST_ASSERT_EQUAL (sizeof (val), vsize);\n    TEST_ASSERT_EQUAL_INT (tenth, val);\n\n    //  Create and connect a socket for collecting monitor events on dealer\n    void *dealer_mon = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (\n      dealer, \"inproc://monitor-dealer\",\n      ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_ACCEPTED));\n\n    //  Connect to the inproc endpoint so we'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (dealer_mon, \"inproc://monitor-dealer\"));\n\n    // connect dealer socket to non-sending stream socket\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));\n\n    // we should get ZMQ_EVENT_CONNECTED and then ZMQ_EVENT_DISCONNECTED\n    int event = get_monitor_event (dealer_mon, NULL, NULL);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_CONNECTED, event);\n    event = get_monitor_event (dealer_mon, NULL, NULL);\n    TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_DISCONNECTED, event);\n\n    test_context_socket_close (dealer);\n    test_context_socket_close (dealer_mon);\n    test_context_socket_close (stream);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_stream_handshake_timeout_accept);\n    RUN_TEST (test_stream_handshake_timeout_connect);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_sub_forward.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test ()\n{\n    char endpoint1[MAX_SOCKET_STRING];\n    char endpoint2[MAX_SOCKET_STRING];\n\n    //  First, create an intermediate device\n    void *xpub = test_context_socket (ZMQ_XPUB);\n    bind_loopback_ipv4 (xpub, endpoint1, sizeof (endpoint1));\n\n    void *xsub = test_context_socket (ZMQ_XSUB);\n    bind_loopback_ipv4 (xsub, endpoint2, sizeof (endpoint2));\n\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pub, endpoint2));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, endpoint1));\n\n    //  Subscribe for all messages.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, \"\", 0));\n\n    //  Pass the subscription upstream through the device\n    char buff[32];\n    int size;\n    TEST_ASSERT_SUCCESS_ERRNO (size = zmq_recv (xpub, buff, sizeof (buff), 0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_send (xsub, buff, size, 0));\n\n    //  Wait a bit till the subscription gets to the publisher\n    msleep (SETTLE_TIME);\n\n    //  Send an empty message\n    send_string_expect_success (pub, \"\", 0);\n\n    //  Pass the message downstream through the device\n    TEST_ASSERT_SUCCESS_ERRNO (size = zmq_recv (xsub, buff, sizeof (buff), 0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_send (xpub, buff, size, 0));\n\n    //  Receive the message in the subscriber\n    recv_string_expect_success (sub, \"\", 0);\n\n    //  Clean up.\n    test_context_socket_close (xpub);\n    test_context_socket_close (xsub);\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_sub_forward_tipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test ()\n{\n    //  First, create an intermediate device.\n    void *xpub = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (xpub, \"tipc://{5560,0,0}\"));\n    void *xsub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (xsub, \"tipc://{5561,0,0}\"));\n\n    //  Create a publisher.\n    void *pub = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pub, \"tipc://{5561,0}@0.0.0\"));\n\n    //  Create a subscriber.\n    void *sub = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"tipc://{5560,0}@0.0.0\"));\n\n    // TODO the remainder of this method is duplicated with test_sub_forward\n\n    //  Subscribe for all messages.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, \"\", 0));\n\n    //  Pass the subscription upstream through the device\n    char buff[32];\n    int size;\n    TEST_ASSERT_SUCCESS_ERRNO (size = zmq_recv (xpub, buff, sizeof (buff), 0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_send (xsub, buff, size, 0));\n\n    //  Wait a bit till the subscription gets to the publisher\n    msleep (SETTLE_TIME);\n\n    //  Send an empty message\n    send_string_expect_success (pub, \"\", 0);\n\n    //  Pass the message downstream through the device\n    TEST_ASSERT_SUCCESS_ERRNO (size = zmq_recv (xsub, buff, sizeof (buff), 0));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_send (xpub, buff, size, 0));\n\n    //  Receive the message in the subscriber\n    recv_string_expect_success (sub, \"\", 0);\n\n    //  Clean up.\n    test_context_socket_close (xpub);\n    test_context_socket_close (xsub);\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nint main ()\n{\n    if (!is_tipc_available ()) {\n        printf (\"TIPC environment unavailable, skipping test\\n\");\n        return 77;\n    }\n\n    UNITY_BEGIN ();\n    RUN_TEST (test);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_system.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#if defined(ZMQ_HAVE_WINDOWS)\n#include <winsock2.h>\n#include <stdexcept>\n#else\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <unistd.h>\n#endif\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n//  Solaris has a default of 256 max files per process\n#ifdef ZMQ_HAVE_SOLARIS\n#define MAX_SOCKETS 200\n#else\n#define MAX_SOCKETS 1000\n#endif\n\n#if defined(ZMQ_HAVE_WINDOWS)\n\nvoid initialise_network (void)\n{\n    WSADATA info;\n    if (WSAStartup (MAKEWORD (2, 0), &info) != 0)\n        throw std::runtime_error (\"Could not start WSA\");\n}\n\n#else\n\nvoid initialise_network (void)\n{\n}\n\n#endif\n\nvoid test_localhost ()\n{\n    //  Check that we have local networking via ZeroMQ\n    void *dealer = test_context_socket (ZMQ_DEALER);\n    if (zmq_bind (dealer, \"tcp://127.0.0.1:*\") == -1) {\n        TEST_FAIL_MESSAGE (\n          \"E: Cannot find 127.0.0.1 -- your system does not have local\\n\"\n          \"E: networking. Please fix this before running libzmq checks.\\n\");\n    }\n\n    test_context_socket_close (dealer);\n}\n\nvoid test_max_sockets ()\n{\n    //  Check that we can create 1,000 sockets\n    fd_t handle[MAX_SOCKETS];\n    int count;\n    for (count = 0; count < MAX_SOCKETS; count++) {\n        handle[count] = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\n        if (handle[count] == retired_fd) {\n            printf (\"W: Only able to create %d sockets on this box\\n\", count);\n            const char msg[] =\n              \"I: Tune your system to increase maximum allowed file handles\\n\"\n#if !defined(ZMQ_HAVE_WINDOWS)\n              \"I: Run 'ulimit -n 1200' in bash\\n\"\n#endif\n              ;\n            TEST_FAIL_MESSAGE (msg);\n        }\n    }\n    //  Release the socket handles\n    for (count = 0; count < MAX_SOCKETS; count++) {\n        close (handle[count]);\n    }\n}\n\n//  This test case stresses the system to shake out known configuration\n//  problems. We're direct system calls when necessary. Some code may\n//  need wrapping to be properly portable.\n\nint main (void)\n{\n    initialise_network ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_localhost);\n    RUN_TEST (test_max_sockets);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_tcp_accept_filter.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <cstring>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_reconnect_ivl_against_pair_socket (const char *my_endpoint_,\n                                             void *sb_)\n{\n    void *sc = test_context_socket (ZMQ_PAIR);\n    int interval = -1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_RECONNECT_IVL, &interval, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_));\n\n    bounce (sb_, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb_, my_endpoint_));\n\n    expect_bounce_fail (sb_, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb_, my_endpoint_));\n\n    expect_bounce_fail (sb_, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_));\n\n    bounce (sb_, sc);\n\n    test_context_socket_close (sc);\n}\n\nvoid test_reconnect_ivl_tcp (bind_function_t bind_function_)\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *sb = test_context_socket (ZMQ_PAIR);\n    bind_function_ (sb, my_endpoint, sizeof my_endpoint);\n\n    test_reconnect_ivl_against_pair_socket (my_endpoint, sb);\n    test_context_socket_close (sb);\n}\n\nvoid test_bad_filter_string (const char *const filter_)\n{\n    void *socket = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL,\n                               zmq_setsockopt (socket, ZMQ_TCP_ACCEPT_FILTER,\n                                               filter_, strlen (filter_)));\n\n    test_context_socket_close (socket);\n}\n\n#define TEST_BAD_FILTER_STRING(case, filter)                                   \\\n    void test_bad_filter_string_##case (){test_bad_filter_string (filter);}\n\nTEST_BAD_FILTER_STRING (foo, \"foo\")\nTEST_BAD_FILTER_STRING (zeros_foo, \"0.0.0.0foo\")\nTEST_BAD_FILTER_STRING (zeros_foo_mask, \"0.0.0.0/foo\")\nTEST_BAD_FILTER_STRING (zeros_empty_mask, \"0.0.0.0/\")\nTEST_BAD_FILTER_STRING (zeros_negative_mask, \"0.0.0.0/-1\")\nTEST_BAD_FILTER_STRING (zeros_too_large_mask, \"0.0.0.0/33\")\n\nvoid test_clear ()\n{\n    void *bind_socket = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (bind_socket, ZMQ_TCP_ACCEPT_FILTER, NULL, 0));\n\n#if 0\n    // XXX Shouldn't this work as well?\n    const char empty_filter[] = \"\";\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      socket, ZMQ_TCP_ACCEPT_FILTER, empty_filter, strlen (empty_filter)));\n#endif\n\n    char endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (bind_socket, endpoint, sizeof (endpoint));\n\n    void *connect_socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, endpoint));\n\n    bounce (bind_socket, connect_socket);\n\n    test_context_socket_close (connect_socket);\n    test_context_socket_close (bind_socket);\n}\n\nconst char non_matching_filter[] = \"127.0.0.255/32\";\n\nvoid test_set_non_matching_and_clear ()\n{\n    void *bind_socket = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (bind_socket, ZMQ_TCP_ACCEPT_FILTER, non_matching_filter,\n                      strlen (non_matching_filter)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (bind_socket, ZMQ_TCP_ACCEPT_FILTER, NULL, 0));\n\n    char endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (bind_socket, endpoint, sizeof (endpoint));\n\n    void *connect_socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, endpoint));\n\n    bounce (bind_socket, connect_socket);\n\n    test_context_socket_close (connect_socket);\n    test_context_socket_close (bind_socket);\n}\n\nvoid test_set_matching (const char *const filter_)\n{\n    void *bind_socket = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      bind_socket, ZMQ_TCP_ACCEPT_FILTER, filter_, strlen (filter_)));\n\n    char endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (bind_socket, endpoint, sizeof (endpoint));\n\n    void *connect_socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, endpoint));\n\n    bounce (bind_socket, connect_socket);\n\n    test_context_socket_close (connect_socket);\n    test_context_socket_close (bind_socket);\n}\n\nvoid test_set_matching_1 ()\n{\n    test_set_matching (\"127.0.0.1/32\");\n}\n\nvoid test_set_matching_2 ()\n{\n    test_set_matching (\"0.0.0.0/0\");\n}\n\nvoid test_set_non_matching ()\n{\n    void *bind_socket = test_context_socket (ZMQ_PAIR);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (bind_socket, ZMQ_TCP_ACCEPT_FILTER, non_matching_filter,\n                      strlen (non_matching_filter)));\n\n    char endpoint[MAX_SOCKET_STRING];\n    bind_loopback_ipv4 (bind_socket, endpoint, sizeof (endpoint));\n\n    void *connect_socket = test_context_socket (ZMQ_PAIR);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, endpoint));\n\n    expect_bounce_fail (bind_socket, connect_socket);\n\n    test_context_socket_close_zero_linger (connect_socket);\n    test_context_socket_close_zero_linger (bind_socket);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_bad_filter_string_foo);\n    RUN_TEST (test_bad_filter_string_zeros_foo);\n    RUN_TEST (test_bad_filter_string_zeros_foo_mask);\n    RUN_TEST (test_bad_filter_string_zeros_empty_mask);\n    RUN_TEST (test_bad_filter_string_zeros_negative_mask);\n    RUN_TEST (test_bad_filter_string_zeros_too_large_mask);\n\n    RUN_TEST (test_clear);\n    RUN_TEST (test_set_non_matching_and_clear);\n    RUN_TEST (test_set_matching_1);\n    RUN_TEST (test_set_matching_2);\n\n    RUN_TEST (test_set_non_matching);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_term_endpoint.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n/* Use the worst case filename size for the buffer (+1 for trailing NUL), this\n * is larger than MAX_SOCKET_STRING, which is not large enough for IPC */\n#define BUF_SIZE (FILENAME_MAX + 1)\n\nconst char *ep_wc_tcp = \"tcp://127.0.0.1:*\";\n#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS\nconst char *ep_wc_ipc = \"ipc://*\";\n#endif\n#if defined ZMQ_HAVE_VMCI\nconst char *ep_wc_vmci = \"vmci://*:*\";\n#endif\n\nvoid test_send_after_unbind_fails ()\n{\n    char my_endpoint[BUF_SIZE];\n\n    //  Create infrastructure.\n    void *push = test_context_socket (ZMQ_PUSH);\n    bind_loopback_ipv4 (push, my_endpoint, BUF_SIZE);\n\n    void *pull = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pull, my_endpoint));\n\n    //  Pass one message through to ensure the connection is established\n    send_string_expect_success (push, \"ABC\", 0);\n    recv_string_expect_success (pull, \"ABC\", 0);\n\n    //  Unbind the listening endpoint\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (push, my_endpoint));\n\n    //  Allow unbind to settle\n    msleep (SETTLE_TIME);\n\n    //  Check that sending would block (there's no outbound connection)\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (push, \"ABC\", 3, ZMQ_DONTWAIT));\n\n    //  Clean up\n    test_context_socket_close (pull);\n    test_context_socket_close (push);\n}\n\nvoid test_send_after_disconnect_fails ()\n{\n    //  Create infrastructure\n    void *pull = test_context_socket (ZMQ_PULL);\n    char my_endpoint[BUF_SIZE];\n    bind_loopback_ipv4 (pull, my_endpoint, BUF_SIZE);\n\n    void *push = test_context_socket (ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (push, my_endpoint));\n\n    //  Pass one message through to ensure the connection is established.\n    send_string_expect_success (push, \"ABC\", 0);\n    recv_string_expect_success (pull, \"ABC\", 0);\n\n    //  Disconnect the bound endpoint\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (push, my_endpoint));\n\n    //  Allow disconnect to settle\n    msleep (SETTLE_TIME);\n\n    //  Check that sending would block (there's no inbound connections).\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (push, \"ABC\", 3, ZMQ_DONTWAIT));\n\n    //  Clean up\n    test_context_socket_close (pull);\n    test_context_socket_close (push);\n}\n\nvoid test_unbind_via_last_endpoint ()\n{\n    //  Create infrastructure (wild-card binding)\n    void *push = test_context_socket (ZMQ_PUSH);\n    char my_endpoint[BUF_SIZE];\n    bind_loopback_ipv4 (push, my_endpoint, BUF_SIZE);\n\n    void *pull = test_context_socket (ZMQ_PULL);\n\n#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pull, ep_wc_ipc));\n#endif\n#if defined ZMQ_HAVE_VMCI\n    void *req = test_context_socket (ZMQ_REQ);\n    int rc = zmq_bind (req, ep_wc_vmci);\n    if (rc < 0 && errno == EAFNOSUPPORT)\n        TEST_IGNORE_MESSAGE (\"VMCI not supported\");\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n#endif\n\n    // Unbind sockets binded by wild-card address\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (push, my_endpoint));\n\n    size_t buf_size = 0;\n    (void) buf_size;\n\n#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS\n    buf_size = sizeof (my_endpoint);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (pull, ZMQ_LAST_ENDPOINT, my_endpoint, &buf_size));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (pull, my_endpoint));\n#endif\n#if defined ZMQ_HAVE_VMCI\n    buf_size = sizeof (my_endpoint);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (req, ZMQ_LAST_ENDPOINT, my_endpoint, &buf_size));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (req, my_endpoint));\n#endif\n\n    //  Clean up\n    test_context_socket_close (pull);\n    test_context_socket_close (push);\n}\n\nvoid test_wildcard_unbind_fails ()\n{\n    //  Create infrastructure (wild-card binding)\n    void *push = test_context_socket (ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (push, ep_wc_tcp));\n    void *pull = test_context_socket (ZMQ_PULL);\n#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pull, ep_wc_ipc));\n#endif\n#if defined ZMQ_HAVE_VMCI\n    void *req = test_context_socket (ZMQ_REQ);\n    int rc = zmq_bind (req, ep_wc_vmci);\n    if (rc < 0 && errno == EAFNOSUPPORT)\n        TEST_IGNORE_MESSAGE (\"VMCI not supported\");\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n#endif\n\n    // Sockets binded by wild-card address can't be unbinded by wild-card address\n    TEST_ASSERT_FAILURE_ERRNO (ENOENT, zmq_unbind (push, ep_wc_tcp));\n#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS\n    TEST_ASSERT_FAILURE_ERRNO (ENOENT, zmq_unbind (pull, ep_wc_ipc));\n#endif\n#if defined ZMQ_HAVE_VMCI\n    TEST_ASSERT_FAILURE_ERRNO (ENOENT, zmq_unbind (req, ep_wc_vmci));\n#endif\n\n    //  Clean up\n    test_context_socket_close (pull);\n    test_context_socket_close (push);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_send_after_unbind_fails);\n    RUN_TEST (test_send_after_disconnect_fails);\n    RUN_TEST (test_unbind_via_last_endpoint);\n    RUN_TEST (test_wildcard_unbind_fails);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_term_endpoint_tipc.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nconst char ep[] = \"tipc://{5560,0,0}\";\nconst char name[] = \"tipc://{5560,0}@0.0.0\";\n\nvoid test_term_endpoint_unbind_tipc ()\n{\n    if (!is_tipc_available ()) {\n        TEST_IGNORE_MESSAGE (\"TIPC environment unavailable, skipping test\\n\");\n    }\n\n    //  Create infrastructure.\n    void *push = test_context_socket (ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (push, ep));\n    void *pull = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pull, name));\n\n    //  Pass one message through to ensure the connection is established.\n    send_string_expect_success (push, \"ABC\", 0);\n    recv_string_expect_success (pull, \"ABC\", 0);\n\n    // Unbind the lisnening endpoint\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (push, ep));\n\n    // Let events some time\n    msleep (SETTLE_TIME);\n\n    //  Check that sending would block (there's no outbound connection).\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (push, \"ABC\", 3, ZMQ_DONTWAIT));\n\n    //  Clean up.\n    test_context_socket_close (pull);\n    test_context_socket_close (push);\n}\n\nvoid test_term_endpoint_disconnect_tipc ()\n{\n    if (!is_tipc_available ()) {\n        TEST_IGNORE_MESSAGE (\"TIPC environment unavailable, skipping test\\n\");\n    }\n\n    //  Create infrastructure.\n    void *push = test_context_socket (ZMQ_PUSH);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (push, name));\n    void *pull = test_context_socket (ZMQ_PULL);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pull, ep));\n\n    //  Pass one message through to ensure the connection is established.\n    send_string_expect_success (push, \"ABC\", 0);\n    recv_string_expect_success (pull, \"ABC\", 0);\n\n    // Disconnect the bound endpoint\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (push, name));\n\n    msleep (SETTLE_TIME);\n\n    //  Check that sending would block (there's no inbound connections).\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_send (push, \"ABC\", 3, ZMQ_DONTWAIT));\n\n    //  Clean up.\n    test_context_socket_close (pull);\n    test_context_socket_close (push);\n}\n\nint main (void)\n{\n    UNITY_BEGIN ();\n    RUN_TEST (test_term_endpoint_unbind_tipc);\n    RUN_TEST (test_term_endpoint_disconnect_tipc);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_thread_safe.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n//  Client threads loop on send/recv until told to exit\nvoid client_thread (void *client_)\n{\n    for (int count = 0; count < 15000; count++) {\n        send_string_expect_success (client_, \"0\", 0);\n    }\n    send_string_expect_success (client_, \"1\", 0);\n}\n\nvoid test_thread_safe ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    void *server = test_context_socket (ZMQ_SERVER);\n    bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);\n\n    void *client = test_context_socket (ZMQ_CLIENT);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));\n\n    void *t1 = zmq_threadstart (client_thread, client);\n    void *t2 = zmq_threadstart (client_thread, client);\n\n    char data;\n    int threads_completed = 0;\n    while (threads_completed < 2) {\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, &data, 1, 0));\n        if (data == '1')\n            threads_completed++; //  Thread ended\n    }\n    zmq_threadclose (t1);\n    zmq_threadclose (t2);\n\n    test_context_socket_close (server);\n    test_context_socket_close (client);\n}\n\nvoid test_getsockopt_thread_safe (void *const socket_)\n{\n    int thread_safe;\n    size_t size = sizeof (int);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket_, ZMQ_THREAD_SAFE, &thread_safe, &size));\n    TEST_ASSERT_EQUAL_INT (1, thread_safe);\n}\n\nvoid test_client_getsockopt_thread_safe ()\n{\n    void *client = test_context_socket (ZMQ_CLIENT);\n    test_getsockopt_thread_safe (client);\n    test_context_socket_close (client);\n}\n\nvoid test_server_getsockopt_thread_safe ()\n{\n    void *server = test_context_socket (ZMQ_SERVER);\n    test_getsockopt_thread_safe (server);\n    test_context_socket_close (server);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    // TODO this file could be merged with test_client_server\n    UNITY_BEGIN ();\n    RUN_TEST (test_client_getsockopt_thread_safe);\n    RUN_TEST (test_server_getsockopt_thread_safe);\n    RUN_TEST (test_thread_safe);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_timeo.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_timeo ()\n{\n    void *frontend = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (frontend, \"inproc://timeout_test\"));\n\n    //  Receive on disconnected socket returns immediately\n    char buffer[32];\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN,\n                               zmq_recv (frontend, buffer, 32, ZMQ_DONTWAIT));\n\n\n    //  Check whether receive timeout is honored\n    const int timeout = 250;\n    const int jitter = 50;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (frontend, ZMQ_RCVTIMEO, &timeout, sizeof (int)));\n\n    void *stopwatch = zmq_stopwatch_start ();\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (frontend, buffer, 32, 0));\n    unsigned int elapsed = zmq_stopwatch_stop (stopwatch) / 1000;\n    TEST_ASSERT_GREATER_THAN_INT (timeout - jitter, elapsed);\n    if (elapsed >= timeout + jitter) {\n        // we cannot assert this on a non-RT system\n        fprintf (stderr,\n                 \"zmq_recv took quite long, with a timeout of %i ms, it took \"\n                 \"actually %i ms\\n\",\n                 timeout, elapsed);\n    }\n\n    //  Check that normal message flow works as expected\n    void *backend = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (backend, \"inproc://timeout_test\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (backend, ZMQ_SNDTIMEO, &timeout, sizeof (int)));\n\n    send_string_expect_success (backend, \"Hello\", 0);\n    recv_string_expect_success (frontend, \"Hello\", 0);\n\n    //  Clean-up\n    test_context_socket_close (backend);\n    test_context_socket_close (frontend);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_timeo);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_timers.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#define __STDC_LIMIT_MACROS // to define SIZE_MAX with older compilers\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\nvoid handler (int timer_id_, void *arg_)\n{\n    (void) timer_id_; //  Stop 'unused' compiler warnings\n    *(static_cast<bool *> (arg_)) = true;\n}\n\nint sleep_and_execute (void *timers_)\n{\n    int timeout = zmq_timers_timeout (timers_);\n\n    //  Sleep methods are inaccurate, so we sleep in a loop until time arrived\n    while (timeout > 0) {\n        msleep (timeout);\n        timeout = zmq_timers_timeout (timers_);\n    }\n\n    return zmq_timers_execute (timers_);\n}\n\nvoid test_null_timer_pointers ()\n{\n    void *timers = NULL;\n\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_destroy (&timers));\n\n//  TODO this currently triggers an access violation\n#if 0\n  TEST_ASSERT_FAILURE_ERRNO(EFAULT, zmq_timers_destroy (NULL));\n#endif\n\n    const size_t dummy_interval = 100;\n    const int dummy_timer_id = 1;\n\n    TEST_ASSERT_FAILURE_ERRNO (\n      EFAULT, zmq_timers_add (timers, dummy_interval, &handler, NULL));\n    TEST_ASSERT_FAILURE_ERRNO (\n      EFAULT, zmq_timers_add (&timers, dummy_interval, &handler, NULL));\n\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_timers_cancel (timers, dummy_timer_id));\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_timers_cancel (&timers, dummy_timer_id));\n\n    TEST_ASSERT_FAILURE_ERRNO (\n      EFAULT, zmq_timers_set_interval (timers, dummy_timer_id, dummy_interval));\n    TEST_ASSERT_FAILURE_ERRNO (\n      EFAULT,\n      zmq_timers_set_interval (&timers, dummy_timer_id, dummy_interval));\n\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_timers_reset (timers, dummy_timer_id));\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT,\n                               zmq_timers_reset (&timers, dummy_timer_id));\n\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_timeout (timers));\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_timeout (&timers));\n\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_execute (timers));\n    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_execute (&timers));\n}\n\nvoid test_corner_cases ()\n{\n    void *timers = zmq_timers_new ();\n    TEST_ASSERT_NOT_NULL (timers);\n\n    const size_t dummy_interval = SIZE_MAX;\n    const int dummy_timer_id = 1;\n\n    //  attempt to cancel non-existent timer\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL,\n                               zmq_timers_cancel (timers, dummy_timer_id));\n\n    //  attempt to set interval of non-existent timer\n    TEST_ASSERT_FAILURE_ERRNO (\n      EINVAL, zmq_timers_set_interval (timers, dummy_timer_id, dummy_interval));\n\n    //  attempt to reset non-existent timer\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL,\n                               zmq_timers_reset (timers, dummy_timer_id));\n\n    //  attempt to add NULL handler\n    TEST_ASSERT_FAILURE_ERRNO (\n      EFAULT, zmq_timers_add (timers, dummy_interval, NULL, NULL));\n\n    const int timer_id = TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_timers_add (timers, dummy_interval, handler, NULL));\n\n    //  attempt to cancel timer twice\n    //  TODO should this case really be an error? canceling twice could be allowed\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_cancel (timers, timer_id));\n\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_timers_cancel (timers, timer_id));\n\n    //  timeout without any timers active\n    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_timers_timeout (timers));\n\n    //  cleanup\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_destroy (&timers));\n}\n\nvoid test_timers ()\n{\n    void *timers = zmq_timers_new ();\n    TEST_ASSERT_NOT_NULL (timers);\n\n    bool timer_invoked = false;\n\n    const unsigned long full_timeout = 100;\n    void *const stopwatch = zmq_stopwatch_start ();\n\n    const int timer_id = TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_timers_add (timers, full_timeout, handler, &timer_invoked));\n\n    //  Timer should not have been invoked yet\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));\n\n    if (zmq_stopwatch_intermediate (stopwatch) < full_timeout) {\n        TEST_ASSERT_FALSE (timer_invoked);\n    }\n\n    //  Wait half the time and check again\n    long timeout = TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_timeout (timers));\n    msleep (timeout / 2);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));\n    if (zmq_stopwatch_intermediate (stopwatch) < full_timeout) {\n        TEST_ASSERT_FALSE (timer_invoked);\n    }\n\n    // Wait until the end\n    TEST_ASSERT_SUCCESS_ERRNO (sleep_and_execute (timers));\n    TEST_ASSERT_TRUE (timer_invoked);\n    timer_invoked = false;\n\n    //  Wait half the time and check again\n    timeout = TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_timeout (timers));\n    msleep (timeout / 2);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));\n    if (zmq_stopwatch_intermediate (stopwatch) < 2 * full_timeout) {\n        TEST_ASSERT_FALSE (timer_invoked);\n    }\n\n    // Reset timer and wait half of the time left\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_reset (timers, timer_id));\n    msleep (timeout / 2);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));\n    if (zmq_stopwatch_stop (stopwatch) < 2 * full_timeout) {\n        TEST_ASSERT_FALSE (timer_invoked);\n    }\n\n    // Wait until the end\n    TEST_ASSERT_SUCCESS_ERRNO (sleep_and_execute (timers));\n    TEST_ASSERT_TRUE (timer_invoked);\n    timer_invoked = false;\n\n    // reschedule\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_set_interval (timers, timer_id, 50));\n    TEST_ASSERT_SUCCESS_ERRNO (sleep_and_execute (timers));\n    TEST_ASSERT_TRUE (timer_invoked);\n    timer_invoked = false;\n\n    // cancel timer\n    timeout = TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_timeout (timers));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_cancel (timers, timer_id));\n    msleep (timeout * 2);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));\n    TEST_ASSERT_FALSE (timer_invoked);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_destroy (&timers));\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_timers);\n    RUN_TEST (test_null_timer_pointers);\n    RUN_TEST (test_corner_cases);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_unbind_wildcard.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_address_wildcard_ipv4 ()\n{\n    /* Address wildcard, IPv6 disabled */\n    void *sb = test_context_socket (ZMQ_REP);\n    void *sc = test_context_socket (ZMQ_REQ);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"tcp://*:*\"));\n\n    char bind_endpoint[256];\n    char connect_endpoint[256];\n    size_t endpoint_len = sizeof (bind_endpoint);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, bind_endpoint, &endpoint_len));\n\n    //  Apparently Windows can't connect to 0.0.0.0. A better fix would be welcome.\n#ifdef ZMQ_HAVE_WINDOWS\n    snprintf (connect_endpoint, 256 * sizeof (char), \"tcp://127.0.0.1:%s\",\n              strrchr (bind_endpoint, ':') + 1);\n#else\n    strcpy (connect_endpoint, bind_endpoint);\n#endif\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_endpoint));\n\n    bounce (sb, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, connect_endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb, bind_endpoint));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_address_wildcard_ipv6 ()\n{\n    int ipv6 = is_ipv6_available ();\n\n    /* Address wildcard, IPv6 enabled */\n    void *sb = test_context_socket (ZMQ_REP);\n    void *sc = test_context_socket (ZMQ_REQ);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sb, ZMQ_IPV6, &ipv6, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_IPV6, &ipv6, sizeof (int)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"tcp://*:*\"));\n\n    char bind_endpoint[256];\n    char connect_endpoint[256];\n    size_t endpoint_len = sizeof (bind_endpoint);\n    memset (bind_endpoint, 0, endpoint_len);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, bind_endpoint, &endpoint_len));\n\n#ifdef ZMQ_HAVE_WINDOWS\n    if (ipv6)\n        snprintf (connect_endpoint, 256 * sizeof (char), \"tcp://[::1]:%s\",\n                  strrchr (bind_endpoint, ':') + 1);\n    else\n        snprintf (connect_endpoint, 256 * sizeof (char), \"tcp://127.0.0.1:%s\",\n                  strrchr (bind_endpoint, ':') + 1);\n#else\n    strcpy (connect_endpoint, bind_endpoint);\n#endif\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_endpoint));\n\n    bounce (sb, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, connect_endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb, bind_endpoint));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_port_wildcard_ipv4_address ()\n{\n    /* Port wildcard, IPv4 address, IPv6 disabled */\n    void *sb = test_context_socket (ZMQ_REP);\n    void *sc = test_context_socket (ZMQ_REQ);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"tcp://127.0.0.1:*\"));\n\n    char endpoint[256];\n    size_t endpoint_len = sizeof (endpoint);\n    memset (endpoint, 0, endpoint_len);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, endpoint, &endpoint_len));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint));\n\n    bounce (sb, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb, endpoint));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_port_wildcard_ipv4_address_ipv6 ()\n{\n    /* Port wildcard, IPv4 address, IPv6 enabled */\n    void *sb = test_context_socket (ZMQ_REP);\n    void *sc = test_context_socket (ZMQ_REQ);\n\n    const int ipv6 = is_ipv6_available ();\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sb, ZMQ_IPV6, &ipv6, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_IPV6, &ipv6, sizeof (int)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"tcp://127.0.0.1:*\"));\n\n    char endpoint[256];\n    size_t endpoint_len = sizeof (endpoint);\n    memset (endpoint, 0, endpoint_len);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, endpoint, &endpoint_len));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint));\n\n    bounce (sb, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb, endpoint));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_port_wildcard_ipv6_address ()\n{\n    const int ipv6 = is_ipv6_available ();\n    if (!ipv6)\n        TEST_IGNORE_MESSAGE (\"ipv6 is not available\");\n\n    /* Port wildcard, IPv6 address, IPv6 enabled */\n    void *sb = test_context_socket (ZMQ_REP);\n    void *sc = test_context_socket (ZMQ_REQ);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sb, ZMQ_IPV6, &ipv6, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_IPV6, &ipv6, sizeof (int)));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"tcp://[::1]:*\"));\n\n    char endpoint[256];\n    size_t endpoint_len = sizeof (endpoint);\n    memset (endpoint, 0, endpoint_len);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, endpoint, &endpoint_len));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint));\n\n    bounce (sb, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, endpoint));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb, endpoint));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_address_wildcard_ipv4);\n    RUN_TEST (test_address_wildcard_ipv6);\n    RUN_TEST (test_port_wildcard_ipv4_address);\n    RUN_TEST (test_port_wildcard_ipv4_address_ipv6);\n    RUN_TEST (test_port_wildcard_ipv6_address);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_use_fd.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n#if !defined(ZMQ_HAVE_WINDOWS)\n\nvoid pre_allocate_sock_tcp (void *socket_, char *my_endpoint_)\n{\n    fd_t s = bind_socket_resolve_port (\"127.0.0.1\", \"0\", my_endpoint_);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket_, ZMQ_USE_FD, &s, sizeof (s)));\n}\n\ntypedef void (*pre_allocate_sock_fun_t) (void *, char *);\n\nvoid setup_socket_pair (pre_allocate_sock_fun_t pre_allocate_sock_fun_,\n                        int bind_socket_type_,\n                        int connect_socket_type_,\n                        void **out_sb_,\n                        void **out_sc_)\n{\n    *out_sb_ = test_context_socket (bind_socket_type_);\n\n    char my_endpoint[MAX_SOCKET_STRING];\n    pre_allocate_sock_fun_ (*out_sb_, my_endpoint);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (*out_sb_, my_endpoint));\n\n    *out_sc_ = test_context_socket (connect_socket_type_);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (*out_sc_, my_endpoint));\n}\n\nvoid test_socket_pair (pre_allocate_sock_fun_t pre_allocate_sock_fun_,\n                       int bind_socket_type_,\n                       int connect_socket_type_)\n{\n    void *sb, *sc;\n    setup_socket_pair (pre_allocate_sock_fun_, bind_socket_type_,\n                       connect_socket_type_, &sb, &sc);\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_req_rep (pre_allocate_sock_fun_t pre_allocate_sock_fun_)\n{\n    test_socket_pair (pre_allocate_sock_fun_, ZMQ_REP, ZMQ_REQ);\n}\n\nvoid test_pair (pre_allocate_sock_fun_t pre_allocate_sock_fun_)\n{\n    test_socket_pair (pre_allocate_sock_fun_, ZMQ_PAIR, ZMQ_PAIR);\n}\n\nvoid test_client_server (pre_allocate_sock_fun_t pre_allocate_sock_fun_)\n{\n#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)\n    void *sb, *sc;\n    setup_socket_pair (pre_allocate_sock_fun_, ZMQ_SERVER, ZMQ_CLIENT, &sb,\n                       &sc);\n\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));\n\n    char *data = static_cast<char *> (zmq_msg_data (&msg));\n    data[0] = 1;\n\n    int rc = zmq_msg_send (&msg, sc, ZMQ_SNDMORE);\n    // TODO which error code is expected?\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n\n    rc = zmq_msg_send (&msg, sc, 0);\n    TEST_ASSERT_EQUAL_INT (1, rc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));\n\n    rc = zmq_msg_recv (&msg, sb, 0);\n    TEST_ASSERT_EQUAL_INT (1, rc);\n\n    uint32_t routing_id = zmq_msg_routing_id (&msg);\n    TEST_ASSERT_NOT_EQUAL (0, routing_id);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));\n\n    data = static_cast<char *> (zmq_msg_data (&msg));\n    data[0] = 2;\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_set_routing_id (&msg, routing_id));\n\n    rc = zmq_msg_send (&msg, sb, ZMQ_SNDMORE);\n    // TODO which error code is expected?\n    TEST_ASSERT_EQUAL_INT (-1, rc);\n\n    rc = zmq_msg_send (&msg, sb, 0);\n    TEST_ASSERT_EQUAL_INT (1, rc);\n\n    rc = zmq_msg_recv (&msg, sc, 0);\n    TEST_ASSERT_EQUAL_INT (1, rc);\n\n    routing_id = zmq_msg_routing_id (&msg);\n    TEST_ASSERT_EQUAL_INT (0, routing_id);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n#endif\n}\n\nvoid test_req_rep_tcp ()\n{\n    test_req_rep (pre_allocate_sock_tcp);\n}\n\nvoid test_pair_tcp ()\n{\n    test_pair (pre_allocate_sock_tcp);\n}\n\nvoid test_client_server_tcp ()\n{\n#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)\n    test_client_server (pre_allocate_sock_tcp);\n#endif\n}\n\nchar ipc_endpoint[MAX_SOCKET_STRING] = \"\";\n\nvoid pre_allocate_sock_ipc (void *sb_, char *my_endpoint_)\n{\n    fd_t s = bind_socket_resolve_port (\"\", \"\", my_endpoint_, AF_UNIX, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sb_, ZMQ_USE_FD, &s, sizeof (s)));\n    strcpy (ipc_endpoint, strchr (my_endpoint_, '/') + 2);\n}\n\nvoid test_req_rep_ipc ()\n{\n    test_req_rep (pre_allocate_sock_ipc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (unlink (ipc_endpoint));\n}\n\nvoid test_pair_ipc ()\n{\n    test_pair (pre_allocate_sock_ipc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (unlink (ipc_endpoint));\n}\n\nvoid test_client_server_ipc ()\n{\n#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)\n    test_client_server (pre_allocate_sock_ipc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (unlink (ipc_endpoint));\n#endif\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_req_rep_tcp);\n    RUN_TEST (test_pair_tcp);\n    RUN_TEST (test_client_server_tcp);\n\n    RUN_TEST (test_req_rep_ipc);\n    RUN_TEST (test_pair_ipc);\n    RUN_TEST (test_client_server_ipc);\n\n    return UNITY_END ();\n}\n#else\nint main ()\n{\n    return 0;\n}\n#endif\n"
  },
  {
    "path": "tests/test_ws_transport.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include <string.h>\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_roundtrip ()\n{\n    char bind_address[MAX_SOCKET_STRING];\n    char connect_address[MAX_SOCKET_STRING];\n    size_t addr_length = sizeof (connect_address);\n\n    void *sb = test_context_socket (ZMQ_REP);\n    void *sc = test_context_socket (ZMQ_REQ);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"ws://*:*/roundtrip\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, bind_address, &addr_length));\n\n    // Windows can't connect to 0.0.0.0\n    snprintf (connect_address, MAX_SOCKET_STRING * sizeof (char),\n              \"ws://127.0.0.1%s\", strrchr (bind_address, ':'));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_address));\n\n    bounce (sb, sc);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, connect_address));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb, bind_address));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_roundtrip_without_path ()\n{\n    char connect_address[MAX_SOCKET_STRING];\n    size_t addr_length = sizeof (connect_address);\n    void *sb = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"ws://127.0.0.1:*\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, connect_address, &addr_length));\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_address));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\n\nvoid test_heartbeat ()\n{\n    char connect_address[MAX_SOCKET_STRING];\n    size_t addr_length = sizeof (connect_address);\n    void *sb = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"ws://127.0.0.1:*/heartbeat\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, connect_address, &addr_length));\n\n    void *sc = test_context_socket (ZMQ_REQ);\n\n    // Setting heartbeat settings\n    int ivl = 10;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_HEARTBEAT_IVL, &ivl, sizeof (ivl)));\n\n    // Disable reconnect, to make sure the ping-pong actually work\n    ivl = -1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sc, ZMQ_RECONNECT_IVL, &ivl, sizeof (ivl)));\n\n    // Connect to server\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_address));\n\n    // Make sure some ping and pong going through\n    msleep (100);\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_short_message ()\n{\n    char connect_address[MAX_SOCKET_STRING];\n    size_t addr_length = sizeof (connect_address);\n    void *sb = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"ws://127.0.0.1:*/short\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, connect_address, &addr_length));\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_address));\n\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 255));\n\n    for (unsigned char i = 0; i < 255; ++i)\n        ((unsigned char *) zmq_msg_data (&msg))[i] = i;\n\n    int rc = zmq_msg_send (&msg, sc, 0);\n    TEST_ASSERT_EQUAL_INT (255, rc);\n\n    rc = zmq_msg_recv (&msg, sb, 0);\n    TEST_ASSERT_EQUAL_INT (255, rc);\n\n    for (unsigned char i = 0; i < 255; ++i)\n        TEST_ASSERT_EQUAL_INT (i, ((unsigned char *) zmq_msg_data (&msg))[i]);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_large_message ()\n{\n    char connect_address[MAX_SOCKET_STRING];\n    size_t addr_length = sizeof (connect_address);\n    void *sb = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"ws://127.0.0.1:*/large\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, connect_address, &addr_length));\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_address));\n\n    zmq_msg_t msg;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 65536));\n\n    for (int i = 0; i < 65536; ++i)\n        ((unsigned char *) zmq_msg_data (&msg))[i] = i % 255;\n\n    int rc = zmq_msg_send (&msg, sc, 0);\n    TEST_ASSERT_EQUAL_INT (65536, rc);\n\n    rc = zmq_msg_recv (&msg, sb, 0);\n    TEST_ASSERT_EQUAL_INT (65536, rc);\n\n    for (int i = 0; i < 65536; ++i)\n        TEST_ASSERT_EQUAL_INT (i % 255,\n                               ((unsigned char *) zmq_msg_data (&msg))[i]);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_curve ()\n{\n    char connect_address[MAX_SOCKET_STRING];\n    size_t addr_length = sizeof (connect_address);\n    char client_public[41];\n    char client_secret[41];\n    char server_public[41];\n    char server_secret[41];\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_curve_keypair (server_public, server_secret));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_curve_keypair (client_public, client_secret));\n\n    void *server = test_context_socket (ZMQ_REP);\n    int as_server = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_CURVE_SERVER, &as_server, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server, ZMQ_CURVE_SECRETKEY, server_secret, 41));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, \"ws://127.0.0.1:*/roundtrip\"));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (server, ZMQ_LAST_ENDPOINT,\n                                               connect_address, &addr_length));\n\n    void *client = test_context_socket (ZMQ_REQ);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, connect_address));\n\n    bounce (server, client);\n\n    test_context_socket_close (client);\n    test_context_socket_close (server);\n}\n\n\nvoid test_mask_shared_msg ()\n{\n    char connect_address[MAX_SOCKET_STRING];\n    size_t addr_length = sizeof (connect_address);\n    void *sb = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"ws://127.0.0.1:*/mask-shared\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, connect_address, &addr_length));\n\n    void *sc = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_address));\n\n    zmq_msg_t msg;\n    zmq_msg_init_size (\n      &msg, 255); // Message have to be long enough so it won't fit inside msg\n    unsigned char *data = (unsigned char *) zmq_msg_data (&msg);\n    for (int i = 0; i < 255; i++)\n        data[i] = i;\n\n    //  Taking a copy to make the msg shared\n    zmq_msg_t copy;\n    zmq_msg_init (&copy);\n    zmq_msg_copy (&copy, &msg);\n\n    //  Sending the shared msg\n    int rc = zmq_msg_send (&msg, sc, 0);\n    TEST_ASSERT_EQUAL_INT (255, rc);\n\n    //  Recv the msg and check that it was masked correctly\n    rc = zmq_msg_recv (&msg, sb, 0);\n    TEST_ASSERT_EQUAL_INT (255, rc);\n    data = (unsigned char *) zmq_msg_data (&msg);\n    for (int i = 0; i < 255; i++)\n        TEST_ASSERT_EQUAL_INT (i, data[i]);\n\n    //  Testing that copy was not masked\n    data = (unsigned char *) zmq_msg_data (&copy);\n    for (int i = 0; i < 255; i++)\n        TEST_ASSERT_EQUAL_INT (i, data[i]);\n\n    //  Constant msg cannot be masked as well, as it is constant\n    rc = zmq_send_const (sc, \"HELLO\", 5, 0);\n    TEST_ASSERT_EQUAL_INT (5, rc);\n    recv_string_expect_success (sb, \"HELLO\", 0);\n\n    zmq_msg_close (&copy);\n    zmq_msg_close (&msg);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nvoid test_pub_sub ()\n{\n    char connect_address[MAX_SOCKET_STRING];\n    size_t addr_length = sizeof (connect_address);\n    void *sb = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"ws://127.0.0.1:*\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, connect_address, &addr_length));\n\n    void *sc = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sc, ZMQ_SUBSCRIBE, \"A\", 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sc, ZMQ_SUBSCRIBE, \"B\", 1));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_address));\n\n    recv_string_expect_success (sb, \"\\1A\", 0);\n    recv_string_expect_success (sb, \"\\1B\", 0);\n\n    send_string_expect_success (sb, \"A\", 0);\n    send_string_expect_success (sb, \"B\", 0);\n\n    recv_string_expect_success (sc, \"A\", 0);\n    recv_string_expect_success (sc, \"B\", 0);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip_without_path);\n    RUN_TEST (test_roundtrip);\n    RUN_TEST (test_short_message);\n    RUN_TEST (test_large_message);\n    RUN_TEST (test_heartbeat);\n    RUN_TEST (test_mask_shared_msg);\n    RUN_TEST (test_pub_sub);\n\n    if (zmq_has (\"curve\"))\n        RUN_TEST (test_curve);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_wss_transport.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include <string.h>\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\n#ifdef ZMQ_WSS_CERT_PEM\nconst char *key =\n  \"-----BEGIN PRIVATE KEY-----\\n\"\n  \"MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDnzizmqK1e0iRR\\n\"\n  \"lY75z9q3TWVBzFYX00Rl18GT2liW6AYzOB/qa55EhjTf4snhC2FaUoosu4MYRdvo\\n\"\n  \"8qBOpFvnQDScJ6o06LyrWyL15kkBYEsTkjmDEXe/TxUVE2IBb991m1F91SIEjK5m\\n\"\n  \"NRH2aRjrN5mL9f8+Crrv96Y4sxGCDkqwOarViFbDYFxdYa7WrvZImpknrmM5KPyg\\n\"\n  \"PtU9gqnlIgAU9bPTGUJGdQeQ+AWKOgw6unV8IiKEX8jyHBoKiAqTspRCCV9yDOKx\\n\"\n  \"eVUGgkcAMpeSv8HVboNbfof8DI+eT8EtYNsWW4dINgiYYEGZIhy74X2dKria6hCc\\n\"\n  \"AYdS+/90nf0RAyymniDtgTGrMIXFmjlYpLngqfAo+zzl21dGh3VnRUFbTak8CH4g\\n\"\n  \"wYIefJFerwJP1im5jAiULWHaiOOk2r5fHdxbBLebqcaWBRSGGNE9cj4bj/qYuHAf\\n\"\n  \"VrNW5+CN3j0h5ss/f8lOoDbbrb6GtSJfI16fuQZd2hW84u38EuVd1/mzbVMv7Bip\\n\"\n  \"yzjbEAcOgn0Mk89zZewooz8Sxr2e1R47/5CCHJodUFqc5hmcnOqRd7YmpM68bS7V\\n\"\n  \"KbnOY3w9Llw6tkXMitmtUs7IiKZ1ViXA3UzMSumvEJKMqOnfNEUH9pkqYe2lVbay\\n\"\n  \"1HSk/hz7AkprVPMlqlF12x/794fg9wIDAQABAoICAHI10UWsYg9P9nkD+Tf4Q0kB\\n\"\n  \"JxyuMtT2UMLk9QmGERP5KeTeiEsVzxrwDOkqclEhLEw2UsILeWHiOaGiuX1F2cos\\n\"\n  \"hj9SA7ih2yOKecUyO1IkQZlY+GEtoBRwQHDr5ePTXQQzDIm1E1eugNb22uzPh2mN\\n\"\n  \"MWgWQjYtT0GggRN6luu/YulE4Hjo/eaxeZDA6kX4WnwXP9KfR2AIY8AIdUQjNtYg\\n\"\n  \"VG3/SSR/U3onexzgNsqOIyxkZjJNFzilgPpZAjOiJ6Px3r5So+Yrlx3eLBhS4+yj\\n\"\n  \"AK9bL4ObOblAtHtpLPHRVdqn2ApB+nuHs+BvvKJYflPLm/pt7BrXrGtRDX3Dj27T\\n\"\n  \"sXPZTBsPmFr8vqlbgIYNCiY3uQonsAO95o0Y0Dx6oVFlzL1ajP49KmUye+p/wEHc\\n\"\n  \"1XfYD8DxfU+ECEZk1/DvmKIPc4cZr2U1i9RBVRiKFd4NFIGYylLihuYhB9FZEyWQ\\n\"\n  \"p0TwM3DFs7PwIQNPE6mGKtjgdgBGkY4AGfCxQzdp1mM+I2700OIx0EHAbxm5JMQm\\n\"\n  \"NQKtBWliiz7+DLK/NWrDVS8N8tdkZVpHUK6ahvJbYG8oDqX0me6Bmk+0SaQJujis\\n\"\n  \"fOPFRNGanr0X97+fqMJnDeOfXAcYurXBm81IkGilUF+2a0wWhS7PGhOT4dcLKRU8\\n\"\n  \"tcmIZRJDWWyv2uQGg2yhAoIBAQD5sM7SX/ZuQ44HHmjQP59//vxCoZYqcPtf+52z\\n\"\n  \"kCpRnbbzFh/uTLRBvQ5NjZp7XOpZ/3y05JnarYChjCuVjG5+SJO7UQ0pl5N7LL0r\\n\"\n  \"3YGSRkfBGE05AiccyitonQssnJ4GVGfkt+1l9kVn4aMN9YkgoWc68vFzHY9CfIjS\\n\"\n  \"3d7QM89vGJBmBCpLG9WC0R24VNH6mfnM0MANwFlYFk9a2cKWueNjMidtHaNgry7A\\n\"\n  \"lWKn7jEUizkb5kNiVoFC+9qYx16unR1U2K4eRJoOhOLNWPaPuGX219iMvQ+CHs2T\\n\"\n  \"ZA72qj0d29t2wS8RmFXAIRNDuc7MkPh3iTF4jdRt57/pU1WPAoIBAQDtqavyOx/h\\n\"\n  \"kilyGjALfca68iQscWuVmWCVzFFfeGvFN4IXSxgM38xmtSEhAILVf7ozv/QNJsxv\\n\"\n  \"9l1xGkY+FaoFTSxglMw0iO4fZwNp2GuEy57jFzJuJyzE4FiueNb5dzoZnGnXxJIS\\n\"\n  \"bnprZgR42aaYAU0PzPwrqyc3PXv2J4tn6O8Mt53JO4bN+/XomD4oQBOhM0iLuS7t\\n\"\n  \"xTUQnsaHr1QglSIGQf4XOmXTO0+dE5uhFXkKP0Frq4MtoJUdEiWNzOdzwzxAZJTL\\n\"\n  \"v8dPOQud9yxKxwRg2rroasKgyRgE6GHqKSRhggiMwVOFzeMxPLJ2oeWmpRZXiMoH\\n\"\n  \"dkiCnPh7DBoZAoIBAGSuUJcvrrSDdO+V6XmfTfdUn+9WLLDsYdAwK0TOauICEFUw\\n\"\n  \"pKt4Lm8bhnrrEFGSA8VKacSfMRKmR2nclW5188/j//3WDtKolgVi4tyfMrICuMg5\\n\"\n  \"vlmwbokDVEGYoXrZpDa1Ljdhms40YYQjzZXBXgvUSUXR1F4wmyWaBanRYRje61PG\\n\"\n  \"ueMI5uzmSk+3dp5vRUQhdkKKIgbpep00Ucc2a2pPhkrnXFJ5UvmXaeip0+AXAZ9h\\n\"\n  \"DCQd0yoB65lQ6LIWIi2SmNMvk/YMf3o/Rxy6NKF7H1JLcrw9N9WmCgrWm9oGhyJV\\n\"\n  \"Fsdp2krj/B++tn/mmmaORkIdBd+wgOnYOuAghC0CggEBAK6KtLgyieh9Eqk06GIY\\n\"\n  \"HlJ/sOde6Pc2bIO3SW/HHcb6TDVVNjWGSzSHA+yb1np70sFc0RyziOMVWWzOMhY4\\n\"\n  \"jORV2CiaPxq6Eb/IRO6APf6KGIeJKsVRSgTRCvAf2SnfUTEr+WO4ftrAfnHPu6sR\\n\"\n  \"ldL+6ZyYG/7qNOPR6O9P/YbzwFRjqaL3b7ppuCD5ZnTjEkeKRVYwS3HeKmmpYf6W\\n\"\n  \"Wj+PpyxXXQesIMowPfkLRHnaLknDSQWNMcrZq4ltIV1xxe3zzZUxCUJV90eMiqaZ\\n\"\n  \"t9K3NNT47tnwRj4VUemQzRBO5OQjvqm49eFH4vnvLNYJcoKfrbfdwxoV2YzrQWYE\\n\"\n  \"7kkCggEBAKzLviuI6eoaPwgKeR2wrFBbrucnY4yqkVIFzFRpjM6azzMArYVpslZW\\n\"\n  \"DTdmi/2QCd9altVAT20Yvml8YqrFszpINV1DqBIfHtQPEy9oKrhFW92rhuJQo/aX\\n\"\n  \"1yILvzmyzLdpQG6zLm7TD7mEkumiT9F3ObeoVnAOllEwUrNAfDPPclRHGowJs6Ya\\n\"\n  \"wv50Idk62v7gnXny9OyFN3kUq6dtwItYqmalfKKGXhTi49mEWX39SSZSt+a15oKM\\n\"\n  \"21fKHdqiG/AXST7n8IlBGRzyW9TqTnmVC5zj7esmqfRT0eno399hl0LOZgJoa4dx\\n\"\n  \"lMwbKi/uEdrUT3ei3nAxnuQolXgClZk=\\n\"\n  \"-----END PRIVATE KEY-----\";\n\nconst char *cert =\n  \"-----BEGIN CERTIFICATE-----\\n\"\n  \"MIIFkTCCA3mgAwIBAgIUWazS3jRxgV/9TgdybZ9ch7nYsQIwDQYJKoZIhvcNAQEL\\n\"\n  \"BQAwVzELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE\\n\"\n  \"CgwTRGVmYXVsdCBDb21wYW55IEx0ZDETMBEGA1UEAwwKemVyb21xLm9yZzAgFw0x\\n\"\n  \"OTExMTAwODMzMThaGA8yMTE5MTAxNzA4MzMxOFowVzELMAkGA1UEBhMCWFgxFTAT\\n\"\n  \"BgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0\\n\"\n  \"ZDETMBEGA1UEAwwKemVyb21xLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC\\n\"\n  \"AgoCggIBAOfOLOaorV7SJFGVjvnP2rdNZUHMVhfTRGXXwZPaWJboBjM4H+prnkSG\\n\"\n  \"NN/iyeELYVpSiiy7gxhF2+jyoE6kW+dANJwnqjTovKtbIvXmSQFgSxOSOYMRd79P\\n\"\n  \"FRUTYgFv33WbUX3VIgSMrmY1EfZpGOs3mYv1/z4Kuu/3pjizEYIOSrA5qtWIVsNg\\n\"\n  \"XF1hrtau9kiamSeuYzko/KA+1T2CqeUiABT1s9MZQkZ1B5D4BYo6DDq6dXwiIoRf\\n\"\n  \"yPIcGgqICpOylEIJX3IM4rF5VQaCRwAyl5K/wdVug1t+h/wMj55PwS1g2xZbh0g2\\n\"\n  \"CJhgQZkiHLvhfZ0quJrqEJwBh1L7/3Sd/REDLKaeIO2BMaswhcWaOVikueCp8Cj7\\n\"\n  \"POXbV0aHdWdFQVtNqTwIfiDBgh58kV6vAk/WKbmMCJQtYdqI46Tavl8d3FsEt5up\\n\"\n  \"xpYFFIYY0T1yPhuP+pi4cB9Ws1bn4I3ePSHmyz9/yU6gNtutvoa1Il8jXp+5Bl3a\\n\"\n  \"Fbzi7fwS5V3X+bNtUy/sGKnLONsQBw6CfQyTz3Nl7CijPxLGvZ7VHjv/kIIcmh1Q\\n\"\n  \"WpzmGZyc6pF3tiakzrxtLtUpuc5jfD0uXDq2RcyK2a1SzsiIpnVWJcDdTMxK6a8Q\\n\"\n  \"koyo6d80RQf2mSph7aVVtrLUdKT+HPsCSmtU8yWqUXXbH/v3h+D3AgMBAAGjUzBR\\n\"\n  \"MB0GA1UdDgQWBBTVHR+4lBIBcr2rEEMdideTAkwDZDAfBgNVHSMEGDAWgBTVHR+4\\n\"\n  \"lBIBcr2rEEMdideTAkwDZDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA\\n\"\n  \"A4ICAQB9M5p9z92UhVXg2baUj9QBN2YFGAeveFRpZ9Y/wktEssTqMKkc+39UtfJS\\n\"\n  \"UclZnzMEhLyTieNqf+8GCgLLI0YSTIJpWwzvQBcXPoo+8IcexANvxR22KZrE51y4\\n\"\n  \"/YfCKh8Q0ZbG8oc5Br8YHwipzGcmWjWtznfMpuaELezv/r381QV1Sbmpw2a0jvwp\\n\"\n  \"uA/bc+4IZ9yvrhC9KkOUnivnCV71U2Wy8zOvrBEJicuGOc+lbWJRKyjbMDi1IybG\\n\"\n  \"VnemtkQEyXFh6f1h8AdaN+Xj7qXX/YKmNk20Siu4qDNo8nozVpOL2DHjoKLa4N2c\\n\"\n  \"ULG3kXScxVxWqCuPVNeypV2TZ9uSVFeKK/VJ5iGvFeifDsqVVo6WC4Pdz0WYes8H\\n\"\n  \"3VqEPSwmNJ1FswLpYpGgCEFnkGRPFFB5dmwr0fuubkgaJPatxrImFac+nukfqZ8N\\n\"\n  \"x/d4t72u1yIs0HnrkAj96ZIUXH5jFGPXbD8eGO0hzw+wbY9KRLXGBBl2B4EAaBdt\\n\"\n  \"Cmp8R8xus3FGDZ5RVftZvTQO2CiTC4yn9Wab/ADDwcXDs6ntHctx4xQpm0tLqMoz\\n\"\n  \"BTH8+ftqyzklar35gJluD84oh1kynEojrPkUvb75NlzxikBSF3pRrOx30Myy7DBx\\n\"\n  \"rhUIqDFxqlYFx9InEzHlvI7cWWdMNqAmSxpz4SXMrd/7PJG+Ag==\\n\"\n  \"-----END CERTIFICATE-----\";\n\nvoid test_roundtrip ()\n{\n    char connect_address[MAX_SOCKET_STRING + sizeof (\"/roundtrip\") - 1];\n    size_t addr_length = sizeof (connect_address);\n    void *sb = test_context_socket (ZMQ_REP);\n    zmq_setsockopt (sb, ZMQ_WSS_CERT_PEM, cert, strlen (cert));\n    zmq_setsockopt (sb, ZMQ_WSS_KEY_PEM, key, strlen (key));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"wss://*:*/roundtrip\"));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, connect_address, &addr_length));\n    strcat (connect_address, \"/roundtrip\");\n\n    void *sc = test_context_socket (ZMQ_REQ);\n    zmq_setsockopt (sc, ZMQ_WSS_TRUST_PEM, cert, strlen (cert));\n    zmq_setsockopt (sc, ZMQ_WSS_HOSTNAME, \"zeromq.org\", strlen (\"zeromq.org\"));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_address));\n\n    bounce (sb, sc);\n\n    test_context_socket_close (sc);\n    test_context_socket_close (sb);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_roundtrip);\n    return UNITY_END ();\n}\n#else\nint main ()\n{\n    printf (\"WSS unavailable, skipping test\\n\");\n    return 77;\n}\n#endif\n"
  },
  {
    "path": "tests/test_xpub_manual.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_basic ()\n{\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n    int manual = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_MANUAL, &manual, 4));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, \"inproc://soname\"));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"inproc://soname\"));\n\n    //  Subscribe for A\n    const char subscription[] = {1, 'A', 0};\n    send_string_expect_success (sub, subscription, 0);\n\n    // Receive subscriptions from subscriber\n    recv_string_expect_success (pub, subscription, 0);\n\n    // Subscribe socket for B instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"B\", 1));\n\n    // Sending A message and B Message\n    send_string_expect_success (pub, \"A\", 0);\n    send_string_expect_success (pub, \"B\", 0);\n\n    recv_string_expect_success (sub, \"B\", ZMQ_DONTWAIT);\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nvoid test_unsubscribe_manual ()\n{\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, \"inproc://soname\"));\n\n    //  set pub socket options\n    int manual = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_MANUAL, &manual, sizeof (manual)));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"inproc://soname\"));\n\n    //  Subscribe for A\n    const uint8_t subscription1[] = {1, 'A'};\n    send_array_expect_success (sub, subscription1, 0);\n\n    //  Subscribe for B\n    const uint8_t subscription2[] = {1, 'B'};\n    send_array_expect_success (sub, subscription2, 0);\n\n    char buffer[3];\n\n    // Receive subscription \"A\" from subscriber\n    recv_array_expect_success (pub, subscription1, 0);\n\n    // Subscribe socket for XA instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"XA\", 2));\n\n    // Receive subscription \"B\" from subscriber\n    recv_array_expect_success (pub, subscription2, 0);\n\n    // Subscribe socket for XB instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"XB\", 2));\n\n    //  Unsubscribe from A\n    const uint8_t unsubscription1[2] = {0, 'A'};\n    send_array_expect_success (sub, unsubscription1, 0);\n\n    // Receive unsubscription \"A\" from subscriber\n    recv_array_expect_success (pub, unsubscription1, 0);\n\n    // Unsubscribe socket from XA instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_UNSUBSCRIBE, \"XA\", 2));\n\n    // Sending messages XA, XB\n    send_string_expect_success (pub, \"XA\", 0);\n    send_string_expect_success (pub, \"XB\", 0);\n\n    // Subscriber should receive XB only\n    recv_string_expect_success (sub, \"XB\", ZMQ_DONTWAIT);\n\n    // Close subscriber\n    test_context_socket_close (sub);\n\n    // Receive unsubscription \"B\"\n    const char unsubscription2[2] = {0, 'B'};\n    TEST_ASSERT_EQUAL_INT (\n      sizeof unsubscription2,\n      TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (pub, buffer, sizeof buffer, 0)));\n    TEST_ASSERT_EQUAL_INT8_ARRAY (unsubscription2, buffer,\n                                  sizeof unsubscription2);\n\n    // Unsubscribe socket from XB instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_UNSUBSCRIBE, \"XB\", 2));\n\n    //  Clean up.\n    test_context_socket_close (pub);\n}\n\nvoid test_xpub_proxy_unsubscribe_on_disconnect ()\n{\n    const uint8_t topic_buff[] = {\"1\"};\n    const uint8_t payload_buff[] = {\"X\"};\n\n    char my_endpoint_backend[MAX_SOCKET_STRING];\n    char my_endpoint_frontend[MAX_SOCKET_STRING];\n\n    int manual = 1;\n\n    // proxy frontend\n    void *xsub_proxy = test_context_socket (ZMQ_XSUB);\n    bind_loopback_ipv4 (xsub_proxy, my_endpoint_frontend,\n                        sizeof my_endpoint_frontend);\n\n    // proxy backend\n    void *xpub_proxy = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_XPUB_MANUAL, &manual, 4));\n    bind_loopback_ipv4 (xpub_proxy, my_endpoint_backend,\n                        sizeof my_endpoint_backend);\n\n    // publisher\n    void *pub = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pub, my_endpoint_frontend));\n\n    // first subscriber subscribes\n    void *sub1 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub1, my_endpoint_backend));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, topic_buff, 1));\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy reroutes and confirms subscriptions\n    const uint8_t subscription[2] = {1, *topic_buff};\n    recv_array_expect_success (xpub_proxy, subscription, ZMQ_DONTWAIT);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic_buff, 1));\n    send_array_expect_success (xsub_proxy, subscription, 0);\n\n    // second subscriber subscribes\n    void *sub2 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub2, my_endpoint_backend));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub2, ZMQ_SUBSCRIBE, topic_buff, 1));\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy reroutes\n    recv_array_expect_success (xpub_proxy, subscription, ZMQ_DONTWAIT);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic_buff, 1));\n    send_array_expect_success (xsub_proxy, subscription, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // let publisher send a msg\n    send_array_expect_success (pub, topic_buff, ZMQ_SNDMORE);\n    send_array_expect_success (pub, payload_buff, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy reroutes data messages to subscribers\n    recv_array_expect_success (xsub_proxy, topic_buff, ZMQ_DONTWAIT);\n    recv_array_expect_success (xsub_proxy, payload_buff, ZMQ_DONTWAIT);\n    send_array_expect_success (xpub_proxy, topic_buff, ZMQ_SNDMORE);\n    send_array_expect_success (xpub_proxy, payload_buff, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // each subscriber should now get a message\n    recv_array_expect_success (sub2, topic_buff, ZMQ_DONTWAIT);\n    recv_array_expect_success (sub2, payload_buff, ZMQ_DONTWAIT);\n\n    recv_array_expect_success (sub1, topic_buff, ZMQ_DONTWAIT);\n    recv_array_expect_success (sub1, payload_buff, ZMQ_DONTWAIT);\n\n    //  Disconnect both subscribers\n    test_context_socket_close (sub1);\n    test_context_socket_close (sub2);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // unsubscribe messages are passed from proxy to publisher\n    const uint8_t unsubscription[] = {0, *topic_buff};\n    recv_array_expect_success (xpub_proxy, unsubscription, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_UNSUBSCRIBE, topic_buff, 1));\n    send_array_expect_success (xsub_proxy, unsubscription, 0);\n\n    // should receive another unsubscribe msg\n    recv_array_expect_success (xpub_proxy, unsubscription, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_UNSUBSCRIBE, topic_buff, 1));\n    send_array_expect_success (xsub_proxy, unsubscription, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // let publisher send a msg\n    send_array_expect_success (pub, topic_buff, ZMQ_SNDMORE);\n    send_array_expect_success (pub, payload_buff, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // nothing should come to the proxy\n    char buffer[1];\n    TEST_ASSERT_FAILURE_ERRNO (\n      EAGAIN, zmq_recv (xsub_proxy, buffer, sizeof buffer, ZMQ_DONTWAIT));\n\n    test_context_socket_close (pub);\n    test_context_socket_close (xpub_proxy);\n    test_context_socket_close (xsub_proxy);\n}\n\nvoid test_missing_subscriptions ()\n{\n    const char *topic1 = \"1\";\n    const char *topic2 = \"2\";\n    const char *payload = \"X\";\n\n    char my_endpoint_backend[MAX_SOCKET_STRING];\n    char my_endpoint_frontend[MAX_SOCKET_STRING];\n\n    int manual = 1;\n\n    // proxy frontend\n    void *xsub_proxy = test_context_socket (ZMQ_XSUB);\n    bind_loopback_ipv4 (xsub_proxy, my_endpoint_frontend,\n                        sizeof my_endpoint_frontend);\n\n    // proxy backend\n    void *xpub_proxy = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_XPUB_MANUAL, &manual, 4));\n    bind_loopback_ipv4 (xpub_proxy, my_endpoint_backend,\n                        sizeof my_endpoint_backend);\n\n    // publisher\n    void *pub = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pub, my_endpoint_frontend));\n\n    // Here's the problem: because subscribers subscribe in quick succession,\n    // the proxy is unable to confirm the first subscription before receiving\n    // the second. This causes the first subscription to get lost.\n\n    // first subscriber\n    void *sub1 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub1, my_endpoint_backend));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, topic1, 1));\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy now reroutes and confirms subscriptions\n    const uint8_t subscription1[] = {1, static_cast<uint8_t> (topic1[0])};\n    recv_array_expect_success (xpub_proxy, subscription1, ZMQ_DONTWAIT);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic1, 1));\n    send_array_expect_success (xsub_proxy, subscription1, 0);\n\n    // second subscriber\n    void *sub2 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub2, my_endpoint_backend));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub2, ZMQ_SUBSCRIBE, topic2, 1));\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    const uint8_t subscription2[] = {1, static_cast<uint8_t> (topic2[0])};\n    recv_array_expect_success (xpub_proxy, subscription2, ZMQ_DONTWAIT);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic2, 1));\n    send_array_expect_success (xsub_proxy, subscription2, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // let publisher send 2 msgs, each with its own topic_buff\n    send_string_expect_success (pub, topic1, ZMQ_SNDMORE);\n    send_string_expect_success (pub, payload, 0);\n    send_string_expect_success (pub, topic2, ZMQ_SNDMORE);\n    send_string_expect_success (pub, payload, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy reroutes data messages to subscribers\n    recv_string_expect_success (xsub_proxy, topic1, ZMQ_DONTWAIT);\n    recv_string_expect_success (xsub_proxy, payload, ZMQ_DONTWAIT);\n    send_string_expect_success (xpub_proxy, topic1, ZMQ_SNDMORE);\n    send_string_expect_success (xpub_proxy, payload, 0);\n\n    recv_string_expect_success (xsub_proxy, topic2, ZMQ_DONTWAIT);\n    recv_string_expect_success (xsub_proxy, payload, ZMQ_DONTWAIT);\n    send_string_expect_success (xpub_proxy, topic2, ZMQ_SNDMORE);\n    send_string_expect_success (xpub_proxy, payload, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // each subscriber should now get a message\n    recv_string_expect_success (sub2, topic2, ZMQ_DONTWAIT);\n    recv_string_expect_success (sub2, payload, ZMQ_DONTWAIT);\n\n    recv_string_expect_success (sub1, topic1, ZMQ_DONTWAIT);\n    recv_string_expect_success (sub1, payload, ZMQ_DONTWAIT);\n\n    //  Clean up\n    test_context_socket_close (sub1);\n    test_context_socket_close (sub2);\n    test_context_socket_close (pub);\n    test_context_socket_close (xpub_proxy);\n    test_context_socket_close (xsub_proxy);\n}\n\nvoid test_unsubscribe_cleanup ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n    int manual = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_MANUAL, &manual, 4));\n    bind_loopback_ipv4 (pub, my_endpoint, sizeof my_endpoint);\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, my_endpoint));\n\n    //  Subscribe for A\n    const uint8_t subscription1[2] = {1, 'A'};\n    send_array_expect_success (sub, subscription1, 0);\n\n\n    // Receive subscriptions from subscriber\n    recv_array_expect_success (pub, subscription1, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"XA\", 2));\n\n    // send 2 messages\n    send_string_expect_success (pub, \"XA\", 0);\n    send_string_expect_success (pub, \"XB\", 0);\n\n    // receive the single message\n    recv_string_expect_success (sub, \"XA\", 0);\n\n    // should be nothing left in the queue\n    char buffer[2];\n    TEST_ASSERT_FAILURE_ERRNO (\n      EAGAIN, zmq_recv (sub, buffer, sizeof buffer, ZMQ_DONTWAIT));\n\n    // close the socket\n    test_context_socket_close (sub);\n\n    // closing the socket will result in an unsubscribe event\n    const uint8_t unsubscription[2] = {0, 'A'};\n    recv_array_expect_success (pub, unsubscription, 0);\n\n    // this doesn't really do anything\n    // there is no last_pipe set it will just fail silently\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_UNSUBSCRIBE, \"XA\", 2));\n\n    // reconnect\n    sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, my_endpoint));\n\n    // send a subscription for B\n    const uint8_t subscription2[2] = {1, 'B'};\n    send_array_expect_success (sub, subscription2, 0);\n\n    // receive the subscription, overwrite it to XB\n    recv_array_expect_success (pub, subscription2, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"XB\", 2));\n\n    // send 2 messages\n    send_string_expect_success (pub, \"XA\", 0);\n    send_string_expect_success (pub, \"XB\", 0);\n\n    // receive the single message\n    recv_string_expect_success (sub, \"XB\", 0);\n\n    // should be nothing left in the queue\n    TEST_ASSERT_FAILURE_ERRNO (\n      EAGAIN, zmq_recv (sub, buffer, sizeof buffer, ZMQ_DONTWAIT));\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nvoid test_user_message ()\n{\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, \"inproc://soname\"));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"inproc://soname\"));\n\n    //  Send some data that is neither sub nor unsub\n    const char subscription[] = {2, 'A', 0};\n    send_string_expect_success (sub, subscription, 0);\n\n    // Receive subscriptions from subscriber\n    recv_string_expect_success (pub, subscription, 0);\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\n#ifdef ZMQ_ONLY_FIRST_SUBSCRIBE\nvoid test_user_message_multi ()\n{\n    const int only_first_subscribe = 1;\n\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, \"inproc://soname\"));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_ONLY_FIRST_SUBSCRIBE,\n                                               &only_first_subscribe,\n                                               sizeof (only_first_subscribe)));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"inproc://soname\"));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_ONLY_FIRST_SUBSCRIBE,\n                                               &only_first_subscribe,\n                                               sizeof (only_first_subscribe)));\n\n    //  Send some data that is neither sub nor unsub\n    const uint8_t msg_common[] = {'A', 'B', 'C'};\n    //  Message starts with 0 but should still treated as user\n    const uint8_t msg_0a[] = {0, 'B', 'C'};\n    const uint8_t msg_0b[] = {0, 'C', 'D'};\n    //  Message starts with 1 but should still treated as user\n    const uint8_t msg_1a[] = {1, 'B', 'C'};\n    const uint8_t msg_1b[] = {1, 'C', 'D'};\n\n    // Test second message starting with 0\n    send_array_expect_success (sub, msg_common, ZMQ_SNDMORE);\n    send_array_expect_success (sub, msg_0a, 0);\n\n    // Receive messages from subscriber\n    recv_array_expect_success (pub, msg_common, 0);\n    recv_array_expect_success (pub, msg_0a, 0);\n\n    // Test second message starting with 1\n    send_array_expect_success (sub, msg_common, ZMQ_SNDMORE);\n    send_array_expect_success (sub, msg_1a, 0);\n\n    // Receive messages from subscriber\n    recv_array_expect_success (pub, msg_common, 0);\n    recv_array_expect_success (pub, msg_1a, 0);\n\n    // Test first message starting with 1\n    send_array_expect_success (sub, msg_1a, ZMQ_SNDMORE);\n    send_array_expect_success (sub, msg_1b, 0);\n    recv_array_expect_success (pub, msg_1a, 0);\n    recv_array_expect_success (pub, msg_1b, 0);\n\n    send_array_expect_success (sub, msg_0a, ZMQ_SNDMORE);\n    send_array_expect_success (sub, msg_0b, 0);\n    recv_array_expect_success (pub, msg_0a, 0);\n    recv_array_expect_success (pub, msg_0b, 0);\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n#endif\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_basic);\n    RUN_TEST (test_unsubscribe_manual);\n    RUN_TEST (test_xpub_proxy_unsubscribe_on_disconnect);\n    RUN_TEST (test_missing_subscriptions);\n    RUN_TEST (test_unsubscribe_cleanup);\n    RUN_TEST (test_user_message);\n#ifdef ZMQ_ONLY_FIRST_SUBSCRIBE\n    RUN_TEST (test_user_message_multi);\n#endif\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_xpub_manual_last_value.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_basic ()\n{\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n    int manual = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_MANUAL_LAST_VALUE, &manual, 4));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, \"inproc://soname\"));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"inproc://soname\"));\n\n    //  Subscribe for A\n    const char subscription[] = {1, 'A', 0};\n    send_string_expect_success (sub, subscription, 0);\n\n    // Receive subscriptions from subscriber\n    recv_string_expect_success (pub, subscription, 0);\n\n    // Subscribe socket for B instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"B\", 1));\n\n    // Sending A message and B Message\n    send_string_expect_success (pub, \"A\", 0);\n    send_string_expect_success (pub, \"B\", 0);\n\n    recv_string_expect_success (sub, \"B\", ZMQ_DONTWAIT);\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nvoid test_unsubscribe_manual ()\n{\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, \"inproc://soname\"));\n\n    //  set pub socket options\n    int manual = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_XPUB_MANUAL_LAST_VALUE,\n                                               &manual, sizeof (manual)));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"inproc://soname\"));\n\n    //  Subscribe for A\n    const uint8_t subscription1[] = {1, 'A'};\n    send_array_expect_success (sub, subscription1, 0);\n\n    //  Subscribe for B\n    const uint8_t subscription2[] = {1, 'B'};\n    send_array_expect_success (sub, subscription2, 0);\n\n    char buffer[3];\n\n    // Receive subscription \"A\" from subscriber\n    recv_array_expect_success (pub, subscription1, 0);\n\n    // Subscribe socket for XA instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"XA\", 2));\n\n    // Receive subscription \"B\" from subscriber\n    recv_array_expect_success (pub, subscription2, 0);\n\n    // Subscribe socket for XB instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"XB\", 2));\n\n    //  Unsubscribe from A\n    const uint8_t unsubscription1[2] = {0, 'A'};\n    send_array_expect_success (sub, unsubscription1, 0);\n\n    // Receive unsubscription \"A\" from subscriber\n    recv_array_expect_success (pub, unsubscription1, 0);\n\n    // Unsubscribe socket from XA instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_UNSUBSCRIBE, \"XA\", 2));\n\n    // Sending messages XA, XB\n    send_string_expect_success (pub, \"XA\", 0);\n    send_string_expect_success (pub, \"XB\", 0);\n\n    // Subscriber should receive XB only\n    recv_string_expect_success (sub, \"XB\", ZMQ_DONTWAIT);\n\n    // Close subscriber\n    test_context_socket_close (sub);\n\n    // Receive unsubscription \"B\"\n    const char unsubscription2[2] = {0, 'B'};\n    TEST_ASSERT_EQUAL_INT (\n      sizeof unsubscription2,\n      TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (pub, buffer, sizeof buffer, 0)));\n    TEST_ASSERT_EQUAL_INT8_ARRAY (unsubscription2, buffer,\n                                  sizeof unsubscription2);\n\n    // Unsubscribe socket from XB instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_UNSUBSCRIBE, \"XB\", 2));\n\n    //  Clean up.\n    test_context_socket_close (pub);\n}\n\nvoid test_xpub_proxy_unsubscribe_on_disconnect ()\n{\n    const uint8_t topic_buff[] = {\"1\"};\n    const uint8_t payload_buff[] = {\"X\"};\n\n    char my_endpoint_backend[MAX_SOCKET_STRING];\n    char my_endpoint_frontend[MAX_SOCKET_STRING];\n\n    int manual = 1;\n\n    // proxy frontend\n    void *xsub_proxy = test_context_socket (ZMQ_XSUB);\n    bind_loopback_ipv4 (xsub_proxy, my_endpoint_frontend,\n                        sizeof my_endpoint_frontend);\n\n    // proxy backend\n    void *xpub_proxy = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_XPUB_MANUAL_LAST_VALUE, &manual, 4));\n    bind_loopback_ipv4 (xpub_proxy, my_endpoint_backend,\n                        sizeof my_endpoint_backend);\n\n    // publisher\n    void *pub = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pub, my_endpoint_frontend));\n\n    // first subscriber subscribes\n    void *sub1 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub1, my_endpoint_backend));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, topic_buff, 1));\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy reroutes and confirms subscriptions\n    const uint8_t subscription[2] = {1, *topic_buff};\n    recv_array_expect_success (xpub_proxy, subscription, ZMQ_DONTWAIT);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic_buff, 1));\n    send_array_expect_success (xsub_proxy, subscription, 0);\n\n    // second subscriber subscribes\n    void *sub2 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub2, my_endpoint_backend));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub2, ZMQ_SUBSCRIBE, topic_buff, 1));\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy reroutes\n    recv_array_expect_success (xpub_proxy, subscription, ZMQ_DONTWAIT);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic_buff, 1));\n    send_array_expect_success (xsub_proxy, subscription, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // let publisher send a msg\n    send_array_expect_success (pub, topic_buff, ZMQ_SNDMORE);\n    send_array_expect_success (pub, payload_buff, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy reroutes data messages to subscribers\n    recv_array_expect_success (xsub_proxy, topic_buff, ZMQ_DONTWAIT);\n    recv_array_expect_success (xsub_proxy, payload_buff, ZMQ_DONTWAIT);\n\n    // send 2 messages\n    send_array_expect_success (xpub_proxy, topic_buff, ZMQ_SNDMORE);\n    send_array_expect_success (xpub_proxy, payload_buff, 0);\n    send_array_expect_success (xpub_proxy, topic_buff, ZMQ_SNDMORE);\n    send_array_expect_success (xpub_proxy, payload_buff, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // sub2 will get 2 messages because the last subscription is sub2.\n    recv_array_expect_success (sub2, topic_buff, ZMQ_DONTWAIT);\n    recv_array_expect_success (sub2, payload_buff, ZMQ_DONTWAIT);\n    recv_array_expect_success (sub2, topic_buff, ZMQ_DONTWAIT);\n    recv_array_expect_success (sub2, payload_buff, ZMQ_DONTWAIT);\n\n    recv_array_expect_success (sub1, topic_buff, ZMQ_DONTWAIT);\n    recv_array_expect_success (sub1, payload_buff, ZMQ_DONTWAIT);\n\n    //  Disconnect both subscribers\n    test_context_socket_close (sub1);\n    test_context_socket_close (sub2);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // unsubscribe messages are passed from proxy to publisher\n    const uint8_t unsubscription[] = {0, *topic_buff};\n    recv_array_expect_success (xpub_proxy, unsubscription, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_UNSUBSCRIBE, topic_buff, 1));\n    send_array_expect_success (xsub_proxy, unsubscription, 0);\n\n    // should receive another unsubscribe msg\n    recv_array_expect_success (xpub_proxy, unsubscription, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_UNSUBSCRIBE, topic_buff, 1));\n    send_array_expect_success (xsub_proxy, unsubscription, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // let publisher send a msg\n    send_array_expect_success (pub, topic_buff, ZMQ_SNDMORE);\n    send_array_expect_success (pub, payload_buff, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // nothing should come to the proxy\n    char buffer[1];\n    TEST_ASSERT_FAILURE_ERRNO (\n      EAGAIN, zmq_recv (xsub_proxy, buffer, sizeof buffer, ZMQ_DONTWAIT));\n\n    test_context_socket_close (pub);\n    test_context_socket_close (xpub_proxy);\n    test_context_socket_close (xsub_proxy);\n}\n\nvoid test_missing_subscriptions ()\n{\n    const char *topic1 = \"1\";\n    const char *topic2 = \"2\";\n    const char *payload = \"X\";\n\n    char my_endpoint_backend[MAX_SOCKET_STRING];\n    char my_endpoint_frontend[MAX_SOCKET_STRING];\n\n    int manual = 1;\n\n    // proxy frontend\n    void *xsub_proxy = test_context_socket (ZMQ_XSUB);\n    bind_loopback_ipv4 (xsub_proxy, my_endpoint_frontend,\n                        sizeof my_endpoint_frontend);\n\n    // proxy backend\n    void *xpub_proxy = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_XPUB_MANUAL_LAST_VALUE, &manual, 4));\n    bind_loopback_ipv4 (xpub_proxy, my_endpoint_backend,\n                        sizeof my_endpoint_backend);\n\n    // publisher\n    void *pub = test_context_socket (ZMQ_PUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pub, my_endpoint_frontend));\n\n    // Here's the problem: because subscribers subscribe in quick succession,\n    // the proxy is unable to confirm the first subscription before receiving\n    // the second. This causes the first subscription to get lost.\n\n    // first subscriber\n    void *sub1 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub1, my_endpoint_backend));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, topic1, 1));\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy now reroutes and confirms subscriptions\n    const uint8_t subscription1[] = {1, static_cast<uint8_t> (topic1[0])};\n    recv_array_expect_success (xpub_proxy, subscription1, ZMQ_DONTWAIT);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic1, 1));\n    send_array_expect_success (xsub_proxy, subscription1, 0);\n\n    // second subscriber\n    void *sub2 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub2, my_endpoint_backend));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub2, ZMQ_SUBSCRIBE, topic2, 1));\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy now reroutes and confirms subscriptions\n    const uint8_t subscription2[] = {1, static_cast<uint8_t> (topic2[0])};\n    recv_array_expect_success (xpub_proxy, subscription2, ZMQ_DONTWAIT);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic2, 1));\n    send_array_expect_success (xsub_proxy, subscription2, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // let publisher send 2 msgs, each with its own topic_buff\n    send_string_expect_success (pub, topic1, ZMQ_SNDMORE);\n    send_string_expect_success (pub, payload, 0);\n    send_string_expect_success (pub, topic2, ZMQ_SNDMORE);\n    send_string_expect_success (pub, payload, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // proxy reroutes data messages to subscribers\n    recv_string_expect_success (xsub_proxy, topic1, ZMQ_DONTWAIT);\n    recv_string_expect_success (xsub_proxy, payload, ZMQ_DONTWAIT);\n    send_string_expect_success (xpub_proxy, topic1, ZMQ_SNDMORE);\n    send_string_expect_success (xpub_proxy, payload, 0);\n\n    recv_string_expect_success (xsub_proxy, topic2, ZMQ_DONTWAIT);\n    recv_string_expect_success (xsub_proxy, payload, ZMQ_DONTWAIT);\n    send_string_expect_success (xpub_proxy, topic2, ZMQ_SNDMORE);\n    send_string_expect_success (xpub_proxy, payload, 0);\n\n    // wait\n    msleep (SETTLE_TIME);\n\n    // only sub2 should now get a message\n    recv_string_expect_success (sub2, topic2, ZMQ_DONTWAIT);\n    recv_string_expect_success (sub2, payload, ZMQ_DONTWAIT);\n\n    //recv_string_expect_success (sub1, topic1, ZMQ_DONTWAIT);\n    //recv_string_expect_success (sub1, payload, ZMQ_DONTWAIT);\n\n    //  Clean up\n    test_context_socket_close (sub1);\n    test_context_socket_close (sub2);\n    test_context_socket_close (pub);\n    test_context_socket_close (xpub_proxy);\n    test_context_socket_close (xsub_proxy);\n}\n\nvoid test_unsubscribe_cleanup ()\n{\n    char my_endpoint[MAX_SOCKET_STRING];\n\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n    int manual = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_MANUAL_LAST_VALUE, &manual, 4));\n    bind_loopback_ipv4 (pub, my_endpoint, sizeof my_endpoint);\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, my_endpoint));\n\n    //  Subscribe for A\n    const uint8_t subscription1[2] = {1, 'A'};\n    send_array_expect_success (sub, subscription1, 0);\n\n\n    // Receive subscriptions from subscriber\n    recv_array_expect_success (pub, subscription1, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"XA\", 2));\n\n    // send 2 messages\n    send_string_expect_success (pub, \"XA\", 0);\n    send_string_expect_success (pub, \"XB\", 0);\n\n    // receive the single message\n    recv_string_expect_success (sub, \"XA\", 0);\n\n    // should be nothing left in the queue\n    char buffer[2];\n    TEST_ASSERT_FAILURE_ERRNO (\n      EAGAIN, zmq_recv (sub, buffer, sizeof buffer, ZMQ_DONTWAIT));\n\n    // close the socket\n    test_context_socket_close (sub);\n\n    // closing the socket will result in an unsubscribe event\n    const uint8_t unsubscription[2] = {0, 'A'};\n    recv_array_expect_success (pub, unsubscription, 0);\n\n    // this doesn't really do anything\n    // there is no last_pipe set it will just fail silently\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_UNSUBSCRIBE, \"XA\", 2));\n\n    // reconnect\n    sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, my_endpoint));\n\n    // send a subscription for B\n    const uint8_t subscription2[2] = {1, 'B'};\n    send_array_expect_success (sub, subscription2, 0);\n\n    // receive the subscription, overwrite it to XB\n    recv_array_expect_success (pub, subscription2, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"XB\", 2));\n\n    // send 2 messages\n    send_string_expect_success (pub, \"XA\", 0);\n    send_string_expect_success (pub, \"XB\", 0);\n\n    // receive the single message\n    recv_string_expect_success (sub, \"XB\", 0);\n\n    // should be nothing left in the queue\n    TEST_ASSERT_FAILURE_ERRNO (\n      EAGAIN, zmq_recv (sub, buffer, sizeof buffer, ZMQ_DONTWAIT));\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nvoid test_manual_last_value ()\n{\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n\n    int hwm = 2000;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SNDHWM, &hwm, 4));\n\n    //  set pub socket options\n    int manual = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_MANUAL_LAST_VALUE, &manual, 4));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, \"inproc://soname\"));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"inproc://soname\"));\n\n    //  Create another subscriber\n    void *sub2 = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub2, \"inproc://soname\"));\n\n    //  Subscribe for \"A\".\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, \"A\", 1));\n\n    const uint8_t subscription[2] = {1, 'A'};\n    //  we must wait for the subscription to be processed here, otherwise some\n    //  or all published messages might be lost\n    recv_array_expect_success (pub, subscription, 0);\n\n    //  manual subscribe message\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"A\", 1));\n    send_string_expect_success (pub, \"A\", 0);\n    recv_string_expect_success (sub, \"A\", 0);\n\n    //  Subscribe for \"A\".\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub2, ZMQ_SUBSCRIBE, \"A\", 1));\n    recv_array_expect_success (pub, subscription, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, \"A\", 1));\n    send_string_expect_success (pub, \"A\", 0);\n    recv_string_expect_success (sub2, \"A\", 0);\n\n    char buffer[255];\n    //  sub won't get a message because the last subscription pipe is sub2.\n    TEST_ASSERT_FAILURE_ERRNO (\n      EAGAIN, zmq_recv (sub, buffer, sizeof (buffer), ZMQ_DONTWAIT));\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n    test_context_socket_close (sub2);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_basic);\n    RUN_TEST (test_unsubscribe_manual);\n    RUN_TEST (test_xpub_proxy_unsubscribe_on_disconnect);\n    RUN_TEST (test_missing_subscriptions);\n    RUN_TEST (test_unsubscribe_cleanup);\n    RUN_TEST (test_manual_last_value);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_xpub_nodrop.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test ()\n{\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n\n    int hwm = 2000;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SNDHWM, &hwm, 4));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, \"inproc://soname\"));\n\n    //  set pub socket options\n    int wait = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_XPUB_NODROP, &wait, 4));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"inproc://soname\"));\n\n    //  Subscribe for all messages.\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, \"\", 0));\n\n    //  we must wait for the subscription to be processed here, otherwise some\n    //  or all published messages might be lost\n    recv_string_expect_success (pub, \"\\1\", 0);\n\n    int hwmlimit = hwm - 1;\n    int send_count = 0;\n\n    //  Send an empty message\n    for (int i = 0; i < hwmlimit; i++) {\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_send (pub, NULL, 0, 0));\n        send_count++;\n    }\n\n    int recv_count = 0;\n    do {\n        //  Receive the message in the subscriber\n        int rc = zmq_recv (sub, NULL, 0, 0);\n        if (rc == -1) {\n            TEST_ASSERT_EQUAL_INT (EAGAIN, errno);\n            break;\n        }\n        TEST_ASSERT_EQUAL_INT (0, rc);\n        recv_count++;\n\n        if (recv_count == 1) {\n            const int sub_rcvtimeo = 250;\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n              sub, ZMQ_RCVTIMEO, &sub_rcvtimeo, sizeof (sub_rcvtimeo)));\n        }\n\n    } while (true);\n\n    TEST_ASSERT_EQUAL_INT (send_count, recv_count);\n\n    //  Now test real blocking behavior\n    //  Set a timeout, default is infinite\n    int timeout = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SNDTIMEO, &timeout, 4));\n\n    send_count = 0;\n    recv_count = 0;\n    hwmlimit = hwm;\n\n    //  Send an empty message until we get an error, which must be EAGAIN\n    while (zmq_send (pub, \"\", 0, 0) == 0)\n        send_count++;\n    TEST_ASSERT_EQUAL_INT (EAGAIN, errno);\n\n    if (send_count > 0) {\n        //  Receive first message with blocking\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (sub, NULL, 0, 0));\n        recv_count++;\n\n        while (zmq_recv (sub, NULL, 0, ZMQ_DONTWAIT) == 0)\n            recv_count++;\n    }\n\n    TEST_ASSERT_EQUAL_INT (send_count, recv_count);\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nint main ()\n{\n    setup_test_environment ();\n    UNITY_BEGIN ();\n    RUN_TEST (test);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_xpub_topic.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nconst char bind_address[] = \"tcp://127.0.0.1:*\";\nchar connect_address[MAX_SOCKET_STRING];\n\n// 245 chars + 10 chars for subscribe command = 255 chars\nconst char short_topic[] =\n  \"ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP\"\n  \"ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP\"\n  \"ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP\"\n  \"ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDE\";\n\n// 246 chars + 10 chars for subscribe command = 256 chars\nconst char long_topic[] =\n  \"ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP\"\n  \"ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP\"\n  \"ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP\"\n  \"ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEF\";\n\n\ntemplate <size_t SIZE>\nvoid test_subscribe_cancel (void *xpub, void *sub, const char (&topic)[SIZE])\n{\n    // Ignore '\\0' terminating the topic string.\n    const size_t topic_len = SIZE - 1;\n\n    //  Subscribe for topic\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic, topic_len));\n\n    // Allow receiving more than the expected number of bytes\n    char buffer[topic_len + 5];\n\n    // Receive subscription\n    int rc =\n      TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (xpub, buffer, sizeof (buffer), 0));\n    TEST_ASSERT_EQUAL_INT (topic_len + 1, rc);\n    TEST_ASSERT_EQUAL_UINT8 (1, buffer[0]);\n    TEST_ASSERT_EQUAL_UINT8_ARRAY (topic, buffer + 1, topic_len);\n\n    // Unsubscribe from topic\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic, topic_len));\n\n    // Receive unsubscription\n    rc =\n      TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (xpub, buffer, sizeof (buffer), 0));\n    TEST_ASSERT_EQUAL_INT (topic_len + 1, rc);\n    TEST_ASSERT_EQUAL_UINT8 (0, buffer[0]);\n    TEST_ASSERT_EQUAL_UINT8_ARRAY (topic, buffer + 1, topic_len);\n}\n\nvoid test_xpub_subscribe_long_topic ()\n{\n    void *xpub = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (xpub, bind_address));\n    size_t len = MAX_SOCKET_STRING;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (xpub, ZMQ_LAST_ENDPOINT, connect_address, &len));\n\n    void *sub = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, connect_address));\n\n    test_subscribe_cancel (xpub, sub, short_topic);\n    test_subscribe_cancel (xpub, sub, long_topic);\n\n    //  Clean up.\n    test_context_socket_close (xpub);\n    test_context_socket_close (sub);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_xpub_subscribe_long_topic);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_xpub_verbose.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nconst uint8_t unsubscribe_a_msg[] = {0, 'A'};\nconst uint8_t subscribe_a_msg[] = {1, 'A'};\nconst uint8_t subscribe_b_msg[] = {1, 'B'};\n\nconst char test_endpoint[] = \"inproc://soname\";\nconst char topic_a[] = \"A\";\nconst char topic_b[] = \"B\";\n\nvoid test_xpub_verbose_one_sub ()\n{\n    void *pub = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, test_endpoint));\n\n    void *sub = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, test_endpoint));\n\n    //  Subscribe for A\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    // Receive subscriptions from subscriber\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    // Subscribe socket for B instead\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic_b, 1));\n\n    // Receive subscriptions from subscriber\n    recv_array_expect_success (pub, subscribe_b_msg, 0);\n\n    //  Subscribe again for A again\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    //  This time it is duplicated, so it will be filtered out\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    int verbose = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_VERBOSE, &verbose, sizeof (int)));\n\n    // Subscribe socket for A again\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    // This time with VERBOSE the duplicated sub will be received\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    // Sending A message and B Message\n    send_string_expect_success (pub, topic_a, 0);\n    send_string_expect_success (pub, topic_b, 0);\n\n    recv_string_expect_success (sub, topic_a, 0);\n    recv_string_expect_success (sub, topic_b, 0);\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nvoid create_xpub_with_2_subs (void **pub_, void **sub0_, void **sub1_)\n{\n    *pub_ = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (*pub_, test_endpoint));\n\n    *sub0_ = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (*sub0_, test_endpoint));\n\n    *sub1_ = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (*sub1_, test_endpoint));\n}\n\nvoid create_duplicate_subscription (void *pub_, void *sub0_, void *sub1_)\n{\n    //  Subscribe for A\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub0_, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    // Receive subscriptions from subscriber\n    recv_array_expect_success (pub_, subscribe_a_msg, 0);\n\n    //  Subscribe again for A on the other socket\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub1_, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    //  This time it is duplicated, so it will be filtered out by XPUB\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub_, NULL, 0, ZMQ_DONTWAIT));\n}\n\nvoid test_xpub_verbose_two_subs ()\n{\n    void *pub, *sub0, *sub1;\n    create_xpub_with_2_subs (&pub, &sub0, &sub1);\n    create_duplicate_subscription (pub, sub0, sub1);\n\n    // Subscribe socket for B instead\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub0, ZMQ_SUBSCRIBE, topic_b, 1));\n\n    // Receive subscriptions from subscriber\n    recv_array_expect_success (pub, subscribe_b_msg, 0);\n\n    int verbose = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_VERBOSE, &verbose, sizeof (int)));\n\n    // Subscribe socket for A again\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    // This time with VERBOSE the duplicated sub will be received\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    // Sending A message and B Message\n    send_string_expect_success (pub, topic_a, 0);\n\n    send_string_expect_success (pub, topic_b, 0);\n\n    recv_string_expect_success (sub0, topic_a, 0);\n    recv_string_expect_success (sub1, topic_a, 0);\n    recv_string_expect_success (sub0, topic_b, 0);\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub0);\n    test_context_socket_close (sub1);\n}\n\nvoid test_xpub_verboser_one_sub ()\n{\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, test_endpoint));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_SUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, test_endpoint));\n\n    //  Unsubscribe for A, does not exist yet\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    //  Does not exist, so it will be filtered out by XSUB\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    //  Subscribe for A\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    // Receive subscriptions from subscriber\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    //  Subscribe again for A again, XSUB will increase refcount\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    //  This time it is duplicated, so it will be filtered out by XPUB\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    //  Unsubscribe for A, this time it exists in XPUB\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    //  XSUB refcounts and will not actually send unsub to PUB until the number\n    //  of unsubs match the earlier subs\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    // Receive unsubscriptions from subscriber\n    recv_array_expect_success (pub, unsubscribe_a_msg, 0);\n\n    //  XSUB only sends the last and final unsub, so XPUB will only receive 1\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    //  Unsubscribe for A, does not exist anymore\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    //  Does not exist, so it will be filtered out by XSUB\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    int verbose = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_VERBOSER, &verbose, sizeof (int)));\n\n    // Subscribe socket for A again\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    // Receive subscriptions from subscriber, did not exist anymore\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    // Sending A message to make sure everything still works\n    send_string_expect_success (pub, topic_a, 0);\n\n    recv_string_expect_success (sub, topic_a, 0);\n\n    //  Unsubscribe for A, this time it exists\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    // Receive unsubscriptions from subscriber\n    recv_array_expect_success (pub, unsubscribe_a_msg, 0);\n\n    //  Unsubscribe for A again, it does not exist anymore so XSUB will filter\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    //  XSUB only sends unsub if it matched it in its trie, IOW: it will only\n    //  send it if it existed in the first place even with XPUB_VERBBOSER\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nvoid test_xpub_verboser_two_subs ()\n{\n    void *pub, *sub0, *sub1;\n    create_xpub_with_2_subs (&pub, &sub0, &sub1);\n    create_duplicate_subscription (pub, sub0, sub1);\n\n    //  Unsubscribe for A, this time it exists in XPUB\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub0, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    //  sub1 is still subscribed, so no notification\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    //  Unsubscribe the second socket to trigger the notification\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub1, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    // Receive unsubscriptions since all sockets are gone\n    recv_array_expect_success (pub, unsubscribe_a_msg, 0);\n\n    //  Make really sure there is only one notification\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    int verbose = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_VERBOSER, &verbose, sizeof (int)));\n\n    // Subscribe socket for A again\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub0, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    // Subscribe socket for A again\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, topic_a, 1));\n\n    // Receive subscriptions from subscriber, did not exist anymore\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    //  VERBOSER is set, so subs from both sockets are received\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    // Sending A message to make sure everything still works\n    send_string_expect_success (pub, topic_a, 0);\n\n    recv_string_expect_success (sub0, topic_a, 0);\n    recv_string_expect_success (sub1, topic_a, 0);\n\n    //  Unsubscribe for A\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub1, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    // Receive unsubscriptions from first subscriber due to VERBOSER\n    recv_array_expect_success (pub, unsubscribe_a_msg, 0);\n\n    //  Unsubscribe for A again from the other socket\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub0, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    // Receive unsubscriptions from first subscriber due to VERBOSER\n    recv_array_expect_success (pub, unsubscribe_a_msg, 0);\n\n    //  Unsubscribe again to make sure it gets filtered now\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (sub1, ZMQ_UNSUBSCRIBE, topic_a, 1));\n\n    //  Unmatched, so XSUB filters even with VERBOSER\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub0);\n    test_context_socket_close (sub1);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_xpub_verbose_one_sub);\n    RUN_TEST (test_xpub_verbose_two_subs);\n    RUN_TEST (test_xpub_verboser_one_sub);\n    RUN_TEST (test_xpub_verboser_two_subs);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_xpub_welcome_msg.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test ()\n{\n    //  Create a publisher\n    void *pub = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, \"inproc://soname\"));\n\n    //  set pub socket options\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_WELCOME_MSG, \"W\", 1));\n\n    //  Create a subscriber\n    void *sub = test_context_socket (ZMQ_SUB);\n\n    // Subscribe to the welcome message\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, \"W\", 1));\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, \"inproc://soname\"));\n\n    const uint8_t buffer[2] = {1, 'W'};\n\n    // Receive the welcome subscription\n    recv_array_expect_success (pub, buffer, 0);\n\n    // Receive the welcome message\n    recv_string_expect_success (sub, \"W\", 0);\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_xsub_verbose.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nconst uint8_t unsubscribe_a_msg[] = {0, 'A'};\nconst uint8_t subscribe_a_msg[] = {1, 'A'};\n\nconst char test_endpoint[] = \"inproc://soname\";\n\nvoid test_xsub_verbose_unsubscribe ()\n{\n    void *pub = test_context_socket (ZMQ_XPUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, test_endpoint));\n\n    void *sub = test_context_socket (ZMQ_XSUB);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, test_endpoint));\n\n    // set option ZMQ_XPUB_VERBOSER to get all messages\n    int xbup_verboser = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (pub, ZMQ_XPUB_VERBOSER, &xbup_verboser, sizeof (int)));\n\n    // unsubscribe from topic A, does not exist yet\n    send_array_expect_success (sub, unsubscribe_a_msg, 0);\n\n    // does not exist, so it will be filtered out by XSUB\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    // subscribe to topic A\n    send_array_expect_success (sub, subscribe_a_msg, 0);\n\n    // receive subscription from subscriber\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    // subscribe again to topic A\n    send_array_expect_success (sub, subscribe_a_msg, 0);\n\n    // receive subscription from subscriber\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    // unsubscribe from topic A\n    send_array_expect_success (sub, unsubscribe_a_msg, 0);\n\n    // The first unsubscribe will be filtered out\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT));\n\n    // unsubscribe again from topic A\n    send_array_expect_success (sub, unsubscribe_a_msg, 0);\n\n    // receive unsubscription from subscriber\n    recv_array_expect_success (pub, unsubscribe_a_msg, 0);\n\n    // set option ZMQ_XSUB_VERBOSE_UNSUBSCRIBE to get duplicate unsubscribes\n    int xsub_verbose = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      sub, ZMQ_XSUB_VERBOSE_UNSUBSCRIBE, &xsub_verbose, sizeof (int)));\n\n    // unsubscribe from topic A, does not exist yet\n    send_array_expect_success (sub, unsubscribe_a_msg, 0);\n\n    // does not exist, but with ZMQ_XSUB_VERBOSE_UNSUBSCRIBE set it will be forwarded anyway\n    recv_array_expect_success (pub, unsubscribe_a_msg, 0);\n\n    // subscribe to topic A\n    send_array_expect_success (sub, subscribe_a_msg, 0);\n\n    // receive subscription from subscriber\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    // subscribe again to topic A\n    send_array_expect_success (sub, subscribe_a_msg, 0);\n\n    // receive subscription from subscriber\n    recv_array_expect_success (pub, subscribe_a_msg, 0);\n\n    // unsubscribe from topic A\n    send_array_expect_success (sub, unsubscribe_a_msg, 0);\n\n    // receive unsubscription from subscriber\n    recv_array_expect_success (pub, unsubscribe_a_msg, 0);\n\n    // unsubscribe again from topic A\n    send_array_expect_success (sub, unsubscribe_a_msg, 0);\n\n    // receive unsubscription from subscriber\n    recv_array_expect_success (pub, unsubscribe_a_msg, 0);\n\n    //  Clean up.\n    test_context_socket_close (pub);\n    test_context_socket_close (sub);\n}\n\nint main ()\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_xsub_verbose_unsubscribe);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_z85_decode_fuzzer.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef ZMQ_USE_FUZZING_ENGINE\n#include <fuzzer/FuzzedDataProvider.h>\n#endif\n\n#include <string>\n#include <stdlib.h>\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\nextern \"C\" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)\n{\n    uint8_t *secret_key;\n\n    if (size < 5)\n        return 0;\n\n    // As per API definition, input must be divisible by 5, so truncate it if it's not\n    size -= size % 5;\n    // As per API definition, the destination must be at least 0.8 times the input data\n    TEST_ASSERT_NOT_NULL (secret_key = (uint8_t *) malloc (size * 4 / 5));\n\n    std::string z85_secret_key (reinterpret_cast<const char *> (data), size);\n    zmq_z85_decode (secret_key, z85_secret_key.c_str ());\n\n    free (secret_key);\n\n    return 0;\n}\n\n#ifndef ZMQ_USE_FUZZING_ENGINE\nvoid test_z85_decode_fuzzer ()\n{\n    uint8_t **data;\n    size_t *len, num_cases = 0;\n    if (fuzzer_corpus_encode (\n          \"tests/libzmq-fuzz-corpora/test_z85_decode_fuzzer_seed_corpus\", &data,\n          &len, &num_cases)\n        != 0)\n        exit (77);\n\n    while (num_cases-- > 0) {\n        TEST_ASSERT_SUCCESS_ERRNO (\n          LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));\n        free (data[num_cases]);\n    }\n\n    free (data);\n    free (len);\n}\n\nint main (int argc, char **argv)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_z85_decode_fuzzer);\n\n    return UNITY_END ();\n}\n#endif\n"
  },
  {
    "path": "tests/test_zmq_poll_fd.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <netdb.h>\n#include <string.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#endif\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_poll_fd ()\n{\n    int recv_socket = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);\n    TEST_ASSERT_NOT_EQUAL (-1, recv_socket);\n\n    int flag = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      setsockopt (recv_socket, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)));\n\n    struct sockaddr_in saddr = bind_bsd_socket (recv_socket);\n\n    void *sb = test_context_socket (ZMQ_REP);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"tcp://127.0.0.1:*\"));\n\n    zmq_pollitem_t pollitems[] = {\n      {sb, 0, ZMQ_POLLIN, 0},\n      {NULL, recv_socket, ZMQ_POLLIN, 0},\n    };\n\n    int send_socket = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);\n    TEST_ASSERT_NOT_EQUAL (-1, send_socket);\n\n    char buf[10];\n    memset (buf, 1, 10);\n\n    TEST_ASSERT_SUCCESS_ERRNO (sendto (\n      send_socket, buf, 10, 0, (struct sockaddr *) &saddr, sizeof (saddr)));\n\n    TEST_ASSERT_EQUAL (1, zmq_poll (pollitems, 2, 1));\n    TEST_ASSERT_BITS_LOW (ZMQ_POLLIN, pollitems[0].revents);\n    TEST_ASSERT_BITS_HIGH (ZMQ_POLLIN, pollitems[1].revents);\n\n    test_context_socket_close (sb);\n\n    close (send_socket);\n    close (recv_socket);\n}\n\nint main ()\n{\n    UNITY_BEGIN ();\n    RUN_TEST (test_poll_fd);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_zmq_ppoll_fd.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h>\n\n#ifndef _WIN32\n#include <netdb.h>\n#include <unistd.h>\n#endif\n\nSETUP_TEARDOWN_TESTCONTEXT\n\nvoid test_ppoll_fd ()\n{\n#ifdef ZMQ_HAVE_PPOLL\n    int recv_socket = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);\n    TEST_ASSERT_NOT_EQUAL (-1, recv_socket);\n\n    int flag = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      setsockopt (recv_socket, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)));\n\n    struct sockaddr_in saddr = bind_bsd_socket (recv_socket);\n\n    void *sb = test_context_socket (ZMQ_REP);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, \"tcp://127.0.0.1:*\"));\n\n    zmq_pollitem_t pollitems[] = {\n      {sb, 0, ZMQ_POLLIN, 0},\n      {NULL, recv_socket, ZMQ_POLLIN, 0},\n    };\n\n    int send_socket = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);\n    TEST_ASSERT_NOT_EQUAL (-1, send_socket);\n\n    char buf[10];\n    memset (buf, 1, 10);\n\n    TEST_ASSERT_SUCCESS_ERRNO (sendto (\n      send_socket, buf, 10, 0, (struct sockaddr *) &saddr, sizeof (saddr)));\n\n    TEST_ASSERT_EQUAL (1, zmq_ppoll (pollitems, 2, 1, NULL));\n    TEST_ASSERT_BITS_LOW (ZMQ_POLLIN, pollitems[0].revents);\n    TEST_ASSERT_BITS_HIGH (ZMQ_POLLIN, pollitems[1].revents);\n\n    test_context_socket_close (sb);\n\n    close (send_socket);\n    close (recv_socket);\n#else\n    TEST_IGNORE_MESSAGE (\"libzmq without zmq_ppoll, ignoring test\");\n#endif // ZMQ_HAVE_PPOLL\n}\n\nint main ()\n{\n    UNITY_BEGIN ();\n    RUN_TEST (test_ppoll_fd);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/test_zmq_ppoll_signals.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n// author: E. G. Patrick Bos, Netherlands eScience Center, 2021\n\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <string.h> // memset\n// types.h and wait.h for waitpid:\n#include <sys/types.h>\n#include <sys/wait.h>\n\nstatic bool sigterm_received = false;\n\nvoid handle_sigterm (int /*signum*/)\n{\n    sigterm_received = true;\n}\n\nvoid recv_string_expect_success_or_eagain (void *socket_,\n                                           const char *str_,\n                                           int flags_)\n{\n    const size_t len = str_ ? strlen (str_) : 0;\n    char buffer[255];\n    TEST_ASSERT_LESS_OR_EQUAL_MESSAGE (sizeof (buffer), len,\n                                       \"recv_string_expect_success cannot be \"\n                                       \"used for strings longer than 255 \"\n                                       \"characters\");\n\n    const int rc = zmq_recv (socket_, buffer, sizeof (buffer), flags_);\n    if (rc < 0) {\n        if (errno == EAGAIN) {\n            printf (\"got EAGAIN\\n\");\n            return;\n        } else {\n            TEST_ASSERT_SUCCESS_ERRNO (rc);\n        }\n    } else {\n        TEST_ASSERT_EQUAL_INT ((int) len, rc);\n        if (str_)\n            TEST_ASSERT_EQUAL_STRING_LEN (str_, buffer, len);\n    }\n}\n\nvoid test_ppoll_signals ()\n{\n#ifdef ZMQ_HAVE_PPOLL\n    size_t len = MAX_SOCKET_STRING;\n    char my_endpoint[MAX_SOCKET_STRING];\n    pid_t child_pid;\n\n    /* Get a random TCP port first */\n    setup_test_context ();\n    void *sb = test_context_socket (ZMQ_REP);\n    bind_loopback (sb, 0, my_endpoint, len);\n    test_context_socket_close (sb);\n    teardown_test_context ();\n\n    do {\n        child_pid = fork ();\n    } while (child_pid == -1); // retry if fork fails\n\n    if (child_pid > 0) { // parent\n        setup_test_context ();\n        void *socket = test_context_socket (ZMQ_REQ);\n        // to make sure we don't hang when the child has already exited at the end, we set a receive timeout of five seconds\n        int recv_timeout = 5000;\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n          socket, ZMQ_RCVTIMEO, &recv_timeout, sizeof (recv_timeout)));\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (socket, my_endpoint));\n        // bind is on the master process to avoid zombie children to hold on to binds\n\n        // first send a test message to check whether the signal mask is setup in the child process\n        send_string_expect_success (socket, \"breaker breaker\", 0);\n        recv_string_expect_success (socket, \"one-niner\", 0);\n\n        // then send the signal\n        kill (child_pid, SIGTERM);\n\n        // for good measure, and to make sure everything went as expected, close off with another handshake, which will trigger the second poll call on the other side\n        send_string_expect_success (socket, \"breaker breaker\", 0);\n        // in case the 1 second sleep was not enough on the child side, we are also fine with an EAGAIN here\n        recv_string_expect_success_or_eagain (socket, \"one-niner\", 0);\n\n        // finish\n        test_context_socket_close (socket);\n        teardown_test_context ();\n\n        // wait for child\n        int status = 0;\n        pid_t pid;\n        do {\n            pid = waitpid (child_pid, &status, 0);\n        } while (-1 == pid\n                 && EINTR == errno); // retry on interrupted system call\n\n        if (0 != status) {\n            if (WIFEXITED (status)) {\n                printf (\"exited, status=%d\\n\", WEXITSTATUS (status));\n            } else if (WIFSIGNALED (status)) {\n                printf (\"killed by signal %d\\n\", WTERMSIG (status));\n            } else if (WIFSTOPPED (status)) {\n                printf (\"stopped by signal %d\\n\", WSTOPSIG (status));\n            } else if (WIFCONTINUED (status)) {\n                printf (\"continued\\n\");\n            }\n        }\n\n        if (-1 == pid) {\n            printf (\"waitpid returned -1, with errno %s\\n\", strerror (errno));\n        }\n    } else { // child\n        setup_test_context ();\n        // set up signal mask and install handler for SIGTERM\n        sigset_t sigmask, sigmask_without_sigterm;\n        sigemptyset (&sigmask);\n        sigaddset (&sigmask, SIGTERM);\n        sigprocmask (SIG_BLOCK, &sigmask, &sigmask_without_sigterm);\n        struct sigaction sa;\n        memset (&sa, '\\0', sizeof (sa));\n        sa.sa_handler = handle_sigterm;\n        TEST_ASSERT_SUCCESS_ERRNO (sigaction (SIGTERM, &sa, NULL));\n\n        void *socket = test_context_socket (ZMQ_REP);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (socket, my_endpoint));\n\n        zmq_pollitem_t pollitems[] = {\n          {socket, 0, ZMQ_POLLIN, 0},\n        };\n\n        // first receive test message and send back handshake\n        recv_string_expect_success (socket, \"breaker breaker\", 0);\n        send_string_expect_success (socket, \"one-niner\", 0);\n\n        // now start ppolling, which should exit with EINTR because of the SIGTERM\n        TEST_ASSERT_FAILURE_ERRNO (\n          EINTR, zmq_ppoll (pollitems, 1, -1, &sigmask_without_sigterm));\n        TEST_ASSERT_TRUE (sigterm_received);\n\n        // poll again for the final handshake\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_ppoll (pollitems, 1, -1, &sigmask_without_sigterm));\n        TEST_ASSERT_BITS_HIGH (ZMQ_POLLIN, pollitems[0].revents);\n        // receive and send back handshake\n        recv_string_expect_success (socket, \"breaker breaker\", 0);\n        send_string_expect_success (socket, \"one-niner\", 0);\n\n        // finish\n        // wait before closing socket, so that parent has time to receive\n        sleep (1);\n        test_context_socket_close (socket);\n        teardown_test_context ();\n        _Exit (0);\n    }\n#else\n    TEST_IGNORE_MESSAGE (\"libzmq without zmq_ppoll, ignoring test\");\n#endif // ZMQ_HAVE_PPOLL\n}\n\n// We note that using zmq_poll instead of zmq_ppoll in the test above, while\n// also not using the sigmask, will fail most of the time, because it is\n// impossible to predict during which call the signal will be handled. Of\n// course, every call could be surrounded with an EINTR check and a subsequent\n// check of sigterm_received's value, but even then a race condition can occur,\n// see the explanation given here: https://250bpm.com/blog:12/\n\nint main ()\n{\n    UNITY_BEGIN ();\n    RUN_TEST (test_ppoll_signals);\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "tests/testutil.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n#include \"testutil.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdarg.h>\n#include <string.h>\n\n#if defined _WIN32\n#include \"../src/windows.hpp\"\n#if defined ZMQ_HAVE_WINDOWS\n#if defined ZMQ_HAVE_IPC\n#include <direct.h>\n#include <afunix.h>\n#endif\n#include <crtdbg.h>\n#pragma warning(disable : 4996)\n// iphlpapi is needed for if_nametoindex (not on Windows XP)\n#if _WIN32_WINNT > _WIN32_WINNT_WINXP\n#pragma comment(lib, \"iphlpapi\")\n#endif\n#endif\n#else\n#include <pthread.h>\n#include <unistd.h>\n#include <signal.h>\n#include <stdlib.h>\n#include <grp.h>\n#include <sys/wait.h>\n#include <sys/socket.h>\n#include <sys/types.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <net/if.h>\n#include <netdb.h>\n#include <sys/un.h>\n#include <dirent.h>\n#if defined(ZMQ_HAVE_AIX)\n#include <sys/types.h>\n#include <sys/socketvar.h>\n#endif\n#endif\n\n#ifndef PATH_MAX\n#define PATH_MAX 1024\n#endif\n\nconst char *SEQ_END = (const char *) 1;\n\nconst char bounce_content[] = \"12345678ABCDEFGH12345678abcdefgh\";\n\nstatic void send_bounce_msg (void *socket_)\n{\n    send_string_expect_success (socket_, bounce_content, ZMQ_SNDMORE);\n    send_string_expect_success (socket_, bounce_content, 0);\n}\n\nstatic void recv_bounce_msg (void *socket_)\n{\n    recv_string_expect_success (socket_, bounce_content, 0);\n    int rcvmore;\n    size_t sz = sizeof (rcvmore);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket_, ZMQ_RCVMORE, &rcvmore, &sz));\n    TEST_ASSERT_TRUE (rcvmore);\n    recv_string_expect_success (socket_, bounce_content, 0);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket_, ZMQ_RCVMORE, &rcvmore, &sz));\n    TEST_ASSERT_FALSE (rcvmore);\n}\n\nvoid bounce (void *server_, void *client_)\n{\n    //  Send message from client to server\n    send_bounce_msg (client_);\n\n    //  Receive message at server side and\n    //  check that message is still the same\n    recv_bounce_msg (server_);\n\n    //  Send two parts back to client\n    send_bounce_msg (server_);\n\n    //  Receive the two parts at the client side\n    recv_bounce_msg (client_);\n}\n\nstatic void send_bounce_msg_may_fail (void *socket_)\n{\n    int timeout = 250;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket_, ZMQ_SNDTIMEO, &timeout, sizeof (int)));\n    int rc = zmq_send (socket_, bounce_content, 32, ZMQ_SNDMORE);\n    TEST_ASSERT_TRUE ((rc == 32) || ((rc == -1) && (errno == EAGAIN)));\n    rc = zmq_send (socket_, bounce_content, 32, 0);\n    TEST_ASSERT_TRUE ((rc == 32) || ((rc == -1) && (errno == EAGAIN)));\n}\n\nstatic void recv_bounce_msg_fail (void *socket_)\n{\n    int timeout = 250;\n    char buffer[32];\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket_, ZMQ_RCVTIMEO, &timeout, sizeof (int)));\n    TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (socket_, buffer, 32, 0));\n}\n\nvoid expect_bounce_fail (void *server_, void *client_)\n{\n    //  Send message from client to server\n    send_bounce_msg_may_fail (client_);\n\n    //  Receive message at server side (should not succeed)\n    recv_bounce_msg_fail (server_);\n\n    //  Send message from server to client to test other direction\n    //  If connection failed, send may block, without a timeout\n    send_bounce_msg_may_fail (server_);\n\n    //  Receive message at client side (should not succeed)\n    recv_bounce_msg_fail (client_);\n}\n\nchar *s_recv (void *socket_)\n{\n    char buffer[256];\n    int size = zmq_recv (socket_, buffer, 255, 0);\n    if (size == -1)\n        return NULL;\n    if (size > 255)\n        size = 255;\n    buffer[size] = 0;\n    return strdup (buffer);\n}\n\nvoid s_send_seq (void *socket_, ...)\n{\n    va_list ap;\n    va_start (ap, socket_);\n    const char *data = va_arg (ap, const char *);\n    while (true) {\n        const char *prev = data;\n        data = va_arg (ap, const char *);\n        bool end = data == SEQ_END;\n\n        if (!prev) {\n            TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_send (socket_, 0, 0, end ? 0 : ZMQ_SNDMORE));\n        } else {\n            TEST_ASSERT_SUCCESS_ERRNO (zmq_send (\n              socket_, prev, strlen (prev) + 1, end ? 0 : ZMQ_SNDMORE));\n        }\n        if (end)\n            break;\n    }\n    va_end (ap);\n}\n\nvoid s_recv_seq (void *socket_, ...)\n{\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n\n    int more;\n    size_t more_size = sizeof (more);\n\n    va_list ap;\n    va_start (ap, socket_);\n    const char *data = va_arg (ap, const char *);\n\n    while (true) {\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, socket_, 0));\n\n        if (!data)\n            TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&msg));\n        else\n            TEST_ASSERT_EQUAL_STRING (data, (const char *) zmq_msg_data (&msg));\n\n        data = va_arg (ap, const char *);\n        bool end = data == SEQ_END;\n\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_getsockopt (socket_, ZMQ_RCVMORE, &more, &more_size));\n\n        TEST_ASSERT_TRUE (!more == end);\n        if (end)\n            break;\n    }\n    va_end (ap);\n\n    zmq_msg_close (&msg);\n}\n\nvoid close_zero_linger (void *socket_)\n{\n    int linger = 0;\n    int rc = zmq_setsockopt (socket_, ZMQ_LINGER, &linger, sizeof (linger));\n    TEST_ASSERT_TRUE (rc == 0 || errno == ETERM);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket_));\n}\n\nvoid setup_test_environment (int timeout_seconds_)\n{\n#if defined _WIN32\n#if defined _MSC_VER\n    _set_abort_behavior (0, _WRITE_ABORT_MSG);\n    _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_FILE);\n    _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR);\n#endif\n#else\n#if defined ZMQ_HAVE_CYGWIN\n    // abort test after 121 seconds\n    alarm (121);\n#else\n#if !defined ZMQ_DISABLE_TEST_TIMEOUT\n    // abort test after timeout_seconds_ seconds\n    alarm (timeout_seconds_);\n#endif\n#endif\n#endif\n#if defined __MVS__\n    // z/OS UNIX System Services: Ignore SIGPIPE during test runs, as a\n    // workaround for no SO_NOGSIGPIPE socket option.\n    signal (SIGPIPE, SIG_IGN);\n#endif\n}\n\nvoid msleep (int milliseconds_)\n{\n#ifdef ZMQ_HAVE_WINDOWS\n    Sleep (milliseconds_);\n#else\n    usleep (static_cast<useconds_t> (milliseconds_) * 1000);\n#endif\n}\n\nint is_ipv6_available ()\n{\n#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)\n    return 0;\n#else\n    int rc, ipv6 = 1;\n    struct sockaddr_in6 test_addr;\n\n    memset (&test_addr, 0, sizeof (test_addr));\n    test_addr.sin6_family = AF_INET6;\n    inet_pton (AF_INET6, \"::1\", &(test_addr.sin6_addr));\n\n    fd_t fd = socket (AF_INET6, SOCK_STREAM, IPPROTO_IP);\n    if (fd == retired_fd)\n        ipv6 = 0;\n    else {\n#ifdef ZMQ_HAVE_WINDOWS\n        setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &ipv6,\n                    sizeof (int));\n        rc = setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &ipv6,\n                         sizeof (int));\n        if (rc == SOCKET_ERROR)\n            ipv6 = 0;\n        else {\n            rc = bind (fd, (struct sockaddr *) &test_addr, sizeof (test_addr));\n            if (rc == SOCKET_ERROR)\n                ipv6 = 0;\n        }\n#else\n        setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &ipv6, sizeof (int));\n        rc = setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6, sizeof (int));\n        if (rc != 0)\n            ipv6 = 0;\n        else {\n            rc = bind (fd, reinterpret_cast<struct sockaddr *> (&test_addr),\n                       sizeof (test_addr));\n            if (rc != 0)\n                ipv6 = 0;\n        }\n#endif\n        close (fd);\n    }\n\n    return ipv6;\n#endif // _WIN32_WINNT < 0x0600\n}\n\nint is_tipc_available ()\n{\n#ifndef ZMQ_HAVE_TIPC\n    return 0;\n#else\n    int tipc = 0;\n\n    void *ctx = zmq_init (1);\n    TEST_ASSERT_NOT_NULL (ctx);\n    void *rep = zmq_socket (ctx, ZMQ_REP);\n    TEST_ASSERT_NOT_NULL (rep);\n    tipc = zmq_bind (rep, \"tipc://{5560,0,0}\");\n\n    zmq_close (rep);\n    zmq_ctx_term (ctx);\n\n    return tipc == 0;\n#endif // ZMQ_HAVE_TIPC\n}\n\nint test_inet_pton (int af_, const char *src_, void *dst_)\n{\n#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)\n    if (af_ == AF_INET) {\n        struct in_addr *ip4addr = (struct in_addr *) dst_;\n\n        ip4addr->s_addr = inet_addr (src_);\n\n        //  INADDR_NONE is -1 which is also a valid representation for IP\n        //  255.255.255.255\n        if (ip4addr->s_addr == INADDR_NONE\n            && strcmp (src_, \"255.255.255.255\") != 0) {\n            return 0;\n        }\n\n        //  Success\n        return 1;\n    } else {\n        //  Not supported.\n        return 0;\n    }\n#else\n    return inet_pton (af_, src_, dst_);\n#endif\n}\n\nsockaddr_in bind_bsd_socket (int socket_)\n{\n    struct sockaddr_in saddr;\n    memset (&saddr, 0, sizeof (saddr));\n    saddr.sin_family = AF_INET;\n    saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);\n#if !defined(_WIN32_WINNT) || (_WIN32_WINNT >= 0x0600)\n    saddr.sin_port = 0;\n#else\n    saddr.sin_port = htons (PORT_6);\n#endif\n\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (\n      bind (socket_, (struct sockaddr *) &saddr, sizeof (saddr)));\n\n#if !defined(_WIN32_WINNT) || (_WIN32_WINNT >= 0x0600)\n    socklen_t saddr_len = sizeof (saddr);\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (\n      getsockname (socket_, (struct sockaddr *) &saddr, &saddr_len));\n#endif\n\n    return saddr;\n}\n\nfd_t connect_socket (const char *endpoint_, const int af_, const int protocol_)\n{\n    struct sockaddr_storage addr;\n    //  OSX is very opinionated and wants the size to match the AF family type\n    socklen_t addr_len;\n    const fd_t s_pre = socket (af_, SOCK_STREAM,\n                               protocol_ == IPPROTO_UDP   ? IPPROTO_UDP\n                               : protocol_ == IPPROTO_TCP ? IPPROTO_TCP\n                                                          : 0);\n#ifdef ZMQ_HAVE_WINDOWS\n    TEST_ASSERT_NOT_EQUAL (INVALID_SOCKET, s_pre);\n#else\n    TEST_ASSERT_NOT_EQUAL (-1, s_pre);\n#endif\n\n    if (af_ == AF_INET || af_ == AF_INET6) {\n        const char *port = strrchr (endpoint_, ':') + 1;\n        char address[MAX_SOCKET_STRING];\n        // getaddrinfo does not like [x:y::z]\n        if (*strchr (endpoint_, '/') + 2 == '[') {\n            strcpy (address, strchr (endpoint_, '[') + 1);\n            address[strlen (address) - strlen (port) - 2] = '\\0';\n        } else {\n            strcpy (address, strchr (endpoint_, '/') + 2);\n            address[strlen (address) - strlen (port) - 1] = '\\0';\n        }\n\n        struct addrinfo *in, hint;\n        memset (&hint, 0, sizeof (struct addrinfo));\n        hint.ai_flags = AI_NUMERICSERV;\n        hint.ai_family = af_;\n        hint.ai_socktype = protocol_ == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;\n        hint.ai_protocol = protocol_ == IPPROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;\n\n        TEST_ASSERT_SUCCESS_RAW_ZERO_ERRNO (\n          getaddrinfo (address, port, &hint, &in));\n        TEST_ASSERT_NOT_NULL (in);\n        memcpy (&addr, in->ai_addr, in->ai_addrlen);\n        addr_len = (socklen_t) in->ai_addrlen;\n        freeaddrinfo (in);\n    } else {\n#if defined(ZMQ_HAVE_IPC)\n        //  Cannot cast addr as gcc 4.4 will fail with strict aliasing errors\n        (*(struct sockaddr_un *) &addr).sun_family = AF_UNIX;\n        strcpy ((*(struct sockaddr_un *) &addr).sun_path, endpoint_);\n        addr_len = sizeof (struct sockaddr_un);\n#else\n        return retired_fd;\n#endif\n    }\n\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (\n      connect (s_pre, (struct sockaddr *) &addr, addr_len));\n\n    return s_pre;\n}\n\nfd_t bind_socket_resolve_port (const char *address_,\n                               const char *port_,\n                               char *my_endpoint_,\n                               const int af_,\n                               const int protocol_)\n{\n    struct sockaddr_storage addr;\n    //  OSX is very opinionated and wants the size to match the AF family type\n    socklen_t addr_len;\n    const fd_t s_pre = socket (af_, SOCK_STREAM,\n                               protocol_ == IPPROTO_UDP   ? IPPROTO_UDP\n                               : protocol_ == IPPROTO_TCP ? IPPROTO_TCP\n                                                          : 0);\n#ifdef ZMQ_HAVE_WINDOWS\n    TEST_ASSERT_NOT_EQUAL (INVALID_SOCKET, s_pre);\n#else\n    TEST_ASSERT_NOT_EQUAL (-1, s_pre);\n#endif\n\n    if (af_ == AF_INET || af_ == AF_INET6) {\n#ifdef ZMQ_HAVE_WINDOWS\n        const char flag = '\\1';\n#elif defined ZMQ_HAVE_VXWORKS\n        char flag = '\\1';\n#else\n        int flag = 1;\n#endif\n        struct addrinfo *in, hint;\n        memset (&hint, 0, sizeof (struct addrinfo));\n        hint.ai_flags = AI_NUMERICSERV;\n        hint.ai_family = af_;\n        hint.ai_socktype = protocol_ == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;\n        hint.ai_protocol = protocol_ == IPPROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;\n\n        TEST_ASSERT_SUCCESS_RAW_ERRNO (\n          setsockopt (s_pre, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)));\n        TEST_ASSERT_SUCCESS_RAW_ZERO_ERRNO (\n          getaddrinfo (address_, port_, &hint, &in));\n        TEST_ASSERT_NOT_NULL (in);\n        memcpy (&addr, in->ai_addr, in->ai_addrlen);\n        addr_len = (socklen_t) in->ai_addrlen;\n        freeaddrinfo (in);\n    } else {\n#if defined(ZMQ_HAVE_IPC)\n        //  Cannot cast addr as gcc 4.4 will fail with strict aliasing errors\n        (*(struct sockaddr_un *) &addr).sun_family = AF_UNIX;\n        addr_len = sizeof (struct sockaddr_un);\n#if defined ZMQ_HAVE_WINDOWS\n        char buffer[MAX_PATH] = \"\";\n\n        TEST_ASSERT_SUCCESS_RAW_ERRNO (tmpnam_s (buffer));\n        TEST_ASSERT_SUCCESS_RAW_ERRNO (_mkdir (buffer));\n        strcat (buffer, \"/ipc\");\n#else\n        char buffer[PATH_MAX] = \"\";\n        strcpy (buffer, \"tmpXXXXXX\");\n#ifdef HAVE_MKDTEMP\n        TEST_ASSERT_TRUE (mkdtemp (buffer));\n        strcat (buffer, \"/socket\");\n#else\n        int fd = mkstemp (buffer);\n        TEST_ASSERT_TRUE (fd != -1);\n        close (fd);\n#endif\n#endif\n        strcpy ((*(struct sockaddr_un *) &addr).sun_path, buffer);\n        memcpy (my_endpoint_, \"ipc://\", 7);\n        strcat (my_endpoint_, buffer);\n\n        // TODO check return value of unlink\n        unlink (buffer);\n#else\n        return retired_fd;\n#endif\n    }\n\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (\n      bind (s_pre, (struct sockaddr *) &addr, addr_len));\n    TEST_ASSERT_SUCCESS_RAW_ERRNO (listen (s_pre, SOMAXCONN));\n\n    if (af_ == AF_INET || af_ == AF_INET6) {\n        addr_len = sizeof (struct sockaddr_storage);\n        TEST_ASSERT_SUCCESS_RAW_ERRNO (\n          getsockname (s_pre, (struct sockaddr *) &addr, &addr_len));\n        snprintf (\n          my_endpoint_, 6 + strlen (address_) + 7 * sizeof (char), \"%s://%s:%u\",\n          protocol_ == IPPROTO_TCP   ? \"tcp\"\n          : protocol_ == IPPROTO_UDP ? \"udp\"\n          : protocol_ == IPPROTO_WSS ? \"wss\"\n                                     : \"ws\",\n          address_,\n          af_ == AF_INET ? ntohs ((*(struct sockaddr_in *) &addr).sin_port)\n                         : ntohs ((*(struct sockaddr_in6 *) &addr).sin6_port));\n    }\n\n    return s_pre;\n}\n\nbool streq (const char *lhs_, const char *rhs_)\n{\n    return strcmp (lhs_, rhs_) == 0;\n}\n\nbool strneq (const char *lhs_, const char *rhs_)\n{\n    return strcmp (lhs_, rhs_) != 0;\n}\n\n#if defined _WIN32\nint fuzzer_corpus_encode (const char *dirname,\n                          uint8_t ***data,\n                          size_t **len,\n                          size_t *num_cases)\n{\n    (void) dirname;\n    (void) data;\n    (void) len;\n    (void) num_cases;\n\n    return -1;\n}\n\n#else\n\nint fuzzer_corpus_encode (const char *dirname,\n                          uint8_t ***data,\n                          size_t **len,\n                          size_t *num_cases)\n{\n    TEST_ASSERT_NOT_NULL (dirname);\n    TEST_ASSERT_NOT_NULL (data);\n    TEST_ASSERT_NOT_NULL (len);\n\n    struct dirent *ent;\n    DIR *dir = opendir (dirname);\n    if (!dir)\n        return -1;\n\n    *len = NULL;\n    *data = NULL;\n    *num_cases = 0;\n\n    while ((ent = readdir (dir)) != NULL) {\n        if (!strcmp (ent->d_name, \".\") || !strcmp (ent->d_name, \"..\"))\n            continue;\n\n        char *filename =\n          (char *) malloc (strlen (dirname) + strlen (ent->d_name) + 2);\n        TEST_ASSERT_NOT_NULL (filename);\n        strcpy (filename, dirname);\n        strcat (filename, \"/\");\n        strcat (filename, ent->d_name);\n        FILE *f = fopen (filename, \"r\");\n        free (filename);\n        if (!f)\n            continue;\n\n        fseek (f, 0, SEEK_END);\n        size_t file_len = ftell (f);\n        fseek (f, 0, SEEK_SET);\n        if (file_len == 0) {\n            fclose (f);\n            continue;\n        }\n\n        *len = (size_t *) realloc (*len, (*num_cases + 1) * sizeof (size_t));\n        TEST_ASSERT_NOT_NULL (*len);\n        *(*len + *num_cases) = file_len;\n        *data =\n          (uint8_t **) realloc (*data, (*num_cases + 1) * sizeof (uint8_t *));\n        TEST_ASSERT_NOT_NULL (*data);\n        *(*data + *num_cases) =\n          (uint8_t *) malloc (file_len * sizeof (uint8_t));\n        TEST_ASSERT_NOT_NULL (*(*data + *num_cases));\n        size_t read_bytes = 0;\n        read_bytes = fread (*(*data + *num_cases), 1, file_len, f);\n        TEST_ASSERT_EQUAL (file_len, read_bytes);\n        (*num_cases)++;\n\n        fclose (f);\n    }\n\n    closedir (dir);\n\n    return 0;\n}\n#endif\n"
  },
  {
    "path": "tests/testutil.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifdef _AIX\n#define MSG_DONTWAIT MSG_NONBLOCK\n#endif\n\n#ifndef __TESTUTIL_HPP_INCLUDED__\n#define __TESTUTIL_HPP_INCLUDED__\n\n#if defined ZMQ_CUSTOM_PLATFORM_HPP\n#include \"platform.hpp\"\n#else\n#include \"../src/platform.hpp\"\n#endif\n#include \"../include/zmq.h\"\n#include \"../src/stdint.hpp\"\n\n//  For AF_INET and IPPROTO_TCP\n#if defined _WIN32\n#include \"../src/windows.hpp\"\n#if defined(__MINGW32__)\n#include <unistd.h>\n#endif\n#else\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <unistd.h>\n#include <stdlib.h>\n#endif\n\n//  This defines the settle time used in tests; raise this if we\n//  get test failures on slower systems due to binds/connects not\n//  settled. Tested to work reliably at 1 msec on a fast PC.\n#define SETTLE_TIME 300 //  In msec\n//  Commonly used buffer size for ZMQ_LAST_ENDPOINT\n//  this used to be sizeof (\"tcp://[::ffff:127.127.127.127]:65536\"), but this\n//  may be too short for ipc wildcard binds, e.g.\n#define MAX_SOCKET_STRING 256\n\n//  We need to test codepaths with non-random bind ports. List them here to\n//  keep them unique, to allow parallel test runs.\n#define ENDPOINT_0 \"tcp://127.0.0.1:5555\"\n#define ENDPOINT_1 \"tcp://127.0.0.1:5556\"\n#define ENDPOINT_2 \"tcp://127.0.0.1:5557\"\n#define ENDPOINT_3 \"tcp://127.0.0.1:5558\"\n#define ENDPOINT_4 \"udp://127.0.0.1:5559\"\n#define ENDPOINT_5 \"udp://127.0.0.1:5560\"\n#define PORT_6 5561\n\n//  For tests that mock ZMTP\nconst uint8_t zmtp_greeting_null[64] = {\n  0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0x7f, 3, 0, 'N', 'U', 'L', 'L',\n  0,    0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0,   0,   0,   0,\n  0,    0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0,   0,   0,   0};\n\nconst uint8_t zmtp_greeting_curve[64] = {\n  0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0x7f, 3, 0, 'C', 'U', 'R', 'V',\n  'E',  0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0,   0,   0,   0,\n  0,    0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0,   0,   0,   0};\nconst uint8_t zmtp_ready_dealer[43] = {\n  4,   41,  5,   'R', 'E', 'A', 'D', 'Y', 11,  'S', 'o', 'c', 'k', 'e', 't',\n  '-', 'T', 'y', 'p', 'e', 0,   0,   0,   6,   'D', 'E', 'A', 'L', 'E', 'R',\n  8,   'I', 'd', 'e', 'n', 't', 'i', 't', 'y', 0,   0,   0,   0};\nconst uint8_t zmtp_ready_xpub[28] = {\n  4,   26,  5,   'R', 'E', 'A', 'D', 'Y', 11, 'S', 'o', 'c', 'k', 'e',\n  't', '-', 'T', 'y', 'p', 'e', 0,   0,   0,  4,   'X', 'P', 'U', 'B'};\nconst uint8_t zmtp_ready_sub[27] = {\n  4,   25,  5,   'R', 'E', 'A', 'D', 'Y', 11, 'S', 'o', 'c', 'k', 'e',\n  't', '-', 'T', 'y', 'p', 'e', 0,   0,   0,  3,   'S', 'U', 'B'};\n\n#undef NDEBUG\n\n#ifndef MSG_NOSIGNAL\n#define MSG_NOSIGNAL 0\n#endif\n\n// duplicated from fd.hpp\n#ifdef ZMQ_HAVE_WINDOWS\n#ifndef NOMINMAX\n#define NOMINMAX // Macros min(a,b) and max(a,b)\n#endif\n\n#include <winsock2.h>\n#include <ws2tcpip.h>\n#include <stdexcept>\n#define close closesocket\ntypedef int socket_size_t;\ninline const char *as_setsockopt_opt_t (const void *opt)\n{\n    return static_cast<const char *> (opt);\n}\n#else\ntypedef size_t socket_size_t;\ninline const void *as_setsockopt_opt_t (const void *opt_)\n{\n    return opt_;\n}\n#endif\n\n// duplicated from fd.hpp\ntypedef zmq_fd_t fd_t;\n#ifdef ZMQ_HAVE_WINDOWS\n#if defined _MSC_VER && _MSC_VER <= 1400\nenum\n{\n    retired_fd = (zmq_fd_t) (~0)\n};\n#else\nenum\n#if _MSC_VER >= 1800\n  : zmq_fd_t\n#endif\n{\n    retired_fd = INVALID_SOCKET\n};\n#endif\n#else\nenum\n{\n    retired_fd = -1\n};\n#endif\n\n//  In MSVC prior to v14, snprintf is not available\n//  The closest implementation is the _snprintf_s function\n#if defined _MSC_VER && _MSC_VER < 1900\n#define snprintf(buffer_, count_, format_, ...)                                \\\n    _snprintf_s (buffer_, count_, _TRUNCATE, format_, __VA_ARGS__)\n#endif\n\n#define LIBZMQ_UNUSED(object) (void) object\n\n//  Bounce a message from client to server and back\n//  For REQ/REP or DEALER/DEALER pairs only\nvoid bounce (void *server_, void *client_);\n\n//  Same as bounce, but expect messages to never arrive\n//  for security or subscriber reasons.\nvoid expect_bounce_fail (void *server_, void *client_);\n\n//  Receive 0MQ string from socket and convert into C string\n//  Caller must free returned string. Returns NULL if the context\n//  is being terminated.\nchar *s_recv (void *socket_);\n\nbool streq (const char *lhs, const char *rhs);\nbool strneq (const char *lhs, const char *rhs);\n\nextern const char *SEQ_END;\n\n//  Sends a message composed of frames that are C strings or null frames.\n//  The list must be terminated by SEQ_END.\n//  Example: s_send_seq (req, \"ABC\", 0, \"DEF\", SEQ_END);\n\nvoid s_send_seq (void *socket_, ...);\n\n//  Receives message a number of frames long and checks that the frames have\n//  the given data which can be either C strings or 0 for a null frame.\n//  The list must be terminated by SEQ_END.\n//  Example: s_recv_seq (rep, \"ABC\", 0, \"DEF\", SEQ_END);\n\nvoid s_recv_seq (void *socket_, ...);\n\n\n//  Sets a zero linger period on a socket and closes it.\nvoid close_zero_linger (void *socket_);\n\n//  Setups the test environment. Must be called at the beginning of each test\n//  executable. On POSIX systems, it sets an alarm to the specified number of\n//  seconds, after which the test will be killed. Set to 0 to disable this\n//  timeout.\nvoid setup_test_environment (int timeout_seconds_ = 60);\n\n//  Provide portable millisecond sleep\n//  http://www.cplusplus.com/forum/unices/60161/\n//  http://en.cppreference.com/w/cpp/thread/sleep_for\n\nvoid msleep (int milliseconds_);\n\n// check if IPv6 is available (0/false if not, 1/true if it is)\n// only way to reliably check is to actually open a socket and try to bind it\nint is_ipv6_available (void);\n\n// check if tipc is available (0/false if not, 1/true if it is)\n// only way to reliably check is to actually open a socket and try to bind it\n// as it depends on a non-default kernel module to be already loaded\nint is_tipc_available (void);\n\n//  Wrapper around 'inet_pton' for systems that don't support it (e.g. Windows\n//  XP)\nint test_inet_pton (int af_, const char *src_, void *dst_);\n\n//  Binds an ipv4 BSD socket to an ephemeral port, returns the compiled sockaddr\nstruct sockaddr_in bind_bsd_socket (int socket);\n\n//  Some custom definitions in addition to IPPROTO_TCP and IPPROTO_UDP\n#define IPPROTO_WS 10000\n#define IPPROTO_WSS 10001\n\n//  Connects a BSD socket to the ZMQ endpoint. Works with ipv4/ipv6/unix.\nfd_t connect_socket (const char *endpoint_,\n                     const int af_ = AF_INET,\n                     const int protocol_ = IPPROTO_TCP);\n\n//  Binds a BSD socket to an ephemeral port, returns the file descriptor.\n//  The resulting ZMQ endpoint will be stored in my_endpoint, including the protocol\n//  prefix, so ensure it is writable and of appropriate size.\n//  Works with ipv4/ipv6/unix. With unix sockets address_/port_ can be empty and\n//  my_endpoint_ will contain a random path.\nfd_t bind_socket_resolve_port (const char *address_,\n                               const char *port_,\n                               char *my_endpoint_,\n                               const int af_ = AF_INET,\n                               const int protocol_ = IPPROTO_TCP);\n\nint fuzzer_corpus_encode (const char *filename,\n                          uint8_t ***data,\n                          size_t **len,\n                          size_t *num_cases);\n\n#endif\n"
  },
  {
    "path": "tests/testutil_monitoring.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n#include \"testutil_monitoring.hpp\"\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\nstatic int\nreceive_monitor_address (void *monitor_, char **address_, bool expect_more_)\n{\n    zmq_msg_t msg;\n\n    zmq_msg_init (&msg);\n    if (zmq_msg_recv (&msg, monitor_, 0) == -1)\n        return -1; //  Interrupted, presumably\n    TEST_ASSERT_EQUAL (expect_more_, zmq_msg_more (&msg));\n\n    if (address_) {\n        const uint8_t *const data =\n          static_cast<const uint8_t *> (zmq_msg_data (&msg));\n        const size_t size = zmq_msg_size (&msg);\n        *address_ = static_cast<char *> (malloc (size + 1));\n        memcpy (*address_, data, size);\n        (*address_)[size] = 0;\n    }\n    zmq_msg_close (&msg);\n\n    return 0;\n}\n\n//  Read one event off the monitor socket; return value and address\n//  by reference, if not null, and event number by value. Returns -1\n//  in case of error.\nstatic int get_monitor_event_internal (void *monitor_,\n                                       int *value_,\n                                       char **address_,\n                                       int recv_flag_)\n{\n    //  First frame in message contains event number and value\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    if (zmq_msg_recv (&msg, monitor_, recv_flag_) == -1) {\n        TEST_ASSERT_FAILURE_ERRNO (EAGAIN, -1);\n        return -1; //  timed out or no message available\n    }\n    TEST_ASSERT_TRUE (zmq_msg_more (&msg));\n\n    uint8_t *data = static_cast<uint8_t *> (zmq_msg_data (&msg));\n    uint16_t event = *reinterpret_cast<uint16_t *> (data);\n    if (value_)\n        memcpy (value_, data + 2, sizeof (uint32_t));\n\n    //  Second frame in message contains event address\n    TEST_ASSERT_SUCCESS_ERRNO (\n      receive_monitor_address (monitor_, address_, false));\n\n    return event;\n}\n\nint get_monitor_event_with_timeout (void *monitor_,\n                                    int *value_,\n                                    char **address_,\n                                    int timeout_)\n{\n    int res;\n    if (timeout_ == -1) {\n        // process infinite timeout in small steps to allow the user\n        // to see some information on the console\n\n        int timeout_step = 250;\n        int wait_time = 0;\n        zmq_setsockopt (monitor_, ZMQ_RCVTIMEO, &timeout_step,\n                        sizeof (timeout_step));\n        while (\n          (res = get_monitor_event_internal (monitor_, value_, address_, 0))\n          == -1) {\n            wait_time += timeout_step;\n            fprintf (stderr, \"Still waiting for monitor event after %i ms\\n\",\n                     wait_time);\n        }\n    } else {\n        zmq_setsockopt (monitor_, ZMQ_RCVTIMEO, &timeout_, sizeof (timeout_));\n        res = get_monitor_event_internal (monitor_, value_, address_, 0);\n    }\n    int timeout_infinite = -1;\n    zmq_setsockopt (monitor_, ZMQ_RCVTIMEO, &timeout_infinite,\n                    sizeof (timeout_infinite));\n    return res;\n}\n\nint get_monitor_event (void *monitor_, int *value_, char **address_)\n{\n    return get_monitor_event_with_timeout (monitor_, value_, address_, -1);\n}\n\nvoid expect_monitor_event (void *monitor_, int expected_event_)\n{\n    TEST_ASSERT_EQUAL_HEX (expected_event_,\n                           get_monitor_event (monitor_, NULL, NULL));\n}\n\nstatic void print_unexpected_event (char *buf_,\n                                    size_t buf_size_,\n                                    int event_,\n                                    int err_,\n                                    int expected_event_,\n                                    int expected_err_)\n{\n    snprintf (buf_, buf_size_,\n              \"Unexpected event: 0x%x, value = %i/0x%x (expected: 0x%x, value \"\n              \"= %i/0x%x)\\n\",\n              event_, err_, err_, expected_event_, expected_err_,\n              expected_err_);\n}\n\nvoid print_unexpected_event_stderr (int event_,\n                                    int err_,\n                                    int expected_event_,\n                                    int expected_err_)\n{\n    char buf[256];\n    print_unexpected_event (buf, sizeof buf, event_, err_, expected_event_,\n                            expected_err_);\n    fputs (buf, stderr);\n}\n\nint expect_monitor_event_multiple (void *server_mon_,\n                                   int expected_event_,\n                                   int expected_err_,\n                                   bool optional_)\n{\n    int count_of_expected_events = 0;\n    int client_closed_connection = 0;\n    int timeout = 250;\n    int wait_time = 0;\n\n    int event;\n    int err;\n    while ((event =\n              get_monitor_event_with_timeout (server_mon_, &err, NULL, timeout))\n             != -1\n           || !count_of_expected_events) {\n        if (event == -1) {\n            if (optional_)\n                break;\n            wait_time += timeout;\n            fprintf (stderr,\n                     \"Still waiting for first event after %ims (expected event \"\n                     \"%x (value %i/0x%x))\\n\",\n                     wait_time, expected_event_, expected_err_, expected_err_);\n            continue;\n        }\n        // ignore errors with EPIPE/ECONNRESET/ECONNABORTED, which can happen\n        // ECONNRESET can happen on very slow machines, when the engine writes\n        // to the peer and then tries to read the socket before the peer reads\n        // ECONNABORTED happens when a client aborts a connection via RST/timeout\n        if (event == ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL\n            && ((err == EPIPE && expected_err_ != EPIPE) || err == ECONNRESET\n                || err == ECONNABORTED)) {\n            fprintf (stderr,\n                     \"Ignored event (skipping any further events): %x (err = \"\n                     \"%i == %s)\\n\",\n                     event, err, zmq_strerror (err));\n            client_closed_connection = 1;\n            break;\n        }\n        if (event != expected_event_\n            || (-1 != expected_err_ && err != expected_err_)) {\n            char buf[256];\n            print_unexpected_event (buf, sizeof buf, event, err,\n                                    expected_event_, expected_err_);\n            TEST_FAIL_MESSAGE (buf);\n        }\n        ++count_of_expected_events;\n    }\n    TEST_ASSERT_TRUE (optional_ || count_of_expected_events > 0\n                      || client_closed_connection);\n\n    return count_of_expected_events;\n}\n\nstatic int64_t get_monitor_event_internal_v2 (void *monitor_,\n                                              uint64_t **value_,\n                                              char **local_address_,\n                                              char **remote_address_,\n                                              int recv_flag_)\n{\n    //  First frame in message contains event number\n    zmq_msg_t msg;\n    zmq_msg_init (&msg);\n    if (zmq_msg_recv (&msg, monitor_, recv_flag_) == -1) {\n        TEST_ASSERT_FAILURE_ERRNO (EAGAIN, -1);\n        return -1; //  timed out or no message available\n    }\n    TEST_ASSERT_TRUE (zmq_msg_more (&msg));\n    TEST_ASSERT_EQUAL_UINT (sizeof (uint64_t), zmq_msg_size (&msg));\n\n    uint64_t event;\n    memcpy (&event, zmq_msg_data (&msg), sizeof (event));\n    zmq_msg_close (&msg);\n\n    //  Second frame in message contains the number of values\n    zmq_msg_init (&msg);\n    if (zmq_msg_recv (&msg, monitor_, recv_flag_) == -1) {\n        TEST_ASSERT_FAILURE_ERRNO (EAGAIN, -1);\n        return -1; //  timed out or no message available\n    }\n    TEST_ASSERT_TRUE (zmq_msg_more (&msg));\n    TEST_ASSERT_EQUAL_UINT (sizeof (uint64_t), zmq_msg_size (&msg));\n\n    uint64_t value_count;\n    memcpy (&value_count, zmq_msg_data (&msg), sizeof (value_count));\n    zmq_msg_close (&msg);\n\n    if (value_) {\n        *value_ =\n          (uint64_t *) malloc ((size_t) value_count * sizeof (uint64_t));\n        TEST_ASSERT_NOT_NULL (*value_);\n    }\n\n    for (uint64_t i = 0; i < value_count; ++i) {\n        //  Subsequent frames in message contain event values\n        zmq_msg_init (&msg);\n        if (zmq_msg_recv (&msg, monitor_, recv_flag_) == -1) {\n            TEST_ASSERT_FAILURE_ERRNO (EAGAIN, -1);\n            return -1; //  timed out or no message available\n        }\n        TEST_ASSERT_TRUE (zmq_msg_more (&msg));\n        TEST_ASSERT_EQUAL_UINT (sizeof (uint64_t), zmq_msg_size (&msg));\n\n        if (value_ && *value_)\n            memcpy (&(*value_)[i], zmq_msg_data (&msg), sizeof (uint64_t));\n        zmq_msg_close (&msg);\n    }\n\n    //  Second-to-last frame in message contains local address\n    TEST_ASSERT_SUCCESS_ERRNO (\n      receive_monitor_address (monitor_, local_address_, true));\n\n    //  Last frame in message contains remote address\n    TEST_ASSERT_SUCCESS_ERRNO (\n      receive_monitor_address (monitor_, remote_address_, false));\n\n    return event;\n}\n\nstatic int64_t get_monitor_event_with_timeout_v2 (void *monitor_,\n                                                  uint64_t **value_,\n                                                  char **local_address_,\n                                                  char **remote_address_,\n                                                  int timeout_)\n{\n    int64_t res;\n    if (timeout_ == -1) {\n        // process infinite timeout in small steps to allow the user\n        // to see some information on the console\n\n        int timeout_step = 250;\n        int wait_time = 0;\n        zmq_setsockopt (monitor_, ZMQ_RCVTIMEO, &timeout_step,\n                        sizeof (timeout_step));\n        while ((res = get_monitor_event_internal_v2 (\n                  monitor_, value_, local_address_, remote_address_, 0))\n               == -1) {\n            wait_time += timeout_step;\n            fprintf (stderr, \"Still waiting for monitor event after %i ms\\n\",\n                     wait_time);\n        }\n    } else {\n        zmq_setsockopt (monitor_, ZMQ_RCVTIMEO, &timeout_, sizeof (timeout_));\n        res = get_monitor_event_internal_v2 (monitor_, value_, local_address_,\n                                             remote_address_, 0);\n    }\n    int timeout_infinite = -1;\n    zmq_setsockopt (monitor_, ZMQ_RCVTIMEO, &timeout_infinite,\n                    sizeof (timeout_infinite));\n    return res;\n}\n\nint64_t get_monitor_event_v2 (void *monitor_,\n                              uint64_t **value_,\n                              char **local_address_,\n                              char **remote_address_)\n{\n    return get_monitor_event_with_timeout_v2 (monitor_, value_, local_address_,\n                                              remote_address_, -1);\n}\n\nvoid expect_monitor_event_v2 (void *monitor_,\n                              int64_t expected_event_,\n                              const char *expected_local_address_,\n                              const char *expected_remote_address_)\n{\n    char *local_address = NULL;\n    char *remote_address = NULL;\n    int64_t event = get_monitor_event_v2 (\n      monitor_, NULL, expected_local_address_ ? &local_address : NULL,\n      expected_remote_address_ ? &remote_address : NULL);\n    bool failed = false;\n    char buf[256];\n    char *pos = buf;\n    if (event != expected_event_) {\n        pos += snprintf (pos, sizeof buf - (pos - buf),\n                         \"Expected monitor event %llx, but received %llx\\n\",\n                         static_cast<long long> (expected_event_),\n                         static_cast<long long> (event));\n        failed = true;\n    }\n    if (expected_local_address_\n        && 0 != strcmp (local_address, expected_local_address_)) {\n        pos += snprintf (pos, sizeof buf - (pos - buf),\n                         \"Expected local address %s, but received %s\\n\",\n                         expected_local_address_, local_address);\n    }\n    if (expected_remote_address_\n        && 0 != strcmp (remote_address, expected_remote_address_)) {\n        snprintf (pos, sizeof buf - (pos - buf),\n                  \"Expected remote address %s, but received %s\\n\",\n                  expected_remote_address_, remote_address);\n    }\n    free (local_address);\n    free (remote_address);\n    TEST_ASSERT_FALSE_MESSAGE (failed, buf);\n}\n\n\nconst char *get_zmqEventName (uint64_t event)\n{\n    switch (event) {\n        case ZMQ_EVENT_CONNECTED:\n            return \"CONNECTED\";\n        case ZMQ_EVENT_CONNECT_DELAYED:\n            return \"CONNECT_DELAYED\";\n        case ZMQ_EVENT_CONNECT_RETRIED:\n            return \"CONNECT_RETRIED\";\n        case ZMQ_EVENT_LISTENING:\n            return \"LISTENING\";\n        case ZMQ_EVENT_BIND_FAILED:\n            return \"BIND_FAILED\";\n        case ZMQ_EVENT_ACCEPTED:\n            return \"ACCEPTED\";\n        case ZMQ_EVENT_ACCEPT_FAILED:\n            return \"ACCEPT_FAILED\";\n        case ZMQ_EVENT_CLOSED:\n            return \"CLOSED\";\n        case ZMQ_EVENT_CLOSE_FAILED:\n            return \"CLOSE_FAILED\";\n        case ZMQ_EVENT_DISCONNECTED:\n            return \"DISCONNECTED\";\n        case ZMQ_EVENT_MONITOR_STOPPED:\n            return \"MONITOR_STOPPED\";\n        case ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL:\n            return \"HANDSHAKE_FAILED_NO_DETAIL\";\n        case ZMQ_EVENT_HANDSHAKE_SUCCEEDED:\n            return \"HANDSHAKE_SUCCEEDED\";\n        case ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL:\n            return \"HANDSHAKE_FAILED_PROTOCOL\";\n        case ZMQ_EVENT_HANDSHAKE_FAILED_AUTH:\n            return \"HANDSHAKE_FAILED_AUTH\";\n        default:\n            return \"UNKNOWN\";\n    }\n}\n\nvoid print_events (void *socket, int timeout, int limit)\n{\n    // print events received\n    int value;\n    char *event_address;\n    int event =\n      get_monitor_event_with_timeout (socket, &value, &event_address, timeout);\n    int i = 0;\n    ;\n    while ((event != -1) && (++i < limit)) {\n        const char *eventName = get_zmqEventName (event);\n        printf (\"Got event: %s\\n\", eventName);\n        event = get_monitor_event_with_timeout (socket, &value, &event_address,\n                                                timeout);\n    }\n}\n"
  },
  {
    "path": "tests/testutil_monitoring.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __TESTUTIL_MONITORING_HPP_INCLUDED__\n#define __TESTUTIL_MONITORING_HPP_INCLUDED__\n\n#include \"../include/zmq.h\"\n#include \"../src/stdint.hpp\"\n\n#include <stddef.h>\n\n//  General, i.e. non-security specific, monitor utilities\n\nint get_monitor_event_with_timeout (void *monitor_,\n                                    int *value_,\n                                    char **address_,\n                                    int timeout_);\n\n//  Read one event off the monitor socket; return value and address\n//  by reference, if not null, and event number by value. Returns -1\n//  in case of error.\nint get_monitor_event (void *monitor_, int *value_, char **address_);\n\nvoid expect_monitor_event (void *monitor_, int expected_event_);\n\nvoid print_unexpected_event_stderr (int event_,\n                                    int err_,\n                                    int expected_event_,\n                                    int expected_err_);\n\n//  expects that one or more occurrences of the expected event are received\n//  via the specified socket monitor\n//  returns the number of occurrences of the expected event\n//  interrupts, if a ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL with EPIPE, ECONNRESET\n//  or ECONNABORTED occurs; in this case, 0 is returned\n//  this should be investigated further, see\n//  https://github.com/zeromq/libzmq/issues/2644\nint expect_monitor_event_multiple (void *server_mon_,\n                                   int expected_event_,\n                                   int expected_err_ = -1,\n                                   bool optional_ = false);\n\nint64_t get_monitor_event_v2 (void *monitor_,\n                              uint64_t **value_,\n                              char **local_address_,\n                              char **remote_address_);\n\nvoid expect_monitor_event_v2 (void *monitor_,\n                              int64_t expected_event_,\n                              const char *expected_local_address_ = NULL,\n                              const char *expected_remote_address_ = NULL);\n\n\nconst char *get_zmqEventName (uint64_t event);\nvoid print_events (void *socket, int timeout, int limit);\n\n#endif\n"
  },
  {
    "path": "tests/testutil_security.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n#include \"testutil_security.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\nconst char *test_zap_domain = \"ZAPTEST\";\n\nvoid socket_config_null_client (void *server_, void *server_secret_)\n{\n    LIBZMQ_UNUSED (server_);\n    LIBZMQ_UNUSED (server_secret_);\n}\n\nvoid socket_config_null_server (void *server_, void *server_secret_)\n{\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      server_, ZMQ_ZAP_DOMAIN, test_zap_domain, strlen (test_zap_domain)));\n#ifdef ZMQ_ZAP_ENFORCE_DOMAIN\n    int required = server_secret_ ? *static_cast<int *> (server_secret_) : 0;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (server_, ZMQ_ZAP_ENFORCE_DOMAIN,\n                                               &required, sizeof (int)));\n#else\n    LIBZMQ_UNUSED (server_secret_);\n#endif\n}\n\nstatic const char test_plain_username[] = \"testuser\";\nstatic const char test_plain_password[] = \"testpass\";\n\nvoid socket_config_plain_client (void *server_, void *server_secret_)\n{\n    LIBZMQ_UNUSED (server_secret_);\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server_, ZMQ_PLAIN_PASSWORD, test_plain_password, 8));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server_, ZMQ_PLAIN_USERNAME, test_plain_username, 8));\n}\n\nvoid socket_config_plain_server (void *server_, void *server_secret_)\n{\n    LIBZMQ_UNUSED (server_secret_);\n\n    int as_server = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server_, ZMQ_PLAIN_SERVER, &as_server, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      server_, ZMQ_ZAP_DOMAIN, test_zap_domain, strlen (test_zap_domain)));\n}\n\nchar valid_client_public[41];\nchar valid_client_secret[41];\nchar valid_server_public[41];\nchar valid_server_secret[41];\n\nvoid setup_testutil_security_curve ()\n{\n    //  Generate new keypairs for these tests\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_curve_keypair (valid_client_public, valid_client_secret));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_curve_keypair (valid_server_public, valid_server_secret));\n}\n\nvoid socket_config_curve_server (void *server_, void *server_secret_)\n{\n    int as_server = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server_, ZMQ_CURVE_SERVER, &as_server, sizeof (int)));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (server_, ZMQ_CURVE_SECRETKEY, server_secret_, 41));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      server_, ZMQ_ZAP_DOMAIN, test_zap_domain, strlen (test_zap_domain)));\n\n#ifdef ZMQ_ZAP_ENFORCE_DOMAIN\n    int required = 1;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (server_, ZMQ_ZAP_ENFORCE_DOMAIN,\n                                               &required, sizeof (int)));\n#endif\n}\n\nvoid socket_config_curve_client (void *client_, void *data_)\n{\n    const curve_client_data_t *const curve_client_data =\n      static_cast<const curve_client_data_t *> (data_);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      client_, ZMQ_CURVE_SERVERKEY, curve_client_data->server_public, 41));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      client_, ZMQ_CURVE_PUBLICKEY, curve_client_data->client_public, 41));\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      client_, ZMQ_CURVE_SECRETKEY, curve_client_data->client_secret, 41));\n}\n\nvoid *zap_requests_handled;\n\nvoid zap_handler_generic (zap_protocol_t zap_protocol_,\n                          const char *expected_routing_id_)\n{\n    void *control = zmq_socket (get_test_context (), ZMQ_REQ);\n    TEST_ASSERT_NOT_NULL (control);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_connect (control, \"inproc://handler-control\"));\n\n    void *handler = zmq_socket (get_test_context (), ZMQ_REP);\n    TEST_ASSERT_NOT_NULL (handler);\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, \"inproc://zeromq.zap.01\"));\n\n    //  Signal main thread that we are ready\n    send_string_expect_success (control, \"GO\", 0);\n\n    zmq_pollitem_t items[] = {\n      {control, 0, ZMQ_POLLIN, 0},\n      {handler, 0, ZMQ_POLLIN, 0},\n    };\n\n    // if ordered not to receive the request, ignore the second poll item\n    const int numitems = (zap_protocol_ == zap_do_not_recv) ? 1 : 2;\n\n    //  Process ZAP requests forever\n    while (zmq_poll (items, numitems, -1) >= 0) {\n        if (items[0].revents & ZMQ_POLLIN) {\n            recv_string_expect_success (control, \"STOP\", 0);\n            break; //  Terminating - main thread signal\n        }\n        if (!(items[1].revents & ZMQ_POLLIN))\n            continue;\n\n        char *version = s_recv (handler);\n        if (!version)\n            break; //  Terminating - peer's socket closed\n        if (zap_protocol_ == zap_disconnect) {\n            free (version);\n            break;\n        }\n\n        char *sequence = s_recv (handler);\n        char *domain = s_recv (handler);\n        char *address = s_recv (handler);\n        char *routing_id = s_recv (handler);\n        char *mechanism = s_recv (handler);\n        bool authentication_succeeded = false;\n        if (streq (mechanism, \"CURVE\")) {\n            uint8_t client_key[32];\n            TEST_ASSERT_EQUAL_INT (32, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (\n                                         handler, client_key, 32, 0)));\n\n            char client_key_text[41];\n            zmq_z85_encode (client_key_text, client_key, 32);\n\n            authentication_succeeded =\n              streq (client_key_text, valid_client_public);\n        } else if (streq (mechanism, \"PLAIN\")) {\n            char client_username[32];\n            int size = TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_recv (handler, client_username, 32, 0));\n            client_username[size] = 0;\n\n            char client_password[32];\n            size = TEST_ASSERT_SUCCESS_ERRNO (\n              zmq_recv (handler, client_password, 32, 0));\n            client_password[size] = 0;\n\n            authentication_succeeded =\n              streq (test_plain_username, client_username)\n              && streq (test_plain_password, client_password);\n        } else if (streq (mechanism, \"NULL\")) {\n            authentication_succeeded = true;\n        } else {\n            char msg[128];\n            printf (\"Unsupported mechanism: %s\\n\", mechanism);\n            TEST_FAIL_MESSAGE (msg);\n        }\n\n        TEST_ASSERT_EQUAL_STRING (\"1.0\", version);\n        TEST_ASSERT_EQUAL_STRING (expected_routing_id_, routing_id);\n\n        send_string_expect_success (\n          handler,\n          zap_protocol_ == zap_wrong_version ? \"invalid_version\" : version,\n          ZMQ_SNDMORE);\n        send_string_expect_success (handler,\n                                    zap_protocol_ == zap_wrong_request_id\n                                      ? \"invalid_request_id\"\n                                      : sequence,\n                                    ZMQ_SNDMORE);\n\n        if (authentication_succeeded) {\n            const char *status_code;\n            switch (zap_protocol_) {\n                case zap_status_internal_error:\n                    status_code = \"500\";\n                    break;\n                case zap_status_temporary_failure:\n                    status_code = \"300\";\n                    break;\n                case zap_status_invalid:\n                    status_code = \"invalid_status\";\n                    break;\n                default:\n                    status_code = \"200\";\n            }\n            send_string_expect_success (handler, status_code, ZMQ_SNDMORE);\n            send_string_expect_success (handler, \"OK\", ZMQ_SNDMORE);\n            send_string_expect_success (handler, \"anonymous\", ZMQ_SNDMORE);\n            if (zap_protocol_ == zap_too_many_parts) {\n                send_string_expect_success (handler, \"\", ZMQ_SNDMORE);\n            }\n            if (zap_protocol_ != zap_do_not_send)\n                send_string_expect_success (handler, \"\", 0);\n        } else {\n            send_string_expect_success (handler, \"400\", ZMQ_SNDMORE);\n            send_string_expect_success (handler, \"Invalid client public key\",\n                                        ZMQ_SNDMORE);\n            send_string_expect_success (handler, \"\", ZMQ_SNDMORE);\n            if (zap_protocol_ != zap_do_not_send)\n                send_string_expect_success (handler, \"\", 0);\n        }\n        free (version);\n        free (sequence);\n        free (domain);\n        free (address);\n        free (routing_id);\n        free (mechanism);\n\n        zmq_atomic_counter_inc (zap_requests_handled);\n    }\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (handler, \"inproc://zeromq.zap.01\"));\n    close_zero_linger (handler);\n\n    if (zap_protocol_ != zap_disconnect) {\n        send_string_expect_success (control, \"STOPPED\", 0);\n    }\n    close_zero_linger (control);\n}\n\nvoid zap_handler (void *)\n{\n    zap_handler_generic (zap_ok);\n}\n\nstatic void setup_handshake_socket_monitor (void *server_,\n                                            void **server_mon_,\n                                            const char *monitor_endpoint_)\n{\n    //  Monitor handshake events on the server\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (\n      server_, monitor_endpoint_,\n      ZMQ_EVENT_HANDSHAKE_SUCCEEDED | ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL\n        | ZMQ_EVENT_HANDSHAKE_FAILED_AUTH\n        | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL));\n\n    //  Create socket for collecting monitor events\n    *server_mon_ = test_context_socket (ZMQ_PAIR);\n    int linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (*server_mon_, ZMQ_LINGER, &linger, sizeof (linger)));\n\n    //  Connect it to the inproc endpoints so they'll get events\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (*server_mon_, monitor_endpoint_));\n}\n\nvoid setup_context_and_server_side (void **zap_control_,\n                                    void **zap_thread_,\n                                    void **server_,\n                                    void **server_mon_,\n                                    char *my_endpoint_,\n                                    zmq_thread_fn zap_handler_,\n                                    socket_config_fn socket_config_,\n                                    void *socket_config_data_,\n                                    const char *routing_id_)\n{\n    //  Spawn ZAP handler\n    zap_requests_handled = zmq_atomic_counter_new ();\n    TEST_ASSERT_NOT_NULL (zap_requests_handled);\n\n    *zap_control_ = test_context_socket (ZMQ_REP);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_bind (*zap_control_, \"inproc://handler-control\"));\n    int linger = 0;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (*zap_control_, ZMQ_LINGER, &linger, sizeof (linger)));\n\n    if (zap_handler_ != NULL) {\n        *zap_thread_ = zmq_threadstart (zap_handler_, NULL);\n\n        recv_string_expect_success (*zap_control_, \"GO\", 0);\n    } else\n        *zap_thread_ = NULL;\n\n    //  Server socket will accept connections\n    *server_ = test_context_socket (ZMQ_DEALER);\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (*server_, ZMQ_LINGER, &linger, sizeof (linger)));\n    //  As per API by default there's no limit to the size of a message,\n    //  but the sanitizer allocator will barf over a gig or so\n    int64_t max_msg_size = 64 * 1024 * 1024;\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      *server_, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));\n\n    socket_config_ (*server_, socket_config_data_);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (\n      *server_, ZMQ_ROUTING_ID, routing_id_, strlen (routing_id_)));\n\n    bind_loopback_ipv4 (*server_, my_endpoint_, MAX_SOCKET_STRING);\n\n    const char server_monitor_endpoint[] = \"inproc://monitor-server\";\n    setup_handshake_socket_monitor (*server_, server_mon_,\n                                    server_monitor_endpoint);\n}\n\nvoid shutdown_context_and_server_side (void *zap_thread_,\n                                       void *server_,\n                                       void *server_mon_,\n                                       void *zap_control_,\n                                       bool zap_handler_stopped_)\n{\n    if (zap_thread_ && !zap_handler_stopped_) {\n        send_string_expect_success (zap_control_, \"STOP\", 0);\n        recv_string_expect_success (zap_control_, \"STOPPED\", 0);\n        TEST_ASSERT_SUCCESS_ERRNO (\n          zmq_unbind (zap_control_, \"inproc://handler-control\"));\n    }\n    test_context_socket_close (zap_control_);\n    zmq_socket_monitor (server_, NULL, 0);\n    test_context_socket_close (server_mon_);\n    test_context_socket_close (server_);\n\n    //  Wait until ZAP handler terminates\n    if (zap_thread_)\n        zmq_threadclose (zap_thread_);\n\n    zmq_atomic_counter_destroy (&zap_requests_handled);\n}\n\nvoid *create_and_connect_client (char *my_endpoint_,\n                                 socket_config_fn socket_config_,\n                                 void *socket_config_data_,\n                                 void **client_mon_)\n{\n    void *client = test_context_socket (ZMQ_DEALER);\n    //  As per API by default there's no limit to the size of a message,\n    //  but the sanitizer allocator will barf over a gig or so\n    int64_t max_msg_size = 64 * 1024 * 1024;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (client, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));\n\n    socket_config_ (client, socket_config_data_);\n\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint_));\n\n    if (client_mon_) {\n        setup_handshake_socket_monitor (client, client_mon_,\n                                        \"inproc://client-monitor\");\n    }\n\n    return client;\n}\n\nvoid expect_new_client_bounce_fail (char *my_endpoint_,\n                                    void *server_,\n                                    socket_config_fn socket_config_,\n                                    void *socket_config_data_,\n                                    void **client_mon_,\n                                    int expected_client_event_,\n                                    int expected_client_value_)\n{\n    void *my_client_mon = NULL;\n    TEST_ASSERT_TRUE (client_mon_ == NULL || expected_client_event_ == 0);\n    if (expected_client_event_ != 0)\n        client_mon_ = &my_client_mon;\n    void *client = create_and_connect_client (my_endpoint_, socket_config_,\n                                              socket_config_data_, client_mon_);\n    expect_bounce_fail (server_, client);\n\n    if (expected_client_event_ != 0) {\n        int events_received = 0;\n        events_received = expect_monitor_event_multiple (\n          my_client_mon, expected_client_event_, expected_client_value_, false);\n\n        TEST_ASSERT_EQUAL_INT (1, events_received);\n\n        test_context_socket_close (my_client_mon);\n    }\n\n    test_context_socket_close_zero_linger (client);\n}\n"
  },
  {
    "path": "tests/testutil_security.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __TESTUTIL_SECURITY_HPP_INCLUDED__\n#define __TESTUTIL_SECURITY_HPP_INCLUDED__\n\n#include \"testutil_unity.hpp\"\n#include \"testutil_monitoring.hpp\"\n\n//  security test utils\n\ntypedef void (socket_config_fn) (void *, void *);\n\n//  NULL specific functions\nvoid socket_config_null_client (void *server_, void *server_secret_);\n\nvoid socket_config_null_server (void *server_, void *server_secret_);\n\n//  PLAIN specific functions\nvoid socket_config_plain_client (void *server_, void *server_secret_);\n\nvoid socket_config_plain_server (void *server_, void *server_secret_);\n\n//  CURVE specific functions\n\n//  We'll generate random test keys at startup\nextern char valid_client_public[41];\nextern char valid_client_secret[41];\nextern char valid_server_public[41];\nextern char valid_server_secret[41];\n\nvoid setup_testutil_security_curve ();\n\nvoid socket_config_curve_server (void *server_, void *server_secret_);\n\nstruct curve_client_data_t\n{\n    const char *server_public;\n    const char *client_public;\n    const char *client_secret;\n};\n\nvoid socket_config_curve_client (void *client_, void *data_);\n\n//  --------------------------------------------------------------------------\n//  This methods receives and validates ZAP requests (allowing or denying\n//  each client connection).\n\nenum zap_protocol_t\n{\n    zap_ok,\n    // ZAP-compliant non-standard cases\n    zap_status_temporary_failure,\n    zap_status_internal_error,\n    // ZAP protocol errors\n    zap_wrong_version,\n    zap_wrong_request_id,\n    zap_status_invalid,\n    zap_too_many_parts,\n    zap_disconnect,\n    zap_do_not_recv,\n    zap_do_not_send\n};\n\nextern void *zap_requests_handled;\n\nvoid zap_handler_generic (zap_protocol_t zap_protocol_,\n                          const char *expected_routing_id_ = \"IDENT\");\n\nvoid zap_handler (void * /*unused_*/);\n\n//  Security-specific monitor event utilities\n\n// assert_* are macros rather than functions, to allow assertion failures be\n// attributed to the causing source code line\n#define assert_no_more_monitor_events_with_timeout(monitor, timeout)                  \\\n    {                                                                                 \\\n        int event_count = 0;                                                          \\\n        int event, err;                                                               \\\n        while ((event = get_monitor_event_with_timeout ((monitor), &err, NULL,        \\\n                                                        (timeout)))                   \\\n               != -1) {                                                               \\\n            if (event == ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL                         \\\n                && (err == EPIPE || err == ECONNRESET                                 \\\n                    || err == ECONNABORTED)) {                                        \\\n                fprintf (stderr,                                                      \\\n                         \"Ignored event (skipping any further events): %x \"           \\\n                         \"(err = %i == %s)\\n\",                                        \\\n                         event, err, zmq_strerror (err));                             \\\n                continue;                                                             \\\n            }                                                                         \\\n            ++event_count;                                                            \\\n            /* TODO write this into a buffer and attach to the assertion msg below */ \\\n            print_unexpected_event_stderr (event, err, 0, 0);                         \\\n        }                                                                             \\\n        TEST_ASSERT_EQUAL_INT (0, event_count);                                       \\\n    }\n\nvoid setup_context_and_server_side (\n  void **zap_control_,\n  void **zap_thread_,\n  void **server_,\n  void **server_mon_,\n  char *my_endpoint_,\n  zmq_thread_fn zap_handler_ = &zap_handler,\n  socket_config_fn socket_config_ = &socket_config_curve_server,\n  void *socket_config_data_ = valid_server_secret,\n  const char *routing_id_ = \"IDENT\");\n\nvoid shutdown_context_and_server_side (void *zap_thread_,\n                                       void *server_,\n                                       void *server_mon_,\n                                       void *zap_control_,\n                                       bool zap_handler_stopped_ = false);\n\nvoid *create_and_connect_client (char *my_endpoint_,\n                                 socket_config_fn socket_config_,\n                                 void *socket_config_data_,\n                                 void **client_mon_ = NULL);\n\nvoid expect_new_client_bounce_fail (char *my_endpoint_,\n                                    void *server_,\n                                    socket_config_fn socket_config_,\n                                    void *socket_config_data_,\n                                    void **client_mon_ = NULL,\n                                    int expected_client_event_ = 0,\n                                    int expected_client_value_ = 0);\n\n#endif\n"
  },
  {
    "path": "tests/testutil_unity.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n#include \"testutil_unity.hpp\"\n\n#include <stdlib.h>\n#include <string.h>\n\n#ifdef _WIN32\n#include <direct.h>\n#else\n#include <unistd.h>\n#endif\n\nint test_assert_success_message_errno_helper (int rc_,\n                                              const char *msg_,\n                                              const char *expr_,\n                                              int line_)\n{\n    if (rc_ == -1) {\n        char buffer[512];\n        buffer[sizeof (buffer) - 1] =\n          0; // to ensure defined behavior with VC++ <= 2013\n        snprintf (buffer, sizeof (buffer) - 1,\n                  \"%s failed%s%s%s, errno = %i (%s)\", expr_,\n                  msg_ ? \" (additional info: \" : \"\", msg_ ? msg_ : \"\",\n                  msg_ ? \")\" : \"\", zmq_errno (), zmq_strerror (zmq_errno ()));\n        UNITY_TEST_FAIL (line_, buffer);\n    }\n    return rc_;\n}\n\nint test_assert_success_message_raw_errno_helper (\n  int rc_, const char *msg_, const char *expr_, int line_, bool zero)\n{\n    if (rc_ == -1 || (zero && rc_ != 0)) {\n#if defined ZMQ_HAVE_WINDOWS\n        int current_errno = WSAGetLastError ();\n#else\n        int current_errno = errno;\n#endif\n\n        char buffer[512];\n        buffer[sizeof (buffer) - 1] =\n          0; // to ensure defined behavior with VC++ <= 2013\n        snprintf (\n          buffer, sizeof (buffer) - 1, \"%s failed%s%s%s with %d, errno = %i/%s\",\n          expr_, msg_ ? \" (additional info: \" : \"\", msg_ ? msg_ : \"\",\n          msg_ ? \")\" : \"\", rc_, current_errno, strerror (current_errno));\n        UNITY_TEST_FAIL (line_, buffer);\n    }\n    return rc_;\n}\n\nint test_assert_success_message_raw_zero_errno_helper (int rc_,\n                                                       const char *msg_,\n                                                       const char *expr_,\n                                                       int line_)\n{\n    return test_assert_success_message_raw_errno_helper (rc_, msg_, expr_,\n                                                         line_, true);\n}\n\nint test_assert_failure_message_raw_errno_helper (\n  int rc_, int expected_errno_, const char *msg_, const char *expr_, int line_)\n{\n    char buffer[512];\n    buffer[sizeof (buffer) - 1] =\n      0; // to ensure defined behavior with VC++ <= 2013\n    if (rc_ != -1) {\n        snprintf (buffer, sizeof (buffer) - 1,\n                  \"%s was unexpectedly successful%s%s%s, expected \"\n                  \"errno = %i, actual return value = %i\",\n                  expr_, msg_ ? \" (additional info: \" : \"\", msg_ ? msg_ : \"\",\n                  msg_ ? \")\" : \"\", expected_errno_, rc_);\n        UNITY_TEST_FAIL (line_, buffer);\n    } else {\n#if defined ZMQ_HAVE_WINDOWS\n        int current_errno = WSAGetLastError ();\n#else\n        int current_errno = errno;\n#endif\n        if (current_errno != expected_errno_) {\n            snprintf (buffer, sizeof (buffer) - 1,\n                      \"%s failed with an unexpected error%s%s%s, expected \"\n                      \"errno = %i, actual errno = %i\",\n                      expr_, msg_ ? \" (additional info: \" : \"\",\n                      msg_ ? msg_ : \"\", msg_ ? \")\" : \"\", expected_errno_,\n                      current_errno);\n            UNITY_TEST_FAIL (line_, buffer);\n        }\n    }\n    return rc_;\n}\n\nvoid send_string_expect_success (void *socket_, const char *str_, int flags_)\n{\n    const size_t len = str_ ? strlen (str_) : 0;\n    const int rc = zmq_send (socket_, str_, len, flags_);\n    TEST_ASSERT_EQUAL_INT ((int) len, rc);\n}\n\nvoid recv_string_expect_success (void *socket_, const char *str_, int flags_)\n{\n    const size_t len = str_ ? strlen (str_) : 0;\n    char buffer[255];\n    TEST_ASSERT_LESS_OR_EQUAL_MESSAGE (sizeof (buffer), len,\n                                       \"recv_string_expect_success cannot be \"\n                                       \"used for strings longer than 255 \"\n                                       \"characters\");\n\n    const int rc = TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_recv (socket_, buffer, sizeof (buffer), flags_));\n    TEST_ASSERT_EQUAL_INT ((int) len, rc);\n    if (str_)\n        TEST_ASSERT_EQUAL_STRING_LEN (str_, buffer, len);\n}\n\nstatic void *internal_manage_test_context (bool init_, bool clear_)\n{\n    static void *test_context = NULL;\n    if (clear_) {\n        TEST_ASSERT_NOT_NULL (test_context);\n        TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_term (test_context));\n        test_context = NULL;\n    } else {\n        if (init_) {\n            TEST_ASSERT_NULL (test_context);\n            test_context = zmq_ctx_new ();\n            TEST_ASSERT_NOT_NULL (test_context);\n        }\n    }\n    return test_context;\n}\n\nstatic void internal_manage_test_sockets (void *socket_, bool add_)\n{\n    static void *test_sockets[MAX_TEST_SOCKETS];\n    static size_t test_socket_count = 0;\n    if (!socket_) {\n        TEST_ASSERT_FALSE (add_);\n\n        // force-close all sockets\n        if (test_socket_count) {\n            for (size_t i = 0; i < test_socket_count; ++i) {\n                close_zero_linger (test_sockets[i]);\n            }\n            fprintf (stderr,\n                     \"WARNING: Forced closure of %i sockets, this is an \"\n                     \"implementation error unless the test case failed\\n\",\n                     static_cast<int> (test_socket_count));\n            test_socket_count = 0;\n        }\n    } else {\n        if (add_) {\n            ++test_socket_count;\n            TEST_ASSERT_LESS_THAN_MESSAGE (MAX_TEST_SOCKETS, test_socket_count,\n                                           \"MAX_TEST_SOCKETS must be \"\n                                           \"increased, or you cannot use the \"\n                                           \"test context\");\n            test_sockets[test_socket_count - 1] = socket_;\n        } else {\n            bool found = false;\n            for (size_t i = 0; i < test_socket_count; ++i) {\n                if (test_sockets[i] == socket_) {\n                    found = true;\n                }\n                if (found) {\n                    if (i < test_socket_count)\n                        test_sockets[i] = test_sockets[i + 1];\n                }\n            }\n            TEST_ASSERT_TRUE_MESSAGE (found,\n                                      \"Attempted to close a socket that was \"\n                                      \"not created by test_context_socket\");\n            --test_socket_count;\n        }\n    }\n}\n\nvoid setup_test_context ()\n{\n    internal_manage_test_context (true, false);\n}\n\nvoid *get_test_context ()\n{\n    return internal_manage_test_context (false, false);\n}\n\nvoid teardown_test_context ()\n{\n    // this condition allows an explicit call to teardown_test_context from a\n    // test. if this is never used, it should probably be removed, to detect\n    // misuses\n    if (get_test_context ()) {\n        internal_manage_test_sockets (NULL, false);\n        internal_manage_test_context (false, true);\n    }\n}\n\nvoid *test_context_socket (int type_)\n{\n    void *const socket = zmq_socket (get_test_context (), type_);\n    TEST_ASSERT_NOT_NULL (socket);\n    internal_manage_test_sockets (socket, true);\n    return socket;\n}\n\nvoid *test_context_socket_close (void *socket_)\n{\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket_));\n    internal_manage_test_sockets (socket_, false);\n    return socket_;\n}\n\nvoid *test_context_socket_close_zero_linger (void *socket_)\n{\n    const int linger = 0;\n    int rc = zmq_setsockopt (socket_, ZMQ_LINGER, &linger, sizeof (linger));\n    TEST_ASSERT_TRUE (rc == 0 || zmq_errno () == ETERM);\n    return test_context_socket_close (socket_);\n}\n\nvoid test_bind (void *socket_,\n                const char *bind_address_,\n                char *my_endpoint_,\n                size_t len_)\n{\n    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (socket_, bind_address_));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_getsockopt (socket_, ZMQ_LAST_ENDPOINT, my_endpoint_, &len_));\n}\n\nvoid bind_loopback (void *socket_, int ipv6_, char *my_endpoint_, size_t len_)\n{\n    if (ipv6_ && !is_ipv6_available ()) {\n        TEST_IGNORE_MESSAGE (\"ipv6 is not available\");\n    }\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_setsockopt (socket_, ZMQ_IPV6, &ipv6_, sizeof (int)));\n\n    test_bind (socket_, ipv6_ ? \"tcp://[::1]:*\" : \"tcp://127.0.0.1:*\",\n               my_endpoint_, len_);\n}\n\nvoid bind_loopback_ipv4 (void *socket_, char *my_endpoint_, size_t len_)\n{\n    bind_loopback (socket_, false, my_endpoint_, len_);\n}\n\nvoid bind_loopback_ipv6 (void *socket_, char *my_endpoint_, size_t len_)\n{\n    bind_loopback (socket_, true, my_endpoint_, len_);\n}\n\nvoid bind_loopback_ipc (void *socket_, char *my_endpoint_, size_t len_)\n{\n    if (!zmq_has (\"ipc\")) {\n        TEST_IGNORE_MESSAGE (\"ipc is not available\");\n    }\n\n    test_bind (socket_, \"ipc://*\", my_endpoint_, len_);\n}\n\nvoid bind_loopback_tipc (void *socket_, char *my_endpoint_, size_t len_)\n{\n    if (!is_tipc_available ()) {\n        TEST_IGNORE_MESSAGE (\"tipc is not available\");\n    }\n\n    test_bind (socket_, \"tipc://<*>\", my_endpoint_, len_);\n}\n\n#if defined(ZMQ_HAVE_IPC)\nvoid make_random_ipc_endpoint (char *out_endpoint_)\n{\n#ifdef ZMQ_HAVE_WINDOWS\n    char random_file[MAX_PATH];\n\n    {\n        const errno_t rc = tmpnam_s (random_file);\n        TEST_ASSERT_EQUAL (0, rc);\n    }\n\n    // TODO or use CreateDirectoryA and specify permissions?\n    const int rc = _mkdir (random_file);\n    TEST_ASSERT_EQUAL (0, rc);\n\n    strcat (random_file, \"/ipc\");\n\n#else\n    char random_file[16];\n    strcpy (random_file, \"tmpXXXXXX\");\n\n#ifdef HAVE_MKDTEMP\n    TEST_ASSERT_TRUE (mkdtemp (random_file));\n    strcat (random_file, \"/ipc\");\n#else\n    int fd = mkstemp (random_file);\n    TEST_ASSERT_TRUE (fd != -1);\n    close (fd);\n#endif\n#endif\n\n    strcpy (out_endpoint_, \"ipc://\");\n    strcat (out_endpoint_, random_file);\n}\n#endif\n"
  },
  {
    "path": "tests/testutil_unity.hpp",
    "content": "#pragma once\n\n/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../include/zmq.h\"\n\n#include \"testutil.hpp\"\n\n#include <unity.h>\n\n// Internal helper functions that are not intended to be directly called from\n// tests. They must be declared in the header since they are used by macros.\n\nint test_assert_success_message_errno_helper (int rc_,\n                                              const char *msg_,\n                                              const char *expr_,\n                                              int line);\n\nint test_assert_success_message_raw_errno_helper (\n  int rc_, const char *msg_, const char *expr_, int line, bool zero_ = false);\n\nint test_assert_success_message_raw_zero_errno_helper (int rc_,\n                                                       const char *msg_,\n                                                       const char *expr_,\n                                                       int line);\n\nint test_assert_failure_message_raw_errno_helper (\n  int rc_, int expected_errno_, const char *msg_, const char *expr_, int line);\n\n/////////////////////////////////////////////////////////////////////////////\n// Macros extending Unity's TEST_ASSERT_* macros in a similar fashion.\n/////////////////////////////////////////////////////////////////////////////\n\n// For TEST_ASSERT_SUCCESS_ERRNO, TEST_ASSERT_SUCCESS_MESSAGE_ERRNO and\n// TEST_ASSERT_FAILURE_ERRNO, 'expr' must be an expression evaluating\n// to a result in the style of a libzmq API function, i.e. an integer which\n// is non-negative in case of success, and -1 in case of a failure, and sets\n// the value returned by zmq_errno () to the error code.\n// TEST_ASSERT_SUCCESS_RAW_ERRNO and TEST_ASSERT_FAILURE_RAW_ERRNO are similar,\n// but used with the native socket API functions, and expect that the error\n// code can be retrieved in the native way (i.e. WSAGetLastError on Windows,\n// and errno otherwise).\n\n// Asserts that the libzmq API 'expr' is successful. In case of a failure, the\n// assertion message includes the literal 'expr', the error number as\n// determined by zmq_errno(), and the additional 'msg'.\n// In case of success, the result of the macro is the result of 'expr'.\n#define TEST_ASSERT_SUCCESS_MESSAGE_ERRNO(expr, msg)                           \\\n    test_assert_success_message_errno_helper (expr, msg, #expr, __LINE__)\n\n// Asserts that the libzmq API 'expr' is successful. In case of a failure, the\n// assertion message includes the literal 'expr' and the error code.\n// A typical use would be:\n//   TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (socket, endpoint));\n// In case of success, the result of the macro is the result of 'expr'.\n//\n// If an additional message should be displayed in case of a failure, use\n// TEST_ASSERT_SUCCESS_MESSAGE_ERRNO.\n#define TEST_ASSERT_SUCCESS_ERRNO(expr)                                        \\\n    test_assert_success_message_errno_helper (expr, NULL, #expr, __LINE__)\n\n// Asserts that the socket API 'expr' is successful. In case of a failure, the\n// assertion message includes the literal 'expr' and the error code.\n// A typical use would be:\n//   TEST_ASSERT_SUCCESS_RAW_ERRNO (send (fd, buffer, 64, 0));\n// In case of success, the result of the macro is the result of 'expr'.\n// Success is strictly defined by a return value different from -1, as opposed\n// to checking that it is 0, like TEST_ASSERT_FAILURE_RAW_ZERO_ERRNO does.\n#define TEST_ASSERT_SUCCESS_RAW_ERRNO(expr)                                    \\\n    test_assert_success_message_raw_errno_helper (expr, NULL, #expr, __LINE__)\n\n// Asserts that the socket API 'expr' is successful. In case of a failure, the\n// assertion message includes the literal 'expr' and the error code.\n// A typical use would be:\n//   TEST_ASSERT_SUCCESS_RAW_ZERO_ERRNO (send (fd, buffer, 64, 0));\n// In case of success, the result of the macro is the result of 'expr'.\n// Success is strictly defined by a return value of 0, as opposed to checking\n// that it is not -1, like TEST_ASSERT_FAILURE_RAW_ERRNO does.\n#define TEST_ASSERT_SUCCESS_RAW_ZERO_ERRNO(expr)                               \\\n    test_assert_success_message_raw_zero_errno_helper (expr, NULL, #expr,      \\\n                                                       __LINE__)\n\n// Asserts that the socket API 'expr' is not successful, and the error code is\n// 'error_code'. In case of an unexpected succces, or a failure with an\n// unexpected error code, the assertion message includes the literal 'expr'\n// and, in case of a failure, the actual error code.\n#define TEST_ASSERT_FAILURE_RAW_ERRNO(error_code, expr)                        \\\n    test_assert_failure_message_raw_errno_helper (expr, error_code, NULL,      \\\n                                                  #expr, __LINE__)\n\n// Asserts that the libzmq API 'expr' is not successful, and the error code is\n// 'error_code'. In case of an unexpected succces, or a failure with an\n// unexpected error code, the assertion message includes the literal 'expr'\n// and, in case of a failure, the actual error code.\n#define TEST_ASSERT_FAILURE_ERRNO(error_code, expr)                            \\\n    {                                                                          \\\n        int _rc = (expr);                                                      \\\n        TEST_ASSERT_EQUAL_INT (-1, _rc);                                       \\\n        TEST_ASSERT_EQUAL_INT (error_code, errno);                             \\\n    }\n\n/////////////////////////////////////////////////////////////////////////////\n// Utility functions for testing sending and receiving.\n/////////////////////////////////////////////////////////////////////////////\n\n// Sends a string via a libzmq socket, and expects the operation to be\n// successful (the meaning of which depends on the socket type and configured\n// options, and might include dropping the message). Otherwise, a Unity test\n// assertion is triggered.\n// 'socket_' must be the libzmq socket to use for sending.\n// 'str_' must be a 0-terminated string.\n// 'flags_' are as documented by the zmq_send function.\nvoid send_string_expect_success (void *socket_, const char *str_, int flags_);\n\n// Receives a message via a libzmq socket, and expects the operation to be\n// successful, and the message to be a given string. Otherwise, a Unity test\n// assertion is triggered.\n// 'socket_' must be the libzmq socket to use for receiving.\n// 'str_' must be a 0-terminated string.\n// 'flags_' are as documented by the zmq_recv function.\nvoid recv_string_expect_success (void *socket_, const char *str_, int flags_);\n\n// Sends a byte array via a libzmq socket, and expects the operation to be\n// successful (the meaning of which depends on the socket type and configured\n// options, and might include dropping the message). Otherwise, a Unity test\n// assertion is triggered.\n// 'socket_' must be the libzmq socket to use for sending.\n// 'array_' must be a C uint8_t array. The array size is automatically\n// determined via template argument deduction.\n// 'flags_' are as documented by the zmq_send function.\ntemplate <size_t SIZE>\nvoid send_array_expect_success (void *socket_,\n                                const uint8_t (&array_)[SIZE],\n                                int flags_)\n{\n    const int rc = zmq_send (socket_, array_, SIZE, flags_);\n    TEST_ASSERT_EQUAL_INT (static_cast<int> (SIZE), rc);\n}\n\n// Receives a message via a libzmq socket, and expects the operation to be\n// successful, and the message to be a given byte array. Otherwise, a Unity\n// test assertion is triggered.\n// 'socket_' must be the libzmq socket to use for receiving.\n// 'array_' must be a C uint8_t array. The array size is automatically\n// determined via template argument deduction.\n// 'flags_' are as documented by the zmq_recv function.\ntemplate <size_t SIZE>\nvoid recv_array_expect_success (void *socket_,\n                                const uint8_t (&array_)[SIZE],\n                                int flags_)\n{\n    char buffer[255];\n    TEST_ASSERT_LESS_OR_EQUAL_MESSAGE (sizeof (buffer), SIZE,\n                                       \"recv_string_expect_success cannot be \"\n                                       \"used for strings longer than 255 \"\n                                       \"characters\");\n\n    const int rc = TEST_ASSERT_SUCCESS_ERRNO (\n      zmq_recv (socket_, buffer, sizeof (buffer), flags_));\n    TEST_ASSERT_EQUAL_INT (static_cast<int> (SIZE), rc);\n    TEST_ASSERT_EQUAL_UINT8_ARRAY (array_, buffer, SIZE);\n}\n\n/////////////////////////////////////////////////////////////////////////////\n// Utility function for handling a test libzmq context, that is set up and\n// torn down for each Unity test case, such that a clean context is available\n// for each test case, and some consistency checks can be performed.\n/////////////////////////////////////////////////////////////////////////////\n\n// Use this is an test executable to perform a default setup and teardown of\n// the test context, which is appropriate for many libzmq test cases.\n#define SETUP_TEARDOWN_TESTCONTEXT                                             \\\n    void setUp ()                                                              \\\n    {                                                                          \\\n        setup_test_context ();                                                 \\\n    }                                                                          \\\n    void tearDown ()                                                           \\\n    {                                                                          \\\n        teardown_test_context ();                                              \\\n    }\n\n// The maximum number of sockets that can be managed by the test context.\n#define MAX_TEST_SOCKETS 128\n\n// Expected to be called during Unity's setUp function.\nvoid setup_test_context ();\n\n// Returns the test context, e.g. to create sockets in another thread using\n// zmq_socket, or set context options.\nvoid *get_test_context ();\n\n// Expected to be called during Unity's tearDown function. Checks that all\n// sockets created via test_context_socket have been properly closed using\n// test_context_socket_close or test_context_socket_close_zero_linger, and generates a warning otherwise.\nvoid teardown_test_context ();\n\n// Creates a libzmq socket on the test context, and tracks its lifecycle.\n// You MUST use test_context_socket_close or test_context_socket_close_zero_linger\n// to close a socket created via this function, otherwise undefined behaviour\n// will result.\n// CAUTION: this function is not thread-safe, and may only be used from the\n// main thread.\nvoid *test_context_socket (int type_);\n\n// Closes a socket created via test_context_socket.\n// CAUTION: this function is not thread-safe, and may only be used from the\n// main thread.\nvoid *test_context_socket_close (void *socket_);\n\n// Closes a socket created via test_context_socket after setting its linger\n// timeout to 0.\n// CAUTION: this function is not thread-safe, and may only be used from the\n// main thread.\nvoid *test_context_socket_close_zero_linger (void *socket_);\n\n/////////////////////////////////////////////////////////////////////////////\n// Utility function for handling wildcard binds.\n/////////////////////////////////////////////////////////////////////////////\n\n// All function binds a socket to some wildcard address, and retrieve the bound\n// endpoint via the ZMQ_LAST_ENDPOINT socket option to a given buffer.\n// Triggers a Unity test assertion in case of a failure (including the buffer\n// being too small for the resulting endpoint string).\n\n// Binds to an explicitly given (wildcard) address.\n// TODO redesign such that this function is not necessary to be exposed, but\n// the protocol to use is rather specified via an enum value\nvoid test_bind (void *socket_,\n                const char *bind_address_,\n                char *my_endpoint_,\n                size_t len_);\n\n// Binds to a tcp endpoint using the ipv4 or ipv6 loopback wildcard address.\nvoid bind_loopback (void *socket_, int ipv6_, char *my_endpoint_, size_t len_);\n\ntypedef void (*bind_function_t) (void *socket_,\n                                 char *my_endpoint_,\n                                 size_t len_);\n\n// Binds to a tcp endpoint using the ipv4 loopback wildcard address.\nvoid bind_loopback_ipv4 (void *socket_, char *my_endpoint_, size_t len_);\n\n// Binds to a tcp endpoint using the ipv6 loopback wildcard address.\nvoid bind_loopback_ipv6 (void *socket_, char *my_endpoint_, size_t len_);\n\n// Binds to an ipc endpoint using the ipc wildcard address.\n// Note that the returned address cannot be reused to bind a second socket.\n// If you need to do this, use make_random_ipc_endpoint instead.\nvoid bind_loopback_ipc (void *socket_, char *my_endpoint_, size_t len_);\n\n// Binds to an ipc endpoint using the tipc wildcard address.\nvoid bind_loopback_tipc (void *socket_, char *my_endpoint_, size_t len_);\n\n#if defined(ZMQ_HAVE_IPC)\n// utility function to create a random IPC endpoint, similar to what a ipc://*\n// wildcard binding does, but in a way it can be reused for multiple binds\n// TODO also add a len parameter here\nvoid make_random_ipc_endpoint (char *out_endpoint_);\n#endif\n"
  },
  {
    "path": "tools/curve_keygen.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include <stdlib.h>\n#include <assert.h>\n#include <zmq.h>\n\nint main (void)\n{\n    puts (\"This tool generates a CurveZMQ keypair, as two printable strings \"\n          \"you can\");\n    puts (\"use in configuration files or source code. The encoding uses Z85, \"\n          \"which\");\n    puts (\n      \"is a base-85 format that is described in 0MQ RFC 32, and which has an\");\n    puts (\"implementation in the z85_codec.h source used by this tool. The \"\n          \"keypair\");\n    puts (\n      \"always works with the secret key held by one party and the public key\");\n    puts (\"distributed (securely!) to peers wishing to connect to it.\");\n\n    char public_key[41];\n    char secret_key[41];\n    if (zmq_curve_keypair (public_key, secret_key)) {\n        if (zmq_errno () == ENOTSUP)\n            puts (\"To use curve_keygen, please install libsodium and then \"\n                  \"rebuild libzmq.\");\n        exit (1);\n    }\n\n    puts (\"\\n== CURVE PUBLIC KEY ==\");\n    puts (public_key);\n\n    puts (\"\\n== CURVE SECRET KEY ==\");\n    puts (secret_key);\n\n    exit (0);\n}\n"
  },
  {
    "path": "unittests/CMakeLists.txt",
    "content": "# CMake build script for ZeroMQ unit tests\ncmake_minimum_required(VERSION 2.8.1...3.31)\n\nset(unittests\n    unittest_ypipe\n    unittest_poller\n    unittest_mtrie\n    unittest_ip_resolver\n    unittest_udp_address\n    unittest_radix_tree\n    unittest_curve_encoding)\n\n# if(ENABLE_DRAFTS) list(APPEND tests ) endif(ENABLE_DRAFTS)\n\n# add location of platform.hpp for Windows builds\nif(WIN32)\n  add_definitions(-DZMQ_CUSTOM_PLATFORM_HPP)\n  add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS)\n  # Same name on 64bit systems\n  link_libraries(ws2_32.lib)\nendif()\n\ninclude_directories(\"${ZeroMQ_SOURCE_DIR}/include\" \"${ZeroMQ_SOURCE_DIR}/src\" \"${ZeroMQ_BINARY_DIR}\")\ninclude_directories(\"${ZeroMQ_SOURCE_DIR}/external/unity\")\n\nforeach(test ${unittests})\n  # target_sources not supported before CMake 3.1\n  add_executable(${test} ${test}.cpp \"unittest_resolver_common.hpp\")\n\n  # per-test directories not generated on OS X / Darwin\n  if(NOT ${CMAKE_CXX_COMPILER_ID} MATCHES \"Clang.*\")\n    link_directories(${test} PRIVATE \"${ZeroMQ_SOURCE_DIR}/../lib\")\n  endif()\n\n  target_link_libraries(${test} testutil-static)\n\n  if(RT_LIBRARY)\n    target_link_libraries(${test} ${RT_LIBRARY})\n  endif()\n\n  if(CMAKE_SYSTEM_NAME MATCHES \"QNX\")\n    target_link_libraries(${test} socket)\n    target_link_libraries(${test} m)\n  endif()\n\n  if (WITH_GSSAPI_KRB5)\n    target_link_libraries(${test} ${GSSAPI_KRB5_LIBRARIES})\n  endif()\n\n  if(WIN32)\n    add_test(\n      NAME ${test}\n      WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH}\n      COMMAND ${test})\n  else()\n    add_test(NAME ${test} COMMAND ${test})\n  endif()\n\n  set_tests_properties(${test} PROPERTIES TIMEOUT 10)\n\n  # TODO prevent libzmq (non-static) being in the list of link libraries at all\n  get_target_property(LIBS ${test} LINK_LIBRARIES)\n  list(REMOVE_ITEM LIBS libzmq)\n  set_target_properties(${test} PROPERTIES LINK_LIBRARIES \"${LIBS}\")\nendforeach()\n\n# Check whether all tests in the current folder are present TODO duplicated with tests/CMakeLists.txt, define as a\n# function?\nfile(READ \"${CMAKE_CURRENT_LIST_FILE}\" CURRENT_LIST_FILE_CONTENT)\nfile(GLOB ALL_TEST_SOURCES \"test_*.cpp\")\nforeach(TEST_SOURCE ${ALL_TEST_SOURCES})\n  get_filename_component(TESTNAME \"${TEST_SOURCE}\" NAME_WE)\n  string(REGEX MATCH \"${TESTNAME}\" MATCH_TESTNAME \"${CURRENT_LIST_FILE_CONTENT}\")\n  if(NOT MATCH_TESTNAME)\n    message(AUTHOR_WARNING \"Test '${TESTNAME}' is not known to CTest.\")\n  endif()\nendforeach()\n"
  },
  {
    "path": "unittests/unittest_curve_encoding.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../tests/testutil_unity.hpp\"\n\n// TODO: remove this ugly hack\n#ifdef close\n#undef close\n#endif\n\n#include <curve_mechanism_base.hpp>\n#include <msg.hpp>\n#include <random.hpp>\n\n#include <unity.h>\n\n#include <vector>\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\nvoid test_roundtrip (zmq::msg_t *msg_)\n{\n#ifdef ZMQ_HAVE_CURVE\n    const std::vector<uint8_t> original (static_cast<uint8_t *> (msg_->data ()),\n                                         static_cast<uint8_t *> (msg_->data ())\n                                           + msg_->size ());\n\n    zmq::curve_encoding_t encoding_client (\"CurveZMQMESSAGEC\",\n                                           \"CurveZMQMESSAGES\", false);\n    zmq::curve_encoding_t encoding_server (\"CurveZMQMESSAGES\",\n                                           \"CurveZMQMESSAGEC\", false);\n\n    uint8_t client_public[32];\n    uint8_t client_secret[32];\n    TEST_ASSERT_SUCCESS_ERRNO (\n      crypto_box_keypair (client_public, client_secret));\n\n    uint8_t server_public[32];\n    uint8_t server_secret[32];\n    TEST_ASSERT_SUCCESS_ERRNO (\n      crypto_box_keypair (server_public, server_secret));\n\n    TEST_ASSERT_SUCCESS_ERRNO (\n      crypto_box_beforenm (encoding_client.get_writable_precom_buffer (),\n                           server_public, client_secret));\n    TEST_ASSERT_SUCCESS_ERRNO (\n      crypto_box_beforenm (encoding_server.get_writable_precom_buffer (),\n                           client_public, server_secret));\n\n    TEST_ASSERT_SUCCESS_ERRNO (encoding_client.encode (msg_));\n\n    // TODO: This is hacky...\n    encoding_server.set_peer_nonce (0);\n    int error_event_code;\n    TEST_ASSERT_SUCCESS_ERRNO (\n      encoding_server.decode (msg_, &error_event_code));\n\n    TEST_ASSERT_EQUAL_INT (original.size (), msg_->size ());\n    if (!original.empty ()) {\n        TEST_ASSERT_EQUAL_UINT8_ARRAY (&original[0], msg_->data (),\n                                       original.size ());\n    }\n#else\n    LIBZMQ_UNUSED (msg_);\n#endif\n}\n\nvoid test_roundtrip_empty ()\n{\n#ifndef ZMQ_HAVE_CURVE\n    TEST_IGNORE_MESSAGE (\"CURVE support is disabled\");\n#endif\n    zmq::msg_t msg;\n    msg.init ();\n\n    test_roundtrip (&msg);\n\n    msg.close ();\n}\n\nvoid test_roundtrip_small ()\n{\n#ifndef ZMQ_HAVE_CURVE\n    TEST_IGNORE_MESSAGE (\"CURVE support is disabled\");\n#endif\n    zmq::msg_t msg;\n    msg.init_size (32);\n    memcpy (msg.data (), \"0123456789ABCDEF0123456789ABCDEF\", 32);\n\n    test_roundtrip (&msg);\n\n    msg.close ();\n}\n\nvoid test_roundtrip_large ()\n{\n#ifndef ZMQ_HAVE_CURVE\n    TEST_IGNORE_MESSAGE (\"CURVE support is disabled\");\n#endif\n    zmq::msg_t msg;\n    msg.init_size (2048);\n    for (size_t pos = 0; pos < 2048; pos += 32) {\n        memcpy (static_cast<char *> (msg.data ()) + pos,\n                \"0123456789ABCDEF0123456789ABCDEF\", 32);\n    }\n\n    test_roundtrip (&msg);\n\n    msg.close ();\n}\n\nvoid test_roundtrip_empty_more ()\n{\n#ifndef ZMQ_HAVE_CURVE\n    TEST_IGNORE_MESSAGE (\"CURVE support is disabled\");\n#endif\n    zmq::msg_t msg;\n    msg.init ();\n    msg.set_flags (zmq::msg_t::more);\n\n    test_roundtrip (&msg);\n    TEST_ASSERT_TRUE (msg.flags () & zmq::msg_t::more);\n\n    msg.close ();\n}\n\nint main ()\n{\n    setup_test_environment ();\n    zmq::random_open ();\n\n    UNITY_BEGIN ();\n\n    RUN_TEST (test_roundtrip_empty);\n    RUN_TEST (test_roundtrip_small);\n    RUN_TEST (test_roundtrip_large);\n\n    RUN_TEST (test_roundtrip_empty_more);\n\n    zmq::random_close ();\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "unittests/unittest_ip_resolver.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include <unity.h>\n#include \"../src/macros.hpp\"\n#include \"../tests/testutil.hpp\"\n#include \"../tests/testutil_unity.hpp\"\n#include \"../unittests/unittest_resolver_common.hpp\"\n\n#include <ip_resolver.hpp>\n#include <ip.hpp>\n\n#ifndef _WIN32\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netdb.h>\n#endif\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\nclass test_ip_resolver_t ZMQ_FINAL : public zmq::ip_resolver_t\n{\n  public:\n    test_ip_resolver_t (zmq::ip_resolver_options_t opts_) :\n        ip_resolver_t (opts_)\n    {\n    }\n\n  protected:\n    struct dns_lut_t\n    {\n        const char *hostname;\n        const char *ipv4;\n        const char *ipv6;\n    };\n\n    int do_getaddrinfo (const char *node_,\n                        const char *service_,\n                        const struct addrinfo *hints_,\n                        struct addrinfo **res_) ZMQ_FINAL\n    {\n        static const struct dns_lut_t dns_lut[] = {\n          {\"ip.zeromq.org\", \"10.100.0.1\", \"fdf5:d058:d656::1\"},\n          {\"ipv4only.zeromq.org\", \"10.100.0.2\", \"::ffff:10.100.0.2\"},\n          {\"ipv6only.zeromq.org\", NULL, \"fdf5:d058:d656::2\"},\n        };\n        unsigned lut_len = sizeof (dns_lut) / sizeof (dns_lut[0]);\n        struct addrinfo ai;\n\n        TEST_ASSERT_NULL (service_);\n\n        bool ipv6 = (hints_->ai_family == AF_INET6);\n        bool no_dns = (hints_->ai_flags & AI_NUMERICHOST) != 0;\n        const char *ip = NULL;\n\n        if (!no_dns) {\n            for (unsigned i = 0; i < lut_len; i++) {\n                if (strcmp (dns_lut[i].hostname, node_) == 0) {\n                    if (ipv6) {\n                        ip = dns_lut[i].ipv6;\n                    } else {\n                        ip = dns_lut[i].ipv4;\n\n                        if (ip == NULL) {\n                            //  No address associated with NAME\n                            return EAI_NODATA;\n                        }\n                    }\n                }\n            }\n        }\n\n        if (ip == NULL) {\n            //  No entry for 'node_' found in the LUT (or DNS is\n            //  forbidden), assume that it's a numeric IP address\n            ip = node_;\n        }\n\n        //  Call the real getaddrinfo implementation, making sure that it won't\n        //  attempt to resolve using DNS\n        ai = *hints_;\n        ai.ai_flags |= AI_NUMERICHOST;\n\n        return zmq::ip_resolver_t::do_getaddrinfo (ip, NULL, &ai, res_);\n    }\n\n    unsigned int do_if_nametoindex (const char *ifname_) ZMQ_FINAL\n    {\n        static const char *dummy_interfaces[] = {\n          \"lo0\",\n          \"eth0\",\n          \"eth1\",\n        };\n        unsigned lut_len =\n          sizeof (dummy_interfaces) / sizeof (dummy_interfaces[0]);\n\n        for (unsigned i = 0; i < lut_len; i++) {\n            if (strcmp (dummy_interfaces[i], ifname_) == 0) {\n                //  The dummy index will be the position in the array + 1 (0 is\n                //  invalid)\n                return i + 1;\n            }\n        }\n\n        //  Not found\n        return 0;\n    }\n};\n\n//  Attempt a resolution and test the results. If 'expected_addr_' is NULL\n//  assume that the resolution is meant to fail.\n//\n//  On windows we can receive an IPv4 address even when an IPv6 is requested, if\n//  we're in this situation then we compare to 'expected_addr_v4_failover_'\n//  instead.\nstatic void test_resolve (zmq::ip_resolver_options_t opts_,\n                          const char *name_,\n                          const char *expected_addr_,\n                          uint16_t expected_port_ = 0,\n                          uint16_t expected_zone_ = 0,\n                          const char *expected_addr_v4_failover_ = NULL)\n{\n    zmq::ip_addr_t addr;\n    int family = opts_.ipv6 () ? AF_INET6 : AF_INET;\n\n    if (family == AF_INET6 && !is_ipv6_available ()) {\n        TEST_IGNORE_MESSAGE (\"ipv6 is not available\");\n    }\n\n    //  Generate an invalid but well-defined 'ip_addr_t'. Avoids testing\n    //  uninitialized values if the code is buggy.\n    memset (&addr, 0xba, sizeof (addr));\n\n    test_ip_resolver_t resolver (opts_);\n\n    int rc = resolver.resolve (&addr, name_);\n\n    if (expected_addr_ == NULL) {\n        // TODO also check the expected errno\n        TEST_ASSERT_EQUAL (-1, rc);\n        return;\n    }\n    TEST_ASSERT_SUCCESS_ERRNO (rc);\n\n\n    validate_address (family, &addr, expected_addr_, expected_port_,\n                      expected_zone_, expected_addr_v4_failover_);\n}\n\n// Helper macro to define the v4/v6 function pairs\n#define MAKE_TEST_V4V6(_test)                                                  \\\n    static void _test##_ipv4 () { _test (false); }                             \\\n                                                                               \\\n    static void _test##_ipv6 () { _test (true); }\n\nstatic void test_bind_any (bool ipv6_)\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.bindable (true).expect_port (true).ipv6 (ipv6_);\n\n    const char *expected = ipv6_ ? \"::\" : \"0.0.0.0\";\n    test_resolve (resolver_opts, \"*:*\", expected, 0);\n}\nMAKE_TEST_V4V6 (test_bind_any)\n\nstatic void test_bind_any_port0 (bool ipv6_)\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.bindable (true).expect_port (true).ipv6 (ipv6_);\n\n    //  Should be equivalent to \"*:*\"\n    const char *expected = ipv6_ ? \"::\" : \"0.0.0.0\";\n    test_resolve (resolver_opts, \"*:0\", expected, 0);\n}\nMAKE_TEST_V4V6 (test_bind_any_port0)\n\nstatic void test_nobind_any (bool ipv6_)\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true).ipv6 (ipv6_);\n\n    //  Wildcard should be rejected if we're not looking for a\n    //  bindable address\n    test_resolve (resolver_opts, \"*:*\", NULL);\n}\nMAKE_TEST_V4V6 (test_nobind_any)\n\nstatic void test_nobind_any_port (bool ipv6_)\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true).ipv6 (ipv6_);\n\n    //  Wildcard should be rejected if we're not looking for a\n    //  bindable address\n    test_resolve (resolver_opts, \"*:1234\", NULL);\n}\nMAKE_TEST_V4V6 (test_nobind_any_port)\n\nstatic void test_nobind_addr_anyport (bool ipv6_)\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true).ipv6 (ipv6_);\n\n    //  Wildcard port should be rejected for non-bindable addresses\n    test_resolve (resolver_opts, \"127.0.0.1:*\", NULL);\n}\nMAKE_TEST_V4V6 (test_nobind_addr_anyport)\n\nstatic void test_nobind_addr_port0 (bool ipv6_)\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true).ipv6 (ipv6_);\n\n    //  Connecting to port 0 is allowed, although it might not be massively\n    //  useful\n    const char *expected = ipv6_ ? \"::ffff:127.0.0.1\" : \"127.0.0.1\";\n    const char *fallback = ipv6_ ? \"127.0.0.1\" : NULL;\n    test_resolve (resolver_opts, \"127.0.0.1:0\", expected, 0, 0, fallback);\n}\nMAKE_TEST_V4V6 (test_nobind_addr_port0)\n\nstatic void test_parse_ipv4_simple ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    test_resolve (resolver_opts, \"1.2.128.129\", \"1.2.128.129\");\n}\n\nstatic void test_parse_ipv4_zero ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    test_resolve (resolver_opts, \"0.0.0.0\", \"0.0.0.0\");\n}\n\nstatic void test_parse_ipv4_max ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    test_resolve (resolver_opts, \"255.255.255.255\", \"255.255.255.255\");\n}\n\nstatic void test_parse_ipv4_brackets ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    //  Not particularly useful, but valid\n    test_resolve (resolver_opts, \"[1.2.128.129]\", \"1.2.128.129\");\n}\n\nstatic void test_parse_ipv4_brackets_missingl ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    test_resolve (resolver_opts, \"1.2.128.129]\", NULL);\n}\n\nstatic void test_parse_ipv4_brackets_missingr ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    test_resolve (resolver_opts, \"[1.2.128.129\", NULL);\n}\n\nstatic void test_parse_ipv4_brackets_bad ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    test_resolve (resolver_opts, \"[1.2.128].129\", NULL);\n}\n\nstatic void test_parse_ipv4_reject_port ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    //  No port expected, should be rejected\n    test_resolve (resolver_opts, \"1.2.128.129:123\", NULL);\n}\n\nstatic void test_parse_ipv4_reject_any ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    //  No port expected, should be rejected\n    test_resolve (resolver_opts, \"1.2.128.129:*\", NULL);\n}\n\nstatic void test_parse_ipv4_reject_ipv6 ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    //  No port expected, should be rejected\n    test_resolve (resolver_opts, \"::1\", NULL);\n}\n\nstatic void test_parse_ipv4_port ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true);\n\n    test_resolve (resolver_opts, \"1.2.128.129:123\", \"1.2.128.129\", 123);\n}\n\nstatic void test_parse_ipv4_port0 ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true);\n\n    //  Port 0 is accepted and is equivalent to *\n    test_resolve (resolver_opts, \"1.2.128.129:0\", \"1.2.128.129\", 0);\n}\n\nstatic void test_parse_ipv4_port_garbage ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true);\n\n    //  The code doesn't validate that the port doesn't contain garbage\n    test_resolve (resolver_opts, \"1.2.3.4:567bad\", \"1.2.3.4\", 567);\n}\n\nstatic void test_parse_ipv4_port_missing ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true);\n\n    test_resolve (resolver_opts, \"1.2.3.4\", NULL);\n}\n\nstatic void test_parse_ipv4_port_bad ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true);\n\n    test_resolve (resolver_opts, \"1.2.3.4:bad\", NULL);\n}\n\nstatic void test_parse_ipv4_port_brackets ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true);\n\n    test_resolve (resolver_opts, \"[192.168.1.1]:5555\", \"192.168.1.1\", 5555);\n}\n\nstatic void test_parse_ipv4_port_brackets_bad ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true);\n\n    test_resolve (resolver_opts, \"[192.168.1.1:]5555\", NULL);\n}\n\nstatic void test_parse_ipv4_port_brackets_bad2 ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true);\n\n    test_resolve (resolver_opts, \"[192.168.1.1:5555]\", NULL);\n}\n\nstatic void test_parse_ipv4_wild_brackets_bad ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true);\n\n    test_resolve (resolver_opts, \"[192.168.1.1:*]\", NULL);\n}\n\nstatic void test_parse_ipv4_port_ipv6_reject ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true);\n\n    test_resolve (resolver_opts, \"[::1]:1234\", NULL);\n}\n\nstatic void test_parse_ipv6_simple ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"::1\", \"::1\");\n}\n\nstatic void test_parse_ipv6_simple2 ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"abcd:1234::1:0:234\", \"abcd:1234::1:0:234\");\n}\n\nstatic void test_parse_ipv6_zero ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"::\", \"::\");\n}\n\nstatic void test_parse_ipv6_max ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\",\n                  \"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\");\n}\n\nstatic void test_parse_ipv6_brackets ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"[::1]\", \"::1\");\n}\n\nstatic void test_parse_ipv6_brackets_missingl ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"::1]\", NULL);\n}\n\nstatic void test_parse_ipv6_brackets_missingr ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"[::1\", NULL);\n}\n\nstatic void test_parse_ipv6_brackets_bad ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"[abcd:1234::1:]0:234\", NULL);\n}\n\nstatic void test_parse_ipv6_port ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true).expect_port (true);\n\n    test_resolve (resolver_opts, \"[1234::1]:80\", \"1234::1\", 80);\n}\n\nstatic void test_parse_ipv6_port_any ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true).expect_port (true).bindable (true);\n\n    test_resolve (resolver_opts, \"[1234::1]:*\", \"1234::1\", 0);\n}\n\nstatic void test_parse_ipv6_port_nobrackets ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true).expect_port (true);\n\n    //  Should this be allowed? Seems error-prone but so far ZMQ accepts it.\n    test_resolve (resolver_opts, \"abcd:1234::1:0:234:123\", \"abcd:1234::1:0:234\",\n                  123);\n}\n\nstatic void test_parse_ipv4_in_ipv6 ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    //  Parsing IPv4 should also work if an IPv6 is requested, it returns an\n    //  IPv6 with the IPv4 address embedded (except sometimes on Windows where\n    //  we end up with an IPv4 anyway)\n    test_resolve (resolver_opts, \"11.22.33.44\", \"::ffff:11.22.33.44\", 0, 0,\n                  \"11.22.33.44\");\n}\n\nstatic void test_parse_ipv4_in_ipv6_port ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true).expect_port (true);\n\n    test_resolve (resolver_opts, \"11.22.33.44:55\", \"::ffff:11.22.33.44\", 55, 0,\n                  \"11.22.33.44\");\n}\n\nstatic void test_parse_ipv6_scope_int ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"3000:4:5::1:234%2\", \"3000:4:5::1:234\", 0, 2);\n}\n\nstatic void test_parse_ipv6_scope_zero ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"3000:4:5::1:234%0\", NULL);\n}\n\nstatic void test_parse_ipv6_scope_int_port ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true).ipv6 (true);\n\n    test_resolve (resolver_opts, \"3000:4:5::1:234%2:1111\", \"3000:4:5::1:234\",\n                  1111, 2);\n}\n\nstatic void test_parse_ipv6_scope_if ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"3000:4:5::1:234%eth1\", \"3000:4:5::1:234\", 0,\n                  3);\n}\n\nstatic void test_parse_ipv6_scope_if_port ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true).ipv6 (true);\n\n    test_resolve (resolver_opts, \"3000:4:5::1:234%eth0:8080\", \"3000:4:5::1:234\",\n                  8080, 2);\n}\n\nstatic void test_parse_ipv6_scope_if_port_brackets ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true).ipv6 (true);\n\n    test_resolve (resolver_opts, \"[3000:4:5::1:234%eth0]:8080\",\n                  \"3000:4:5::1:234\", 8080, 2);\n}\n\nstatic void test_parse_ipv6_scope_badif ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true);\n\n    test_resolve (resolver_opts, \"3000:4:5::1:234%bad0\", NULL);\n}\n\nstatic void test_dns_ipv4_simple ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true);\n\n    test_resolve (resolver_opts, \"ip.zeromq.org\", \"10.100.0.1\");\n}\n\nstatic void test_dns_ipv4_only ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true);\n\n    test_resolve (resolver_opts, \"ipv4only.zeromq.org\", \"10.100.0.2\");\n}\n\nstatic void test_dns_ipv4_invalid ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true);\n\n    test_resolve (resolver_opts, \"invalid.zeromq.org\", NULL);\n}\n\nstatic void test_dns_ipv4_ipv6 ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true);\n\n    test_resolve (resolver_opts, \"ipv6only.zeromq.org\", NULL);\n}\n\nstatic void test_dns_ipv4_numeric ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true);\n\n    //  Numeric IPs should still work\n    test_resolve (resolver_opts, \"5.4.3.2\", \"5.4.3.2\");\n}\n\nstatic void test_dns_ipv4_port ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.expect_port (true).allow_dns (true);\n\n    test_resolve (resolver_opts, \"ip.zeromq.org:1234\", \"10.100.0.1\", 1234);\n}\n\nstatic void test_dns_ipv6_simple ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true).allow_dns (true);\n\n    test_resolve (resolver_opts, \"ip.zeromq.org\", \"fdf5:d058:d656::1\");\n}\n\nstatic void test_dns_ipv6_only ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true).allow_dns (true);\n\n    test_resolve (resolver_opts, \"ipv6only.zeromq.org\", \"fdf5:d058:d656::2\");\n}\n\nstatic void test_dns_ipv6_invalid ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true).allow_dns (true);\n\n    test_resolve (resolver_opts, \"invalid.zeromq.org\", NULL);\n}\n\nstatic void test_dns_ipv6_ipv4 ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true).allow_dns (true);\n\n    //  If a host doesn't have an IPv6 then it should resolve as an embedded v4\n    //  address in an IPv6\n    test_resolve (resolver_opts, \"ipv4only.zeromq.org\", \"::ffff:10.100.0.2\");\n}\n\nstatic void test_dns_ipv6_numeric ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true).allow_dns (true);\n\n    //  Numeric IPs should still work\n    test_resolve (resolver_opts, \"fdf5:d058:d656::1\", \"fdf5:d058:d656::1\");\n}\n\nstatic void test_dns_ipv6_port ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (true).expect_port (true).allow_dns (true);\n\n    test_resolve (resolver_opts, \"ip.zeromq.org:1234\", \"fdf5:d058:d656::1\",\n                  1234);\n}\n\nvoid test_dns_brackets ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true);\n\n    test_resolve (resolver_opts, \"[ip.zeromq.org]\", \"10.100.0.1\");\n}\n\nvoid test_dns_brackets_bad ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true);\n\n    test_resolve (resolver_opts, \"[ip.zeromq].org\", NULL);\n}\n\nvoid test_dns_brackets_port ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true);\n\n    test_resolve (resolver_opts, \"[ip.zeromq.org]:22\", \"10.100.0.1\", 22);\n}\n\nvoid test_dns_brackets_port_bad ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true);\n\n    test_resolve (resolver_opts, \"[ip.zeromq.org:22]\", NULL);\n}\n\nvoid test_dns_deny (bool ipv6_)\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (false).ipv6 (ipv6_);\n\n    //  DNS resolution shouldn't work when disallowed\n    test_resolve (resolver_opts, \"ip.zeromq.org\", NULL);\n}\nMAKE_TEST_V4V6 (test_dns_deny)\n\nvoid test_dns_ipv6_scope ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true).ipv6 (true);\n\n    //  Not sure if that's very useful but you could technically add a scope\n    //  identifier to a hostname\n    test_resolve (resolver_opts, \"ip.zeromq.org%lo0\", \"fdf5:d058:d656::1\", 0,\n                  1);\n}\n\nvoid test_dns_ipv6_scope_port ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true).expect_port (true).ipv6 (true);\n\n    //  Not sure if that's very useful but you could technically add a scope\n    //  identifier to a hostname\n    test_resolve (resolver_opts, \"ip.zeromq.org%lo0:4444\", \"fdf5:d058:d656::1\",\n                  4444, 1);\n}\n\nvoid test_dns_ipv6_scope_port_brackets ()\n{\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.allow_dns (true).expect_port (true).ipv6 (true);\n\n    test_resolve (resolver_opts, \"[ip.zeromq.org%lo0]:4444\",\n                  \"fdf5:d058:d656::1\", 4444, 1);\n}\n\nstatic void test_addr (int family_, const char *addr_, bool multicast_)\n{\n    if (family_ == AF_INET6 && !is_ipv6_available ()) {\n        TEST_IGNORE_MESSAGE (\"ipv6 is not available\");\n    }\n\n    zmq::ip_resolver_options_t resolver_opts;\n\n    resolver_opts.ipv6 (family_ == AF_INET6);\n\n    test_ip_resolver_t resolver (resolver_opts);\n    zmq::ip_addr_t addr;\n\n    TEST_ASSERT_SUCCESS_ERRNO (resolver.resolve (&addr, addr_));\n\n    TEST_ASSERT_EQUAL (family_, addr.family ());\n    TEST_ASSERT_EQUAL (multicast_, addr.is_multicast ());\n}\n\nstatic void test_addr_unicast_ipv4 ()\n{\n    test_addr (AF_INET, \"1.2.3.4\", false);\n}\n\nstatic void test_addr_unicast_ipv6 ()\n{\n    test_addr (AF_INET6, \"abcd::1\", false);\n}\n\nstatic void test_addr_multicast_ipv4 ()\n{\n    test_addr (AF_INET, \"230.1.2.3\", true);\n}\n\nstatic void test_addr_multicast_ipv6 ()\n{\n    test_addr (AF_INET6, \"ffab::1234\", true);\n}\n\nstatic void test_addr_multicast_ipv4_min ()\n{\n    test_addr (AF_INET, \"224.0.0.0\", true);\n}\n\nstatic void test_addr_multicast_ipv6_min ()\n{\n    test_addr (AF_INET6, \"ff00::\", true);\n}\n\nstatic void test_addr_multicast_ipv4_max ()\n{\n    test_addr (AF_INET, \"239.255.255.255\", true);\n}\n\nstatic void test_addr_multicast_ipv6_max ()\n{\n    test_addr (AF_INET6, \"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\", true);\n}\n\nstatic void test_addr_multicast_ipv4_sub ()\n{\n    test_addr (AF_INET, \"223.255.255.255\", false);\n}\n\nstatic void test_addr_multicast_ipv6_sub ()\n{\n    test_addr (AF_INET6, \"feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\", false);\n}\n\nstatic void test_addr_multicast_ipv4_over ()\n{\n    test_addr (AF_INET, \"240.0.0.0\", false);\n}\n\nint main (void)\n{\n    zmq::initialize_network ();\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n\n    RUN_TEST (test_bind_any_ipv4);\n    RUN_TEST (test_bind_any_ipv6);\n    RUN_TEST (test_bind_any_port0_ipv4);\n    RUN_TEST (test_bind_any_port0_ipv6);\n    RUN_TEST (test_nobind_any_ipv4);\n    RUN_TEST (test_nobind_any_ipv6);\n    RUN_TEST (test_nobind_any_port_ipv4);\n    RUN_TEST (test_nobind_any_port_ipv6);\n    RUN_TEST (test_nobind_addr_anyport_ipv4);\n    RUN_TEST (test_nobind_addr_anyport_ipv6);\n    RUN_TEST (test_nobind_addr_port0_ipv4);\n    RUN_TEST (test_nobind_addr_port0_ipv6);\n    RUN_TEST (test_parse_ipv4_simple);\n    RUN_TEST (test_parse_ipv4_zero);\n    RUN_TEST (test_parse_ipv4_max);\n    RUN_TEST (test_parse_ipv4_brackets);\n    RUN_TEST (test_parse_ipv4_brackets_missingl);\n    RUN_TEST (test_parse_ipv4_brackets_missingr);\n    RUN_TEST (test_parse_ipv4_brackets_bad);\n    RUN_TEST (test_parse_ipv4_reject_port);\n    RUN_TEST (test_parse_ipv4_reject_any);\n    RUN_TEST (test_parse_ipv4_reject_ipv6);\n    RUN_TEST (test_parse_ipv4_port);\n    RUN_TEST (test_parse_ipv4_port0);\n    RUN_TEST (test_parse_ipv4_port_garbage);\n    RUN_TEST (test_parse_ipv4_port_missing);\n    RUN_TEST (test_parse_ipv4_port_bad);\n    RUN_TEST (test_parse_ipv4_port_brackets);\n    RUN_TEST (test_parse_ipv4_port_brackets_bad);\n    RUN_TEST (test_parse_ipv4_port_brackets_bad2);\n    RUN_TEST (test_parse_ipv4_wild_brackets_bad);\n    RUN_TEST (test_parse_ipv4_port_ipv6_reject);\n    RUN_TEST (test_parse_ipv6_simple);\n    RUN_TEST (test_parse_ipv6_simple2);\n    RUN_TEST (test_parse_ipv6_zero);\n    RUN_TEST (test_parse_ipv6_max);\n    RUN_TEST (test_parse_ipv6_brackets);\n    RUN_TEST (test_parse_ipv6_brackets_missingl);\n    RUN_TEST (test_parse_ipv6_brackets_missingr);\n    RUN_TEST (test_parse_ipv6_brackets_bad);\n    RUN_TEST (test_parse_ipv6_port);\n    RUN_TEST (test_parse_ipv6_port_any);\n    RUN_TEST (test_parse_ipv6_port_nobrackets);\n    RUN_TEST (test_parse_ipv4_in_ipv6);\n    RUN_TEST (test_parse_ipv4_in_ipv6_port);\n    RUN_TEST (test_parse_ipv6_scope_int);\n    RUN_TEST (test_parse_ipv6_scope_zero);\n    RUN_TEST (test_parse_ipv6_scope_int_port);\n    RUN_TEST (test_parse_ipv6_scope_if);\n    RUN_TEST (test_parse_ipv6_scope_if_port);\n    RUN_TEST (test_parse_ipv6_scope_if_port_brackets);\n    RUN_TEST (test_parse_ipv6_scope_badif);\n    RUN_TEST (test_dns_ipv4_simple);\n    RUN_TEST (test_dns_ipv4_only);\n    RUN_TEST (test_dns_ipv4_invalid);\n    RUN_TEST (test_dns_ipv4_ipv6);\n    RUN_TEST (test_dns_ipv4_numeric);\n    RUN_TEST (test_dns_ipv4_port);\n    RUN_TEST (test_dns_ipv6_simple);\n    RUN_TEST (test_dns_ipv6_only);\n    RUN_TEST (test_dns_ipv6_invalid);\n    RUN_TEST (test_dns_ipv6_ipv4);\n    RUN_TEST (test_dns_ipv6_numeric);\n    RUN_TEST (test_dns_ipv6_port);\n    RUN_TEST (test_dns_brackets);\n    RUN_TEST (test_dns_brackets_bad);\n    RUN_TEST (test_dns_deny_ipv4);\n    RUN_TEST (test_dns_deny_ipv6);\n    RUN_TEST (test_dns_ipv6_scope);\n    RUN_TEST (test_dns_ipv6_scope_port);\n    RUN_TEST (test_dns_ipv6_scope_port_brackets);\n    RUN_TEST (test_addr_unicast_ipv4);\n    RUN_TEST (test_addr_unicast_ipv6);\n    RUN_TEST (test_addr_multicast_ipv4);\n    RUN_TEST (test_addr_multicast_ipv6);\n    RUN_TEST (test_addr_multicast_ipv4_min);\n    RUN_TEST (test_addr_multicast_ipv6_min);\n    RUN_TEST (test_addr_multicast_ipv4_max);\n    RUN_TEST (test_addr_multicast_ipv6_max);\n    RUN_TEST (test_addr_multicast_ipv4_sub);\n    RUN_TEST (test_addr_multicast_ipv6_sub);\n    RUN_TEST (test_addr_multicast_ipv4_over);\n\n    zmq::shutdown_network ();\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "unittests/unittest_mtrie.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../tests/testutil.hpp\"\n\n#if defined(min)\n#undef min\n#endif\n\n#include <generic_mtrie_impl.hpp>\n\n#include <unity.h>\n\nvoid setUp ()\n{\n}\nvoid tearDown ()\n{\n}\n\nint getlen (const zmq::generic_mtrie_t<int>::prefix_t &data_)\n{\n    return static_cast<int> (strlen (reinterpret_cast<const char *> (data_)));\n}\n\nvoid test_create ()\n{\n    zmq::generic_mtrie_t<int> mtrie;\n}\n\nvoid mtrie_count (int *pipe_, int *count_)\n{\n    LIBZMQ_UNUSED (pipe_);\n    ++*count_;\n}\n\nvoid test_check_empty_match_nonempty_data ()\n{\n    zmq::generic_mtrie_t<int> mtrie;\n    const zmq::generic_mtrie_t<int>::prefix_t test_name =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (\"foo\");\n\n    int count = 0;\n    mtrie.match (test_name, getlen (test_name), mtrie_count, &count);\n    TEST_ASSERT_EQUAL_INT (0, count);\n}\n\nvoid test_check_empty_match_empty_data ()\n{\n    zmq::generic_mtrie_t<int> mtrie;\n\n    int count = 0;\n    mtrie.match (NULL, 0, mtrie_count, &count);\n    TEST_ASSERT_EQUAL_INT (0, count);\n}\n\nvoid test_add_single_entry_match_exact ()\n{\n    int pipe;\n\n    zmq::generic_mtrie_t<int> mtrie;\n    const zmq::generic_mtrie_t<int>::prefix_t test_name =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (\"foo\");\n\n    bool res = mtrie.add (test_name, getlen (test_name), &pipe);\n    TEST_ASSERT_TRUE (res);\n\n    TEST_ASSERT_EQUAL_INT (1, mtrie.num_prefixes ());\n\n    int count = 0;\n    mtrie.match (test_name, getlen (test_name), mtrie_count, &count);\n    TEST_ASSERT_EQUAL_INT (1, count);\n}\n\nvoid test_add_single_entry_twice_match_exact ()\n{\n    int pipe;\n\n    zmq::generic_mtrie_t<int> mtrie;\n    const zmq::generic_mtrie_t<int>::prefix_t test_name =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (\"foo\");\n\n    bool res = mtrie.add (test_name, getlen (test_name), &pipe);\n    TEST_ASSERT_TRUE (res);\n    TEST_ASSERT_EQUAL_INT (1, mtrie.num_prefixes ());\n\n    res = mtrie.add (test_name, getlen (test_name), &pipe);\n    TEST_ASSERT_FALSE (res);\n    TEST_ASSERT_EQUAL_INT (1, mtrie.num_prefixes ());\n\n    int count = 0;\n    mtrie.match (test_name, getlen (test_name), mtrie_count, &count);\n    TEST_ASSERT_EQUAL_INT (1, count);\n}\n\nvoid test_add_two_entries_with_same_name_match_exact ()\n{\n    int pipe_1, pipe_2;\n\n    zmq::generic_mtrie_t<int> mtrie;\n    const zmq::generic_mtrie_t<int>::prefix_t test_name =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (\"foo\");\n\n    bool res = mtrie.add (test_name, getlen (test_name), &pipe_1);\n    TEST_ASSERT_TRUE (res);\n    TEST_ASSERT_EQUAL_INT (1, mtrie.num_prefixes ());\n\n    res = mtrie.add (test_name, getlen (test_name), &pipe_2);\n    TEST_ASSERT_FALSE (res);\n    TEST_ASSERT_EQUAL_INT (1, mtrie.num_prefixes ());\n\n    int count = 0;\n    mtrie.match (test_name, getlen (test_name), mtrie_count, &count);\n    TEST_ASSERT_EQUAL_INT (2, count);\n}\n\nvoid test_add_two_entries_match_prefix_and_exact ()\n{\n    int pipe_1, pipe_2;\n\n    zmq::generic_mtrie_t<int> mtrie;\n    const zmq::generic_mtrie_t<int>::prefix_t test_name_prefix =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (\"foo\");\n    const zmq::generic_mtrie_t<int>::prefix_t test_name_full =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (\"foobar\");\n\n    bool res = mtrie.add (test_name_prefix, getlen (test_name_prefix), &pipe_1);\n    TEST_ASSERT_TRUE (res);\n    TEST_ASSERT_EQUAL_INT (1, mtrie.num_prefixes ());\n\n    res = mtrie.add (test_name_full, getlen (test_name_full), &pipe_2);\n    TEST_ASSERT_TRUE (res);\n    TEST_ASSERT_EQUAL_INT (2, mtrie.num_prefixes ());\n\n    int count = 0;\n    mtrie.match (test_name_full, getlen (test_name_full), mtrie_count, &count);\n    TEST_ASSERT_EQUAL_INT (2, count);\n}\n\nvoid test_add_rm_single_entry_match_exact ()\n{\n    int pipe;\n    zmq::generic_mtrie_t<int> mtrie;\n    const zmq::generic_mtrie_t<int>::prefix_t test_name =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (\"foo\");\n\n    mtrie.add (test_name, getlen (test_name), &pipe);\n    TEST_ASSERT_EQUAL_INT (1, mtrie.num_prefixes ());\n    zmq::generic_mtrie_t<int>::rm_result res =\n      mtrie.rm (test_name, getlen (test_name), &pipe);\n    TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::last_value_removed, res);\n    TEST_ASSERT_EQUAL_INT (0, mtrie.num_prefixes ());\n\n    int count = 0;\n    mtrie.match (test_name, getlen (test_name), mtrie_count, &count);\n    TEST_ASSERT_EQUAL_INT (0, count);\n}\n\nvoid test_rm_nonexistent_0_size_empty ()\n{\n    int pipe;\n    zmq::generic_mtrie_t<int> mtrie;\n\n    zmq::generic_mtrie_t<int>::rm_result res = mtrie.rm (0, 0, &pipe);\n    TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::not_found, res);\n    TEST_ASSERT_EQUAL_INT (0, mtrie.num_prefixes ());\n}\n\nvoid test_rm_nonexistent_empty ()\n{\n    int pipe;\n    zmq::generic_mtrie_t<int> mtrie;\n    const zmq::generic_mtrie_t<int>::prefix_t test_name =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (\"foo\");\n\n    zmq::generic_mtrie_t<int>::rm_result res =\n      mtrie.rm (test_name, getlen (test_name), &pipe);\n    TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::not_found, res);\n    TEST_ASSERT_EQUAL_INT (0, mtrie.num_prefixes ());\n\n    int count = 0;\n    mtrie.match (test_name, getlen (test_name), mtrie_count, &count);\n    TEST_ASSERT_EQUAL_INT (0, count);\n}\n\nvoid test_add_and_rm_other (const char *add_name_, const char *rm_name_)\n{\n    int addpipe, rmpipe;\n    zmq::generic_mtrie_t<int> mtrie;\n    const zmq::generic_mtrie_t<int>::prefix_t add_name_data =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (add_name_);\n    const zmq::generic_mtrie_t<int>::prefix_t rm_name_data =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (rm_name_);\n\n    mtrie.add (add_name_data, getlen (add_name_data), &addpipe);\n    TEST_ASSERT_EQUAL_INT (1, mtrie.num_prefixes ());\n\n    zmq::generic_mtrie_t<int>::rm_result res =\n      mtrie.rm (rm_name_data, getlen (rm_name_data), &rmpipe);\n    TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::not_found, res);\n    TEST_ASSERT_EQUAL_INT (1, mtrie.num_prefixes ());\n\n    {\n        int count = 0;\n        mtrie.match (add_name_data, getlen (add_name_data), mtrie_count,\n                     &count);\n        TEST_ASSERT_EQUAL_INT (1, count);\n    }\n\n    if (strncmp (add_name_, rm_name_,\n                 std::min (strlen (add_name_), strlen (rm_name_) + 1))\n        != 0) {\n        int count = 0;\n        mtrie.match (rm_name_data, getlen (rm_name_data), mtrie_count, &count);\n        TEST_ASSERT_EQUAL_INT (0, count);\n    }\n}\n\nvoid test_rm_nonexistent_nonempty_samename ()\n{\n    // TODO this triggers an assertion\n    test_add_and_rm_other (\"foo\", \"foo\");\n}\n\nvoid test_rm_nonexistent_nonempty_differentname ()\n{\n    test_add_and_rm_other (\"foo\", \"bar\");\n}\n\nvoid test_rm_nonexistent_nonempty_prefix ()\n{\n    // TODO here, a test assertion fails\n    test_add_and_rm_other (\"foobar\", \"foo\");\n}\n\nvoid test_rm_nonexistent_nonempty_prefixed ()\n{\n    test_add_and_rm_other (\"foo\", \"foobar\");\n}\n\nvoid add_indexed_expect_unique (zmq::generic_mtrie_t<int> &mtrie_,\n                                int *pipes_,\n                                const char **names_,\n                                size_t i_)\n{\n    const zmq::generic_mtrie_t<int>::prefix_t name_data =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (names_[i_]);\n\n    bool res = mtrie_.add (name_data, getlen (name_data), &pipes_[i_]);\n    TEST_ASSERT_EQUAL (\n      zmq::generic_mtrie_t<int>::last_value_removed,\n      res); // FIXME asserting equality between enum and bool? I think first arg for macro should be \"true\"\n}\n\nvoid test_rm_nonexistent_between ()\n{\n    int pipes[3];\n    const char *names[] = {\"foo1\", \"foo2\", \"foo3\"};\n\n    zmq::generic_mtrie_t<int> mtrie;\n    add_indexed_expect_unique (mtrie, pipes, names, 0);\n    add_indexed_expect_unique (mtrie, pipes, names, 2);\n    TEST_ASSERT_EQUAL_INT (2, mtrie.num_prefixes ());\n\n    const zmq::generic_mtrie_t<int>::prefix_t name_data =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (names[1]);\n\n    zmq::generic_mtrie_t<int>::rm_result res =\n      mtrie.rm (name_data, getlen (name_data), &pipes[1]);\n    TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::not_found, res);\n    TEST_ASSERT_EQUAL_INT (2, mtrie.num_prefixes ());\n}\n\ntemplate <size_t N>\nvoid add_entries (zmq::generic_mtrie_t<int> &mtrie_,\n                  int (&pipes_)[N],\n                  const char *(&names_)[N])\n{\n    for (size_t i = 0; i < N; ++i) {\n        add_indexed_expect_unique (mtrie_, pipes_, names_, i);\n    }\n    TEST_ASSERT_EQUAL_INT (N, mtrie_.num_prefixes ());\n}\n\nvoid test_add_multiple ()\n{\n    int pipes[3];\n    const char *names[] = {\"foo1\", \"foo2\", \"foo3\"};\n\n    zmq::generic_mtrie_t<int> mtrie;\n    add_entries (mtrie, pipes, names);\n\n    for (size_t i = 0; i < sizeof (names) / sizeof (names[0]); ++i) {\n        const zmq::generic_mtrie_t<int>::prefix_t name_data =\n          reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (names[i]);\n        int count = 0;\n        mtrie.match (name_data, getlen (name_data), mtrie_count, &count);\n        TEST_ASSERT_EQUAL_INT (1, count);\n    }\n}\n\nvoid test_add_multiple_reverse ()\n{\n    int pipes[3];\n    const char *names[] = {\"foo1\", \"foo2\", \"foo3\"};\n\n    zmq::generic_mtrie_t<int> mtrie;\n    for (int i = 2; i >= 0; --i) {\n        add_indexed_expect_unique (mtrie, pipes, names,\n                                   static_cast<size_t> (i));\n    }\n    TEST_ASSERT_EQUAL_INT (3, mtrie.num_prefixes ());\n\n    for (size_t i = 0; i < 3; ++i) {\n        const zmq::generic_mtrie_t<int>::prefix_t name_data =\n          reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (names[i]);\n        int count = 0;\n        mtrie.match (name_data, getlen (name_data), mtrie_count, &count);\n        TEST_ASSERT_EQUAL_INT (1, count);\n    }\n}\n\ntemplate <size_t N> void add_and_rm_entries (const char *(&names_)[N])\n{\n    int pipes[N];\n    zmq::generic_mtrie_t<int> mtrie;\n    add_entries (mtrie, pipes, names_);\n\n    for (size_t i = 0; i < N; ++i) {\n        const zmq::generic_mtrie_t<int>::prefix_t name_data =\n          reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (names_[i]);\n\n        zmq::generic_mtrie_t<int>::rm_result res =\n          mtrie.rm (name_data, getlen (name_data), &pipes[i]);\n        TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::last_value_removed, res);\n    }\n    TEST_ASSERT_EQUAL_INT (0, mtrie.num_prefixes ());\n}\n\nvoid test_rm_multiple_in_order ()\n{\n    const char *names[] = {\"foo1\", \"foo2\", \"foo3\"};\n    add_and_rm_entries (names);\n}\n\nvoid test_rm_multiple_reverse_order ()\n{\n    const char *names[] = {\"foo3\", \"foo2\", \"foo1\"};\n    add_and_rm_entries (names);\n}\n\nvoid check_name (zmq::generic_mtrie_t<int>::prefix_t data_,\n                 size_t len_,\n                 const char *name_)\n{\n    TEST_ASSERT_EQUAL_UINT (strlen (name_), len_);\n    TEST_ASSERT_EQUAL_STRING_LEN (name_, data_, len_);\n}\n\ntemplate <size_t N> void add_entries_rm_pipes_unique (const char *(&names_)[N])\n{\n    int pipes[N];\n    zmq::generic_mtrie_t<int> mtrie;\n    add_entries (mtrie, pipes, names_);\n\n    for (size_t i = 0; i < N; ++i) {\n        mtrie.rm (&pipes[i], check_name, names_[i], false);\n    }\n}\n\nvoid test_rm_with_callback_multiple_in_order ()\n{\n    const char *names[] = {\"foo1\", \"foo2\", \"foo3\"};\n\n    add_entries_rm_pipes_unique (names);\n}\n\nvoid test_rm_with_callback_multiple_reverse_order ()\n{\n    const char *names[] = {\"foo3\", \"foo2\", \"foo1\"};\n\n    add_entries_rm_pipes_unique (names);\n}\n\nvoid check_count (zmq::generic_mtrie_t<int>::prefix_t data_,\n                  size_t len_,\n                  int *count_)\n{\n    LIBZMQ_UNUSED (data_);\n    LIBZMQ_UNUSED (len_);\n\n    --(*count_);\n    TEST_ASSERT_GREATER_OR_EQUAL (0, *count_);\n}\n\nvoid add_duplicate_entry (zmq::generic_mtrie_t<int> &mtrie_, int (&pipes_)[2])\n{\n    const char *name = \"foo\";\n\n    const zmq::generic_mtrie_t<int>::prefix_t name_data =\n      reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (name);\n\n    bool res = mtrie_.add (name_data, getlen (name_data), &pipes_[0]);\n    TEST_ASSERT_TRUE (res);\n    TEST_ASSERT_EQUAL_INT (1, mtrie_.num_prefixes ());\n    res = mtrie_.add (name_data, getlen (name_data), &pipes_[1]);\n    TEST_ASSERT_FALSE (res);\n    TEST_ASSERT_EQUAL_INT (1, mtrie_.num_prefixes ());\n}\n\nvoid test_rm_with_callback_duplicate ()\n{\n    int pipes[2];\n    zmq::generic_mtrie_t<int> mtrie;\n    add_duplicate_entry (mtrie, pipes);\n\n    int count = 1;\n    mtrie.rm (&pipes[0], check_count, &count, false);\n    count = 1;\n    mtrie.rm (&pipes[1], check_count, &count, false);\n}\n\nvoid test_rm_with_callback_duplicate_uniq_only ()\n{\n    int pipes[2];\n    zmq::generic_mtrie_t<int> mtrie;\n    add_duplicate_entry (mtrie, pipes);\n\n    int count = 0;\n    mtrie.rm (&pipes[0], check_count, &count, true);\n    count = 1;\n    mtrie.rm (&pipes[1], check_count, &count, true);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_create);\n    RUN_TEST (test_check_empty_match_nonempty_data);\n    RUN_TEST (test_check_empty_match_empty_data);\n    RUN_TEST (test_add_single_entry_match_exact);\n    RUN_TEST (test_add_single_entry_twice_match_exact);\n    RUN_TEST (test_add_rm_single_entry_match_exact);\n    RUN_TEST (test_add_two_entries_match_prefix_and_exact);\n    RUN_TEST (test_add_two_entries_with_same_name_match_exact);\n\n    RUN_TEST (test_rm_nonexistent_0_size_empty);\n    RUN_TEST (test_rm_nonexistent_empty);\n    RUN_TEST (test_rm_nonexistent_nonempty_samename);\n    RUN_TEST (test_rm_nonexistent_nonempty_differentname);\n    RUN_TEST (test_rm_nonexistent_nonempty_prefix);\n    RUN_TEST (test_rm_nonexistent_nonempty_prefixed);\n    RUN_TEST (test_rm_nonexistent_between);\n\n    RUN_TEST (test_add_multiple);\n    RUN_TEST (test_add_multiple_reverse);\n    RUN_TEST (test_rm_multiple_in_order);\n    RUN_TEST (test_rm_multiple_reverse_order);\n\n    RUN_TEST (test_rm_with_callback_multiple_in_order);\n    RUN_TEST (test_rm_with_callback_multiple_reverse_order);\n    RUN_TEST (test_rm_with_callback_duplicate);\n    RUN_TEST (test_rm_with_callback_duplicate_uniq_only);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "unittests/unittest_poller.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../tests/testutil.hpp\"\n\n#include <poller.hpp>\n#include <i_poll_events.hpp>\n#include <ip.hpp>\n\n#include <unity.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#define closesocket close\n#endif\n\nvoid setUp ()\n{\n}\nvoid tearDown ()\n{\n}\n\nvoid test_create ()\n{\n    zmq::thread_ctx_t thread_ctx;\n    zmq::poller_t poller (thread_ctx);\n}\n\n#if 0\n// TODO this triggers an assertion. should it be a valid use case?\nvoid test_start_empty ()\n{\n    zmq::thread_ctx_t thread_ctx;\n    zmq::poller_t poller (thread_ctx);\n    poller.start ();\n    msleep (SETTLE_TIME);\n}\n#endif\n\nstruct test_events_t : zmq::i_poll_events\n{\n    test_events_t (zmq::fd_t fd_, zmq::poller_t &poller_) :\n        _fd (fd_),\n        _poller (poller_)\n    {\n        (void) _fd;\n    }\n\n    void in_event () ZMQ_OVERRIDE\n    {\n        _poller.rm_fd (_handle);\n        _handle = (zmq::poller_t::handle_t) NULL;\n\n        // this must only be incremented after rm_fd\n        in_events.add (1);\n    }\n\n\n    void out_event () ZMQ_OVERRIDE\n    {\n        // TODO\n    }\n\n\n    void timer_event (int id_) ZMQ_OVERRIDE\n    {\n        LIBZMQ_UNUSED (id_);\n        _poller.rm_fd (_handle);\n        _handle = (zmq::poller_t::handle_t) NULL;\n\n        // this must only be incremented after rm_fd\n        timer_events.add (1);\n    }\n\n    void set_handle (zmq::poller_t::handle_t handle_) { _handle = handle_; }\n\n    zmq::atomic_counter_t in_events, timer_events;\n\n  private:\n    zmq::fd_t _fd;\n    zmq::poller_t &_poller;\n    zmq::poller_t::handle_t _handle;\n};\n\nvoid wait_in_events (test_events_t &events_)\n{\n    void *watch = zmq_stopwatch_start ();\n    while (events_.in_events.get () < 1) {\n        msleep (1);\n#ifdef ZMQ_BUILD_DRAFT\n        TEST_ASSERT_LESS_OR_EQUAL_MESSAGE (SETTLE_TIME,\n                                           zmq_stopwatch_intermediate (watch),\n                                           \"Timeout waiting for in event\");\n#endif\n    }\n    zmq_stopwatch_stop (watch);\n}\n\nvoid wait_timer_events (test_events_t &events_)\n{\n    void *watch = zmq_stopwatch_start ();\n    while (events_.timer_events.get () < 1) {\n        msleep (1);\n#ifdef ZMQ_BUILD_DRAFT\n        TEST_ASSERT_LESS_OR_EQUAL_MESSAGE (SETTLE_TIME,\n                                           zmq_stopwatch_intermediate (watch),\n                                           \"Timeout waiting for timer event\");\n#endif\n    }\n    zmq_stopwatch_stop (watch);\n}\n\nvoid create_nonblocking_fdpair (zmq::fd_t *r_, zmq::fd_t *w_)\n{\n    int rc = zmq::make_fdpair (r_, w_);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n    TEST_ASSERT_NOT_EQUAL (zmq::retired_fd, *r_);\n    TEST_ASSERT_NOT_EQUAL (zmq::retired_fd, *w_);\n    zmq::unblock_socket (*r_);\n    zmq::unblock_socket (*w_);\n}\n\nvoid send_signal (zmq::fd_t w_)\n{\n#if defined ZMQ_HAVE_EVENTFD\n    const uint64_t inc = 1;\n    ssize_t sz = write (w_, &inc, sizeof (inc));\n    assert (sz == sizeof (inc));\n#else\n    {\n        char msg[] = \"test\";\n        int rc = send (w_, msg, sizeof (msg), 0);\n        assert (rc == sizeof (msg));\n    }\n#endif\n}\n\nvoid close_fdpair (zmq::fd_t w_, zmq::fd_t r_)\n{\n    int rc = closesocket (w_);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n#if !defined ZMQ_HAVE_EVENTFD\n    rc = closesocket (r_);\n    TEST_ASSERT_EQUAL_INT (0, rc);\n#else\n    LIBZMQ_UNUSED (r_);\n#endif\n}\n\nvoid test_add_fd_and_start_and_receive_data ()\n{\n    zmq::thread_ctx_t thread_ctx;\n    zmq::poller_t poller (thread_ctx);\n\n    zmq::fd_t r, w;\n    create_nonblocking_fdpair (&r, &w);\n\n    test_events_t events (r, poller);\n\n    zmq::poller_t::handle_t handle = poller.add_fd (r, &events);\n    events.set_handle (handle);\n    poller.set_pollin (handle);\n    poller.start ();\n\n    send_signal (w);\n\n    wait_in_events (events);\n\n    // required cleanup\n    close_fdpair (w, r);\n}\n\nvoid test_add_fd_and_remove_by_timer ()\n{\n    zmq::fd_t r, w;\n    create_nonblocking_fdpair (&r, &w);\n\n    zmq::thread_ctx_t thread_ctx;\n    zmq::poller_t poller (thread_ctx);\n\n    test_events_t events (r, poller);\n\n    zmq::poller_t::handle_t handle = poller.add_fd (r, &events);\n    events.set_handle (handle);\n\n    poller.add_timer (50, &events, 0);\n    poller.start ();\n\n    wait_timer_events (events);\n\n    // required cleanup\n    close_fdpair (w, r);\n}\n\n#ifdef _WIN32\nvoid test_add_fd_with_pending_failing_connect ()\n{\n    zmq::thread_ctx_t thread_ctx;\n    zmq::poller_t poller (thread_ctx);\n\n    zmq::fd_t bind_socket = socket (AF_INET, SOCK_STREAM, 0);\n    sockaddr_in addr = {0};\n    addr.sin_family = AF_INET;\n    addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);\n    addr.sin_port = 0;\n    TEST_ASSERT_EQUAL_INT (0, bind (bind_socket,\n                                    reinterpret_cast<const sockaddr *> (&addr),\n                                    sizeof (addr)));\n\n    int addr_len = static_cast<int> (sizeof (addr));\n    TEST_ASSERT_EQUAL_INT (0, getsockname (bind_socket,\n                                           reinterpret_cast<sockaddr *> (&addr),\n                                           &addr_len));\n\n    zmq::fd_t connect_socket = socket (AF_INET, SOCK_STREAM, 0);\n    zmq::unblock_socket (connect_socket);\n\n    TEST_ASSERT_EQUAL_INT (\n      -1, connect (connect_socket, reinterpret_cast<const sockaddr *> (&addr),\n                   sizeof (addr)));\n    TEST_ASSERT_EQUAL_INT (WSAEWOULDBLOCK, WSAGetLastError ());\n\n    test_events_t events (connect_socket, poller);\n\n    zmq::poller_t::handle_t handle = poller.add_fd (connect_socket, &events);\n    events.set_handle (handle);\n    poller.set_pollin (handle);\n    poller.start ();\n\n    wait_in_events (events);\n\n    int value;\n    int value_len = sizeof (value);\n    TEST_ASSERT_EQUAL_INT (0, getsockopt (connect_socket, SOL_SOCKET, SO_ERROR,\n                                          reinterpret_cast<char *> (&value),\n                                          &value_len));\n    TEST_ASSERT_EQUAL_INT (WSAECONNREFUSED, value);\n\n    // required cleanup\n    close (connect_socket);\n    close (bind_socket);\n}\n#endif\n\nint main (void)\n{\n    UNITY_BEGIN ();\n\n    zmq::initialize_network ();\n    setup_test_environment ();\n\n    RUN_TEST (test_create);\n    RUN_TEST (test_add_fd_and_start_and_receive_data);\n    RUN_TEST (test_add_fd_and_remove_by_timer);\n\n#if defined _WIN32\n    RUN_TEST (test_add_fd_with_pending_failing_connect);\n#endif\n\n    zmq::shutdown_network ();\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "unittests/unittest_radix_tree.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../tests/testutil.hpp\"\n\n#include <radix_tree.hpp>\n#include <stdint.hpp>\n\n#include <set>\n#include <string>\n#include <string.h>\n#include <unity.h>\n#include <vector>\n\nvoid setUp ()\n{\n}\nvoid tearDown ()\n{\n}\n\nbool tree_add (zmq::radix_tree_t &tree_, const std::string &key_)\n{\n    return tree_.add (reinterpret_cast<const unsigned char *> (key_.data ()),\n                      key_.size ());\n}\n\nbool tree_rm (zmq::radix_tree_t &tree_, const std::string &key_)\n{\n    return tree_.rm (reinterpret_cast<const unsigned char *> (key_.data ()),\n                     key_.size ());\n}\n\nbool tree_check (zmq::radix_tree_t &tree_, const std::string &key_)\n{\n    return tree_.check (reinterpret_cast<const unsigned char *> (key_.data ()),\n                        key_.size ());\n}\n\nvoid test_empty ()\n{\n    zmq::radix_tree_t tree;\n\n    TEST_ASSERT_TRUE (tree.size () == 0);\n}\n\nvoid test_add_single_entry ()\n{\n    zmq::radix_tree_t tree;\n\n    TEST_ASSERT_TRUE (tree_add (tree, \"foo\"));\n}\n\nvoid test_add_same_entry_twice ()\n{\n    zmq::radix_tree_t tree;\n\n    TEST_ASSERT_TRUE (tree_add (tree, \"test\"));\n    TEST_ASSERT_FALSE (tree_add (tree, \"test\"));\n}\n\nvoid test_rm_when_empty ()\n{\n    zmq::radix_tree_t tree;\n\n    TEST_ASSERT_FALSE (tree_rm (tree, \"test\"));\n}\n\nvoid test_rm_single_entry ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"temporary\");\n    TEST_ASSERT_TRUE (tree_rm (tree, \"temporary\"));\n}\n\nvoid test_rm_unique_entry_twice ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"test\");\n    TEST_ASSERT_TRUE (tree_rm (tree, \"test\"));\n    TEST_ASSERT_FALSE (tree_rm (tree, \"test\"));\n}\n\nvoid test_rm_duplicate_entry ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"test\");\n    tree_add (tree, \"test\");\n    TEST_ASSERT_FALSE (tree_rm (tree, \"test\"));\n    TEST_ASSERT_TRUE (tree_rm (tree, \"test\"));\n}\n\nvoid test_rm_common_prefix ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"checkpoint\");\n    tree_add (tree, \"checklist\");\n    TEST_ASSERT_FALSE (tree_rm (tree, \"check\"));\n}\n\nvoid test_rm_common_prefix_entry ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"checkpoint\");\n    tree_add (tree, \"checklist\");\n    tree_add (tree, \"check\");\n    TEST_ASSERT_TRUE (tree_rm (tree, \"check\"));\n}\n\nvoid test_rm_null_entry ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"\");\n    TEST_ASSERT_TRUE (tree_rm (tree, \"\"));\n}\n\nvoid test_check_empty ()\n{\n    zmq::radix_tree_t tree;\n\n    TEST_ASSERT_FALSE (tree_check (tree, \"foo\"));\n}\n\nvoid test_check_added_entry ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"entry\");\n    TEST_ASSERT_TRUE (tree_check (tree, \"entry\"));\n}\n\nvoid test_check_common_prefix ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"introduce\");\n    tree_add (tree, \"introspect\");\n    TEST_ASSERT_FALSE (tree_check (tree, \"intro\"));\n}\n\nvoid test_check_prefix ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"toasted\");\n    TEST_ASSERT_FALSE (tree_check (tree, \"toast\"));\n    TEST_ASSERT_FALSE (tree_check (tree, \"toaste\"));\n    TEST_ASSERT_FALSE (tree_check (tree, \"toaster\"));\n}\n\nvoid test_check_nonexistent_entry ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"red\");\n    TEST_ASSERT_FALSE (tree_check (tree, \"blue\"));\n}\n\nvoid test_check_query_longer_than_entry ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"foo\");\n    TEST_ASSERT_TRUE (tree_check (tree, \"foobar\"));\n}\n\nvoid test_check_null_entry_added ()\n{\n    zmq::radix_tree_t tree;\n\n    tree_add (tree, \"\");\n    TEST_ASSERT_TRUE (tree_check (tree, \"all queries return true\"));\n}\n\nvoid test_size ()\n{\n    zmq::radix_tree_t tree;\n\n    // Adapted from the example on wikipedia.\n    std::vector<std::string> keys;\n    keys.push_back (\"tester\");\n    keys.push_back (\"water\");\n    keys.push_back (\"slow\");\n    keys.push_back (\"slower\");\n    keys.push_back (\"test\");\n    keys.push_back (\"team\");\n    keys.push_back (\"toast\");\n\n    for (size_t i = 0; i < keys.size (); ++i)\n        TEST_ASSERT_TRUE (tree_add (tree, keys[i]));\n    TEST_ASSERT_TRUE (tree.size () == keys.size ());\n    for (size_t i = 0; i < keys.size (); ++i)\n        TEST_ASSERT_FALSE (tree_add (tree, keys[i]));\n    TEST_ASSERT_TRUE (tree.size () == 2 * keys.size ());\n    for (size_t i = 0; i < keys.size (); ++i)\n        TEST_ASSERT_FALSE (tree_rm (tree, keys[i]));\n    TEST_ASSERT_TRUE (tree.size () == keys.size ());\n    for (size_t i = 0; i < keys.size (); ++i)\n        TEST_ASSERT_TRUE (tree_rm (tree, keys[i]));\n    TEST_ASSERT_TRUE (tree.size () == 0);\n}\n\nvoid return_key (unsigned char *data_, size_t size_, void *arg_)\n{\n    std::vector<std::string> *vec =\n      reinterpret_cast<std::vector<std::string> *> (arg_);\n    std::string key;\n    for (size_t i = 0; i < size_; ++i)\n        key.push_back (static_cast<char> (data_[i]));\n    vec->push_back (key);\n}\n\nvoid test_apply ()\n{\n    zmq::radix_tree_t tree;\n\n    std::set<std::string> keys;\n    keys.insert (\"tester\");\n    keys.insert (\"water\");\n    keys.insert (\"slow\");\n    keys.insert (\"slower\");\n    keys.insert (\"test\");\n    keys.insert (\"team\");\n    keys.insert (\"toast\");\n\n    const std::set<std::string>::iterator end = keys.end ();\n    for (std::set<std::string>::iterator it = keys.begin (); it != end; ++it)\n        tree_add (tree, *it);\n\n    std::vector<std::string> *vec = new std::vector<std::string> ();\n    tree.apply (return_key, static_cast<void *> (vec));\n    for (size_t i = 0; i < vec->size (); ++i)\n        TEST_ASSERT_TRUE (keys.count ((*vec)[i]) > 0);\n    delete vec;\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n\n    RUN_TEST (test_empty);\n    RUN_TEST (test_add_single_entry);\n    RUN_TEST (test_add_same_entry_twice);\n\n    RUN_TEST (test_rm_when_empty);\n    RUN_TEST (test_rm_single_entry);\n    RUN_TEST (test_rm_unique_entry_twice);\n    RUN_TEST (test_rm_duplicate_entry);\n    RUN_TEST (test_rm_common_prefix);\n    RUN_TEST (test_rm_common_prefix_entry);\n    RUN_TEST (test_rm_null_entry);\n\n    RUN_TEST (test_check_empty);\n    RUN_TEST (test_check_added_entry);\n    RUN_TEST (test_check_common_prefix);\n    RUN_TEST (test_check_prefix);\n    RUN_TEST (test_check_nonexistent_entry);\n    RUN_TEST (test_check_query_longer_than_entry);\n    RUN_TEST (test_check_null_entry_added);\n\n    RUN_TEST (test_size);\n\n    RUN_TEST (test_apply);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "unittests/unittest_resolver_common.hpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#ifndef __UNITTEST_RESOLVER_COMMON_INCLUDED__\n#define __UNITTEST_RESOLVER_COMMON_INCLUDED__\n\n#include <ip_resolver.hpp>\n#include <string.h>\n\n//  Attempt a resolution and test the results.\n//\n//  On windows we can receive an IPv4 address even when an IPv6 is requested, if\n//  we're in this situation then we compare to 'expected_addr_v4_failover_'\n//  instead.\nvoid validate_address (int family,\n                       const zmq::ip_addr_t *addr_,\n                       const char *expected_addr_,\n                       uint16_t expected_port_ = 0,\n                       uint16_t expected_zone_ = 0,\n                       const char *expected_addr_v4_failover_ = NULL)\n{\n#if defined ZMQ_HAVE_WINDOWS\n    if (family == AF_INET6 && expected_addr_v4_failover_ != NULL\n        && addr_->family () == AF_INET) {\n        //  We've requested an IPv6 but the system gave us an IPv4, use the\n        //  failover address\n        family = AF_INET;\n        expected_addr_ = expected_addr_v4_failover_;\n    }\n#else\n    (void) expected_addr_v4_failover_;\n#endif\n\n    TEST_ASSERT_EQUAL (family, addr_->family ());\n\n    if (family == AF_INET6) {\n        struct in6_addr expected_addr;\n        const sockaddr_in6 *ip6_addr = &addr_->ipv6;\n\n        TEST_ASSERT_EQUAL (\n          1, test_inet_pton (AF_INET6, expected_addr_, &expected_addr));\n\n        int neq = memcmp (&ip6_addr->sin6_addr, &expected_addr,\n                          sizeof (expected_addr_));\n\n        TEST_ASSERT_EQUAL (0, neq);\n        TEST_ASSERT_EQUAL (htons (expected_port_), ip6_addr->sin6_port);\n        TEST_ASSERT_EQUAL (expected_zone_, ip6_addr->sin6_scope_id);\n    } else {\n        struct in_addr expected_addr;\n        const sockaddr_in *ip4_addr = &addr_->ipv4;\n\n        TEST_ASSERT_EQUAL (\n          1, test_inet_pton (AF_INET, expected_addr_, &expected_addr));\n\n        TEST_ASSERT_EQUAL (expected_addr.s_addr, ip4_addr->sin_addr.s_addr);\n        TEST_ASSERT_EQUAL (htons (expected_port_), ip4_addr->sin_port);\n    }\n}\n\n#endif // __UNITTEST_RESOLVER_COMMON_INCLUDED__\n"
  },
  {
    "path": "unittests/unittest_udp_address.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include <unity.h>\n#include \"../tests/testutil.hpp\"\n#include \"../unittests/unittest_resolver_common.hpp\"\n\n#include <ip.hpp>\n#include <udp_address.hpp>\n\nvoid setUp ()\n{\n}\n\nvoid tearDown ()\n{\n}\n\n//  Test an UDP address resolution. If 'dest_addr_' is NULL assume the\n//  resolution is supposed to fail.\nstatic void test_resolve (bool bind_,\n                          int family_,\n                          const char *name_,\n                          const char *target_addr_,\n                          uint16_t expected_port_,\n                          const char *bind_addr_,\n                          bool multicast_)\n{\n    if (family_ == AF_INET6 && !is_ipv6_available ()) {\n        TEST_IGNORE_MESSAGE (\"ipv6 is not available\");\n    }\n\n    zmq::udp_address_t addr;\n\n    int rc = addr.resolve (name_, bind_, family_ == AF_INET6);\n\n    if (target_addr_ == NULL) {\n        TEST_ASSERT_EQUAL (-1, rc);\n        TEST_ASSERT_EQUAL (EINVAL, errno);\n        return;\n    }\n    TEST_ASSERT_EQUAL (0, rc);\n\n\n    TEST_ASSERT_EQUAL (multicast_, addr.is_mcast ());\n\n    if (bind_addr_ == NULL) {\n        // Bind ANY\n        if (family_ == AF_INET) {\n            bind_addr_ = \"0.0.0.0\";\n        } else {\n            bind_addr_ = \"::\";\n        }\n    }\n\n    validate_address (family_, addr.target_addr (), target_addr_,\n                      expected_port_);\n    validate_address (family_, addr.bind_addr (), bind_addr_, expected_port_);\n}\n\nstatic void test_resolve_bind (int family_,\n                               const char *name_,\n                               const char *dest_addr_,\n                               uint16_t expected_port_ = 0,\n                               const char *bind_addr_ = NULL,\n                               bool multicast_ = false)\n{\n    test_resolve (true, family_, name_, dest_addr_, expected_port_, bind_addr_,\n                  multicast_);\n}\n\nstatic void test_resolve_connect (int family_,\n                                  const char *name_,\n                                  const char *dest_addr_,\n                                  uint16_t expected_port_ = 0,\n                                  const char *bind_addr_ = NULL,\n                                  bool multicast_ = false)\n{\n    test_resolve (false, family_, name_, dest_addr_, expected_port_, bind_addr_,\n                  multicast_);\n}\n\nstatic void test_resolve_ipv4_simple ()\n{\n    test_resolve_connect (AF_INET, \"127.0.0.1:5555\", \"127.0.0.1\", 5555);\n}\n\nstatic void test_resolve_ipv6_simple ()\n{\n    test_resolve_connect (AF_INET6, \"[::1]:123\", \"::1\", 123);\n}\n\nstatic void test_resolve_ipv4_bind ()\n{\n    test_resolve_bind (AF_INET, \"127.0.0.1:5555\", \"127.0.0.1\", 5555,\n                       \"127.0.0.1\");\n}\n\nstatic void test_resolve_ipv6_bind ()\n{\n    test_resolve_bind (AF_INET6, \"[abcd::1234:1]:5555\", \"abcd::1234:1\", 5555,\n                       \"abcd::1234:1\");\n}\n\nstatic void test_resolve_ipv4_bind_any ()\n{\n    test_resolve_bind (AF_INET, \"*:*\", \"0.0.0.0\", 0, \"0.0.0.0\");\n}\n\nstatic void test_resolve_ipv6_bind_any ()\n{\n    test_resolve_bind (AF_INET6, \"*:*\", \"::\", 0, \"::\");\n}\n\nstatic void test_resolve_ipv4_bind_anyport ()\n{\n    test_resolve_bind (AF_INET, \"127.0.0.1:*\", \"127.0.0.1\", 0, \"127.0.0.1\");\n}\n\nstatic void test_resolve_ipv6_bind_anyport ()\n{\n    test_resolve_bind (AF_INET6, \"[1:2:3:4::5]:*\", \"1:2:3:4::5\", 0,\n                       \"1:2:3:4::5\");\n}\n\nstatic void test_resolve_ipv4_bind_any_port ()\n{\n    test_resolve_bind (AF_INET, \"*:5555\", \"0.0.0.0\", 5555, \"0.0.0.0\");\n}\n\nstatic void test_resolve_ipv6_bind_any_port ()\n{\n    test_resolve_bind (AF_INET6, \"*:5555\", \"::\", 5555, \"::\");\n}\n\nstatic void test_resolve_ipv4_connect_any ()\n{\n    //  Cannot use wildcard for connection\n    test_resolve_connect (AF_INET, \"*:5555\", NULL);\n}\n\nstatic void test_resolve_ipv6_connect_any ()\n{\n    //  Cannot use wildcard for connection\n    test_resolve_connect (AF_INET6, \"*:5555\", NULL);\n}\n\nstatic void test_resolve_ipv4_connect_anyport ()\n{\n    test_resolve_connect (AF_INET, \"127.0.0.1:*\", NULL);\n}\n\nstatic void test_resolve_ipv6_connect_anyport ()\n{\n    test_resolve_connect (AF_INET6, \"[::1]:*\", NULL);\n}\n\nstatic void test_resolve_ipv4_connect_port0 ()\n{\n    test_resolve_connect (AF_INET, \"127.0.0.1:0\", \"127.0.0.1\", 0);\n}\n\nstatic void test_resolve_ipv6_connect_port0 ()\n{\n    test_resolve_connect (AF_INET6, \"[2000:abcd::1]:0\", \"2000:abcd::1\", 0);\n}\n\nstatic void test_resolve_ipv4_bind_mcast ()\n{\n    test_resolve_bind (AF_INET, \"239.0.0.1:1234\", \"239.0.0.1\", 1234, \"0.0.0.0\",\n                       true);\n}\n\nstatic void test_resolve_ipv6_bind_mcast ()\n{\n    test_resolve_bind (AF_INET6, \"[ff00::1]:1234\", \"ff00::1\", 1234, \"::\", true);\n}\n\nstatic void test_resolve_ipv4_connect_mcast ()\n{\n    test_resolve_connect (AF_INET, \"239.0.0.1:2222\", \"239.0.0.1\", 2222, NULL,\n                          true);\n}\n\nstatic void test_resolve_ipv6_connect_mcast ()\n{\n    test_resolve_connect (AF_INET6, \"[ff00::1]:2222\", \"ff00::1\", 2222, NULL,\n                          true);\n}\n\nstatic void test_resolve_ipv4_mcast_src_bind ()\n{\n    test_resolve_bind (AF_INET, \"127.0.0.1;230.2.8.12:5555\", \"230.2.8.12\", 5555,\n                       \"127.0.0.1\", true);\n}\n\nstatic void test_resolve_ipv6_mcast_src_bind ()\n{\n    if (!is_ipv6_available ()) {\n        TEST_IGNORE_MESSAGE (\"ipv6 is not available\");\n    }\n\n    zmq::udp_address_t addr;\n    int rc = addr.resolve (\"[::1];[ffab::4]:5555\", true, true);\n\n    //  For the time being this fails because we only support binding multicast\n    //  by interface name, not interface IP\n    TEST_ASSERT_EQUAL (-1, rc);\n    TEST_ASSERT_EQUAL (ENODEV, errno);\n}\n\nstatic void test_resolve_ipv4_mcast_src_bind_any ()\n{\n    test_resolve_bind (AF_INET, \"*;230.2.8.12:5555\", \"230.2.8.12\", 5555,\n                       \"0.0.0.0\", true);\n}\n\nstatic void test_resolve_ipv6_mcast_src_bind_any ()\n{\n    test_resolve_bind (AF_INET6, \"*;[ffff::]:5555\", \"ffff::\", 5555, \"::\", true);\n}\n\nstatic void test_resolve_ipv4_mcast_src_connect ()\n{\n    test_resolve_connect (AF_INET, \"8.9.10.11;230.2.8.12:5555\", \"230.2.8.12\",\n                          5555, \"8.9.10.11\", true);\n}\n\nstatic void test_resolve_ipv6_mcast_src_connect ()\n{\n    if (!is_ipv6_available ()) {\n        TEST_IGNORE_MESSAGE (\"ipv6 is not available\");\n    }\n\n    zmq::udp_address_t addr;\n    int rc = addr.resolve (\"[1:2:3::4];[ff01::1]:5555\", false, true);\n\n    //  For the time being this fails because we only support binding multicast\n    //  by interface name, not interface IP\n    TEST_ASSERT_EQUAL (-1, rc);\n    TEST_ASSERT_EQUAL (ENODEV, errno);\n}\n\nstatic void test_resolve_ipv4_mcast_src_connect_any ()\n{\n    test_resolve_connect (AF_INET, \"*;230.2.8.12:5555\", \"230.2.8.12\", 5555,\n                          \"0.0.0.0\", true);\n}\n\nstatic void test_resolve_ipv6_mcast_src_connect_any ()\n{\n    test_resolve_connect (AF_INET6, \"*;[ff10::1]:5555\", \"ff10::1\", 5555,\n                          \"::\", true);\n}\n\nstatic void test_resolve_ipv4_mcast_src_bind_bad ()\n{\n    test_resolve_bind (AF_INET, \"127.0.0.1;1.2.3.4:5555\", NULL);\n}\n\nstatic void test_resolve_ipv6_mcast_src_bind_bad ()\n{\n    test_resolve_bind (AF_INET6, \"[::1];[fe00::1]:5555\", NULL);\n}\n\nstatic void test_resolve_ipv4_mcast_src_connect_bad ()\n{\n    test_resolve_connect (AF_INET, \"127.0.0.1;1.2.3.4:5555\", NULL);\n}\n\nstatic void test_resolve_ipv6_mcast_src_connect_bad ()\n{\n    test_resolve_connect (AF_INET6, \"[::1];[fe00:1]:5555\", NULL);\n}\n\nint main (void)\n{\n    zmq::initialize_network ();\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n\n    RUN_TEST (test_resolve_ipv4_simple);\n    RUN_TEST (test_resolve_ipv6_simple);\n    RUN_TEST (test_resolve_ipv4_bind);\n    RUN_TEST (test_resolve_ipv6_bind);\n    RUN_TEST (test_resolve_ipv4_bind_any);\n    RUN_TEST (test_resolve_ipv6_bind_any);\n    RUN_TEST (test_resolve_ipv4_bind_anyport);\n    RUN_TEST (test_resolve_ipv6_bind_anyport);\n    RUN_TEST (test_resolve_ipv4_bind_any_port);\n    RUN_TEST (test_resolve_ipv6_bind_any_port);\n    RUN_TEST (test_resolve_ipv4_connect_any);\n    RUN_TEST (test_resolve_ipv6_connect_any);\n    RUN_TEST (test_resolve_ipv4_connect_anyport);\n    RUN_TEST (test_resolve_ipv6_connect_anyport);\n    RUN_TEST (test_resolve_ipv4_connect_port0);\n    RUN_TEST (test_resolve_ipv6_connect_port0);\n    RUN_TEST (test_resolve_ipv4_bind_mcast);\n    RUN_TEST (test_resolve_ipv6_bind_mcast);\n    RUN_TEST (test_resolve_ipv4_connect_mcast);\n    RUN_TEST (test_resolve_ipv6_connect_mcast);\n    RUN_TEST (test_resolve_ipv4_mcast_src_bind);\n    RUN_TEST (test_resolve_ipv6_mcast_src_bind);\n    RUN_TEST (test_resolve_ipv4_mcast_src_bind_any);\n    RUN_TEST (test_resolve_ipv6_mcast_src_bind_any);\n    RUN_TEST (test_resolve_ipv4_mcast_src_connect);\n    RUN_TEST (test_resolve_ipv6_mcast_src_connect);\n    RUN_TEST (test_resolve_ipv4_mcast_src_connect_any);\n    RUN_TEST (test_resolve_ipv6_mcast_src_connect_any);\n    RUN_TEST (test_resolve_ipv4_mcast_src_bind_bad);\n    RUN_TEST (test_resolve_ipv6_mcast_src_bind_bad);\n    RUN_TEST (test_resolve_ipv4_mcast_src_connect_bad);\n    RUN_TEST (test_resolve_ipv6_mcast_src_connect_bad);\n\n    zmq::shutdown_network ();\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "unittests/unittest_ypipe.cpp",
    "content": "/* SPDX-License-Identifier: MPL-2.0 */\n\n#include \"../tests/testutil.hpp\"\n\n#include <ypipe.hpp>\n\n#include <unity.h>\n\nvoid setUp ()\n{\n}\nvoid tearDown ()\n{\n}\n\nvoid test_create ()\n{\n    zmq::ypipe_t<int, 1> ypipe;\n}\n\nvoid test_check_read_empty ()\n{\n    zmq::ypipe_t<int, 1> ypipe;\n    TEST_ASSERT_FALSE (ypipe.check_read ());\n}\n\nvoid test_read_empty ()\n{\n    zmq::ypipe_t<int, 1> ypipe;\n    int read_value = -1;\n    TEST_ASSERT_FALSE (ypipe.read (&read_value));\n    TEST_ASSERT_EQUAL (-1, read_value);\n}\n\nvoid test_write_complete_and_check_read_and_read ()\n{\n    const int value = 42;\n    zmq::ypipe_t<int, 1> ypipe;\n    ypipe.write (value, false);\n    TEST_ASSERT_FALSE (ypipe.check_read ());\n    int read_value = -1;\n    TEST_ASSERT_FALSE (ypipe.read (&read_value));\n    TEST_ASSERT_EQUAL_INT (-1, read_value);\n}\n\nvoid test_write_complete_and_flush_and_check_read_and_read ()\n{\n    const int value = 42;\n    zmq::ypipe_t<int, 1> ypipe;\n    ypipe.write (value, false);\n    ypipe.flush ();\n    TEST_ASSERT_TRUE (ypipe.check_read ());\n    int read_value = -1;\n    TEST_ASSERT_TRUE (ypipe.read (&read_value));\n    TEST_ASSERT_EQUAL_INT (value, read_value);\n}\n\nint main (void)\n{\n    setup_test_environment ();\n\n    UNITY_BEGIN ();\n    RUN_TEST (test_create);\n    RUN_TEST (test_check_read_empty);\n    RUN_TEST (test_read_empty);\n    RUN_TEST (test_write_complete_and_check_read_and_read);\n    RUN_TEST (test_write_complete_and_flush_and_check_read_and_read);\n\n    return UNITY_END ();\n}\n"
  },
  {
    "path": "version.sh",
    "content": "#!/bin/sh\n#\n# This script extracts the 0MQ version from include/zmq.h, which is the master\n# location for this information.\n#\nif [ ! -f include/zmq.h ]; then\n    echo \"version.sh: error: include/zmq.h does not exist\" 1>&2\n    exit 1\nfi\nMAJOR=`grep -E '^#define +ZMQ_VERSION_MAJOR +[0-9]+$' include/zmq.h`\nMINOR=`grep -E '^#define +ZMQ_VERSION_MINOR +[0-9]+$' include/zmq.h`\nPATCH=`grep -E '^#define +ZMQ_VERSION_PATCH +[0-9]+$' include/zmq.h`\nif [ -z \"$MAJOR\" -o -z \"$MINOR\" -o -z \"$PATCH\" ]; then\n    echo \"version.sh: error: could not extract version from include/zmq.h\" 1>&2\n    exit 1\nfi\nMAJOR=`echo $MAJOR | awk '{ print $3 }'`\nMINOR=`echo $MINOR | awk '{ print $3 }'`\nPATCH=`echo $PATCH | awk '{ print $3 }'`\necho $MAJOR.$MINOR.$PATCH | tr -d '\\n'\n\n"
  }
]