Compare commits

..

No commits in common. "master" and "v3.4-dev4" have entirely different histories.

232 changed files with 4911 additions and 13459 deletions

16
.github/matrix.py vendored
View file

@ -19,10 +19,9 @@ from packaging import version
# #
# this CI is used for both development and stable branches of HAProxy # this CI is used for both development and stable branches of HAProxy
# #
# naming convention used, if branch/tag name matches: # naming convention used, if branch name matches:
# #
# "haproxy-" - stable branches # "haproxy-" - stable branches
# "vX.Y.Z" - release tags
# otherwise - development branch (i.e. "latest" ssl variants, "latest" github images) # otherwise - development branch (i.e. "latest" ssl variants, "latest" github images)
# #
@ -121,13 +120,11 @@ def clean_compression(compression):
def main(ref_name): def main(ref_name):
print("Generating matrix for branch '{}'.".format(ref_name)) print("Generating matrix for branch '{}'.".format(ref_name))
is_stable = "haproxy-" in ref_name or re.match(r'^v\d+\.\d+\.\d+$', ref_name)
matrix = [] matrix = []
# Ubuntu # Ubuntu
if is_stable: if "haproxy-" in ref_name:
os = "ubuntu-24.04" # stable branch os = "ubuntu-24.04" # stable branch
os_arm = "ubuntu-24.04-arm" # stable branch os_arm = "ubuntu-24.04-arm" # stable branch
else: else:
@ -231,7 +228,7 @@ def main(ref_name):
# "BORINGSSL=yes", # "BORINGSSL=yes",
] ]
if not is_stable: # development branch if "haproxy-" not in ref_name: # development branch
ssl_versions = ssl_versions + [ ssl_versions = ssl_versions + [
"OPENSSL_VERSION=latest", "OPENSSL_VERSION=latest",
"LIBRESSL_VERSION=latest", "LIBRESSL_VERSION=latest",
@ -278,8 +275,11 @@ def main(ref_name):
} }
) )
# macOS on dev branches # macOS
if not is_stable:
if "haproxy-" in ref_name:
os = "macos-13" # stable branch
else:
os = "macos-26" # development branch os = "macos-26" # development branch
TARGET = "osx" TARGET = "osx"

View file

@ -11,6 +11,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Compile admin/halog/halog
run: |
make admin/halog/halog
- name: Compile dev/flags/flags - name: Compile dev/flags/flags
run: | run: |
make dev/flags/flags make dev/flags/flags

View file

@ -11,7 +11,7 @@ on:
jobs: jobs:
combined-build-and-run: build:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }} if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
permissions: permissions:
@ -21,47 +21,84 @@ jobs:
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Update Docker to the latest - name: Log in to the Container registry
uses: docker/setup-docker-action@v4 uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker image - name: Build and push Docker image
id: push id: push
uses: docker/build-push-action@v6 uses: docker/build-push-action@v5
with: with:
context: https://github.com/haproxytech/haproxy-qns.git context: https://github.com/haproxytech/haproxy-qns.git
platforms: linux/amd64 push: true
build-args: | build-args: |
SSLLIB=AWS-LC SSLLIB=AWS-LC
tags: local:aws-lc tags: ghcr.io/${{ github.repository }}:aws-lc
- name: Cleanup registry
uses: actions/delete-package-versions@v5
with:
owner: ${{ github.repository_owner }}
package-name: 'haproxy'
package-type: container
min-versions-to-keep: 1
delete-only-untagged-versions: 'true'
run:
needs: build
strategy:
matrix:
suite: [
{ client: chrome, tests: "http3" },
{ client: picoquic, tests: "handshake,transfer,longrtt,chacha20,multiplexing,retry,resumption,zerortt,http3,blackhole,keyupdate,ecn,amplificationlimit,handshakeloss,transferloss,handshakecorruption,transfercorruption,ipv6,v2" },
{ client: quic-go, tests: "handshake,transfer,longrtt,chacha20,multiplexing,retry,resumption,zerortt,http3,blackhole,keyupdate,ecn,amplificationlimit,handshakeloss,transferloss,handshakecorruption,transfercorruption,ipv6,v2" },
{ client: ngtcp2, tests: "handshake,transfer,longrtt,chacha20,multiplexing,retry,resumption,zerortt,http3,blackhole,keyupdate,ecn,amplificationlimit,handshakeloss,transferloss,handshakecorruption,transfercorruption,ipv6,v2" }
]
fail-fast: false
name: ${{ matrix.suite.client }}
runs-on: ubuntu-24.04
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v5
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Install tshark - name: Install tshark
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get -y install tshark sudo apt-get -y install tshark
- name: Pull image
run: |
docker pull ghcr.io/${{ github.repository }}:aws-lc
- name: Run - name: Run
run: | run: |
git clone https://github.com/quic-interop/quic-interop-runner git clone https://github.com/quic-interop/quic-interop-runner
cd quic-interop-runner cd quic-interop-runner
pip install -r requirements.txt --break-system-packages pip install -r requirements.txt --break-system-packages
python run.py -j result.json -l logs-chrome -r haproxy=local:aws-lc -t "http3" -c chrome -s haproxy python run.py -j result.json -l logs -r haproxy=ghcr.io/${{ github.repository }}:aws-lc -t ${{ matrix.suite.tests }} -c ${{ matrix.suite.client }} -s haproxy
python run.py -j result.json -l logs-picoquic -r haproxy=local:aws-lc -t "handshake,transfer,longrtt,chacha20,multiplexing,retry,resumption,zerortt,http3,blackhole,keyupdate,ecn,amplificationlimit,handshakeloss,transferloss,handshakecorruption,transfercorruption,ipv6,v2" -c picoquic -s haproxy
python run.py -j result.json -l logs-quic-go -r haproxy=local:aws-lc -t "handshake,transfer,longrtt,chacha20,multiplexing,retry,resumption,zerortt,http3,blackhole,keyupdate,ecn,amplificationlimit,handshakeloss,transferloss,handshakecorruption,transfercorruption,ipv6,v2" -c quic-go -s haproxy
python run.py -j result.json -l logs-ngtcp2 -r haproxy=local:aws-lc -t "handshake,transfer,longrtt,chacha20,multiplexing,retry,resumption,zerortt,http3,blackhole,keyupdate,ecn,amplificationlimit,handshakeloss,transferloss,handshakecorruption,transfercorruption,ipv6,v2" -c ngtcp2 -s haproxy
- name: Delete succeeded logs - name: Delete succeeded logs
if: failure() if: failure()
run: | run: |
for client in chrome picoquic quic-go ngtcp2; do cd quic-interop-runner/logs/haproxy_${{ matrix.suite.client }}
pushd quic-interop-runner/logs-${client}/haproxy_${client}
cat ../../result.json | jq -r '.results[][] | select(.result=="succeeded") | .name' | xargs rm -rf cat ../../result.json | jq -r '.results[][] | select(.result=="succeeded") | .name' | xargs rm -rf
popd
done
- name: Logs upload - name: Logs upload
if: failure() if: failure()
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: logs name: logs-${{ matrix.suite.client }}
path: quic-interop-runner/logs*/ path: quic-interop-runner/logs/
retention-days: 6 retention-days: 6

View file

@ -11,7 +11,7 @@ on:
jobs: jobs:
combined-build-and-run: build:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }} if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
permissions: permissions:
@ -21,45 +21,82 @@ jobs:
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Update Docker to the latest - name: Log in to the Container registry
uses: docker/setup-docker-action@v4 uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker image - name: Build and push Docker image
id: push id: push
uses: docker/build-push-action@v6 uses: docker/build-push-action@v5
with: with:
context: https://github.com/haproxytech/haproxy-qns.git context: https://github.com/haproxytech/haproxy-qns.git
platforms: linux/amd64 push: true
build-args: | build-args: |
SSLLIB=LibreSSL SSLLIB=LibreSSL
tags: local:libressl tags: ghcr.io/${{ github.repository }}:libressl
- name: Cleanup registry
uses: actions/delete-package-versions@v5
with:
owner: ${{ github.repository_owner }}
package-name: 'haproxy'
package-type: container
min-versions-to-keep: 1
delete-only-untagged-versions: 'true'
run:
needs: build
strategy:
matrix:
suite: [
{ client: picoquic, tests: "handshake,transfer,longrtt,chacha20,multiplexing,retry,http3,blackhole,amplificationlimit,handshakeloss,transferloss,handshakecorruption,transfercorruption,v2" },
{ client: quic-go, tests: "handshake,transfer,longrtt,chacha20,multiplexing,retry,http3,blackhole,amplificationlimit,transferloss,transfercorruption,v2" }
]
fail-fast: false
name: ${{ matrix.suite.client }}
runs-on: ubuntu-24.04
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v5
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Install tshark - name: Install tshark
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get -y install tshark sudo apt-get -y install tshark
- name: Pull image
run: |
docker pull ghcr.io/${{ github.repository }}:libressl
- name: Run - name: Run
run: | run: |
git clone https://github.com/quic-interop/quic-interop-runner git clone https://github.com/quic-interop/quic-interop-runner
cd quic-interop-runner cd quic-interop-runner
pip install -r requirements.txt --break-system-packages pip install -r requirements.txt --break-system-packages
python run.py -j result.json -l logs-picoquic -r haproxy=local:libressl -t "handshake,transfer,longrtt,chacha20,multiplexing,retry,http3,blackhole,amplificationlimit,handshakeloss,transferloss,handshakecorruption,transfercorruption,v2" -c picoquic -s haproxy python run.py -j result.json -l logs -r haproxy=ghcr.io/${{ github.repository }}:libressl -t ${{ matrix.suite.tests }} -c ${{ matrix.suite.client }} -s haproxy
python run.py -j result.json -l logs-quic-go -r haproxy=local:libressl -t "handshake,transfer,longrtt,chacha20,multiplexing,retry,http3,blackhole,amplificationlimit,transferloss,transfercorruption,v2" -c quic-go -s haproxy
- name: Delete succeeded logs - name: Delete succeeded logs
if: failure() if: failure()
run: | run: |
for client in picoquic quic-go; do cd quic-interop-runner/logs/haproxy_${{ matrix.suite.client }}
pushd quic-interop-runner/logs-${client}/haproxy_${client}
cat ../../result.json | jq -r '.results[][] | select(.result=="succeeded") | .name' | xargs rm -rf cat ../../result.json | jq -r '.results[][] | select(.result=="succeeded") | .name' | xargs rm -rf
popd
done
- name: Logs upload - name: Logs upload
if: failure() if: failure()
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: logs name: logs-${{ matrix.suite.client }}
path: quic-interop-runner/logs*/ path: quic-interop-runner/logs/
retention-days: 6 retention-days: 6

View file

