Go to main content

Remote Administration Daemon Developer's Guide

Exit Print View

Updated: April 2020
 
 

RAD APIs in C

This section describes the APIs that are available for C language.

Entry Points in C

All entry points take a pointer to the object instance and a pointer to the internal structure for the method or attribute. The object instance pointer is essential for distinguishing different objects that implement the same interface. The internal structure pointer is theoretically useful for sharing the same implementation across multiple methods or attributes, but isn't used and may be removed.

Additionally, all entry points return a conerr_t. If the access is successful, they should return CE_OK.

If the access fails due to a system error or a module defined error, they should return the respective error codes. For more information about the error codes, see Error Codes in C.

If an expected error occurs and an error payload is defined, it may be set in *error. The caller will unref the error object when it is done with it.

  • A method entry point has the type meth_invoke_f:

    typedef conerr_t (meth_invoke_f)(rad_instance_t *inst, adr_method_t *meth,
        adr_data_t **result, adr_data_t **args, int count, adr_data_t **error);

    args is an array of count arguments.

    Upon successful return, *result should contain the return value of the method, if any.

    The entry point for a method named METHOD in interface INTERFACE is named interface_INTERFACE_invoke_METHOD.

  • An attribute read entry point has the type attr_read_f:

    typedef conerr_t (attr_read_f)(rad_instance_t *inst, adr_attribute_t *attr, 
    adr_data_t **value, adr_data_t **error);

    Upon successful return, *value should contain the value of the attribute, if any.

    The read entry point for an attribute named ATTR in interface INTERFACE is named interface_INTERFACE_read_ATTR.

  • An attribute write entry point has the type attr_write_f:

    typedef conerr_t (attr_write_f)(rad_instance_t *inst, adr_attribute_t *attr,
        adr_data_t *newvalue, adr_data_t **error);

    newvalue points to the new value. If the attribute is nullable, newvalue can be NULL.

    The write entry point for an attribute named ATTR in interface INTERFACE is named interface_INTERFACE_write_ATTR.

rad explicitly checks the types of all arguments passed to methods and all values written to attributes. Stub implementations can assume that all data provided is of the correct type. Stub implementations are responsible for returning valid data. Returning invalid data results in an undefined behavior.

Error Codes in C

RAD distinguishes errors as system errors and module defined errors.

System Errors

If the access fails due to a system error, the entry points should return one of the following error codes:

  • CE_SYSTEM - An operation fails due to a system error. This error code should not have payload.

  • CE_NOTFOUND - The retrieve operation fails because the object does not exist. This error code should not have payload.

  • CE_EXISTS - The create operation fails because the object already exists. This error code should not have payload.

  • CE_PRIV - An operation fails due to insufficient privileges. This error code should not have payload.

  • CE_NOMEM - An operation fails due to insufficient memory. This error code should not have payload.

Module Defined Errors

If the access fails due to an expected error as described in the API definition, the entry points should return CE_OBJECT. If an expected error occurs and an error payload is defined, it may be set in *error.


Note -  Do not use the CE_MISMATCH and the CE_ILLEGAL error codes. If there is any data type mismatch error or an illegal access error, return the CE_OBJECT error code with a payload describing the illegal arguments.

Global Variables in C

Variables
Description
boolean_t rad_isproxy
A flag to determine if code is executing in the main or proxy rad daemon. Only special system modules, which are integral to the operation of RAD, may use this variable.
rad_container_t
*rad_container
The rad container that contains the object instance.

RAD Module Registration in C

Function
Description
int _rad_init(void *handle);
A module must provide a _rad_init. This is called by the RAD daemon when the module is loaded and is a convenient point for module initialization including registration. Return 0 to indicate that the module successfully initialized.
int rad_module_register(void *handle, int version, rad_modinfo_t *modinfo);
rad_module_register provides a handle, which is the handle provided to the module in the call to _rad_init. This handle is used by the RAD daemon to maintain the private list of loaded modules. The version indicates which version of the rad module interface the module is using. modinfo contains information used to identify the module.

RAD Instance Management in C

