2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * @brief Wrapper functions around the libcouchbase Couchbase client driver.
23 * @copyright 2013-2014 Aaron Hurt <ahurt@anbcs.com>
28 #include <freeradius-devel/radiusd.h>
30 #include <libcouchbase/couchbase.h>
31 #include <json/json.h>
33 #include "couchbase.h"
34 #include "jsonc_missing.h"
36 /* general couchbase error callback */
37 void couchbase_error_callback(lcb_t instance, lcb_error_t error, const char *errinfo) {
39 ERROR("rlm_couchbase: (error_callback) %s (0x%x), %s", lcb_strerror(instance, error), error, errinfo);
42 /* couchbase value store callback */
43 void couchbase_store_callback(lcb_t instance, const void *cookie, lcb_storage_t operation, lcb_error_t error, const lcb_store_resp_t *resp) {
44 if (error != LCB_SUCCESS) {
46 ERROR("rlm_couchbase: (store_callback) %s (0x%x)", lcb_strerror(instance, error), error);
54 /* couchbase value get callback */
55 void couchbase_get_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_get_resp_t *resp) {
56 cookie_u cu; /* union of const and non const pointers */
57 cu.cdata = cookie; /* set const union member to cookie passed from couchbase */
58 cookie_t *c = (cookie_t *) cu.data; /* set our cookie struct using non-const member */
59 const char *bytes = resp->v.v0.bytes; /* the payload of this chunk */
60 lcb_size_t nbytes = resp->v.v0.nbytes; /* length of this data chunk */
65 /* check for valid bytes */
66 if (bytes && nbytes > 1) {
68 DEBUG("rlm_couchbase: (get_callback) got %zu bytes", nbytes);
69 /* build json object */
70 c->jobj = json_tokener_parse_verbose(bytes, &c->jerr);
71 /* switch on current error status */
73 case json_tokener_success:
78 ERROR("rlm_couchbase: (get_callback) JSON Tokener error: %s", json_tokener_error_desc(c->jerr));
85 DEBUG("rlm_couchbase: (get_callback) key does not exist");
89 ERROR("rlm_couchbase: (get_callback) %s (0x%x)", lcb_strerror(instance, error), error);
94 /* connect to couchbase */
95 lcb_t couchbase_init_connection(const char *host, const char *bucket, const char *pass) {
96 lcb_t instance; /* couchbase instance */
97 lcb_error_t error; /* couchbase command return */
98 struct lcb_create_st options; /* init create struct */
101 memset(&options, 0, sizeof(options));
103 /* assign couchbase create options */
104 options.v.v0.host = host;
105 options.v.v0.bucket = bucket;
107 /* assign user and password if they were both passed */
108 if (bucket != NULL && pass != NULL) {
109 options.v.v0.user = bucket;
110 options.v.v0.passwd = pass;
113 /* create couchbase connection instance */
114 if ((error = lcb_create(&instance, &options)) != LCB_SUCCESS) {
115 /* log error and return */
116 ERROR("rlm_couchbase: failed to create couchbase instance: %s (0x%x)", lcb_strerror(NULL, error), error);
117 /* return instance */
121 /* initiate connection */
122 if ((error = lcb_connect(instance)) == LCB_SUCCESS) {
123 /* set general method callbacks */
124 lcb_set_error_callback(instance, couchbase_error_callback);
125 lcb_set_get_callback(instance, couchbase_get_callback);
126 lcb_set_store_callback(instance, couchbase_store_callback);
127 /* wait on connection */
131 ERROR("rlm_couchbase: Failed to initiate couchbase connection: %s (0x%x)", lcb_strerror(NULL, error), error);
134 /* return instance */
138 /* store document/key in couchbase */
139 lcb_error_t couchbase_set_key(lcb_t instance, const char *key, const char *document, int expire) {
140 lcb_error_t error; /* couchbase command return */
141 lcb_store_cmd_t cmd; /* store command stuct */
142 const lcb_store_cmd_t *commands[1]; /* store commands array */
146 memset(&cmd, 0, sizeof(cmd));
148 /* populate command struct */
150 cmd.v.v0.nkey = strlen(cmd.v.v0.key);
151 cmd.v.v0.bytes = document;
152 cmd.v.v0.nbytes = strlen(cmd.v.v0.bytes);
153 cmd.v.v0.exptime = expire;
154 cmd.v.v0.operation = LCB_SET;
156 /* store key/document in couchbase */
157 if ((error = lcb_store(instance, NULL, 1, commands)) == LCB_SUCCESS) {
158 /* enter event loop on success */
166 /* pull document from couchbase by key */
167 lcb_error_t couchbase_get_key(lcb_t instance, const void *cookie, const char *key) {
168 lcb_error_t error; /* couchbase command return */
169 lcb_get_cmd_t cmd; /* get command struct */
170 const lcb_get_cmd_t *commands[1]; /* get commands array */
174 memset(&cmd, 0, sizeof(cmd));
176 /* populate command struct */
178 cmd.v.v0.nkey = strlen(cmd.v.v0.key);
181 if ((error = lcb_get(instance, cookie, 1, commands)) == LCB_SUCCESS) {
182 /* enter event loop on success */