ebt_ulog based arpwatch
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.

300 lines
7.7KB

  1. /***************************************************************************
  2. * Copyright (C) 07/2007 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <sys/time.h>
  23. #include <sys/types.h>
  24. #include "list.h"
  25. #include "logging.h"
  26. #include "event.h"
  27. static LIST_HEAD(event_fd_list);
  28. static LIST_HEAD(event_timeout_list);
  29. struct event_fd {
  30. struct list_head list;
  31. unsigned int flags;
  32. int fd;
  33. int (*read_cb)(int fd, void *privdata);
  34. int (*write_cb)(int fd, void *privdata);
  35. void *read_priv;
  36. void *write_priv;
  37. };
  38. struct event_timeout {
  39. struct list_head list;
  40. unsigned int flags;
  41. struct timeval intervall;
  42. struct timeval nextrun;
  43. int (*callback)(void *privdata);
  44. void *privdata;
  45. };
  46. struct event_fd * event_add_fd(
  47. struct event_fd *entry,
  48. int fd,
  49. int type,
  50. int (*callback)(int fd, void *privdata),
  51. void *privdata)
  52. {
  53. /* check valid filediskriptor */
  54. if (fd < 0 || fd > FD_SETSIZE) {
  55. log_print(LOG_ERROR, "event_add_fd(): invalid fd");
  56. return NULL;
  57. }
  58. /* check valid type (read/write) */
  59. if (!(type & FD_TYPES)) {
  60. log_print(LOG_ERROR, "event_add_fd(): invalid type");
  61. return NULL;
  62. }
  63. /* create new entry */
  64. if (entry == NULL) {
  65. entry = malloc(sizeof(struct event_fd));
  66. if (entry == NULL) {
  67. log_print(LOG_ERROR, "event_add_fd(): out of memory");
  68. return NULL;
  69. }
  70. memset(entry, 0, sizeof(struct event_fd));
  71. entry->flags |= EVENT_NEW;
  72. entry->fd = fd;
  73. /* put it on the list */
  74. list_add_tail(&entry->list, &event_fd_list);
  75. }
  76. if (type & FD_READ) {
  77. entry->flags = (callback != NULL) ? (entry->flags | FD_READ | EVENT_NEW) : (entry->flags & ~FD_READ);
  78. entry->read_cb = callback;
  79. entry->read_priv = privdata;
  80. } else if (type & FD_WRITE) {
  81. entry->flags = (callback != NULL) ? (entry->flags | FD_WRITE | EVENT_NEW) : (entry->flags & ~FD_WRITE);
  82. entry->write_cb = callback;
  83. entry->write_priv = privdata;
  84. }
  85. return entry;
  86. }
  87. int event_get_fd(struct event_fd *entry)
  88. {
  89. return (entry != NULL) ? entry->fd: -1;
  90. }
  91. void event_remove_fd(struct event_fd *entry)
  92. {
  93. /* mark the event as deleted -> remove in select() loop */
  94. entry->flags |= EVENT_DELETE;
  95. }
  96. static void add_timeval(struct timeval *ret, struct timeval *a, struct timeval *b)
  97. {
  98. ret->tv_usec = a->tv_usec + b->tv_usec;
  99. ret->tv_sec = a->tv_sec + b->tv_sec;
  100. if (ret->tv_usec >= 1000000) {
  101. ret->tv_usec -= 1000000;
  102. ret->tv_sec++;
  103. }
  104. }
  105. static void sub_timeval(struct timeval *ret, struct timeval *a, struct timeval *b)
  106. {
  107. ret->tv_usec = a->tv_usec - b->tv_usec;
  108. ret->tv_sec = a->tv_sec - b->tv_sec;
  109. if (ret->tv_usec < 0) {
  110. ret->tv_usec += 1000000;
  111. ret->tv_sec--;
  112. }
  113. }
  114. static int cmp_timeval(struct timeval *a, struct timeval *b)
  115. {
  116. if (a->tv_sec > b->tv_sec)
  117. return -1;
  118. if (a->tv_sec < b->tv_sec)
  119. return 1;
  120. if (a->tv_usec > b->tv_usec)
  121. return -1;
  122. if (a->tv_usec < b->tv_usec)
  123. return 1;
  124. return 0;
  125. }
  126. static void schedule_nextrun(struct event_timeout *entry, struct timeval *now)
  127. {
  128. add_timeval(&entry->nextrun, now, &entry->intervall);
  129. struct event_timeout *search;
  130. list_for_each_entry(search, &event_timeout_list, list) {
  131. if (search->nextrun.tv_sec > entry->nextrun.tv_sec) {
  132. list_add_tail(&entry->list, &search->list);
  133. return;
  134. } else if (search->nextrun.tv_sec == entry->nextrun.tv_sec &&
  135. search->nextrun.tv_usec > entry->nextrun.tv_usec) {
  136. list_add_tail(&entry->list, &search->list);
  137. return;
  138. }
  139. }
  140. list_add_tail(&entry->list, &event_timeout_list);
  141. }
  142. struct event_timeout * event_add_timeout(
  143. struct timeval *timeout,
  144. int (*callback)(void *privdata),
  145. void *privdata)
  146. {
  147. struct event_timeout *entry;
  148. entry = malloc(sizeof(struct event_timeout));
  149. if (entry == NULL) {
  150. log_print(LOG_ERROR, "event_add_timeout(): out of memory");
  151. return NULL;
  152. }
  153. entry->flags = 0;
  154. memcpy(&entry->intervall, timeout, sizeof(entry->intervall));
  155. entry->callback = callback;
  156. entry->privdata = privdata;
  157. struct timeval now;
  158. gettimeofday(&now, NULL);
  159. schedule_nextrun(entry, &now);
  160. return entry;
  161. }
  162. void event_remove_timeout(struct event_timeout *entry)
  163. {
  164. /* mark the event as deleted -> remove in select() loop */
  165. entry->flags |= EVENT_DELETE;
  166. }
  167. int event_loop(void)
  168. {
  169. fd_set *fdsets = malloc(sizeof(fd_set) * 2);
  170. if (fdsets == NULL) {
  171. log_print(LOG_ERROR, "event_loop(): out of memory");
  172. return -1;
  173. }
  174. while (1) {
  175. struct timeval timeout, *timeout_p = NULL;
  176. if (!list_empty(&event_timeout_list)) {
  177. struct timeval now;
  178. gettimeofday(&now, NULL);
  179. struct event_timeout *entry, *tmp;
  180. list_for_each_entry_safe(entry, tmp, &event_timeout_list, list) {
  181. if (entry->flags & EVENT_DELETE) {
  182. list_del(&entry->list);
  183. free(entry);
  184. continue;
  185. }
  186. /* first timeout not elapsed, exit search (since list is sorted) */
  187. if (cmp_timeval(&entry->nextrun, &now) == -1)
  188. break;
  189. /* remove event from list */
  190. list_del(&entry->list);
  191. /* execute callback, when callback returns 0 -> schedule event again */
  192. if (entry->callback(entry->privdata)) {
  193. free(entry);
  194. } else {
  195. schedule_nextrun(entry, &now);
  196. }
  197. }
  198. if (!list_empty(&event_timeout_list)) {
  199. entry = list_entry(event_timeout_list.next, typeof(*entry), list);
  200. /* calc select() timeout */
  201. sub_timeval(&timeout, &entry->nextrun, &now);
  202. timeout_p = &timeout;
  203. }
  204. }
  205. fd_set *readfds = NULL, *writefds = NULL;
  206. struct event_fd *entry, *tmp;
  207. list_for_each_entry_safe(entry, tmp, &event_fd_list, list) {
  208. entry->flags &= ~EVENT_NEW;
  209. if (entry->flags & EVENT_DELETE) {
  210. list_del(&entry->list);
  211. free(entry);
  212. continue;
  213. }
  214. if (entry->flags & FD_READ) {
  215. if (readfds == NULL) {
  216. readfds = &fdsets[0];
  217. FD_ZERO(readfds);
  218. }
  219. FD_SET(entry->fd, readfds);
  220. }
  221. if (entry->flags & FD_WRITE) {
  222. if (writefds == NULL) {
  223. writefds = &fdsets[1];
  224. FD_ZERO(writefds);
  225. }
  226. FD_SET(entry->fd, writefds);
  227. }
  228. }
  229. int i = select(FD_SETSIZE, readfds, writefds, NULL, timeout_p);
  230. if (i <= 0) {
  231. /* On error, -1 is returned, and errno is set
  232. * appropriately; the sets and timeout become
  233. * undefined, so do not rely on their contents
  234. * after an error.
  235. */
  236. continue;
  237. }
  238. list_for_each_entry(entry, &event_fd_list, list) {
  239. if (((entry->flags & (FD_READ | EVENT_NEW)) == FD_READ) && FD_ISSET(entry->fd, readfds))
  240. if (entry->read_cb(entry->fd, entry->read_priv) != 0)
  241. entry->flags |= EVENT_DELETE;
  242. if (((entry->flags & (FD_WRITE | EVENT_NEW)) == FD_WRITE) && FD_ISSET(entry->fd, writefds))
  243. if (entry->write_cb(entry->fd, entry->write_priv) != 0)
  244. entry->flags |= EVENT_DELETE;
  245. }
  246. }
  247. free(fdsets);
  248. }