How-to: Write an Asterisk Module, Part 3

Greetings fellow developers!

This is part 3 of a series on implementing the basic interfaces to provide features to Asterisk.

Part 1 – Basic Module Structure
Part 2 – CDR Handling Interface

In this section, you will see how to implement an Asterisk CLI command. CLI commands are extremely useful for showing configuration, statistics, and other debugging purposes.

We are going to continue editing the module from part 2, res_helloworld2.c.

The first step is to include the header file which defines the CLI command interface.

#include "asterisk/cli.h"

Here is the code for a CLI command, “echo”. It simply prints back the first argument to the CLI command. The individual parts of this function will be described later.

static char *handle_cli_echo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
    switch (cmd) {
    case CLI_INIT:
        e->command = "echo";
        e->usage =
            "Usage: echo <stuff>n"
            "       Print back the first argument.n"
            "Examples:n"
            "       echo foon"
            "       echo "multiple words"n"
            "";
        return NULL;
    case CLI_GENERATE:
        return NULL;
    }

    if (a->argc == e->args) {
        ast_cli(a->fd, "You did not provide an argument to echonn");
        return CLI_SHOWUSAGE;
    }

    ast_cli(a->fd, "%sn", a->argv[1]);

    return CLI_SUCCESS;
}

The first line of this CLI handler matches the defined function prototype for CLI command handlers. The ast_cli_entry argument includes static information about the CLI command being executed. The cmd argument is set when the CLI command is being invoked for a reason other than normal execution from the CLI, which will be explained more later. The ast_cli_args argument contains information specific to this one time execution of the command, like the arguments to the command.

static char *handle_cli_echo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

The switch statement at the beginning of the function handles when the cmd argument is set to indicate that the function is being called for a reason other than normal execution. There are two cases handled.

  • CLI_INIT. Every CLI command handler is called one time with a cmd of CLI_INIT. This asks the function to fill in the documentation on what the command is, as well as usage documentation.
  • CLI_GENERATE. This cmd is used for implementing tab completion. CLI commands that provide tab completion of arguments must add code here. Implementing tab completion may be explained in a later tutorial. For now, there are many examples throughout the code.

The next code snippet ensures that at least one argument has been provided to the function. It is worth noting here that the ast_cli_entry argument is used to retrieve how many arguments define the command itself and the ast_cli_args argument is used to retrieve how many arguments were actually specified at the CLI when executing this command. If they are equal, then simply “echo” was provided.

if (a->argc == e->args) {
ast_cli(a->fd, "You did not provide an argument to echonn");
return CLI_SHOWUSAGE;
}

Finally, we print a single argument to the CLI, and return that the execution of the CLI command was successful.

ast_cli(a->fd, "%sn", a->argv[1]);
return CLI_SUCCESS;

The next thing that we have to add is the table of CLI commands included in this module. We will use AST_CLI_DEFINE() to add a single entry to this table. AST_CLI_DEFINE includes the pointer to the CLI command handling function, as well as a brief summary of what the command does.

static struct ast_cli_entry cli_helloworld[] = {
AST_CLI_DEFINE(handle_cli_echo, "Echo to the CLI"),
};

Finally, as discussed in part 2, we have to modify load_module and unload_module to register and unregister the CLI command table with the Asterisk core.

In unload_module, we add this:

ast_cli_unregister_multiple(cli_helloworld, ARRAY_LEN(cli_helloworld));

In load_module, we add this:

ast_cli_register_multiple(cli_helloworld, ARRAY_LEN(cli_helloworld));

That’s it! Recompile and reinstall the module. Take a look at res_helloworld3.c, for the completed code.

You can then try it out.

*CLI> help echo
Usage: echo 
       Print back the first argument.
Examples:
       echo foo
       echo "multiple words"

*CLI> echo
You did not provide an argument to echo

Usage: echo 
       Print back the first argument.
Examples:
       echo foo
       echo "multiple words"

*CLI> echo foo
foo

*CLI> echo hello world
hello

*CLI> echo "hello world"
hello world

10 thoughts on “How-to: Write an Asterisk Module, Part 3

  1. Pingback: Programando módulos personalizados para Asterisk at Mi Brain-Training Personal

  2. Congratulations for your article.
    You could talk about connections to databases, such as Oracle for example?

    Thanks a lot.

  3. Hello Russel, thanks for the nice tutorials series.

    How do I get the .c file for this ‘part 3’? I tried the link, but got a ‘no permissions to read file’.

  4. Hi

    Haven’t found an answer anywhere else so thought that I would ask here. Is it possible to compile a newer version of the chan_iax.c module (2.6.2.6) for an earlier verison of 2.6.1.4? I’m hoping that I could just drop in the newer code. And how to do this? TIA

  5. Hi Russell,

    I’m considering trying Asterisk for a very particular purpose…

    If I call home and then type “0” the computer do something (for instance, start an application), if I type, for instance “3”, the computer do another thing…

    Its just a simple remote controller. Is it possible? Could you please tell me where to start?

    Thanks in advance!

    Best regards,
    Fernando Rocha

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s