diff options
author | ivan <ivan> | 2005-04-25 09:33:35 +0000 |
---|---|---|
committer | ivan <ivan> | 2005-04-25 09:33:35 +0000 |
commit | beba6672fb9c9c5769c81f8029bb88cd2bc910e9 (patch) | |
tree | f771eb9b9e470deea0374e173cd66a0be4dbf847 /FS/FS | |
parent | 3d08b7bbf79c0131497d4812c552efe8a89d4cf3 (diff) |
pick up freeside-sqlradius-radacctd again after all these years, now it just needs to update the "seconds" field(s), finally closes: Bug#1125
Diffstat (limited to 'FS/FS')
-rw-r--r-- | FS/FS/Conf.pm | 7 | ||||
-rw-r--r-- | FS/FS/Daemon.pm | 91 | ||||
-rw-r--r-- | FS/FS/part_export/sqlradius.pm | 83 | ||||
-rw-r--r-- | FS/FS/svc_acct.pm | 35 |
4 files changed, 215 insertions, 1 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index eb02ff12a..8ca2c1ba2 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1448,6 +1448,13 @@ httemplate/docs/config.html 'type' => [qw( checkbox textarea )], }, + { + 'key' => 'svc_acct-usage_suspend', + 'section' => 'billing', + 'description' => 'Suspends the package an account belongs to when svc_acct.seconds is decremented to 0 or below (accounts with an empty seconds value are ignored). Typically used in conjunction with prepaid packages and freeside-sqlradius-radacctd.', + 'type' => 'checkbox', + }, + ); 1; diff --git a/FS/FS/Daemon.pm b/FS/FS/Daemon.pm new file mode 100644 index 000000000..3e64f79e9 --- /dev/null +++ b/FS/FS/Daemon.pm @@ -0,0 +1,91 @@ +package FS::Daemon; + +use vars qw( @ISA @EXPORT_OK ); +use vars qw( $pid_dir $me $pid_file $sigint $sigterm $logfile ); +use Exporter; +use Fcntl qw(:flock); +use POSIX qw(setsid); +use Date::Format; + +#this is a simple refactoring of the stuff from freeside-queued, just to +#avoid duplicate code. eventually this should use something from CPAN. + +@ISA = qw(Exporter); +@EXPORT_OK = qw( daemonize1 drop_root daemonize2 sigint sigterm logfile ); + +$pid_dir = '/var/run'; + +sub daemonize1 { + $me = shift; + + $pid_file = "$pid_dir/$me"; + $pid_file .= '.'.shift if scalar(@_); + $pid_file .= '.pid'; + + chdir "/" or die "Can't chdir to /: $!"; + open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; + defined(my $pid = fork) or die "Can't fork: $!"; + if ( $pid ) { + print "$me started with pid $pid\n"; #logging to $log_file\n"; + exit unless $pid_file; + my $pidfh = new IO::File ">$pid_file" or exit; + print $pidfh "$pid\n"; + exit; + } + + #sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; } + #$SIG{CHLD} = \&REAPER; + $sigterm = 0; + $sigint = 0; + $SIG{INT} = sub { warn "SIGINT received; shutting down\n"; $sigint++; }; + $SIG{TERM} = sub { warn "SIGTERM received; shutting down\n"; $sigterm++; }; +} + +sub drop_root { + my $freeside_gid = scalar(getgrnam('freeside')) + or die "can't find freeside group\n"; + $) = $freeside_gid; + $( = $freeside_gid; + #if freebsd can't setuid(), presumably it can't setgid() either. grr fleabsd + ($(,$)) = ($),$(); + $) = $freeside_gid; + + $> = $FS::UID::freeside_uid; + $< = $FS::UID::freeside_uid; + #freebsd is sofa king broken, won't setuid() + ($<,$>) = ($>,$<); + $> = $FS::UID::freeside_uid; +} + +sub daemonize2 { + open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!"; + setsid or die "Can't start a new session: $!"; + open STDERR, '>&STDOUT' or die "Can't dup stdout: $!"; + + $SIG{__DIE__} = \&_die; + $SIG{__WARN__} = \&_logmsg; + + warn "$me starting\n"; +} + +sub sigint { $sigint; } +sub sigterm { $sigterm; } + +sub logfile { $logfile = shift; } #_logmsg('test'); } + +sub _die { + my $msg = shift; + unlink $pid_file if -e $pid_file; + _logmsg($msg); +} + +sub _logmsg { + chomp( my $msg = shift ); + my $log = new IO::File ">>$logfile"; + flock($log, LOCK_EX); + seek($log, 0, 2); + print $log "[". time2str("%a %b %e %T %Y",time). "] [$$] $msg\n"; + flock($log, LOCK_UN); + close $log; +} + diff --git a/FS/FS/part_export/sqlradius.pm b/FS/FS/part_export/sqlradius.pm index b9fef2079..03802b2a7 100644 --- a/FS/FS/part_export/sqlradius.pm +++ b/FS/FS/part_export/sqlradius.pm @@ -2,8 +2,10 @@ package FS::part_export::sqlradius; use vars qw(@ISA $DEBUG %info %options $notes1 $notes2); use Tie::IxHash; -use FS::Record qw( dbh ); +use FS::Record qw( dbh qsearch ); use FS::part_export; +use FS::svc_acct; +use FS::export_svc; @ISA = qw(FS::part_export); @@ -466,5 +468,84 @@ sub usage_sessions { } +=item update_svc_acct + +=cut + +sub update_svc_acct { + my $self = shift; + + my $dbh = sqlradius_connect( map $self->option($_), + qw( datasrc username password ) ); + + my @fields = qw( radacctid username realm acctsessiontime ); + + my @param = (); + my $where = ''; + + my $sth = $dbh->prepare(" + SELECT RadAcctId, UserName, Realm, AcctSessionTime + FROM radacct + WHERE FreesideStatus IS NULL + AND AcctStopTime != 0 + ") or die $dbh->errstr; + $sth->execute() or die $sth->errstr; + + while ( my $row = $sth->fetchrow_arrayref ) { + my($RadAcctId, $UserName, $Realm, $AcctSessionTime) = @$row; + warn "processing record: ". + "$RadAcctId ($UserName\@$Realm for ${AcctSessionTime}s" + if $DEBUG; + + my %search = ( 'username' => $UserName ); + my $extra_sql = ''; + if ( ref($self) =~ /withdomain/ ) { #well... + $extra_sql = " AND '$Realm' = ( SELECT domain FROM svc_domain + WHERE svc_domain.svcnum = svc_acct.domsvc ) "; + my $svc_domain = qsearch + } + + my @svc_acct = + grep { qsearch( 'export_svc', { 'exportnum' => $self->exportnum, + 'svcpart' => $_->cust_svc->svcpart, } ) + } + qsearch( 'svc_acct', + { 'username' => $UserName }, + '', + $extra_sql + ); + + my $errinfo = "for RADIUS detail RadAcctID $RadAcctId ". + "(UserName $UserName, Realm $Realm)"; + my $status = 'skipped'; + if ( !@svc_acct ) { + warn "WARNING: no svc_acct record found $errinfo - skipping\n"; + } elsif ( scalar(@svc_acct) > 1 ) { + warn "WARNING: multiple svc_acct records found $errinfo - skipping\n"; + } else { + my $svc_acct = $svc_acct[0]; + warn "found svc_acct ". $svc_acct->svcnum. " $errinfo\n" if $DEBUG; + if ( $svc_acct->seconds !~ /^$/ ) { + warn " svc_acct.seconds found (". $svc_acct->seconds. + ") - decrementing\n" + if $DEBUG; + $svc_acct->decrement_seconds($AcctSessionTime); + $status = 'done'; + } else { + warn " no existing seconds value for svc_acct - skiping\n" if $DEBUG; + } + } + + warn "setting FreesideStatus to $status $errinfo\n" if $DEBUG; + my $psth = $dbh->prepare("UPDATE radacct + SET FreesideStatus = ? + WHERE RadAcctId = ?" + ) or die $dbh->errstr; + $psth->execute($status, $RadAcctId) or die $psth->errstr; + + } + +} + 1; diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index d806fe9bc..1daf83a32 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -1120,6 +1120,41 @@ sub acct_snarf { qsearch('acct_snarf', { 'svcnum' => $self->svcnum } ); } +=item decrement_seconds SECONDS + +Decrements the I<seconds> field of this record by the given amount. + +=cut + +sub decrement_seconds { + my( $self, $seconds ) = @_; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $sth = dbh->prepare( + 'UPDATE svc_acct SET seconds = seconds - ? WHERE svcnum = ?' + ) or die dbh->errstr;; + $sth->execute($seconds, $self->svcnum) or die $sth->errstr; + if ( $conf->exists('svc_acct-usage_suspend') + && $self->seconds - $seconds <= 0 ) { + #my $error = $self->suspend; + my $error = $self->cust_svc->cust_pkg->suspend; + die $error if $error; + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + +} + =item seconds_since TIMESTAMP Returns the number of seconds this account has been online since TIMESTAMP, |