ubusd.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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 <sys/socket.h>
  14. #ifdef FreeBSD
  15. #include <sys/param.h>
  16. #endif
  17. #include "ubusd.h"
  18. #define USES_EXTERNAL_BUFFER ~0U
  19. static struct ubus_msg_buf *ubus_msg_ref(struct ubus_msg_buf *ub)
  20. {
  21. struct ubus_msg_buf *new_ub;
  22. if (ub->refcount == USES_EXTERNAL_BUFFER) {
  23. new_ub = ubus_msg_new(ub->data, ub->len, false);
  24. if (!new_ub)
  25. return NULL;
  26. memcpy(&new_ub->hdr, &ub->hdr, sizeof(struct ubus_msghdr));
  27. new_ub->fd = ub->fd;
  28. return new_ub;
  29. }
  30. ub->refcount++;
  31. return ub;
  32. }
  33. struct ubus_msg_buf *ubus_msg_new(void *data, int len, bool shared)
  34. {
  35. struct ubus_msg_buf *ub;
  36. int buflen = sizeof(*ub);
  37. if (!shared)
  38. buflen += len;
  39. ub = calloc(1, buflen);
  40. if (!ub)
  41. return NULL;
  42. ub->fd = -1;
  43. if (shared) {
  44. ub->refcount = USES_EXTERNAL_BUFFER;
  45. ub->data = data;
  46. } else {
  47. ub->refcount = 1;
  48. ub->data = (void *) (ub + 1);
  49. if (data)
  50. memcpy(ub + 1, data, len);
  51. }
  52. ub->len = len;
  53. return ub;
  54. }
  55. void ubus_msg_free(struct ubus_msg_buf *ub)
  56. {
  57. switch (ub->refcount) {
  58. case 1:
  59. case USES_EXTERNAL_BUFFER:
  60. if (ub->fd >= 0)
  61. close(ub->fd);
  62. free(ub);
  63. break;
  64. default:
  65. ub->refcount--;
  66. break;
  67. }
  68. }
  69. ssize_t ubus_msg_writev(int fd, struct ubus_msg_buf *ub, size_t offset)
  70. {
  71. uint8_t fd_buf[CMSG_SPACE(sizeof(int))] = { 0 };
  72. static struct iovec iov[2];
  73. struct msghdr msghdr = { 0 };
  74. struct ubus_msghdr hdr;
  75. struct cmsghdr *cmsg;
  76. ssize_t ret;
  77. int *pfd;
  78. msghdr.msg_iov = iov;
  79. msghdr.msg_iovlen = ARRAY_SIZE(iov);
  80. msghdr.msg_control = fd_buf;
  81. msghdr.msg_controllen = sizeof(fd_buf);
  82. cmsg = CMSG_FIRSTHDR(&msghdr);
  83. cmsg->cmsg_type = SCM_RIGHTS;
  84. cmsg->cmsg_level = SOL_SOCKET;
  85. cmsg->cmsg_len = CMSG_LEN(sizeof(int));
  86. pfd = (int *) CMSG_DATA(cmsg);
  87. msghdr.msg_controllen = cmsg->cmsg_len;
  88. *pfd = ub->fd;
  89. if (ub->fd < 0 || offset) {
  90. msghdr.msg_control = NULL;
  91. msghdr.msg_controllen = 0;
  92. }
  93. if (offset < sizeof(ub->hdr)) {
  94. hdr.version = ub->hdr.version;
  95. hdr.type = ub->hdr.type;
  96. hdr.seq = cpu_to_be16(ub->hdr.seq);
  97. hdr.peer = cpu_to_be32(ub->hdr.peer);
  98. iov[0].iov_base = ((char *) &hdr) + offset;
  99. iov[0].iov_len = sizeof(hdr) - offset;
  100. iov[1].iov_base = (char *) ub->data;
  101. iov[1].iov_len = ub->len;
  102. } else {
  103. offset -= sizeof(ub->hdr);
  104. iov[0].iov_base = ((char *) ub->data) + offset;
  105. iov[0].iov_len = ub->len - offset;
  106. msghdr.msg_iovlen = 1;
  107. }
  108. do {
  109. ret = sendmsg(fd, &msghdr, 0);
  110. } while (ret < 0 && errno == EINTR);
  111. return ret;
  112. }
  113. void ubus_msg_list_free(struct ubus_msg_buf_list *ubl)
  114. {
  115. list_del_init(&ubl->list);
  116. ubus_msg_free(ubl->msg);
  117. free(ubl);
  118. }
  119. static void ubus_msg_enqueue(struct ubus_client *cl, struct ubus_msg_buf *ub)
  120. {
  121. struct ubus_msg_buf_list *ubl;
  122. if (cl->txq_len + ub->len > UBUS_CLIENT_MAX_TXQ_LEN)
  123. return;
  124. ubl = calloc(1, sizeof(struct ubus_msg_buf_list));
  125. if (!ubl)
  126. return;
  127. INIT_LIST_HEAD(&ubl->list);
  128. ubl->msg = ubus_msg_ref(ub);
  129. list_add_tail(&ubl->list, &cl->tx_queue);
  130. cl->txq_len += ub->len;
  131. }
  132. /* takes the msgbuf reference */
  133. void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub)
  134. {
  135. ssize_t written;
  136. if (ub->hdr.type != UBUS_MSG_MONITOR)
  137. ubusd_monitor_message(cl, ub, true);
  138. if (list_empty(&cl->tx_queue)) {
  139. written = ubus_msg_writev(cl->sock.fd, ub, 0);
  140. if (written < 0)
  141. written = 0;
  142. if (written >= (ssize_t) (ub->len + sizeof(ub->hdr)))
  143. return;
  144. cl->txq_ofs = written;
  145. cl->txq_len = -written;
  146. /* get an event once we can write to the socket again */
  147. uloop_fd_add(&cl->sock, ULOOP_READ | ULOOP_WRITE | ULOOP_EDGE_TRIGGER);
  148. }
  149. ubus_msg_enqueue(cl, ub);
  150. }