From 5a86c7a637da1467c9890d31aaccdf4c428dd87d Mon Sep 17 00:00:00 2001 From: Sadeep Madurange Date: Wed, 12 Aug 2026 23:29:03 +0800 Subject: Lock-file semaphore for CGI script. --- lex.cgi | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) (limited to 'lex.cgi') diff --git a/lex.cgi b/lex.cgi index 9c11b28..797fa1c 100755 --- a/lex.cgi +++ b/lex.cgi @@ -2,13 +2,14 @@ use strict; use warnings; +use Email::MIME; +use Fcntl qw(:flock); use File::Spec; use File::Find; use File::Path qw(make_path); -use Time::HiRes qw(time); -use Email::MIME; use OpenBSD::Pledge; use OpenBSD::Unveil; +use Time::HiRes qw(time); my $start_time = time(); @@ -43,8 +44,9 @@ unveil("/dev/null", "rw") or die "unveil /dev/null failed: $!"; unveil($base_dir, "rwc") or die "unveil $base_dir failed: $!"; unveil() or die "unveil lock failed: $!"; -pledge('stdio rpath wpath cpath') or die "pledge failed: $!"; +pledge('stdio rpath wpath cpath flock') or die "pledge failed: $!"; +my $dop = 5; my $log_file = "$base_dir/debug.log"; my $max_log_bytes = 1024 * 1024; # 1 MB cap @@ -107,6 +109,40 @@ sub verify_pgp_signature { return $verified ? 1 : 0; } +sub acquire_lock { + my ($max_slots) = @_; + my $lock_dir = "$base_dir/locks"; + + unless (-d $lock_dir) { + make_path($lock_dir) or do { + log_msg("ERROR: Failed to create lock dir $lock_dir: $!"); + return undef; + }; + } + + for my $i (1 .. $max_slots) { + my $slot_file = "$lock_dir/slot_$i.lock"; + my $fh; + + unless (open($fh, '>>', $slot_file)) { + next; + } + + if (flock($fh, LOCK_EX | LOCK_NB)) { + return $fh; + } + close($fh); + } + + return undef; # All slots full +} + +my $lock_fh = acquire_lock($dop); +unless ($lock_fh) { + log_msg("WARN: Concurrency limit ($dop) reached. Dropping request."); + respond_ok(); +} + my $content_type = $ENV{'CONTENT_TYPE'} // ''; my $content_length = $ENV{'CONTENT_LENGTH'} // 0; -- cgit v1.2.3