Commit Graph

142 Commits

Author SHA1 Message Date
Vladimir Dubrovin
7cdfd87aa6 UDP services in one thread: udppm and dnspr without client threads
A UDP service now runs in its own thread alone (udploop()): it reads the
service's socket and the sockets of its sessions towards their
destinations, keeps their deadlines, and answers every client from the
service's socket. A session is a struct clientparam as a client thread's
would be, with a slot of maxchild, among the service's children and
counted on its listener, but without a thread. The services supply
handlers (struct udpservice, childdef.udp): udppm keeps a session per
client address, forwarding its datagrams, behind the headers of a
parent chain, from a socket of its own and answering what comes back,
until STRING_L of silence or, with -s, the first answer; dnspr makes a
session of each query, answered at once from the fake address, the
name cache or the resolver, or sent on to the first name server over
UDP, whose answer is waited for in the loop up to DNS_TO (a name server
over TCP is still waited for in place). Authentication stays in the
loop for now; datagrams over a bandwidth limit, or of a client without
a free slot, are dropped.

On a reload the old service goes on serving the socket until it sees
its configuration replaced, then hands its sessions to the listener;
the newest service of its kind there, which until then does not read
the socket so that no client gets two sessions, adopts them: a slot of
its own, the old one given back, its filters and limits, and
re-authentication. A session is ended with 26 if the newest service is
of another kind, 27 without a slot, or with what the authentication
says; sessions nobody is left to adopt are ended by the last service to
stop on the listener.

On Windows a send on a socket waited while another thread polled it,
which delayed udppm's answers by up to a second, and old UDP services
did not exit after a reload; with one thread per socket neither
happens, and the second socket bound to the service's address
(NO_SHARE_UDP_SOCKET) is gone from the code and the build files.

udpinit, the global udp_table, udpnext(), udppmchild() and
dnsprchild() are gone; udpsockmap() serves SOCKS5 UDP ASSOCIATE only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 14:57:35 +03:00
Vladimir Dubrovin
d83a48fe18 Share one listening socket among services on one address
Services of one configuration on the same address, port, network
namespace and device now share one listener and its socket, all
accepting on it, instead of each binding its own: on Linux the second
bind failed unless SO_REUSEPORT was set. A listener keeps a list of the
services accepting on it; the first to start opens the socket under the
listener's open_mutex, as binding may take long, and the others use it
("Accepting connections, shared"). The socket is closed once the last of
them stops.