@ -18,7 +18,6 @@ jobs:
msys2: msys2:
name: ${{ matrix.name }} name: ${{ matrix.name }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
defaults: defaults:
run: run:
shell: msys2 {0} shell: msys2 {0}

380
CHANGELOG
View file

@ -1,386 +1,6 @@
ChangeLog : ChangeLog :
=========== ===========
2026/03/20 : 3.4-dev7
- BUG/MINOR: stconn: Increase SC bytes_out value in se_done_ff()
- BUG/MINOR: ssl-sample: Fix sample_conv_sha2() by checking EVP_Digest* failures
- BUG/MINOR: backend: Don't get proto to use for webscoket if there is no server
- BUG/MINOR: jwt: Missing 'jwt_tokenize' return value check
- MINOR: flt_http_comp: define and use proxy_get_comp() helper function
- MEDIUM: flt_http_comp: split "compression" filter in 2 distinct filters
- CLEANUP: flt_http_comp: comp_state doesn't bother about the direction anymore
- BUG/MINOR: admin: haproxy-reload use explicit socat address type
- MEDIUM: admin: haproxy-reload conversion to POSIX sh
- BUG/MINOR: admin: haproxy-reload rename -vv long option
- SCRIPTS: git-show-backports: hide the common ancestor warning in quiet mode
- SCRIPTS: git-show-backports: add a restart-from-last option
- MINOR: mworker: add a BUG_ON() on mproxy_li in _send_status
- BUG/MINOR: mworker: don't set the PROC_O_LEAVING flag on master process
- Revert "BUG/MINOR: jwt: Missing 'jwt_tokenize' return value check"
- MINOR: jwt: Improve 'jwt_tokenize' function
- MINOR: jwt: Convert EC JWK to EVP_PKEY
- MINOR: jwt: Parse ec-specific fields in jose header
- MINOR: jwt: Manage ECDH-ES algorithm in jwt_decrypt_jwk function
- MINOR: jwt: Add ecdh-es+axxxkw support in jwt_decrypt_jwk converter
- MINOR: jwt: Manage ec certificates in jwt_decrypt_cert
- DOC: jwt: Add ECDH support in jwt_decrypt converters
- MINOR: stconn: Call sc_conn_process from the I/O callback if TASK_WOKEN_MSG state was set
- MINOR: mux-h2: Rely on h2s_notify_send() when resuming h2s for sending
- MINOR: mux-spop: Rely on spop_strm_notify_send() when resuming streams for sending
- MINOR: muxes: Wakup the data layer from a mux stream with TASK_WOKEN_IO state
- MAJOR: muxes: No longer use app_ops .wake() callback function from muxes
- MINOR: applet: Call sc_applet_process() instead of .wake() callback function
- MINOR: connection: Call sc_conn_process() instead of .wake() callback function
- MEDIUM: stconn: Remove .wake() callback function from app_ops
- MINOR: check: Remove wake_srv_chk() function
- MINOR: haterm: Remove hstream_wake() function
- MINOR: stconn: Wakup the SC with TASK_WOKEN_IO state from opposite side
- MEDIUM: stconn: Merge all .chk_rcv() callback functions in sc_chk_rcv()
- MINOR: stconn: Remove .chk_rcv() callback functions
- MEDIUM: stconn: Merge all .chk_snd() callback functions in sc_chk_snd()
- MINOR: stconn: Remove .chk_snd() callback functions
- MEDIUM: stconn: Merge all .abort() callback functions in sc_abort()
- MINOR: stconn: Remove .abort() callback functions
- MEDIUM: stconn: Merge all .shutdown() callback functions in sc_shutdown()
- MINOR: stconn: Remove .shutdown() callback functions
- MINOR: stconn: Totally app_ops from the stconns
- MINOR: stconn: Simplify sc_abort/sc_shutdown by merging calls to se_shutdown
- DEBUG: stconn: Add a CHECK_IF() when I/O are performed on a orphan SC
- MEDIUM: mworker: exiting when couldn't find the master mworker_proc element
- BUILD: ssl: use ASN1_STRING accessors for OpenSSL 4.0 compatibility
- BUILD: ssl: make X509_NAME usage OpenSSL 4.0 ready
- BUG/MINOR: tcpcheck: Fix typo in error error message for `http-check expect`
- BUG/MINOR: jws: fix memory leak in jws_b64_signature
- DOC: configuration: http-check expect example typo
- DOC/CLEANUP: config: update mentions of the old "Global parameters" section
- BUG/MEDIUM: ssl: Handle receiving early data with BoringSSL/AWS-LC
- BUG/MINOR: mworker: always stop the receiving listener
- BUG/MEDIUM: ssl: Don't report read data as early data with AWS-LC
- BUILD: makefile: fix range build without test command
- BUG/MINOR: memprof: avoid a small memory leak in "show profiling"
- BUG/MINOR: proxy: do not forget to validate quic-initial rules
- MINOR: activity: use dynamic allocation for "show profiling" entries
- MINOR: tools: extend the pointer hashing code to ease manipulations
- MINOR: tools: add a new pointer hash function that also takes an argument
- MINOR: memprof: attempt different retry slots for different hashes on collision
- MINOR: tinfo: start to add basic thread_exec_ctx
- MINOR: memprof: prepare to consider exec_ctx in reporting
- MINOR: memprof: also permit to sort output by calling context
- MINOR: tools: add a function to write a thread execution context.
- MINOR: debug: report the execution context on thread dumps
- MINOR: memprof: report the execution context on profiling output
- MINOR: initcall: record the file and line declaration of an INITCALL
- MINOR: tools: decode execution context TH_EX_CTX_INITCALL
- MINOR: tools: support decoding ha_caller type exec context
- MINOR: sample: store location for fetch/conv via initcalls
- MINOR: sample: also report contexts registered directly
- MINOR: tools: support an execution context that is just a function
- MINOR: actions: store the location of keywords registered via initcalls
- MINOR: actions: also report execution contexts registered directly
- MINOR: filters: set the exec context to the current filter config
- MINOR: ssl: set the thread execution context during message callbacks
- MINOR: connection: track mux calls to report their allocation context
- MINOR: task: set execution context on task/tasklet calls
- MINOR: applet: set execution context on applet calls
- MINOR: cli: keep the info of the current keyword being processed in the appctx
- MINOR: cli: keep track of the initcall context since kw registration
- MINOR: cli: implement execution context for manually registered keywords
- MINOR: activity: support aggregating by caller also for memprofile
- MINOR: activity: raise the default number of memprofile buckets to 4k
- DOC: internals: short explanation on how thread_exec_ctx works
- BUG/MINOR: mworker: only match worker processes when looking for unspawned proc
- MINOR: traces: defer processing of "-dt" options
- BUG/MINOR: mworker: fix typo &= instead of & in proc list serialization
- BUG/MINOR: mworker: set a timeout on the worker socketpair read at startup
- BUG/MINOR: mworker: avoid passing NULL version in proc list serialization
- BUG/MINOR: sockpair: set FD_CLOEXEC on fd received via SCM_RIGHTS
- BUG/MEDIUM: stconn: Don't forget to wakeup applets on shutdown
- BUG/MINOR: spoe: Properly switch SPOE filter to WAITING_ACK state
- BUG/MEDIUM: spoe: Properly abort processing on client abort
- BUG/MEDIUM: stconn: Fix abort on close when a large buffer is used
- BUG/MEDIUM: stconn: Don't perform L7 retries with large buffer
- BUG/MINOR: h2/h3: Only test number of trailers inserted in HTX message
- MINOR: htx: Add function to truncate all blocks after a specific block
- BUG/MINOR: h2/h3: Never insert partial headers/trailers in an HTX message
- BUG/MINOR: http-ana: Swap L7 buffer with request buffer by hand
- BUG/MINOR: stream: Fix crash in stream dump if the current rule has no keyword
- BUG/MINOR: mjson: make mystrtod() length-aware to prevent out-of-bounds reads
- MEDIUM: stats-file/clock: automatically update now_offset based on shared clock
- MINOR: promex: export "haproxy_sticktable_local_updates" metric
- BUG/MINOR: spoe: Fix condition to abort processing on client abort
- BUILD: spoe: Remove unsused variable
- MINOR: tools: add a function to create a tar file header
- MINOR: tools: add a function to load a file into a tar archive
- MINOR: config: support explicit "on" and "off" for "set-dumpable"
- MINOR: debug: read all libs in memory when set-dumpable=libs
- DEV: gdb: add a new utility to extract libs from a core dump: libs-from-core
- MINOR: debug: copy debug symbols from /usr/lib/debug when present
- MINOR: debug: opportunistically load libthread_db.so.1 with set-dumpable=libs
- BUG/MINOR: mworker: don't try to access an initializing process
- BUG/MEDIUM: peers: enforce check on incoming table key type
- BUG/MINOR: mux-h2: properly ignore R bit in GOAWAY stream ID
- BUG/MINOR: mux-h2: properly ignore R bit in WINDOW_UPDATE increments
- OPTIM: haterm: use chunk builders for generated response headers
- BUG/MAJOR: h3: check body size with content-length on empty FIN
- BUG/MEDIUM: h3: reject unaligned frames except DATA
- BUG/MINOR: mworker/cli: fix show proc pagination losing entries on resume
- CI: github: treat vX.Y.Z release tags as stable like haproxy-* branches
- MINOR: freq_ctr: add a function to add values with a peak
- MINOR: task: maintain a per-thread indicator of the peak run-queue size
- MINOR: mux-h2: store the concurrent streams hard limit in the h2c
- MINOR: mux-h2: permit to moderate the advertised streams limit depending on load
- MINOR: mux-h2: permit to fix a minimum value for the advertised streams limit
- BUG/MINOR: mworker: fix sort order of mworker_proc in 'show proc'
- CLEANUP: mworker: fix tab/space mess in mworker_env_to_proc_list()
2026/03/05 : 3.4-dev6
- CLEANUP: acme: remove duplicate includes
- BUG/MINOR: proxy: detect strdup error on server auto SNI
- BUG/MINOR: server: set auto SNI for dynamic servers
- BUG/MINOR: server: enable no-check-sni-auto for dynamic servers
- MINOR: haterm: provide -b and -c options (RSA key size, ECDSA curves)
- MINOR: haterm: add long options for QUIC and TCP "bind" settings
- BUG/MINOR: haterm: missing allocation check in copy_argv()
- BUG/MINOR: quic: fix counters used on BE side
- MINOR: quic: add BUG_ON() on half_open_conn counter access from BE
- BUG/MINOR: quic/h3: display QUIC/H3 backend module on HTML stats
- BUG/MINOR: acme: acme_ctx_destroy() leaks auth->dns
- BUG/MINOR: acme: wrong labels logic always memprintf errmsg
- MINOR: ssl: clarify error reporting for unsupported keywords
- BUG/MINOR: acme: fix incorrect number of arguments allowed in config
- CLEANUP: haterm: remove unreachable labels hstream_add_data()
- CLEANUP: haterm: avoid static analyzer warnings about rand() use
- CLEANUP: ssl: Remove a useless variable from ssl_gen_x509()
- CI: use the latest docker for QUIC Interop
- CI: remove redundant "halog" compilation
- CLENAUP: cfgparse: accept-invalid-http-* does not support "no"/"defaults"
- BUG/MEDIUM: spoe: Acquire context buffer in applet before consuming a frame
- MINOR: traces: always mark trace_source as thread-aligned
- MINOR: ncbmbuf: improve itbmap_next() code
- MINOR: proxy: improve code when checking server name conflicts
- MINOR: quic: add a new metric for ncbuf failures
- BUG/MINOR: haterm: cannot reset default "haterm" mode
- BUG/MEDIUM: cpu-topo: Distribute CPUs fairly across groups
- BUG/MINOR: quic: missing app ops init during backend 0-RTT sessions
- CLEANUP: ssl: remove outdated comments
- MINOR: mux-h2: also count glitches on invalid trailers
- MINOR: mux-h2: add a new setting, "tune.h2.log-errors" to tweak error logging
- BUG/MEDIUM: mux-h2: make sure to always report pending errors to the stream
- BUG/MINOR: server: adjust initialization order for dynamic servers
- CLEANUP: tree-wide: drop a few useless null-checks before free()
- CLEANUP: quic-stats: include counters from quic_stats
- REORG: stats/counters: move extra_counters to counters not stats
- CLEANUP: stats: drop stats.h / stats-t.h where not needed
- MEDIUM: counters: change the fill_stats() API to pass the module and extra_counters
- CLEANUP: counters: only retrieve zeroes for unallocated extra_counters
- MEDIUM: counters: add a dedicated storage for extra_counters in various structs
- MINOR: counters: store a tgroup step for extra_counters to access multiple tgroups
- MEDIUM: counters: store the number of thread groups accessing extra_counters
- MINOR: counters: add EXTRA_COUNTERS_BASE() to retrieve extra_counters base storage
- MEDIUM: counters: return aggregate extra counters in ->fill_stats()
- MEDIUM: counters: make EXTRA_COUNTERS_GET() consider tgid
- BUG/MINOR: call EXTRA_COUNTERS_FREE() before srv_free_params() in srv_drop()
- MINOR: promex: test applet resume in stress mode
- BUG/MINOR: promex: fix server iteration when last server is deleted
- BUG/MINOR: proxy: add dynamic backend into ID tree
- MINOR: proxy: convert proxy flags to uint
- MINOR: server: refactor srv_detach()
- MINOR: proxy: define a basic "del backend" CLI
- MINOR: proxy: define proxy watcher member
- MINOR: stats: protect proxy iteration via watcher
- MINOR: promex: use watcher to iterate over backend instances
- MINOR: lua: use watcher for proxies iterator
- MINOR: proxy: add refcount to proxies
- MINOR: proxy: rename default refcount to avoid confusion
- MINOR: server: take proxy refcount when deleting a server
- MINOR: lua: handle proxy refcount
- MINOR: proxy: prevent backend removal when unsupported
- MINOR: proxy: prevent deletion of backend referenced by config elements
- MINOR: proxy: prevent backend deletion if server still exists in it
- MINOR: server: mark backend removal as forbidden if QUIC was used
- MINOR: cli: implement wait on be-removable
- MINOR: proxy: add comment for defaults_px_ref/unref_all()
- MEDIUM: proxy: add lock for global accesses during proxy free
- MEDIUM: proxy: add lock for global accesses during default free
- MINOR: proxy: use atomic ops for default proxy refcount
- MEDIUM: proxy: implement backend deletion
- REGTESTS: add a test on "del backend"
- REGTESTS: complete "del backend" with unnamed defaults ref free
- BUG/MINOR: hlua: fix return with push nil on proxy check
- BUG/MEDIUM: stream: Handle TASK_WOKEN_RES as a stream event
- MINOR: quic: use signed char type for ALPN manipulation
- MINOR: quic/h3: reorganize stream reject after MUX closure
- MINOR: mux-quic: add function for ALPN to app-ops conversion
- MEDIUM: quic/mux-quic: adjust app-ops install
- MINOR: quic: use server cache for ALPN on BE side
- BUG/MEDIUM: hpack: correctly deal with too large decoded numbers
- BUG/MAJOR: qpack: unchecked length passed to huffman decoder
- BUG/MINOR: qpack: fix 1-byte OOB read in qpack_decode_fs_pfx()
- BUG/MINOR: quic: fix OOB read in preferred_address transport parameter
- BUG/MEDIUM: qpack: correctly deal with too large decoded numbers
- BUG/MINOR: hlua: Properly enable/disable line receives from HTTP applet
- BUG/MEDIUM: hlua: Fix end of request detection when retrieving payload
- BUG/MINOR: hlua: Properly enable/disable receives for TCP applets
- MINOR: htx: Add a function to retrieve the HTTP version from a start-line
- MINOR: h1-htx: Reports non-HTTP version via dedicated flags
- BUG/MINOR: h1-htx: Be sure that H1 response version starts by "HTTP/"
- MINOR: http-ana: Save the message version in the http_msg structure
- MEDIUM: http-fetch: Rework how HTTP message version is retrieved
- MEDIUM: http-ana: Use the version of the opposite side for internal messages
- DEBUG: stream: Display the currently running rule in stream dump
- MINOR: filters: Use filter API as far as poissible to break loops on filters
- MINOR: filters: Set last_entity when a filter fails on stream_start callback
- MINOR: stream: Display the currently running filter per channel in stream dump
- DOC: config: Use the right alias for %B
- BUG/MINOR: channel: Increase the stconn bytes_in value in channel_add_input()
- BUG/MINOR: sample: Fix sample to retrieve the number of bytes received and sent
- BUG/MINOR: http-ana: Increment scf bytes_out value if an haproxy error is sent
- BUG/MAJOR: fcgi: Fix param decoding by properly checking its size
- BUG/MAJOR: resolvers: Properly lowered the names found in DNS response
- BUG/MEDIUM: mux-fcgi: Use a safe loop to resume each stream eligible for sending
- MINOR: mux-fcgi: Use a dedicated function to resume streams eligible for sending
- CLEANUP: qpack: simplify length checks in qpack_decode_fs()
- MINOR: counters: Introduce COUNTERS_UPDATE_MAX()
- MINOR: listeners: Update the frequency counters separately when needed
- MINOR: proxies: Update beconn separately
- MINOR: stats: Add an option to disable the calculation of max counters
2026/02/19 : 3.4-dev5
- DOC: internals: addd mworker V3 internals
- BUG/MINOR: threads: Initialize maxthrpertgroup earlier.
- BUG/MEDIUM: threads: Differ checking the max threads per group number
- BUG/MINOR: startup: fix allocation error message of progname string
- BUG/MINOR: startup: handle a possible strdup() failure
- MINOR: cfgparse: validate defaults proxies separately
- MINOR: cfgparse: move proxy post-init in a dedicated function
- MINOR: proxy: refactor proxy inheritance of a defaults section
- MINOR: proxy: refactor mode parsing
- MINOR: backend: add function to check support for dynamic servers
- MINOR: proxy: define "add backend" handler
- MINOR: proxy: parse mode on dynamic backend creation
- MINOR: proxy: parse guid on dynamic backend creation
- MINOR: proxy: check default proxy compatibility on "add backend"
- MEDIUM: proxy: implement dynamic backend creation
- MINOR: proxy: assign dynamic proxy ID
- REGTESTS: add dynamic backend creation test
- BUG/MINOR: proxy: fix clang build error on "add backend" handler
- BUG/MINOR: proxy: fix null dereference in "add backend" handler
- MINOR: net_helper: extend the ip.fp output with an option presence mask
- BUG/MINOR: proxy: fix default ALPN bind settings
- CLEANUP: lb-chash: free lb_nodes from chash's deinit(), not global
- BUG/MEDIUM: lb-chash: always properly initialize lb_nodes with dynamic servers
- CLEANUP: haproxy: fix bad line wrapping in run_poll_loop()
- MINOR: activity: support setting/clearing lock/memory watching for task profiling
- MEDIUM: activity: apply and use new finegrained task profiling settings
- MINOR: activity: allow to switch per-task lock/memory profiling at runtime
- MINOR: startup: Add the SSL lib verify directory in haproxy -vv
- BUG/MINOR: ssl: SSL_CERT_DIR environment variable doesn't affect haproxy
- CLEANUP: initcall: adjust comments to INITCALL{0,1} macros
- DOC: proxy-proto: underline the packed attribute for struct pp2_tlv_ssl
- MINOR: queues: Check minconn first in srv_dynamic_maxconn()
- MINOR: servers: Call process_srv_queue() without lock when possible
- BUG/MINOR: quic: ensure handshake speed up is only run once per conn
- BUG/MAJOR: quic: reject invalid token
- BUG/MAJOR: quic: fix parsing frame type
- MINOR: ssl: Missing '\n' in error message
- MINOR: jwt: Convert an RSA JWK into an EVP_PKEY
- MINOR: jwt: Add new jwt_decrypt_jwk converter
- REGTESTS: jwt: Add new "jwt_decrypt_jwk" tests
- MINOR: startup: Add HAVE_WORKING_TCP_MD5SIG in haproxy -vv
- MINOR: startup: sort the feature list in haproxy -vv
- MINOR: startup: show the list of detected features at runtime with haproxy -vv
- SCRIPTS: build-vtest: allow to set a TMPDIR and a DESTDIR
- MINOR: filters: rework RESUME_FILTER_* macros as inline functions
- MINOR: filters: rework filter iteration for channel related callback functions
- MEDIUM: filters: use per-channel filter list when relevant
- DEV: gdb: add a utility to find the post-mortem address from a core
- BUG/MINOR: deviceatlas: add missing return on error in config parsers
- BUG/MINOR: deviceatlas: add NULL checks on strdup() results in config parsers
- BUG/MEDIUM: deviceatlas: fix resource leaks on init error paths
- BUG/MINOR: deviceatlas: fix off-by-one in da_haproxy_conv()
- BUG/MINOR: deviceatlas: fix cookie vlen using wrong length after extraction
- BUG/MINOR: deviceatlas: fix double-checked locking race in checkinst
- BUG/MINOR: deviceatlas: fix resource leak on hot-reload compile failure
- BUG/MINOR: deviceatlas: fix deinit to only finalize when initialized
- BUG/MINOR: deviceatlas: set cache_size on hot-reloaded atlas instance
- MINOR: deviceatlas: check getproptype return and remove pprop indirection
- MINOR: deviceatlas: increase DA_MAX_HEADERS and header buffer sizes
- MINOR: deviceatlas: define header_evidence_entry in dummy library header
- MINOR: deviceatlas: precompute maxhdrlen to skip oversized headers early
- CLEANUP: deviceatlas: add unlikely hints and minor code tidying
- DEV: gdb: use unsigned longs to display pools memory usage
- BUG/MINOR: ssl: lack crtlist_dup_ssl_conf() declaration
- BUG/MINOR: ssl: double-free on error path w/ ssl-f-use parser
- BUG/MINOR: ssl: fix leak in ssl-f-use parser upon error
- BUG/MINOR: ssl: clarify ssl-f-use errors in post-section parsing
- BUG/MINOR: ssl: error with ssl-f-use when no "crt"
- MEDIUM: backend: make "balance random" consider tg local req rate when loads are equal
- BUG/MAJOR: Revert "MEDIUM: mux-quic: add BUG_ON if sending on locally closed QCS"
- BUG/MEDIUM: h3: reject frontend CONNECT as currently not implemented
- MINOR: mux-quic: add BUG_ON_STRESS() when draining data on closed stream
- REGTESTS: fix quoting in feature cmd which prevents test execution
- BUG/MEDIUM: mux-h2/quic: Stop sending via fast-forward if stream is closed
- BUG/MEDIUM: mux-h1: Stop sending vi fast-forward for unexpected states
- BUG/MEDIUM: applet: Fix test on shut flags for legacy applets (v2)
- DEV: term-events: Fix hanshake events decoding
- BUG/MINOR: flt-trace: Properly compute length of the first DATA block
- MINOR: flt-trace: Add an option to limit the amount of data forwarded
- CLEANUP: compression: Remove unused static buffers
- BUG/MEDIUM: shctx: Use the next block when data exactly filled a block
- BUG/MINOR: http-ana: Stop to wait for body on client error/abort
- MINOR: stconn: Add missing SC_FL_NO_FASTFWD flag in sc_show_flags
- REORG: stconn: Move functions related to channel buffers to sc_strm.h
- BUG/MEDIUM: jwe: fix timing side-channel and dead code in JWE decryption
- MINOR: tree-wide: Use the buffer size instead of global setting when possible
- MINOR: buffers: Swap buffers of same size only
- BUG/MINOR: config: Check buffer pool creation for failures
- MEDIUM: cache: Don't rely on a chunk to store messages payload
- MEDIUM: stream: Limit number of synchronous send per stream wakeup
- MEDIUM: compression: Be sure to never compress more than a chunk at once
- MEDIUM: mux-h1/mux-h2/mux-fcgi/h3: Disable 0-copy for buffers of different size
- MEDIUM: applet: Disable 0-copy for buffers of different size
- MINOR: h1-htx: Disable 0-copy for buffers of different size
- MEDIUM: stream: Offer buffers of default size only
- BUG/MEDIUM: htx: Fix function used to change part of a block value when defrag
- MEDIUM: htx: Refactor transfer of htx blocks to merge DATA blocks if possible
- MEDIUM: htx: Refactor htx defragmentation to merge data blocks
- MEDIUM: htx: Improve detection of fragmented/unordered HTX messages
- MINOR: http-ana: Do a defrag on unaligned HTX message when waiting for payload
- MINOR: http-fetch: Use pointer to HTX DATA block when retrieving HTX body
- MEDIUM: dynbuf: Add a pool for large buffers with a configurable size
- MEDIUM: chunk: Add support for large chunks
- MEDIUM: stconn: Properly handle large buffers during a receive
- MEDIUM: sample: Get chunks with a size dependent on input data when necessary
- MEDIUM: http-fetch: Be able to use large chunks when necessary
- MINPR: htx: Get large chunk if necessary to perform a defrag
- MEDIUM: http-ana: Use a large buffer if necessary when waiting for body
- MINOR: dynbuf: Add helpers to know if a buffer is a default or a large buffer
- MINOR: config: reject configs using HTTP with large bufsize >= 256 MB
- CI: do not use ghcr.io for Quic Interop workflows
- BUG/MEDIUM: ssl: SSL backend sessions used after free
- CI: vtest: move the vtest2 URL to vinyl-cache.org
- CI: github: disable windows.yml by default on unofficials repo
- MEDIUM: Add connect/queue/tarpit timeouts to set-timeout
- CLEANUP: mux-h1: Remove unneeded null check
- DOC: remove openssl no-deprecated CI image
- BUG/MINOR: acme: fix X509_NAME leak when X509_set_issuer_name() fails
- BUG/MINOR: backend: check delay MUX before conn_prepare()
- OPTIM: backend: reduce contention when checking MUX init with ALPN
- DOC: configuration: add the ACME wiki page link
- MINOR: ssl/ckch: Move EVP_PKEY and cert code generation from acme
- MINOR: ssl/ckch: certificates generation from "load" "crt-store" directive
- MINOR: trace: add definitions for haterm streams
- MINOR: init: allow a fileless init mode
- MEDIUM: init: allow the redefinition of argv[] parsing function
- MINOR: stconn: stream instantiation from proxy callback
- MINOR: haterm: add haterm HTTP server
- MINOR: haterm: new "haterm" utility
- MINOR: haterm: increase thread-local pool size
- BUG/MEDIUM: stats-file: fix shm-stats-file recover when all process slots are full
- BUG/MINOR: stats-file: manipulate shm-stats-file heartbeat using unsigned int
- BUG/MEDIUM: stats-file: detect and fix inconsistent shared clock when resuming from shm-stats-file
- CI: github: only enable OS X on development branches
2026/02/04 : 3.4-dev4 2026/02/04 : 3.4-dev4
- BUG/MEDIUM: hlua: fix invalid lua_pcall() usage in hlua_traceback() - BUG/MEDIUM: hlua: fix invalid lua_pcall() usage in hlua_traceback()
- BUG/MINOR: hlua: consume error object if ignored after a failing lua_pcall() - BUG/MINOR: hlua: consume error object if ignored after a failing lua_pcall()

View file

@ -956,7 +956,6 @@ endif # obsolete targets
endif # TARGET endif # TARGET
OBJS = OBJS =
HATERM_OBJS =
ifneq ($(EXTRA_OBJS),) ifneq ($(EXTRA_OBJS),)
OBJS += $(EXTRA_OBJS) OBJS += $(EXTRA_OBJS)
@ -1004,14 +1003,12 @@ OBJS += src/mux_h2.o src/mux_h1.o src/mux_fcgi.o src/log.o \
src/http_acl.o src/dict.o src/dgram.o src/pipe.o \ src/http_acl.o src/dict.o src/dgram.o src/pipe.o \
src/hpack-huff.o src/hpack-enc.o src/ebtree.o src/hash.o \ src/hpack-huff.o src/hpack-enc.o src/ebtree.o src/hash.o \
src/httpclient_cli.o src/version.o src/ncbmbuf.o src/ech.o \ src/httpclient_cli.o src/version.o src/ncbmbuf.o src/ech.o \
src/cfgparse-peers.o src/haterm.o src/cfgparse-peers.o
ifneq ($(TRACE),) ifneq ($(TRACE),)
OBJS += src/calltrace.o OBJS += src/calltrace.o
endif endif
HATERM_OBJS += $(OBJS) src/haterm_init.o
# Used only for forced dependency checking. May be cleared during development. # Used only for forced dependency checking. May be cleared during development.
INCLUDES = $(wildcard include/*/*.h) INCLUDES = $(wildcard include/*/*.h)
DEP = $(INCLUDES) .build_opts DEP = $(INCLUDES) .build_opts
@ -1043,7 +1040,7 @@ IGNORE_OPTS=help install install-man install-doc install-bin \
uninstall clean tags cscope tar git-tar version update-version \ uninstall clean tags cscope tar git-tar version update-version \
opts reg-tests reg-tests-help unit-tests admin/halog/halog dev/flags/flags \ opts reg-tests reg-tests-help unit-tests admin/halog/halog dev/flags/flags \
dev/haring/haring dev/ncpu/ncpu dev/poll/poll dev/tcploop/tcploop \ dev/haring/haring dev/ncpu/ncpu dev/poll/poll dev/tcploop/tcploop \
dev/term_events/term_events dev/gdb/pm-from-core dev/gdb/libs-from-core dev/term_events/term_events
ifneq ($(TARGET),) ifneq ($(TARGET),)
ifeq ($(filter $(firstword $(MAKECMDGOALS)),$(IGNORE_OPTS)),) ifeq ($(filter $(firstword $(MAKECMDGOALS)),$(IGNORE_OPTS)),)
@ -1059,9 +1056,6 @@ endif # non-empty target
haproxy: $(OPTIONS_OBJS) $(OBJS) haproxy: $(OPTIONS_OBJS) $(OBJS)
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS) $(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
haterm: $(OPTIONS_OBJS) $(HATERM_OBJS)
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
objsize: haproxy objsize: haproxy
$(Q)objdump -t $^|grep ' g '|grep -F '.text'|awk '{print $$5 FS $$6}'|sort $(Q)objdump -t $^|grep ' g '|grep -F '.text'|awk '{print $$5 FS $$6}'|sort
@ -1077,12 +1071,6 @@ admin/dyncookie/dyncookie: admin/dyncookie/dyncookie.o
dev/flags/flags: dev/flags/flags.o dev/flags/flags: dev/flags/flags.o
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS) $(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
dev/gdb/libs-from-core: dev/gdb/libs-from-core.o
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
dev/gdb/pm-from-core: dev/gdb/pm-from-core.o
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
dev/haring/haring: dev/haring/haring.o dev/haring/haring: dev/haring/haring.o
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS) $(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
@ -1181,7 +1169,7 @@ distclean: clean
$(Q)rm -f admin/dyncookie/dyncookie $(Q)rm -f admin/dyncookie/dyncookie
$(Q)rm -f dev/haring/haring dev/ncpu/ncpu{,.so} dev/poll/poll dev/tcploop/tcploop $(Q)rm -f dev/haring/haring dev/ncpu/ncpu{,.so} dev/poll/poll dev/tcploop/tcploop
$(Q)rm -f dev/hpack/decode dev/hpack/gen-enc dev/hpack/gen-rht $(Q)rm -f dev/hpack/decode dev/hpack/gen-enc dev/hpack/gen-rht
$(Q)rm -f dev/qpack/decode dev/gdb/pm-from-core dev/gdb/libs-from-core $(Q)rm -f dev/qpack/decode
tags: tags:
$(Q)find src include \( -name '*.c' -o -name '*.h' \) -print0 | \ $(Q)find src include \( -name '*.c' -o -name '*.h' \) -print0 | \
@ -1335,8 +1323,7 @@ range:
echo "[ $$index/$$count ] $$commit #############################"; \ echo "[ $$index/$$count ] $$commit #############################"; \
git checkout -q $$commit || die 1; \ git checkout -q $$commit || die 1; \
$(MAKE) all || die 1; \ $(MAKE) all || die 1; \
set -- $(TEST_CMD); \ [ -z "$(TEST_CMD)" ] || $(TEST_CMD) || die 1; \
[ "$$#" -eq 0 ] || "$$@" || die 1; \
index=$$((index + 1)); \ index=$$((index + 1)); \
done; \ done; \
echo;echo "Done! $${count} commit(s) built successfully for RANGE $${RANGE}" ; \ echo;echo "Done! $${count} commit(s) built successfully for RANGE $${RANGE}" ; \

View file

@ -2,6 +2,7 @@
[![alpine/musl](https://github.com/haproxy/haproxy/actions/workflows/musl.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/musl.yml) [![alpine/musl](https://github.com/haproxy/haproxy/actions/workflows/musl.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/musl.yml)
[![AWS-LC](https://github.com/haproxy/haproxy/actions/workflows/aws-lc.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/aws-lc.yml) [![AWS-LC](https://github.com/haproxy/haproxy/actions/workflows/aws-lc.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/aws-lc.yml)
[![openssl no-deprecated](https://github.com/haproxy/haproxy/actions/workflows/openssl-nodeprecated.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/openssl-nodeprecated.yml)
[![Illumos](https://github.com/haproxy/haproxy/actions/workflows/illumos.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/illumos.yml) [![Illumos](https://github.com/haproxy/haproxy/actions/workflows/illumos.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/illumos.yml)
[![NetBSD](https://github.com/haproxy/haproxy/actions/workflows/netbsd.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/netbsd.yml) [![NetBSD](https://github.com/haproxy/haproxy/actions/workflows/netbsd.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/netbsd.yml)
[![FreeBSD](https://api.cirrus-ci.com/github/haproxy/haproxy.svg?task=FreeBSD)](https://cirrus-ci.com/github/haproxy/haproxy/) [![FreeBSD](https://api.cirrus-ci.com/github/haproxy/haproxy.svg?task=FreeBSD)](https://cirrus-ci.com/github/haproxy/haproxy/)

View file

@ -1,2 +1,2 @@
$Format:%ci$ $Format:%ci$
2026/03/20 2026/02/04

View file

@ -1 +1 @@
3.4-dev7 3.4-dev4

View file

@ -31,7 +31,6 @@ static struct {
da_atlas_t atlas; da_atlas_t atlas;
da_evidence_id_t useragentid; da_evidence_id_t useragentid;
da_severity_t loglevel; da_severity_t loglevel;
size_t maxhdrlen;
char separator; char separator;
unsigned char daset:1; unsigned char daset:1;
} global_deviceatlas = { } global_deviceatlas = {
@ -43,7 +42,6 @@ static struct {
.atlasmap = NULL, .atlasmap = NULL,
.atlasfd = -1, .atlasfd = -1,
.useragentid = 0, .useragentid = 0,
.maxhdrlen = 0,
.daset = 0, .daset = 0,
.separator = '|', .separator = '|',
}; };
@ -59,10 +57,6 @@ static int da_json_file(char **args, int section_type, struct proxy *curpx,
return -1; return -1;
} }
global_deviceatlas.jsonpath = strdup(args[1]); global_deviceatlas.jsonpath = strdup(args[1]);
if (unlikely(global_deviceatlas.jsonpath == NULL)) {
memprintf(err, "deviceatlas json file : out of memory.\n");
return -1;
}
return 0; return 0;
} }
@ -79,7 +73,6 @@ static int da_log_level(char **args, int section_type, struct proxy *curpx,
loglevel = atol(args[1]); loglevel = atol(args[1]);
if (loglevel < 0 || loglevel > 3) { if (loglevel < 0 || loglevel > 3) {
memprintf(err, "deviceatlas log level : expects a log level between 0 and 3, %s given.\n", args[1]); memprintf(err, "deviceatlas log level : expects a log level between 0 and 3, %s given.\n", args[1]);
return -1;
} else { } else {
global_deviceatlas.loglevel = (da_severity_t)loglevel; global_deviceatlas.loglevel = (da_severity_t)loglevel;
} }
@ -108,10 +101,6 @@ static int da_properties_cookie(char **args, int section_type, struct proxy *cur
return -1; return -1;
} else { } else {
global_deviceatlas.cookiename = strdup(args[1]); global_deviceatlas.cookiename = strdup(args[1]);
if (unlikely(global_deviceatlas.cookiename == NULL)) {
memprintf(err, "deviceatlas cookie name : out of memory.\n");
return -1;
}
} }
global_deviceatlas.cookienamelen = strlen(global_deviceatlas.cookiename); global_deviceatlas.cookienamelen = strlen(global_deviceatlas.cookiename);
return 0; return 0;
@ -130,7 +119,6 @@ static int da_cache_size(char **args, int section_type, struct proxy *curpx,
cachesize = atol(args[1]); cachesize = atol(args[1]);
if (cachesize < 0 || cachesize > DA_CACHE_MAX) { if (cachesize < 0 || cachesize > DA_CACHE_MAX) {
memprintf(err, "deviceatlas cache size : expects a cache size between 0 and %d, %s given.\n", DA_CACHE_MAX, args[1]); memprintf(err, "deviceatlas cache size : expects a cache size between 0 and %d, %s given.\n", DA_CACHE_MAX, args[1]);
return -1;
} else { } else {
#ifdef APINOCACHE #ifdef APINOCACHE
fprintf(stdout, "deviceatlas cache size : no-op, its support is disabled.\n"); fprintf(stdout, "deviceatlas cache size : no-op, its support is disabled.\n");
@ -177,7 +165,7 @@ static int init_deviceatlas(void)
da_status_t status; da_status_t status;
jsonp = fopen(global_deviceatlas.jsonpath, "r"); jsonp = fopen(global_deviceatlas.jsonpath, "r");
if (unlikely(jsonp == 0)) { if (jsonp == 0) {
ha_alert("deviceatlas : '%s' json file has invalid path or is not readable.\n", ha_alert("deviceatlas : '%s' json file has invalid path or is not readable.\n",
global_deviceatlas.jsonpath); global_deviceatlas.jsonpath);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
@ -189,11 +177,9 @@ static int init_deviceatlas(void)
status = da_atlas_compile(jsonp, da_haproxy_read, da_haproxy_seek, status = da_atlas_compile(jsonp, da_haproxy_read, da_haproxy_seek,
&global_deviceatlas.atlasimgptr, &atlasimglen); &global_deviceatlas.atlasimgptr, &atlasimglen);
fclose(jsonp); fclose(jsonp);
if (unlikely(status != DA_OK)) { if (status != DA_OK) {
ha_alert("deviceatlas : '%s' json file is invalid.\n", ha_alert("deviceatlas : '%s' json file is invalid.\n",
global_deviceatlas.jsonpath); global_deviceatlas.jsonpath);
free(global_deviceatlas.atlasimgptr);
da_fini();
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -201,10 +187,8 @@ static int init_deviceatlas(void)
status = da_atlas_open(&global_deviceatlas.atlas, extraprops, status = da_atlas_open(&global_deviceatlas.atlas, extraprops,
global_deviceatlas.atlasimgptr, atlasimglen); global_deviceatlas.atlasimgptr, atlasimglen);
if (unlikely(status != DA_OK)) { if (status != DA_OK) {
ha_alert("deviceatlas : data could not be compiled.\n"); ha_alert("deviceatlas : data could not be compiled.\n");
free(global_deviceatlas.atlasimgptr);
da_fini();
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
@ -213,28 +197,11 @@ static int init_deviceatlas(void)
if (global_deviceatlas.cookiename == 0) { if (global_deviceatlas.cookiename == 0) {
global_deviceatlas.cookiename = strdup(DA_COOKIENAME_DEFAULT); global_deviceatlas.cookiename = strdup(DA_COOKIENAME_DEFAULT);
if (unlikely(global_deviceatlas.cookiename == NULL)) {
ha_alert("deviceatlas : out of memory.\n");
da_atlas_close(&global_deviceatlas.atlas);
free(global_deviceatlas.atlasimgptr);
da_fini();
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
global_deviceatlas.cookienamelen = strlen(global_deviceatlas.cookiename); global_deviceatlas.cookienamelen = strlen(global_deviceatlas.cookiename);
} }
global_deviceatlas.useragentid = da_atlas_header_evidence_id(&global_deviceatlas.atlas, global_deviceatlas.useragentid = da_atlas_header_evidence_id(&global_deviceatlas.atlas,
"user-agent"); "user-agent");
{
size_t hi;
global_deviceatlas.maxhdrlen = 16;
for (hi = 0; hi < global_deviceatlas.atlas.header_evidence_count; hi++) {
size_t nl = strlen(global_deviceatlas.atlas.header_priorities[hi].name);
if (nl > global_deviceatlas.maxhdrlen)
global_deviceatlas.maxhdrlen = nl;
}
}
if ((global_deviceatlas.atlasfd = shm_open(ATLASMAPNM, O_RDWR, 0660)) != -1) { if ((global_deviceatlas.atlasfd = shm_open(ATLASMAPNM, O_RDWR, 0660)) != -1) {
global_deviceatlas.atlasmap = mmap(NULL, ATLASTOKSZ, PROT_READ | PROT_WRITE, MAP_SHARED, global_deviceatlas.atlasfd, 0); global_deviceatlas.atlasmap = mmap(NULL, ATLASTOKSZ, PROT_READ | PROT_WRITE, MAP_SHARED, global_deviceatlas.atlasfd, 0);
if (global_deviceatlas.atlasmap == MAP_FAILED) { if (global_deviceatlas.atlasmap == MAP_FAILED) {
@ -264,13 +231,15 @@ static void deinit_deviceatlas(void)
free(global_deviceatlas.cookiename); free(global_deviceatlas.cookiename);
da_atlas_close(&global_deviceatlas.atlas); da_atlas_close(&global_deviceatlas.atlas);
free(global_deviceatlas.atlasimgptr); free(global_deviceatlas.atlasimgptr);
da_fini();
} }
if (global_deviceatlas.atlasfd != -1) { if (global_deviceatlas.atlasfd != -1) {
munmap(global_deviceatlas.atlasmap, ATLASTOKSZ); munmap(global_deviceatlas.atlasmap, ATLASTOKSZ);
close(global_deviceatlas.atlasfd); close(global_deviceatlas.atlasfd);
shm_unlink(ATLASMAPNM);
} }
da_fini();
} }
static void da_haproxy_checkinst(void) static void da_haproxy_checkinst(void)
@ -289,10 +258,6 @@ static void da_haproxy_checkinst(void)
da_property_decl_t extraprops[1] = {{NULL, 0}}; da_property_decl_t extraprops[1] = {{NULL, 0}};
#ifdef USE_THREAD #ifdef USE_THREAD
HA_SPIN_LOCK(OTHER_LOCK, &dadwsch_lock); HA_SPIN_LOCK(OTHER_LOCK, &dadwsch_lock);
if (base[0] == 0) {
HA_SPIN_UNLOCK(OTHER_LOCK, &dadwsch_lock);
return;
}
#endif #endif
strlcpy2(atlasp, base + sizeof(char), sizeof(atlasp)); strlcpy2(atlasp, base + sizeof(char), sizeof(atlasp));
jsonp = fopen(atlasp, "r"); jsonp = fopen(atlasp, "r");
@ -310,20 +275,10 @@ static void da_haproxy_checkinst(void)
fclose(jsonp); fclose(jsonp);
if (status == DA_OK) { if (status == DA_OK) {
if (da_atlas_open(&inst, extraprops, cnew, atlassz) == DA_OK) { if (da_atlas_open(&inst, extraprops, cnew, atlassz) == DA_OK) {
inst.config.cache_size = global_deviceatlas.cachesize;
da_atlas_close(&global_deviceatlas.atlas); da_atlas_close(&global_deviceatlas.atlas);
free(global_deviceatlas.atlasimgptr); free(global_deviceatlas.atlasimgptr);
global_deviceatlas.atlasimgptr = cnew; global_deviceatlas.atlasimgptr = cnew;
global_deviceatlas.atlas = inst; global_deviceatlas.atlas = inst;
{
size_t hi;
global_deviceatlas.maxhdrlen = 16;
for (hi = 0; hi < inst.header_evidence_count; hi++) {
size_t nl = strlen(inst.header_priorities[hi].name);
if (nl > global_deviceatlas.maxhdrlen)
global_deviceatlas.maxhdrlen = nl;
}
}
base[0] = 0; base[0] = 0;
ha_notice("deviceatlas : new instance, data file date `%s`.\n", ha_notice("deviceatlas : new instance, data file date `%s`.\n",
da_getdatacreationiso8601(&global_deviceatlas.atlas)); da_getdatacreationiso8601(&global_deviceatlas.atlas));
@ -331,8 +286,6 @@ static void da_haproxy_checkinst(void)
ha_alert("deviceatlas : instance update failed.\n"); ha_alert("deviceatlas : instance update failed.\n");
free(cnew); free(cnew);
} }
} else {
free(cnew);
} }
#ifdef USE_THREAD #ifdef USE_THREAD
HA_SPIN_UNLOCK(OTHER_LOCK, &dadwsch_lock); HA_SPIN_UNLOCK(OTHER_LOCK, &dadwsch_lock);
@ -344,7 +297,7 @@ static void da_haproxy_checkinst(void)
static int da_haproxy(const struct arg *args, struct sample *smp, da_deviceinfo_t *devinfo) static int da_haproxy(const struct arg *args, struct sample *smp, da_deviceinfo_t *devinfo)
{ {
struct buffer *tmp; struct buffer *tmp;
da_propid_t prop; da_propid_t prop, *pprop;
da_status_t status; da_status_t status;
da_type_t proptype; da_type_t proptype;
const char *propname; const char *propname;
@ -364,15 +317,13 @@ static int da_haproxy(const struct arg *args, struct sample *smp, da_deviceinfo_
chunk_appendf(tmp, "%c", global_deviceatlas.separator); chunk_appendf(tmp, "%c", global_deviceatlas.separator);
continue; continue;
} }
if (unlikely(da_atlas_getproptype(&global_deviceatlas.atlas, prop, &proptype) != DA_OK)) { pprop = &prop;
chunk_appendf(tmp, "%c", global_deviceatlas.separator); da_atlas_getproptype(&global_deviceatlas.atlas, *pprop, &proptype);
continue;
}
switch (proptype) { switch (proptype) {
case DA_TYPE_BOOLEAN: { case DA_TYPE_BOOLEAN: {
bool val; bool val;
status = da_getpropboolean(devinfo, prop, &val); status = da_getpropboolean(devinfo, *pprop, &val);
if (status == DA_OK) { if (status == DA_OK) {
chunk_appendf(tmp, "%d", val); chunk_appendf(tmp, "%d", val);
} }
@ -381,7 +332,7 @@ static int da_haproxy(const struct arg *args, struct sample *smp, da_deviceinfo_
case DA_TYPE_INTEGER: case DA_TYPE_INTEGER:
case DA_TYPE_NUMBER: { case DA_TYPE_NUMBER: {
long val; long val;
status = da_getpropinteger(devinfo, prop, &val); status = da_getpropinteger(devinfo, *pprop, &val);
if (status == DA_OK) { if (status == DA_OK) {
chunk_appendf(tmp, "%ld", val); chunk_appendf(tmp, "%ld", val);
} }
@ -389,7 +340,7 @@ static int da_haproxy(const struct arg *args, struct sample *smp, da_deviceinfo_
} }
case DA_TYPE_STRING: { case DA_TYPE_STRING: {
const char *val; const char *val;
status = da_getpropstring(devinfo, prop, &val); status = da_getpropstring(devinfo, *pprop, &val);
if (status == DA_OK) { if (status == DA_OK) {
chunk_appendf(tmp, "%s", val); chunk_appendf(tmp, "%s", val);
} }
@ -420,26 +371,29 @@ static int da_haproxy_conv(const struct arg *args, struct sample *smp, void *pri
{ {
da_deviceinfo_t devinfo; da_deviceinfo_t devinfo;
da_status_t status; da_status_t status;
char useragentbuf[1024]; const char *useragent;
char useragentbuf[1024] = { 0 };
int i; int i;
if (unlikely(global_deviceatlas.daset == 0) || smp->data.u.str.data == 0) { if (global_deviceatlas.daset == 0 || smp->data.u.str.data == 0) {
return 1; return 1;
} }
da_haproxy_checkinst(); da_haproxy_checkinst();
i = smp->data.u.str.data > sizeof(useragentbuf) - 1 ? sizeof(useragentbuf) - 1 : smp->data.u.str.data; i = smp->data.u.str.data > sizeof(useragentbuf) ? sizeof(useragentbuf) : smp->data.u.str.data;
memcpy(useragentbuf, smp->data.u.str.area, i); memcpy(useragentbuf, smp->data.u.str.area, i - 1);
useragentbuf[i] = 0; useragentbuf[i - 1] = 0;
useragent = (const char *)useragentbuf;
status = da_search(&global_deviceatlas.atlas, &devinfo, status = da_search(&global_deviceatlas.atlas, &devinfo,
global_deviceatlas.useragentid, useragentbuf, 0); global_deviceatlas.useragentid, useragent, 0);
return status != DA_OK ? 0 : da_haproxy(args, smp, &devinfo); return status != DA_OK ? 0 : da_haproxy(args, smp, &devinfo);
} }
#define DA_MAX_HEADERS 32 #define DA_MAX_HEADERS 24
static int da_haproxy_fetch(const struct arg *args, struct sample *smp, const char *kw, void *private) static int da_haproxy_fetch(const struct arg *args, struct sample *smp, const char *kw, void *private)
{ {
@ -449,10 +403,10 @@ static int da_haproxy_fetch(const struct arg *args, struct sample *smp, const ch
struct channel *chn; struct channel *chn;
struct htx *htx; struct htx *htx;
struct htx_blk *blk; struct htx_blk *blk;
char vbuf[DA_MAX_HEADERS][1024]; char vbuf[DA_MAX_HEADERS][1024] = {{ 0 }};
int i, nbh = 0; int i, nbh = 0;
if (unlikely(global_deviceatlas.daset == 0)) { if (global_deviceatlas.daset == 0) {
return 0; return 0;
} }
@ -460,17 +414,18 @@ static int da_haproxy_fetch(const struct arg *args, struct sample *smp, const ch
chn = (smp->strm ? &smp->strm->req : NULL); chn = (smp->strm ? &smp->strm->req : NULL);
htx = smp_prefetch_htx(smp, chn, NULL, 1); htx = smp_prefetch_htx(smp, chn, NULL, 1);
if (unlikely(!htx)) if (!htx)
return 0; return 0;
i = 0;
for (blk = htx_get_first_blk(htx); nbh < DA_MAX_HEADERS && blk; blk = htx_get_next_blk(htx, blk)) { for (blk = htx_get_first_blk(htx); nbh < DA_MAX_HEADERS && blk; blk = htx_get_next_blk(htx, blk)) {
size_t vlen; size_t vlen;
char *pval; char *pval;
da_evidence_id_t evid; da_evidence_id_t evid;
enum htx_blk_type type; enum htx_blk_type type;
struct ist n, v; struct ist n, v;
char hbuf[64]; char hbuf[24] = { 0 };
char tval[1024]; char tval[1024] = { 0 };
type = htx_get_blk_type(blk); type = htx_get_blk_type(blk);
@ -483,18 +438,20 @@ static int da_haproxy_fetch(const struct arg *args, struct sample *smp, const ch
continue; continue;
} }
if (n.len > global_deviceatlas.maxhdrlen || n.len >= sizeof(hbuf)) { /* The HTTP headers used by the DeviceAtlas API are not longer */
if (n.len >= sizeof(hbuf)) {
continue; continue;
} }
memcpy(hbuf, n.ptr, n.len); memcpy(hbuf, n.ptr, n.len);
hbuf[n.len] = 0; hbuf[n.len] = 0;
pval = v.ptr;
vlen = v.len;
evid = -1; evid = -1;
i = v.len > sizeof(tval) - 1 ? sizeof(tval) - 1 : v.len; i = v.len > sizeof(tval) - 1 ? sizeof(tval) - 1 : v.len;
memcpy(tval, v.ptr, i); memcpy(tval, v.ptr, i);
tval[i] = 0; tval[i] = 0;
pval = tval; pval = tval;
vlen = i;
if (strcasecmp(hbuf, "Accept-Language") == 0) { if (strcasecmp(hbuf, "Accept-Language") == 0) {
evid = da_atlas_accept_language_evidence_id(&global_deviceatlas.atlas); evid = da_atlas_accept_language_evidence_id(&global_deviceatlas.atlas);
@ -512,7 +469,7 @@ static int da_haproxy_fetch(const struct arg *args, struct sample *smp, const ch
continue; continue;
} }
vlen = pl; vlen -= global_deviceatlas.cookienamelen - 1;
pval = p; pval = p;
evid = da_atlas_clientprop_evidence_id(&global_deviceatlas.atlas); evid = da_atlas_clientprop_evidence_id(&global_deviceatlas.atlas);
} else { } else {

View file

@ -141,11 +141,6 @@ enum {
DA_INITIAL_MEMORY_ESTIMATE = 1024 * 1024 * 14 DA_INITIAL_MEMORY_ESTIMATE = 1024 * 1024 * 14
}; };
struct header_evidence_entry {
const char *name;
da_evidence_id_t id;
};
struct da_config { struct da_config {
unsigned int cache_size; unsigned int cache_size;
unsigned int __reserved[15]; /* enough reserved keywords for future use */ unsigned int __reserved[15]; /* enough reserved keywords for future use */

View file

@ -407,7 +407,6 @@ listed below. Metrics from extra counters are not listed.
+----------------------------------------------------+ +----------------------------------------------------+
| haproxy_sticktable_size | | haproxy_sticktable_size |
| haproxy_sticktable_used | | haproxy_sticktable_used |
| haproxy_sticktable_local_updates |
+----------------------------------------------------+ +----------------------------------------------------+
* Resolvers metrics * Resolvers metrics

View file

@ -36,7 +36,6 @@
#include <haproxy/stats.h> #include <haproxy/stats.h>
#include <haproxy/stconn.h> #include <haproxy/stconn.h>
#include <haproxy/stream.h> #include <haproxy/stream.h>
#include <haproxy/stress.h>
#include <haproxy/task.h> #include <haproxy/task.h>
#include <haproxy/tools.h> #include <haproxy/tools.h>
#include <haproxy/version.h> #include <haproxy/version.h>
@ -83,7 +82,6 @@ struct promex_ctx {
unsigned field_num; /* current field number (ST_I_PX_* etc) */ unsigned field_num; /* current field number (ST_I_PX_* etc) */
unsigned mod_field_num; /* first field number of the current module (ST_I_PX_* etc) */ unsigned mod_field_num; /* first field number of the current module (ST_I_PX_* etc) */
int obj_state; /* current state among PROMEX_{FRONT|BACK|SRV|LI}_STATE_* */ int obj_state; /* current state among PROMEX_{FRONT|BACK|SRV|LI}_STATE_* */
struct watcher px_watch; /* watcher to automatically update next pointer */
struct watcher srv_watch; /* watcher to automatically update next pointer */ struct watcher srv_watch; /* watcher to automatically update next pointer */
struct list modules; /* list of promex modules to export */ struct list modules; /* list of promex modules to export */
struct eb_root filters; /* list of filters to apply on metrics name */ struct eb_root filters; /* list of filters to apply on metrics name */
@ -349,10 +347,6 @@ static int promex_dump_ts(struct appctx *appctx, struct ist prefix,
istcat(&n, prefix, PROMEX_MAX_NAME_LEN); istcat(&n, prefix, PROMEX_MAX_NAME_LEN);
istcat(&n, name, PROMEX_MAX_NAME_LEN); istcat(&n, name, PROMEX_MAX_NAME_LEN);
/* In stress mode, force yielding on each metric. */
if (STRESS_RUN1(istlen(*out), 0))
goto full;
if ((ctx->flags & PROMEX_FL_METRIC_HDR) && if ((ctx->flags & PROMEX_FL_METRIC_HDR) &&
!promex_dump_ts_header(n, desc, type, out, max)) !promex_dump_ts_header(n, desc, type, out, max))
goto full; goto full;
@ -632,6 +626,8 @@ static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx)
} }
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) { list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
void *counters;
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_FE)) if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_FE))
continue; continue;
@ -668,7 +664,8 @@ static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx)
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE)) if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE))
goto next_px2; goto next_px2;
if (!mod->fill_stats(mod, px->extra_counters_fe, stats + ctx->field_num, &ctx->mod_field_num)) counters = EXTRA_COUNTERS_GET(px->extra_counters_fe, mod);
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
return -1; return -1;
val = stats[ctx->field_num + ctx->mod_field_num]; val = stats[ctx->field_num + ctx->mod_field_num];
@ -820,6 +817,8 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
} }
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) { list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
void *counters;
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_LI)) if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_LI))
continue; continue;
@ -865,7 +864,8 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
labels[lb_idx+1].name = ist("mod"); labels[lb_idx+1].name = ist("mod");
labels[lb_idx+1].value = ist2(mod->name, strlen(mod->name)); labels[lb_idx+1].value = ist2(mod->name, strlen(mod->name));
if (!mod->fill_stats(mod, li->extra_counters, stats + ctx->field_num, &ctx->mod_field_num)) counters = EXTRA_COUNTERS_GET(li->extra_counters, mod);
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
return -1; return -1;
val = stats[ctx->field_num + ctx->mod_field_num]; val = stats[ctx->field_num + ctx->mod_field_num];
@ -941,6 +941,9 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
if (promex_filter_metric(appctx, prefix, name)) if (promex_filter_metric(appctx, prefix, name))
continue; continue;
if (!px)
px = proxies_list;
while (px) { while (px) {
struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
unsigned int srv_state_count[PROMEX_SRV_STATE_COUNT] = { 0 }; unsigned int srv_state_count[PROMEX_SRV_STATE_COUNT] = { 0 };
@ -1095,16 +1098,9 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
&val, labels, &out, max)) &val, labels, &out, max))
goto full; goto full;
next_px: next_px:
px = watcher_next(&ctx->px_watch, px->next); px = px->next;
} }
watcher_detach(&ctx->px_watch);
ctx->flags |= PROMEX_FL_METRIC_HDR; ctx->flags |= PROMEX_FL_METRIC_HDR;
/* Prepare a new iteration for the next stat column.
* Update ctx.p[0] via watcher.
*/
watcher_attach(&ctx->px_watch, proxies_list);
px = proxies_list;
} }
/* Skip extra counters */ /* Skip extra counters */
@ -1117,6 +1113,8 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
} }
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) { list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
void *counters;
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_BE)) if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_BE))
continue; continue;
@ -1127,6 +1125,9 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
if (promex_filter_metric(appctx, prefix, name)) if (promex_filter_metric(appctx, prefix, name))
continue; continue;
if (!px)
px = proxies_list;
while (px) { while (px) {
struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
struct promex_metric metric; struct promex_metric metric;
@ -1150,7 +1151,8 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE)) if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
goto next_px2; goto next_px2;
if (!mod->fill_stats(mod, px->extra_counters_be, stats + ctx->field_num, &ctx->mod_field_num)) counters = EXTRA_COUNTERS_GET(px->extra_counters_be, mod);
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
return -1; return -1;
val = stats[ctx->field_num + ctx->mod_field_num]; val = stats[ctx->field_num + ctx->mod_field_num];
@ -1161,39 +1163,25 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
goto full; goto full;
next_px2: next_px2:
px = watcher_next(&ctx->px_watch, px->next); px = px->next;
} }
watcher_detach(&ctx->px_watch);
ctx->flags |= PROMEX_FL_METRIC_HDR; ctx->flags |= PROMEX_FL_METRIC_HDR;
/* Prepare a new iteration for the next stat column.
* Update ctx.p[0] via watcher.
*/
watcher_attach(&ctx->px_watch, proxies_list);
px = proxies_list;
} }
ctx->field_num += mod->stats_count; ctx->field_num += mod->stats_count;
ctx->mod_field_num = 0; ctx->mod_field_num = 0;
} }
end: px = NULL;
if (ret) {
watcher_detach(&ctx->px_watch);
mod = NULL; mod = NULL;
}
end:
if (out.len) { if (out.len) {
if (!htx_add_data_atonce(htx, out)) { if (!htx_add_data_atonce(htx, out))
watcher_detach(&ctx->px_watch);
return -1; /* Unexpected and unrecoverable error */ return -1; /* Unexpected and unrecoverable error */
} }
} /* Save pointers (0=current proxy, 1=current stats module) of the current context */
ctx->p[0] = px;
/* Save pointers of the current context for dump resumption :
* 0=current proxy, 1=current stats module
* Note that p[0] is already automatically updated via px_watch.
*/
ctx->p[1] = mod; ctx->p[1] = mod;
return ret; return ret;
full: full:
@ -1235,6 +1223,9 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
if (promex_filter_metric(appctx, prefix, name)) if (promex_filter_metric(appctx, prefix, name))
continue; continue;
if (!px)
px = proxies_list;
while (px) { while (px) {
struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
enum promex_mt_type type; enum promex_mt_type type;
@ -1254,6 +1245,11 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE)) if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
goto next_px; goto next_px;
if (!sv) {
watcher_attach(&ctx->srv_watch, px->srv);
sv = px->srv;
}
while (sv) { while (sv) {
labels[lb_idx].name = ist("server"); labels[lb_idx].name = ist("server");
labels[lb_idx].value = ist2(sv->id, strlen(sv->id)); labels[lb_idx].value = ist2(sv->id, strlen(sv->id));
@ -1409,25 +1405,9 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
next_px: next_px:
watcher_detach(&ctx->srv_watch); watcher_detach(&ctx->srv_watch);
px = watcher_next(&ctx->px_watch, px->next); px = px->next;
if (px) {
/* Update ctx.p[1] via watcher. */
watcher_attach(&ctx->srv_watch, px->srv);
sv = ctx->p[1];
} }
}
watcher_detach(&ctx->px_watch);
ctx->flags |= PROMEX_FL_METRIC_HDR; ctx->flags |= PROMEX_FL_METRIC_HDR;
/* Prepare a new iteration for the next stat column.
* Update ctx.p[0]/p[1] via px_watch/srv_watch.
*/
watcher_attach(&ctx->px_watch, proxies_list);
px = proxies_list;
if (likely(px)) {
watcher_attach(&ctx->srv_watch, px->srv);
sv = ctx->p[1];
}
} }
/* Skip extra counters */ /* Skip extra counters */
@ -1440,6 +1420,8 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
} }
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) { list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
void *counters;
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_SRV)) if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_SRV))
continue; continue;
@ -1450,6 +1432,9 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
if (promex_filter_metric(appctx, prefix, name)) if (promex_filter_metric(appctx, prefix, name))
continue; continue;
if (!px)
px = proxies_list;
while (px) { while (px) {
struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
struct promex_metric metric; struct promex_metric metric;
@ -1470,6 +1455,11 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE)) if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
goto next_px2; goto next_px2;
if (!sv) {
watcher_attach(&ctx->srv_watch, px->srv);
sv = px->srv;
}
while (sv) { while (sv) {
labels[lb_idx].name = ist("server"); labels[lb_idx].name = ist("server");
labels[lb_idx].value = ist2(sv->id, strlen(sv->id)); labels[lb_idx].value = ist2(sv->id, strlen(sv->id));
@ -1481,7 +1471,8 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
goto next_sv2; goto next_sv2;
if (!mod->fill_stats(mod, sv->extra_counters, stats + ctx->field_num, &ctx->mod_field_num)) counters = EXTRA_COUNTERS_GET(sv->extra_counters, mod);
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
goto error; goto error;
val = stats[ctx->field_num + ctx->mod_field_num]; val = stats[ctx->field_num + ctx->mod_field_num];
@ -1497,47 +1488,28 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
next_px2: next_px2:
watcher_detach(&ctx->srv_watch); watcher_detach(&ctx->srv_watch);
px = watcher_next(&ctx->px_watch, px->next); px = px->next;
if (px) {
/* Update ctx.p[1] via watcher. */
watcher_attach(&ctx->srv_watch, px->srv);
sv = ctx->p[1];
} }
}
watcher_detach(&ctx->px_watch);
ctx->flags |= PROMEX_FL_METRIC_HDR; ctx->flags |= PROMEX_FL_METRIC_HDR;
/* Prepare a new iteration for the next stat column.
* Update ctx.p[0]/p[1] via px_watch/srv_watch.
*/
watcher_attach(&ctx->px_watch, proxies_list);
px = proxies_list;
if (likely(px)) {
watcher_attach(&ctx->srv_watch, px->srv);
sv = ctx->p[1];
}
} }
ctx->field_num += mod->stats_count; ctx->field_num += mod->stats_count;
ctx->mod_field_num = 0; ctx->mod_field_num = 0;
} }
end: px = NULL;
if (ret) { sv = NULL;
watcher_detach(&ctx->px_watch);
watcher_detach(&ctx->srv_watch);
mod = NULL; mod = NULL;
}
end:
if (out.len) { if (out.len) {
if (!htx_add_data_atonce(htx, out)) if (!htx_add_data_atonce(htx, out))
return -1; /* Unexpected and unrecoverable error */ return -1; /* Unexpected and unrecoverable error */
} }
/* Save pointers of the current context for dump resumption : /* Save pointers (0=current proxy, 1=current server, 2=current stats module) of the current context */
* 0=current proxy, 1=current server, 2=current stats module ctx->p[0] = px;
* Note that p[0]/p[1] are already automatically updated via px_watch/srv_watch. ctx->p[1] = sv;
*/
ctx->p[2] = mod; ctx->p[2] = mod;
return ret; return ret;
full: full:
@ -1545,7 +1517,6 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
goto end; goto end;
error: error:
watcher_detach(&ctx->px_watch);
watcher_detach(&ctx->srv_watch); watcher_detach(&ctx->srv_watch);
return -1; return -1;
} }
@ -1768,11 +1739,6 @@ static int promex_dump_metrics(struct appctx *appctx, struct htx *htx)
ctx->field_num = ST_I_PX_PXNAME; ctx->field_num = ST_I_PX_PXNAME;
ctx->mod_field_num = 0; ctx->mod_field_num = 0;
appctx->st1 = PROMEX_DUMPER_BACK; appctx->st1 = PROMEX_DUMPER_BACK;
if (ctx->flags & PROMEX_FL_SCOPE_BACK) {
/* Update ctx.p[0] via watcher. */
watcher_attach(&ctx->px_watch, proxies_list);
}
__fallthrough; __fallthrough;
case PROMEX_DUMPER_BACK: case PROMEX_DUMPER_BACK:
@ -1790,15 +1756,6 @@ static int promex_dump_metrics(struct appctx *appctx, struct htx *htx)
ctx->field_num = ST_I_PX_PXNAME; ctx->field_num = ST_I_PX_PXNAME;
ctx->mod_field_num = 0; ctx->mod_field_num = 0;
appctx->st1 = PROMEX_DUMPER_SRV; appctx->st1 = PROMEX_DUMPER_SRV;
if (ctx->flags & PROMEX_FL_SCOPE_SERVER) {
/* Update ctx.p[0] via watcher. */
watcher_attach(&ctx->px_watch, proxies_list);
if (likely(proxies_list)) {
/* Update ctx.p[1] via watcher. */
watcher_attach(&ctx->srv_watch, proxies_list->srv);
}
}
__fallthrough; __fallthrough;
case PROMEX_DUMPER_SRV: case PROMEX_DUMPER_SRV:
@ -2076,7 +2033,6 @@ static int promex_appctx_init(struct appctx *appctx)
LIST_INIT(&ctx->modules); LIST_INIT(&ctx->modules);
ctx->filters = EB_ROOT; ctx->filters = EB_ROOT;
appctx->st0 = PROMEX_ST_INIT; appctx->st0 = PROMEX_ST_INIT;
watcher_init(&ctx->px_watch, &ctx->p[0], offsetof(struct proxy, watcher_list));
watcher_init(&ctx->srv_watch, &ctx->p[1], offsetof(struct server, watcher_list)); watcher_init(&ctx->srv_watch, &ctx->p[1], offsetof(struct server, watcher_list));
return 0; return 0;
} }
@ -2091,11 +2047,6 @@ static void promex_appctx_release(struct appctx *appctx)
struct promex_metric_filter *flt; struct promex_metric_filter *flt;
struct eb32_node *node, *next; struct eb32_node *node, *next;
if (appctx->st1 == PROMEX_DUMPER_BACK ||
appctx->st1 == PROMEX_DUMPER_SRV) {
watcher_detach(&ctx->px_watch);
}
if (appctx->st1 == PROMEX_DUMPER_SRV) if (appctx->st1 == PROMEX_DUMPER_SRV)
watcher_detach(&ctx->srv_watch); watcher_detach(&ctx->srv_watch);

