1290001Sglebius/*
2290001Sglebius * Copyright 2007-2012 Niels Provos and Nick Mathewson
3290001Sglebius * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
4290001Sglebius * Copyright 2003 Michael A. Davis <mike@datanerds.net>
5290001Sglebius *
6290001Sglebius * Redistribution and use in source and binary forms, with or without
7290001Sglebius * modification, are permitted provided that the following conditions
8290001Sglebius * are met:
9290001Sglebius * 1. Redistributions of source code must retain the above copyright
10290001Sglebius *    notice, this list of conditions and the following disclaimer.
11290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright
12290001Sglebius *    notice, this list of conditions and the following disclaimer in the
13290001Sglebius *    documentation and/or other materials provided with the distribution.
14290001Sglebius * 3. The name of the author may not be used to endorse or promote products
15290001Sglebius *    derived from this software without specific prior written permission.
16290001Sglebius *
17290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27290001Sglebius */
28290001Sglebius#include "event2/event-config.h"
29290001Sglebius#include "evconfig-private.h"
30290001Sglebius
31290001Sglebius#ifdef _WIN32
32290001Sglebius
33290001Sglebius#include <winsock2.h>
34290001Sglebius#include <windows.h>
35290001Sglebius#include <sys/types.h>
36290001Sglebius#include <sys/queue.h>
37290001Sglebius#include <limits.h>
38290001Sglebius#include <signal.h>
39290001Sglebius#include <stdio.h>
40290001Sglebius#include <stdlib.h>
41290001Sglebius#include <string.h>
42290001Sglebius#include <errno.h>
43290001Sglebius
44290001Sglebius#include "event2/util.h"
45290001Sglebius#include "util-internal.h"
46290001Sglebius#include "log-internal.h"
47290001Sglebius#include "event2/event.h"
48290001Sglebius#include "event-internal.h"
49290001Sglebius#include "evmap-internal.h"
50290001Sglebius#include "event2/thread.h"
51290001Sglebius#include "evthread-internal.h"
52290001Sglebius#include "time-internal.h"
53290001Sglebius
54290001Sglebius#define XFREE(ptr) do { if (ptr) mm_free(ptr); } while (0)
55290001Sglebius
56290001Sglebiusextern struct event_list timequeue;
57290001Sglebiusextern struct event_list addqueue;
58290001Sglebius
59290001Sglebiusstruct win_fd_set {
60290001Sglebius	u_int fd_count;
61290001Sglebius	SOCKET fd_array[1];
62290001Sglebius};
63290001Sglebius
64290001Sglebius/* MSDN says this is required to handle SIGFPE */
65290001Sglebiusvolatile double SIGFPE_REQ = 0.0f;
66290001Sglebius
67290001Sglebiusstruct idx_info {
68290001Sglebius	int read_pos_plus1;
69290001Sglebius	int write_pos_plus1;
70290001Sglebius};
71290001Sglebius
72290001Sglebiusstruct win32op {
73290001Sglebius	unsigned num_fds_in_fd_sets;
74290001Sglebius	int resize_out_sets;
75290001Sglebius	struct win_fd_set *readset_in;
76290001Sglebius	struct win_fd_set *writeset_in;
77290001Sglebius	struct win_fd_set *readset_out;
78290001Sglebius	struct win_fd_set *writeset_out;
79290001Sglebius	struct win_fd_set *exset_out;
80290001Sglebius	unsigned signals_are_broken : 1;
81290001Sglebius};
82290001Sglebius
83290001Sglebiusstatic void *win32_init(struct event_base *);
84290001Sglebiusstatic int win32_add(struct event_base *, evutil_socket_t, short old, short events, void *idx_);
85290001Sglebiusstatic int win32_del(struct event_base *, evutil_socket_t, short old, short events, void *idx_);
86290001Sglebiusstatic int win32_dispatch(struct event_base *base, struct timeval *);
87290001Sglebiusstatic void win32_dealloc(struct event_base *);
88290001Sglebius
89290001Sglebiusstruct eventop win32ops = {
90290001Sglebius	"win32",
91290001Sglebius	win32_init,
92290001Sglebius	win32_add,
93290001Sglebius	win32_del,
94290001Sglebius	win32_dispatch,
95290001Sglebius	win32_dealloc,
96290001Sglebius	0, /* doesn't need reinit */
97290001Sglebius	0, /* No features supported. */
98290001Sglebius	sizeof(struct idx_info),
99290001Sglebius};
100290001Sglebius
101290001Sglebius#define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET)))
102290001Sglebius
103290001Sglebiusstatic int
104290001Sglebiusgrow_fd_sets(struct win32op *op, unsigned new_num_fds)
105290001Sglebius{
106290001Sglebius	size_t size;
107290001Sglebius
108290001Sglebius	EVUTIL_ASSERT(new_num_fds >= op->readset_in->fd_count &&
109290001Sglebius	       new_num_fds >= op->writeset_in->fd_count);
110290001Sglebius	EVUTIL_ASSERT(new_num_fds >= 1);
111290001Sglebius
112290001Sglebius	size = FD_SET_ALLOC_SIZE(new_num_fds);
113290001Sglebius	if (!(op->readset_in = mm_realloc(op->readset_in, size)))
114290001Sglebius		return (-1);
115290001Sglebius	if (!(op->writeset_in = mm_realloc(op->writeset_in, size)))
116290001Sglebius		return (-1);
117290001Sglebius	op->resize_out_sets = 1;
118290001Sglebius	op->num_fds_in_fd_sets = new_num_fds;
119290001Sglebius	return (0);
120290001Sglebius}
121290001Sglebius
122290001Sglebiusstatic int
123290001Sglebiusdo_fd_set(struct win32op *op, struct idx_info *ent, evutil_socket_t s, int read)
124290001Sglebius{
125290001Sglebius	struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
126290001Sglebius	if (read) {
127290001Sglebius		if (ent->read_pos_plus1 > 0)
128290001Sglebius			return (0);
129290001Sglebius	} else {
130290001Sglebius		if (ent->write_pos_plus1 > 0)
131290001Sglebius			return (0);
132290001Sglebius	}
133290001Sglebius	if (set->fd_count == op->num_fds_in_fd_sets) {
134290001Sglebius		if (grow_fd_sets(op, op->num_fds_in_fd_sets*2))
135290001Sglebius			return (-1);
136290001Sglebius		/* set pointer will have changed and needs reiniting! */
137290001Sglebius		set = read ? op->readset_in : op->writeset_in;
138290001Sglebius	}
139290001Sglebius	set->fd_array[set->fd_count] = s;
140290001Sglebius	if (read)
141290001Sglebius		ent->read_pos_plus1 = set->fd_count+1;
142290001Sglebius	else
143290001Sglebius		ent->write_pos_plus1 = set->fd_count+1;
144290001Sglebius	return (set->fd_count++);
145290001Sglebius}
146290001Sglebius
147290001Sglebiusstatic int
148290001Sglebiusdo_fd_clear(struct event_base *base,
149290001Sglebius			struct win32op *op, struct idx_info *ent, int read)
150290001Sglebius{
151290001Sglebius	int i;
152290001Sglebius	struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
153290001Sglebius	if (read) {
154290001Sglebius		i = ent->read_pos_plus1 - 1;
155290001Sglebius		ent->read_pos_plus1 = 0;
156290001Sglebius	} else {
157290001Sglebius		i = ent->write_pos_plus1 - 1;
158290001Sglebius		ent->write_pos_plus1 = 0;
159290001Sglebius	}
160290001Sglebius	if (i < 0)
161290001Sglebius		return (0);
162290001Sglebius	if (--set->fd_count != (unsigned)i) {
163290001Sglebius		struct idx_info *ent2;
164290001Sglebius		SOCKET s2;
165290001Sglebius		s2 = set->fd_array[i] = set->fd_array[set->fd_count];
166290001Sglebius
167290001Sglebius		ent2 = evmap_io_get_fdinfo_(&base->io, s2);
168290001Sglebius
169290001Sglebius		if (!ent2) /* This indicates a bug. */
170290001Sglebius			return (0);
171290001Sglebius		if (read)
172290001Sglebius			ent2->read_pos_plus1 = i+1;
173290001Sglebius		else
174290001Sglebius			ent2->write_pos_plus1 = i+1;
175290001Sglebius	}
176290001Sglebius	return (0);
177290001Sglebius}
178290001Sglebius
179290001Sglebius#define NEVENT 32
180290001Sglebiusvoid *
181290001Sglebiuswin32_init(struct event_base *base)
182290001Sglebius{
183290001Sglebius	struct win32op *winop;
184290001Sglebius	size_t size;
185290001Sglebius	if (!(winop = mm_calloc(1, sizeof(struct win32op))))
186290001Sglebius		return NULL;
187290001Sglebius	winop->num_fds_in_fd_sets = NEVENT;
188290001Sglebius	size = FD_SET_ALLOC_SIZE(NEVENT);
189290001Sglebius	if (!(winop->readset_in = mm_malloc(size)))
190290001Sglebius		goto err;
191290001Sglebius	if (!(winop->writeset_in = mm_malloc(size)))
192290001Sglebius		goto err;
193290001Sglebius	if (!(winop->readset_out = mm_malloc(size)))
194290001Sglebius		goto err;
195290001Sglebius	if (!(winop->writeset_out = mm_malloc(size)))
196290001Sglebius		goto err;
197290001Sglebius	if (!(winop->exset_out = mm_malloc(size)))
198290001Sglebius		goto err;
199290001Sglebius	winop->readset_in->fd_count = winop->writeset_in->fd_count = 0;
200290001Sglebius	winop->readset_out->fd_count = winop->writeset_out->fd_count
201290001Sglebius		= winop->exset_out->fd_count = 0;
202290001Sglebius
203290001Sglebius	if (evsig_init_(base) < 0)
204290001Sglebius		winop->signals_are_broken = 1;
205290001Sglebius
206290001Sglebius	evutil_weakrand_seed_(&base->weakrand_seed, 0);
207290001Sglebius
208290001Sglebius	return (winop);
209290001Sglebius err:
210290001Sglebius	XFREE(winop->readset_in);
211290001Sglebius	XFREE(winop->writeset_in);
212290001Sglebius	XFREE(winop->readset_out);
213290001Sglebius	XFREE(winop->writeset_out);
214290001Sglebius	XFREE(winop->exset_out);
215290001Sglebius	XFREE(winop);
216290001Sglebius	return (NULL);
217290001Sglebius}
218290001Sglebius
219290001Sglebiusint
220290001Sglebiuswin32_add(struct event_base *base, evutil_socket_t fd,
221290001Sglebius			 short old, short events, void *idx_)
222290001Sglebius{
223290001Sglebius	struct win32op *win32op = base->evbase;
224290001Sglebius	struct idx_info *idx = idx_;
225290001Sglebius
226290001Sglebius	if ((events & EV_SIGNAL) && win32op->signals_are_broken)
227290001Sglebius		return (-1);
228290001Sglebius
229290001Sglebius	if (!(events & (EV_READ|EV_WRITE)))
230290001Sglebius		return (0);
231290001Sglebius
232290001Sglebius	event_debug(("%s: adding event for %d", __func__, (int)fd));
233290001Sglebius	if (events & EV_READ) {
234290001Sglebius		if (do_fd_set(win32op, idx, fd, 1)<0)
235290001Sglebius			return (-1);
236290001Sglebius	}
237290001Sglebius	if (events & EV_WRITE) {
238290001Sglebius		if (do_fd_set(win32op, idx, fd, 0)<0)
239290001Sglebius			return (-1);
240290001Sglebius	}
241290001Sglebius	return (0);
242290001Sglebius}
243290001Sglebius
244290001Sglebiusint
245290001Sglebiuswin32_del(struct event_base *base, evutil_socket_t fd, short old, short events,
246290001Sglebius		  void *idx_)
247290001Sglebius{
248290001Sglebius	struct win32op *win32op = base->evbase;
249290001Sglebius	struct idx_info *idx = idx_;
250290001Sglebius
251290001Sglebius	event_debug(("%s: Removing event for "EV_SOCK_FMT,
252290001Sglebius		__func__, EV_SOCK_ARG(fd)));
253290001Sglebius	if (events & EV_READ)
254290001Sglebius		do_fd_clear(base, win32op, idx, 1);
255290001Sglebius	if (events & EV_WRITE)
256290001Sglebius		do_fd_clear(base, win32op, idx, 0);
257290001Sglebius
258290001Sglebius	return 0;
259290001Sglebius}
260290001Sglebius
261290001Sglebiusstatic void
262290001Sglebiusfd_set_copy(struct win_fd_set *out, const struct win_fd_set *in)
263290001Sglebius{
264290001Sglebius	out->fd_count = in->fd_count;
265290001Sglebius	memcpy(out->fd_array, in->fd_array, in->fd_count * (sizeof(SOCKET)));
266290001Sglebius}
267290001Sglebius
268290001Sglebius/*
269290001Sglebius  static void dump_fd_set(struct win_fd_set *s)
270290001Sglebius  {
271290001Sglebius  unsigned int i;
272290001Sglebius  printf("[ ");
273290001Sglebius  for(i=0;i<s->fd_count;++i)
274290001Sglebius  printf("%d ",(int)s->fd_array[i]);
275290001Sglebius  printf("]\n");
276290001Sglebius  }
277290001Sglebius*/
278290001Sglebius
279290001Sglebiusint
280290001Sglebiuswin32_dispatch(struct event_base *base, struct timeval *tv)
281290001Sglebius{
282290001Sglebius	struct win32op *win32op = base->evbase;
283290001Sglebius	int res = 0;
284290001Sglebius	unsigned j, i;
285290001Sglebius	int fd_count;
286290001Sglebius	SOCKET s;
287290001Sglebius
288290001Sglebius	if (win32op->resize_out_sets) {
289290001Sglebius		size_t size = FD_SET_ALLOC_SIZE(win32op->num_fds_in_fd_sets);
290290001Sglebius		if (!(win32op->readset_out = mm_realloc(win32op->readset_out, size)))
291290001Sglebius			return (-1);
292290001Sglebius		if (!(win32op->exset_out = mm_realloc(win32op->exset_out, size)))
293290001Sglebius			return (-1);
294290001Sglebius		if (!(win32op->writeset_out = mm_realloc(win32op->writeset_out, size)))
295290001Sglebius			return (-1);
296290001Sglebius		win32op->resize_out_sets = 0;
297290001Sglebius	}
298290001Sglebius
299290001Sglebius	fd_set_copy(win32op->readset_out, win32op->readset_in);
300290001Sglebius	fd_set_copy(win32op->exset_out, win32op->writeset_in);
301290001Sglebius	fd_set_copy(win32op->writeset_out, win32op->writeset_in);
302290001Sglebius
303290001Sglebius	fd_count =
304290001Sglebius	    (win32op->readset_out->fd_count > win32op->writeset_out->fd_count) ?
305290001Sglebius	    win32op->readset_out->fd_count : win32op->writeset_out->fd_count;
306290001Sglebius
307290001Sglebius	if (!fd_count) {
308290001Sglebius		long msec = tv ? evutil_tv_to_msec_(tv) : LONG_MAX;
309290001Sglebius		/* Sleep's DWORD argument is unsigned long */
310290001Sglebius		if (msec < 0)
311290001Sglebius			msec = LONG_MAX;
312290001Sglebius		/* Windows doesn't like you to call select() with no sockets */
313290001Sglebius		Sleep(msec);
314290001Sglebius		return (0);
315290001Sglebius	}
316290001Sglebius
317290001Sglebius	EVBASE_RELEASE_LOCK(base, th_base_lock);
318290001Sglebius
319290001Sglebius	res = select(fd_count,
320290001Sglebius		     (struct fd_set*)win32op->readset_out,
321290001Sglebius		     (struct fd_set*)win32op->writeset_out,
322290001Sglebius		     (struct fd_set*)win32op->exset_out, tv);
323290001Sglebius
324290001Sglebius	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
325290001Sglebius
326290001Sglebius	event_debug(("%s: select returned %d", __func__, res));
327290001Sglebius
328290001Sglebius	if (res <= 0) {
329290001Sglebius		return res;
330290001Sglebius	}
331290001Sglebius
332290001Sglebius	if (win32op->readset_out->fd_count) {
333290001Sglebius		i = evutil_weakrand_range_(&base->weakrand_seed,
334290001Sglebius		    win32op->readset_out->fd_count);
335290001Sglebius		for (j=0; j<win32op->readset_out->fd_count; ++j) {
336290001Sglebius			if (++i >= win32op->readset_out->fd_count)
337290001Sglebius				i = 0;
338290001Sglebius			s = win32op->readset_out->fd_array[i];
339290001Sglebius			evmap_io_active_(base, s, EV_READ);
340290001Sglebius		}
341290001Sglebius	}
342290001Sglebius	if (win32op->exset_out->fd_count) {
343290001Sglebius		i = evutil_weakrand_range_(&base->weakrand_seed,
344290001Sglebius		    win32op->exset_out->fd_count);
345290001Sglebius		for (j=0; j<win32op->exset_out->fd_count; ++j) {
346290001Sglebius			if (++i >= win32op->exset_out->fd_count)
347290001Sglebius				i = 0;
348290001Sglebius			s = win32op->exset_out->fd_array[i];
349290001Sglebius			evmap_io_active_(base, s, EV_WRITE);
350290001Sglebius		}
351290001Sglebius	}
352290001Sglebius	if (win32op->writeset_out->fd_count) {
353290001Sglebius		SOCKET s;
354290001Sglebius		i = evutil_weakrand_range_(&base->weakrand_seed,
355290001Sglebius		    win32op->writeset_out->fd_count);
356290001Sglebius		for (j=0; j<win32op->writeset_out->fd_count; ++j) {
357290001Sglebius			if (++i >= win32op->writeset_out->fd_count)
358290001Sglebius				i = 0;
359290001Sglebius			s = win32op->writeset_out->fd_array[i];
360290001Sglebius			evmap_io_active_(base, s, EV_WRITE);
361290001Sglebius		}
362290001Sglebius	}
363290001Sglebius	return (0);
364290001Sglebius}
365290001Sglebius
366290001Sglebiusvoid
367290001Sglebiuswin32_dealloc(struct event_base *base)
368290001Sglebius{
369290001Sglebius	struct win32op *win32op = base->evbase;
370290001Sglebius
371290001Sglebius	evsig_dealloc_(base);
372290001Sglebius	if (win32op->readset_in)
373290001Sglebius		mm_free(win32op->readset_in);
374290001Sglebius	if (win32op->writeset_in)
375290001Sglebius		mm_free(win32op->writeset_in);
376290001Sglebius	if (win32op->readset_out)
377290001Sglebius		mm_free(win32op->readset_out);
378290001Sglebius	if (win32op->writeset_out)
379290001Sglebius		mm_free(win32op->writeset_out);
380290001Sglebius	if (win32op->exset_out)
381290001Sglebius		mm_free(win32op->exset_out);
382290001Sglebius	/* XXXXX free the tree. */
383290001Sglebius
384290001Sglebius	memset(win32op, 0, sizeof(*win32op));
385290001Sglebius	mm_free(win32op);
386290001Sglebius}
387290001Sglebius
388290001Sglebius#endif
389