# /usr/local/freeradius/etc/raddb/sites-enabled/default
preacct {
    fillrealm
    acct_unique
}

accounting {
    sql
    billing
    detail
}

# /usr/local/freeradius/etc/raddb/modules/acct_unique
acct_unique {
    key = "Calling-Station-Id, Acct-Session-Id, 3GPP2-Correlation-Id"
}

# /usr/local/freeradius/etc/raddb/modules/detail
detail {
    detailfile = ${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d
    detailperm = 0600
}

# /usr/local/freeradius/etc/raddb/modules/exec
exec billing {
    wait = no
    program = "/usr/local/freeradius/scripts/billing.pl"
    input_pairs = request
}

# /usr/local/freeradius/etc/raddb/modules/realm
realm fillrealm {
    format = suffix
    delimiter = "@"
}

# /usr/local/freeradius/etc/raddb/radiusd.conf
...
thread pool {
    start_servers = 5
    max_servers = 32
    min_spare_servers = 3
    max_spare_servers = 10
    max_requests_per_server = 0
}

modules {
    $INCLUDE ${confdir}/modules/
    $INCLUDE sql.conf
}

$INCLUDE sites-enabled/

# /usr/local/freeradius/scripts/billing.pl
#!/usr/bin/perl

use strict;
use POSIX ':sys_wait_h';
require '/usr/local/freeradius/scripts/inc/common.pm';
require '/usr/local/freeradius/scripts/inc/mysql.pm';
require '/usr/local/freeradius/scripts/inc/tibrv.pm';

my $pid = fork();
unless (defined $pid) {
    common::log("Error: top level fork() failed: $!");
    exit(1);
}
# exit in parent, become child of init
exit(0) if ($pid);
# 2nd level fork in child
$pid = fork();
unless (defined $pid) {
    common::log("Error: 2nd level fork() failed: $!");
    exit(1);
}
if ($pid > 0) {
    # wait for child exit code
    waitpid($pid, 0);
    exit(0);
}
# do the main job in 2nd level child
...