View file

@ -1,10 +1,11 @@
#!/bin/sh #!/bin/bash
set -e set -e
export VERBOSE=1 export VERBOSE=1
export TIMEOUT=90 export TIMEOUT=90
export MASTER_SOCKET="${MASTER_SOCKET:-/var/run/haproxy-master.sock}" export MASTER_SOCKET=${MASTER_SOCKET:-/var/run/haproxy-master.sock}
export RET=
alert() { alert() {
if [ "$VERBOSE" -ge "1" ]; then if [ "$VERBOSE" -ge "1" ]; then
@ -14,38 +15,32 @@ alert() {
reload() { reload() {
if [ -S "$MASTER_SOCKET" ]; then while read -r line; do
socat_addr="UNIX-CONNECT:${MASTER_SOCKET}"
if [ "$line" = "Success=0" ]; then
RET=1
elif [ "$line" = "Success=1" ]; then
RET=0
elif [ "$line" = "Another reload is still in progress." ]; then
alert "$line"
elif [ "$line" = "--" ]; then
continue;
else else
case "$MASTER_SOCKET" in if [ "$RET" = 1 ] && [ "$VERBOSE" = "2" ]; then
*:[0-9]*) echo "$line" >&2
socat_addr="TCP:${MASTER_SOCKET}" elif [ "$VERBOSE" = "3" ]; then
;; echo "$line" >&2
*) fi
alert "Invalid master socket address '${MASTER_SOCKET}': expected a UNIX socket file or <host>:<port>" fi
done < <(echo "reload" | socat -t"${TIMEOUT}" "${MASTER_SOCKET}" -)
if [ -z "$RET" ]; then
alert "Couldn't finish the reload before the timeout (${TIMEOUT})."
return 1 return 1
;;
esac
fi fi
echo "reload" | socat -t"${TIMEOUT}" "$socat_addr" - | { return "$RET"
read -r status || { alert "No status received (connection error or timeout after ${TIMEOUT}s)."; exit 1; }
case "$status" in
"Success=1") ret=0 ;;
"Success=0") ret=1 ;;
*) alert "Unexpected response: '$status'"; exit 1 ;;
esac
read -r _ # consume "--"
if [ "$VERBOSE" -ge 3 ] || { [ "$ret" = 1 ] && [ "$VERBOSE" -ge 2 ]; }; then
cat >&2
else
cat >/dev/null
fi
exit "$ret"
}
} }
usage() { usage() {
@ -57,12 +52,12 @@ usage() {
echo " EXPERIMENTAL script!" echo " EXPERIMENTAL script!"
echo "" echo ""
echo "Options:" echo "Options:"
echo " -S, --master-socket <addr> Unix socket path or <host>:<port> (default: ${MASTER_SOCKET})" echo " -S, --master-socket <path> Use the master socket at <path> (default: ${MASTER_SOCKET})"
echo " -d, --debug Debug mode, set -x" echo " -d, --debug Debug mode, set -x"
echo " -t, --timeout Timeout (socat -t) (default: ${TIMEOUT})" echo " -t, --timeout Timeout (socat -t) (default: ${TIMEOUT})"
echo " -s, --silent Silent mode (no output)" echo " -s, --silent Silent mode (no output)"
echo " -v, --verbose Verbose output (output from haproxy on failure)" echo " -v, --verbose Verbose output (output from haproxy on failure)"
echo " -vv --verbose=all Very verbose output (output from haproxy on success and failure)" echo " -vv Even more verbose output (output from haproxy on success and failure)"
echo " -h, --help This help" echo " -h, --help This help"
echo "" echo ""
echo "Examples:" echo "Examples:"
@ -89,7 +84,7 @@ main() {
VERBOSE=2 VERBOSE=2
shift shift
;; ;;
-vv|--verbose=all) -vv|--verbose)
VERBOSE=3 VERBOSE=3
shift shift
;; ;;

View file

@ -1,162 +0,0 @@
/*
* Extracts the libs archives from a core dump
*
* Copyright (C) 2026 Willy Tarreau <w@1wt.eu>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/* Note: builds with no option under glibc, and can be built as a minimal
* uploadable static executable using nolibc as well:
gcc -o libs-from-core -nostdinc -nostdlib -s -Os -static -fno-ident \
-fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables \
-Wl,--gc-sections,--orphan-handling=discard,-znoseparate-code \
-I /path/to/nolibc-sysroot/include libs-from-core.c
*/
#define _GNU_SOURCE
#include <sys/mman.h>
#include <sys/stat.h>
#include <elf.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void usage(const char *progname)
{
const char *slash = strrchr(progname, '/');
if (slash)
progname = slash + 1;
fprintf(stderr,
"Usage: %s [-q] <core_file>\n"
"Locate a libs archive from an haproxy core dump and dump it to stdout.\n"
"Arguments:\n"
" -q Query mode: only report offset and length, do not dump\n"
" core_file Core dump produced by haproxy\n",
progname);
}
int main(int argc, char **argv)
{
Elf64_Ehdr *ehdr;
Elf64_Phdr *phdr;
struct stat st;
uint8_t *mem;
int i, fd;
const char *fname;
int quiet = 0;
int arg;
for (arg = 1; arg < argc; arg++) {
if (*argv[arg] != '-')
break;
if (strcmp(argv[arg], "-q") == 0)
quiet = 1;
else if (strcmp(argv[arg], "--") == 0) {
arg++;
break;
}
}
if (arg < argc) {
fname = argv[arg];
} else {
usage(argv[0]);
exit(1);
}
fd = open(fname, O_RDONLY);
/* Let's just map the core dump as an ELF header */
fstat(fd, &st);
mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (mem == MAP_FAILED) {
perror("mmap()");
exit(1);
}
/* get the program headers */
ehdr = (Elf64_Ehdr *)mem;
/* check that it's really a core. Should be "\x7fELF" */
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
fprintf(stderr, "ELF magic not found.\n");
exit(1);
}
if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
fprintf(stderr, "Only 64-bit ELF supported.\n");
exit(1);
}
if (ehdr->e_type != ET_CORE) {
fprintf(stderr, "ELF type %d, not a core dump.\n", ehdr->e_type);
exit(1);
}
/* OK we can safely go with program headers */
phdr = (Elf64_Phdr *)(mem + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
uint64_t size = phdr[i].p_filesz;
uint64_t offset = phdr[i].p_offset;
int ret = 0;
if (phdr[i].p_type != PT_LOAD)
continue;
//fprintf(stderr, "Scanning segment %d...\n", ehdr->e_phnum);
//fprintf(stderr, "\r%-5d: off=%lx va=%lx sz=%lx ", i, (long)offset, (long)phdr[i].p_vaddr, (long)size);
if (!size)
continue;
if (size < 512) // minimum for a tar header
continue;
/* tar magic */
if (memcmp(mem + offset + 257, "ustar\0""00", 8) != 0)
continue;
/* uid, gid */
if (memcmp(mem + offset + 108, "0000000\0""0000000\0", 16) != 0)
continue;
/* link name */
if (memcmp(mem + offset + 157, "haproxy-libs-dump\0", 18) != 0)
continue;
/* OK that's really it */
if (quiet)
printf("offset=%#lx size=%#lx\n", offset, size);
else
ret = (write(1, mem + offset, size) == size) ? 0 : 1;
return ret;
}
//fprintf(stderr, "\r%75s\n", "\r");
fprintf(stderr, "libs archive not found. Was 'set-dumpable' set to 'libs' ?\n");
return 1;
}

View file

@ -1,141 +0,0 @@
/*
* Find the post-mortem offset from a core dump
*
* Copyright (C) 2026 Willy Tarreau <w@1wt.eu>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/* Note: builds with no option under glibc, and can be built as a minimal
* uploadable static executable using nolibc as well:
gcc -o pm-from-core -nostdinc -nostdlib -s -Os -static -fno-ident \
-fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables \
-Wl,--gc-sections,--orphan-handling=discard,-znoseparate-code \
-I /path/to/nolibc-sysroot/include pm-from-core.c
*/
#define _GNU_SOURCE
#include <sys/mman.h>
#include <sys/stat.h>
#include <elf.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__GLIBC__)
# define my_memmem memmem
#else
void *my_memmem(const void *haystack, size_t haystacklen,
const void *needle, size_t needlelen)
{
while (haystacklen >= needlelen) {
if (!memcmp(haystack, needle, needlelen))
return (void*)haystack;
haystack++;
haystacklen--;
}
return NULL;
}
#endif
#define MAGIC "POST-MORTEM STARTS HERE+7654321\0"
int main(int argc, char **argv)
{
Elf64_Ehdr *ehdr;
Elf64_Phdr *phdr;
struct stat st;
uint8_t *mem;
int i, fd;
if (argc < 2) {
printf("Usage: %s <core_file>\n", argv[0]);
exit(1);
}
fd = open(argv[1], O_RDONLY);
/* Let's just map the core dump as an ELF header */
fstat(fd, &st);
mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (mem == MAP_FAILED) {
perror("mmap()");
exit(1);
}
/* get the program headers */
ehdr = (Elf64_Ehdr *)mem;
/* check that it's really a core. Should be "\x7fELF" */
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
fprintf(stderr, "ELF magic not found.\n");
exit(1);
}
if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
fprintf(stderr, "Only 64-bit ELF supported.\n");
exit(1);
}
if (ehdr->e_type != ET_CORE) {
fprintf(stderr, "ELF type %d, not a core dump.\n", ehdr->e_type);
exit(1);
}
/* OK we can safely go with program headers */
phdr = (Elf64_Phdr *)(mem + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
uint64_t size = phdr[i].p_filesz;
uint64_t offset = phdr[i].p_offset;
uint64_t vaddr = phdr[i].p_vaddr;
uint64_t found_ofs;
uint8_t *found;
if (phdr[i].p_type != PT_LOAD)
continue;
//printf("Scanning segment %d...\n", ehdr->e_phnum);
//printf("\r%-5d: off=%lx va=%lx sz=%lx ", i, (long)offset, (long)vaddr, (long)size);
if (!size)
continue;
if (size >= 1048576) // don't scan large segments
continue;
found = my_memmem(mem + offset, size, MAGIC, sizeof(MAGIC) - 1);
if (!found)
continue;
found_ofs = found - (mem + offset);
printf("Found post-mortem magic in segment %d:\n", i);
printf(" Core File Offset: 0x%lx (0x%lx + 0x%lx)\n", offset + found_ofs, offset, found_ofs);
printf(" Runtime VAddr: 0x%lx (0x%lx + 0x%lx)\n", vaddr + found_ofs, vaddr, found_ofs);
printf(" Segment Size: 0x%lx\n", size);
printf("\nIn gdb, copy-paste this line:\n\n pm_init 0x%lx\n\n", vaddr + found_ofs);
return 0;
}
//printf("\r%75s\n", "\r");
printf("post-mortem magic not found\n");
return 1;
}

View file

@ -14,8 +14,8 @@ define pools_dump
set $idx=$idx + 1 set $idx=$idx + 1
end end
set $mem = (unsigned long)$total * $e->size set $mem = $total * $e->size
printf "list=%#lx pool_head=%p name=%s size=%u alloc=%u used=%u mem=%lu\n", $p, $e, $e->name, $e->size, $total, $used, $mem printf "list=%#lx pool_head=%p name=%s size=%u alloc=%u used=%u mem=%u\n", $p, $e, $e->name, $e->size, $total, $used, $mem
set $p = *(void **)$p set $p = *(void **)$p
end end
end end

View file

@ -30,8 +30,8 @@ static const char *tevt_fd_types[16] = {
}; };
static const char *tevt_hs_types[16] = { static const char *tevt_hs_types[16] = {
[ 0] = "-", [ 1] = "-", [ 2] = "-", [ 3] = "-", [ 0] = "-", [ 1] = "-", [ 2] = "-", [ 3] = "rcv_err",
[ 4] = "snd_err", [ 5] = "truncated_shutr", [ 6] = "truncated_rcv_err", [ 7] = "-", [ 4] = "snd_err", [ 5] = "-", [ 6] = "-", [ 7] = "-",
[ 8] = "-", [ 9] = "-", [10] = "-", [11] = "-", [ 8] = "-", [ 9] = "-", [10] = "-", [11] = "-",
[12] = "-", [13] = "-", [14] = "-", [15] = "-", [12] = "-", [13] = "-", [14] = "-", [15] = "-",
}; };

File diff suppressed because it is too large Load diff

View file

@ -1,140 +0,0 @@
------
HATerm
------
HAProxy's dummy HTTP
server for benchmarks
1. Background
-------------
HATerm is a dummy HTTP server that leverages the flexible and scalable
architecture of HAProxy to ease benchmarking of HTTP agents in all versions of
HTTP currently supported by HAProxy (HTTP/1, HTTP/2, HTTP/3), and both in clear
and TLS / QUIC. It follows the same principle as its ancestor HTTPTerm [1],
consisting in producing HTTP responses entirely configured by the request
parameters (size, response time, status etc). It also preserves the spirit
HTTPTerm which does not require any configuration beyond an optional listening
address and a port number, though it also supports advanced configurations with
the full spectrum of HAProxy features for specific testing. The goal remains
to make it almost as fast as the original HTTPTerm so that it can become a
de-facto replacement, with a compatible command line and request parameters
that will not change users' habits.
[1] https://github.com/wtarreau/httpterm
2. Compilation
--------------
HATerm may be compiled in the same way as HAProxy but with "haterm" as Makefile
target to provide on the "make" command line as follows:
$ make -j $(nproc) TARGET=linux-glibc haterm
HATerm supports HTTPS/SSL/TCP:
$ make TARGET=linux-glibc USE_OPENSSL=1
It also supports QUIC:
$ make -j $(nproc) TARGET=linux-glibc USE_OPENSSL=1 USE_QUIC=1 haterm
Technically speaking, it uses the regular HAProxy source and object code with a
different command line parser. As such, all build options supported by HAProxy
also apply to HATerm. See INSTALL for more details about how to compile them.
3. Execution
------------
HATerm is a very easy to use HTTP server with supports for all the HTTP
versions. It displays its usage when run without argument or wrong arguments:
$ ./haterm
Usage : haterm -L [<ip>]:<clear port>[:<TCP&QUIC SSL port>] [-L...]* [opts]
where <opts> may be any combination of:
-G <line> : multiple option; append <line> to the "global" section
-F <line> : multiple option; append <line> to the "frontend" section
-T <line> : multiple option; append <line> to the "traces" section
-C : dump the configuration and exit
-D : goes daemon
-b <keysize> : RSA key size in bits (ex: "2048", "4096"...)
-c <curves> : ECSDA curves (ex: "P-256", "P-384"...)
-v : shows version
-d : enable the traces for all http protocols
--quic-bind-opts <opts> : append options to QUIC "bind" lines
--tcp-bind-opts <opts> : append options to TCP "bind" lines
Arguments -G, -F, -T permit to append one or multiple lines at the end of their
respective sections. A tab character ('\t') is prepended at the beginning of
the argument, and a line feed ('\n') is appended at the end. It is also
possible to insert multiple lines at once using escape sequences '\n' and '\t'
inside the string argument.
As HAProxy, HATerm may listen on several TCP/UDP addresses which can be
provided by multiple "-L" options. To be functional, it needs at least one
correct "-L" option to be set.
Examples:
$ ./haterm -L 127.0.0.1:8888 # listen on 127.0.0.1:8888 TCP address
$ ./haterm -L 127.0.0.1:8888:8889 # listen on 127.0.0.1:8888 TCP address,
# 127.0.01:8889 SSL/TCP address,
# and 127.0.01:8889 QUIC/UDP address
$ ./haterm -L 127.0.0.1:8888:8889 -L [::1]:8888:8889
With USE_QUIC_OPENSSL_COMPAT support, the user must configure a global
section as for HAProxy. HATerm sets internally its configuration in.
memory as this is done by HAProxy from configuration files:
$ ./haterm -L 127.0.0.1:8888:8889
[NOTICE] (1371578) : haproxy version is 3.4-dev4-ba5eab-28
[NOTICE] (1371578) : path to executable is ./haterm
[ALERT] (1371578) : Binding [haterm cfgfile:12] for frontend
___haterm_frontend___: this SSL library does not
support the QUIC protocol. A limited compatibility
layer may be enabled using the "limited-quic" global
option if desired.
Such an alert may be fixed with "-G' option:
$ ./haterm -L 127.0.0.1:8888:8889 -G "limited-quic"
When the SSL support is not compiled in, the second port is ignored. This is
also the case for the QUIC support.
HATerm adjusts its responses depending on the requests it receives. An empty
query string provides the information about how the URIs are understood by
HATerm:
$ curl http://127.0.0.1:8888/?
HAProxy's dummy HTTP server for benchmarks - version 3.4-dev4.
All integer argument values are in the form [digits]*[kmgr] (r=random(0..1))
The following arguments are supported to override the default objects :
- /?s=<size> return <size> bytes.
E.g. /?s=20k
- /?r=<retcode> present <retcode> as the HTTP return code.
E.g. /?r=404
- /?c=<cache> set the return as not cacheable if <1.
E.g. /?c=0
- /?A=<req-after> drain the request body after sending the response.
E.g. /?A=1
- /?C=<close> force the response to use close if >0.
E.g. /?C=1
- /?K=<keep-alive> force the response to use keep-alive if >0.
E.g. /?K=1
- /?t=<time> wait <time> milliseconds before responding.
E.g. /?t=500
- /?k=<enable> Enable transfer encoding chunked with only one chunk
if >0.
- /?R=<enable> Enable sending random data if >0.
Note that those arguments may be cumulated on one line separated by a set of
delimitors among [&?,;/] :
- GET /?s=20k&c=1&t=700&K=30r HTTP/1.0
- GET /?r=500?s=0?c=0?t=1000 HTTP/1.0