Such services must be of one type with the same -ol options: otherwise
the configuration is refused ("a service of another type listens
there", "a service with other socket options listens there").

mainclaim() now runs for every service, at startup too: it joins the
listener of its configuration for the address, takes over one of an
older configuration (one of its type first), or makes a new one, under
one hold of listener_mutex so that a listener found is not freed before
it is joined.

Services connecting back (-r) to one place share a pseudo-listener
without a socket, of any type. After a reload a client moves to one of
the newest services of its type on its listener with a slot free: 26 if
there is none of its type, 27 if none has a slot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:31:50 +03:00
Vladimir Dubrovin
3520e6e7cf Hand listening sockets over on a reload
A service's TCP listening socket is kept as a listener: when a reload
commits, before the old services are told to stop, each new service
takes over the listener of an older configuration's service on the same
address, port, network namespace and device with the same -ol options.
It skips socket() and bind(), calling only listen() again for its own
backlog, and logs "Accepting connections, taken over". The old service
stops accepting at its next poll and lets go of the socket; whoever
lets go last closes it, unlinking a Unix socket's path.

So a service staying where it was no longer leaves a gap: before, the
old one closed its socket and the new one opened another, and a
connection queued on the old socket was reset. UDP services, whose
clients read from the service's socket, and two services of the same
configuration on one address keep their own sockets as before.

A test case makes requests nonstop through three reloads and wants none
refused or reset; against the build before this, connections were
reset. The reload case no longer waits out the switch. SIGUSR1 in
3proxy(8) describes how a reload behaves now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:14:04 +03:00
Vladimir Dubrovin
21ba6e9d0c Reload the configuration atomically
A reload reads the file into a new configuration, allocated from the
defaults, and prepares its services without starting them. Only if the
whole file is read without an error does it come into force: the old
configuration's services stop accepting, the new ones start. On an
error everything prepared is dropped and the old configuration, which
never stopped, stays in force.

Each service holds its configuration until it is freed, after its last
client; a configuration no longer in force is released when the last
holder lets go (confhold/confput). freeconf() now only releases what a
configuration holds, touching nothing global.

What runs without a service of its own reads the configuration in
force, runconf, rather than conf, which a reload points at the one
being read: the resolver, which holds it while it waits (a client
resolves with its own service's), the log, the thread pool, the admin
pages, which walk the services under config_mutex, and the signal
handlers.

The users table, havelog and the resolver choice are per configuration
now, the resolver applied when the configuration comes into force, so
a refused file leaves the users as they were. The log file, the
configuration file name, the string table, daemon mode and the filter
list belong to the process and are handed from one configuration to
the next. Settings left out of a new file go back to their defaults,
where before they kept the old values.

The gap between the old and the new listening sockets remains: a
connection queued on an old service's socket when it closes is reset.
Handing the socket over is the next phase.

A test case reloads a broken file (nothing changes, alice still gets
in, bob from the refused file does not) and a good one (bob only, the
service on its new port, the old one closed, a download through the
old service finishing whole). 40 reloads, a third refused, under load
show no memory errors under AddressSanitizer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 20:15:14 +03:00
Vladimir Dubrovin
796e9f8156 Fix memory leaks found under AddressSanitizer
- readconfig() kept its line buffer and argument array on every error
  return, so each refused reload leaked them.
- A filter refusing a connection in filter_client (TLS: a failed
  handshake) was not kept, so its filter_clear never ran and the state
  it made was lost. makefilters() now clears it, and empties the slot
  first: a pooled worker's slot may hold the previous connection's.
- ssl_filter_close() freed the client CA paths but not the server ones,
  for every TLS service set up.
- Compiled patterns were never freed: an ACL's (pcre: and regex: host
  names), an httpsrv rule's. copyacl() shared them between the
  configuration's ACL and each service's copy; each copy now compiles
  its own, and freeacl() and freehttprules() free them.

What LeakSanitizer still reports is OpenSSL's per-thread random
generator state of pooled threads, released only by OpenSSL at exit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 20:15:01 +03:00
Vladimir Dubrovin
d0e88a7b88 Optional kernel TLS with OpenSSL (ssl_ktls)
ssl_ktls asks OpenSSL to hand TLS to the kernel (SSL_OP_ENABLE_KTLS)
on the connections of the services which follow, both to clients and
to servers; ssl_noktls, the default, keeps it in 3proxy. Where the
library, the kernel and the cipher allow it, the kernel then encrypts
and decrypts, and SSL_read/SSL_write go on working over it. What a
service got is logged on its first TLS connection.

Reading ahead is left off where the kernel took receiving, which reads
a record at a time. A build whose library has no kernel TLS (wolfSSL,
OpenSSL before 3.0 or without it) warns and ignores the command.
splice() is not used for TLS services yet.

Tested on AlmaLinux 10 (OpenSSL 3.5.8, tls module): both directions
of both legs of a TLS chain in the kernel, the suite passing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:29:21 +03:00
Vladimir Dubrovin
737bdc7d24 Reach the configuration through a pointer
conf is now a pointer to the current configuration rather than the
structure itself: at first confboot, which exists before main() runs, as
plugins and the standalone services use it too; later configurations
will start from confdefaults. Both are made from confinit.h, the one list
of initial values. The timeouts are an array of the configuration
instead of a pointer to a global one. Nothing behaves differently yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 19:12:54 +03:00
Vladimir Dubrovin
8bd5c0f0fa Keep the values of numbered traffic counters across reloads
What a numbered counter counted now belongs to the process: a counter
rule points to the value of its number, created the first time the
number is met (from the counter file, if one is open) and shared by the
rules of that number in every configuration loaded. A reload no longer
resets it when there is no counter file, and once configurations can
outlive one another, clients of the old and the new one count into the
same value. An unnumbered counter, and those LdapPlugin makes, keep a
value of their own as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 19:05:59 +03:00
Vladimir Dubrovin
8887031324 Remove fields and declarations nothing uses
conf.haveerror was only initialised and srvparam.srvfds only declared;
the extern declarations of stdlog and demon named globals that do not
exist (both are fields of conf); a local in make_ace() and one in the
webadmin XML page were never used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:12:19 +03:00
Vladimir Dubrovin
a2592f4038 Keep the clock, timetoexit and needreload out of conf
They are the state of the process, not configuration: conf.time (now
curtime), timetoexit and needreload are globals of their own. Plugins
reach needreload through a pointer added at the end of struct
pluginlink; LdapPlugin uses it. The extern for a paused global, never
defined, goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:05:33 +03:00
Vladimir Dubrovin
3b2d664563 Keep the name servers and RADIUS servers in conf
nservers, numservers and authnserver (resolve.c, common.c) and
radiuslist, nradservers and radiussecret (authradius.c) were globals of
their own; they are configuration, set by nserver, authnserver and
radius, and now live in struct extparam with the rest of it.
MAXNSERVERS, MAXRADIUS and struct radserver move to structures.h, which
plugins include without proxy.h.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:39:37 +03:00
Vladimir Dubrovin
18c0ebda0f Remove dial on demand
dialer ran a program when a name could not be resolved, for dial-up
links; with nscache it did not even run. The command is still accepted
and ignored, so configurations using it keep loading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:36:23 +03:00
Vladimir Dubrovin
bdee95c7e0 Threads pool added 2026-10-12 22:40:41 +03:00
Vladimir Dubrovin
cc19bbff6d Unify Linux namespace operations 2026-10-12 18:18:27 +03:00
Vladimir Dubrovin
f1b8d30799 Load the time zone and connect syslog before chroot
The C library reads /etc/localtime on the first use of local time and
connects to /dev/log on the first syslog() call. With a chroot before
either, every local time became UTC and every syslog message was lost.
The time zone is now loaded before chroot() and openlog() connects at
once. The chroot entry of 3proxy.cfg(5) lists what PAM, LDAP and ODBC
still need inside the chroot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:16:37 +03:00
Vladimir Dubrovin
a20f646169 Pre-allocate client/server/tmp/etc buffers with client structure
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run
2026-10-12 17:19:55 +03:00
Vladimir Dubrovin
95fd3be6fa Reorganize service config parsing / main loop 2026-10-12 13:08:55 +03:00
Vladimir Dubrovin
36382bda96 Remove sleeps on proxy termination 2026-10-10 23:28:19 +03:00
Vladimir Dubrovin
bf1930789d parent: support fraction and % syntaxis for weight; support fallbacks with 0 weight
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Has been cancelled
2026-09-16 20:04:10 +03:00
Vladimir Dubrovin
5af6147a41 -Xftp flag for http proxy
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Has been cancelled
2026-08-29 23:53:59 +03:00
Vladimir Dubrovin
927b011bd4 http server implemented, pcre support for hostnames in acls implemented 2026-08-27 14:34:27 +03:00
Vladimir Dubrovin
7bc34002df Guard attempts to load TransparentPlugin
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run
Update version files / version (push) Has been cancelled
2026-08-26 17:06:08 +03:00
Vladimir Dubrovin
88b3225bdf Transparent moved to main code (TransparentPlugin removed), BSD pf support added 2026-08-26 14:34:44 +03:00
Vladimir Dubrovin
cb9effab9b Fix: insufficient default stack for wolfSSL with glibc 2026-08-25 19:07:20 +03:00
Vladimir Dubrovin
3526759e59 implement small http server for admin and testing 2026-08-25 17:21:33 +03:00
Vladimir Dubrovin
6ca4a2686d port range support (parent extport / intport) 2026-08-25 14:23:33 +03:00
Vladimir Dubrovin
4fb5c95704 Print error on non-zero local redirection in conf
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Has been cancelled
2026-08-12 17:08:09 +03:00
Vladimir Dubrovin
763e21e053 Fixed: maxchild dropped to 100 on config reload if not explicitly set, system-specific tuning hints added to doc 2026-08-01 10:22:03 +03:00
Vladimir Dubrovin
4877b39f2c Fix deadcode / warnings / minor bugs 2026-07-31 18:55:59 +03:00
Vladimir Dubrovin
5f1ed7363b Fix: race conditions / stack overflow on FreeBSD / minor bugs 2026-07-31 13:27:33 +03:00
Vladimir Dubrovin
4af02c9268 Fix: pcre/ssl command handlers broken in last commits
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
2026-07-26 15:51:55 +03:00
Vladimir Dubrovin
c94766dff7 Fix: dnspr was broken since udppm rewrite. -F (fake resolve to redirect traffic) option added to dnspr 2026-07-22 17:34:51 +03:00
Vladimir Dubrovin
9ab2e820b5 Added imapp, starttls support for smtpp, pop3p, tlspr 2026-07-22 16:15:50 +03:00
Vladimir Dubrovin
f173f8860d wolfSSL support added 2026-07-13 20:24:51 +03:00
Vladimir Dubrovin
289d2f5211 Use C89 style declarations 2026-05-22 18:57:23 +03:00
Vladimir Dubrovin
05c4832c6c Minor cleanups 2026-05-13 23:21:13 +03:00
Vladimir Dubrovin
381ef993a7 Minor logging improvement / code cleanup
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
2026-05-12 21:21:59 +03:00
Vladimir Dubrovin
5fdd4a4d6f NOODBC inverted to WITH_ODBC 2026-05-08 20:30:14 +03:00
Vladimir Dubrovin
6286bfcd6e Fix crypt passwords 2026-05-08 19:00:14 +03:00
Vladimir Dubrovin
b1d21cbdca Copyright update 2026-05-08 18:07:08 +03:00
Vladimir Dubrovin
8c638fcaff Revert usage of OpenSSL blake2 implementation 2026-05-08 16:45:44 +03:00
Vladimir Dubrovin
f8c22d5f91 Fix: symbols collision with openssl, could lead to crash
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
2026-05-08 14:03:47 +03:00
Vladimir Dubrovin
750bb38907 Do not fail on -n 2026-05-07 19:10:13 +03:00
Vladimir Dubrovin
0e13f57139 Allocate udp buffer dynamically 2026-05-06 22:45:00 +03:00
Vladimir Dubrovin
fbd1788f4c increase stack size 2026-05-04 21:34:13 +03:00
Vladimir Dubrovin
830b2d39d1 Use standard malloc functions
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
2026-05-04 18:50:02 +03:00
Vladimir Dubrovin
a338a0c689 Speedup passwords lists 2026-05-04 18:37:18 +03:00
Vladimir Dubrovin
8107f03062 Move PCRE/SSL to main code 2026-05-01 15:11:08 +03:00
Vladimir Dubrovin
a3fb7aff07 Clean up UDP code 2026-04-30 11:32:12 +03:00
Vladimir Dubrovin
b1ac46da79 Remove linux futext implementation
Some checks failed
Build Win32 3proxy-lite with Watcom / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
Build Win32 3proxy with MSVC / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
Build Win64 3proxy with MSVC / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
Build Win-arm64 3proxy with MSVC / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
2026-04-28 18:06:54 +03:00