diff --git a/CMakeLists.txt b/CMakeLists.txt index c8e933345d54c4739ae1c6ae670c3bc7790f7b2b..0a206c37a8c68b1738dfaa43b358319f02d38bcf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,7 @@ option(LWS_WITH_GCOV "Build with gcc gcov coverage instrumentation" OFF) option(LWS_WITH_EXPORT_LWSTARGETS "Export libwebsockets CMake targets. Disable if they conflict with an outer cmake project." ON) option(LWS_REPRODUCIBLE "Build libwebsockets reproducible. It removes the build user and hostname from the build" ON) option(LWS_WITH_MINIMAL_EXAMPLES "Also build the normally standalone minimal examples, for QA" OFF) +option(LWS_WITH_LWSAC "lwsac Chunk Allocation api" ON) # # End of user settings # @@ -149,6 +150,10 @@ if (WIN32 OR LWS_WITH_ESP32) set(LWS_UNIX_SOCK 0) endif() +if (LWS_WITH_ESP32) + set(LWS_WITH_LWSAC 0) +endif() + project(libwebsockets C) set(PACKAGE "libwebsockets") @@ -875,6 +880,12 @@ if (LWS_WITH_PEER_LIMITS) lib/misc/peer-limits.c) endif() +if (LWS_WITH_LWSAC) + list(APPEND SOURCES + lib/misc/lwsac/lwsac.c + lib/misc/lwsac/cached-file.c) +endif() + if (NOT LWS_WITHOUT_CLIENT) list(APPEND SOURCES lib/core/connect.c diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index 6c6d1e3ba4dbd5ab426abccbfc092e2af03a3a53..343ec95cb7daa6e34bc138657187bc3310741ae8 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -15,6 +15,8 @@ #cmakedefine LWS_ROLE_CGI #cmakedefine LWS_ROLE_DBUS +#cmakedefine LWS_WITH_LWSAC + /* Define to 1 to use wolfSSL/CyaSSL as a replacement for OpenSSL. * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ #cmakedefine USE_WOLFSSL diff --git a/doc-assets/lwsac.svg b/doc-assets/lwsac.svg new file mode 100644 index 0000000000000000000000000000000000000000..1a8ba874d6ad2ca7680fe30673fbfaaec48327ed --- /dev/null +++ b/doc-assets/lwsac.svg @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="187.8mm" height="80.752mm" version="1.1" viewBox="0 0 187.79663 80.752144" xmlns="http://www.w3.org/2000/svg"> + <defs> + <filter id="a" x="-.014418" y="-.034864" width="1.0288" height="1.0697" color-interpolation-filters="sRGB"> + <feGaussianBlur stdDeviation="1.5466839"/> + </filter> + </defs> + <g transform="translate(-161.61 156.88)"> + <g> + <g stroke="#666" stroke-linejoin="round"> + <rect transform="matrix(.709 0 0 .709 167.83 -486.38)" x="-5.0609" y="468.46" width="257.45" height="106.47" ry="0" filter="url(#a)" stroke-width=".24551"/> + <rect x="163.71" y="-154.85" width="182.53" height="75.489" ry="0" fill="#f2f2f2" stroke-width=".17406"/> + <rect x="171.7" y="-140.36" width="30.952" height="50.082" fill="#808080" stroke-width=".40058"/> + <rect x="172.68" y="-139.06" width="28.784" height="6.4996" fill="#a00" stroke-width=".11698"/> + <rect x="172.74" y="-131.83" width="28.784" height="40.39" fill="#c4c8b7" stroke-width=".11698"/> + </g> + <text x="181.33067" y="-136.13423" fill="#ffffff" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="181.33067" y="-136.13423" fill="#ffffff" font-family="'Open Sans'" font-size="2.8222px" stroke-width=".39677">struct lwsac</tspan></text> + <text x="184.53554" y="-92.850395" fill="#000000" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="184.53554" y="-92.850395" font-family="'Open Sans'" stroke-width=".39677">allocated area</tspan></text> + <path d="m206.96-138.6 1.5352 0.74171-1.4119 0.76078-0.0812-0.34638-6.239-0.0174c0.0635-0.40246-0.0214-0.51522 0.0725-0.82588l6.136 5e-3z" fill="#2a7fff"/> + <rect x="172" y="-150.67" width="26.156" height="4.4025" fill="#500" stroke="#666" stroke-linejoin="round" stroke-width=".091779"/> + <text x="185.17738" y="-147.67433" fill="#ffffff" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="185.17738" y="-147.67433" fill="#ffffff" font-family="'Open Sans'" font-size="2.8222px" stroke-width=".39677">struct lwsac *head</tspan></text> + <text x="198.1916" y="-137.38612" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="198.1916" y="-137.38612">next</tspan><tspan x="198.1916" y="-135.51024">head</tspan><tspan x="198.1916" y="-133.63435">curr</tspan></text> + <path d="m174.55-138.71-0.74171 2.0619-0.76078-1.8964 0.34638-0.10906 0.0174-8.3796c0.40246 0.0853 0.51522-0.0288 0.82587 0.0974l-5e-3 8.2413z" fill="#2a7fff"/> + <text x="188.84824" y="-135.46999" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="188.84824" y="-135.46999" text-align="start">ofs</tspan><tspan x="188.84824" y="-133.5941" text-align="start">alloc_size</tspan></text> + <path d="m195.91-144.71-0.7417-2.0619-0.76078 1.8964 0.34637 0.10906-0.0412 9.1651c0.24984 0.0323 0.88518-0.0192 1.5658-0.0156 0.0711-0.0968 0.0691-0.46205 0.015-0.82619-0.45397 2e-3 -0.78488-5e-3 -0.69634-0.0411l-5e-3 -8.2413z" fill="#2a7fff"/> + </g> + <path d="m201.26-131.89-2.3876 2.1223-0.13265 35.947 2.7855 2.255" fill="none" stroke="#000" stroke-dasharray="0.5627649, 0.1875883" stroke-width=".18759"/> + <path d="m191.97-133.09 6.8975 7.6934" fill="none" stroke="#000" stroke-dasharray="0.37517659, 0.1875883" stroke-width=".18759"/> + <path d="m174.12-132.51-1.5352 0.7417 1.4119 0.76078 0.0812-0.34638 2.127 0.0157c-0.0635-0.40245 0.0214-0.54838-0.0725-0.85903l-2.024 5e-3z"/> + <path d="m176.09-131.63 5.7037 0.0664 6.2343-3.913 0.66323-0.0995" fill="none" stroke="#000" stroke-dasharray="0.37517659, 0.1875883" stroke-width=".18759"/> + <g> + <rect x="220.5" y="-140.05" width="30.952" height="50.082" fill="#808080" stroke="#666" stroke-linejoin="round" stroke-width=".40058"/> + <rect x="221.48" y="-138.74" width="28.784" height="6.4996" fill="#a00" stroke="#666" stroke-linejoin="round" stroke-width=".11698"/> + <text x="226.27528" y="-118.77273" fill="#000000" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="226.27528" y="-118.77273" font-family="'Open Sans'" stroke-width=".18759">ptr aligned</tspan></text> + <rect x="221.54" y="-131.51" width="28.784" height="40.39" fill="#c4c8b7" stroke="#666" stroke-linejoin="round" stroke-width=".11698"/> + <text x="230.13133" y="-135.82219" fill="#ffffff" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="230.13133" y="-135.82219" fill="#ffffff" font-family="'Open Sans'" font-size="2.8222px" stroke-width=".39677">struct lwsac</tspan></text> + <text x="233.3362" y="-92.538383" fill="#000000" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="233.3362" y="-92.538383" font-family="'Open Sans'" stroke-width=".39677">allocated area</tspan></text> + <path d="m255.76-138.29 1.5352 0.74171-1.4119 0.76078-0.0812-0.34638-6.239-0.0174c0.0635-0.40246-0.0214-0.51522 0.0725-0.82588l6.136 5e-3z" fill="#2a7fff"/> + <rect x="220.8" y="-150.36" width="26.156" height="4.4025" fill="#500" stroke="#666" stroke-linejoin="round" stroke-width=".091779"/> + <text x="233.97806" y="-147.36229" fill="#ffffff" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="233.97806" y="-147.36229" fill="#ffffff" font-family="'Open Sans'" font-size="2.8222px" stroke-width=".39677">struct lwsac *head</tspan></text> + <text x="246.99228" y="-137.07408" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="246.99228" y="-137.07408">next</tspan><tspan x="246.99228" y="-135.1982">head</tspan><tspan x="246.99228" y="-133.32231">curr</tspan></text> + <path d="m223.35-138.4-0.74171 2.0619-0.76078-1.8964 0.34638-0.10905 0.0174-8.3796c0.40246 0.0853 0.51522-0.0288 0.82588 0.0974l-5e-3 8.2413z" fill="#2a7fff"/> + <text x="237.64891" y="-135.15791" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="237.64891" y="-135.15791" text-align="start">ofs</tspan><tspan x="237.64891" y="-133.28203" text-align="start">alloc_size</tspan></text> + <path d="m244.71-144.39-0.74171-2.0619-0.76078 1.8964 0.34638 0.10906-0.0412 9.1651c0.24984 0.0323 0.88518-0.0192 1.5658-0.0156 0.0711-0.0968 0.0691-0.46205 0.015-0.82618-0.45397 2e-3 -0.78488-5e-3 -0.69634-0.0411l-5e-3 -8.2413z" fill="#2a7fff"/> + <rect x="221.98" y="-130.85" width="27.712" height="7.4313" fill="#ff8080" stroke="#666" stroke-linejoin="round" stroke-width=".14463"/> + <rect x="221.97" y="-121.59" width="27.712" height="7.4313" fill="#ff8080" stroke="#666" stroke-linejoin="round" stroke-width=".14463"/> + </g> + <path d="m250.06-131.58-2.3876 2.1223-0.13265 35.947 2.7855 2.255" fill="none" stroke="#000" stroke-dasharray="0.56276491, 0.1875883" stroke-width=".18759"/> + <path d="m240.78-132.77 6.8975 7.6934" fill="none" stroke="#000" stroke-dasharray="0.37517659, 0.1875883" stroke-width=".18759"/> + <text x="235.9016" y="-126.22051" fill="#ffffff" font-family="'Open Sans'" font-size="2.5582px" letter-spacing="0px" stroke-width=".31977" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="235.9016" y="-126.22051" fill="#ffffff" font-family="'Open Sans'" stroke-width=".31977">lwsac_use area</tspan></text> + <path d="m223.49-112.72-1.5352 0.7417 1.4119 0.76079 0.0812-0.34638 2.127 0.0157c-0.0635-0.40245 0.0214-0.54838-0.0725-0.85903l-2.024 5e-3z"/> + <path d="m225.29-112.13 8.31 0.0664 3.0298-2.9076 0.20032-20.194 0.66323-0.0995" fill="none" stroke="#000" stroke-dasharray="0.37517659, 0.1875883" stroke-width=".18759"/> + <g> + <text x="177.42035" y="-129.76131" fill="#000000" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="177.42035" y="-129.76131" font-family="'Open Sans'" stroke-width=".18759">ptr aligned</tspan></text> + <text x="235.79298" y="-122.17254" fill="#000000" font-family="'Open Sans'" font-size="1.0364px" letter-spacing="0px" stroke-width=".12956" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="235.79298" y="-122.17254" font-family="'Open Sans'" stroke-width=".12956">alignment padding</tspan></text> + <path d="m220.64-131.26 1.5352 0.7417-1.4119 0.76079-0.0812-0.34638-2.127 0.0157c0.0635-0.40246-0.0214-0.54838 0.0725-0.85903l2.024 5e-3z"/> + <g font-family="'Open Sans'" letter-spacing="0px" text-anchor="middle" word-spacing="0px"> + <text x="235.89856" y="-116.96035" fill="#ffffff" font-size="2.5582px" stroke-width=".31977" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="235.89856" y="-116.96035" fill="#ffffff" font-family="'Open Sans'" stroke-width=".31977">lwsac_use area</tspan></text> + <text x="226.27226" y="-109.51257" fill="#000000" font-size="1.5007px" stroke-width=".18759" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="226.27226" y="-109.51257" font-family="'Open Sans'" stroke-width=".18759">ptr aligned</tspan></text> + <text x="235.78995" y="-112.91241" fill="#000000" font-size="1.0364px" stroke-width=".12956" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="235.78995" y="-112.91241" font-family="'Open Sans'" stroke-width=".12956">alignment padding</tspan></text> + </g> + <path d="m220.64-122 1.5352 0.7417-1.4119 0.76079-0.0812-0.34638-2.127 0.0157c0.0635-0.40245-0.0214-0.54838 0.0725-0.85903l2.024 5e-3z"/> + <rect x="268.33" y="-140.45" width="30.952" height="50.082" fill="#808080" stroke="#666" stroke-linejoin="round" stroke-width=".40058"/> + <rect x="269.31" y="-139.14" width="28.784" height="6.4996" fill="#a00" stroke="#666" stroke-linejoin="round" stroke-width=".11698"/> + <text x="274.10483" y="-119.17068" fill="#000000" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="274.10483" y="-119.17068" font-family="'Open Sans'" stroke-width=".18759">ptr aligned</tspan></text> + <rect x="269.37" y="-131.91" width="28.784" height="40.39" fill="#c4c8b7" stroke="#666" stroke-linejoin="round" stroke-width=".11698"/> + <text x="277.96088" y="-136.22011" fill="#ffffff" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="277.96088" y="-136.22011" fill="#ffffff" font-family="'Open Sans'" font-size="2.8222px" stroke-width=".39677">struct lwsac</tspan></text> + <text x="281.16574" y="-92.936333" fill="#000000" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="281.16574" y="-92.936333" font-family="'Open Sans'" stroke-width=".39677">allocated area</tspan></text> + <rect x="302.47" y="-140.62" width="30.952" height="50.082" fill="#808080" stroke="#666" stroke-linejoin="round" stroke-width=".40058"/> + <rect x="303.45" y="-139.31" width="28.784" height="6.4996" fill="#a00" stroke="#666" stroke-linejoin="round" stroke-width=".11698"/> + <path d="m303.59-138.69 1.5352 0.7417-1.4119 0.76078-0.0812-0.34638-6.239-0.0174c0.0635-0.40245-0.0214-0.51522 0.0725-0.82587l6.136 5e-3z" fill="#2a7fff"/> + <rect x="268.63" y="-150.76" width="26.156" height="4.4025" fill="#500" stroke="#666" stroke-linejoin="round" stroke-width=".091779"/> + <text x="281.80762" y="-147.76024" fill="#ffffff" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="281.80762" y="-147.76024" fill="#ffffff" font-family="'Open Sans'" font-size="2.8222px" stroke-width=".39677">struct lwsac *head</tspan></text> + <text x="294.82181" y="-137.47203" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="294.82181" y="-137.47203">next</tspan><tspan x="294.82181" y="-135.59615">head</tspan><tspan x="294.82181" y="-133.72026">curr</tspan></text> + <path d="m271.18-138.8-0.74171 2.0619-0.76078-1.8964 0.34638-0.10906 0.0174-8.3796c0.40246 0.0853 0.51522-0.0288 0.82587 0.0974l-5e-3 8.2413z" fill="#2a7fff"/> + <text x="285.47845" y="-135.55586" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="285.47845" y="-135.55586" text-align="start">ofs</tspan><tspan x="285.47845" y="-133.67998" text-align="start">alloc_size</tspan></text> + <path d="m292.54-144.79-0.74171-2.0619-0.76078 1.8964 0.34638 0.10906-0.0412 9.1651c0.24984 0.0323 0.88517-0.0192 1.5658-0.0156 0.0711-0.0968 0.0691-0.46206 0.015-0.82619-0.45397 2e-3 -0.78487-5e-3 -0.69633-0.0411l-5e-3 -8.2413z" fill="#2a7fff"/> + <rect x="269.81" y="-131.25" width="27.712" height="7.4313" fill="#ff8080" stroke="#666" stroke-linejoin="round" stroke-width=".14463"/> + <rect x="269.8" y="-121.99" width="27.712" height="7.4313" fill="#ff8080" stroke="#666" stroke-linejoin="round" stroke-width=".14463"/> + </g> + <path d="m297.89-131.98-2.3876 2.1223-0.13264 35.947 2.7855 2.255" fill="none" stroke="#000" stroke-dasharray="0.56276492, 0.1875883" stroke-width=".18759"/> + <path d="m288.61-133.17 6.8975 7.6934" fill="none" stroke="#000" stroke-dasharray="0.37517659, 0.1875883" stroke-width=".18759"/> + <text x="283.73114" y="-126.61846" fill="#ffffff" font-family="'Open Sans'" font-size="2.5582px" letter-spacing="0px" stroke-width=".31977" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="283.73114" y="-126.61846" fill="#ffffff" font-family="'Open Sans'" stroke-width=".31977">lwsac_use area</tspan></text> + <path d="m271.31-113.11-1.5352 0.7417 1.4119 0.76079 0.0812-0.34638 2.127 0.0157c-0.0635-0.40246 0.0214-0.54838-0.0725-0.85904l-2.024 5e-3z"/> + <path d="m273.12-112.52 8.31 0.0664 3.0298-2.9076 0.20032-20.194 0.66323-0.0995" fill="none" stroke="#000" stroke-dasharray="0.37517659, 0.1875883" stroke-width=".18759"/> + <g> + <text x="283.62253" y="-122.57049" fill="#000000" font-family="'Open Sans'" font-size="1.0364px" letter-spacing="0px" stroke-width=".12956" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="283.62253" y="-122.57049" font-family="'Open Sans'" stroke-width=".12956">alignment padding</tspan></text> + <path d="m268.47-131.66 1.5352 0.74171-1.4119 0.76078-0.0812-0.34638-2.127 0.0157c0.0635-0.40245-0.0214-0.54838 0.0725-0.85903l2.024 5e-3z"/> + <g font-family="'Open Sans'" letter-spacing="0px" text-anchor="middle" word-spacing="0px"> + <text x="283.72812" y="-117.3583" fill="#ffffff" font-size="2.5582px" stroke-width=".31977" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="283.72812" y="-117.3583" fill="#ffffff" font-family="'Open Sans'" stroke-width=".31977">lwsac_use area</tspan></text> + <text x="274.10181" y="-109.91051" fill="#000000" font-size="1.5007px" stroke-width=".18759" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="274.10181" y="-109.91051" font-family="'Open Sans'" stroke-width=".18759">ptr aligned</tspan></text> + <text x="283.61948" y="-113.31036" fill="#000000" font-size="1.0364px" stroke-width=".12956" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="283.61948" y="-113.31036" font-family="'Open Sans'" stroke-width=".12956">alignment padding</tspan></text> + </g> + <path d="m268.47-122.4 1.5352 0.7417-1.4119 0.76079-0.0812-0.34638-2.127 0.0157c0.0635-0.40246-0.0214-0.54838 0.0725-0.85904l2.024 5e-3z"/> + <rect x="303.52" y="-132.08" width="28.784" height="40.39" fill="#c4c8b7" stroke="#666" stroke-linejoin="round" stroke-width=".11698"/> + <text x="312.10593" y="-136.39232" fill="#ffffff" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="312.10593" y="-136.39232" fill="#ffffff" font-family="'Open Sans'" font-size="2.8222px" stroke-width=".39677">struct lwsac</tspan></text> + <text x="315.31079" y="-93.108513" fill="#000000" font-family="'Open Sans'" font-size="3.1742px" letter-spacing="0px" stroke-width=".39677" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="315.31079" y="-93.108513" font-family="'Open Sans'" stroke-width=".39677">allocated area</tspan></text> + <path d="m337.74-138.86 1.5352 0.74171-1.4119 0.76078-0.0812-0.34638-6.239-0.0174c0.0635-0.40245-0.0214-0.51522 0.0725-0.82587l6.136 5e-3z" fill="#2a7fff"/> + <text x="328.96686" y="-137.64424" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="328.96686" y="-137.64424">next</tspan><tspan x="328.96686" y="-135.76836">head</tspan><tspan x="328.96686" y="-133.89247">curr</tspan></text> + <text x="319.6235" y="-135.72807" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" stroke-width=".18759" text-align="center" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="319.6235" y="-135.72807" text-align="start">ofs</tspan><tspan x="319.6235" y="-133.85219" text-align="start">alloc_size</tspan></text> + <rect x="304.15" y="-131.34" width="27.572" height="28.913" fill="#ff8080" stroke="#666" stroke-linejoin="round" stroke-width=".28455"/> + </g> + <path d="m332.04-132.15-2.3876 2.1223-0.13264 35.947 2.7855 2.255" fill="none" stroke="#000" stroke-dasharray="0.56276491, 0.1875883" stroke-width=".18759"/> + <path d="m322.75-133.34 6.8975 7.6934" fill="none" stroke="#000" stroke-dasharray="0.37517659, 0.1875883" stroke-width=".18759"/> + <path d="m292.68-145.32 0.74171-1.5352 0.76078 1.4119-0.34638 0.0812 0.0259 2.071 28.542 0.041 2.225 2.8639 0.0875 2.9524 0.64641 0.65493 1.5316 2e-3 0.0488 0.76904-2.1195-0.0297-1.142-1.1761-0.0569-2.9726-2.1165-2.253c-0.40246-0.0635-28.205 0.0547-28.516-0.0391l5e-3 -2.8532z" fill="#2a7fff"/> + <path d="m303.21-134.9 1.5352 0.74171-1.4119 0.76078-0.0812-0.34638-6.239-0.0174c0.0635-0.40245-0.0214-0.51522 0.0725-0.82587l6.136 5e-3z" fill="#2a7fff"/> + <path d="m307.26-100.45 1.4591 0.0664 3.06-3.7843-9e-3 -23.607 7.6934-8.0582" fill="none" stroke="#000" stroke-dasharray="0.37517659, 0.1875883" stroke-width=".18759"/> + <g> + <path d="m305.59-100.91-1.5352 0.74171 1.4119 0.76078 0.0812-0.34638 2.127 0.01569c-0.0635-0.40245 0.0214-0.54838-0.0725-0.85903l-2.024 5e-3z"/> + <g font-family="'Open Sans'" letter-spacing="0px" text-anchor="middle" word-spacing="0px"> + <text x="318.0058" y="-105.15496" fill="#ffffff" font-size="2.5582px" stroke-width=".31977" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="318.0058" y="-105.15496" fill="#ffffff" font-family="'Open Sans'" stroke-width=".31977">lwsac_use area</tspan></text> + <text x="308.37949" y="-97.707207" fill="#000000" font-size="1.5007px" stroke-width=".18759" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="308.37949" y="-97.707207" font-family="'Open Sans'" stroke-width=".18759">ptr aligned</tspan></text> + <text x="317.89719" y="-101.10705" fill="#000000" font-size="1.0364px" stroke-width=".12956" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="317.89719" y="-101.10705" font-family="'Open Sans'" stroke-width=".12956">alignment padding</tspan></text> + </g> + <path d="m302.48-132.08 1.5352 0.74171-1.4119 0.76078-0.0812-0.34638-2.127 0.0157c0.0635-0.40245-0.0214-0.54838 0.0725-0.85903l2.024 5e-3z"/> + <g stroke-width=".18759"> + <rect x="204.83" y="-139.17" width="5.018" height="2.6731" ry="1.3366" fill="#808080" stroke="#666" stroke-linejoin="round"/> + <text x="207.36176" y="-137.33116" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="207.36176" y="-137.33116" fill="#ffffff" font-family="'Open Sans'" stroke-width=".18759">NULL</tspan></text> + <rect x="253.14" y="-139.13" width="5.018" height="2.6731" ry="1.3366" fill="#808080" stroke="#666" stroke-linejoin="round"/> + <text x="255.6705" y="-137.29219" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="255.6705" y="-137.29219" fill="#ffffff" font-family="'Open Sans'" stroke-width=".18759">NULL</tspan></text> + <rect x="336.04" y="-139.46" width="5.018" height="2.6731" ry="1.3366" fill="#808080" stroke="#666" stroke-linejoin="round"/> + <text x="338.57361" y="-137.62383" fill="#ffffff" font-family="'Open Sans'" font-size="1.5007px" letter-spacing="0px" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="338.57361" y="-137.62383" fill="#ffffff" font-family="'Open Sans'" stroke-width=".18759">NULL</tspan></text> + </g> + </g> + <g fill="#0000ff" font-family="'Open Sans'" font-size="3.2649px" letter-spacing="0px" stroke-width=".40811" text-anchor="middle" word-spacing="0px"> + <text x="187.11359" y="-84.657211" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="187.11359" y="-84.657211" fill="#0000ff" font-family="'Open Sans'" stroke-width=".40811">empty, generic lwsac</tspan></text> + <text x="235.71112" y="-84.353561" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="235.71112" y="-84.353561" fill="#0000ff" font-family="'Open Sans'" stroke-width=".40811">lwsac with 2 "uses"</tspan></text> + <text x="300.70877" y="-83.844711" text-align="center" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25" xml:space="preserve"><tspan x="300.70877" y="-83.844711" fill="#0000ff" font-family="'Open Sans'" stroke-width=".40811">lwsac with 2 "uses", 3rd requires a new one</tspan></text> + </g> + </g> +</svg> diff --git a/include/libwebsockets.h b/include/libwebsockets.h index c4fc84ad85063a3ce6da296b728b628a7cce0af6..3d63dffe1634d02102ec850b556583effe82f0d2 100644 --- a/include/libwebsockets.h +++ b/include/libwebsockets.h @@ -409,6 +409,7 @@ struct lws; #include <libwebsockets/lws-stats.h> #include <libwebsockets/lws-threadpool.h> #include <libwebsockets/lws-tokenize.h> +#include <libwebsockets/lws-lwsac.h> #if defined(LWS_WITH_TLS) diff --git a/include/libwebsockets/lws-lwsac.h b/include/libwebsockets/lws-lwsac.h new file mode 100644 index 0000000000000000000000000000000000000000..1f914b66a650f2beb9994748dc833370e9fb6628 --- /dev/null +++ b/include/libwebsockets/lws-lwsac.h @@ -0,0 +1,191 @@ +/* + * libwebsockets - lws alloc chunk + * + * Copyright (C) 2018 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * included from libwebsockets.h + */ + +/** \defgroup log lwsac + * + * ##Allocated Chunks + * + * If you know you will be allocating a large, unknown number of same or + * differently sized objects, it's certainly possible to do it with libc + * malloc. However the allocation cost in time and memory overhead can + * add up, and deallocation means walking the structure of every object and + * freeing them in turn. + * + * lwsac (LWS Allocated Chunks) allocates chunks intended to be larger + * than your objects (4000 bytes by default) which you linearly allocate from + * using lwsac_use(). + * + * If your next request won't fit in the current chunk, a new chunk is added + * to the chain of chunks and the allocaton done from there. If the request + * is larger than the chunk size, an oversize chunk is created to satisfy it. + * + * When you are finished with the allocations, you call lwsac_free() and + * free all the *chunks*. So you may have thousands of objects in the chunks, + * but they are all destroyed with the chunks without having to deallocate them + * one by one pointlessly. + */ +///@{ + +struct lwsac; +typedef unsigned char * lwsac_cached_file_t; + + +#define lws_list_ptr_container(P,T,M) ((T *)((char *)(P) - offsetof(T, M))) + +/* + * linked-list helper that's commonly useful to manage lists of things + * allocated using lwsac. + * + * These lists point to their corresponding "next" member in the target, NOT + * the original containing struct. To get the containing struct, you must use + * lws_list_ptr_container() to convert. + * + * It's like that because it means we no longer have to have the next pointer + * at the start of the struct, and we can have the same struct on multiple + * linked-lists with everything held in the struct itself. + */ +typedef void * lws_list_ptr; + +/* + * optional sorting callback called by lws_list_ptr_insert() to sort the right + * things inside the opqaue struct being sorted / inserted on the list. + */ +typedef int (*lws_list_ptr_sort_func_t)(lws_list_ptr a, lws_list_ptr b); + +#define lws_list_ptr_advance(_lp) _lp = *((void **)_lp) + +/* sort may be NULL if you don't care about order */ +LWS_VISIBLE LWS_EXTERN void +lws_list_ptr_insert(lws_list_ptr *phead, lws_list_ptr *add, + lws_list_ptr_sort_func_t sort); + + +/** + * lwsac_use - allocate / use some memory from a lwsac + * + * \param head: pointer to the lwsac list object + * \param ensure: the number of bytes we want to use + * \param chunk_size: 0, or the size of the chunk to (over)allocate if + * what we want won't fit in the current tail chunk. If + * 0, the default value of 4000 is used. If ensure is + * larger, it is used instead. + * + * This also serves to init the lwsac if *head is NULL. Basically it does + * whatever is necessary to return you a pointer to ensure bytes of memory + * reserved for the caller. + * + * Returns NULL if OOM. + */ +LWS_VISIBLE LWS_EXTERN void * +lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size); + +/** + * lwsac_free - deallocate all chunks in the lwsac and set head NULL + * + * \param head: pointer to the lwsac list object + * + * This deallocates all chunks in the lwsac, then sets *head to NULL. All + * lwsac_use() pointers are invalidated in one hit without individual frees. + */ +LWS_VISIBLE LWS_EXTERN void +lwsac_free(struct lwsac **head); + +/* + * Optional helpers useful for where consumers may need to defer destruction + * until all consumers are finished with the lwsac + */ + +/** + * lwsac_detach() - destroy an lwsac unless somebody else is referencing it + * + * \param head: pointer to the lwsac list object + * + * The creator of the lwsac can all this instead of lwsac_free() when it itself + * has finished with the lwsac, but other code may be consuming it. + * + * If there are no other references, the lwsac is destroyed, *head is set to + * NULL and that's the end; however if something else has called + * lwsac_reference() on the lwsac, it simply returns. When lws_unreference() + * is called and no references are left, it will be destroyed then. + */ +LWS_VISIBLE LWS_EXTERN void +lwsac_detach(struct lwsac **head); + +/** + * lwsac_reference() - increase the lwsac reference count + * + * \param head: pointer to the lwsac list object + * + * Increment the reference count on the lwsac to defer destruction. + */ +LWS_VISIBLE LWS_EXTERN void +lwsac_reference(struct lwsac *head); + +/** + * lwsac_reference() - increase the lwsac reference count + * + * \param head: pointer to the lwsac list object + * + * Decrement the reference count on the lwsac... if it reached 0 on a detached + * lwsac then the lwsac is immediately destroyed and *head set to NULL. + */ +LWS_VISIBLE LWS_EXTERN void +lwsac_unreference(struct lwsac **head); + + +/* helpers to keep a file cached in memory */ + +LWS_VISIBLE LWS_EXTERN void +lwsac_use_cached_file_start(lwsac_cached_file_t cache); + +LWS_VISIBLE LWS_EXTERN void +lwsac_use_cached_file_end(lwsac_cached_file_t *cache); + +LWS_VISIBLE LWS_EXTERN void +lwsac_use_cached_file_detach(lwsac_cached_file_t *cache); + +LWS_VISIBLE LWS_EXTERN int +lwsac_cached_file(const char *filepath, lwsac_cached_file_t *cache, + size_t *len); + +/* more advanced helpers */ + +LWS_VISIBLE LWS_EXTERN size_t +lwsac_sizeof(void); + +LWS_VISIBLE LWS_EXTERN size_t +lwsac_get_tail_pos(struct lwsac *lac); + +LWS_VISIBLE LWS_EXTERN struct lwsac * +lwsac_get_next(struct lwsac *lac); + +LWS_VISIBLE LWS_EXTERN size_t +lwsac_align(size_t length); + +LWS_VISIBLE LWS_EXTERN void +lwsac_info(struct lwsac *head); + +LWS_VISIBLE LWS_EXTERN uint64_t +lwsac_total_alloc(struct lwsac *head); + +///@} diff --git a/lib/misc/lwsac/README.md b/lib/misc/lwsac/README.md new file mode 100644 index 0000000000000000000000000000000000000000..33462a7430703172859285a7562c555d0118e1b3 --- /dev/null +++ b/lib/misc/lwsac/README.md @@ -0,0 +1,63 @@ +## LWS Allocated Chunks + + + +These apis provide a way to manage a linked-list of allocated chunks... + +[ HEAD alloc ] -> [ next alloc ] -> [ next alloc ] -> [ curr alloc ] + +... and sub-allocate trivially inside the chunks. These sub-allocations are +not tracked by lwsac at all, there is a "used" high-water mark for each chunk +that's simply advanced by the amount sub-allocated. If the allocation size +matches the platform pointer alignment, there is zero overhead to sub-allocate +(otherwise the allocation is padded to the next platform pointer alignment +automatically). + +If you have an unknown amount of relatively little things to allocate, including +strings or other unstructured data, lwsac is significantly more efficient than +individual allocations using malloc or so. + +## lwsac_use() api + +When you make an sub-allocation using `lwsac_use()`, you can either +set the `chunk_size` arg to zero, defaulting to 4000, or a specific chunk size. +In the event the requested sub-allocation exceeds the chunk size, the chunk +size is increated to match it automatically for this allocation only. + +Subsequent `lwsac_use()` calls will advance internal pointers to use up the +remaining space inside the current chunk if possible; if not enough remaining +space it is skipped, a new allocation is chained on and the request pointed to +there. + +Lwsac does not store information about sub-allocations. There is really zero +overhead for individual sub-allocations (unless their size is not +pointer-aligned, in which case the actual amount sub-allocated is rounded up to +the next pointer alignment automatically). For structs, which are pointer- +aligned naturally, and a chunk size relatively large for the sub-allocation +size, lwsac is extremely efficient even for huge numbers of small allocations. + +This makes lwsac very effective when the total amount of allocation needed is +not known at the start and may be large... it will simply add on chunks to cope +with whatever happens. + +## lwsac_free() api + +When you are finished with the lwsac, you simply free the chain of allocated +chunks using lwsac_free() on the lwsac head. There's no tracking or individual +destruction of suballocations - the whole chain of chunks the suballocations +live in are freed and invalidated all together. + +If the structs stored in the lwsac allocated things **outside** the lwsac, then the +user must unwind through them and perform the frees. But the idea of lwsac is +things stored in the lwsac also suballocate into the lwsac, and point into the +lwsac if they need to, avoiding any need to visit them during destroy. It's +like clearing up after a kids' party by gathering up a disposable tablecloth: +no matter what was left on the table, it's all gone in one step. + +## lws_list_ptr helpers + +A common pattern needed with sub-allocated structs is they are on one or more +linked-list. To make that simple to do cleanly, lws_list... apis are provided +along with a generic insertion function that can take a sort callback. These +allow a struct to participate on multiple linked-lists simultaneously. + diff --git a/lib/misc/lwsac/cached-file.c b/lib/misc/lwsac/cached-file.c new file mode 100644 index 0000000000000000000000000000000000000000..f5f64d21669f9f4b30404451679ea691faa4fad1 --- /dev/null +++ b/lib/misc/lwsac/cached-file.c @@ -0,0 +1,202 @@ +/* + * libwebsockets - lws alloc chunk live file caching + * + * Copyright (C) 2018 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "core/private.h" +#include "misc/lwsac/private.h" + +/* + * Helper for caching a file in memory in a lac, but also to check at intervals + * no less than 5s if the file is still fresh. + * + * Set *cache to NULL the first time before calling. + * + * You should call this each time before using the cache... if it's + * + * - less than 5s since the last freshness check, and + * - the file is already in memory + * + * it just returns with *cache left alone; this costs very little. You should + * call `lwsac_use_cached_file_start()` and `lwsac_use_cached_file_end()` to lock + * the cache against deletion while you are using it. + * + * If it's + * + * - at least 5s since the last freshness check, and + * - the file timestamp has changed + * + * then + * + * - the file is reloaded into a new lac and *cache set to that + * + * - the old cache lac, if any, is detached (so it will be freed when its + * reference count reaches zero, or immediately if nobody has it) + * + * Note the call can fail due to OOM or filesystem issue at any time. + * + * + * After the LAC header there is stored a `struct cached_file_info` and then + * the raw file contents. * + * + * [LAC header] + * [struct cached_file_info] + * [file contents] <--- *cache is set to here + * + * The api returns a lwsac_cached_file_t type offset to point to the file + * contents. Helpers for reference counting and freeing are also provided + * that take that type and know how to correct it back to operate on the LAC. + */ + +#define cache_file_to_lac(c) ((struct lwsac *)((char *)c - \ + sizeof(struct cached_file_info) - \ + sizeof(struct lwsac))) + +void +lwsac_use_cached_file_start(lwsac_cached_file_t cache) +{ + struct lwsac *lac = cache_file_to_lac(cache); + + lac->refcount++; + // lwsl_debug("%s: html refcount: %d\n", __func__, lac->refcount); +} + +void +lwsac_use_cached_file_end(lwsac_cached_file_t *cache) +{ + struct lwsac *lac; + + if (!cache || !*cache) + return; + + lac = cache_file_to_lac(*cache); + + if (!lac->refcount) + lwsl_err("%s: html refcount zero on entry\n", __func__); + + if (lac->refcount && !--lac->refcount && lac->detached) { + *cache = NULL; /* not usable any more */ + lwsac_free(&lac); + } +} + +void +lwsac_use_cached_file_detach(lwsac_cached_file_t *cache) +{ + struct lwsac *lac = cache_file_to_lac(*cache); + + lac->detached = 1; + if (lac->refcount) + return; + + *cache = NULL; + lwsac_free(&lac); +} + +int +lwsac_cached_file(const char *filepath, lwsac_cached_file_t *cache, size_t *len) +{ + struct cached_file_info *info = NULL; + lwsac_cached_file_t old = *cache; + struct lwsac *lac = NULL; + time_t t = time(NULL); + unsigned char *a; + struct stat s; + size_t all; + ssize_t rd; + int fd; + + if (old) { /* we already have a cached copy of it */ + + info = (struct cached_file_info *)((*cache) - sizeof(*info)); + + if (t - info->last_confirm < 5) + /* we checked it as fresh less than 5s ago, use old */ + return 0; + } + + /* + * ...it's been 5s, we should check again on the filesystem + * that the file hasn't changed + */ + + fd = open(filepath, O_RDONLY); + if (fd < 0) { + lwsl_err("%s: cannot open %s\n", __func__, filepath); + + return 1; + } + + if (fstat(fd, &s)) { + lwsl_err("%s: cannot stat %s\n", __func__, filepath); + + goto bail; + } + + if (old && s.st_mtime == info->s.st_mtime) { + /* it still seems to be the same as our cached one */ + info->last_confirm = t; + + close(fd); + + return 0; + } + + /* + * we either didn't cache it yet, or it has changed since we cached + * it... reload in a new lac and then detach the old lac. + */ + + all = sizeof(*info) + s.st_size + 1; + + info = lwsac_use(&lac, all, all); + if (!info) + goto bail; + + info->s = s; + info->last_confirm = t; + + a = (unsigned char *)(info + 1); + + *len = s.st_size; + a[s.st_size] = '\0'; + + rd = read(fd, a, s.st_size); + if (rd != s.st_size) { + lwsl_err("%s: cannot read %s (%d)\n", __func__, filepath, + (int)rd); + goto bail1; + } + + close(fd); + + *cache = (lwsac_cached_file_t)a; + if (old) + lwsac_use_cached_file_detach(&old); + + return 0; + +bail1: + lwsac_free(&lac); + +bail: + close(fd); + + return 1; +} diff --git a/lib/misc/lwsac/lwsac.c b/lib/misc/lwsac/lwsac.c new file mode 100644 index 0000000000000000000000000000000000000000..abde1a832ba54d63c09c2c1ac6ec279e5d9706c6 --- /dev/null +++ b/lib/misc/lwsac/lwsac.c @@ -0,0 +1,182 @@ +/* + * libwebsockets - lws alloc chunk + * + * Copyright (C) 2018 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "core/private.h" +#include "misc/lwsac/private.h" + +void +lws_list_ptr_insert(lws_list_ptr *head, lws_list_ptr *add, + lws_list_ptr_sort_func_t sort_func) +{ + while (sort_func && *head) { + if (sort_func(add, *head) <= 0) + break; + + head = *head; + } + + *add = *head; + *head = add; +} + +size_t +lwsac_align(size_t length) +{ + size_t align = sizeof(int *); + + if (length & (align - 1)) + length += align - (length & (align - 1)); + + return length; +} + +size_t +lwsac_sizeof(void) +{ + return sizeof(struct lwsac); +} + +size_t +lwsac_get_tail_pos(struct lwsac *lac) +{ + return lac->ofs; +} + +struct lwsac * +lwsac_get_next(struct lwsac *lac) +{ + return lac->next; +} + +void * +lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size) +{ + struct lwsac *chunk; + size_t ofs, alloc; + + /* ensure there's a chunk and enough space in it for this name */ + + if (!*head || (*head)->curr->alloc_size - (*head)->curr->ofs < ensure) { + + if (!chunk_size) + alloc = LWSAC_CHUNK_SIZE + sizeof(*chunk); + else + alloc = chunk_size + sizeof(*chunk); + + /* + * If we get asked for something outside our expectation, + * allocate to meet it + */ + + if (ensure >= alloc - sizeof(*chunk)) + alloc = ensure + sizeof(*chunk); + + chunk = malloc(alloc); + if (!chunk) { + lwsl_err("%s: OOM trying to alloc %llud\n", __func__, + (unsigned long long)alloc); + return NULL; + } + + if (!*head) { + *head = chunk; + chunk->total_alloc_size = 0; + chunk->total_blocks = 0; + } + else + (*head)->curr->next = chunk; + + (*head)->curr = chunk; + (*head)->curr->head = *head; + + chunk->next = NULL; + chunk->alloc_size = alloc; + chunk->detached = 0; + chunk->refcount = 0; + + (*head)->total_alloc_size += alloc; + (*head)->total_blocks++; + + /* + * belabouring the point... ofs is aligned to the platform's + * generic struct alignment at the start then + */ + (*head)->curr->ofs = sizeof(*chunk); + } + + ofs = (*head)->curr->ofs; + + (*head)->curr->ofs += lwsac_align(ensure); + if ((*head)->curr->ofs >= (*head)->curr->alloc_size) + (*head)->curr->ofs = (*head)->curr->alloc_size; + + return (char *)(*head)->curr + ofs; +} + +void +lwsac_free(struct lwsac **head) +{ + struct lwsac *it = *head; + + while (it) { + struct lwsac *tmp = it->next; + + free(it); + it = tmp; + } + + *head = NULL; +} + +void +lwsac_info(struct lwsac *head) +{ + lwsl_notice("%s: lac %p: %dKiB in %d blocks\n", __func__, head, + (int)(head->total_alloc_size >> 10), head->total_blocks); +} + +uint64_t +lwsac_total_alloc(struct lwsac *head) +{ + return head->total_alloc_size; +} + +void +lwsac_reference(struct lwsac *head) +{ + head->refcount++; +} + +void +lwsac_unreference(struct lwsac **head) +{ + (*head)->refcount--; + if ((*head)->detached && !(*head)->refcount) + lwsac_free(head); +} + +void +lwsac_detach(struct lwsac **head) +{ + (*head)->detached = 1; + if (!(*head)->refcount) + lwsac_free(head); +} diff --git a/lib/misc/lwsac/private.h b/lib/misc/lwsac/private.h new file mode 100644 index 0000000000000000000000000000000000000000..efefeb85af782454e12f995b7baa8bbe79744c9d --- /dev/null +++ b/lib/misc/lwsac/private.h @@ -0,0 +1,48 @@ +/* + * libwebsockets - lws alloc chunk + * + * Copyright (C) 2018 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <sys/stat.h> + +/* under page size of 4096 to allow overhead */ +#define LWSAC_CHUNK_SIZE 4000 + +/* + * the chunk list members all point back to the head themselves so the list + * can be detached from the formal head and free itself when its reference + * count reaches zero. + */ + +struct lwsac { + struct lwsac *next; + struct lwsac *head; /* pointer back to the first chunk */ + struct lwsac *curr; /* applies to head chunk only */ + size_t total_alloc_size; /* applies to head chunk only */ + size_t alloc_size; + size_t ofs; /* next writeable position inside chunk */ + int refcount; /* applies to head chunk only */ + int total_blocks; /* applies to head chunk only */ + char detached; /* if our refcount gets to zero, free the chunk list */ +}; + +struct cached_file_info { + struct stat s; + time_t last_confirm; +}; diff --git a/minimal-examples/api-tests/README.md b/minimal-examples/api-tests/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b047af52f43633bc03fa6377a002eb51b5828e91 --- /dev/null +++ b/minimal-examples/api-tests/README.md @@ -0,0 +1,5 @@ +|name|tests| +---|--- +api-test-lwsac|LWS Allocated Chunks +api-test-lws_tokenize|Generic secure string tokenizer + diff --git a/minimal-examples/api-tests/api-test-lwsac/CMakeLists.txt b/minimal-examples/api-tests/api-test-lwsac/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a73c6807e9c8669ed78910d801c8e0926fb8ab3a --- /dev/null +++ b/minimal-examples/api-tests/api-test-lwsac/CMakeLists.txt @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 2.8) +include(CheckCSourceCompiles) + +set(SAMP lws-api-test-lwsac) +set(SRCS main.c) + +# If we are being built as part of lws, confirm current build config supports +# reqconfig, else skip building ourselves. +# +# If we are being built externally, confirm installed lws was configured to +# support reqconfig, else error out with a helpful message about the problem. +# +MACRO(require_lws_config reqconfig _val result) + + if (DEFINED ${reqconfig}) + if (${reqconfig}) + set (rq 1) + else() + set (rq 0) + endif() + else() + set(rq 0) + endif() + + if (${_val} EQUAL ${rq}) + set(SAME 1) + else() + set(SAME 0) + endif() + + if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME}) + if (${_val}) + message("${SAMP}: skipping as lws being built without ${reqconfig}") + else() + message("${SAMP}: skipping as lws built with ${reqconfig}") + endif() + set(${result} 0) + else() + if (LWS_WITH_MINIMAL_EXAMPLES) + set(MET ${SAME}) + else() + CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig}) + if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig}) + set(HAS_${reqconfig} 0) + else() + set(HAS_${reqconfig} 1) + endif() + if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val})) + set(MET 1) + else() + set(MET 0) + endif() + endif() + if (NOT MET) + if (${_val}) + message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}") + else() + message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project") + endif() + endif() + endif() +ENDMACRO() + + + + add_executable(${SAMP} ${SRCS}) + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets) + endif() diff --git a/minimal-examples/api-tests/api-test-lwsac/README.md b/minimal-examples/api-tests/api-test-lwsac/README.md new file mode 100644 index 0000000000000000000000000000000000000000..74034c793f330199d851a6248a5bec836f71cb90 --- /dev/null +++ b/minimal-examples/api-tests/api-test-lwsac/README.md @@ -0,0 +1,22 @@ +# lws api test lwsac + +Demonstrates how to use and performs selftests for lwsac + +## build + +``` + $ cmake . && make +``` + +## usage + +Commandline option|Meaning +---|--- +-d <loglevel>|Debug verbosity in decimal, eg, -d15 + +``` + $ ./lws-api-test-lwsac +[2018/10/09 09:14:17:4834] USER: LWS API selftest: lwsac +[2018/10/09 09:14:17:4835] USER: Completed: PASS +``` + diff --git a/minimal-examples/api-tests/api-test-lwsac/main.c b/minimal-examples/api-tests/api-test-lwsac/main.c new file mode 100644 index 0000000000000000000000000000000000000000..854e0adc24f7c9feeb72ccd92cd87a410a888dd0 --- /dev/null +++ b/minimal-examples/api-tests/api-test-lwsac/main.c @@ -0,0 +1,81 @@ +/* + * lws-api-test-lwsac + * + * Copyright (C) 2018 Andy Green <andy@warmcat.com> + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + */ + +#include <libwebsockets.h> + +struct mytest { + int payload; + /* notice doesn't have to be at start of struct */ + lws_list_ptr list_next; + /* a struct can appear on multiple lists too... */ +}; + +/* converts a ptr to struct mytest .list_next to a ptr to struct mytest */ +#define list_to_mytest(p) lws_list_ptr_container(p, struct mytest, list_next) + +int main(int argc, const char **argv) +{ + int n, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE, acc; + lws_list_ptr list_head = NULL, iter; + struct lwsac *lwsac = NULL; + struct mytest *m; + const char *p; + + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS API selftest: lwsac\n"); + + /* + * 1) allocate and create 1000 struct mytest in a linked-list + */ + + for (n = 0; n < 1000; n++) { + m = lwsac_use(&lwsac, sizeof(*m), 0); + m->payload = n; + + lws_list_ptr_insert(&list_head, &m->list_next, NULL); + } + + /* + * 2) report some debug info about the lwsac state... those 1000 + * allocations actually only required 4 mallocs + */ + + lwsac_info(lwsac); + + /* 3) iterate the list, accumulating the payloads */ + + acc = 0; + iter = list_head; + while (iter) { + m = list_to_mytest(iter); + acc += m->payload; + + lws_list_ptr_advance(iter); + } + + if (acc != 499500) { + lwsl_err("%s: FAIL acc %d\n", __func__, acc); + + return 1; + } + + /* + * 4) deallocate everything (lwsac is also set to NULL). It just + * deallocates the 4 mallocs, everything in there is gone accordingly + */ + + lwsac_free(&lwsac); + + lwsl_user("Completed: PASS\n"); + + return 0; +} diff --git a/minimal-examples/api-tests/api-test-lwsac/selftest.sh b/minimal-examples/api-tests/api-test-lwsac/selftest.sh new file mode 100755 index 0000000000000000000000000000000000000000..16d1e2e8e463dec610c1cc4c2c7cc22f3cf0b14f --- /dev/null +++ b/minimal-examples/api-tests/api-test-lwsac/selftest.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# +# $1: path to minimal example binaries... +# if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1 +# that will be ./bin from your build dir +# +# $2: path for logs and results. The results will go +# in a subdir named after the directory this script +# is in +# +# $3: offset for test index count +# +# $4: total test count +# +# $5: path to ./minimal-examples dir in lws +# +# Test return code 0: OK, 254: timed out, other: error indication + +. $5/selftests-library.sh + +COUNT_TESTS=1 + +dotest $1 $2 apiselftest +exit $FAILS