View file

@ -539,22 +539,10 @@ message. These functions are used by HTX analyzers or by multiplexers.
with the first block not removed, or NULL if everything was removed, and with the first block not removed, or NULL if everything was removed, and
the amount of data drained. the amount of data drained.
- htx_xfer() transfers HTX blocks from an HTX message to another, stopping - htx_xfer_blks() transfers HTX blocks from an HTX message to another,
when a specific amount of bytes, including meta-data, was copied. If the stopping after the first block of a specified type is transferred or when
tail block is a DATA block, it may be partially copied. All other block a specific amount of bytes, including meta-data, was moved. If the tail
are transferred at once. By default, copied blocks are removed from the block is a DATA block, it may be partially moved. All other block are
original HTX message and headers and trailers parts cannot be partially
copied. But flags can be set to change the default behavior:
- HTX_XFER_KEEP_SRC_BLKS: source blocks are not removed
- HTX_XFER_PARTIAL_HDRS_COPY: partial headers and trailers
part can be xferred
- HTX_XFER_HDRS_ONLY: Only the headers part is xferred
- htx_xfer_blks() [DEPRECATED] transfers HTX blocks from an HTX message to
another, stopping after the first block of a specified type is transferred
or when a specific amount of bytes, including meta-data, was moved. If the
tail block is a DATA block, it may be partially moved. All other block are
transferred at once or kept. This function returns a mixed value, with the transferred at once or kept. This function returns a mixed value, with the
last block moved, or NULL if nothing was moved, and the amount of data last block moved, or NULL if nothing was moved, and the amount of data
transferred. When HEADERS or TRAILERS blocks must be transferred, this transferred. When HEADERS or TRAILERS blocks must be transferred, this

View file

@ -208,38 +208,3 @@ starts with -st to achieve a hard stop on the previous worker.
Version 3.0 got rid of the libsystemd dependencies for sd_notify() after the Version 3.0 got rid of the libsystemd dependencies for sd_notify() after the
events of xz/openssh, the function is now implemented directly in haproxy in events of xz/openssh, the function is now implemented directly in haproxy in
src/systemd.c. src/systemd.c.
### mworker V3
This version was implemented with HAProxy 3.1, the goal was to stop parsing and
applying the configuration in the master process.
One of the caveats of the previous implementation was that the parser could take
a lot of time, and the master process would be stuck in the parser instead of
handling its polling loop, signals etc. Some parts of the configuration parsing
could also be less reliable with third-party code (EXTRA_OBJS), it could, for
example, allow opening FDs and not closing them before the reload which
would crash the master after a few reloads.
The startup of the master-worker was reorganized this way:
- the "discovery" mode, which is a lighter configuration parsing step, only
applies the configuration which need to be effective for the master process.
For example, "master-worker", "mworker-max-reloads" and less than 20 other
keywords that are identified by KWF_DISCOVERY in the code. It is really fast
as it don't need all the configuration to be applied in the master process.
- the master will then fork a worker, with a PROC_O_INIT flag. This worker has
a temporary sockpair connected to the master CLI. Once the worker is forked,
the master initializes its configuration and starts its polling loop.
- The newly forked worker will try to parse the configuration, which could
result in a failure (exit 1), or any bad error code. In case of success, the
worker will send a "READY" message to the master CLI then close this FD. At
this step everything was initialized and the worker can enter its polling
loop.
- The master then waits for the worker, it could:
* receive the READY message over the mCLI, resulting in a successful loading
of haproxy
* receive a SIGCHLD, meaning the worker exited and couldn't load

View file

@ -1,50 +0,0 @@
2026-03-12 - thread execution context
Thread execution context (thread_exec_ctx) is a combination of type and pointer
that are set in the current running thread at th_ctx->exec_ctx when entering
certain processing (tasks, sample fetch functions, actions, CLI keywords etc).
They're refined along execution, so that a task such as process_stream could
temporarily switch to a converter while evaluating an expression and switch
back to process_stream. They are reported in thread dumps and are mixed with
caller locations for memory profiling. As such they are intentionally not too
precise in order to avoid an explosion of the number of buckets. At the moment,
the level of granularity it provides is sufficient to try to narrow a
misbehaving origin down to a list of keywords. The context types can currently
be:
- something registered via an initcall, with the initcall's location
- something registered via an ha_caller, with the caller's location
- an explicit sample fetch / converter / action / CLI keyword list
- an explicit function (mainly used for actions without keywords)
- a task / tasklet (no distinction is made), using the ->process pointer
- a filter (e.g. compression), via flt_conf, reporting name
- a mux (via the mux_ops, reporting the name)
- an applet (e.g. cache, stats, CLI)
A macro EXEC_CTX_MAKE(type, pointer) makes a thread_exec_ctx from such
values.
A macro EXEC_CTX_NO_RET(ctx, statement) calls a void statement under the
specified context.
A macro EXEC_CTX_WITH_RET(ctx, expr) calls an expression under the specified
context.
Most locations were modified to directly use these macros on the fly, by
retrieving the context from where it was set on the element being evaluated
(e.g. an action rule contains the context inherited by the action keyword
that was used to create it).
In tools.c, chunk_append_thread_ctx() tries to decode the given exec_ctx and
appends it into the provided buffer. It's used by ha_thread_dump_one() and
cli_io_handler_show_activity() for memory profiling. In this latter case,
the detected thread_ctx are reported in the output under brackets prefixed
with "[via ...]" to distinguish call paths to the same allocators.
A good way to test if a context is properly reported is to place a bleeding
malloc() call into one of the monitored functions, e.g.:
DISGUISE(malloc(8));
and issue "show profiling memory" after stressing the function. Its context
must appear on the right with the number of calls.

View file

@ -1725,27 +1725,6 @@ add acl [@<ver>] <acl> <pattern>
This command cannot be used if the reference <acl> is a name also used with This command cannot be used if the reference <acl> is a name also used with
a map. In this case, the "add map" command must be used instead. a map. In this case, the "add map" command must be used instead.
add backend <name> from <defproxy> [mode <mode>] [guid <guid>] [ EXPERIMENTAL ]
Instantiate a new backend proxy with the name <name>.
Only TCP or HTTP proxies can be created. All of the settings are inherited
from <defproxy> default proxy instance. By default, it is mandatory to
specify the backend mode via the argument of the same name, unless <defproxy>
already defines it explicitely. It is also possible to use an optional GUID
argument if wanted.
Servers can be added via the command "add server". The backend is initialized
in the unpublished state. Once considered ready for traffic, use "publish
backend" to expose the newly created instance.
All named default proxies can be used, given that they validate the same
inheritance rules applied during configuration parsing. There is some
exceptions though, for example when the mode is neither TCP nor HTTP.
This command is restricted and can only be issued on sockets configured for
level "admin". Moreover, this feature is still considered in development so it
also requires experimental mode (see "experimental-mode on").
add map [@<ver>] <map> <key> <value> add map [@<ver>] <map> <key> <value>
add map [@<ver>] <map> <payload> add map [@<ver>] <map> <payload>
Add an entry into the map <map> to associate the value <value> to the key Add an entry into the map <map> to associate the value <value> to the key
@ -2121,30 +2100,6 @@ del acl <acl> [<key>|#<ref>]
listing the content of the acl. Note that if the reference <acl> is a name and listing the content of the acl. Note that if the reference <acl> is a name and
is shared with a map, the entry will be also deleted in the map. is shared with a map, the entry will be also deleted in the map.
del backend <name>
Removes the backend proxy with the name <name>.
This operation is only possible for TCP or HTTP proxies. To succeed, the
backend instance must have been first unpublished. Also, all of its servers
must first be removed (via "del server" CLI). Finally, no stream must still
be attached to the backend instance.
There is additional restrictions which prevent backend removal. First, a
backend cannot be removed if it is explicitely referenced by config elements,
for example via a use_backend rule or in sample expressions. Some proxies
options are also incompatible with runtime deletion. Currently, this is the
case when deprecated dispatch or option transparent are used. Also, a backend
cannot be removed if there is a stick-table declared in it. Finally, it is
impossible for now to remove a backend if QUIC servers were present in it.
It can be useful to use "wait be-removable" prior to this command to check
for the aformentioned requisites. This also provides a methode to wait for
the final closure of the streams attached to the target backend.
This command is restricted and can only be issued on sockets configured for
level "admin". Moreover, this feature is still considered in development so it
also requires experimental mode (see "experimental-mode on").
del map <map> [<key>|#<ref>] del map <map> [<key>|#<ref>]
Delete all the map entries from the map <map> corresponding to the key <key>. Delete all the map entries from the map <map> corresponding to the key <key>.
<map> is the #<id> or the <name> returned by "show map". If the <ref> is used, <map> is the #<id> or the <name> returned by "show map". If the <ref> is used,
@ -2579,8 +2534,7 @@ set maxconn global <maxconn>
delayed until the threshold is reached. A value of zero restores the initial delayed until the threshold is reached. A value of zero restores the initial
setting. setting.
set profiling memory { on | off } set profiling { tasks | memory } { auto | on | off }
set profiling tasks { auto | on | off | lock | no-lock | memory | no-memory }
Enables or disables CPU or memory profiling for the indicated subsystem. This Enables or disables CPU or memory profiling for the indicated subsystem. This
is equivalent to setting or clearing the "profiling" settings in the "global" is equivalent to setting or clearing the "profiling" settings in the "global"
section of the configuration file. Please also see "show profiling". Note section of the configuration file. Please also see "show profiling". Note
@ -2590,13 +2544,6 @@ set profiling tasks { auto | on | off | lock | no-lock | memory | no-memory }
on the linux-glibc target), and requires USE_MEMORY_PROFILING to be set at on the linux-glibc target), and requires USE_MEMORY_PROFILING to be set at
compile time. compile time.
. For tasks profiling, it is possible to enable or disable the collection of
per-task lock and memory timings at runtime, but the change is only taken
into account next time the profiler switches from off/auto to on (either
automatically or manually). Thus when using "no-lock" to disable per-task
lock profiling and save CPU cycles, it is recommended to flip the task
profiling off then on to commit the change.
set rate-limit connections global <value> set rate-limit connections global <value>
Change the process-wide connection rate limit, which is set by the global Change the process-wide connection rate limit, which is set by the global
'maxconnrate' setting. A value of zero disables the limitation. This limit 'maxconnrate' setting. A value of zero disables the limitation. This limit
@ -3356,7 +3303,7 @@ show pools [byname|bysize|byusage] [detailed] [match <pfx>] [<nb>]
- Pool quic_conn_c (152 bytes) : 1337 allocated (203224 bytes), ... - Pool quic_conn_c (152 bytes) : 1337 allocated (203224 bytes), ...
Total: 15 pools, 109578176 bytes allocated, 109578176 used ... Total: 15 pools, 109578176 bytes allocated, 109578176 used ...
show profiling [{all | status | tasks | memory}] [byaddr|bytime|byctx|aggr|<max_lines>]* show profiling [{all | status | tasks | memory}] [byaddr|bytime|aggr|<max_lines>]*
Dumps the current profiling settings, one per line, as well as the command Dumps the current profiling settings, one per line, as well as the command
needed to change them. When tasks profiling is enabled, some per-function needed to change them. When tasks profiling is enabled, some per-function
statistics collected by the scheduler will also be emitted, with a summary statistics collected by the scheduler will also be emitted, with a summary
@ -3365,15 +3312,14 @@ show profiling [{all | status | tasks | memory}] [byaddr|bytime|byctx|aggr|<max_
allocations/releases and their sizes will be reported. It is possible to allocations/releases and their sizes will be reported. It is possible to
limit the dump to only the profiling status, the tasks, or the memory limit the dump to only the profiling status, the tasks, or the memory
profiling by specifying the respective keywords; by default all profiling profiling by specifying the respective keywords; by default all profiling
information are dumped. It is also possible to limit the number of lines of information are dumped. It is also possible to limit the number of lines
of output of each category by specifying a numeric limit. If is possible to of output of each category by specifying a numeric limit. If is possible to
request that the output is sorted by address, by total execution time, or by request that the output is sorted by address or by total execution time
calling context instead of usage, e.g. to ease comparisons between subsequent instead of usage, e.g. to ease comparisons between subsequent calls or to
calls or to check what needs to be optimized, and to aggregate task activity check what needs to be optimized, and to aggregate task activity by called
by called function instead of seeing the details. Please note that profiling function instead of seeing the details. Please note that profiling is
is essentially aimed at developers since it gives hints about where CPU essentially aimed at developers since it gives hints about where CPU cycles
cycles or memory are wasted in the code. There is nothing useful to monitor or memory are wasted in the code. There is nothing useful to monitor there.
there.
show resolvers [<resolvers section id>] show resolvers [<resolvers section id>]
Dump statistics for the given resolvers section, or all resolvers sections Dump statistics for the given resolvers section, or all resolvers sections
@ -4548,13 +4494,6 @@ wait { -h | <delay> } [<condition> [<args>...]]
specified condition to be satisfied, to unrecoverably fail, or to remain specified condition to be satisfied, to unrecoverably fail, or to remain
unsatisfied for the whole <delay> duration. The supported conditions are: unsatisfied for the whole <delay> duration. The supported conditions are:
- be-removable <proxy> : this will wait for the specified proxy backend to be
removable by the "del backend" command. Some conditions will never be
accepted (e.g. backend not yet unpublished or with servers in it) and will
cause the report of a specific error message indicating what condition is
not met. If everything is OK before the delay, a success is returned and
the operation is terminated.
- srv-removable <proxy>/<server> : this will wait for the specified server to - srv-removable <proxy>/<server> : this will wait for the specified server to
be removable by the "del server" command, i.e. be in maintenance and no be removable by the "del server" command, i.e. be in maintenance and no
longer have any connection on it (neither active or idle). Some conditions longer have any connection on it (neither active or idle). Some conditions

View file

@ -627,10 +627,7 @@ For the type PP2_TYPE_SSL, the value is itself a defined like this :
uint8_t client; uint8_t client;
uint32_t verify; uint32_t verify;
struct pp2_tlv sub_tlv[0]; struct pp2_tlv sub_tlv[0];
} __attribute__((packed)); };
Note the "packed" attribute which indicates that each field starts immediately
after the previous one (i.e. without type-specific alignment nor padding).
The <verify> field will be zero if the client presented a certificate The <verify> field will be zero if the client presented a certificate
and it was successfully verified, and non-zero otherwise. and it was successfully verified, and non-zero otherwise.

View file

@ -58,7 +58,6 @@ struct acme_auth {
struct ist auth; /* auth URI */ struct ist auth; /* auth URI */
struct ist chall; /* challenge URI */ struct ist chall; /* challenge URI */
struct ist token; /* token */ struct ist token; /* token */
int validated; /* already validated */
int ready; /* is the challenge ready ? */ int ready; /* is the challenge ready ? */
void *next; void *next;
}; };

View file

