root/luci2/libuloop/uloop.c @ 6072

Revision 6072, 3.5 KB (checked in by Cyrus, 3 years ago)

uloop: Avoid fd-leakage

Line 
1/*
2 *   Copyright (C) 2010 John Crispin <blogic@openwrt.org>
3 *   Copyright (C) 2010 Steven Barth <steven@midlink.org>
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; either version 2 of the License, or
8 *   (at your option) any later version.
9 *
10 *   This program is distributed in the hope that it will be useful,
11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *   GNU General Public License for more details.
14 *
15 *   You should have received a copy of the GNU General Public License
16 *   along with this program; if not, write to the Free Software
17 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20
21#include <unistd.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <errno.h>
25#include <poll.h>
26#include <string.h>
27#include <time.h>
28#include <fcntl.h>
29#include <signal.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/epoll.h>
33
34#include <libubus.h>
35#include "uloop.h"
36#include "ulog.h"
37
38
39/**
40 * FIXME: uClibc < 0.9.30.3 does not define EPOLLRDHUP for Linux >= 2.6.17
41 */
42#ifndef EPOLLRDHUP
43#define EPOLLRDHUP 0x2000
44#endif
45
46
47static int epoll_fd = 0;
48static int uloop_loop = 1;
49static struct ubus_ctx *uloop_ubus = 0;
50
51void uloop_init(void)
52{
53    epoll_fd = epoll_create(32);
54    fcntl(epoll_fd, F_SETFD, fcntl(epoll_fd, F_GETFD) | FD_CLOEXEC);
55}
56
57static void uloop_ubus_cb(struct uloop_sock *u)
58{
59    ubus_recv(uloop_ubus);
60}
61
62struct uloop_sock* uloop_sock_add(int sock, void *priv, _uloop_sock_handler cb)
63{
64    struct epoll_event ev;
65    struct uloop_sock *u = malloc(sizeof(struct uloop_sock));
66    u->sock = sock;
67    u->priv = priv;
68    u->cb = cb;
69    memset(&ev, 0, sizeof(struct epoll_event));
70    ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
71    ev.data.fd = sock;
72    ev.data.ptr = u;
73    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev);
74    return u;
75}
76
77void uloop_ubus_add(struct ubus_ctx *ctx)
78{
79    if(!uloop_ubus)
80        uloop_ubus = ctx;
81}
82
83void uloop_sock_delete(struct uloop_sock *u)
84{
85    if(u->priv != uloop_ubus)
86        free(u->priv);
87    free(u);
88}
89
90static void uloop_handler_INT(int signo)
91{
92    LOG("away we go\n");
93    uloop_loop = 0;
94}
95
96static void uloop_setup_signals(void)
97{
98    struct sigaction s1, s2;
99    memset(&s1, 0, sizeof(struct sigaction));
100    memset(&s2, 0, sizeof(struct sigaction));
101    s1.sa_handler = uloop_handler_INT;
102    s1.sa_flags = 0;
103    sigaction(SIGINT, &s1, NULL);
104    s2.sa_handler = uloop_handler_INT;
105    s2.sa_flags = 0;
106    sigaction(SIGTERM, &s2, NULL);
107}
108
109int uloop(void (*cb)(void), int timeout)
110{
111    #define MAX_EVENTS  10
112    struct uloop_sock *ubus_sock = 0;
113    struct epoll_event events[MAX_EVENTS];
114    int nfds, n;
115    time_t t = time(0);
116    uloop_loop = 1;
117    uloop_setup_signals();
118    while(uloop_loop)
119    {
120        if(uloop_ubus)
121            if(ubus_connect(uloop_ubus) > 0)
122            {
123                int ubus_fd = ubus_get_sock(uloop_ubus);
124                fcntl(ubus_fd, F_SETFD, fcntl(ubus_fd, F_GETFD) | FD_CLOEXEC);
125                ubus_sock = uloop_sock_add(ubus_fd, uloop_ubus, uloop_ubus_cb);
126            }
127        nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, 1000);
128        for(n = 0; n < nfds; ++n)
129        {
130            struct uloop_sock *u = (struct uloop_sock*)events[n].data.ptr;
131            if(events[n].events & EPOLLRDHUP)
132            {
133                epoll_ctl(epoll_fd, EPOLL_CTL_DEL, u->sock, 0);
134                uloop_sock_delete(u);
135                close(u->sock);
136            } else if(events[n].events & EPOLLIN)
137            {
138                if(u->cb)
139                    u->cb(u);
140            }
141        }
142        if(cb)
143        {
144            if(difftime(time(0), t) < timeout)
145                continue;
146            t = time(0);
147            cb();
148        }
149    }
150    if(ubus_sock)
151        uloop_sock_delete(ubus_sock);
152    return 0;
153}
Note: See TracBrowser for help on using the browser.