You declare a Bro function
type using:
where argument is a (possibly empty) comma-separated list of arguments, and the final “function(
argument*)
:
type
:
type” declares the return type of the function.
It is optional; if missing, then the function does not return a value.
Each argument is declared using:
param-name :
type
So, for example:
function(a: addr, p: port): string
corresponds to a function that takes two parameters, a
of type
addr
and p
of type port
, and returns a value of
type string
.
You could furthermore declare:
global generate_id: function(a: addr, p: port): string;
to define generate_id
as a variable of this type. Note that
the declaration does not define the body of the function,
and, indeed, generate_id
could have different function bodies
at different times, by assigning different function values to it.
When defining a function including its body, the syntax is slightly different:
function func-name ( argument* ) [ : type ] { statement* }
That is, you introduce func-name, the name of the function, between
the keywork function
and the opening parenthesis of the argument
list, and you list the statements of the function within braces at the end.
For the previous example, we could define its body using:
function generate_id(a: addr, p: port): string { if ( a in local_servers ) # Ignore port, they're always the same. return fmt("server %s", a); if ( p < 1024/tcp ) # Privileged port, flag it. return fmt("%s/priv-%s", a, p); # Nothing special - default formatting. return fmt("%s/%s", a, p); }
We also could have omitted the first definition; a function definition
like the one immediately above automatically defines generate_id
as a function of type function(a: addr, p: port): string
. Note
though that if func-name was indeed already declared, then the
argument list much match exactly that of the previous definition.
This includes the names of the arguments; Unlike in C, you cannot change
the argument names between their first (forward) definition and the
full definition of the function.
You can also define functions without using any name. These are referred to as are a type of expression.
You can only do two things with functions: or assign them. As an example of the latter, suppose we have:
local id_funcs: table[conn_id] of function(p: port, a: addr): string;
would declare a local variable indexed by a
same type as in the previous example. You could then execute:
id_funcs[c$id] = generate_id
or call whatever function is associated with a given conn_id
:
print fmt("id is: %s", id_funcs[c$id](80/tcp, 1.2.3.4));