@ -102,10 +102,7 @@ enum act_name {
/* Timeout name valid for a set-timeout rule */ /* Timeout name valid for a set-timeout rule */
enum act_timeout_name { enum act_timeout_name {
ACT_TIMEOUT_CONNECT,
ACT_TIMEOUT_SERVER, ACT_TIMEOUT_SERVER,
ACT_TIMEOUT_QUEUE,
ACT_TIMEOUT_TARPIT,
ACT_TIMEOUT_TUNNEL, ACT_TIMEOUT_TUNNEL,
ACT_TIMEOUT_CLIENT, ACT_TIMEOUT_CLIENT,
}; };
@ -198,11 +195,6 @@ struct act_rule {
struct server *srv; /* target server to attach the connection */ struct server *srv; /* target server to attach the connection */
struct sample_expr *name; /* used to differentiate idle connections */ struct sample_expr *name; /* used to differentiate idle connections */
} attach_srv; /* 'attach-srv' rule */ } attach_srv; /* 'attach-srv' rule */
struct {
enum log_orig_id orig;
char *profile_name;
struct log_profile *profile;
} do_log; /* 'do-log' action */
struct { struct {
int value; int value;
struct sample_expr *expr; struct sample_expr *expr;
@ -211,7 +203,6 @@ struct act_rule {
void *p[4]; void *p[4];
} act; /* generic pointers to be used by custom actions */ } act; /* generic pointers to be used by custom actions */
} arg; /* arguments used by some actions */ } arg; /* arguments used by some actions */
struct thread_exec_ctx exec_ctx; /* execution context */
struct { struct {
char *file; /* file name where the rule appears (or NULL) */ char *file; /* file name where the rule appears (or NULL) */
int line; /* line number where the rule appears */ int line; /* line number where the rule appears */
@ -223,9 +214,7 @@ struct action_kw {
enum act_parse_ret (*parse)(const char **args, int *cur_arg, struct proxy *px, enum act_parse_ret (*parse)(const char **args, int *cur_arg, struct proxy *px,
struct act_rule *rule, char **err); struct act_rule *rule, char **err);
int flags; int flags;
/* 4 bytes here */
void *private; void *private;
struct thread_exec_ctx exec_ctx; /* execution context */
}; };
struct action_kw_list { struct action_kw_list {

View file

@ -35,7 +35,6 @@ int act_resolution_cb(struct resolv_requester *requester, struct dns_counters *c
int act_resolution_error_cb(struct resolv_requester *requester, int error_code); int act_resolution_error_cb(struct resolv_requester *requester, int error_code);
const char *action_suggest(const char *word, const struct list *keywords, const char **extra); const char *action_suggest(const char *word, const struct list *keywords, const char **extra);
void free_act_rule(struct act_rule *rule); void free_act_rule(struct act_rule *rule);
void act_add_list(struct list *head, struct action_kw_list *kw_list);
static inline struct action_kw *action_lookup(struct list *keywords, const char *kw) static inline struct action_kw *action_lookup(struct list *keywords, const char *kw)
{ {

View file

@ -24,7 +24,6 @@
#include <haproxy/api-t.h> #include <haproxy/api-t.h>
#include <haproxy/freq_ctr-t.h> #include <haproxy/freq_ctr-t.h>
#include <haproxy/tinfo-t.h>
/* bit fields for the "profiling" global variable */ /* bit fields for the "profiling" global variable */
#define HA_PROF_TASKS_OFF 0x00000000 /* per-task CPU profiling forced disabled */ #define HA_PROF_TASKS_OFF 0x00000000 /* per-task CPU profiling forced disabled */
@ -34,8 +33,6 @@
#define HA_PROF_TASKS_MASK 0x00000003 /* per-task CPU profiling mask */ #define HA_PROF_TASKS_MASK 0x00000003 /* per-task CPU profiling mask */
#define HA_PROF_MEMORY 0x00000004 /* memory profiling */ #define HA_PROF_MEMORY 0x00000004 /* memory profiling */
#define HA_PROF_TASKS_MEM 0x00000008 /* per-task CPU profiling with memory */
#define HA_PROF_TASKS_LOCK 0x00000010 /* per-task CPU profiling with locks */
#ifdef USE_MEMORY_PROFILING #ifdef USE_MEMORY_PROFILING
@ -85,7 +82,6 @@ struct memprof_stats {
unsigned long long alloc_tot; unsigned long long alloc_tot;
unsigned long long free_tot; unsigned long long free_tot;
void *info; // for pools, ptr to the pool void *info; // for pools, ptr to the pool
struct thread_exec_ctx exec_ctx;
}; };
#endif #endif

View file

@ -130,7 +130,6 @@ struct appctx {
int (*io_handler)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK */ int (*io_handler)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK */
void (*io_release)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK, void (*io_release)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK,
if the command is terminated or the session released */ if the command is terminated or the session released */
struct cli_kw *kw; /* the keyword being processed */
} cli_ctx; /* context dedicated to the CLI applet */ } cli_ctx; /* context dedicated to the CLI applet */
struct buffer_wait buffer_wait; /* position in the list of objects waiting for a buffer */ struct buffer_wait buffer_wait; /* position in the list of objects waiting for a buffer */

View file

@ -62,13 +62,6 @@ ssize_t applet_append_line(void *ctx, struct ist v1, struct ist v2, size_t ofs,
static forceinline void applet_fl_set(struct appctx *appctx, uint on); static forceinline void applet_fl_set(struct appctx *appctx, uint on);
static forceinline void applet_fl_clr(struct appctx *appctx, uint off); static forceinline void applet_fl_clr(struct appctx *appctx, uint off);
/* macros to switch the calling context to the applet during a call. There's
* one with a return value for most calls, and one without for the few like
* fct(), shut(), or release() with no return.
*/
#define CALL_APPLET_WITH_RET(applet, func) EXEC_CTX_WITH_RET(EXEC_CTX_MAKE(TH_EX_CTX_APPLET, (applet)), (applet)->func)
#define CALL_APPLET_NO_RET(applet, func) EXEC_CTX_NO_RET(EXEC_CTX_MAKE(TH_EX_CTX_APPLET, (applet)), (applet)->func)
static forceinline uint appctx_app_test(const struct appctx *appctx, uint test) static forceinline uint appctx_app_test(const struct appctx *appctx, uint test)
{ {
@ -133,7 +126,7 @@ static inline int appctx_init(struct appctx *appctx)
task_set_thread(appctx->t, tid); task_set_thread(appctx->t, tid);
if (appctx->applet->init) if (appctx->applet->init)
return CALL_APPLET_WITH_RET(appctx->applet, init(appctx)); return appctx->applet->init(appctx);
return 0; return 0;
} }

View file

@ -192,7 +192,6 @@ struct lbprm {
void (*server_requeue)(struct server *); /* function used to place the server where it must be */ void (*server_requeue)(struct server *); /* function used to place the server where it must be */
void (*proxy_deinit)(struct proxy *); /* to be called when we're destroying the proxy */ void (*proxy_deinit)(struct proxy *); /* to be called when we're destroying the proxy */
void (*server_deinit)(struct server *); /* to be called when we're destroying the server */ void (*server_deinit)(struct server *); /* to be called when we're destroying the server */
int (*server_init)(struct server *); /* initialize a freshly added server (runtime); <0=fail. */
}; };
#endif /* _HAPROXY_BACKEND_T_H */ #endif /* _HAPROXY_BACKEND_T_H */

View file

@ -69,7 +69,6 @@ int backend_parse_balance(const char **args, char **err, struct proxy *curproxy)
int tcp_persist_rdp_cookie(struct stream *s, struct channel *req, int an_bit); int tcp_persist_rdp_cookie(struct stream *s, struct channel *req, int an_bit);
int be_downtime(struct proxy *px); int be_downtime(struct proxy *px);
int be_supports_dynamic_srv(struct proxy *px, char **msg);
void recount_servers(struct proxy *px); void recount_servers(struct proxy *px);
void update_backend_weight(struct proxy *px); void update_backend_weight(struct proxy *px);

View file

@ -24,7 +24,6 @@
#include <haproxy/api-t.h> #include <haproxy/api-t.h>
#include <haproxy/buf-t.h> #include <haproxy/buf-t.h>
#include <haproxy/filters-t.h>
#include <haproxy/show_flags-t.h> #include <haproxy/show_flags-t.h>
/* The CF_* macros designate Channel Flags, which may be ORed in the bit field /* The CF_* macros designate Channel Flags, which may be ORed in the bit field
@ -206,7 +205,6 @@ struct channel {
unsigned char xfer_large; /* number of consecutive large xfers */ unsigned char xfer_large; /* number of consecutive large xfers */
unsigned char xfer_small; /* number of consecutive small xfers */ unsigned char xfer_small; /* number of consecutive small xfers */
int analyse_exp; /* expiration date for current analysers (if set) */ int analyse_exp; /* expiration date for current analysers (if set) */
struct chn_flt flt; /* current state of filters active on this channel */
}; };

View file

@ -376,7 +376,6 @@ static inline void channel_add_input(struct channel *chn, unsigned int len)
c_adv(chn, fwd); c_adv(chn, fwd);
} }
/* notify that some data was read */ /* notify that some data was read */
chn_prod(chn)->bytes_in += len;
chn->flags |= CF_READ_EVENT; chn->flags |= CF_READ_EVENT;
} }
@ -788,12 +787,8 @@ static inline int channel_recv_max(const struct channel *chn)
*/ */
static inline size_t channel_data_limit(const struct channel *chn) static inline size_t channel_data_limit(const struct channel *chn)
{ {
size_t max = (global.tune.bufsize - global.tune.maxrewrite);
size_t max;
if (!c_size(chn))
return 0;
max = (c_size(chn) - global.tune.maxrewrite);
if (IS_HTX_STRM(chn_strm(chn))) if (IS_HTX_STRM(chn_strm(chn)))
max -= HTX_BUF_OVERHEAD; max -= HTX_BUF_OVERHEAD;
return max; return max;

View file

@ -59,7 +59,6 @@ enum chk_result {
#define CHK_ST_FASTINTER 0x0400 /* force fastinter check */ #define CHK_ST_FASTINTER 0x0400 /* force fastinter check */
#define CHK_ST_READY 0x0800 /* check ready to migrate or run, see below */ #define CHK_ST_READY 0x0800 /* check ready to migrate or run, see below */
#define CHK_ST_SLEEPING 0x1000 /* check was sleeping, i.e. not currently bound to a thread, see below */ #define CHK_ST_SLEEPING 0x1000 /* check was sleeping, i.e. not currently bound to a thread, see below */
#define CHK_ST_USE_SMALL_BUFF 0x2000 /* Use small buffers if possible for the request */
/* 4 possible states for CHK_ST_SLEEPING and CHK_ST_READY: /* 4 possible states for CHK_ST_SLEEPING and CHK_ST_READY:
* SLP RDY State Description * SLP RDY State Description
@ -189,7 +188,6 @@ struct check {
char **envp; /* the environment to use if running a process-based check */ char **envp; /* the environment to use if running a process-based check */
struct pid_list *curpid; /* entry in pid_list used for current process-based test, or -1 if not in test */ struct pid_list *curpid; /* entry in pid_list used for current process-based test, or -1 if not in test */
struct sockaddr_storage addr; /* the address to check */ struct sockaddr_storage addr; /* the address to check */
struct protocol *proto; /* protocol used for check, may be different from the server's one */
char *pool_conn_name; /* conn name used on reuse */ char *pool_conn_name; /* conn name used on reuse */
char *sni; /* Server name */ char *sni; /* Server name */
char *alpn_str; /* ALPN to use for checks */ char *alpn_str; /* ALPN to use for checks */

View file

@ -78,11 +78,12 @@ struct task *process_chk(struct task *t, void *context, unsigned int state);
struct task *srv_chk_io_cb(struct task *t, void *ctx, unsigned int state); struct task *srv_chk_io_cb(struct task *t, void *ctx, unsigned int state);
int check_buf_available(void *target); int check_buf_available(void *target);
struct buffer *check_get_buf(struct check *check, struct buffer *bptr, unsigned int small_buffer); struct buffer *check_get_buf(struct check *check, struct buffer *bptr);
void check_release_buf(struct check *check, struct buffer *bptr); void check_release_buf(struct check *check, struct buffer *bptr);
const char *init_check(struct check *check, int type); const char *init_check(struct check *check, int type);
void free_check(struct check *check); void free_check(struct check *check);
void check_purge(struct check *check); void check_purge(struct check *check);
int wake_srv_chk(struct stconn *sc);
int init_srv_check(struct server *srv); int init_srv_check(struct server *srv);
int init_srv_agent_check(struct server *srv); int init_srv_agent_check(struct server *srv);

View file

@ -32,8 +32,6 @@
extern struct pool_head *pool_head_trash; extern struct pool_head *pool_head_trash;
extern struct pool_head *pool_head_large_trash;
extern struct pool_head *pool_head_small_trash;
/* function prototypes */ /* function prototypes */
@ -48,10 +46,6 @@ int chunk_asciiencode(struct buffer *dst, struct buffer *src, char qc);
int chunk_strcmp(const struct buffer *chk, const char *str); int chunk_strcmp(const struct buffer *chk, const char *str);
int chunk_strcasecmp(const struct buffer *chk, const char *str); int chunk_strcasecmp(const struct buffer *chk, const char *str);
struct buffer *get_trash_chunk(void); struct buffer *get_trash_chunk(void);
struct buffer *get_large_trash_chunk(void);
struct buffer *get_small_trash_chunk(void);
struct buffer *get_trash_chunk_sz(size_t size);
struct buffer *get_larger_trash_chunk(struct buffer *chunk);
int init_trash_buffers(int first); int init_trash_buffers(int first);
static inline void chunk_reset(struct buffer *chk) static inline void chunk_reset(struct buffer *chk)
@ -112,79 +106,11 @@ static forceinline struct buffer *alloc_trash_chunk(void)
return chunk; return chunk;
} }
/*
* Allocate a large trash chunk from the reentrant pool. The buffer starts at
* the end of the chunk. This chunk must be freed using free_trash_chunk(). This
* call may fail and the caller is responsible for checking that the returned
* pointer is not NULL.
*/
static forceinline struct buffer *alloc_large_trash_chunk(void)
{
struct buffer *chunk;
if (!pool_head_large_trash)
return NULL;
chunk = pool_alloc(pool_head_large_trash);
if (chunk) {
char *buf = (char *)chunk + sizeof(struct buffer);
*buf = 0;
chunk_init(chunk, buf,
pool_head_large_trash->size - sizeof(struct buffer));
}
return chunk;
}
/*
* Allocate a small trash chunk from the reentrant pool. The buffer starts at
* the end of the chunk. This chunk must be freed using free_trash_chunk(). This
* call may fail and the caller is responsible for checking that the returned
* pointer is not NULL.
*/
static forceinline struct buffer *alloc_small_trash_chunk(void)
{
struct buffer *chunk;
if (!pool_head_small_trash)
return NULL;
chunk = pool_alloc(pool_head_small_trash);
if (chunk) {
char *buf = (char *)chunk + sizeof(struct buffer);
*buf = 0;
chunk_init(chunk, buf,
pool_head_small_trash->size - sizeof(struct buffer));
}
return chunk;
}
/*
* Allocate a trash chunk accordingly to the requested size. This chunk must be
* freed using free_trash_chunk(). This call may fail and the caller is
* responsible for checking that the returned pointer is not NULL.
*/
static forceinline struct buffer *alloc_trash_chunk_sz(size_t size)
{
if (pool_head_small_trash && size <= pool_head_small_trash->size)
return alloc_small_trash_chunk();
else if (size <= pool_head_trash->size)
return alloc_trash_chunk();
else if (pool_head_large_trash && size <= pool_head_large_trash->size)
return alloc_large_trash_chunk();
else
return NULL;
}
/* /*
* free a trash chunk allocated by alloc_trash_chunk(). NOP on NULL. * free a trash chunk allocated by alloc_trash_chunk(). NOP on NULL.
*/ */
static forceinline void free_trash_chunk(struct buffer *chunk) static forceinline void free_trash_chunk(struct buffer *chunk)
{ {
if (pool_head_small_trash && chunk && chunk->size == pool_head_small_trash->size - sizeof(struct buffer))
pool_free(pool_head_small_trash, chunk);
else if (pool_head_large_trash && chunk && chunk->size == pool_head_large_trash->size - sizeof(struct buffer))
pool_free(pool_head_large_trash, chunk);
else
pool_free(pool_head_trash, chunk); pool_free(pool_head_trash, chunk);
} }

View file

@ -23,7 +23,6 @@
#define _HAPROXY_CLI_T_H #define _HAPROXY_CLI_T_H
#include <haproxy/applet-t.h> #include <haproxy/applet-t.h>
#include <haproxy/tinfo-t.h>
/* Access level for a stats socket (appctx->cli_ctx.level) */ /* Access level for a stats socket (appctx->cli_ctx.level) */
#define ACCESS_LVL_NONE 0x0000 #define ACCESS_LVL_NONE 0x0000
@ -101,7 +100,6 @@ enum cli_wait_err {
enum cli_wait_cond { enum cli_wait_cond {
CLI_WAIT_COND_NONE, // no condition to wait on CLI_WAIT_COND_NONE, // no condition to wait on
CLI_WAIT_COND_SRV_UNUSED,// wait for server to become unused CLI_WAIT_COND_SRV_UNUSED,// wait for server to become unused
CLI_WAIT_COND_BE_UNUSED, // wait for backend to become unused
}; };
struct cli_wait_ctx { struct cli_wait_ctx {
@ -121,8 +119,6 @@ struct cli_kw {
void (*io_release)(struct appctx *appctx); void (*io_release)(struct appctx *appctx);
void *private; void *private;
int level; /* this is the level needed to show the keyword usage and to use it */ int level; /* this is the level needed to show the keyword usage and to use it */
/* 4-byte hole here */
struct thread_exec_ctx exec_ctx; /* execution context */
}; };
struct cli_kw_list { struct cli_kw_list {

View file

@ -34,7 +34,6 @@
#include <haproxy/listener-t.h> #include <haproxy/listener-t.h>
#include <haproxy/obj_type.h> #include <haproxy/obj_type.h>
#include <haproxy/pool-t.h> #include <haproxy/pool-t.h>
#include <haproxy/protocol.h>
#include <haproxy/server.h> #include <haproxy/server.h>
#include <haproxy/session-t.h> #include <haproxy/session-t.h>
#include <haproxy/task-t.h> #include <haproxy/task-t.h>
@ -50,13 +49,6 @@ extern struct mux_stopping_data mux_stopping_data[MAX_THREADS];
#define IS_HTX_CONN(conn) ((conn)->mux && ((conn)->mux->flags & MX_FL_HTX)) #define IS_HTX_CONN(conn) ((conn)->mux && ((conn)->mux->flags & MX_FL_HTX))
/* macros to switch the calling context to the mux during a call. There's one
* with a return value for most calls, and one without for the few like shut(),
* detach() or destroy() with no return.
*/
#define CALL_MUX_WITH_RET(mux, func) EXEC_CTX_WITH_RET(EXEC_CTX_MAKE(TH_EX_CTX_MUX, (mux)), (mux)->func)
#define CALL_MUX_NO_RET(mux, func) EXEC_CTX_NO_RET(EXEC_CTX_MAKE(TH_EX_CTX_MUX, (mux)), (mux)->func)
/* receive a PROXY protocol header over a connection */ /* receive a PROXY protocol header over a connection */
int conn_recv_proxy(struct connection *conn, int flag); int conn_recv_proxy(struct connection *conn, int flag);
int conn_send_proxy(struct connection *conn, unsigned int flag); int conn_send_proxy(struct connection *conn, unsigned int flag);
@ -488,7 +480,7 @@ static inline int conn_install_mux(struct connection *conn, const struct mux_ops
conn->mux = mux; conn->mux = mux;
conn->ctx = ctx; conn->ctx = ctx;
ret = mux->init ? CALL_MUX_WITH_RET(mux, init(conn, prx, sess, &BUF_NULL)) : 0; ret = mux->init ? mux->init(conn, prx, sess, &BUF_NULL) : 0;
if (ret < 0) { if (ret < 0) {
conn->mux = NULL; conn->mux = NULL;
conn->ctx = NULL; conn->ctx = NULL;
@ -610,13 +602,13 @@ void list_mux_proto(FILE *out);
*/ */
static inline const struct mux_proto_list *conn_get_best_mux_entry( static inline const struct mux_proto_list *conn_get_best_mux_entry(
const struct ist mux_proto, const struct ist mux_proto,
int proto_side, int proto_is_quic, int proto_mode) int proto_side, int proto_mode)
{ {
struct mux_proto_list *item; struct mux_proto_list *item;
struct mux_proto_list *fallback = NULL; struct mux_proto_list *fallback = NULL;
list_for_each_entry(item, &mux_proto_list.list, list) { list_for_each_entry(item, &mux_proto_list.list, list) {
if (!(item->side & proto_side) || !(item->mode & proto_mode) || (proto_is_quic && !(item->mux->flags & MX_FL_FRAMED))) if (!(item->side & proto_side) || !(item->mode & proto_mode))
continue; continue;
if (istlen(mux_proto) && isteq(mux_proto, item->token)) if (istlen(mux_proto) && isteq(mux_proto, item->token))
return item; return item;
@ -641,7 +633,7 @@ static inline const struct mux_ops *conn_get_best_mux(struct connection *conn,
{ {
const struct mux_proto_list *item; const struct mux_proto_list *item;
item = conn_get_best_mux_entry(mux_proto, proto_side, proto_is_quic(conn->ctrl), proto_mode); item = conn_get_best_mux_entry(mux_proto, proto_side, proto_mode);
return item ? item->mux : NULL; return item ? item->mux : NULL;
} }

View file

@ -185,29 +185,6 @@ struct be_counters {
} p; /* protocol-specific stats */ } p; /* protocol-specific stats */
}; };
/* extra counters that are registered at boot by various modules */
enum counters_type {
COUNTERS_FE = 0,
COUNTERS_BE,
COUNTERS_SV,
COUNTERS_LI,
COUNTERS_RSLV,
COUNTERS_OFF_END /* must always be last */
};
struct extra_counters {
char **datap; /* points to pointer to heap containing counters allocated in a linear fashion */
size_t size; /* size of allocated data */
size_t tgrp_step; /* distance in words between two datap for consecutive tgroups, 0 for single */
uint nbtgrp; /* number of thread groups accessing these counters */
enum counters_type type; /* type of object containing the counters */
};
#define EXTRA_COUNTERS(name) \
struct extra_counters *name
#endif /* _HAPROXY_COUNTERS_T_H */ #endif /* _HAPROXY_COUNTERS_T_H */
/* /*

View file

@ -26,9 +26,6 @@
#include <haproxy/counters-t.h> #include <haproxy/counters-t.h>
#include <haproxy/guid-t.h> #include <haproxy/guid-t.h>
#include <haproxy/global.h>
extern THREAD_LOCAL void *trash_counters;
int counters_fe_shared_prepare(struct fe_counters_shared *counters, const struct guid_node *guid, char **errmsg); int counters_fe_shared_prepare(struct fe_counters_shared *counters, const struct guid_node *guid, char **errmsg);
int counters_be_shared_prepare(struct be_counters_shared *counters, const struct guid_node *guid, char **errmsg); int counters_be_shared_prepare(struct be_counters_shared *counters, const struct guid_node *guid, char **errmsg);
@ -104,106 +101,4 @@ void counters_be_shared_drop(struct be_counters_shared *counters);
__ret; \ __ret; \
}) })
#define COUNTERS_UPDATE_MAX(counter, count) \
do { \
if (!(global.tune.options & GTUNE_NO_MAX_COUNTER)) \
HA_ATOMIC_UPDATE_MAX(counter, count); \
} while (0)
/* Manipulation of extra_counters, for boot-time registrable modules */
/* retrieve the base storage of extra counters (first tgroup if any) */
#define EXTRA_COUNTERS_BASE(counters, mod) \
(likely(counters) ? \
((void *)(*(counters)->datap + (mod)->counters_off[(counters)->type])) : \
(trash_counters))
/* retrieve the pointer to the extra counters storage for module <mod> for the
* current TGID.
*/
#define EXTRA_COUNTERS_GET(counters, mod) \
(likely(counters) ? \
((void *)(counters)->datap[(counters)->tgrp_step * (tgid - 1)] + \
(mod)->counters_off[(counters)->type]) : \
(trash_counters))
#define EXTRA_COUNTERS_REGISTER(counters, ctype, alloc_failed_label, storage, step) \
do { \
typeof(*counters) _ctr; \
_ctr = calloc(1, sizeof(*_ctr)); \
if (!_ctr) \
goto alloc_failed_label; \
_ctr->type = (ctype); \
_ctr->tgrp_step = (step); \
_ctr->datap = (storage); \
*(counters) = _ctr; \
} while (0)
#define EXTRA_COUNTERS_ADD(mod, counters, new_counters, csize) \
do { \
typeof(counters) _ctr = (counters); \
(mod)->counters_off[_ctr->type] = _ctr->size; \
_ctr->size += (csize); \
} while (0)
#define EXTRA_COUNTERS_ALLOC(counters, alloc_failed_label, nbtg) \
do { \
typeof(counters) _ctr = (counters); \
char **datap = _ctr->datap; \
uint tgrp; \
_ctr->nbtgrp = _ctr->tgrp_step ? (nbtg) : 1; \
for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \
*datap = malloc((_ctr)->size); \
if (!*_ctr->datap) \
goto alloc_failed_label; \
datap += _ctr->tgrp_step; \
} \
} while (0)
#define EXTRA_COUNTERS_INIT(counters, mod, init_counters, init_counters_size) \
do { \
typeof(counters) _ctr = (counters); \
char **datap = _ctr->datap; \
uint tgrp; \
for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \
memcpy(*datap + mod->counters_off[_ctr->type], \
(init_counters), (init_counters_size)); \
datap += _ctr->tgrp_step; \
} \
} while (0)
#define EXTRA_COUNTERS_FREE(counters) \
do { \
typeof(counters) _ctr = (counters); \
if (_ctr) { \
char **datap = _ctr->datap; \
uint tgrp; \
for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \
ha_free(datap); \
datap += _ctr->tgrp_step; \
} \
free(_ctr); \
} \
} while (0)
/* aggregate all values of <metricp> over the thread groups handled by
* <counters>. <metricp> MUST correspond to an entry of the first tgrp of
* <counters>. The number of groups and the step are found in <counters>. The
* type of the return value is the same as <metricp>, and must be a scalar so
* that values are summed before being returned.
*/
#define EXTRA_COUNTERS_AGGR(counters, metricp) \
({ \
typeof(counters) _ctr = (counters); \
typeof(metricp) *valp, _ret = 0; \
if (_ctr) { \
size_t ofs = (char *)&metricp - _ctr->datap[0]; \
uint tgrp; \
for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \
valp = (typeof(valp))(_ctr->datap[tgrp * (counters)->tgrp_step] + ofs); \
_ret += HA_ATOMIC_LOAD(valp); \
} \
} \
_ret; \
})
#endif /* _HAPROXY_COUNTERS_H */ #endif /* _HAPROXY_COUNTERS_H */

View file

@ -536,11 +536,6 @@
#define TIME_STATS_SAMPLES 512 #define TIME_STATS_SAMPLES 512
#endif #endif
/* number of samples used to measure the load in the run queue */
#ifndef RQ_LOAD_SAMPLES
#define RQ_LOAD_SAMPLES 512
#endif
/* max ocsp cert id asn1 encoded length */ /* max ocsp cert id asn1 encoded length */
#ifndef OCSP_MAX_CERTID_ASN1_LENGTH #ifndef OCSP_MAX_CERTID_ASN1_LENGTH
#define OCSP_MAX_CERTID_ASN1_LENGTH 128 #define OCSP_MAX_CERTID_ASN1_LENGTH 128
@ -606,7 +601,7 @@
* store stats. * store stats.
*/ */
#ifndef MEMPROF_HASH_BITS #ifndef MEMPROF_HASH_BITS
# define MEMPROF_HASH_BITS 12 # define MEMPROF_HASH_BITS 10
#endif #endif
#define MEMPROF_HASH_BUCKETS (1U << MEMPROF_HASH_BITS) #define MEMPROF_HASH_BUCKETS (1U << MEMPROF_HASH_BITS)

View file

@ -24,12 +24,12 @@
#include <import/ebtree-t.h> #include <import/ebtree-t.h>
#include <haproxy/buf-t.h>
#include <haproxy/connection-t.h> #include <haproxy/connection-t.h>
#include <haproxy/counters-t.h> #include <haproxy/buf-t.h>
#include <haproxy/dgram-t.h> #include <haproxy/dgram-t.h>
#include <haproxy/dns_ring-t.h> #include <haproxy/dns_ring-t.h>
#include <haproxy/obj_type-t.h> #include <haproxy/obj_type-t.h>
#include <haproxy/stats-t.h>
#include <haproxy/task-t.h> #include <haproxy/task-t.h>
#include <haproxy/thread.h> #include <haproxy/thread.h>
@ -152,7 +152,6 @@ struct dns_nameserver {
struct dns_stream_server *stream; /* used for tcp dns */ struct dns_stream_server *stream; /* used for tcp dns */
EXTRA_COUNTERS(extra_counters); EXTRA_COUNTERS(extra_counters);
char *extra_counters_storage; /* storage used for extra_counters above */
struct dns_counters *counters; struct dns_counters *counters;
struct list list; /* nameserver chained list */ struct list list; /* nameserver chained list */

View file

@ -36,8 +36,6 @@
#include <haproxy/pool.h> #include <haproxy/pool.h>
extern struct pool_head *pool_head_buffer; extern struct pool_head *pool_head_buffer;
extern struct pool_head *pool_head_large_buffer;
extern struct pool_head *pool_head_small_buffer;
int init_buffer(void); int init_buffer(void);
void buffer_dump(FILE *o, struct buffer *b, int from, int to); void buffer_dump(FILE *o, struct buffer *b, int from, int to);
@ -55,42 +53,6 @@ static inline int buffer_almost_full(const struct buffer *buf)
return b_almost_full(buf); return b_almost_full(buf);
} }
/* Return 1 if <sz> is the default buffer size */
static inline int b_is_default_sz(size_t sz)
{
return (sz == pool_head_buffer->size);
}
/* Return 1 if <sz> is the size of a large buffer (alwoys false is large buffers are not configured) */
static inline int b_is_large_sz(size_t sz)
{
return (pool_head_large_buffer && sz == pool_head_large_buffer->size);
}
/* Return 1 if <sz> is the size of a small buffer */
static inline int b_is_small_sz(size_t sz)
{
return (pool_head_small_buffer && sz == pool_head_small_buffer->size);
}
/* Return 1 if <bug> is a default buffer */
static inline int b_is_default(struct buffer *buf)
{
return b_is_default_sz(b_size(buf));
}
/* Return 1 if <buf> is a large buffer (alwoys 0 is large buffers are not configured) */
static inline int b_is_large(struct buffer *buf)
{
return b_is_large_sz(b_size(buf));
}
/* Return 1 if <buf> is a small buffer */
static inline int b_is_small(struct buffer *buf)
{
return b_is_small_sz(b_size(buf));
}
/**************************************************/ /**************************************************/
/* Functions below are used for buffer allocation */ /* Functions below are used for buffer allocation */
/**************************************************/ /**************************************************/
@ -174,20 +136,13 @@ static inline char *__b_get_emergency_buf(void)
#define __b_free(_buf) \ #define __b_free(_buf) \
do { \ do { \
char *area = (_buf)->area; \ char *area = (_buf)->area; \
size_t sz = (_buf)->size; \
\ \
/* let's first clear the area to save an occasional "show sess all" \ /* let's first clear the area to save an occasional "show sess all" \
* glancing over our shoulder from getting a dangling pointer. \ * glancing over our shoulder from getting a dangling pointer. \
*/ \ */ \
*(_buf) = BUF_NULL; \ *(_buf) = BUF_NULL; \
__ha_barrier_store(); \ __ha_barrier_store(); \
/* if enabled, large buffers are always strictly greater \ if (th_ctx->emergency_bufs_left < global.tune.reserved_bufs) \
* than the default buffers */ \
if (unlikely(b_is_large_sz(sz))) \
pool_free(pool_head_large_buffer, area); \
else if (unlikely(b_is_small_sz(sz))) \
pool_free(pool_head_small_buffer, area); \
else if (th_ctx->emergency_bufs_left < global.tune.reserved_bufs) \
th_ctx->emergency_bufs[th_ctx->emergency_bufs_left++] = area; \ th_ctx->emergency_bufs[th_ctx->emergency_bufs_left++] = area; \
else \ else \
pool_free(pool_head_buffer, area); \ pool_free(pool_head_buffer, area); \
@ -200,35 +155,6 @@ static inline char *__b_get_emergency_buf(void)
__b_free((_buf)); \ __b_free((_buf)); \
} while (0) } while (0)
static inline struct buffer *b_alloc_small(struct buffer *buf)
{
char *area = NULL;
if (!buf->size) {
area = pool_alloc(pool_head_small_buffer);
if (!area)
return NULL;
buf->area = area;
buf->size = global.tune.bufsize_small;
}
return buf;
}
static inline struct buffer *b_alloc_large(struct buffer *buf)
{
char *area = NULL;
if (!buf->size) {
area = pool_alloc(pool_head_large_buffer);
if (!area)
return NULL;
buf->area = area;
buf->size = global.tune.bufsize_large;
}
return buf;
}
/* Offer one or multiple buffer currently belonging to target <from> to whoever /* Offer one or multiple buffer currently belonging to target <from> to whoever
* needs one. Any pointer is valid for <from>, including NULL. Its purpose is * needs one. Any pointer is valid for <from>, including NULL. Its purpose is
* to avoid passing a buffer to oneself in case of failed allocations (e.g. * to avoid passing a buffer to oneself in case of failed allocations (e.g.

View file

@ -232,28 +232,22 @@ struct filter {
* 0: request channel, 1: response channel */ * 0: request channel, 1: response channel */
unsigned int pre_analyzers; /* bit field indicating analyzers to pre-process */ unsigned int pre_analyzers; /* bit field indicating analyzers to pre-process */
unsigned int post_analyzers; /* bit field indicating analyzers to post-process */ unsigned int post_analyzers; /* bit field indicating analyzers to post-process */
struct list list; /* Filter list for the stream */ struct list list; /* Next filter for the same proxy/stream */
/* req_list and res_list are exactly equivalent, except the order may differ */
struct list req_list; /* Filter list for request channel */
struct list res_list; /* Filter list for response channel */
}; };
/* /*
* Structure reprensenting the "global" state of filters attached to a stream. * Structure reprensenting the "global" state of filters attached to a stream.
* Doesn't hold much information, as the channel themselves hold chn_flt struct
* which contains the per-channel members.
*/ */
struct strm_flt { struct strm_flt {
struct list filters; /* List of filters attached to a stream */ struct list filters; /* List of filters attached to a stream */
struct filter *current[2]; /* From which filter resume processing, for a specific channel.
* This is used for resumable callbacks only,
* If NULL, we start from the first filter.
* 0: request channel, 1: response channel */
unsigned short flags; /* STRM_FL_* */ unsigned short flags; /* STRM_FL_* */
}; unsigned char nb_req_data_filters; /* Number of data filters registered on the request channel */
unsigned char nb_rsp_data_filters; /* Number of data filters registered on the response channel */
/* structure holding filter state for some members that are channel oriented */ unsigned long long offset[2];
struct chn_flt {
struct list filters; /* List of filters attached to a channel */
struct filter *current; /* From which filter resume processing, for a specific channel. */
unsigned char nb_data_filters; /* Number of data filters registered on channel */
unsigned long long offset;
}; };
#endif /* _HAPROXY_FILTERS_T_H */ #endif /* _HAPROXY_FILTERS_T_H */

View file

@ -28,9 +28,7 @@
#include <haproxy/stream-t.h> #include <haproxy/stream-t.h>
extern const char *trace_flt_id; extern const char *trace_flt_id;
extern const char *http_comp_req_flt_id; extern const char *http_comp_flt_id;
extern const char *http_comp_res_flt_id;
extern const char *cache_store_flt_id; extern const char *cache_store_flt_id;
extern const char *spoe_filter_id; extern const char *spoe_filter_id;
extern const char *fcgi_flt_id; extern const char *fcgi_flt_id;
@ -42,13 +40,13 @@ extern const char *fcgi_flt_id;
/* Useful macros to access per-channel values. It can be safely used inside /* Useful macros to access per-channel values. It can be safely used inside
* filters. */ * filters. */
#define CHN_IDX(chn) (((chn)->flags & CF_ISRESP) == CF_ISRESP) #define CHN_IDX(chn) (((chn)->flags & CF_ISRESP) == CF_ISRESP)
#define FLT_STRM_OFF(s, chn) (chn->flt.offset) #define FLT_STRM_OFF(s, chn) (strm_flt(s)->offset[CHN_IDX(chn)])
#define FLT_OFF(flt, chn) ((flt)->offset[CHN_IDX(chn)]) #define FLT_OFF(flt, chn) ((flt)->offset[CHN_IDX(chn)])
#define HAS_FILTERS(strm) ((strm)->strm_flt.flags & STRM_FLT_FL_HAS_FILTERS) #define HAS_FILTERS(strm) ((strm)->strm_flt.flags & STRM_FLT_FL_HAS_FILTERS)
#define HAS_REQ_DATA_FILTERS(strm) ((strm)->req.flt.nb_data_filters != 0) #define HAS_REQ_DATA_FILTERS(strm) ((strm)->strm_flt.nb_req_data_filters != 0)
#define HAS_RSP_DATA_FILTERS(strm) ((strm)->res.flt.nb_data_filters != 0) #define HAS_RSP_DATA_FILTERS(strm) ((strm)->strm_flt.nb_rsp_data_filters != 0)
#define HAS_DATA_FILTERS(strm, chn) (((chn)->flags & CF_ISRESP) ? HAS_RSP_DATA_FILTERS(strm) : HAS_REQ_DATA_FILTERS(strm)) #define HAS_DATA_FILTERS(strm, chn) (((chn)->flags & CF_ISRESP) ? HAS_RSP_DATA_FILTERS(strm) : HAS_REQ_DATA_FILTERS(strm))
#define IS_REQ_DATA_FILTER(flt) ((flt)->flags & FLT_FL_IS_REQ_DATA_FILTER) #define IS_REQ_DATA_FILTER(flt) ((flt)->flags & FLT_FL_IS_REQ_DATA_FILTER)
@ -139,11 +137,14 @@ static inline void
register_data_filter(struct stream *s, struct channel *chn, struct filter *filter) register_data_filter(struct stream *s, struct channel *chn, struct filter *filter)
{ {
if (!IS_DATA_FILTER(filter, chn)) { if (!IS_DATA_FILTER(filter, chn)) {
if (chn->flags & CF_ISRESP) if (chn->flags & CF_ISRESP) {
filter->flags |= FLT_FL_IS_RSP_DATA_FILTER; filter->flags |= FLT_FL_IS_RSP_DATA_FILTER;
else strm_flt(s)->nb_rsp_data_filters++;
}
else {
filter->flags |= FLT_FL_IS_REQ_DATA_FILTER; filter->flags |= FLT_FL_IS_REQ_DATA_FILTER;
chn->flt.nb_data_filters++; strm_flt(s)->nb_req_data_filters++;
}
} }
} }
@ -152,64 +153,16 @@ static inline void
unregister_data_filter(struct stream *s, struct channel *chn, struct filter *filter) unregister_data_filter(struct stream *s, struct channel *chn, struct filter *filter)
{ {
if (IS_DATA_FILTER(filter, chn)) { if (IS_DATA_FILTER(filter, chn)) {
if (chn->flags & CF_ISRESP) if (chn->flags & CF_ISRESP) {
filter->flags &= ~FLT_FL_IS_RSP_DATA_FILTER; filter->flags &= ~FLT_FL_IS_RSP_DATA_FILTER;
else strm_flt(s)->nb_rsp_data_filters--;
}
else {
filter->flags &= ~FLT_FL_IS_REQ_DATA_FILTER; filter->flags &= ~FLT_FL_IS_REQ_DATA_FILTER;
chn->flt.nb_data_filters--; strm_flt(s)->nb_req_data_filters--;
} }
} }
/*
* flt_list_start() and flt_list_next() can be used to iterate over the list of filters
* for a given <strm> and <chn> combination. It will automatically choose the proper
* list to iterate from depending on the context.
*
* flt_list_start() has to be called exactly once to get the first value from the list
* to get the following values, use flt_list_next() until NULL is returned.
*
* Example:
*
* struct filter *filter;
*
* for (filter = flt_list_start(stream, channel); filter;
* filter = flt_list_next(stream, channel, filter)) {
* ...
* }
*/
static inline struct filter *flt_list_start(struct stream *strm, struct channel *chn)
{
struct filter *filter;
if (chn->flags & CF_ISRESP) {
filter = LIST_NEXT(&chn->flt.filters, struct filter *, res_list);
if (&filter->res_list == &chn->flt.filters)
filter = NULL; /* empty list */
}
else {
filter = LIST_NEXT(&chn->flt.filters, struct filter *, req_list);
if (&filter->req_list == &chn->flt.filters)
filter = NULL; /* empty list */
}
return filter;
}
static inline struct filter *flt_list_next(struct stream *strm, struct channel *chn,
struct filter *filter)
{
if (chn->flags & CF_ISRESP) {
filter = LIST_NEXT(&filter->res_list, struct filter *, res_list);
if (&filter->res_list == &chn->flt.filters)
filter = NULL; /* end of list */
}
else {
filter = LIST_NEXT(&filter->req_list, struct filter *, req_list);
if (&filter->req_list == &chn->flt.filters)
filter = NULL; /* end of list */
}
return filter;
} }
/* This function must be called when a filter alter payload data. It updates /* This function must be called when a filter alter payload data. It updates
@ -224,8 +177,7 @@ flt_update_offsets(struct filter *filter, struct channel *chn, int len)
struct stream *s = chn_strm(chn); struct stream *s = chn_strm(chn);
struct filter *f; struct filter *f;
for (f = flt_list_start(s, chn); f; list_for_each_entry(f, &strm_flt(s)->filters, list) {
f = flt_list_next(s, chn, f)) {
if (f == filter) if (f == filter)
break; break;
FLT_OFF(f, chn) += len; FLT_OFF(f, chn) += len;

View file

@ -403,25 +403,6 @@ static inline uint swrate_add_scaled_opportunistic(uint *sum, uint n, uint v, ui
return new_sum; return new_sum;
} }
/* Like swrate_add() except that if <v> is beyond the current average, the
* average is replaced by the peak. This is essentially used to measure peak
* loads in the scheduler, reason why it is provided as a local variant that
* does not involve atomic operations.
*/
static inline uint swrate_add_peak_local(uint *sum, uint n, uint v)
{
uint old_sum, new_sum;
old_sum = *sum;
if (v * n > old_sum)
new_sum = v * n;
else
new_sum = old_sum - (old_sum + n - 1) / n + v;
*sum = new_sum;
return new_sum;
}
/* Returns the average sample value for the sum <sum> over a sliding window of /* Returns the average sample value for the sum <sum> over a sliding window of
* <n> samples. Better if <n> is a power of two. It must be the same <n> as the * <n> samples. Better if <n> is a power of two. It must be the same <n> as the
* one used above in all additions. * one used above in all additions.

View file

@ -79,14 +79,13 @@
#define GTUNE_DISABLE_H2_WEBSOCKET (1<<21) #define GTUNE_DISABLE_H2_WEBSOCKET (1<<21)
#define GTUNE_DISABLE_ACTIVE_CLOSE (1<<22) #define GTUNE_DISABLE_ACTIVE_CLOSE (1<<22)
#define GTUNE_QUICK_EXIT (1<<23) #define GTUNE_QUICK_EXIT (1<<23)
#define GTUNE_COLLECT_LIBS (1<<24) /* (1<<24) unused */
/* (1<<25) unused */ /* (1<<25) unused */
#define GTUNE_USE_FAST_FWD (1<<26) #define GTUNE_USE_FAST_FWD (1<<26)
#define GTUNE_LISTENER_MQ_FAIR (1<<27) #define GTUNE_LISTENER_MQ_FAIR (1<<27)
#define GTUNE_LISTENER_MQ_OPT (1<<28) #define GTUNE_LISTENER_MQ_OPT (1<<28)
#define GTUNE_LISTENER_MQ_ANY (GTUNE_LISTENER_MQ_FAIR | GTUNE_LISTENER_MQ_OPT) #define GTUNE_LISTENER_MQ_ANY (GTUNE_LISTENER_MQ_FAIR | GTUNE_LISTENER_MQ_OPT)
#define GTUNE_NO_KTLS (1<<29) #define GTUNE_NO_KTLS (1<<29)
#define GTUNE_NO_MAX_COUNTER (1<<30)
/* subsystem-specific debugging options for tune.debug */ /* subsystem-specific debugging options for tune.debug */
#define GDBG_CPU_AFFINITY (1U<< 0) #define GDBG_CPU_AFFINITY (1U<< 0)
@ -180,7 +179,6 @@ struct global {
uint recv_enough; /* how many input bytes at once are "enough" */ uint recv_enough; /* how many input bytes at once are "enough" */
uint bufsize; /* buffer size in bytes, defaults to BUFSIZE */ uint bufsize; /* buffer size in bytes, defaults to BUFSIZE */
uint bufsize_small;/* small buffer size in bytes */ uint bufsize_small;/* small buffer size in bytes */
uint bufsize_large;/* large buffer size in bytes */
int maxrewrite; /* buffer max rewrite size in bytes, defaults to MAXREWRITE */ int maxrewrite; /* buffer max rewrite size in bytes, defaults to MAXREWRITE */
int reserved_bufs; /* how many buffers can only be allocated for response */ int reserved_bufs; /* how many buffers can only be allocated for response */
int buf_limit; /* if not null, how many total buffers may only be allocated */ int buf_limit; /* if not null, how many total buffers may only be allocated */

View file

@ -24,7 +24,6 @@
#include <haproxy/api-t.h> #include <haproxy/api-t.h>
#include <haproxy/global-t.h> #include <haproxy/global-t.h>
#include <haproxy/cfgparse.h>
extern struct global global; extern struct global global;
extern int pid; /* current process id */ extern int pid; /* current process id */
@ -55,12 +54,6 @@ extern char **old_argv;
extern const char *old_unixsocket; extern const char *old_unixsocket;
extern int daemon_fd[2]; extern int daemon_fd[2];
extern int devnullfd; extern int devnullfd;
extern int fileless_mode;
extern struct cfgfile fileless_cfg;
/* storage for collected libs */
extern void *lib_storage;
extern size_t lib_size;
struct proxy; struct proxy;
struct server; struct server;

View file

@ -99,7 +99,7 @@ enum h1m_state {
#define H1_MF_TE_CHUNKED 0x00010000 // T-E "chunked" #define H1_MF_TE_CHUNKED 0x00010000 // T-E "chunked"
#define H1_MF_TE_OTHER 0x00020000 // T-E other than supported ones found (only "chunked" is supported for now) #define H1_MF_TE_OTHER 0x00020000 // T-E other than supported ones found (only "chunked" is supported for now)
#define H1_MF_UPG_H2C 0x00040000 // "h2c" or "h2" used as upgrade token #define H1_MF_UPG_H2C 0x00040000 // "h2c" or "h2" used as upgrade token
#define H1_MF_NOT_HTTP 0x00080000 // Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted)
/* Mask to use to reset H1M flags when we restart headers parsing. /* Mask to use to reset H1M flags when we restart headers parsing.
* *
* WARNING: Don't forget to update it if a new flag must be preserved when * WARNING: Don't forget to update it if a new flag must be preserved when

View file

@ -222,7 +222,6 @@ struct hlua_proxy_list {
}; };
struct hlua_proxy_list_iterator_context { struct hlua_proxy_list_iterator_context {
struct watcher px_watch; /* watcher to automatically update next pointer on backend deletion */
struct proxy *next; struct proxy *next;
char capabilities; char capabilities;
}; };

View file

@ -1,36 +0,0 @@
#ifndef _HAPROXY_HSTREAM_T_H
#define _HAPROXY_HSTREAM_T_H
#include <haproxy/dynbuf-t.h>
#include <haproxy/http-t.h>
#include <haproxy/obj_type-t.h>
/* hastream stream */
struct hstream {
enum obj_type obj_type;
struct session *sess;
struct stconn *sc;
struct task *task;
struct buffer req;
struct buffer res;
unsigned long long to_write; /* #of response data bytes to write after headers */
struct buffer_wait buf_wait; /* Wait list for buffer allocation */
int flags;
int ka; /* .0: keep-alive .1: forced .2: http/1.1, .3: was_reused */
int req_cache;
unsigned long long req_size; /* values passed in the URI to override the server's */
unsigned long long req_body; /* remaining body to be consumed from the request */
int req_code;
int res_wait; /* time to wait before replying in ms */
int res_time;
int req_chunked;
int req_random;
int req_after_res; /* Drain the request body after having sent the response */
enum http_meth_t req_meth;
};
#endif /* _HAPROXY_HSTREAM_T_H */

View file

@ -1,11 +0,0 @@
#ifndef _HAPROXY_HSTREAM_H
#define _HAPROXY_HSTREAM_H
#include <haproxy/cfgparse.h>
#include <haproxy/hstream-t.h>
struct task *sc_hstream_io_cb(struct task *t, void *ctx, unsigned int state);
void hstream_shutdown(struct stconn *sc);
void *hstream_new(struct session *sess, struct stconn *sc, struct buffer *input);
#endif /* _HAPROXY_HSTREAM_H */

View file

@ -228,8 +228,7 @@ enum h1_state {
*/ */
struct http_msg { struct http_msg {
enum h1_state msg_state; /* where we are in the current message parsing */ enum h1_state msg_state; /* where we are in the current message parsing */
unsigned char vsn; /* HTTP version, 4 bits per digit */ /* 3 bytes unused here */
/* 2 bytes unused here */
unsigned int flags; /* flags describing the message (HTTP version, ...) */ unsigned int flags; /* flags describing the message (HTTP version, ...) */
struct channel *chn; /* pointer to the channel transporting the message */ struct channel *chn; /* pointer to the channel transporting the message */
}; };

View file

@ -49,7 +49,7 @@ int http_req_replace_stline(int action, const char *replace, int len,
int http_res_set_status(unsigned int status, struct ist reason, struct stream *s); int http_res_set_status(unsigned int status, struct ist reason, struct stream *s);
void http_check_request_for_cacheability(struct stream *s, struct channel *req); void http_check_request_for_cacheability(struct stream *s, struct channel *req);
void http_check_response_for_cacheability(struct stream *s, struct channel *res); void http_check_response_for_cacheability(struct stream *s, struct channel *res);
enum rule_result http_wait_for_msg_body(struct stream *s, struct channel *chn, unsigned int time, unsigned int bytes, unsigned int large_buffer); enum rule_result http_wait_for_msg_body(struct stream *s, struct channel *chn, unsigned int time, unsigned int bytes);
void http_perform_server_redirect(struct stream *s, struct stconn *sc); void http_perform_server_redirect(struct stream *s, struct stconn *sc);
void http_server_error(struct stream *s, struct stconn *sc, int err, int finst, struct http_reply *msg); void http_server_error(struct stream *s, struct stconn *sc, int err, int finst, struct http_reply *msg);
void http_reply_and_close(struct stream *s, short status, struct http_reply *msg); void http_reply_and_close(struct stream *s, short status, struct http_reply *msg);

View file

@ -93,22 +93,4 @@ struct http_errors {
struct list list; /* http-errors list */ struct list list; /* http-errors list */
}; };
/* Indicates the keyword origin of an http-error definition. This is used in
* <conf_errors> type to indicate which part of the internal union should be
* manipulated.
*/
enum http_err_directive {
HTTP_ERR_DIRECTIVE_SECTION = 0, /* "errorfiles" keyword referencing a http-errors section */
HTTP_ERR_DIRECTIVE_INLINE, /* "errorfile" keyword with inline error definition */
};
/* Used with "errorfiles" directives. It indicates for each known HTTP error
* status codes if they are defined in the target http-errors section.
*/
enum http_err_import {
HTTP_ERR_IMPORT_NO = 0,
HTTP_ERR_IMPORT_IMPLICIT, /* import every errcode defined in a section */
HTTP_ERR_IMPORT_EXPLICIT, /* import a specific errcode from a section */
};
#endif /* _HAPROXY_HTTP_HTX_T_H */ #endif /* _HAPROXY_HTTP_HTX_T_H */

View file

@ -78,7 +78,6 @@ struct buffer *http_load_errorfile(const char *file, char **errmsg);
struct buffer *http_load_errormsg(const char *key, const struct ist msg, char **errmsg); struct buffer *http_load_errormsg(const char *key, const struct ist msg, char **errmsg);
struct buffer *http_parse_errorfile(int status, const char *file, char **errmsg); struct buffer *http_parse_errorfile(int status, const char *file, char **errmsg);
struct buffer *http_parse_errorloc(int errloc, int status, const char *url, char **errmsg); struct buffer *http_parse_errorloc(int errloc, int status, const char *url, char **errmsg);
int proxy_check_http_errors(struct proxy *px);
int proxy_dup_default_conf_errors(struct proxy *curpx, const struct proxy *defpx, char **errmsg); int proxy_dup_default_conf_errors(struct proxy *curpx, const struct proxy *defpx, char **errmsg);
void proxy_release_conf_errors(struct proxy *px); void proxy_release_conf_errors(struct proxy *px);

View file

@ -141,7 +141,6 @@
#define HTX_SL_F_NORMALIZED_URI 0x00000800 /* The received URI is normalized (an implicit absolute-uri form) */ #define HTX_SL_F_NORMALIZED_URI 0x00000800 /* The received URI is normalized (an implicit absolute-uri form) */
#define HTX_SL_F_CONN_UPG 0x00001000 /* The message contains "connection: upgrade" header */ #define HTX_SL_F_CONN_UPG 0x00001000 /* The message contains "connection: upgrade" header */
#define HTX_SL_F_BODYLESS_RESP 0x00002000 /* The response to this message is bodyloess (only for reqyest) */ #define HTX_SL_F_BODYLESS_RESP 0x00002000 /* The response to this message is bodyloess (only for reqyest) */
#define HTX_SL_F_NOT_HTTP 0x00004000 /* Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted) */
/* This function is used to report flags in debugging tools. Please reflect /* This function is used to report flags in debugging tools. Please reflect
* below any single-bit flag addition above in the same order via the * below any single-bit flag addition above in the same order via the
@ -178,7 +177,7 @@ static forceinline char *hsl_show_flags(char *buf, size_t len, const char *delim
#define HTX_FL_PARSING_ERROR 0x00000001 /* Set when a parsing error occurred */ #define HTX_FL_PARSING_ERROR 0x00000001 /* Set when a parsing error occurred */
#define HTX_FL_PROCESSING_ERROR 0x00000002 /* Set when a processing error occurred */ #define HTX_FL_PROCESSING_ERROR 0x00000002 /* Set when a processing error occurred */
#define HTX_FL_FRAGMENTED 0x00000004 /* Set when the HTX buffer is fragmented */ #define HTX_FL_FRAGMENTED 0x00000004 /* Set when the HTX buffer is fragmented */
#define HTX_FL_UNORDERED 0x00000008 /* Set when the HTX buffer are not ordered */ /* 0x00000008 unused */
#define HTX_FL_EOM 0x00000010 /* Set when end-of-message is reached from the HTTP point of view #define HTX_FL_EOM 0x00000010 /* Set when end-of-message is reached from the HTTP point of view
* (at worst, on the EOM block is missing) * (at worst, on the EOM block is missing)
*/ */
@ -193,7 +192,7 @@ static forceinline char *htx_show_flags(char *buf, size_t len, const char *delim
_(0); _(0);
/* flags */ /* flags */
_(HTX_FL_PARSING_ERROR, _(HTX_FL_PROCESSING_ERROR, _(HTX_FL_PARSING_ERROR, _(HTX_FL_PROCESSING_ERROR,
_(HTX_FL_FRAGMENTED, _(HTX_FL_UNORDERED, _(HTX_FL_EOM))))); _(HTX_FL_FRAGMENTED, _(HTX_FL_EOM))));
/* epilogue */ /* epilogue */
_(~0U); _(~0U);
return buf; return buf;

View file

@ -37,7 +37,6 @@ struct htx_blk *htx_add_blk(struct htx *htx, enum htx_blk_type type, uint32_t bl
struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk); struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk);
struct htx_ret htx_find_offset(struct htx *htx, uint32_t offset); struct htx_ret htx_find_offset(struct htx *htx, uint32_t offset);
void htx_truncate(struct htx *htx, uint32_t offset); void htx_truncate(struct htx *htx, uint32_t offset);
void htx_truncate_blk(struct htx *htx, struct htx_blk *blk);
struct htx_ret htx_drain(struct htx *htx, uint32_t max); struct htx_ret htx_drain(struct htx *htx, uint32_t max);
struct htx_blk *htx_replace_blk_value(struct htx *htx, struct htx_blk *blk, struct htx_blk *htx_replace_blk_value(struct htx *htx, struct htx_blk *blk,
@ -57,16 +56,6 @@ size_t htx_add_data(struct htx *htx, const struct ist data);
struct htx_blk *htx_add_last_data(struct htx *htx, struct ist data); struct htx_blk *htx_add_last_data(struct htx *htx, struct ist data);
void htx_move_blk_before(struct htx *htx, struct htx_blk **blk, struct htx_blk **ref); void htx_move_blk_before(struct htx *htx, struct htx_blk **blk, struct htx_blk **ref);
int htx_append_msg(struct htx *dst, const struct htx *src); int htx_append_msg(struct htx *dst, const struct htx *src);
struct buffer *htx_move_to_small_buffer(struct buffer *dst, struct buffer *src);
struct buffer *htx_move_to_large_buffer(struct buffer *dst, struct buffer *src);
struct buffer *htx_copy_to_small_buffer(struct buffer *dst, struct buffer *src);
struct buffer *htx_copy_to_large_buffer(struct buffer *dst, struct buffer *src);
#define HTX_XFER_DEFAULT 0x00000000 /* Default XFER: no partial xfer / remove blocks from source */
#define HTX_XFER_KEEP_SRC_BLKS 0x00000001 /* Don't remove xfer blocks from source messages during xfer */
#define HTX_XFER_PARTIAL_HDRS_COPY 0x00000002 /* Allow partial copy of headers and trailers part */
#define HTX_XFER_HDRS_ONLY 0x00000003 /* Only Transfert header blocks (start-line, header and EOH) */
size_t htx_xfer(struct htx *dst, struct htx *src, size_t count, unsigned int flags);
/* Functions and macros to get parts of the start-line or length of these /* Functions and macros to get parts of the start-line or length of these
* parts. Request and response start-lines are both composed of 3 parts. * parts. Request and response start-lines are both composed of 3 parts.
@ -109,11 +98,6 @@ static inline struct ist htx_sl_p3(const struct htx_sl *sl)
return ist2(HTX_SL_P3_PTR(sl), HTX_SL_P3_LEN(sl)); return ist2(HTX_SL_P3_PTR(sl), HTX_SL_P3_LEN(sl));
} }
static inline struct ist htx_sl_vsn(const struct htx_sl *sl)
{
return ((sl->flags & HTX_SL_F_IS_RESP) ? htx_sl_p1(sl) : htx_sl_p3(sl));
}
static inline struct ist htx_sl_req_meth(const struct htx_sl *sl) static inline struct ist htx_sl_req_meth(const struct htx_sl *sl)
{ {
return htx_sl_p1(sl); return htx_sl_p1(sl);
@ -490,12 +474,11 @@ static inline struct htx_sl *htx_add_stline(struct htx *htx, enum htx_blk_type t
static inline struct htx_blk *htx_add_header(struct htx *htx, const struct ist name, static inline struct htx_blk *htx_add_header(struct htx *htx, const struct ist name,
const struct ist value) const struct ist value)
{ {
struct htx_blk *blk, *tailblk; struct htx_blk *blk;
if (name.len > 255 || value.len > 1048575) if (name.len > 255 || value.len > 1048575)
return NULL; return NULL;
tailblk = htx_get_tail_blk(htx);
blk = htx_add_blk(htx, HTX_BLK_HDR, name.len + value.len); blk = htx_add_blk(htx, HTX_BLK_HDR, name.len + value.len);
if (!blk) if (!blk)
return NULL; return NULL;
@ -503,8 +486,6 @@ static inline struct htx_blk *htx_add_header(struct htx *htx, const struct ist n
blk->info += (value.len << 8) + name.len; blk->info += (value.len << 8) + name.len;
ist2bin_lc(htx_get_blk_ptr(htx, blk), name); ist2bin_lc(htx_get_blk_ptr(htx, blk), name);
memcpy(htx_get_blk_ptr(htx, blk) + name.len, value.ptr, value.len); memcpy(htx_get_blk_ptr(htx, blk) + name.len, value.ptr, value.len);
if (tailblk && htx_get_blk_type(tailblk) >= HTX_BLK_EOH)
htx->flags |= HTX_FL_UNORDERED;
return blk; return blk;
} }
@ -514,12 +495,11 @@ static inline struct htx_blk *htx_add_header(struct htx *htx, const struct ist n
static inline struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist name, static inline struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist name,
const struct ist value) const struct ist value)
{ {
struct htx_blk *blk, *tailblk; struct htx_blk *blk;
if (name.len > 255 || value.len > 1048575) if (name.len > 255 || value.len > 1048575)
return NULL; return NULL;
tailblk = htx_get_tail_blk(htx);
blk = htx_add_blk(htx, HTX_BLK_TLR, name.len + value.len); blk = htx_add_blk(htx, HTX_BLK_TLR, name.len + value.len);
if (!blk) if (!blk)
return NULL; return NULL;
@ -527,8 +507,6 @@ static inline struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist
blk->info += (value.len << 8) + name.len; blk->info += (value.len << 8) + name.len;
ist2bin_lc(htx_get_blk_ptr(htx, blk), name); ist2bin_lc(htx_get_blk_ptr(htx, blk), name);
memcpy(htx_get_blk_ptr(htx, blk) + name.len, value.ptr, value.len); memcpy(htx_get_blk_ptr(htx, blk) + name.len, value.ptr, value.len);
if (tailblk && htx_get_blk_type(tailblk) >= HTX_BLK_EOT)
htx->flags |= HTX_FL_UNORDERED;
return blk; return blk;
} }

View file

@ -20,11 +20,6 @@ extern struct list server_deinit_list;
extern struct list per_thread_free_list; extern struct list per_thread_free_list;
extern struct list per_thread_deinit_list; extern struct list per_thread_deinit_list;
/* initcall caller location */
extern const struct initcall *caller_initcall;
extern const char *caller_file;
extern int caller_line;
void hap_register_pre_check(int (*fct)()); void hap_register_pre_check(int (*fct)());
void hap_register_post_check(int (*fct)()); void hap_register_post_check(int (*fct)());
void hap_register_post_proxy_check(int (*fct)(struct proxy *)); void hap_register_post_proxy_check(int (*fct)(struct proxy *));

View file

@ -77,8 +77,6 @@ struct initcall {
void *arg1; void *arg1;
void *arg2; void *arg2;
void *arg3; void *arg3;
const char *loc_file; /* file where the call is declared, or NULL */
int loc_line; /* line where the call is declared, or NULL */
#if defined(USE_OBSOLETE_LINKER) #if defined(USE_OBSOLETE_LINKER)
void *next; void *next;
#endif #endif
@ -109,8 +107,6 @@ struct initcall {
.arg1 = (void *)(a1), \ .arg1 = (void *)(a1), \
.arg2 = (void *)(a2), \ .arg2 = (void *)(a2), \
.arg3 = (void *)(a3), \ .arg3 = (void *)(a3), \
.loc_file = __FILE__, \
.loc_line = linenum, \
} : NULL } : NULL
@ -135,8 +131,6 @@ __attribute__((constructor)) static void __initcb_##linenum() \
.arg1 = (void *)(a1), \ .arg1 = (void *)(a1), \
.arg2 = (void *)(a2), \ .arg2 = (void *)(a2), \
.arg3 = (void *)(a3), \ .arg3 = (void *)(a3), \
.loc_file = __FILE__, \
.loc_line = linenum, \
}; \ }; \
if (stg < STG_SIZE) { \ if (stg < STG_SIZE) { \
entry.next = __initstg[stg]; \ entry.next = __initstg[stg]; \
@ -153,14 +147,14 @@ __attribute__((constructor)) static void __initcb_##linenum() \
#define _DECLARE_INITCALL(...) \ #define _DECLARE_INITCALL(...) \
__DECLARE_INITCALL(__VA_ARGS__) __DECLARE_INITCALL(__VA_ARGS__)
/* This requires that function <function> is called without arguments /* This requires that function <function> is called with pointer argument
* during init stage <stage> which must be one of init_stage. * <argument> during init stage <stage> which must be one of init_stage.
*/ */
#define INITCALL0(stage, function) \ #define INITCALL0(stage, function) \
_DECLARE_INITCALL(stage, __LINE__, function, 0, 0, 0) _DECLARE_INITCALL(stage, __LINE__, function, 0, 0, 0)
/* This requires that function <function> is called with pointer argument /* This requires that function <function> is called with pointer argument
* <arg1> during init stage <stage> which must be one of init_stage. * <argument> during init stage <stage> which must be one of init_stage.
*/ */
#define INITCALL1(stage, function, arg1) \ #define INITCALL1(stage, function, arg1) \
_DECLARE_INITCALL(stage, __LINE__, function, arg1, 0, 0) _DECLARE_INITCALL(stage, __LINE__, function, arg1, 0, 0)
@ -235,15 +229,8 @@ extern struct initcall *__initstg[STG_SIZE];
const struct initcall **ptr; \ const struct initcall **ptr; \
if (stg >= STG_SIZE) \ if (stg >= STG_SIZE) \
break; \ break; \
FOREACH_INITCALL(ptr, stg) { \ FOREACH_INITCALL(ptr, stg) \
caller_initcall = *ptr; \
caller_file = (*ptr)->loc_file; \
caller_line = (*ptr)->loc_line; \
(*ptr)->fct((*ptr)->arg1, (*ptr)->arg2, (*ptr)->arg3); \ (*ptr)->fct((*ptr)->arg1, (*ptr)->arg2, (*ptr)->arg3); \
caller_initcall = NULL; \
caller_file = NULL; \
caller_line = 0; \
} \
} while (0) } while (0)
#else // USE_OBSOLETE_LINKER #else // USE_OBSOLETE_LINKER
@ -256,15 +243,8 @@ extern struct initcall *__initstg[STG_SIZE];
const struct initcall *ptr; \ const struct initcall *ptr; \
if (stg >= STG_SIZE) \ if (stg >= STG_SIZE) \
break; \ break; \
FOREACH_INITCALL(ptr, stg) { \ FOREACH_INITCALL(ptr, stg) \
caller_initcall = ptr; \
caller_file = (ptr)->loc_file; \
caller_line = (ptr)->loc_line; \
(ptr)->fct((ptr)->arg1, (ptr)->arg2, (ptr)->arg3); \ (ptr)->fct((ptr)->arg1, (ptr)->arg2, (ptr)->arg3); \
caller_initcall = NULL; \
caller_file = NULL; \
caller_line = 0; \
} \
} while (0) } while (0)
#endif // USE_OBSOLETE_LINKER #endif // USE_OBSOLETE_LINKER

View file

@ -27,7 +27,7 @@
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
enum jwt_alg jwt_parse_alg(const char *alg_str, unsigned int alg_len); enum jwt_alg jwt_parse_alg(const char *alg_str, unsigned int alg_len);
int jwt_tokenize(const struct buffer *jwt, struct jwt_item *items, unsigned int item_num); int jwt_tokenize(const struct buffer *jwt, struct jwt_item *items, unsigned int *item_num);
int jwt_tree_load_cert(char *path, int pathlen, int tryload_cert, const char *file, int line, char **err); int jwt_tree_load_cert(char *path, int pathlen, int tryload_cert, const char *file, int line, char **err);
enum jwt_vrfy_status jwt_verify(const struct buffer *token, const struct buffer *alg, enum jwt_vrfy_status jwt_verify(const struct buffer *token, const struct buffer *alg,

View file

@ -28,13 +28,13 @@
#include <import/ebtree-t.h> #include <import/ebtree-t.h>
#include <haproxy/api-t.h> #include <haproxy/api-t.h>
#include <haproxy/counters-t.h>
#include <haproxy/guid-t.h> #include <haproxy/guid-t.h>
#include <haproxy/obj_type-t.h> #include <haproxy/obj_type-t.h>
#include <haproxy/quic_cc-t.h> #include <haproxy/quic_cc-t.h>
#include <haproxy/quic_sock-t.h> #include <haproxy/quic_sock-t.h>
#include <haproxy/quic_tp-t.h> #include <haproxy/quic_tp-t.h>
#include <haproxy/receiver-t.h> #include <haproxy/receiver-t.h>
#include <haproxy/stats-t.h>
#include <haproxy/thread.h> #include <haproxy/thread.h>
/* Some pointer types reference below */ /* Some pointer types reference below */
@ -263,7 +263,6 @@ struct listener {
struct li_per_thread *per_thr; /* per-thread fields (one per thread in the group) */ struct li_per_thread *per_thr; /* per-thread fields (one per thread in the group) */
char *extra_counters_storage; /* storage for extra_counters */
EXTRA_COUNTERS(extra_counters); EXTRA_COUNTERS(extra_counters);
}; };

View file

@ -200,8 +200,6 @@ enum qcc_app_ops_close_side {
/* QUIC application layer operations */ /* QUIC application layer operations */
struct qcc_app_ops { struct qcc_app_ops {
const char *alpn;
/* Initialize <qcc> connection app context. */ /* Initialize <qcc> connection app context. */
int (*init)(struct qcc *qcc); int (*init)(struct qcc *qcc);
/* Finish connection initialization if prelude required. */ /* Finish connection initialization if prelude required. */
@ -234,9 +232,6 @@ struct qcc_app_ops {
void (*inc_err_cnt)(void *ctx, int err_code); void (*inc_err_cnt)(void *ctx, int err_code);
/* Set QCC error code as suspicious activity has been detected. */ /* Set QCC error code as suspicious activity has been detected. */
void (*report_susp)(void *ctx); void (*report_susp)(void *ctx);
/* Free function to close a stream after MUX layer shutdown. */
int (*strm_reject)(struct list *out, uint64_t id);
}; };
#endif /* USE_QUIC */ #endif /* USE_QUIC */

View file

@ -12,9 +12,6 @@
#include <haproxy/mux_quic-t.h> #include <haproxy/mux_quic-t.h>
#include <haproxy/stconn.h> #include <haproxy/stconn.h>
#include <haproxy/h3.h>
#include <haproxy/hq_interop.h>
#define qcc_report_glitch(qcc, inc, ...) ({ \ #define qcc_report_glitch(qcc, inc, ...) ({ \
COUNT_GLITCH(__VA_ARGS__); \ COUNT_GLITCH(__VA_ARGS__); \
_qcc_report_glitch(qcc, inc); \ _qcc_report_glitch(qcc, inc); \
@ -91,7 +88,7 @@ static inline char *qcs_st_to_str(enum qcs_state st)
} }
} }
int qcc_install_app_ops(struct qcc *qcc); int qcc_install_app_ops(struct qcc *qcc, const struct qcc_app_ops *app_ops);
/* Register <qcs> stream for http-request timeout. If the stream is not yet /* Register <qcs> stream for http-request timeout. If the stream is not yet
* attached in the configured delay, qcc timeout task will be triggered. This * attached in the configured delay, qcc timeout task will be triggered. This
@ -118,16 +115,6 @@ void qcc_show_quic(struct qcc *qcc);
void qcc_wakeup(struct qcc *qcc); void qcc_wakeup(struct qcc *qcc);
static inline const struct qcc_app_ops *quic_alpn_to_app_ops(const char *alpn, int alpn_len)
{
if (alpn_len >= 2 && memcmp(alpn, "h3", 2) == 0)
return &h3_ops;
else if (alpn_len >= 10 && memcmp(alpn, "hq-interop", 10) == 0)
return &hq_interop_ops;
return NULL;
}
#endif /* USE_QUIC */ #endif /* USE_QUIC */
#endif /* _HAPROXY_MUX_QUIC_H */ #endif /* _HAPROXY_MUX_QUIC_H */

View file

@ -46,7 +46,6 @@ enum obj_type {
#ifdef USE_QUIC #ifdef USE_QUIC
OBJ_TYPE_DGRAM, /* object is a struct quic_dgram */ OBJ_TYPE_DGRAM, /* object is a struct quic_dgram */
#endif #endif
OBJ_TYPE_HATERM, /* object is a struct hstream */
OBJ_TYPE_ENTRIES /* last one : number of entries */ OBJ_TYPE_ENTRIES /* last one : number of entries */
} __attribute__((packed)) ; } __attribute__((packed)) ;

