summaryrefslogtreecommitdiff
path: root/FS/bin/freeside-sqlradius-radacctd
blob: 7b2d04dc7348977be8e5dfd512ed1e7d6f9b3eea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/perl -w

use strict;
use vars qw( @part_export );
use subs qw(myshutdown);
use POSIX qw(:sys_wait_h);
#use IO::File;
use FS::Daemon qw(daemonize1 drop_root logfile daemonize2 sigint sigterm);
use FS::UID qw(adminsuidsetup); #forksuidsetup driver_name dbh myconnect);
use FS::Record qw(qsearch); # qsearchs);
use FS::part_export;
use FS::part_export::sqlradius;
#use FS::svc_acct;
#use FS::cust_svc;

my $user = shift or die &usage;

#daemonize1('freeside-sqlradius-radacctd', $user); #keep unique pid files w/multi installs
daemonize1('freeside-sqlradius-radacctd');

drop_root();

#$ENV{HOME} = (getpwuid($>))[7]; #for ssh

adminsuidsetup $user;

logfile( "%%%FREESIDE_LOG%%%/sqlradius-radacctd-log.". $FS::UID::datasrc );

daemonize2();

#--

my @part_export = FS::part_export::sqlradius->all_sqlradius_withaccounting();

die "no sqlradius, sqlradius_withdomain, radiator or phone_sqlradius exports".
    " without ignore_accounting"
  unless @part_export;

while (1) {

  #fork off one kid per export (machine)
  # _>{'_radacct_kid'} is an evil kludge
  foreach my $part_export ( grep ! $_->{'_radacct_kid'}, @part_export ) {
 
    defined( my $pid = fork ) or do {
      warn "WARNING: can't fork to spawn child for ". $part_export->machine;
      next;
    };

    if ( $pid ) {
      $part_export->{'_radacct_kid'} = $pid;
      warn "child $pid spawned for ". $part_export->machine;
    } else { #kid time

      adminsuidsetup($user); #get our own db handle

      until ( sigint || sigterm ) {
        $part_export->update_svc();
        sleep 1;
      }

      warn "child for ". $part_export->machine. " done";
      exit;

    } #eo kid

  }

  #reap up any kids that died...
  &reap_kids;

  myshutdown() if sigterm() || sigint();

  sleep 5;
}

#-- 

sub myshutdown {
  &reap_kids;

  #kill all the kids
  kill 'TERM', $_ foreach grep $_, map $_->{'_radacct_kid'}, @part_export;

  my $wait = 12; #wait up to 1 minute
  while ( ( grep $_->{'_radacct_kid'}, @part_export ) && $wait-- ) {
    warn "waiting for children to terminate";
    sleep 5;
    &reap_kids;
  }
  warn "abandoning children" if grep $_->{'_radacct_kid'}, @part_export;
  die "exiting";
}

sub reap_kids {
  #warn "reaping kids\n";
  foreach my $part_export ( grep $_->{'_radacct_kid'}, @part_export ) {
    my $pid = $part_export->{'_radacct_kid'};
    my $kid = waitpid($pid, WNOHANG);
    if ( $kid > 0 ) {
      $part_export->{'_radacct_kid'} = '';
    }
  }
  #warn "done reaping\n";
}

sub usage {
  die "Usage:\n\n  freeside-sqlradius-radacctd user\n";
}

=head1 NAME

freeside-sqlradius-radacctd - Real-time radacct import daemon

=head1 SYNOPSIS

  freeside-sqlradius-radacctd username

=head1 DESCRIPTION

Imports records from an the SQL radacct tables of all sqlradius, 
sqlradius_withdomain and radiator exports (except those with the
ignore_accounting flag) and updates the following fields in svc_acct (see
L<FS::svc_acct>) for each account: last_login, last_logout, seconds,
upbytes, downbytes, totalbytes.  Runs as a daemon and updates the database
in real-time.

B<username> is a username added by freeside-adduser.

=head1 RADIUS DATABASE CHANGES

In 1.7.4+, freeside-upgrade should have taken care of these changes already.

ALTER TABLE radacct ADD COLUMN FreesideStatus varchar(32) NULL;

If you want to ignore the existing accountg records, also do:

UPDATE radacct SET FreesideStatus = 'done' WHERE FreesideStatus IS NULL;

=head1 SEE ALSO

=cut

1;