server.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * Copyright (C) 2011-2014 Felix Fietkau <nbd@openwrt.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License version 2.1
  6. * as published by the Free Software Foundation
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. #include <unistd.h>
  14. #include <signal.h>
  15. #include <libubox/blobmsg_json.h>
  16. #include "libubus.h"
  17. #include "count.h"
  18. static struct ubus_context *ctx;
  19. static struct ubus_subscriber test_event;
  20. static struct blob_buf b;
  21. enum {
  22. HELLO_ID,
  23. HELLO_MSG,
  24. __HELLO_MAX
  25. };
  26. static const struct blobmsg_policy hello_policy[] = {
  27. [HELLO_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },
  28. [HELLO_MSG] = { .name = "msg", .type = BLOBMSG_TYPE_STRING },
  29. };
  30. struct hello_request {
  31. struct ubus_request_data req;
  32. struct uloop_timeout timeout;
  33. int fd;
  34. int idx;
  35. char data[];
  36. };
  37. static void test_hello_fd_reply(struct uloop_timeout *t)
  38. {
  39. struct hello_request *req = container_of(t, struct hello_request, timeout);
  40. char *data;
  41. data = alloca(strlen(req->data) + 32);
  42. sprintf(data, "msg%d: %s\n", ++req->idx, req->data);
  43. if (write(req->fd, data, strlen(data)) < 0) {
  44. close(req->fd);
  45. free(req);
  46. return;
  47. }
  48. uloop_timeout_set(&req->timeout, 1000);
  49. }
  50. static void test_hello_reply(struct uloop_timeout *t)
  51. {
  52. struct hello_request *req = container_of(t, struct hello_request, timeout);
  53. int fds[2];
  54. blob_buf_init(&b, 0);
  55. blobmsg_add_string(&b, "message", req->data);
  56. ubus_send_reply(ctx, &req->req, b.head);
  57. if (pipe(fds) == -1) {
  58. fprintf(stderr, "Failed to create pipe\n");
  59. return;
  60. }
  61. ubus_request_set_fd(ctx, &req->req, fds[0]);
  62. ubus_complete_deferred_request(ctx, &req->req, 0);
  63. req->fd = fds[1];
  64. req->timeout.cb = test_hello_fd_reply;
  65. test_hello_fd_reply(t);
  66. }
  67. static int test_hello(struct ubus_context *ctx, struct ubus_object *obj,
  68. struct ubus_request_data *req, const char *method,
  69. struct blob_attr *msg)
  70. {
  71. struct hello_request *hreq;
  72. struct blob_attr *tb[__HELLO_MAX];
  73. const char *format = "%s received a message: %s";
  74. const char *msgstr = "(unknown)";
  75. blobmsg_parse(hello_policy, ARRAY_SIZE(hello_policy), tb, blob_data(msg), blob_len(msg));
  76. if (tb[HELLO_MSG])
  77. msgstr = blobmsg_data(tb[HELLO_MSG]);
  78. hreq = calloc(1, sizeof(*hreq) + strlen(format) + strlen(obj->name) + strlen(msgstr) + 1);
  79. if (!hreq)
  80. return UBUS_STATUS_UNKNOWN_ERROR;
  81. sprintf(hreq->data, format, obj->name, msgstr);
  82. ubus_defer_request(ctx, req, &hreq->req);
  83. hreq->timeout.cb = test_hello_reply;
  84. uloop_timeout_set(&hreq->timeout, 1000);
  85. return 0;
  86. }
  87. enum {
  88. WATCH_ID,
  89. WATCH_COUNTER,
  90. __WATCH_MAX
  91. };
  92. static const struct blobmsg_policy watch_policy[__WATCH_MAX] = {
  93. [WATCH_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },
  94. [WATCH_COUNTER] = { .name = "counter", .type = BLOBMSG_TYPE_INT32 },
  95. };
  96. static void
  97. test_handle_remove(struct ubus_context *ctx, struct ubus_subscriber *s,
  98. uint32_t id)
  99. {
  100. fprintf(stderr, "Object %08x went away\n", id);
  101. }
  102. static int
  103. test_notify(struct ubus_context *ctx, struct ubus_object *obj,
  104. struct ubus_request_data *req, const char *method,
  105. struct blob_attr *msg)
  106. {
  107. #if 0
  108. char *str;
  109. str = blobmsg_format_json(msg, true);
  110. fprintf(stderr, "Received notification '%s': %s\n", method, str);
  111. free(str);
  112. #endif
  113. return 0;
  114. }
  115. static int test_watch(struct ubus_context *ctx, struct ubus_object *obj,
  116. struct ubus_request_data *req, const char *method,
  117. struct blob_attr *msg)
  118. {
  119. struct blob_attr *tb[__WATCH_MAX];
  120. int ret;
  121. blobmsg_parse(watch_policy, __WATCH_MAX, tb, blob_data(msg), blob_len(msg));
  122. if (!tb[WATCH_ID])
  123. return UBUS_STATUS_INVALID_ARGUMENT;
  124. test_event.remove_cb = test_handle_remove;
  125. test_event.cb = test_notify;
  126. ret = ubus_subscribe(ctx, &test_event, blobmsg_get_u32(tb[WATCH_ID]));
  127. fprintf(stderr, "Watching object %08x: %s\n", blobmsg_get_u32(tb[WATCH_ID]), ubus_strerror(ret));
  128. return ret;
  129. }
  130. enum {
  131. COUNT_TO,
  132. COUNT_STRING,
  133. __COUNT_MAX
  134. };
  135. static const struct blobmsg_policy count_policy[__COUNT_MAX] = {
  136. [COUNT_TO] = { .name = "to", .type = BLOBMSG_TYPE_INT32 },
  137. [COUNT_STRING] = { .name = "string", .type = BLOBMSG_TYPE_STRING },
  138. };
  139. static int test_count(struct ubus_context *ctx, struct ubus_object *obj,
  140. struct ubus_request_data *req, const char *method,
  141. struct blob_attr *msg)
  142. {
  143. struct blob_attr *tb[__COUNT_MAX];
  144. char *s1, *s2;
  145. uint32_t num;
  146. blobmsg_parse(count_policy, __COUNT_MAX, tb, blob_data(msg), blob_len(msg));
  147. if (!tb[COUNT_TO] || !tb[COUNT_STRING])
  148. return UBUS_STATUS_INVALID_ARGUMENT;
  149. num = blobmsg_get_u32(tb[COUNT_TO]);
  150. s1 = blobmsg_get_string(tb[COUNT_STRING]);
  151. s2 = count_to_number(num);
  152. if (!s1 || !s2) {
  153. free(s2);
  154. return UBUS_STATUS_UNKNOWN_ERROR;
  155. }
  156. blob_buf_init(&b, 0);
  157. blobmsg_add_u32(&b, "rc", strcmp(s1, s2));
  158. ubus_send_reply(ctx, req, b.head);
  159. free(s2);
  160. return 0;
  161. }
  162. static const struct ubus_method test_methods[] = {
  163. UBUS_METHOD("hello", test_hello, hello_policy),
  164. UBUS_METHOD("watch", test_watch, watch_policy),
  165. UBUS_METHOD("count", test_count, count_policy),
  166. };
  167. static struct ubus_object_type test_object_type =
  168. UBUS_OBJECT_TYPE("test", test_methods);
  169. static struct ubus_object test_object = {
  170. .name = "test",
  171. .type = &test_object_type,
  172. .methods = test_methods,
  173. .n_methods = ARRAY_SIZE(test_methods),
  174. };
  175. static void server_main(void)
  176. {
  177. int ret;
  178. ret = ubus_add_object(ctx, &test_object);
  179. if (ret)
  180. fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));
  181. ret = ubus_register_subscriber(ctx, &test_event);
  182. if (ret)
  183. fprintf(stderr, "Failed to add watch handler: %s\n", ubus_strerror(ret));
  184. uloop_run();
  185. }
  186. int main(int argc, char **argv)
  187. {
  188. const char *ubus_socket = NULL;
  189. int ch;
  190. while ((ch = getopt(argc, argv, "cs:")) != -1) {
  191. switch (ch) {
  192. case 's':
  193. ubus_socket = optarg;
  194. break;
  195. default:
  196. break;
  197. }
  198. }
  199. argc -= optind;
  200. argv += optind;
  201. uloop_init();
  202. signal(SIGPIPE, SIG_IGN);
  203. ctx = ubus_connect(ubus_socket);
  204. if (!ctx) {
  205. fprintf(stderr, "Failed to connect to ubus\n");
  206. return -1;
  207. }
  208. ubus_add_uloop(ctx);
  209. server_main();
  210. ubus_free(ctx);
  211. uloop_done();
  212. return 0;
  213. }