Function
Description
rad_instance_t *rad_instance_create(rad_object_type *type, void *data, void (*)(void *)freef);
rad_instance_create uses the supplied parameters to create a new instance of an object of type. data is the user data to store with the instance and the freef function is a callback which will be called with the user data when the instance is removed. If the function fails, it returns NULL. Otherwise, a valid instance reference is returned.
void * rad_instance_getdata(rad_instance_t *instance);
rad_instance_getdata returns the user data (supplied in rad_instance_create) of the RAD instance.
void rad_instance_notify (rad_instance_t *instance, const char *event, long sequence, adr_data_t *data);
rad_instance_notify generates an event on the supplied instance. The sequence is supplied in the event as the sequence number and the payload of the event is provided in data.

RAD Container Interactions in C

Function
Description
conerr_t rad_cont_insert(rad_container_t *container, adr_name_t *name, rad_instance_t *instance);
Create a RAD instance, rad_instance_t, using the supplied name and object and then insert into container. If the operation succeeds, CE_OK is returned.
conerr_t rad_cont_insert_singleton(rad_container_t *container, adr_name_t *name, rad_object_t *object);
void rad_cont_remove(rad_container_t *container, adr_name_t *name);
Remove the instance from the container.
conerr_t rad_cont_register_dynamic(rad_container_t *container, adr_name_t *name, rad_modinfo_t *modinfo, rad_dyn_list_t listf, rad_dyn_lookup_t lookupf, void *arg);
Register a dynamic container instance manager. The container defines the container in which the instances will be managed. The name defines the name filter for which this instance manager is responsible. A typical name would define the type of the instance which are managed. For example, zname = adr_name_vcreate (MOD_DOMAIN, 1, "type", "Zone") would be responsible for managing all instances with a type of "Zone". listf is a user-supplied function which is invoked when objects with the matching pattern are listed. lookupf is a user-supplied function which is invoked when objects with the matching name are looked up. arg is stored and provided in the callback to the user functions.
conerr_t (*rad_dyn_list_t)(adr_pattern_t *pattern, adr_data_t **data, void *arg);
conerr_t (*rad_dyn_lookup_t)(adr_name_t **name, rad_instance_t **inst, void *arg);

RAD Logging in C

Function
Description
void rad_log(rad_logtype_t type, 
const char * format, ...);
Log a message with type and format to the rad log. If the type is a lower level than the rad logging level, then the message is discarded.
void rad_log_alloc()
Log a memory allocation failure with log level RL_FATAL.
rad_logtype_t rad_get_loglevel()
Return the logging level.

Using Threads in RAD in C

Function
Description
void *rad_thread_arg(rad_thread_t *tp);
Return the arg referenced by the thread tp.
void rad_thread_ack(rad_thread_t *tp, 
rad_moderr_t error);
This function is intended to be used from a user function previously supplied as an argument to rad_thread_create. It should not be used in any other context.
Acknowledge the thread referenced by tp. This process enables the controlling thread, from which a new thread was created using rad_thread_create, to make progress. The error is used to update the return value from rad_thread_create and is set to RM_OK for success.
rad_moderr_t rad_thread_create(rad_threadfp_t fp,
 void *arg);
Create a thread to run fp. This function will not return until the user function (fp) calls rad_thread_ack. arg is stored and passed into fp as a member of the rad_thread_t data. It can be accessed using rad_thread_arg.
rad_moderr_t rad_thread_create_async(
rad_thread_asyncfp_t fp, void *arg);
Create a thread to run fp. arg is stored and passed into fp.

RAD Synchronization Functions in C

Function
Description
void rad_mutex_init(pthread_mutex_t *mutex);
Initialize a mutex.abort() on failure.
void rad_mutex_enter(pthread_mutex_t *mutex);
Lock a mutex. abort() on failure.
void rad_mutex_exit(pthread_mutex_t *mutex);
Unlock a mutex. abort() on failure.
void rad_cond_init(pthread_cond_t *cond);
Initialize a condition variable, cond. abort(), on failure.

RAD Subprocess Functions in C

