00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #define _GNU_SOURCE
00020 #include <sys/types.h>
00021 #include <sys/select.h>
00022 #include <sys/socket.h>
00023 #include <sys/un.h>
00024 #include <string.h>
00025 #include <microhttpd.h>
00026 #include <json.h>
00027 #include <libxml/uri.h>
00028 #include <stdio.h>
00029 #include <unistd.h>
00030 #include <errno.h>
00031 #include <sys/param.h>
00032 #include <stdlib.h>
00033
00034 #include "lsm_rest.h"
00035
00036
00037
00038
00039
00040
00041
00042 void para_list_init(ParaList_t * para_list)
00043 {
00044 para_list->head = NULL;
00045 }
00046
00047 int para_list_add(ParaList_t * para_list, const char *key_name,
00048 const void *value, const enum lsm_json_type value_type,
00049 const ssize_t array_len)
00050 {
00051 if (para_list == NULL)
00052 return -1;
00053 Parameter_t *new_para_node = (Parameter_t *) malloc(sizeof(Parameter_t));
00054 new_para_node->key_name = key_name;
00055 new_para_node->value = value;
00056 new_para_node->value_type = value_type;
00057 new_para_node->array_len = array_len;
00058 new_para_node->next = NULL;
00059 if (para_list->head == NULL) {
00060 para_list->head = new_para_node;
00061 } else {
00062 Parameter_t *current = para_list->head;
00063 while (current->next != NULL) {
00064 current = current->next;
00065 }
00066 current->next = new_para_node;
00067 }
00068 return 0;
00069 }
00070
00071 void para_list_free(ParaList_t * para_list)
00072 {
00073 if (para_list == NULL)
00074 return;
00075 if (para_list->head == NULL) {
00076 free(para_list);
00077 } else {
00078 Parameter_t *current = para_list->head;
00079 Parameter_t *next = current->next;
00080 free(current);
00081 while (next != NULL) {
00082 current = next;
00083 next = current->next;
00084 free(current);
00085 }
00086 free(para_list);
00087 }
00088 return;
00089 }
00090
00091 json_object *para_to_json(const enum lsm_json_type value_type,
00092 const void *para_value, ssize_t array_len)
00093 {
00094 json_object *para_val_obj = NULL;
00095 switch (value_type) {
00096 case lsm_json_type_null:
00097 break;
00098 case lsm_json_type_int:
00099 para_val_obj = json_object_new_int64(*(int64_t *) para_value);
00100 break;
00101 case lsm_json_type_float:
00102 para_val_obj = json_object_new_double(*(double *) para_value);
00103 break;
00104 case lsm_json_type_string:
00105 para_val_obj = json_object_new_string((const char *) para_value);
00106 break;
00107 case lsm_json_type_bool:
00108 para_val_obj = json_object_new_boolean(*(json_bool *) para_value);
00109 break;
00110 case lsm_json_type_array_str:
00111 para_val_obj = json_object_new_array();
00112 ssize_t i;
00113 for (i = 0; i < array_len; i++) {
00114 json_object *array_member = para_to_json(lsm_json_type_string,
00115 (void *) ((char **)
00116 para_value)[i],
00117 0);
00118 json_object_array_add(para_val_obj, array_member);
00119 }
00120 break;
00121 default:
00122 break;
00123 }
00124 return para_val_obj;
00125 }
00126
00127
00128 json_object *para_list_to_json(ParaList_t * para_list)
00129 {
00130 Parameter_t *cur_node = para_list->head;
00131 if (cur_node == NULL) {
00132 return NULL;
00133 }
00134 json_object *jobj = json_object_new_object();
00135 while (cur_node != NULL) {
00136 json_object_object_add(jobj,
00137 cur_node->key_name,
00138 para_to_json(cur_node->value_type,
00139 cur_node->value,
00140 cur_node->array_len));
00141 cur_node = cur_node->next;
00142 }
00143 return jobj;
00144 }
00145
00146 static int connect_socket(const char *uri_str, const char *plugin_dir,
00147 int *error_no)
00148 {
00149 int socket_fd = -1;
00150 xmlURIPtr uri_obj;
00151 uri_obj = xmlParseURI(uri_str);
00152 char *uri_scheme = NULL;
00153 if (uri_obj != NULL) {
00154 uri_scheme = strdup(uri_obj->scheme);
00155 xmlFreeURI(uri_obj);
00156 uri_obj = NULL;
00157 } else {
00158 *error_no = errno;
00159 return socket_fd;
00160 }
00161 char *plugin_file = NULL;
00162 if (asprintf(&plugin_file, "%s/%s", plugin_dir, uri_scheme) == -1) {
00163 free(uri_scheme);
00164 *error_no = ENOMEM;
00165 return socket_fd;
00166 }
00167 free(uri_scheme);
00168
00169 socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
00170 if (socket_fd != -1) {
00171 struct sockaddr_un addr;
00172 memset(&addr, 0, sizeof(addr));
00173 addr.sun_family = AF_UNIX;
00174 if (strlen(plugin_file) > (sizeof(addr.sun_path) - 1)) {
00175 socket_fd = -1;
00176 fprintf(stderr, "Plugin file path too long: %s, "
00177 "max is %zu", plugin_file, sizeof(addr.sun_path) - 1);
00178 }
00179 strcpy(addr.sun_path, plugin_file);
00180 free(plugin_file);
00181 if (connect(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
00182 *error_no = errno;
00183 socket_fd = -1;
00184 }
00185 } else {
00186 *error_no = errno;
00187 }
00188 return socket_fd;
00189 }
00190
00191
00192 static int send_msg(int socket_fd, const char *msg, int *error_no)
00193 {
00194 int rc = -1;
00195 size_t len = strlen(msg);
00196 size_t new_msg_len = strlen(msg) + LSM_HEADER_LEN + 1;
00197 char *msg_with_header = (char *) malloc(new_msg_len);
00198 sprintf(msg_with_header, "%0*zu%s", LSM_HEADER_LEN, len, msg);
00199 ssize_t written = 0;
00200 new_msg_len -= 1;
00201 while (written < new_msg_len) {
00202 ssize_t wrote = send(socket_fd, msg_with_header + written,
00203 (new_msg_len - written),
00204 MSG_NOSIGNAL);
00205 if (wrote != -1) {
00206 written += wrote;
00207 } else {
00208 *error_no = errno;
00209 break;
00210 }
00211 }
00212 if ((written == new_msg_len) && *error_no == 0) {
00213 rc = 0;
00214 }
00215 free(msg_with_header);
00216 return rc;
00217 }
00218
00219 static char *_recv_msg(int socket_fd, size_t count, int *error_no)
00220 {
00221 char buff[LSM_SOCK_BUFF_LEN];
00222 size_t amount_read = 0;
00223 *error_no = 0;
00224 char *msg = malloc(count + 1);
00225 memset(msg, 0, count + 1);
00226 while (amount_read < count) {
00227 ssize_t rd = (ssize_t) recv(socket_fd, buff,
00228 MIN(sizeof(buff), count - amount_read),
00229 MSG_WAITALL);
00230 if (rd > 0) {
00231 memcpy(msg + amount_read, buff, rd);
00232 amount_read += rd;
00233 } else if (errno == EAGAIN) {
00234 printf("retry\n");
00235 errno = 0;
00236 continue;
00237 } else {
00238 *error_no = errno;
00239 break;
00240 }
00241 }
00242 if (*error_no == 0) {
00243 msg[count] = '\0';
00244 return msg;
00245 } else {
00246 fprintf(stderr, "recv() got error_no, : %d\n", *error_no);
00247 free(msg);
00248 return NULL;
00249 }
00250 }
00251
00252 static char *recv_msg(int socket_fd, int *error_no)
00253 {
00254 *error_no = 0;
00255 char *msg_len_str = _recv_msg(socket_fd, LSM_HEADER_LEN, error_no);
00256 if (msg_len_str == NULL) {
00257 fprintf(stderr, "Failed to read the JSON length "
00258 "with error_no%d\n", *error_no);
00259 return NULL;
00260 }
00261 errno = 0;
00262 size_t msg_len = (size_t) strtoul(msg_len_str, NULL, 10);
00263 free(msg_len_str);
00264 if ((errno == ERANGE && (msg_len == LONG_MAX || msg_len == LONG_MIN))
00265 || (errno != 0 && msg_len == 0)) {
00266 perror("strtol");
00267 return NULL;
00268 }
00269 if (msg_len == 0) {
00270 fprintf(stderr, "No data needed to retrieve\n");
00271 return NULL;
00272 }
00273 char *msg = _recv_msg(socket_fd, msg_len, error_no);
00274 if (msg == NULL) {
00275 fprintf(stderr, "Failed to retrieve data from socket "
00276 "with error_no %d\n", *error_no);
00277 return NULL;
00278 }
00279 return msg;
00280 }
00281
00282 static char *rpc(int socket_fd, const char *method, ParaList_t * para_list,
00283 int *error_no)
00284 {
00285 *error_no = 0;
00286 json_object *jobj = json_object_new_object();
00287 json_object_object_add(jobj, "method", json_object_new_string(method));
00288 json_object *js_params = para_list_to_json(para_list);
00289 if (js_params != NULL) {
00290 json_object_object_add(jobj, "params", js_params);
00291 }
00292 json_object_object_add(jobj, "id", json_object_new_int(LSM_DEFAULT_ID));
00293 const char *json_string =
00294 json_object_to_json_string_ext(jobj, JSON_C_TO_STRING_PRETTY);
00295 printf("Sending JSON to plugin:\n%s\n", json_string);
00296 *error_no = 0;
00297 int rc = send_msg(socket_fd, json_string, error_no);
00298 json_object_put(jobj);
00299 if (rc != 0) {
00300 fprintf(stderr, "Got error when sending message to socket, "
00301 "rc=%d, error_no=%d\n", rc, *error_no);
00302 return NULL;
00303 }
00304 char *recv_json_string = NULL;
00305 recv_json_string = recv_msg(socket_fd, error_no);
00306 if (*error_no != 0) {
00307 printf("Got error when receiving message to socket,"
00308 "error_no=%d\n", *error_no);
00309 free(recv_json_string);
00310 return NULL;
00311 }
00312 if (recv_json_string == NULL) {
00313 printf("No data retrieved\n");
00314 return NULL;
00315 }
00316 json_object *recv_json = json_tokener_parse(recv_json_string);
00317 free(recv_json_string);
00318 json_object *result_json;
00319 if (!json_object_object_get_ex(recv_json, "result", &result_json)) {
00320 printf("No 'result' node in received JSON data");
00321 json_object_put(recv_json);
00322 return NULL;
00323 }
00324 char *result_str;
00325 result_str = (char *) json_object_to_json_string_ext(result_json,
00326 JSON_C_TO_STRING_PRETTY);
00327 char *rc_msg = strdup(result_str);
00328 json_object_put(recv_json);
00329 return rc_msg;
00330 }
00331
00332 static int plugin_startup(int socket_fd, const char *uri, const char *pass,
00333 int tmo)
00334 {
00335 printf("Starting the plugin\n");
00336 int error_no = 0;
00337 enum lsm_json_type pass_type = lsm_json_type_string;
00338 if (pass == NULL) {
00339 pass_type = lsm_json_type_null;
00340 }
00341 ParaList_t *para_list = (ParaList_t *) malloc(sizeof(ParaList_t));
00342 para_list_init(para_list);
00343 para_list_add(para_list, "uri", uri, lsm_json_type_string, 0);
00344 para_list_add(para_list, "password", pass, pass_type, 0);
00345 para_list_add(para_list, "timeout", &tmo, lsm_json_type_int, 0);
00346 char *msg = rpc(socket_fd, "plugin_register", para_list, &error_no);
00347 free(msg);
00348 para_list_free(para_list);
00349 return error_no;
00350 }
00351
00352 static int plugin_shutdown(int socket_fd)
00353 {
00354 printf("Shutting down the plugin\n");
00355 int error_no = 0;
00356 ParaList_t *para_list = (ParaList_t *) malloc(sizeof(ParaList_t));
00357 para_list_init(para_list);
00358 static int lsm_flags = 0;
00359 para_list_add(para_list, "flags", &lsm_flags, lsm_json_type_int, 0);
00360 char *msg = rpc(socket_fd, "plugin_unregister", para_list, &error_no);
00361 free(msg);
00362 para_list_free(para_list);
00363 return error_no;
00364 }
00365
00366 static char *v01_query(int socket_fd, const char *method,
00367 ParaList_t * para_list, int *error_no)
00368 {
00369 *error_no = 0;
00370 if (para_list == NULL) {
00371 para_list = (ParaList_t *) malloc(sizeof(ParaList_t));
00372 para_list_init(para_list);
00373 }
00374 int lsm_flags = 0;
00375 para_list_add(para_list, "flags", &lsm_flags, lsm_json_type_int, 0);
00376 char *json_str = rpc(socket_fd, method, para_list, error_no);
00377 para_list_free(para_list);
00378 return json_str;
00379 }
00380
00381 static char *lsm_api_0_1(struct MHD_Connection *connection,
00382 const char *uri, const char *pass,
00383 const char *url, const char *method,
00384 const char *upload_data)
00385 {
00386 const char *plugin_dir = getenv("LSM_UDS_PATH");
00387 if (plugin_dir == NULL) {
00388 plugin_dir = LSM_UDS_PATH_DEFAULT;
00389 fprintf(stdout, "Using default LSM_UDS_PATH: %s\n", plugin_dir);
00390 }
00391 int error_no = 0;
00392 int socket_fd = connect_socket(uri, plugin_dir, &error_no);
00393 if (socket_fd == -1) {
00394 fprintf(stderr, "Failed to connecting to the socket for URI "
00395 "%s with error_no %d\n", uri, error_no);
00396 return NULL;
00397 }
00398 error_no = plugin_startup(socket_fd, uri, pass, LSM_REST_TMO);
00399 if (error_no != 0) {
00400 fprintf(stderr, "Failed to register plugin, " "error_no %d", error_no);
00401 plugin_shutdown(socket_fd);
00402 shutdown(socket_fd, 0);
00403 return NULL;
00404 }
00405 error_no = 0;
00406 char *json_msg = NULL;
00407 int i;
00408 int flag_found = 0;
00409 for (i = 0; i < sizeof(lsm_query_strs) / sizeof(char *); i++) {
00410 if (0 == strcmp(url, lsm_query_strs[i])) {
00411 flag_found = 1;
00412 json_msg = v01_query(socket_fd, lsm_query_strs[i], NULL, &error_no);
00413 break;
00414 }
00415 }
00416 if (flag_found == 0) {
00417 fprintf(stderr, "Not supported: %s\n", url);
00418 }
00419 if (error_no != 0) {
00420 fprintf(stderr, "Failed to call method %s(), error_no: %d\n",
00421 url, error_no);
00422 }
00423 error_no = plugin_shutdown(socket_fd);
00424 if (error_no != 0) {
00425 fprintf(stderr, "Failed to unregister plugin, "
00426 "error_no %d", error_no);
00427 }
00428 shutdown(socket_fd, 0);
00429 return json_msg;
00430 }
00431
00432 static int answer_to_connection(void *cls, struct MHD_Connection *connection,
00433 const char *url,
00434 const char *method, const char *version,
00435 const char *upload_data,
00436 size_t * upload_data_size, void **con_cls)
00437 {
00438 printf("New '%s' request, URL: '%s'\n", method, url);
00439 struct MHD_Response *response;
00440
00441 if (0 != strcmp(method, "GET")) {
00442 return MHD_NO;
00443 }
00444
00445 if (strlen(url) == 1) {
00446 return MHD_NO;
00447 }
00448
00449 const char *uri = MHD_lookup_connection_value(connection,
00450 MHD_GET_ARGUMENT_KIND, "uri");
00451
00452 const char *pass = MHD_lookup_connection_value(connection,
00453 MHD_GET_ARGUMENT_KIND,
00454 "pass");
00455
00456 int ret;
00457 char api_version[LSM_API_VER_LEN + 1];
00458 memcpy(api_version, url + 1, LSM_API_VER_LEN);
00459
00460 api_version[LSM_API_VER_LEN] = '\0';
00461 char *json_str = NULL;
00462 size_t url_no_api_ver_len = strlen(url) - strlen(api_version) - 1 - 1;
00463
00464
00465 char *url_no_api_ver = malloc(url_no_api_ver_len + 1);
00466 strcpy(url_no_api_ver, url + strlen(api_version) + 1 + 1);
00467 if (0 == strcmp(api_version, "v0.1")) {
00468 printf("v0.1 API request found\n");
00469 json_str = lsm_api_0_1(connection, uri, pass, url_no_api_ver,
00470 method, upload_data);
00471 free(url_no_api_ver);
00472 if (json_str == NULL) {
00473 return MHD_NO;
00474 }
00475 } else {
00476 free(url_no_api_ver);
00477 return MHD_NO;
00478 }
00479 response = MHD_create_response_from_buffer(strlen(json_str),
00480 (void *) json_str,
00481 MHD_RESPMEM_MUST_FREE);
00482
00483 MHD_add_response_header(response, "Content-Type", LSM_JSON_MIME);
00484
00485 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
00486 MHD_destroy_response(response);
00487 return ret;
00488 }
00489
00490 int main(int argc, char **argv)
00491 {
00492 struct MHD_Daemon *daemon;
00493 daemon =
00494 MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, LSM_REST_PORT, NULL, NULL,
00495 &answer_to_connection, NULL, MHD_OPTION_END);
00496 while (1) {
00497 sleep(60);
00498 }
00499 MHD_stop_daemon(daemon);
00500 return EXIT_SUCCESS;
00501 }