View file

@ -26,7 +26,6 @@
#include <haproxy/applet-t.h> #include <haproxy/applet-t.h>
#include <haproxy/check-t.h> #include <haproxy/check-t.h>
#include <haproxy/connection-t.h> #include <haproxy/connection-t.h>
#include <haproxy/hstream-t.h>
#include <haproxy/listener-t.h> #include <haproxy/listener-t.h>
#include <haproxy/obj_type-t.h> #include <haproxy/obj_type-t.h>
#include <haproxy/pool.h> #include <haproxy/pool.h>
@ -190,19 +189,6 @@ static inline struct check *objt_check(enum obj_type *t)
return __objt_check(t); return __objt_check(t);
} }
static inline struct hstream *__objt_hstream(enum obj_type *t)
{
return container_of(t, struct hstream, obj_type);
}
static inline struct hstream *objt_hstream(enum obj_type *t)
{
if (!t || *t != OBJ_TYPE_HATERM)
return NULL;
return __objt_hstream(t);
}
#ifdef USE_QUIC #ifdef USE_QUIC
static inline struct quic_dgram *__objt_dgram(enum obj_type *t) static inline struct quic_dgram *__objt_dgram(enum obj_type *t)
{ {

View file

@ -394,12 +394,6 @@ static inline unsigned long ERR_peek_error_func(const char **func)
#define __OPENSSL_110_CONST__ #define __OPENSSL_110_CONST__
#endif #endif
#if (HA_OPENSSL_VERSION_NUMBER >= 0x40000000L) && (!defined(USE_OPENSSL_WOLFSSL))
#define __X509_NAME_CONST__ const
#else
#define __X509_NAME_CONST__
#endif
/* ERR_remove_state() was deprecated in 1.0.0 in favor of /* ERR_remove_state() was deprecated in 1.0.0 in favor of
* ERR_remove_thread_state(), which was in turn deprecated in * ERR_remove_thread_state(), which was in turn deprecated in
* 1.1.0 and does nothing anymore. Let's simply silently kill * 1.1.0 and does nothing anymore. Let's simply silently kill

View file

@ -124,12 +124,6 @@ static inline int real_family(int ss_family)
return fam ? fam->real_family : AF_UNSPEC; return fam ? fam->real_family : AF_UNSPEC;
} }
static inline int proto_is_quic(const struct protocol *proto)
{
return (proto->proto_type == PROTO_TYPE_DGRAM &&
proto->xprt_type == PROTO_TYPE_STREAM);
}
#endif /* _HAPROXY_PROTOCOL_H */ #endif /* _HAPROXY_PROTOCOL_H */
/* /*

View file

@ -38,6 +38,7 @@
#include <haproxy/obj_type-t.h> #include <haproxy/obj_type-t.h>
#include <haproxy/queue-t.h> #include <haproxy/queue-t.h>
#include <haproxy/server-t.h> #include <haproxy/server-t.h>
#include <haproxy/stats-t.h>
#include <haproxy/tcpcheck-t.h> #include <haproxy/tcpcheck-t.h>
#include <haproxy/thread-t.h> #include <haproxy/thread-t.h>
#include <haproxy/tools-t.h> #include <haproxy/tools-t.h>
@ -156,17 +157,14 @@ enum PR_SRV_STATE_FILE {
#define PR_O2_RSTRICT_REQ_HDR_NAMES_NOOP 0x01000000 /* preserve request header names containing chars outside of [0-9a-zA-Z-] charset */ #define PR_O2_RSTRICT_REQ_HDR_NAMES_NOOP 0x01000000 /* preserve request header names containing chars outside of [0-9a-zA-Z-] charset */
#define PR_O2_RSTRICT_REQ_HDR_NAMES_MASK 0x01c00000 /* mask for restrict-http-header-names option */ #define PR_O2_RSTRICT_REQ_HDR_NAMES_MASK 0x01c00000 /* mask for restrict-http-header-names option */
/* unused : 0x02000000 ... 0x08000000 */
/* server health checks */ /* server health checks */
#define PR_O2_CHK_NONE 0x00000000 /* no L7 health checks configured (TCP by default) */ #define PR_O2_CHK_NONE 0x00000000 /* no L7 health checks configured (TCP by default) */
#define PR_O2_TCPCHK_CHK 0x02000000 /* use TCPCHK check for server health */ #define PR_O2_TCPCHK_CHK 0x90000000 /* use TCPCHK check for server health */
#define PR_O2_EXT_CHK 0x04000000 /* use external command for server health */ #define PR_O2_EXT_CHK 0xA0000000 /* use external command for server health */
#define PR_O2_CHK_ANY 0x06000000 /* Mask to cover any check */ /* unused: 0xB0000000 to 0xF000000, reserved for health checks */
#define PR_O2_CHK_ANY 0xF0000000 /* Mask to cover any check */
#define PR_O2_USE_SBUF_QUEUE 0x08000000 /* use small buffer for request when stream are queued*/
#define PR_O2_USE_SBUF_L7_RETRY 0x10000000 /* use small buffer for request when L7 retires are enabled */
#define PR_O2_USE_SBUF_CHECK 0x20000000 /* use small buffer for request's healthchecks */
#define PR_O2_USE_SBUF_ALL 0x38000000 /* all flags for use-large-buffer option */
/* unused : 0x40000000 ... 0x80000000 */
/* end of proxy->options2 */ /* end of proxy->options2 */
/* bits for proxy->options3 */ /* bits for proxy->options3 */
@ -242,16 +240,14 @@ enum PR_SRV_STATE_FILE {
#define PR_RE_JUNK_REQUEST 0x00020000 /* We received an incomplete or garbage response */ #define PR_RE_JUNK_REQUEST 0x00020000 /* We received an incomplete or garbage response */
/* Proxy flags */ /* Proxy flags */
#define PR_FL_DISABLED 0x00000001 /* The proxy was disabled in the configuration (not at runtime) */ #define PR_FL_DISABLED 0x01 /* The proxy was disabled in the configuration (not at runtime) */
#define PR_FL_STOPPED 0x00000002 /* The proxy was stopped */ #define PR_FL_STOPPED 0x02 /* The proxy was stopped */
#define PR_FL_DEF_EXPLICIT_MODE 0x00000004 /* Proxy mode is explicitely defined - only used for defaults instance */ #define PR_FL_READY 0x04 /* The proxy is ready to be used (initialized and configured) */
#define PR_FL_EXPLICIT_REF 0x00000008 /* The default proxy is explicitly referenced by another proxy */ #define PR_FL_EXPLICIT_REF 0x08 /* The default proxy is explicitly referenced by another proxy */
#define PR_FL_IMPLICIT_REF 0x00000010 /* The default proxy is implicitly referenced by another proxy */ #define PR_FL_IMPLICIT_REF 0x10 /* The default proxy is implicitly referenced by another proxy */
#define PR_FL_PAUSED 0x00000020 /* The proxy was paused at run time (reversible) */ #define PR_FL_PAUSED 0x20 /* The proxy was paused at run time (reversible) */
#define PR_FL_CHECKED 0x00000040 /* The proxy configuration was fully checked (including postparsing checks) */ #define PR_FL_CHECKED 0x40 /* The proxy configuration was fully checked (including postparsing checks) */
#define PR_FL_BE_UNPUBLISHED 0x00000080 /* The proxy cannot be targetted by content switching rules */ #define PR_FL_BE_UNPUBLISHED 0x80 /* The proxy cannot be targetted by content switching rules */
#define PR_FL_DELETED 0x00000100 /* Proxy has been deleted and must be manipulated with care */
#define PR_FL_NON_PURGEABLE 0x00000200 /* Proxy referenced by config elements which prevent its runtime removal. */
struct stream; struct stream;
@ -297,8 +293,7 @@ struct error_snapshot {
struct server *srv; /* server associated with the error (or NULL) */ struct server *srv; /* server associated with the error (or NULL) */
/* @64 */ /* @64 */
unsigned int ev_id; /* event number (counter incremented for each capture) */ unsigned int ev_id; /* event number (counter incremented for each capture) */
unsigned int buf_size; /* buffer size */ /* @68: 4 bytes hole here */
struct sockaddr_storage src; /* client's address */ struct sockaddr_storage src; /* client's address */
/**** protocol-specific part ****/ /**** protocol-specific part ****/
@ -310,16 +305,13 @@ struct error_snapshot {
struct proxy_per_tgroup { struct proxy_per_tgroup {
struct queue queue; struct queue queue;
struct lbprm_per_tgrp lbprm; struct lbprm_per_tgrp lbprm;
char *extra_counters_fe_storage; /* storage for extra_counters_fe */
char *extra_counters_be_storage; /* storage for extra_counters_be */
} THREAD_ALIGNED(); } THREAD_ALIGNED();
struct proxy { struct proxy {
enum obj_type obj_type; /* object type == OBJ_TYPE_PROXY */ enum obj_type obj_type; /* object type == OBJ_TYPE_PROXY */
char flags; /* bit field PR_FL_* */
enum pr_mode mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP, ... */ enum pr_mode mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP, ... */
char cap; /* supported capabilities (PR_CAP_*) */ char cap; /* supported capabilities (PR_CAP_*) */
/* 1 byte hole */
unsigned int flags; /* bit field PR_FL_* */
int to_log; /* things to be logged (LW_*), special value LW_LOGSTEPS == follow log-steps */ int to_log; /* things to be logged (LW_*), special value LW_LOGSTEPS == follow log-steps */
unsigned long last_change; /* internal use only: last time the proxy state was changed */ unsigned long last_change; /* internal use only: last time the proxy state was changed */
@ -420,7 +412,6 @@ struct proxy {
int redispatch_after; /* number of retries before redispatch */ int redispatch_after; /* number of retries before redispatch */
unsigned down_time; /* total time the proxy was down */ unsigned down_time; /* total time the proxy was down */
int (*accept)(struct stream *s); /* application layer's accept() */ int (*accept)(struct stream *s); /* application layer's accept() */
void *(*stream_new_from_sc)(struct session *sess, struct stconn *sc, struct buffer *in); /* stream instantiation callback for mux stream connector */
struct conn_src conn_src; /* connection source settings */ struct conn_src conn_src; /* connection source settings */
enum obj_type *default_target; /* default target to use for accepted streams or NULL */ enum obj_type *default_target; /* default target to use for accepted streams or NULL */
struct proxy *next; struct proxy *next;
@ -483,7 +474,7 @@ struct proxy {
struct log_steps log_steps; /* bitfield of log origins where log should be generated during request handling */ struct log_steps log_steps; /* bitfield of log origins where log should be generated during request handling */
const char *file_prev; /* file of the previous instance found with the same name, or NULL */ const char *file_prev; /* file of the previous instance found with the same name, or NULL */
int line_prev; /* line of the previous instance found with the same name, or 0 */ int line_prev; /* line of the previous instance found with the same name, or 0 */
unsigned int def_ref; /* default proxy only refcount */ unsigned int refcount; /* refcount on this proxy (only used for default proxy for now) */
} conf; /* config information */ } conf; /* config information */
struct http_ext *http_ext; /* http ext options */ struct http_ext *http_ext; /* http ext options */
struct ceb_root *used_server_addr; /* list of server addresses in use */ struct ceb_root *used_server_addr; /* list of server addresses in use */
@ -512,8 +503,6 @@ struct proxy {
struct list filter_configs; /* list of the filters that are declared on this proxy */ struct list filter_configs; /* list of the filters that are declared on this proxy */
struct guid_node guid; /* GUID global tree node */ struct guid_node guid; /* GUID global tree node */
struct mt_list watcher_list; /* list of elems which currently references this proxy instance (currently only used with backends) */
uint refcount; /* refcount to keep proxy from being deleted during runtime */
EXTRA_COUNTERS(extra_counters_fe); EXTRA_COUNTERS(extra_counters_fe);
EXTRA_COUNTERS(extra_counters_be); EXTRA_COUNTERS(extra_counters_be);

View file

@ -26,7 +26,6 @@
#include <haproxy/api.h> #include <haproxy/api.h>
#include <haproxy/applet-t.h> #include <haproxy/applet-t.h>
#include <haproxy/counters.h>
#include <haproxy/freq_ctr.h> #include <haproxy/freq_ctr.h>
#include <haproxy/list.h> #include <haproxy/list.h>
#include <haproxy/listener-t.h> #include <haproxy/listener-t.h>
@ -42,8 +41,6 @@ extern unsigned int error_snapshot_id; /* global ID assigned to each error then
extern struct ceb_root *proxy_by_name; /* tree of proxies sorted by name */ extern struct ceb_root *proxy_by_name; /* tree of proxies sorted by name */
extern struct list defaults_list; /* all defaults proxies list */ extern struct list defaults_list; /* all defaults proxies list */
extern unsigned int dynpx_next_id;
extern const struct cfg_opt cfg_opts[]; extern const struct cfg_opt cfg_opts[];
extern const struct cfg_opt cfg_opts2[]; extern const struct cfg_opt cfg_opts2[];
extern const struct cfg_opt cfg_opts3[]; extern const struct cfg_opt cfg_opts3[];
@ -59,10 +56,9 @@ void stop_proxy(struct proxy *p);
int stream_set_backend(struct stream *s, struct proxy *be); int stream_set_backend(struct stream *s, struct proxy *be);
void deinit_proxy(struct proxy *p); void deinit_proxy(struct proxy *p);
void proxy_drop(struct proxy *p); void free_proxy(struct proxy *p);
const char *proxy_cap_str(int cap); const char *proxy_cap_str(int cap);
const char *proxy_mode_str(int mode); const char *proxy_mode_str(int mode);
enum pr_mode str_to_proxy_mode(const char *mode);
const char *proxy_find_best_option(const char *word, const char **extra); const char *proxy_find_best_option(const char *word, const char **extra);
uint proxy_get_next_id(uint from); uint proxy_get_next_id(uint from);
void proxy_store_name(struct proxy *px); void proxy_store_name(struct proxy *px);
@ -78,12 +74,12 @@ void defaults_px_destroy_all_unref(void);
void defaults_px_detach(struct proxy *px); void defaults_px_detach(struct proxy *px);
void defaults_px_ref_all(void); void defaults_px_ref_all(void);
void defaults_px_unref_all(void); void defaults_px_unref_all(void);
int proxy_ref_defaults(struct proxy *px, struct proxy *defpx, char **errmsg);
void proxy_ref_defaults(struct proxy *px, struct proxy *defpx);
void proxy_unref_defaults(struct proxy *px); void proxy_unref_defaults(struct proxy *px);
int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char **errmsg); int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char **errmsg);
struct proxy *alloc_new_proxy(const char *name, unsigned int cap, struct proxy *alloc_new_proxy(const char *name, unsigned int cap,
char **errmsg); char **errmsg);
void proxy_take(struct proxy *px);
struct proxy *parse_new_proxy(const char *name, unsigned int cap, struct proxy *parse_new_proxy(const char *name, unsigned int cap,
const char *file, int linenum, const char *file, int linenum,
const struct proxy *defproxy); const struct proxy *defproxy);
@ -101,9 +97,6 @@ int resolve_stick_rule(struct proxy *curproxy, struct sticking_rule *mrule);
void free_stick_rules(struct list *rules); void free_stick_rules(struct list *rules);
void free_server_rules(struct list *srules); void free_server_rules(struct list *srules);
int proxy_init_per_thr(struct proxy *px); int proxy_init_per_thr(struct proxy *px);
int proxy_finalize(struct proxy *px, int *err_code);
int be_check_for_deletion(const char *bename, struct proxy **pb, const char **pm);
/* /*
* This function returns a string containing the type of the proxy in a format * This function returns a string containing the type of the proxy in a format
@ -182,7 +175,7 @@ static inline void proxy_inc_fe_conn_ctr(struct listener *l, struct proxy *fe)
} }
if (l && l->counters && l->counters->shared.tg) if (l && l->counters && l->counters->shared.tg)
_HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->cum_conn); _HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->cum_conn);
COUNTERS_UPDATE_MAX(&fe->fe_counters.cps_max, HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.cps_max,
update_freq_ctr(&fe->fe_counters._conn_per_sec, 1)); update_freq_ctr(&fe->fe_counters._conn_per_sec, 1));
} }
@ -195,7 +188,7 @@ static inline void proxy_inc_fe_sess_ctr(struct listener *l, struct proxy *fe)
} }
if (l && l->counters && l->counters->shared.tg) if (l && l->counters && l->counters->shared.tg)
_HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->cum_sess); _HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->cum_sess);
COUNTERS_UPDATE_MAX(&fe->fe_counters.sps_max, HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.sps_max,
update_freq_ctr(&fe->fe_counters._sess_per_sec, 1)); update_freq_ctr(&fe->fe_counters._sess_per_sec, 1));
} }
@ -222,7 +215,7 @@ static inline void proxy_inc_be_ctr(struct proxy *be)
_HA_ATOMIC_INC(&be->be_counters.shared.tg[tgid - 1]->cum_sess); _HA_ATOMIC_INC(&be->be_counters.shared.tg[tgid - 1]->cum_sess);
update_freq_ctr(&be->be_counters.shared.tg[tgid - 1]->sess_per_sec, 1); update_freq_ctr(&be->be_counters.shared.tg[tgid - 1]->sess_per_sec, 1);
} }
COUNTERS_UPDATE_MAX(&be->be_counters.sps_max, HA_ATOMIC_UPDATE_MAX(&be->be_counters.sps_max,
update_freq_ctr(&be->be_counters._sess_per_sec, 1)); update_freq_ctr(&be->be_counters._sess_per_sec, 1));
} }
@ -242,7 +235,7 @@ static inline void proxy_inc_fe_req_ctr(struct listener *l, struct proxy *fe,
} }
if (l && l->counters && l->counters->shared.tg) if (l && l->counters && l->counters->shared.tg)
_HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->p.http.cum_req[http_ver]); _HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->p.http.cum_req[http_ver]);
COUNTERS_UPDATE_MAX(&fe->fe_counters.p.http.rps_max, HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.p.http.rps_max,
update_freq_ctr(&fe->fe_counters.p.http._req_per_sec, 1)); update_freq_ctr(&fe->fe_counters.p.http._req_per_sec, 1));
} }

View file

@ -13,7 +13,6 @@ int qcs_http_handle_standalone_fin(struct qcs *qcs);
size_t qcs_http_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count, size_t qcs_http_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count,
char *fin); char *fin);
size_t qcs_http_reset_buf(struct qcs *qcs, struct buffer *buf, size_t count);
#endif /* USE_QUIC */ #endif /* USE_QUIC */

View file

@ -38,6 +38,7 @@
#include <haproxy/quic_cc-t.h> #include <haproxy/quic_cc-t.h>
#include <haproxy/quic_frame-t.h> #include <haproxy/quic_frame-t.h>
#include <haproxy/quic_openssl_compat-t.h> #include <haproxy/quic_openssl_compat-t.h>
#include <haproxy/quic_stats-t.h>
#include <haproxy/quic_tls-t.h> #include <haproxy/quic_tls-t.h>
#include <haproxy/quic_tp-t.h> #include <haproxy/quic_tp-t.h>
#include <haproxy/show_flags-t.h> #include <haproxy/show_flags-t.h>
@ -400,8 +401,6 @@ struct quic_conn {
struct eb_root streams_by_id; /* qc_stream_desc tree */ struct eb_root streams_by_id; /* qc_stream_desc tree */
const char *alpn;
/* MUX */ /* MUX */
struct qcc *qcc; struct qcc *qcc;
struct task *timer_task; struct task *timer_task;
@ -410,9 +409,7 @@ struct quic_conn {
/* Handshake expiration date */ /* Handshake expiration date */
unsigned int hs_expire; unsigned int hs_expire;
/* Callback to close any stream after MUX closure - set by the MUX itself */ const struct qcc_app_ops *app_ops;
int (*strm_reject)(struct list *out, uint64_t stream_id);
/* Proxy counters */ /* Proxy counters */
struct quic_counters *prx_counters; struct quic_counters *prx_counters;

View file

@ -30,7 +30,6 @@
#include <import/eb64tree.h> #include <import/eb64tree.h>
#include <import/ebmbtree.h> #include <import/ebmbtree.h>
#include <haproxy/counters.h>
#include <haproxy/chunk.h> #include <haproxy/chunk.h>
#include <haproxy/dynbuf.h> #include <haproxy/dynbuf.h>
#include <haproxy/ncbmbuf.h> #include <haproxy/ncbmbuf.h>
@ -84,7 +83,7 @@ void qc_check_close_on_released_mux(struct quic_conn *qc);
int quic_stateless_reset_token_cpy(unsigned char *pos, size_t len, int quic_stateless_reset_token_cpy(unsigned char *pos, size_t len,
const unsigned char *salt, size_t saltlen); const unsigned char *salt, size_t saltlen);
int quic_reuse_srv_params(struct quic_conn *qc, int quic_reuse_srv_params(struct quic_conn *qc,
const char *alpn, const unsigned char *alpn,
const struct quic_early_transport_params *etps); const struct quic_early_transport_params *etps);
/* Returns true if <qc> is used on the backed side (as a client). */ /* Returns true if <qc> is used on the backed side (as a client). */
@ -194,17 +193,13 @@ static inline void *qc_counters(enum obj_type *o, const struct stats_module *m)
p = l ? l->bind_conf->frontend : p = l ? l->bind_conf->frontend :
s ? s->proxy : NULL; s ? s->proxy : NULL;
if (l && p) return p ? EXTRA_COUNTERS_GET(p->extra_counters_fe, m) : NULL;
return EXTRA_COUNTERS_GET(p->extra_counters_fe, m);
else if (s && p)
return EXTRA_COUNTERS_GET(p->extra_counters_be, m);
return NULL;
} }
void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm); void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm);
void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err); void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err);
void quic_set_tls_alert(struct quic_conn *qc, int alert); void quic_set_tls_alert(struct quic_conn *qc, int alert);
int qc_register_alpn(struct quic_conn *qc, const char *alpn, int alpn_len); int quic_set_app_ops(struct quic_conn *qc, const unsigned char *alpn, size_t alpn_len);
int qc_check_dcid(struct quic_conn *qc, unsigned char *dcid, size_t dcid_len); int qc_check_dcid(struct quic_conn *qc, unsigned char *dcid, size_t dcid_len);
void qc_notify_err(struct quic_conn *qc); void qc_notify_err(struct quic_conn *qc);

View file

@ -6,6 +6,8 @@
#error "Must define USE_OPENSSL" #error "Must define USE_OPENSSL"
#endif #endif
extern struct stats_module quic_stats_module;
enum { enum {
QUIC_ST_RXBUF_FULL, QUIC_ST_RXBUF_FULL,
QUIC_ST_DROPPED_PACKET, QUIC_ST_DROPPED_PACKET,
@ -50,7 +52,6 @@ enum {
QUIC_ST_STREAM_DATA_BLOCKED, QUIC_ST_STREAM_DATA_BLOCKED,
QUIC_ST_STREAMS_BLOCKED_BIDI, QUIC_ST_STREAMS_BLOCKED_BIDI,
QUIC_ST_STREAMS_BLOCKED_UNI, QUIC_ST_STREAMS_BLOCKED_UNI,
QUIC_ST_NCBUF_GAP_LIMIT,
QUIC_STATS_COUNT /* must be the last */ QUIC_STATS_COUNT /* must be the last */
}; };
@ -98,7 +99,6 @@ struct quic_counters {
long long stream_data_blocked; /* total number of times STREAM_DATA_BLOCKED frame was received */ long long stream_data_blocked; /* total number of times STREAM_DATA_BLOCKED frame was received */
long long streams_blocked_bidi; /* total number of times STREAMS_BLOCKED_BIDI frame was received */ long long streams_blocked_bidi; /* total number of times STREAMS_BLOCKED_BIDI frame was received */
long long streams_blocked_uni; /* total number of times STREAMS_BLOCKED_UNI frame was received */ long long streams_blocked_uni; /* total number of times STREAMS_BLOCKED_UNI frame was received */
long long ncbuf_gap_limit; /* total number of times we failed to add data to ncbuf due to gap size limit */
}; };
#endif /* USE_QUIC */ #endif /* USE_QUIC */

View file

@ -7,9 +7,7 @@
#endif #endif
#include <haproxy/quic_stats-t.h> #include <haproxy/quic_stats-t.h>
#include <haproxy/stats-t.h>
extern struct stats_module quic_stats_module;
void quic_stats_transp_err_count_inc(struct quic_counters *ctrs, int error_code); void quic_stats_transp_err_count_inc(struct quic_counters *ctrs, int error_code);
#endif /* USE_QUIC */ #endif /* USE_QUIC */

View file

@ -27,6 +27,7 @@
#include <haproxy/connection-t.h> #include <haproxy/connection-t.h>
#include <haproxy/dns-t.h> #include <haproxy/dns-t.h>
#include <haproxy/obj_type-t.h> #include <haproxy/obj_type-t.h>
#include <haproxy/stats-t.h>
#include <haproxy/task-t.h> #include <haproxy/task-t.h>
#include <haproxy/thread.h> #include <haproxy/thread.h>

View file

@ -24,7 +24,6 @@
#define _HAPROXY_SAMPLE_T_H #define _HAPROXY_SAMPLE_T_H
#include <haproxy/api-t.h> #include <haproxy/api-t.h>
#include <haproxy/tinfo-t.h>
#include <haproxy/sample_data-t.h> #include <haproxy/sample_data-t.h>
/* input and output sample types /* input and output sample types
@ -266,7 +265,6 @@ struct sample_conv {
unsigned int in_type; /* expected input sample type */ unsigned int in_type; /* expected input sample type */
unsigned int out_type; /* output sample type */ unsigned int out_type; /* output sample type */
void *private; /* private values. only used by maps and Lua */ void *private; /* private values. only used by maps and Lua */
struct thread_exec_ctx exec_ctx; /* execution context */
}; };
/* sample conversion expression */ /* sample conversion expression */
@ -290,7 +288,6 @@ struct sample_fetch {
unsigned int use; /* fetch source (SMP_USE_*) */ unsigned int use; /* fetch source (SMP_USE_*) */
unsigned int val; /* fetch validity (SMP_VAL_*) */ unsigned int val; /* fetch validity (SMP_VAL_*) */
void *private; /* private values. only used by Lua */ void *private; /* private values. only used by Lua */
struct thread_exec_ctx exec_ctx; /* execution context */
}; };
/* sample expression */ /* sample expression */