Function
Description
exec_params_t *rad_exec_params_alloc
Allocate a control structure for executing a subprocess.
void rad_exec_params_free(exec_params_t *params);
Free a subprocess control structure, params.
void rad_exec_params_set_cwd(exec_params_t *params,
const char *cwd);
Set the current working directory, cwd, in a subprocess control structure, params.
void rad_exec_params_set_env(exec_params_t *params,
const char **envp);
Set the environment, envp, in a subprocess control structure, params.
void rad_exec_params_set_loglevel(
exec_params_t *params, rad_logtype_t loglevel);
Set the RAD log level, loglevel, in a subprocess control structure, params.
int rad_exec_params_set_stdin(exec_params_t *params,
int fd);
Set the stdin file descriptor, fd, in a subprocess control structure, params.
int rad_exec_params_set_stdout(exec_params_t *params,
int fd);
Set the stdout file descriptor, fd, in a subprocess control structure, params.
int rad_exec_params_set_stderr(exec_params_t *params,
int fd);
Set the stderr file descriptor, fd, in a subprocess control structure, params.
int rad_forkexec(exec_params_t *params,
 	const char **argv, exec_result_t *result);
Use the supplied subprocess control structure, params, to fork and execute (execv) the supplied args, argv. If result is not NULL, it is updated with the subprocess pid and file descriptor details.
int rad_forkexec_wait(exec_params_t *params,
 	const char **argv, int *status);
Use the supplied subprocess control structure, params, to fork and execute (execv) the supplied args, argv. If status is not NULL, it is updated with the exit status of the subprocess. This function will wait for the subprocess to terminate before returning.
int rad_wait(exec_params_t *params,
 	exec_result_t *result, int *status);
Use the supplied subprocess control structure, params, to wait for a previous invocation of rad_forkexe to complete. If result is not NULL, it is updated with the subprocess pid and file descriptor details. If status is not NULL, it is updated with the exit status of the subprocess. This function will wait for the subprocess to terminate before returning.

RAD Utility Functions in C

Function
Description
void *rad_zalloc(size_t size);
Return a pointer to a zero-allocated block of size bytes.
char *rad_strndup(char *string, size_t length);
Create and return a duplicate of string that is of size, length bytes.
int rad_strccmp(const char * zstring, const char * cstring, size_t length);
Compare two strings, up to a maximum size of length bytes.
int rad_openf(const char *format, int oflag, mode_tmode, ...);
Open a file with access mode, oflag, and mode, mode, whose path is specified by calling sprintf() on format.
FILE *rad_fopenf(const char *format, const char *mode, ...);
Open a file with mode, whose path is specified by calling sprintf() on format.

RAD Locale Functions in C

Function
Description
int rad_locale_parse(const char *locale,
 	rad_locale_t **rad_locale);
Update rad_locale with locale details based on locale. If locale is NULL, then attempt to retrieve a locale based on the locale of the RAD connection. Returns 0 on success.
void rad_locale_free(rad_locale_t *rad_locale);
Free a locale, rad_locale, previously obtained with rad_locale_parse.

Transactional Processing in RAD Modules in C

Transactional processing has no direct support within a module. If a transactional model is desirable, the module creator must provide the required building blocks, start_transaction, commit, rollback, and other related processes.

Asynchronous Methods and Progress Reporting in RAD in C

Asynchronous methods and progress reporting is achieved using threads and events. The pattern is to return a token from a synchronous method invocation which spawns a thread to do work asynchronously. This worker thread is then responsible for providing notifications to interested parties events.

For example, an interface has a method which returns a Task object. The method is called installpkg and takes one argument, the name of the package to install.

Task installpkg(string pkgname);

The Task instance returned by the method, contains enough information to identify a task. Prior to invoking installpkg, the client subscribes to a task-update event. The worker thread is responsible for issuing events about the progress of the work. These events contain information about the progress of the task.

In a minimal implementation, the worker thread would issue one event to notify the client that the task was complete and what the outcome of the task was. A more complex implementation would provide multiple events documenting progress and possibly also provide an additional method that a client could invoke to interrogate the server for a progress report.