server.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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. size_t len = sizeof(*hreq) + sizeof(format) + strlen(obj->name) + strlen(msgstr) + 1;
  79. hreq = calloc(1, len);
  80. if (!hreq)
  81. return UBUS_STATUS_UNKNOWN_ERROR;
  82. snprintf(hreq->data, len, format, obj->name, msgstr);
  83. ubus_defer_request(ctx, req, &hreq->req);
  84. hreq->timeout.cb = test_hello_reply;
  85. uloop_timeout_set(&hreq->timeout, 1000);
  86. return 0;
  87. }
  88. enum {
  89. WATCH_ID,
  90. WATCH_COUNTER,
  91. __WATCH_MAX
  92. };
  93. static const struct blobmsg_policy watch_policy[__WATCH_MAX] = {
  94. [WATCH_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },
  95. [WATCH_COUNTER] = { .name = "counter", .type = BLOBMSG_TYPE_INT32 },
  96. };
  97. static void
  98. test_handle_remove(struct ubus_context *ctx, struct ubus_subscriber *s,
  99. uint32_t id)
  100. {
  101. fprintf(stderr, "Object %08x went away\n", id);
  102. }
  103. static int
  104. test_notify(struct ubus_context *ctx, struct ubus_object *obj,
  105. struct ubus_request_data *req, const char *method,
  106. struct blob_attr *msg)
  107. {
  108. #if 0
  109. char *str;
  110. str = blobmsg_format_json(msg, true);
  111. fprintf(stderr, "Received notification '%s': %s\n", method, str);
  112. free(str);
  113. #endif
  114. return 0;
  115. }
  116. static int test_watch(struct ubus_context *ctx, struct ubus_object *obj,
  117. struct ubus_request_data *req, const char *method,
  118. struct blob_attr *msg)
  119. {
  120. struct blob_attr *tb[__WATCH_MAX];
  121. int ret;
  122. blobmsg_parse(watch_policy, __WATCH_MAX, tb, blob_data(msg), blob_len(msg));
  123. if (!tb[WATCH_ID])
  124. return UBUS_STATUS_INVALID_ARGUMENT;
  125. test_event.remove_cb = test_handle_remove;
  126. test_event.cb = test_notify;
  127. ret = ubus_subscribe(ctx, &test_event, blobmsg_get_u32(tb[WATCH_ID]));
  128. fprintf(stderr, "Watching object %08x: %s\n", blobmsg_get_u32(tb[WATCH_ID]), ubus_strerror(ret));
  129. return ret;
  130. }
  131. enum {
  132. COUNT_TO,
  133. COUNT_STRING,
  134. __COUNT_MAX
  135. };
  136. static const struct blobmsg_policy count_policy[__COUNT_MAX] = {
  137. [COUNT_TO] = { .name = "to", .type = BLOBMSG_TYPE_INT32 },
  138. [COUNT_STRING] = { .name = "string", .type = BLOBMSG_TYPE_STRING },
  139. };
  140. static int test_count(struct ubus_context *ctx, struct ubus_object *obj,
  141. struct ubus_request_data *req, const char *method,
  142. struct blob_attr *msg)
  143. {
  144. struct blob_attr *tb[__COUNT_MAX];
  145. char *s1, *s2;
  146. uint32_t num;
  147. blobmsg_parse(count_policy, __COUNT_MAX, tb, blob_data(msg), blob_len(msg));
  148. if (!tb[COUNT_TO] || !tb[COUNT_STRING])
  149. return UBUS_STATUS_INVALID_ARGUMENT;
  150. num = blobmsg_get_u32(tb[COUNT_TO]);
  151. s1 = blobmsg_get_string(tb[COUNT_STRING]);
  152. s2 = count_to_number(num);
  153. if (!s1 || !s2) {
  154. free(s2);
  155. return UBUS_STATUS_UNKNOWN_ERROR;
  156. }
  157. blob_buf_init(&b, 0);
  158. blobmsg_add_u32(&b, "rc", strcmp(s1, s2));
  159. ubus_send_reply(ctx, req, b.head);
  160. free(s2);
  161. return 0;
  162. }
  163. static const struct ubus_method test_methods[] = {
  164. UBUS_METHOD("hello", test_hello, hello_policy),
  165. UBUS_METHOD("watch", test_watch, watch_policy),
  166. UBUS_METHOD("count", test_count, count_policy),
  167. };
  168. static struct ubus_object_type test_object_type =
  169. UBUS_OBJECT_TYPE("test", test_methods);
  170. static struct ubus_object test_object = {
  171. .name = "test",
  172. .type = &test_object_type,
  173. .methods = test_methods,
  174. .n_methods = ARRAY_SIZE(test_methods),
  175. };
  176. static void server_main(void)
  177. {
  178. int ret;
  179. ret = ubus_add_object(ctx, &test_object);
  180. if (ret)
  181. fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));
  182. ret = ubus_register_subscriber(ctx, &test_event);
  183. if (ret)
  184. fprintf(stderr, "Failed to add watch handler: %s\n", ubus_strerror(ret));
  185. uloop_run();
  186. }
  187. int main(int argc, char **argv)
  188. {
  189. const char *ubus_socket = NULL;
  190. int ch;
  191. while ((ch = getopt(argc, argv, "cs:")) != -1) {
  192. switch (ch) {
  193. case 's':
  194. ubus_socket = optarg;
  195. break;
  196. default:
  197. break;
  198. }
  199. }
  200. uloop_init();
  201. signal(SIGPIPE, SIG_IGN);
  202. ctx = ubus_connect(ubus_socket);
  203. if (!ctx) {
  204. fprintf(stderr, "Failed to connect to ubus\n");
  205. return -1;
  206. }
  207. ubus_add_uloop(ctx);
  208. server_main();
  209. ubus_free(ctx);
  210. uloop_done();
  211. return 0;
  212. }