View file

@ -36,13 +36,9 @@
void sc_update_rx(struct stconn *sc); void sc_update_rx(struct stconn *sc);
void sc_update_tx(struct stconn *sc); void sc_update_tx(struct stconn *sc);
void sc_abort(struct stconn *sc);
void sc_shutdown(struct stconn *sc);
void sc_chk_rcv(struct stconn *sc);
struct task *sc_conn_io_cb(struct task *t, void *ctx, unsigned int state); struct task *sc_conn_io_cb(struct task *t, void *ctx, unsigned int state);
int sc_conn_sync_recv(struct stconn *sc); int sc_conn_sync_recv(struct stconn *sc);
int sc_conn_sync_send(struct stconn *sc); void sc_conn_sync_send(struct stconn *sc);
int sc_applet_sync_recv(struct stconn *sc); int sc_applet_sync_recv(struct stconn *sc);
void sc_applet_sync_send(struct stconn *sc); void sc_applet_sync_send(struct stconn *sc);
@ -78,70 +74,6 @@ static inline struct buffer *sc_ob(const struct stconn *sc)
{ {
return &sc_oc(sc)->buf; return &sc_oc(sc)->buf;
} }
/* The application layer tells the stream connector that it just got the input
* buffer it was waiting for. A read activity is reported. The SC_FL_HAVE_BUFF
* flag is set and held until sc_used_buff() is called to indicate it was
* used.
*/
static inline void sc_have_buff(struct stconn *sc)
{
if (sc->flags & SC_FL_NEED_BUFF) {
sc->flags &= ~SC_FL_NEED_BUFF;
sc->flags |= SC_FL_HAVE_BUFF;
sc_ep_report_read_activity(sc);
}
}
/* The stream connector failed to get an input buffer and is waiting for it.
* It indicates a willingness to deliver data to the buffer that will have to
* be retried. As such, callers will often automatically clear SE_FL_HAVE_NO_DATA
* to be called again as soon as SC_FL_NEED_BUFF is cleared.
*/
static inline void sc_need_buff(struct stconn *sc)
{
sc->flags |= SC_FL_NEED_BUFF;
}
/* The stream connector indicates that it has successfully allocated the buffer
* it was previously waiting for so it drops the SC_FL_HAVE_BUFF bit.
*/
static inline void sc_used_buff(struct stconn *sc)
{
sc->flags &= ~SC_FL_HAVE_BUFF;
}
/* Tell a stream connector some room was made in the input buffer and any
* failed attempt to inject data into it may be tried again. This is usually
* called after a successful transfer of buffer contents to the other side.
* A read activity is reported.
*/
static inline void sc_have_room(struct stconn *sc)
{
if (sc->flags & SC_FL_NEED_ROOM) {
sc->flags &= ~SC_FL_NEED_ROOM;
sc->room_needed = 0;
sc_ep_report_read_activity(sc);
}
}
/* The stream connector announces it failed to put data into the input buffer
* by lack of room. Since it indicates a willingness to deliver data to the
* buffer that will have to be retried. Usually the caller will also clear
* SE_FL_HAVE_NO_DATA to be called again as soon as SC_FL_NEED_ROOM is cleared.
*
* The caller is responsible to specified the amount of free space required to
* progress. It must take care to not exceed the buffer size.
*/
static inline void sc_need_room(struct stconn *sc, ssize_t room_needed)
{
sc->flags |= SC_FL_NEED_ROOM;
BUG_ON_HOT(room_needed > (ssize_t)c_size(sc_ic(sc)));
sc->room_needed = room_needed;
}
/* returns the stream's task associated to this stream connector */ /* returns the stream's task associated to this stream connector */
static inline struct task *sc_strm_task(const struct stconn *sc) static inline struct task *sc_strm_task(const struct stconn *sc)
{ {
@ -364,6 +296,38 @@ static inline int sc_is_recv_allowed(const struct stconn *sc)
return !(sc->flags & (SC_FL_WONT_READ|SC_FL_NEED_BUFF|SC_FL_NEED_ROOM)); return !(sc->flags & (SC_FL_WONT_READ|SC_FL_NEED_BUFF|SC_FL_NEED_ROOM));
} }
/* This is to be used after making some room available in a channel. It will
* return without doing anything if the stream connector's RX path is blocked.
* It will automatically mark the stream connector as busy processing the end
* point in order to avoid useless repeated wakeups.
* It will then call ->chk_rcv() to enable receipt of new data.
*/
static inline void sc_chk_rcv(struct stconn *sc)
{
if (sc_ep_test(sc, SE_FL_APPLET_NEED_CONN) &&
sc_state_in(sc_opposite(sc)->state, SC_SB_RDY|SC_SB_EST|SC_SB_DIS|SC_SB_CLO)) {
sc_ep_clr(sc, SE_FL_APPLET_NEED_CONN);
sc_ep_report_read_activity(sc);
}
if (!sc_is_recv_allowed(sc))
return;
if (!sc_state_in(sc->state, SC_SB_RDY|SC_SB_EST))
return;
sc_ep_set(sc, SE_FL_HAVE_NO_DATA);
if (likely(sc->app_ops->chk_rcv))
sc->app_ops->chk_rcv(sc);
}
/* Calls chk_snd on the endpoint using the data layer */
static inline void sc_chk_snd(struct stconn *sc)
{
if (likely(sc->app_ops->chk_snd))
sc->app_ops->chk_snd(sc);
}
/* Perform a synchronous receive using the right version, depending the endpoing /* Perform a synchronous receive using the right version, depending the endpoing
* is a connection or an applet. * is a connection or an applet.
@ -380,15 +344,10 @@ static inline int sc_sync_recv(struct stconn *sc)
/* Perform a synchronous send using the right version, depending the endpoing is /* Perform a synchronous send using the right version, depending the endpoing is
* a connection or an applet. * a connection or an applet.
*/ */
static inline int sc_sync_send(struct stconn *sc, unsigned cnt) static inline void sc_sync_send(struct stconn *sc)
{ {
if (!sc_ep_test(sc, SE_FL_T_MUX)) if (sc_ep_test(sc, SE_FL_T_MUX))
return 0; sc_conn_sync_send(sc);
if (cnt >= 2 && co_data(sc_oc(sc))) {
task_wakeup(__sc_strm(sc)->task, TASK_WOKEN_MSG);
return 0;
}
return sc_conn_sync_send(sc);
} }
/* Combines both sc_update_rx() and sc_update_tx() at once */ /* Combines both sc_update_rx() and sc_update_tx() at once */
@ -508,10 +467,24 @@ static inline void sc_schedule_abort(struct stconn *sc)
sc->flags |= SC_FL_ABRT_WANTED; sc->flags |= SC_FL_ABRT_WANTED;
} }
/* Abort the SC and notify the endpoint using the data layer */
static inline void sc_abort(struct stconn *sc)
{
if (likely(sc->app_ops->abort))
sc->app_ops->abort(sc);
}
/* Schedule a shutdown for the SC */ /* Schedule a shutdown for the SC */
static inline void sc_schedule_shutdown(struct stconn *sc) static inline void sc_schedule_shutdown(struct stconn *sc)
{ {
sc->flags |= SC_FL_SHUT_WANTED; sc->flags |= SC_FL_SHUT_WANTED;
} }
/* Shutdown the SC and notify the endpoint using the data layer */
static inline void sc_shutdown(struct stconn *sc)
{
if (likely(sc->app_ops->shutdown))
sc->app_ops->shutdown(sc);
}
#endif /* _HAPROXY_SC_STRM_H */ #endif /* _HAPROXY_SC_STRM_H */

View file

@ -286,7 +286,6 @@ struct srv_per_tgroup {
struct queue queue; /* pending connections */ struct queue queue; /* pending connections */
struct server *server; /* pointer to the corresponding server */ struct server *server; /* pointer to the corresponding server */
struct eb32_node lb_node; /* node used for tree-based load balancing */ struct eb32_node lb_node; /* node used for tree-based load balancing */
char *extra_counters_storage; /* storage for extra_counters */
struct server *next_full; /* next server in the temporary full list */ struct server *next_full; /* next server in the temporary full list */
unsigned int last_other_tgrp_served; /* Last other tgrp we dequeued from */ unsigned int last_other_tgrp_served; /* Last other tgrp we dequeued from */
unsigned int self_served; /* Number of connection we dequeued from our own queue */ unsigned int self_served; /* Number of connection we dequeued from our own queue */

View file

@ -29,7 +29,6 @@
#include <haproxy/api.h> #include <haproxy/api.h>
#include <haproxy/applet-t.h> #include <haproxy/applet-t.h>
#include <haproxy/arg-t.h> #include <haproxy/arg-t.h>
#include <haproxy/counters.h>
#include <haproxy/freq_ctr.h> #include <haproxy/freq_ctr.h>
#include <haproxy/proxy-t.h> #include <haproxy/proxy-t.h>
#include <haproxy/resolvers-t.h> #include <haproxy/resolvers-t.h>
@ -56,7 +55,6 @@ int srv_update_addr(struct server *s, void *ip, int ip_sin_family, struct server
struct sample_expr *_parse_srv_expr(char *expr, struct arg_list *args_px, struct sample_expr *_parse_srv_expr(char *expr, struct arg_list *args_px,
const char *file, int linenum, char **err); const char *file, int linenum, char **err);
int server_parse_exprs(struct server *srv, struct proxy *px, char **err); int server_parse_exprs(struct server *srv, struct proxy *px, char **err);
int srv_configure_auto_sni(struct server *srv, int *err_code, char **err);
int server_set_inetaddr(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater, struct buffer *msg); int server_set_inetaddr(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater, struct buffer *msg);
int server_set_inetaddr_warn(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater); int server_set_inetaddr_warn(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater);
void server_get_inetaddr(struct server *s, struct server_inetaddr *inetaddr); void server_get_inetaddr(struct server *s, struct server_inetaddr *inetaddr);
@ -213,7 +211,7 @@ static inline void srv_inc_sess_ctr(struct server *s)
_HA_ATOMIC_INC(&s->counters.shared.tg[tgid - 1]->cum_sess); _HA_ATOMIC_INC(&s->counters.shared.tg[tgid - 1]->cum_sess);
update_freq_ctr(&s->counters.shared.tg[tgid - 1]->sess_per_sec, 1); update_freq_ctr(&s->counters.shared.tg[tgid - 1]->sess_per_sec, 1);
} }
COUNTERS_UPDATE_MAX(&s->counters.sps_max, HA_ATOMIC_UPDATE_MAX(&s->counters.sps_max,
update_freq_ctr(&s->counters._sess_per_sec, 1)); update_freq_ctr(&s->counters._sess_per_sec, 1));
} }
@ -351,26 +349,28 @@ static inline int srv_is_transparent(const struct server *srv)
(srv->flags & SRV_F_MAPPORTS); (srv->flags & SRV_F_MAPPORTS);
} }
/* Detach <srv> server from its parent proxy list. /* Detach server from proxy list. It is supported to call this
* * even if the server is not yet in the list
* Must be called under thread isolation. * Must be called under thread isolation or when it is safe to assume
* that the parent proxy doesn't is not skimming through the server list
*/ */
static inline void srv_detach(struct server *srv) static inline void srv_detach(struct server *srv)
{ {
struct proxy *px = srv->proxy; struct proxy *px = srv->proxy;
if (px->srv == srv)
px->srv = srv->next;
else {
struct server *prev; struct server *prev;
if (px->srv == srv) {
px->srv = srv->next;
}
else {
for (prev = px->srv; prev && prev->next != srv; prev = prev->next) for (prev = px->srv; prev && prev->next != srv; prev = prev->next)
; ;
BUG_ON(!prev); /* Server instance not found in proxy list ? */
BUG_ON(!prev);
prev->next = srv->next; prev->next = srv->next;
} }
/* reset the proxy's ready_srv if it was this one */
/* Reset the proxy's ready_srv if it was this one. */
HA_ATOMIC_CAS(&px->ready_srv, &srv, NULL); HA_ATOMIC_CAS(&px->ready_srv, &srv, NULL);
} }

View file

@ -73,14 +73,6 @@ struct ckch_conf {
char *id; char *id;
char **domains; char **domains;
} acme; } acme;
struct {
struct {
char *type; /* "RSA" or "ECSDA" */
int bits; /* bits for RSA */
char *curves; /* NID of curves for ECDSA*/
} key;
int on;
} gencrt;
}; };
/* /*

View file

@ -80,7 +80,6 @@ void ssl_store_delete_cafile_entry(struct cafile_entry *ca_e);
int ssl_store_load_ca_from_buf(struct cafile_entry *ca_e, char *cert_buf, int append); int ssl_store_load_ca_from_buf(struct cafile_entry *ca_e, char *cert_buf, int append);
int ssl_store_load_locations_file(char *path, int create_if_none, enum cafile_type type); int ssl_store_load_locations_file(char *path, int create_if_none, enum cafile_type type);
int __ssl_store_load_locations_file(char *path, int create_if_none, enum cafile_type type, int shuterror); int __ssl_store_load_locations_file(char *path, int create_if_none, enum cafile_type type, int shuterror);
const char *ha_default_cert_dir();
extern struct cert_exts cert_exts[]; extern struct cert_exts cert_exts[];
extern int (*ssl_commit_crlfile_cb)(const char *path, X509_STORE *ctx, char **err); extern int (*ssl_commit_crlfile_cb)(const char *path, X509_STORE *ctx, char **err);

View file

@ -28,7 +28,6 @@
/* crt-list entry functions */ /* crt-list entry functions */
void ssl_sock_free_ssl_conf(struct ssl_bind_conf *conf); void ssl_sock_free_ssl_conf(struct ssl_bind_conf *conf);
struct ssl_bind_conf *crtlist_dup_ssl_conf(struct ssl_bind_conf *src);
char **crtlist_dup_filters(char **args, int fcount); char **crtlist_dup_filters(char **args, int fcount);
void crtlist_free_filters(char **args); void crtlist_free_filters(char **args);
void crtlist_entry_free(struct crtlist_entry *entry); void crtlist_entry_free(struct crtlist_entry *entry);

