rrd based system stats
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

207 lines
4.4 KiB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <sys/ioctl.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. #include <netinet/ip.h>
  9. #include <arpa/inet.h>
  10. #include "configfile.h"
  11. #include "event.h"
  12. #include "helper.h"
  13. #include "list.h"
  14. #include "logging.h"
  15. #include "network.h"
  16. #include "plugins.h"
  17. #include "rrdtool.h"
  18. #include "sockaddr.h"
  19. #define PKTSIZE 1400
  20. struct net_entry {
  21. struct list_head list;
  22. struct event_fd *event;
  23. struct sockaddr_in addr;
  24. int socket;
  25. };
  26. static LIST_HEAD(srv_list);
  27. static LIST_HEAD(cli_list);
  28. static char *fwd_buf;
  29. static int fwd_buf_len;
  30. void net_submit_flush(void)
  31. {
  32. if (fwd_buf_len == 0)
  33. return;
  34. struct net_entry *entry;
  35. list_for_each_entry(entry, &cli_list, list)
  36. sendto(entry->socket, fwd_buf, fwd_buf_len, 0, (struct sockaddr *)&entry->addr, sizeof(entry->addr));
  37. fwd_buf_len = 0;
  38. }
  39. int net_submit(const char *hostname, const char *pluginname, const char *filename, int ds_id, const char *data)
  40. {
  41. if (list_empty(&cli_list))
  42. return 0;
  43. int size = snprintf(fwd_buf + fwd_buf_len, PKTSIZE - fwd_buf_len, "%s:%s:%s:%d %s\n",
  44. hostname, pluginname, filename, ds_id, data);
  45. if (size < 0 || size >= PKTSIZE - fwd_buf_len) {
  46. /* the complete buffer is already full */
  47. if (fwd_buf_len == 0) {
  48. log_print(LOG_ERROR, "net_submit(): arguments too long");
  49. return -1;
  50. }
  51. /* flush & retry */
  52. net_submit_flush();
  53. return net_submit(hostname, pluginname, filename, ds_id, data);
  54. }
  55. fwd_buf_len += size;
  56. return 0;
  57. }
  58. static int net_receive(int socket, void *privdata)
  59. {
  60. int recvsize;
  61. if (ioctl(socket, FIONREAD, &recvsize) == -1) {
  62. log_print(LOG_WARN, "net_receive(): ioctl(FIONREAD)");
  63. return 0;
  64. }
  65. char *buf = malloc(recvsize);
  66. if (buf == NULL) {
  67. log_print(LOG_WARN, "net_receive(): out of memory");
  68. return 0;
  69. }
  70. int size = recv(socket, buf, recvsize, 0);
  71. if (size <= 0) {
  72. log_print(LOG_WARN, "net_receive(): recv()");
  73. free(buf);
  74. return 0;
  75. }
  76. char *delim;
  77. int pos = 0;
  78. while ((delim = memchr(buf + pos, '\n', size - pos)) != NULL) {
  79. *delim = '\0';
  80. char *data[2];
  81. int ret = strsplit(buf + pos, " ", data, 2);
  82. pos = (delim - buf) +1;
  83. if (ret != 2) {
  84. log_print(LOG_ERROR, "net_receive(): abort data-split");
  85. continue;
  86. }
  87. char *part[4];
  88. ret = strsplit(data[0], ":", part, 4);
  89. if (ret != 4) {
  90. log_print(LOG_ERROR, "net_receive(): abort header-split");
  91. continue;
  92. }
  93. rrd_submit(part[0], part[1], part[2], atoi(part[3]), data[1]);
  94. }
  95. free(buf);
  96. return 0;
  97. }
  98. static struct net_entry * create_net_entry(const char *value)
  99. {
  100. struct net_entry *entry = malloc(sizeof(struct net_entry));
  101. if (entry == NULL)
  102. return NULL;
  103. if (parse_sockaddr(value, &entry->addr) < 0) {
  104. free(entry);
  105. return NULL;
  106. }
  107. entry->socket = socket(PF_INET, SOCK_DGRAM, 0);
  108. if (entry->socket < 0) {
  109. free(entry);
  110. return NULL;
  111. }
  112. return entry;
  113. }
  114. static int net_init_srv_cb(const char *value, void *privdata)
  115. {
  116. struct net_entry *entry = create_net_entry(value);
  117. if (entry == NULL) {
  118. log_print(LOG_ERROR, "net_init_srv_cb(): can not create net_entry");
  119. return -1;
  120. }
  121. if (bind(entry->socket, (struct sockaddr *)&entry->addr, sizeof(entry->addr)) < 0) {
  122. log_print(LOG_ERROR, "net_init_srv_cb(): bind()");
  123. close(entry->socket);
  124. free(entry);
  125. return -1;
  126. }
  127. entry->event = event_add_readfd(NULL, entry->socket, net_receive, NULL);
  128. list_add(&entry->list, &srv_list);
  129. log_print(LOG_INFO, "listen on %s", get_sockaddr_buf(&entry->addr));
  130. return 0;
  131. }
  132. static int net_init_cli_cb(const char *value, void *privdata)
  133. {
  134. struct net_entry *entry = create_net_entry(value);
  135. if (entry == NULL) {
  136. log_print(LOG_ERROR, "net_init_cli_cb(): can not create net_entry");
  137. return -1;
  138. }
  139. list_add(&entry->list, &cli_list);
  140. log_print(LOG_INFO, "forwarding to %s", get_sockaddr_buf(&entry->addr));
  141. return 0;
  142. }
  143. int net_init(void)
  144. {
  145. config_get_strings("global", "listen", net_init_srv_cb, NULL);
  146. config_get_strings("global", "forward", net_init_cli_cb, NULL);
  147. fwd_buf = malloc(PKTSIZE);
  148. if (fwd_buf == NULL) {
  149. log_print(LOG_ERROR, "net_submit(): out of memory");
  150. return -1;
  151. }
  152. return 0;
  153. }
  154. void net_close(void) {
  155. struct net_entry *entry, *tmp;
  156. list_for_each_entry_safe(entry, tmp, &cli_list, list) {
  157. list_del(&entry->list);
  158. close(entry->socket);
  159. free(entry);
  160. }
  161. list_for_each_entry_safe(entry, tmp, &srv_list, list) {
  162. list_del(&entry->list);
  163. event_remove_fd(entry->event);
  164. close(entry->socket);
  165. free(entry);
  166. }
  167. fwd_buf_len = 0;
  168. if (fwd_buf != NULL)
  169. free(fwd_buf);
  170. }