A clone of btpd with my configuration changes.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. The name of the author may not be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #ifdef HAVE_CONFIG_H
  28. #include "config.h"
  29. #endif
  30. #include <stdint.h>
  31. #include <sys/types.h>
  32. #include <sys/resource.h>
  33. #ifdef HAVE_SYS_TIME_H
  34. #include <sys/time.h>
  35. #else
  36. #include <sys/_time.h>
  37. #endif
  38. #include <sys/queue.h>
  39. #include <sys/epoll.h>
  40. #include <signal.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <unistd.h>
  45. #include <errno.h>
  46. #ifdef HAVE_FCNTL_H
  47. #include <fcntl.h>
  48. #endif
  49. #include "event.h"
  50. #include "evsignal.h"
  51. #include "log.h"
  52. extern volatile sig_atomic_t evsignal_caught;
  53. /* due to limitations in the epoll interface, we need to keep track of
  54. * all file descriptors outself.
  55. */
  56. struct evepoll {
  57. struct event *evread;
  58. struct event *evwrite;
  59. };
  60. struct epollop {
  61. struct evepoll *fds;
  62. int nfds;
  63. struct epoll_event *events;
  64. int nevents;
  65. int epfd;
  66. };
  67. void *epoll_init (void);
  68. int epoll_add (void *, struct event *);
  69. int epoll_del (void *, struct event *);
  70. int epoll_recalc (struct event_base *, void *, int);
  71. int epoll_dispatch (struct event_base *, void *, struct timeval *);
  72. void epoll_dealloc (void *);
  73. struct eventop epollops = {
  74. "epoll",
  75. epoll_init,
  76. epoll_add,
  77. epoll_del,
  78. epoll_recalc,
  79. epoll_dispatch,
  80. epoll_dealloc
  81. };
  82. #ifdef HAVE_SETFD
  83. #define FD_CLOSEONEXEC(x) do { \
  84. if (fcntl(x, F_SETFD, 1) == -1) \
  85. event_warn("fcntl(%d, F_SETFD)", x); \
  86. } while (0)
  87. #else
  88. #define FD_CLOSEONEXEC(x)
  89. #endif
  90. #define NEVENT 32000
  91. void *
  92. epoll_init(void)
  93. {
  94. int epfd, nfiles = NEVENT;
  95. struct rlimit rl;
  96. struct epollop *epollop;
  97. /* Disable epollueue when this environment variable is set */
  98. if (getenv("EVENT_NOEPOLL"))
  99. return (NULL);
  100. if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
  101. rl.rlim_cur != RLIM_INFINITY) {
  102. /*
  103. * Solaris is somewhat retarded - it's important to drop
  104. * backwards compatibility when making changes. So, don't
  105. * dare to put rl.rlim_cur here.
  106. */
  107. nfiles = rl.rlim_cur - 1;
  108. }
  109. /* Initalize the kernel queue */
  110. if ((epfd = epoll_create(nfiles)) == -1) {
  111. event_warn("epoll_create");
  112. return (NULL);
  113. }
  114. FD_CLOSEONEXEC(epfd);
  115. if (!(epollop = calloc(1, sizeof(struct epollop))))
  116. return (NULL);
  117. epollop->epfd = epfd;
  118. /* Initalize fields */
  119. epollop->events = malloc(nfiles * sizeof(struct epoll_event));
  120. if (epollop->events == NULL) {
  121. free(epollop);
  122. return (NULL);
  123. }
  124. epollop->nevents = nfiles;
  125. epollop->fds = calloc(nfiles, sizeof(struct evepoll));
  126. if (epollop->fds == NULL) {
  127. free(epollop->events);
  128. free(epollop);
  129. return (NULL);
  130. }
  131. epollop->nfds = nfiles;
  132. evsignal_init();
  133. return (epollop);
  134. }
  135. int
  136. epoll_recalc(struct event_base *base, void *arg, int max)
  137. {
  138. struct epollop *epollop = arg;
  139. if (max > epollop->nfds) {
  140. struct evepoll *fds;
  141. int nfds;
  142. nfds = epollop->nfds;
  143. while (nfds < max)
  144. nfds <<= 1;
  145. fds = realloc(epollop->fds, nfds * sizeof(struct evepoll));
  146. if (fds == NULL) {
  147. event_warn("realloc");
  148. return (-1);
  149. }
  150. epollop->fds = fds;
  151. memset(fds + epollop->nfds, 0,
  152. (nfds - epollop->nfds) * sizeof(struct evepoll));
  153. epollop->nfds = nfds;
  154. }
  155. return (0);
  156. }
  157. int
  158. epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
  159. {
  160. struct epollop *epollop = arg;
  161. struct epoll_event *events = epollop->events;
  162. struct evepoll *evep;
  163. int i, res, timeout;
  164. timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
  165. res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
  166. if (res == -1) {
  167. if (errno != EINTR) {
  168. event_warn("epoll_wait");
  169. return (-1);
  170. }
  171. evsignal_process();
  172. return (0);
  173. } else if (evsignal_caught)
  174. evsignal_process();
  175. event_debug(("%s: epoll_wait reports %d", __func__, res));
  176. for (i = 0; i < res; i++) {
  177. int which = 0;
  178. int what = events[i].events;
  179. struct event *evread = NULL, *evwrite = NULL;
  180. evep = (struct evepoll *)events[i].data.ptr;
  181. if (what & EPOLLHUP)
  182. what |= EPOLLIN | EPOLLOUT;
  183. else if (what & EPOLLERR)
  184. what |= EPOLLIN | EPOLLOUT;
  185. if (what & EPOLLIN) {
  186. evread = evep->evread;
  187. which |= EV_READ;
  188. }
  189. if (what & EPOLLOUT) {
  190. evwrite = evep->evwrite;
  191. which |= EV_WRITE;
  192. }
  193. if (!which)
  194. continue;
  195. if (evread != NULL && !(evread->ev_events & EV_PERSIST))
  196. event_del(evread);
  197. if (evwrite != NULL && evwrite != evread &&
  198. !(evwrite->ev_events & EV_PERSIST))
  199. event_del(evwrite);
  200. if (evread != NULL)
  201. event_active(evread, EV_READ, 1);
  202. if (evwrite != NULL)
  203. event_active(evwrite, EV_WRITE, 1);
  204. }
  205. return (0);
  206. }
  207. int
  208. epoll_add(void *arg, struct event *ev)
  209. {
  210. struct epollop *epollop = arg;
  211. struct epoll_event epev = {0, {0}};
  212. struct evepoll *evep;
  213. int fd, op, events;
  214. if (ev->ev_events & EV_SIGNAL)
  215. return (evsignal_add(ev));
  216. fd = ev->ev_fd;
  217. if (fd >= epollop->nfds) {
  218. /* Extent the file descriptor array as necessary */
  219. if (epoll_recalc(ev->ev_base, epollop, fd) == -1)
  220. return (-1);
  221. }
  222. evep = &epollop->fds[fd];
  223. op = EPOLL_CTL_ADD;
  224. events = 0;
  225. if (evep->evread != NULL) {
  226. events |= EPOLLIN;
  227. op = EPOLL_CTL_MOD;
  228. }
  229. if (evep->evwrite != NULL) {
  230. events |= EPOLLOUT;
  231. op = EPOLL_CTL_MOD;
  232. }
  233. if (ev->ev_events & EV_READ)
  234. events |= EPOLLIN;
  235. if (ev->ev_events & EV_WRITE)
  236. events |= EPOLLOUT;
  237. epev.data.ptr = evep;
  238. epev.events = events;
  239. if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)
  240. return (-1);
  241. /* Update events responsible */
  242. if (ev->ev_events & EV_READ)
  243. evep->evread = ev;
  244. if (ev->ev_events & EV_WRITE)
  245. evep->evwrite = ev;
  246. return (0);
  247. }
  248. int
  249. epoll_del(void *arg, struct event *ev)
  250. {
  251. struct epollop *epollop = arg;
  252. struct epoll_event epev = {0, {0}};
  253. struct evepoll *evep;
  254. int fd, events, op;
  255. int needwritedelete = 1, needreaddelete = 1;
  256. if (ev->ev_events & EV_SIGNAL)
  257. return (evsignal_del(ev));
  258. fd = ev->ev_fd;
  259. if (fd >= epollop->nfds)
  260. return (0);
  261. evep = &epollop->fds[fd];
  262. op = EPOLL_CTL_DEL;
  263. events = 0;
  264. if (ev->ev_events & EV_READ)
  265. events |= EPOLLIN;
  266. if (ev->ev_events & EV_WRITE)
  267. events |= EPOLLOUT;
  268. if ((events & (EPOLLIN|EPOLLOUT)) != (EPOLLIN|EPOLLOUT)) {
  269. if ((events & EPOLLIN) && evep->evwrite != NULL) {
  270. needwritedelete = 0;
  271. events = EPOLLOUT;
  272. op = EPOLL_CTL_MOD;
  273. } else if ((events & EPOLLOUT) && evep->evread != NULL) {
  274. needreaddelete = 0;
  275. events = EPOLLIN;
  276. op = EPOLL_CTL_MOD;
  277. }
  278. }
  279. epev.events = events;
  280. epev.data.ptr = evep;
  281. if (needreaddelete)
  282. evep->evread = NULL;
  283. if (needwritedelete)
  284. evep->evwrite = NULL;
  285. if (epoll_ctl(epollop->epfd, op, fd, &epev) == -1)
  286. return (-1);
  287. return (0);
  288. }
  289. void
  290. epoll_dealloc(void *arg)
  291. {
  292. struct epollop *epollop = arg;
  293. if (epollop->fds)
  294. free(epollop->fds);
  295. if (epollop->events)
  296. free(epollop->events);
  297. if (epollop->epfd >= 0)
  298. close(epollop->epfd);
  299. memset(epollop, 0, sizeof(struct epollop));
  300. free(epollop);
  301. }