14. Execution sequence and hook processing

This section describes when and how hooks are processed.
Radiator supports Perl hooks in many places in the configuration file. A hook is a piece of Perl code (in fact a Perl subroutine) that is run by Radiator at specified times. This allows the administrator to add custom code to handle unique or special processing requirements at run-time.
Hooks are specified verbatim or by file name in the Radiator configuration file.
Hooks are parsed by Perl at startup time, when the Radiator configuration file is read or re-read. Any syntax or compile-time errors in the hook are reported at that time.
Hooks are run at their specified times inside a Perl eval. This means that run-time errors, or a perl die() command results in a ERROR level message logged by Radiator.
Each hook is passed a set of run-time arguments, which depend on the type of hook being called. Arguments might include, for example, a reference to the request currently being processed, allowing the custom code to inspect and depend on the contents of the request. Hook arguments are documented separately for each hook.
The code for a hook can be placed verbatim in the configuration file:
UserPasswordHook sub {return $_[1]->{'GN'}}
Extend it over several lines using backslash line ending:
ConnectionHook sub {$_[1]->func(-access_mode => 'read_write',\
      -isolation_level => 'read_committed',\
      -lock_resolution => 'wait',\
      'ib_set_tx_param')}
You can also place the hook code in a separate external file that is named in the configuration file:
AcctHook file:"%d/hooks/sqlradacct.pl"
The code in the external file looks like this:
# Contents of file sqlradacct.pl:
sub
{
      use DBI;
      my ($p, $rp, $handled, $reason) = @_;
      ........
}
Tip
An external file can define several Perl functions that can be called from other functions in that file, or by another hook.
The standard hooks are:
Note that arguments preceded by '\' are passed by reference. You need to dereference them to get at the actual parameter. It is done this way to enable you to switch the object it points to. In any case, to reference the request in, such as PreClientHook, you would need to refer to it as ${$_[0]}, and the second argument to a hook would be accessed as ${$_[1]}, etc. For example, to get an attribute from the request in PreClientHook, you would use something like:
my $modtype = ${$_[0]}->get_attr('USR-Modulation-Type');
Some example hooks are found in goodies/hooks.txt in your distribution.
Hooks are executed at fixed times during request processing:
  1. Server started
  2. StartupHook called
  3. Radiator waits for requests
  4. Request received from NAS
  5. Global RewriteUsernames applied
  6. PreClientHook called
  7. Client clause selected
  8. Global ClientHook called
  9. Client-specific ClientHook called
  10. Client RewriteUsernames applied
  11. Duplicate detection done
  12. PreHandlerHook called
  13. Handler selected
  14. PreProcessingHook called
  15. Handler's RewriteUsername and RewriteFunction applied
  16. Session database updated (accounting requests only)
  17. Accounting log files (AcctLogFileName and WtmpFileName) written
  18. PreAuthHook called
  19. AuthBy clauses invoked. AuthBy SQL may call PostAuthSelectHook, AuthBy LDAP2 may call PostSearchHook and other AuthBys may call their specific hooks. AuthBy-specific PostAuthHook called after each AuthBy
  20. Handler-specific PostAuthHook called
  21. Statistics updated
  22. PostProcessingHook called (if there is a reply to be sent)
  23. AuthLog and AcctLog called
  24. Reply sent to NAS (unless request was proxied)
  25. Reply received from proxy server (if the request was proxied to another RADIUS server...)
  26. ReplyHook called
  27. PostProcessingHook called
  28. Reply sent to NAS
  29. If no reply was received from a proxy server by <AuthBy RADIUS>, even after multiple retransmissions and timeouts, CacheReplyHook is called (if CachePasswords is specified), then NoReplyHook is called.
  30. After all requests have been satisfied and timers run at the end of the main loop, MainLoopHook is run. Typically this happens once per second.
  31. ShutdownHook called after receiving a SIGTERM and before exiting.