View file

@ -32,8 +32,6 @@ int ssl_sock_set_generated_cert(SSL_CTX *ctx, unsigned int key, struct bind_conf
unsigned int ssl_sock_generated_cert_key(const void *data, size_t len); unsigned int ssl_sock_generated_cert_key(const void *data, size_t len);
int ssl_sock_gencert_load_ca(struct bind_conf *bind_conf); int ssl_sock_gencert_load_ca(struct bind_conf *bind_conf);
void ssl_sock_gencert_free_ca(struct bind_conf *bind_conf); void ssl_sock_gencert_free_ca(struct bind_conf *bind_conf);
EVP_PKEY *ssl_gen_EVP_PKEY(int keytype, int curves, int bits, char **errmsg);
X509 *ssl_gen_x509(EVP_PKEY *pkey);
#endif /* USE_OPENSSL */ #endif /* USE_OPENSSL */
#endif /* _HAPROXY_SSL_GENCERT_H */ #endif /* _HAPROXY_SSL_GENCERT_H */

View file

@ -25,13 +25,12 @@
#include <haproxy/connection.h> #include <haproxy/connection.h>
#include <haproxy/counters.h>
#include <haproxy/openssl-compat.h> #include <haproxy/openssl-compat.h>
#include <haproxy/pool-t.h> #include <haproxy/pool-t.h>
#include <haproxy/proxy-t.h> #include <haproxy/proxy-t.h>
#include <haproxy/quic_conn-t.h> #include <haproxy/quic_conn-t.h>
#include <haproxy/ssl_sock-t.h> #include <haproxy/ssl_sock-t.h>
#include <haproxy/stats-t.h> #include <haproxy/stats.h>
#include <haproxy/thread.h> #include <haproxy/thread.h>
extern struct list tlskeys_reference; extern struct list tlskeys_reference;
@ -74,7 +73,7 @@ int ssl_sock_get_alpn(const struct connection *conn, void *xprt_ctx,
const char **str, int *len); const char **str, int *len);
int ssl_bio_and_sess_init(struct connection *conn, SSL_CTX *ssl_ctx, int ssl_bio_and_sess_init(struct connection *conn, SSL_CTX *ssl_ctx,
SSL **ssl, BIO **bio, BIO_METHOD *bio_meth, void *ctx); SSL **ssl, BIO **bio, BIO_METHOD *bio_meth, void *ctx);
void ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv); int ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv);
const char *ssl_sock_get_sni(struct connection *conn); const char *ssl_sock_get_sni(struct connection *conn);
const char *ssl_sock_get_cert_sig(struct connection *conn); const char *ssl_sock_get_cert_sig(struct connection *conn);
const char *ssl_sock_get_cipher_name(struct connection *conn); const char *ssl_sock_get_cipher_name(struct connection *conn);

View file

@ -34,10 +34,10 @@ int cert_get_pkey_algo(X509 *crt, struct buffer *out);
int ssl_sock_get_serial(X509 *crt, struct buffer *out); int ssl_sock_get_serial(X509 *crt, struct buffer *out);
int ssl_sock_crt2der(X509 *crt, struct buffer *out); int ssl_sock_crt2der(X509 *crt, struct buffer *out);
int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out); int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out);
int ssl_sock_get_dn_entry(__X509_NAME_CONST__ X509_NAME *a, const struct buffer *entry, int pos, int ssl_sock_get_dn_entry(X509_NAME *a, const struct buffer *entry, int pos,
struct buffer *out); struct buffer *out);
int ssl_sock_get_dn_formatted(__X509_NAME_CONST__ X509_NAME *a, const struct buffer *format, struct buffer *out); int ssl_sock_get_dn_formatted(X509_NAME *a, const struct buffer *format, struct buffer *out);
int ssl_sock_get_dn_oneline(__X509_NAME_CONST__ X509_NAME *a, struct buffer *out); int ssl_sock_get_dn_oneline(X509_NAME *a, struct buffer *out);
X509* ssl_sock_get_peer_certificate(SSL *ssl); X509* ssl_sock_get_peer_certificate(SSL *ssl);
X509* ssl_sock_get_verified_chain_root(SSL *ssl); X509* ssl_sock_get_verified_chain_root(SSL *ssl);
unsigned int openssl_version_parser(const char *version); unsigned int openssl_version_parser(const char *version);

View file

@ -36,7 +36,7 @@ struct shm_stats_file_hdr {
/* 2 bytes hole */ /* 2 bytes hole */
uint global_now_ms; /* global monotonic date (ms) common to all processes using the shm */ uint global_now_ms; /* global monotonic date (ms) common to all processes using the shm */
ullong global_now_ns; /* global monotonic date (ns) common to all processes using the shm */ ullong global_now_ns; /* global monotonic date (ns) common to all processes using the shm */
ALWAYS_PAD(8); // 8 bytes hole llong now_offset; /* offset applied to global monotonic date on startup */
/* each process uses one slot and is identified using its pid, max 64 in order /* each process uses one slot and is identified using its pid, max 64 in order
* to be able to use bitmask to refer to a process and then look its pid in the * to be able to use bitmask to refer to a process and then look its pid in the
* "slots.pid" map * "slots.pid" map
@ -47,7 +47,7 @@ struct shm_stats_file_hdr {
*/ */
struct { struct {
pid_t pid; pid_t pid;
uint heartbeat; // last activity of this process + heartbeat timeout, in ticks int heartbeat; // last activity of this process + heartbeat timeout, in ticks
} slots[64]; } slots[64];
int objects; /* actual number of objects stored in the shm */ int objects; /* actual number of objects stored in the shm */
int objects_slots; /* total available objects slots unless map is resized */ int objects_slots; /* total available objects slots unless map is resized */

View file

@ -25,7 +25,6 @@
#include <import/ebtree-t.h> #include <import/ebtree-t.h>
#include <haproxy/api-t.h> #include <haproxy/api-t.h>
#include <haproxy/buf-t.h> #include <haproxy/buf-t.h>
#include <haproxy/counters-t.h>
/* Flags for applet.ctx.stats.flags */ /* Flags for applet.ctx.stats.flags */
#define STAT_F_FMT_HTML 0x00000001 /* dump the stats in HTML format */ #define STAT_F_FMT_HTML 0x00000001 /* dump the stats in HTML format */
@ -516,13 +515,23 @@ struct field {
} u; } u;
}; };
enum counters_type {
COUNTERS_FE = 0,
COUNTERS_BE,
COUNTERS_SV,
COUNTERS_LI,
COUNTERS_RSLV,
COUNTERS_OFF_END
};
/* Entity used to generate statistics on an HAProxy component */ /* Entity used to generate statistics on an HAProxy component */
struct stats_module { struct stats_module {
struct list list; struct list list;
const char *name; const char *name;
/* function used to generate the stats module using counters provided through data parameter */ /* functor used to generate the stats module using counters provided through data parameter */
int (*fill_stats)(struct stats_module *, struct extra_counters *, struct field *, unsigned int *); int (*fill_stats)(void *data, struct field *, unsigned int *);
struct stat_col *stats; /* statistics provided by the module */ struct stat_col *stats; /* statistics provided by the module */
void *counters; /* initial values of allocated counters */ void *counters; /* initial values of allocated counters */
@ -534,6 +543,12 @@ struct stats_module {
char clearable; /* reset on a clear counters */ char clearable; /* reset on a clear counters */
}; };
struct extra_counters {
char *data; /* heap containing counters allocated in a linear fashion */
size_t size; /* size of allocated data */
enum counters_type type; /* type of object containing the counters */
};
/* stats_domain is used in a flag as a 1 byte field */ /* stats_domain is used in a flag as a 1 byte field */
enum stats_domain { enum stats_domain {
STATS_DOMAIN_PROXY = 0, STATS_DOMAIN_PROXY = 0,
@ -578,9 +593,58 @@ struct show_stat_ctx {
int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */ int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */
int st_code; /* the status code returned by an action */ int st_code; /* the status code returned by an action */
struct buffer chunk; /* temporary buffer which holds a single-line output */ struct buffer chunk; /* temporary buffer which holds a single-line output */
struct watcher px_watch; /* watcher to automatically update obj1 on backend deletion */
struct watcher srv_watch; /* watcher to automatically update obj2 on server deletion */ struct watcher srv_watch; /* watcher to automatically update obj2 on server deletion */
enum stat_state state; /* phase of output production */ enum stat_state state; /* phase of output production */
}; };
extern THREAD_LOCAL void *trash_counters;
#define EXTRA_COUNTERS(name) \
struct extra_counters *name
#define EXTRA_COUNTERS_GET(counters, mod) \
(likely(counters) ? \
((void *)((counters)->data + (mod)->counters_off[(counters)->type])) : \
(trash_counters))
#define EXTRA_COUNTERS_REGISTER(counters, ctype, alloc_failed_label) \
do { \
typeof(*counters) _ctr; \
_ctr = calloc(1, sizeof(*_ctr)); \
if (!_ctr) \
goto alloc_failed_label; \
_ctr->type = (ctype); \
*(counters) = _ctr; \
} while (0)
#define EXTRA_COUNTERS_ADD(mod, counters, new_counters, csize) \
do { \
typeof(counters) _ctr = (counters); \
(mod)->counters_off[_ctr->type] = _ctr->size; \
_ctr->size += (csize); \
} while (0)
#define EXTRA_COUNTERS_ALLOC(counters, alloc_failed_label) \
do { \
typeof(counters) _ctr = (counters); \
_ctr->data = malloc((_ctr)->size); \
if (!_ctr->data) \
goto alloc_failed_label; \
} while (0)
#define EXTRA_COUNTERS_INIT(counters, mod, init_counters, init_counters_size) \
do { \
typeof(counters) _ctr = (counters); \
memcpy(_ctr->data + mod->counters_off[_ctr->type], \
(init_counters), (init_counters_size)); \
} while (0)
#define EXTRA_COUNTERS_FREE(counters) \
do { \
if (counters) { \
free((counters)->data); \
free(counters); \
} \
} while (0)
#endif /* _HAPROXY_STATS_T_H */ #endif /* _HAPROXY_STATS_T_H */

View file

@ -24,7 +24,6 @@
#define _HAPROXY_STATS_H #define _HAPROXY_STATS_H
#include <haproxy/api.h> #include <haproxy/api.h>
#include <haproxy/counters.h>
#include <haproxy/listener-t.h> #include <haproxy/listener-t.h>
#include <haproxy/stats-t.h> #include <haproxy/stats-t.h>
#include <haproxy/tools-t.h> #include <haproxy/tools-t.h>
@ -168,8 +167,7 @@ static inline enum stats_domain_px_cap stats_px_get_cap(uint32_t domain)
} }
int stats_allocate_proxy_counters_internal(struct extra_counters **counters, int stats_allocate_proxy_counters_internal(struct extra_counters **counters,
int type, int px_cap, int type, int px_cap);
char **storage, size_t step);
int stats_allocate_proxy_counters(struct proxy *px); int stats_allocate_proxy_counters(struct proxy *px);
void stats_register_module(struct stats_module *m); void stats_register_module(struct stats_module *m);

View file

@ -224,7 +224,7 @@ static forceinline char *sc_show_flags(char *buf, size_t len, const char *delim,
_(SC_FL_NEED_BUFF, _(SC_FL_NEED_ROOM, _(SC_FL_NEED_BUFF, _(SC_FL_NEED_ROOM,
_(SC_FL_RCV_ONCE, _(SC_FL_SND_ASAP, _(SC_FL_SND_NEVERWAIT, _(SC_FL_SND_EXP_MORE, _(SC_FL_RCV_ONCE, _(SC_FL_SND_ASAP, _(SC_FL_SND_NEVERWAIT, _(SC_FL_SND_EXP_MORE,
_(SC_FL_ABRT_WANTED, _(SC_FL_SHUT_WANTED, _(SC_FL_ABRT_DONE, _(SC_FL_SHUT_DONE, _(SC_FL_ABRT_WANTED, _(SC_FL_SHUT_WANTED, _(SC_FL_ABRT_DONE, _(SC_FL_SHUT_DONE,
_(SC_FL_EOS, _(SC_FL_HAVE_BUFF, _(SC_FL_NO_FASTFWD))))))))))))))))))))); _(SC_FL_EOS, _(SC_FL_HAVE_BUFF))))))))))))))))))));
/* epilogue */ /* epilogue */
_(~0U); _(~0U);
return buf; return buf;
@ -349,6 +349,19 @@ struct sedesc {
unsigned long long kop; /* Known outgoing payload length (see above) */ unsigned long long kop; /* Known outgoing payload length (see above) */
}; };
/* sc_app_ops describes the application layer's operations and notification
* callbacks when I/O activity is reported and to use to perform shutr/shutw.
* There are very few combinations in practice (strm/chk <-> none/mux/applet).
*/
struct sc_app_ops {
void (*chk_rcv)(struct stconn *); /* chk_rcv function, may not be null */
void (*chk_snd)(struct stconn *); /* chk_snd function, may not be null */
void (*abort)(struct stconn *); /* abort function, may not be null */
void (*shutdown)(struct stconn *); /* shutdown function, may not be null */
int (*wake)(struct stconn *); /* data-layer callback to report activity */
char name[8]; /* data layer name, zero-terminated */
};
/* /*
* This structure describes the elements of a connection relevant to a stream * This structure describes the elements of a connection relevant to a stream
*/ */
@ -370,6 +383,7 @@ struct stconn {
struct wait_event wait_event; /* We're in a wait list */ struct wait_event wait_event; /* We're in a wait list */
struct sedesc *sedesc; /* points to the stream endpoint descriptor */ struct sedesc *sedesc; /* points to the stream endpoint descriptor */
enum obj_type *app; /* points to the applicative point (stream or check) */ enum obj_type *app; /* points to the applicative point (stream or check) */
const struct sc_app_ops *app_ops; /* general operations used at the app layer */
struct sockaddr_storage *src; /* source address (pool), when known, otherwise NULL */ struct sockaddr_storage *src; /* source address (pool), when known, otherwise NULL */
struct sockaddr_storage *dst; /* destination address (pool), when known, otherwise NULL */ struct sockaddr_storage *dst; /* destination address (pool), when known, otherwise NULL */
}; };

View file

@ -24,7 +24,6 @@
#include <haproxy/api.h> #include <haproxy/api.h>
#include <haproxy/connection.h> #include <haproxy/connection.h>
#include <haproxy/hstream-t.h>
#include <haproxy/htx-t.h> #include <haproxy/htx-t.h>
#include <haproxy/obj_type.h> #include <haproxy/obj_type.h>
#include <haproxy/stconn-t.h> #include <haproxy/stconn-t.h>
@ -46,19 +45,15 @@ void se_shutdown(struct sedesc *sedesc, enum se_shut_mode mode);
struct stconn *sc_new_from_endp(struct sedesc *sedesc, struct session *sess, struct buffer *input); struct stconn *sc_new_from_endp(struct sedesc *sedesc, struct session *sess, struct buffer *input);
struct stconn *sc_new_from_strm(struct stream *strm, unsigned int flags); struct stconn *sc_new_from_strm(struct stream *strm, unsigned int flags);
struct stconn *sc_new_from_check(struct check *check, unsigned int flags); struct stconn *sc_new_from_check(struct check *check, unsigned int flags);
struct stconn *sc_new_from_haterm(struct sedesc *sd, struct session *sess, struct buffer *input);
void sc_free(struct stconn *sc); void sc_free(struct stconn *sc);
int sc_attach_mux(struct stconn *sc, void *target, void *ctx); int sc_attach_mux(struct stconn *sc, void *target, void *ctx);
int sc_attach_strm(struct stconn *sc, struct stream *strm); int sc_attach_strm(struct stconn *sc, struct stream *strm);
int sc_attach_hstream(struct stconn *sc, struct hstream *hs);
void sc_destroy(struct stconn *sc); void sc_destroy(struct stconn *sc);
int sc_reset_endp(struct stconn *sc); int sc_reset_endp(struct stconn *sc);
struct appctx *sc_applet_create(struct stconn *sc, struct applet *app); struct appctx *sc_applet_create(struct stconn *sc, struct applet *app);
int sc_applet_process(struct stconn *sc);
int sc_conn_process(struct stconn *sc);
void sc_conn_prepare_endp_upgrade(struct stconn *sc); void sc_conn_prepare_endp_upgrade(struct stconn *sc);
void sc_conn_abort_endp_upgrade(struct stconn *sc); void sc_conn_abort_endp_upgrade(struct stconn *sc);
@ -336,19 +331,14 @@ static inline struct check *sc_check(const struct stconn *sc)
return NULL; return NULL;
} }
/* Returns the haterm stream from a sc if the application is a /* Returns the name of the application layer's name for the stconn,
* haterm stream. Otherwise NULL is returned. __sc_hstream() returns the haterm * or "NONE" when none is attached.
* stream without any control while sc_hstream() check the application type.
*/ */
static inline struct hstream *__sc_hstream(const struct stconn *sc) static inline const char *sc_get_data_name(const struct stconn *sc)
{ {
return __objt_hstream(sc->app); if (!sc->app_ops)
} return "NONE";
static inline struct hstream *sc_hstream(const struct stconn *sc) return sc->app_ops->name;
{
if (obj_type(sc->app) == OBJ_TYPE_HATERM)
return __objt_hstream(sc->app);
return NULL;
} }
/* Returns non-zero if the stream connector's Rx path is blocked because of /* Returns non-zero if the stream connector's Rx path is blocked because of
@ -407,6 +397,67 @@ static inline void se_need_remote_conn(struct sedesc *se)
se_fl_set(se, SE_FL_APPLET_NEED_CONN); se_fl_set(se, SE_FL_APPLET_NEED_CONN);
} }
/* The application layer tells the stream connector that it just got the input
* buffer it was waiting for. A read activity is reported. The SC_FL_HAVE_BUFF
* flag is set and held until sc_used_buff() is called to indicate it was
* used.
*/
static inline void sc_have_buff(struct stconn *sc)
{
if (sc->flags & SC_FL_NEED_BUFF) {
sc->flags &= ~SC_FL_NEED_BUFF;
sc->flags |= SC_FL_HAVE_BUFF;
sc_ep_report_read_activity(sc);
}
}
/* The stream connector failed to get an input buffer and is waiting for it.
* It indicates a willingness to deliver data to the buffer that will have to
* be retried. As such, callers will often automatically clear SE_FL_HAVE_NO_DATA
* to be called again as soon as SC_FL_NEED_BUFF is cleared.
*/
static inline void sc_need_buff(struct stconn *sc)
{
sc->flags |= SC_FL_NEED_BUFF;
}
/* The stream connector indicates that it has successfully allocated the buffer
* it was previously waiting for so it drops the SC_FL_HAVE_BUFF bit.
*/
static inline void sc_used_buff(struct stconn *sc)
{
sc->flags &= ~SC_FL_HAVE_BUFF;
}
/* Tell a stream connector some room was made in the input buffer and any
* failed attempt to inject data into it may be tried again. This is usually
* called after a successful transfer of buffer contents to the other side.
* A read activity is reported.
*/
static inline void sc_have_room(struct stconn *sc)
{
if (sc->flags & SC_FL_NEED_ROOM) {
sc->flags &= ~SC_FL_NEED_ROOM;
sc->room_needed = 0;
sc_ep_report_read_activity(sc);
}
}
/* The stream connector announces it failed to put data into the input buffer
* by lack of room. Since it indicates a willingness to deliver data to the
* buffer that will have to be retried. Usually the caller will also clear
* SE_FL_HAVE_NO_DATA to be called again as soon as SC_FL_NEED_ROOM is cleared.
*
* The caller is responsible to specified the amount of free space required to
* progress. It must take care to not exceed the buffer size.
*/
static inline void sc_need_room(struct stconn *sc, ssize_t room_needed)
{
sc->flags |= SC_FL_NEED_ROOM;
BUG_ON_HOT(room_needed > (ssize_t)global.tune.bufsize);
sc->room_needed = room_needed;
}
/* The stream endpoint indicates that it's ready to consume data from the /* The stream endpoint indicates that it's ready to consume data from the
* stream's output buffer. Report a send activity if the SE is unblocked. * stream's output buffer. Report a send activity if the SE is unblocked.
*/ */
@ -452,7 +503,7 @@ static inline size_t se_nego_ff(struct sedesc *se, struct buffer *input, size_t
goto end; goto end;
} }
ret = CALL_MUX_WITH_RET(mux, nego_fastfwd(se->sc, input, count, flags)); ret = mux->nego_fastfwd(se->sc, input, count, flags);
if (se->iobuf.flags & IOBUF_FL_FF_BLOCKED) { if (se->iobuf.flags & IOBUF_FL_FF_BLOCKED) {
sc_ep_report_blocked_send(se->sc, 0); sc_ep_report_blocked_send(se->sc, 0);
@ -485,7 +536,7 @@ static inline size_t se_done_ff(struct sedesc *se)
size_t to_send = se_ff_data(se); size_t to_send = se_ff_data(se);
BUG_ON(!mux->done_fastfwd); BUG_ON(!mux->done_fastfwd);
ret = CALL_MUX_WITH_RET(mux, done_fastfwd(se->sc)); ret = mux->done_fastfwd(se->sc);
if (ret) { if (ret) {
/* Something was forwarded, unblock the zero-copy forwarding. /* Something was forwarded, unblock the zero-copy forwarding.
* If all data was sent, report and send activity. * If all data was sent, report and send activity.
@ -517,7 +568,7 @@ static inline size_t se_done_ff(struct sedesc *se)
} }
} }
} }
se->sc->bytes_out += ret;
return ret; return ret;
} }

View file

@ -180,7 +180,6 @@ enum {
STRM_EVT_SHUT_SRV_DOWN = 0x00000004, /* Must be shut because the selected server became available */ STRM_EVT_SHUT_SRV_DOWN = 0x00000004, /* Must be shut because the selected server became available */
STRM_EVT_SHUT_SRV_UP = 0x00000008, /* Must be shut because a preferred server became available */ STRM_EVT_SHUT_SRV_UP = 0x00000008, /* Must be shut because a preferred server became available */
STRM_EVT_KILLED = 0x00000010, /* Must be shut for external reason */ STRM_EVT_KILLED = 0x00000010, /* Must be shut for external reason */
STRM_EVT_RES = 0x00000020, /* A requested resource is available (a buffer, a conn_slot...) */
}; };
/* This function is used to report flags in debugging tools. Please reflect /* This function is used to report flags in debugging tools. Please reflect
@ -321,10 +320,7 @@ struct stream {
struct list *current_rule_list; /* this is used to store the current executed rule list. */ struct list *current_rule_list; /* this is used to store the current executed rule list. */
void *current_rule; /* this is used to store the current rule to be resumed. */ void *current_rule; /* this is used to store the current rule to be resumed. */
int rules_exp; /* expiration date for current rules execution */ int rules_exp; /* expiration date for current rules execution */
int tunnel_timeout; /* per-stream tunnel timeout, set by set-timeout action */ int tunnel_timeout;
int connect_timeout; /* per-stream connect timeout, set by set-timeout action */
int queue_timeout; /* per-stream queue timeout, set by set-timeout action */
int tarpit_timeout; /* per-stream tarpit timeout, set by set-timeout action */
struct { struct {
void *ptr; /* Pointer on the entity (def: NULL) */ void *ptr; /* Pointer on the entity (def: NULL) */

View file

@ -59,7 +59,7 @@ extern struct pool_head *pool_head_uniqueid;
extern struct data_cb sess_conn_cb; extern struct data_cb sess_conn_cb;
void *stream_new(struct session *sess, struct stconn *sc, struct buffer *input); struct stream *stream_new(struct session *sess, struct stconn *sc, struct buffer *input);
void stream_free(struct stream *s); void stream_free(struct stream *s);
int stream_upgrade_from_sc(struct stconn *sc, struct buffer *input); int stream_upgrade_from_sc(struct stconn *sc, struct buffer *input);
int stream_set_http_mode(struct stream *s, const struct mux_proto_list *mux_proto); int stream_set_http_mode(struct stream *s, const struct mux_proto_list *mux_proto);
@ -412,7 +412,6 @@ static inline void stream_shutdown(struct stream *s, int why)
static inline unsigned int stream_map_task_state(unsigned int state) static inline unsigned int stream_map_task_state(unsigned int state)
{ {
return ((state & TASK_WOKEN_TIMER) ? STRM_EVT_TIMER : 0) | return ((state & TASK_WOKEN_TIMER) ? STRM_EVT_TIMER : 0) |
((state & TASK_WOKEN_RES) ? STRM_EVT_RES : 0) |
((state & TASK_WOKEN_MSG) ? STRM_EVT_MSG : 0) | ((state & TASK_WOKEN_MSG) ? STRM_EVT_MSG : 0) |
((state & TASK_F_UEVT1) ? STRM_EVT_SHUT_SRV_DOWN : 0) | ((state & TASK_F_UEVT1) ? STRM_EVT_SHUT_SRV_DOWN : 0) |
((state & TASK_F_UEVT3) ? STRM_EVT_SHUT_SRV_UP : 0) | ((state & TASK_F_UEVT3) ? STRM_EVT_SHUT_SRV_UP : 0) |

View file

@ -130,6 +130,7 @@ struct notification {
* on return. * on return.
*/ */
#define TASK_COMMON \ #define TASK_COMMON \
struct { \
unsigned int state; /* task state : bitfield of TASK_ */ \ unsigned int state; /* task state : bitfield of TASK_ */ \
int tid; /* tid of task/tasklet. <0 = local for tasklet, unbound for task */ \ int tid; /* tid of task/tasklet. <0 = local for tasklet, unbound for task */ \
struct task *(*process)(struct task *t, void *ctx, unsigned int state); /* the function which processes the task */ \ struct task *(*process)(struct task *t, void *ctx, unsigned int state); /* the function which processes the task */ \
@ -138,14 +139,11 @@ struct notification {
uint32_t wake_date; /* date of the last task wakeup */ \ uint32_t wake_date; /* date of the last task wakeup */ \
unsigned int calls; /* number of times process was called */ \ unsigned int calls; /* number of times process was called */ \
TASK_DEBUG_STORAGE; \ TASK_DEBUG_STORAGE; \
short last_run; /* 16-bit now_ms of last run */ }
/* a 16- or 48-bit hole remains here and is used by task */
/* The base for all tasks */ /* The base for all tasks */
struct task { struct task {
TASK_COMMON; /* must be at the beginning! */ TASK_COMMON; /* must be at the beginning! */
short nice; /* task prio from -1024 to +1024 */
int expire; /* next expiration date for this task, in ticks */
struct eb32_node rq; /* ebtree node used to hold the task in the run queue */ struct eb32_node rq; /* ebtree node used to hold the task in the run queue */
/* WARNING: the struct task is often aliased as a struct tasklet when /* WARNING: the struct task is often aliased as a struct tasklet when
* it is NOT in the run queue. The tasklet has its struct list here * it is NOT in the run queue. The tasklet has its struct list here
@ -153,12 +151,14 @@ struct task {
* ever reorder these fields without taking this into account! * ever reorder these fields without taking this into account!
*/ */
struct eb32_node wq; /* ebtree node used to hold the task in the wait queue */ struct eb32_node wq; /* ebtree node used to hold the task in the wait queue */
int expire; /* next expiration date for this task, in ticks */
short nice; /* task prio from -1024 to +1024 */
/* 16-bit hole here */
}; };
/* lightweight tasks, without priority, mainly used for I/Os */ /* lightweight tasks, without priority, mainly used for I/Os */
struct tasklet { struct tasklet {
TASK_COMMON; /* must be at the beginning! */ TASK_COMMON; /* must be at the beginning! */
/* 48-bit hole here */
struct list list; struct list list;
/* WARNING: the struct task is often aliased as a struct tasklet when /* WARNING: the struct task is often aliased as a struct tasklet when
* it is not in the run queue. The task has its struct rq here where * it is not in the run queue. The task has its struct rq here where

View file

@ -121,7 +121,6 @@ enum tcpcheck_rule_type {
/* Unused 0x000000A0..0x00000FF0 (reserved for future proto) */ /* Unused 0x000000A0..0x00000FF0 (reserved for future proto) */
#define TCPCHK_RULES_TCP_CHK 0x00000FF0 #define TCPCHK_RULES_TCP_CHK 0x00000FF0
#define TCPCHK_RULES_PROTO_CHK 0x00000FF0 /* Mask to cover protocol check */ #define TCPCHK_RULES_PROTO_CHK 0x00000FF0 /* Mask to cover protocol check */
#define TCPCHK_RULES_MAY_USE_SBUF 0x00001000 /* checks may try to use small buffers if possible for the request */
struct check; struct check;
struct tcpcheck_connect { struct tcpcheck_connect {

View file

@ -217,7 +217,6 @@ enum lock_label {
QC_CID_LOCK, QC_CID_LOCK,
CACHE_LOCK, CACHE_LOCK,
GUID_LOCK, GUID_LOCK,
PROXIES_DEL_LOCK,
OTHER_LOCK, OTHER_LOCK,
/* WT: make sure never to use these ones outside of development, /* WT: make sure never to use these ones outside of development,
* we need them for lock profiling! * we need them for lock profiling!

View file

@ -362,19 +362,15 @@ static inline unsigned long thread_isolated()
extern uint64_t now_mono_time(void); \ extern uint64_t now_mono_time(void); \
if (_LK_ != _LK_UN) { \ if (_LK_ != _LK_UN) { \
th_ctx->lock_level += bal; \ th_ctx->lock_level += bal; \
if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \ if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) \
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) \
lock_start = now_mono_time(); \ lock_start = now_mono_time(); \
} \ } \
(void)(expr); \ (void)(expr); \
if (_LK_ == _LK_UN) { \ if (_LK_ == _LK_UN) { \
th_ctx->lock_level += bal; \ th_ctx->lock_level += bal; \
if (th_ctx->lock_level == 0 &&\ if (th_ctx->lock_level == 0 && unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) \
unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) \
th_ctx->locked_total += now_mono_time() - th_ctx->lock_start_date; \ th_ctx->locked_total += now_mono_time() - th_ctx->lock_start_date; \
} else if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \ } else if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) { \
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) { \
uint64_t now = now_mono_time(); \ uint64_t now = now_mono_time(); \
if (lock_start) \ if (lock_start) \
th_ctx->lock_wait_total += now - lock_start; \ th_ctx->lock_wait_total += now - lock_start; \
@ -388,8 +384,7 @@ static inline unsigned long thread_isolated()
typeof(expr) _expr = (expr); \ typeof(expr) _expr = (expr); \
if (_expr == 0) { \ if (_expr == 0) { \
th_ctx->lock_level += bal; \ th_ctx->lock_level += bal; \
if (unlikely((th_ctx->flags & (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \ if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) { \
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) { \
if (_LK_ == _LK_UN && th_ctx->lock_level == 0) \ if (_LK_ == _LK_UN && th_ctx->lock_level == 0) \
th_ctx->locked_total += now_mono_time() - th_ctx->lock_start_date; \ th_ctx->locked_total += now_mono_time() - th_ctx->lock_start_date; \
else if (_LK_ != _LK_UN && th_ctx->lock_level == 1) \ else if (_LK_ != _LK_UN && th_ctx->lock_level == 1) \

Some files were not shown because too many files have changed in this diff Show more