1 #include "fdevent.h"
2 #include "buffer.h"
3 #include "log.h"
4 
5 #include <sys/types.h>
6 
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <signal.h>
13 #include <fcntl.h>
14 
15 #ifdef USE_SOLARIS_DEVPOLL
16 
17 # include <sys/devpoll.h>
18 
fdevent_solaris_devpoll_free(fdevents * ev)19 static void fdevent_solaris_devpoll_free(fdevents *ev) {
20 	free(ev->devpollfds);
21 	close(ev->devpoll_fd);
22 }
23 
24 /* return -1 is fine here */
25 
fdevent_solaris_devpoll_event_del(fdevents * ev,int fde_ndx,int fd)26 static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
27 	struct pollfd pfd;
28 
29 	if (fde_ndx < 0) return -1;
30 
31 	pfd.fd = fd;
32 	pfd.events = POLLREMOVE;
33 	pfd.revents = 0;
34 
35 	if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
36 		log_error_write(ev->srv, __FILE__, __LINE__, "S(D, S)",
37 			"(del) write failed: ", fd, strerror(errno));
38 
39 		return -1;
40 	}
41 
42 	return -1;
43 }
44 
fdevent_solaris_devpoll_event_set(fdevents * ev,int fde_ndx,int fd,int events)45 static int fdevent_solaris_devpoll_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
46 	struct pollfd pfd;
47 	int add = 0;
48 
49 	int pevents = 0;
50 	if (events & FDEVENT_IN)  pevents |= POLLIN;
51 	if (events & FDEVENT_OUT) pevents |= POLLOUT;
52 
53 	if (fde_ndx == -1) add = 1;
54 
55 	pfd.fd = fd;
56 	pfd.events = pevents;
57 	pfd.revents = 0;
58 
59 	if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
60 		log_error_write(ev->srv, __FILE__, __LINE__, "S(D, S)",
61 			"(set) write failed: ", fd, strerror(errno));
62 
63 		return -1;
64 	}
65 
66 	return fd;
67 }
68 
fdevent_solaris_devpoll_poll(fdevents * ev,int timeout_ms)69 static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
70 	struct dvpoll dopoll;
71 	int ret;
72 
73 	dopoll.dp_timeout = timeout_ms;
74 	dopoll.dp_nfds = ev->maxfds - 1;
75 	dopoll.dp_fds = ev->devpollfds;
76 
77 	ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
78 
79 	return ret;
80 }
81 
fdevent_solaris_devpoll_event_get_revent(fdevents * ev,size_t ndx)82 static int fdevent_solaris_devpoll_event_get_revent(fdevents *ev, size_t ndx) {
83 	int r, poll_r;
84 
85 	r = 0;
86 	poll_r = ev->devpollfds[ndx].revents;
87 
88 	/* map POLL* to FDEVEN_*; they are probably the same, but still. */
89 
90 	if (poll_r & POLLIN) r |= FDEVENT_IN;
91 	if (poll_r & POLLOUT) r |= FDEVENT_OUT;
92 	if (poll_r & POLLERR) r |= FDEVENT_ERR;
93 	if (poll_r & POLLHUP) r |= FDEVENT_HUP;
94 	if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
95 	if (poll_r & POLLPRI) r |= FDEVENT_PRI;
96 
97 	return r;
98 }
99 
fdevent_solaris_devpoll_event_get_fd(fdevents * ev,size_t ndx)100 static int fdevent_solaris_devpoll_event_get_fd(fdevents *ev, size_t ndx) {
101 	return ev->devpollfds[ndx].fd;
102 }
103 
fdevent_solaris_devpoll_event_next_fdndx(fdevents * ev,int last_ndx)104 static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
105 	size_t i;
106 
107 	UNUSED(ev);
108 
109 	i = (last_ndx < 0) ? 0 : last_ndx + 1;
110 
111 	return i;
112 }
113 
fdevent_solaris_devpoll_reset(fdevents * ev)114 int fdevent_solaris_devpoll_reset(fdevents *ev) {
115 	/* a forked process does only inherit the filedescriptor,
116 	 * but every operation on the device will lead to a EACCES */
117 	if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
118 		log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
119 			"opening /dev/poll failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
120 
121 		return -1;
122 	}
123 
124 	if (fcntl(ev->devpoll_fd, F_SETFD, FD_CLOEXEC) < 0) {
125 		log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
126 			"fcntl /dev/poll fd failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
127 
128 		close(ev->devpoll_fd);
129 
130 		return -1;
131 	}
132 	return 0;
133 }
fdevent_solaris_devpoll_init(fdevents * ev)134 int fdevent_solaris_devpoll_init(fdevents *ev) {
135 	ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
136 #define SET(x) \
137 	ev->x = fdevent_solaris_devpoll_##x;
138 
139 	SET(free);
140 	SET(poll);
141 	SET(reset);
142 
143 	SET(event_del);
144 	SET(event_set);
145 
146 	SET(event_next_fdndx);
147 	SET(event_get_fd);
148 	SET(event_get_revent);
149 
150 	ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
151 
152 	if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
153 		log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
154 			"opening /dev/poll failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
155 
156 		return -1;
157 	}
158 
159 	/* we just wanted to check if it works */
160 	close(ev->devpoll_fd);
161 
162 	ev->devpoll_fd = -1;
163 
164 	return 0;
165 }
166 
167 #else
fdevent_solaris_devpoll_init(fdevents * ev)168 int fdevent_solaris_devpoll_init(fdevents *ev) {
169 	UNUSED(ev);
170 
171 	log_error_write(ev->srv, __FILE__, __LINE__, "S",
172 		"solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"");
173 
174 	return -1;
175 }
176 #endif
177