C-icap uses the doxygen documentation system to document API functions. To produce the API documentation you need to have doxygen installed. Then under the c-icap source distribution, just run:
make doc
The documentation will be produced in HTML form under the directory ''docs/html/''. The c-icap is still under development so some of its API interfaces are not complete and they are subject to change. However someone should not expect huge changes between different releases (0.x releases).
In this page also exist some sample code for the major tools provided by the c-icap server.
Before start writing your own service you need to:
To modify/examine an HTTP objects (HTTP requests or responses) there is a number of utility functions. Most of them are documented with doxygen documentation system in the following modules/sections:
The c-icap provides an easy way to allow developers define their own configuration parameters for services and modules. Example usage:
char *CONF1 = NULL; int CONF2 = -1; int MYCFG_PARAM = 0; int my_cfg_handler(char *directive, char **argv, void *setdata); /*Configuration table, should attached to the related ci_service_t object .....*/ static struct ci_conf_entry conf_variables[] = { {"Conf1", &CONF1, ci_cfg_set_str, NULL}, /* use the ci_cfg_set_str predefined handler */ {"Conf2", &CONF2, ci_cfg_onoff, NULL}, /* use the ci_cfg_onoff predefined handler */ {"Conf3", NULL, my_cfg_handler, NULL}, /* use a custom handler */ {NULL, NULL, NULL, NULL} }; /*example custom configuration handler*/ int my_cfg_handler(char *directive, char **argv, void *setdata) { if (argv[0]!= NULL) { MYCFG_PARAM = atoi(argv[0]); return 1; } else return 0; }
For the available configuration parameter handlers, look in the configuration API module/section in c-icap documentation.
To create an access list and add acls use the following code:
ci_access_entry_t *My_Access_List = NULL; ... /*Normally the following code exist inside a configuration parameter handler*/ ci_access_entry_t *access_entry; if ((access_entry = ci_access_entry_new(&My_Access_List), CI_ACCESS_ALLOW /*or CI_ACCESS_DENY*/)) == NULL) { return ERROR; } for (argc = 0; argv[argc]!= NULL; argc++) { char *acl_spec_name = argv[argc]; if (!ci_access_entry_add_acl_by_name(access_entry, acl_spec_name)) { ci_debug_printf(1,"Error adding acl spec: %s, (is it defined?)\n", acl_spec_name); return ERROR; } }
To check if an access list matches a request use :
/*My_Access_List is a global variable*/ ci_access_entry_t *My_Access_List; ... ci_request_t *current_req = req; int ret; if (ret=ci_access_entry_match_request(My_Access_List,current_req)) { /*The request matches the accesslist*/ if (ret == CI_ACCESS_ALLOW) { /*Allowed*/ } else { /* CI_ACCESS_DENY or CI_ACCESS_UNKNOWN */ /*denied*/ } }
The following code creates the ERROR_FOUND template for the my_srv error page. This template should stored in the TemplateDir/my_srv/en/ERROR_FOUND file.
ci_membuf_t *error_page; error_page = ci_txt_template_build_content(req, "my_srv", "ERROR_FOUND", NULL); ... /*release error_page*/ ci_membuf_free(error_page);
The following creates the template ERROR_FOUND for the service my_srv using custom formating codes: The %TT formating code produces the "TEST" string.
static int fmt_test(ci_request_t *req, char *buf, int len, char *param) { return snprintf(buf, len, "TEST"); } struct ci_fmt_entry my_fmt_table [] = { {"%TT", "A Test", fmt_test}, { NULL, NULL, NULL} } ci_membuf_t *error_page; error_page = ci_txt_template_build_content(req, "my_srv", "AN-ERROR", my_fmt_table); ... /*release error_page*/ ci_membuf_free(error_page);
Visit this web page for an easy way to configure and view c-icap runtime statistics: FAQ:How can I get some c-icap runtime statistics
/* Create the REQUESTS_PROCCESSED and BYTES_PROCESSED counters. This part of code normally placed in ci_service_module::mod_post_init_service or ci_service_module::mod_init_service service handlers */ REQUESTS_PROCCESSED = ci_stat_entry_register("Requests processed", STAT_INT64_T, "My Service"); BYTES_PROCESSED = ci_stat_entry_register("Bytes processed", STAT_KBS_T, "My Service"); if (REQUESTS_PROCCESSED < 0 || BYTES_PROCESSED < 0) { /*an error*/ return CI_ERROR; } .... /*Increase the REQUESTS_PROCCESSED and BYTES_PROCESSED counters:*/ ci_stat_uint64_inc(REQUESTS_PROCESSED, 1); ci_stat_kbs_inc(BYTES_PROCESSED, bytes); /*bytes is the size of processed object*/
/* Create a hash lookup table. Just fix the path variable to create file, bdb or ldap tables. This part of code normally placed in ci_service_module::mod_post_init_service or ci_service_module::mod_init_service service handlers */ struct ci_lookup_table *lt_db; const char *path = "hash:/path/to/file.txt" lt_db = ci_lookup_table_create(path); if (lt_db && !lt_db->open(lt_db)) { ci_lookup_table_destroy(lt_db); lt_db = NULL; } ... /* To search in the lookup table for a record with key "chtsanti" use the following code. The record will be stored to a NULL terminated string array and will be set to vals.. */ char **vals=NULL; const char *key="chtsanti"; ret = lt_db->search(lt_db, key, (void ***)&vals); /* do something with vals */ for (i=0; vals[i]!= NULL, i++) print("Found the value:%s", vals[i]) lt_db->release_result(lt_db, vals); ... /*The lookup table does not needed any more destroy it */ ci_lookup_table_destroy(lt_db);