not logged in | [Login]
Always use radiusd -X
when debugging!
The goal is to have consistent, clear code. All code should share a common style, format, choice of function / variable names, etc. This means that people looking at the code see the code, and not the wildly different coding styles.
Code should be commented. There are over 100K LoC in the server, and it's impossible to always remember why things are done the way they are. The comments should explain the choices behind the code, the goal, or philosophy, or the "gotcha's".
Function documentation should be doxygen style. Below is an example of doxygen function documentation, use it as a guide when writing your own.
/** Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser
*
* @param out Where to write the ip address value.
* @param value to parse.
* @param inlen Length of value, if value is \0 terminated inlen may be -1.
* @param resolve If true and value doesn't look like an IP address, try and resolve value as a
* hostname.
* @return
* - 0 if ip address was parsed successfully.
* - -1 on failure.
*/
Nouns should always precede verbs <prefix>_<noun>_<verb>[_<verb qualifiers>]
.
Good
fr_request_alloc()
fr_dict_find_by_name()
python_interp_exec()
Bad
do_python()
rest_parse_pairs()
Name components should be separated by underscores.
frPairFind
-> badfrpairfind
-> badfr_pairfind
-> badfr_pair_find
-> goodfr_
All functions in the protocol library should be prefixed with fr
. The rationale is that as libfreeradius is a library intended to be used by 3rd party applications it requires a namespace to avoid conflicts.
<group>_
Functions in the server library should not have a global prefix, but should use a common prefix i.e. functions which manipulate value pairs should use the pair_
prefix, dictionary functions should use the dict_
prefix.
Public functions should use the mod_
prefix, e.g. mod_authorize
, mod_authentication
, mod_instantiate
. If the module uses its own library, those functions should be prefixed with the name of the module e.g. python_
, rest_
, eap_
.
Ideally, all of the functions in a module should be static
. If they cannot be that, the function name prefixes given above are required.
Library and structure initialisations functions should use the verb init
. Functions that initialise structures should expect them to contain garbage values (be uninitialised).
Structure allocation functions should use the verb alloc
. create
should not be used.
Explicit free
or destroy
functions should be avoided, and talloc destructors used wherever possible. Talloc destructor functions should be static and be prefixed with _
to mark them as private e.g. _fr_pair_free()
Callbacks should be prefixed with a _
to mark them as private e.g. int _my_comparator(int a, int b)
.
bool
is used where the function is answering a true/false question. A good example is the is_whitespace
function, which checks if the entire string is made up of whitespace.
bool is_whitespace(char const *value)
{
do {
if (!isspace(*value)) return false;
} while (*++value);
return true;
}
Should be used for most functions. Negative integers indicate failure, zero indicates success, positive integers indicate success with caveats.
If you find a function returns significant (>= 4) numbers of different integer values, you should define C preprocessor macros, and an enum type so that it's clear in calling code what the different values mean.
typedef enum {
FUNC_RCODE_SUCCESS = 0,
FUNC_RCODE_NO_MEMORY = -1,
FUNC_RCODE_BAD_ARGUMENTS0 = -2,
FUNC_RCODE_BAD_ARGUMENTS1 = -3
} func_rcode_t;
func_rcode_t my_function(int arg0, int arg1)
{
void *mem;
mem = talloc(NULL, void);
if (!mem) return FUNC_RCODE_NO_MEMORY;
if (arg0 > 10) return FUNC_RCODE_BAD_ARGUMENTS0;
if (arg1 > 10) return FUNC_RCODE_BAD_ARGUMENTS1;
return FUNC_RCODE_SUCCESS;
}
Used only for allocation functions where there's a single simple failure mode (in which case NULL is returned).
my_structure_t *simple_memory_alloc(TALLOC_CTX *ctx, int arg0, int arg1)
{
return talloc(ctx, my_structure_t);
}
For more complicated failures the function should return an integer, and write a pointer to the allocated memory via one of the arguments.
int complicated_memory_alloc(TALLOC_CTX *ctx, my_structure_t **out, int arg0, int arg1)
{
my_structure_t *structure.
if (arg0 == 0) {
fr_strerror_printf("Invalid parameter, arg0 must be greater than 0");
return -2;
}
structure = talloc(ctx, my_structure_t);
if (!structure) return -1;
return 0;
}
Arguments should be in the following order
For modules the instance data pointer should be directly before the REQUEST *
pointer.
Last edited by Arran Cudbard-Bell (arr2036), 2021-01-21 17:30:45
Sponsored by Network RADIUS