mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
winsock_event handler, working resolution and validation on windows.
git-svn-id: file:///svn/unbound/trunk@1124 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
7a528cdf53
commit
f7059107b3
11 changed files with 763 additions and 61 deletions
|
|
@ -63,6 +63,9 @@
|
||||||
/* Define to 1 if you have the `gmtime_r' function. */
|
/* Define to 1 if you have the `gmtime_r' function. */
|
||||||
#undef HAVE_GMTIME_R
|
#undef HAVE_GMTIME_R
|
||||||
|
|
||||||
|
/* If you have HMAC_CTX_init */
|
||||||
|
#undef HAVE_HMAC_CTX_INIT
|
||||||
|
|
||||||
/* Define to 1 if you have the `inet_aton' function. */
|
/* Define to 1 if you have the `inet_aton' function. */
|
||||||
#undef HAVE_INET_ATON
|
#undef HAVE_INET_ATON
|
||||||
|
|
||||||
|
|
@ -81,9 +84,6 @@
|
||||||
/* Define to 1 if you have the `kill' function. */
|
/* Define to 1 if you have the `kill' function. */
|
||||||
#undef HAVE_KILL
|
#undef HAVE_KILL
|
||||||
|
|
||||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
|
||||||
#undef HAVE_LIBCRYPTO
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `ldns' library (-lldns). */
|
/* Define to 1 if you have the `ldns' library (-lldns). */
|
||||||
#undef HAVE_LIBLDNS
|
#undef HAVE_LIBLDNS
|
||||||
|
|
||||||
|
|
|
||||||
74
configure
vendored
74
configure
vendored
|
|
@ -19675,14 +19675,11 @@ echo "${ECHO_T}found in $ssldir" >&6
|
||||||
RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib"
|
RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "$as_me:$LINENO: checking for HMAC_CTX_init in -lcrypto" >&5
|
echo "$as_me:$LINENO: checking for HMAC_CTX_init in -lcrypto" >&5
|
||||||
echo $ECHO_N "checking for HMAC_CTX_init in -lcrypto... $ECHO_C" >&6
|
echo $ECHO_N "checking for HMAC_CTX_init in -lcrypto... $ECHO_C" >&6
|
||||||
if test "${ac_cv_lib_crypto_HMAC_CTX_init+set}" = set; then
|
ORIGLIBS="$LIBS"
|
||||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
LIBS="$LIBS -lcrypto"
|
||||||
else
|
cat >conftest.$ac_ext <<_ACEOF
|
||||||
ac_check_lib_save_LIBS=$LIBS
|
|
||||||
LIBS="-lcrypto $LIBS"
|
|
||||||
cat >conftest.$ac_ext <<_ACEOF
|
|
||||||
#line $LINENO "configure"
|
#line $LINENO "configure"
|
||||||
/* confdefs.h. */
|
/* confdefs.h. */
|
||||||
_ACEOF
|
_ACEOF
|
||||||
|
|
@ -19690,17 +19687,13 @@ cat confdefs.h >>conftest.$ac_ext
|
||||||
cat >>conftest.$ac_ext <<_ACEOF
|
cat >>conftest.$ac_ext <<_ACEOF
|
||||||
/* end confdefs.h. */
|
/* end confdefs.h. */
|
||||||
|
|
||||||
/* Override any gcc2 internal prototype to avoid an error. */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
#endif
|
|
||||||
/* We use char because int might match the return type of a gcc2
|
|
||||||
builtin and then its argument prototype would still apply. */
|
|
||||||
char HMAC_CTX_init ();
|
|
||||||
int
|
int
|
||||||
main ()
|
main ()
|
||||||
{
|
{
|
||||||
HMAC_CTX_init ();
|
|
||||||
|
int HMAC_CTX_init(void);
|
||||||
|
(void)HMAC_CTX_init();
|
||||||
|
|
||||||
;
|
;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -19717,29 +19710,24 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
|
||||||
ac_status=$?
|
ac_status=$?
|
||||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||||
(exit $ac_status); }; }; then
|
(exit $ac_status); }; }; then
|
||||||
ac_cv_lib_crypto_HMAC_CTX_init=yes
|
|
||||||
|
echo "$as_me:$LINENO: result: yes" >&5
|
||||||
|
echo "${ECHO_T}yes" >&6
|
||||||
|
|
||||||
|
cat >>confdefs.h <<\_ACEOF
|
||||||
|
#define HAVE_HMAC_CTX_INIT 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
|
||||||
else
|
else
|
||||||
echo "$as_me: failed program was:" >&5
|
echo "$as_me: failed program was:" >&5
|
||||||
sed 's/^/| /' conftest.$ac_ext >&5
|
sed 's/^/| /' conftest.$ac_ext >&5
|
||||||
|
|
||||||
ac_cv_lib_crypto_HMAC_CTX_init=no
|
|
||||||
fi
|
|
||||||
rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
|
|
||||||
LIBS=$ac_check_lib_save_LIBS
|
|
||||||
fi
|
|
||||||
echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_HMAC_CTX_init" >&5
|
|
||||||
echo "${ECHO_T}$ac_cv_lib_crypto_HMAC_CTX_init" >&6
|
|
||||||
if test $ac_cv_lib_crypto_HMAC_CTX_init = yes; then
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
|
||||||
#define HAVE_LIBCRYPTO 1
|
|
||||||
_ACEOF
|
|
||||||
|
|
||||||
LIBS="-lcrypto $LIBS"
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
|
echo "$as_me:$LINENO: result: no" >&5
|
||||||
|
echo "${ECHO_T}no" >&6
|
||||||
# check if -lwsock32 or -lgdi32 are needed.
|
# check if -lwsock32 or -lgdi32 are needed.
|
||||||
LIBS="$LIBS -lcrypto -lgdi32"
|
LIBS="$LIBS -lgdi32"
|
||||||
echo "$as_me:$LINENO: checking if -lcrypto needs -lgdi32" >&5
|
echo "$as_me:$LINENO: checking if -lcrypto needs -lgdi32" >&5
|
||||||
echo $ECHO_N "checking if -lcrypto needs -lgdi32... $ECHO_C" >&6
|
echo $ECHO_N "checking if -lcrypto needs -lgdi32... $ECHO_C" >&6
|
||||||
cat >conftest.$ac_ext <<_ACEOF
|
cat >conftest.$ac_ext <<_ACEOF
|
||||||
|
|
@ -19754,28 +19742,34 @@ int
|
||||||
main ()
|
main ()
|
||||||
{
|
{
|
||||||
|
|
||||||
void HMAC_CTX_init(void);
|
int HMAC_CTX_init(void);
|
||||||
(void)HMAC_CTX_init();
|
(void)HMAC_CTX_init();
|
||||||
|
|
||||||
;
|
;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_ACEOF
|
_ACEOF
|
||||||
rm -f conftest.$ac_objext
|
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||||
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
|
||||||
(eval $ac_compile) 2>&5
|
(eval $ac_link) 2>&5
|
||||||
ac_status=$?
|
ac_status=$?
|
||||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||||
(exit $ac_status); } &&
|
(exit $ac_status); } &&
|
||||||
{ ac_try='test -s conftest.$ac_objext'
|
{ ac_try='test -s conftest$ac_exeext'
|
||||||
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||||
(eval $ac_try) 2>&5
|
(eval $ac_try) 2>&5
|
||||||
ac_status=$?
|
ac_status=$?
|
||||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||||
(exit $ac_status); }; }; then
|
(exit $ac_status); }; }; then
|
||||||
|
|
||||||
|
|
||||||
|
cat >>confdefs.h <<\_ACEOF
|
||||||
|
#define HAVE_HMAC_CTX_INIT 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
echo "$as_me:$LINENO: result: yes" >&5
|
echo "$as_me:$LINENO: result: yes" >&5
|
||||||
echo "${ECHO_T}yes" >&6
|
echo "${ECHO_T}yes" >&6
|
||||||
|
|
||||||
else
|
else
|
||||||
echo "$as_me: failed program was:" >&5
|
echo "$as_me: failed program was:" >&5
|
||||||
sed 's/^/| /' conftest.$ac_ext >&5
|
sed 's/^/| /' conftest.$ac_ext >&5
|
||||||
|
|
@ -19788,10 +19782,10 @@ echo "$as_me: error: OpenSSL found in $ssldir, but version 0.9.7 or higher is re
|
||||||
{ (exit 1); exit 1; }; }
|
{ (exit 1); exit 1; }; }
|
||||||
|
|
||||||
fi
|
fi
|
||||||
rm -f conftest.$ac_objext conftest.$ac_ext
|
rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
29
configure.ac
29
configure.ac
|
|
@ -510,15 +510,30 @@ AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname],
|
||||||
if test "x$enable_rpath" = xyes; then
|
if test "x$enable_rpath" = xyes; then
|
||||||
RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib"
|
RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib"
|
||||||
fi
|
fi
|
||||||
AC_CHECK_LIB(crypto, HMAC_CTX_init,, [
|
|
||||||
|
AC_MSG_CHECKING([for HMAC_CTX_init in -lcrypto])
|
||||||
|
ORIGLIBS="$LIBS"
|
||||||
|
LIBS="$LIBS -lcrypto"
|
||||||
|
AC_TRY_LINK(, [
|
||||||
|
int HMAC_CTX_init(void);
|
||||||
|
(void)HMAC_CTX_init();
|
||||||
|
], [
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE([HAVE_HMAC_CTX_INIT], 1,
|
||||||
|
[If you have HMAC_CTX_init])
|
||||||
|
], [
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
# check if -lwsock32 or -lgdi32 are needed.
|
# check if -lwsock32 or -lgdi32 are needed.
|
||||||
LIBS="$LIBS -lcrypto -lgdi32"
|
LIBS="$LIBS -lgdi32"
|
||||||
AC_MSG_CHECKING([if -lcrypto needs -lgdi32])
|
AC_MSG_CHECKING([if -lcrypto needs -lgdi32])
|
||||||
AC_TRY_COMPILE([], [
|
AC_TRY_LINK([], [
|
||||||
void HMAC_CTX_init(void);
|
int HMAC_CTX_init(void);
|
||||||
(void)HMAC_CTX_init();
|
(void)HMAC_CTX_init();
|
||||||
], [
|
],[
|
||||||
AC_MSG_RESULT(yes) ],[
|
AC_DEFINE([HAVE_HMAC_CTX_INIT], 1,
|
||||||
|
[If you have HMAC_CTX_init])
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
],[
|
||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(no)
|
||||||
AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required])
|
AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required])
|
||||||
])
|
])
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,13 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_MINI_EVENT
|
#ifdef USE_MINI_EVENT
|
||||||
#include "util/mini_event.h"
|
# ifdef USE_WINSOCK
|
||||||
|
# include "util/winsock_event.h"
|
||||||
|
# else
|
||||||
|
# include "util/mini_event.h"
|
||||||
|
# endif
|
||||||
#else
|
#else
|
||||||
#include <event.h>
|
# include <event.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** global debug value to keep track of heap memory allocation */
|
/** global debug value to keep track of heap memory allocation */
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
17 June 2008: Wouter
|
||||||
|
- outgoing num fds 32 by default on windows ; it supports less
|
||||||
|
fds for waiting on than unixes.
|
||||||
|
- winsock_event minievent handler for windows. (you could also
|
||||||
|
attempt to link with libevent/libev ports for windows).
|
||||||
|
- neater crypto check and gdi32 detection.
|
||||||
|
- unbound.exe works to resolve and validate www.nlnetlabs.nl on vista.
|
||||||
|
|
||||||
16 June 2008: Wouter
|
16 June 2008: Wouter
|
||||||
- on windows, use windows threads, mutex and thread-local-storage(Tls).
|
- on windows, use windows threads, mutex and thread-local-storage(Tls).
|
||||||
- detect if openssl needs gdi32.
|
- detect if openssl needs gdi32.
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,11 @@ config_create()
|
||||||
cfg->do_udp = 1;
|
cfg->do_udp = 1;
|
||||||
cfg->do_tcp = 1;
|
cfg->do_tcp = 1;
|
||||||
cfg->use_syslog = 1;
|
cfg->use_syslog = 1;
|
||||||
|
#ifndef USE_WINSOCK
|
||||||
cfg->outgoing_num_ports = 256;
|
cfg->outgoing_num_ports = 256;
|
||||||
|
#else
|
||||||
|
cfg->outgoing_num_ports = 32; /* windows is limited in num fds */
|
||||||
|
#endif
|
||||||
cfg->outgoing_num_tcp = 10;
|
cfg->outgoing_num_tcp = 10;
|
||||||
cfg->incoming_num_tcp = 10;
|
cfg->incoming_num_tcp = 10;
|
||||||
cfg->msg_buffer_size = 65552; /* 64 k + a small margin */
|
cfg->msg_buffer_size = 65552; /* 64 k + a small margin */
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef USE_MINI_EVENT
|
#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include "util/mini_event.h"
|
#include "util/mini_event.h"
|
||||||
#include "util/fptr_wlist.h"
|
#include "util/fptr_wlist.h"
|
||||||
|
|
@ -376,8 +376,10 @@ int signal_del(struct event* ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* USE_MINI_EVENT */
|
#else /* USE_MINI_EVENT */
|
||||||
|
#ifndef USE_WINSOCK
|
||||||
int mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
int mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /* not USE_WINSOCK */
|
||||||
#endif /* USE_MINI_EVENT */
|
#endif /* USE_MINI_EVENT */
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
#ifndef MINI_EVENT_H
|
#ifndef MINI_EVENT_H
|
||||||
#define MINI_EVENT_H
|
#define MINI_EVENT_H
|
||||||
|
|
||||||
#ifdef USE_MINI_EVENT
|
#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
|
||||||
|
|
||||||
#ifndef HAVE_EVENT_BASE_FREE
|
#ifndef HAVE_EVENT_BASE_FREE
|
||||||
#define HAVE_EVENT_BASE_FREE
|
#define HAVE_EVENT_BASE_FREE
|
||||||
|
|
@ -124,7 +124,7 @@ struct event {
|
||||||
void *ev_arg;
|
void *ev_arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* function prototypes as they appear in event.h */
|
/* function prototypes (some are as they appear in event.h) */
|
||||||
/** create event base */
|
/** create event base */
|
||||||
void *event_init(uint32_t* time_secs, struct timeval* time_tv);
|
void *event_init(uint32_t* time_secs, struct timeval* time_tv);
|
||||||
/** get version */
|
/** get version */
|
||||||
|
|
@ -159,7 +159,7 @@ int signal_add(struct event *, struct timeval *);
|
||||||
/** remove signal handler */
|
/** remove signal handler */
|
||||||
int signal_del(struct event *);
|
int signal_del(struct event *);
|
||||||
|
|
||||||
#endif /* USE_MINI_EVENT */
|
#endif /* USE_MINI_EVENT and not USE_WINSOCK */
|
||||||
|
|
||||||
/** compare events in tree, based on timevalue, ptr for uniqueness */
|
/** compare events in tree, based on timevalue, ptr for uniqueness */
|
||||||
int mini_ev_cmp(const void* a, const void* b);
|
int mini_ev_cmp(const void* a, const void* b);
|
||||||
|
|
|
||||||
|
|
@ -54,11 +54,15 @@
|
||||||
/* We define libevent structures here to hide the libevent stuff. */
|
/* We define libevent structures here to hide the libevent stuff. */
|
||||||
|
|
||||||
#ifdef USE_MINI_EVENT
|
#ifdef USE_MINI_EVENT
|
||||||
#include "util/mini_event.h"
|
# ifdef USE_WINSOCK
|
||||||
#else
|
# include "util/winsock_event.h"
|
||||||
/* we use libevent */
|
# else
|
||||||
#include <event.h>
|
# include "util/mini_event.h"
|
||||||
#endif
|
# endif /* USE_WINSOCK */
|
||||||
|
#else /* USE_MINI_EVENT */
|
||||||
|
/* we use libevent */
|
||||||
|
# include <event.h>
|
||||||
|
#endif /* USE_MINI_EVENT */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The internal event structure for keeping libevent info for the event.
|
* The internal event structure for keeping libevent info for the event.
|
||||||
|
|
|
||||||
478
util/winsock_event.c
Normal file
478
util/winsock_event.c
Normal file
|
|
@ -0,0 +1,478 @@
|
||||||
|
/*
|
||||||
|
* util/winsock_event.c - implementation of the unbound winsock event handler.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008, NLnet Labs. All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is open source.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||||
|
* be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Implementation of the unbound WinSock2 API event notification handler
|
||||||
|
* for the Windows port.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#ifdef USE_WINSOCK
|
||||||
|
#include <signal.h>
|
||||||
|
#include "util/winsock_event.h"
|
||||||
|
#include "util/fptr_wlist.h"
|
||||||
|
|
||||||
|
int mini_ev_cmp(const void* a, const void* b)
|
||||||
|
{
|
||||||
|
const struct event *e = (const struct event*)a;
|
||||||
|
const struct event *f = (const struct event*)b;
|
||||||
|
if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
|
||||||
|
return -1;
|
||||||
|
if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
|
||||||
|
return 1;
|
||||||
|
if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
|
||||||
|
return -1;
|
||||||
|
if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
|
||||||
|
return 1;
|
||||||
|
if(e < f)
|
||||||
|
return -1;
|
||||||
|
if(e > f)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set time */
|
||||||
|
static int
|
||||||
|
settime(struct event_base* base)
|
||||||
|
{
|
||||||
|
if(gettimeofday(base->time_tv, NULL) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
*base->time_secs = (uint32_t)base->time_tv->tv_sec;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a fd in the list of items.
|
||||||
|
* Note that not all items have a fd associated (those are -1).
|
||||||
|
* Signals are stored separately, and not searched.
|
||||||
|
* @param base: event base to look in.
|
||||||
|
* @param fd: what socket to look for.
|
||||||
|
* @return the index in the array, or -1 on failure.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
find_fd(struct event_base* base, int fd)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<base->max; i++) {
|
||||||
|
if(base->items[i]->ev_fd == fd)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *event_init(uint32_t* time_secs, struct timeval* time_tv)
|
||||||
|
{
|
||||||
|
struct event_base* base = (struct event_base*)malloc(
|
||||||
|
sizeof(struct event_base));
|
||||||
|
if(!base)
|
||||||
|
return NULL;
|
||||||
|
memset(base, 0, sizeof(*base));
|
||||||
|
base->time_secs = time_secs;
|
||||||
|
base->time_tv = time_tv;
|
||||||
|
if(settime(base) < 0) {
|
||||||
|
event_base_free(base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
base->items = (struct event**)calloc(WSK_MAX_ITEMS,
|
||||||
|
sizeof(struct event*));
|
||||||
|
if(!base->items) {
|
||||||
|
event_base_free(base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
base->cap = WSK_MAX_ITEMS;
|
||||||
|
base->max = 0;
|
||||||
|
base->times = rbtree_create(mini_ev_cmp);
|
||||||
|
if(!base->times) {
|
||||||
|
event_base_free(base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*));
|
||||||
|
if(!base->signals) {
|
||||||
|
event_base_free(base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *event_get_version(void)
|
||||||
|
{
|
||||||
|
return "winsock-event-"PACKAGE_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *event_get_method(void)
|
||||||
|
{
|
||||||
|
return "WSAWaitForMultipleEvents";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** call timeouts handlers, and return how long to wait for next one or -1 */
|
||||||
|
static void handle_timeouts(struct event_base* base, struct timeval* now,
|
||||||
|
struct timeval* wait)
|
||||||
|
{
|
||||||
|
struct event* p;
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
wait->tv_sec = (time_t)-1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while((rbnode_t*)(p = (struct event*)rbtree_first(base->times))
|
||||||
|
!=RBTREE_NULL) {
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
if(p->ev_timeout.tv_sec > now->tv_sec ||
|
||||||
|
(p->ev_timeout.tv_sec==now->tv_sec &&
|
||||||
|
p->ev_timeout.tv_usec > now->tv_usec)) {
|
||||||
|
/* there is a next larger timeout. wait for it */
|
||||||
|
wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
|
||||||
|
if(now->tv_usec > p->ev_timeout.tv_usec) {
|
||||||
|
wait->tv_sec--;
|
||||||
|
wait->tv_usec = 1000000 - (now->tv_usec -
|
||||||
|
p->ev_timeout.tv_usec);
|
||||||
|
} else {
|
||||||
|
wait->tv_usec = p->ev_timeout.tv_usec
|
||||||
|
- now->tv_usec;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* event times out, remove it */
|
||||||
|
(void)rbtree_delete(base->times, p);
|
||||||
|
p->ev_events &= ~EV_TIMEOUT;
|
||||||
|
fptr_ok(fptr_whitelist_event(p->ev_callback));
|
||||||
|
(*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** call select and callbacks for that */
|
||||||
|
static int handle_select(struct event_base* base, struct timeval* wait)
|
||||||
|
{
|
||||||
|
DWORD timeout = 0; /* in milliseconds */
|
||||||
|
DWORD ret;
|
||||||
|
WSAEVENT waitfor[WSK_MAX_ITEMS];
|
||||||
|
struct event* eventlist[WSK_MAX_ITEMS];
|
||||||
|
WSANETWORKEVENTS netev;
|
||||||
|
int i, numwait = 0, startidx = 0, was_timeout = 0;
|
||||||
|
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
if(wait->tv_sec==(time_t)-1)
|
||||||
|
wait = NULL;
|
||||||
|
if(wait)
|
||||||
|
timeout = wait->tv_sec*1000 + wait->tv_usec/1000;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* prepare event array */
|
||||||
|
for(i=0; i<base->max; i++) {
|
||||||
|
if(base->items[i]->ev_fd == -1)
|
||||||
|
continue; /* skip timer only events */
|
||||||
|
eventlist[numwait] = base->items[i];
|
||||||
|
waitfor[numwait++] = base->items[i]->hEvent;
|
||||||
|
}
|
||||||
|
log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS);
|
||||||
|
|
||||||
|
|
||||||
|
/* do the wait */
|
||||||
|
if(numwait == 0) {
|
||||||
|
/* WSAWaitFor.. doesn't like 0 event objects */
|
||||||
|
if(wait) {
|
||||||
|
Sleep(timeout);
|
||||||
|
}
|
||||||
|
was_timeout = 1;
|
||||||
|
} else {
|
||||||
|
ret = WSAWaitForMultipleEvents(numwait, waitfor,
|
||||||
|
0 /* do not wait for all, just one will do */,
|
||||||
|
wait?timeout:WSA_INFINITE,
|
||||||
|
0); /* we are not alertable (IO completion events) */
|
||||||
|
if(ret == WSA_WAIT_IO_COMPLETION) {
|
||||||
|
log_err("WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION");
|
||||||
|
return -1;
|
||||||
|
} else if(ret == WSA_WAIT_FAILED) {
|
||||||
|
log_err("WSAWaitForMultipleEvents failed: %s",
|
||||||
|
wsa_strerror(WSAGetLastError()));
|
||||||
|
return -1;
|
||||||
|
} else if(ret == WSA_WAIT_TIMEOUT) {
|
||||||
|
was_timeout = 1;
|
||||||
|
} else
|
||||||
|
startidx = ret - WSA_WAIT_EVENT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get new time after wait */
|
||||||
|
if(settime(base) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* callbacks */
|
||||||
|
if(was_timeout)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for(i=startidx; i<numwait; i++) {
|
||||||
|
short bits = 0;
|
||||||
|
/* eventlist[i] fired */
|
||||||
|
if(WSAEnumNetworkEvents(eventlist[i]->ev_fd,
|
||||||
|
/*waitfor[i],*/ /* reset the event handle */
|
||||||
|
NULL, /* do not reset the event handle */
|
||||||
|
&netev) != 0) {
|
||||||
|
log_err("WSAEnumNetworkEvents failed: %s",
|
||||||
|
wsa_strerror(WSAGetLastError()));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if((netev.lNetworkEvents & FD_READ)) {
|
||||||
|
if(netev.iErrorCode[FD_READ_BIT] != 0)
|
||||||
|
log_err("FD_READ_BIT error: %s",
|
||||||
|
wsa_strerror(netev.iErrorCode[FD_READ_BIT]));
|
||||||
|
bits |= EV_READ;
|
||||||
|
}
|
||||||
|
if((netev.lNetworkEvents & FD_WRITE)) {
|
||||||
|
if(netev.iErrorCode[FD_WRITE_BIT] != 0)
|
||||||
|
log_err("FD_WRITE_BIT error: %s",
|
||||||
|
wsa_strerror(netev.iErrorCode[FD_WRITE_BIT]));
|
||||||
|
bits |= EV_WRITE;
|
||||||
|
}
|
||||||
|
if((netev.lNetworkEvents & FD_CONNECT)) {
|
||||||
|
if(netev.iErrorCode[FD_CONNECT_BIT] != 0)
|
||||||
|
log_err("FD_CONNECT_BIT error: %s",
|
||||||
|
wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT]));
|
||||||
|
bits |= EV_READ;
|
||||||
|
bits |= EV_WRITE;
|
||||||
|
}
|
||||||
|
if((netev.lNetworkEvents & FD_ACCEPT)) {
|
||||||
|
if(netev.iErrorCode[FD_ACCEPT_BIT] != 0)
|
||||||
|
log_err("FD_ACCEPT_BIT error: %s",
|
||||||
|
wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT]));
|
||||||
|
bits |= EV_READ;
|
||||||
|
}
|
||||||
|
if((netev.lNetworkEvents & FD_CLOSE)) {
|
||||||
|
if(netev.iErrorCode[FD_CLOSE_BIT] != 0)
|
||||||
|
log_err("FD_CLOSE_BIT error: %s",
|
||||||
|
wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT]));
|
||||||
|
bits |= EV_READ;
|
||||||
|
bits |= EV_WRITE;
|
||||||
|
}
|
||||||
|
if(bits) {
|
||||||
|
fptr_ok(fptr_whitelist_event(
|
||||||
|
eventlist[i]->ev_callback));
|
||||||
|
(*eventlist[i]->ev_callback)(eventlist[i]->ev_fd,
|
||||||
|
bits, eventlist[i]->ev_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_base_dispatch(struct event_base *base)
|
||||||
|
{
|
||||||
|
struct timeval wait;
|
||||||
|
if(settime(base) < 0)
|
||||||
|
return -1;
|
||||||
|
while(!base->need_to_exit)
|
||||||
|
{
|
||||||
|
/* see if timeouts need handling */
|
||||||
|
handle_timeouts(base, base->time_tv, &wait);
|
||||||
|
if(base->need_to_exit)
|
||||||
|
return 0;
|
||||||
|
/* do select */
|
||||||
|
if(handle_select(base, &wait) < 0) {
|
||||||
|
if(base->need_to_exit)
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_base_loopexit(struct event_base *base,
|
||||||
|
struct timeval * ATTR_UNUSED(tv))
|
||||||
|
{
|
||||||
|
base->need_to_exit = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void event_base_free(struct event_base *base)
|
||||||
|
{
|
||||||
|
if(!base)
|
||||||
|
return;
|
||||||
|
if(base->items)
|
||||||
|
free(base->items);
|
||||||
|
if(base->times)
|
||||||
|
free(base->times);
|
||||||
|
if(base->signals)
|
||||||
|
free(base->signals);
|
||||||
|
free(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void event_set(struct event *ev, int fd, short bits,
|
||||||
|
void (*cb)(int, short, void *), void *arg)
|
||||||
|
{
|
||||||
|
ev->node.key = ev;
|
||||||
|
ev->ev_fd = fd;
|
||||||
|
ev->ev_events = bits;
|
||||||
|
ev->ev_callback = cb;
|
||||||
|
fptr_ok(fptr_whitelist_event(ev->ev_callback));
|
||||||
|
ev->ev_arg = arg;
|
||||||
|
ev->added = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_base_set(struct event_base *base, struct event *ev)
|
||||||
|
{
|
||||||
|
ev->ev_base = base;
|
||||||
|
ev->added = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_add(struct event *ev, struct timeval *tv)
|
||||||
|
{
|
||||||
|
if(ev->added)
|
||||||
|
event_del(ev);
|
||||||
|
log_assert(ev->ev_fd==-1 || find_fd(ev->ev_base, ev->ev_fd) == -1);
|
||||||
|
if(ev->ev_base->max == ev->ev_base->cap)
|
||||||
|
return -1;
|
||||||
|
ev->idx = ev->ev_base->max++;
|
||||||
|
ev->ev_base->items[ev->idx] = ev;
|
||||||
|
|
||||||
|
if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
|
||||||
|
BOOL b=0;
|
||||||
|
int t, l;
|
||||||
|
long events = 0;
|
||||||
|
if( (ev->ev_events&EV_READ) )
|
||||||
|
events |= FD_READ;
|
||||||
|
if( (ev->ev_events&EV_WRITE) )
|
||||||
|
events |= FD_WRITE;
|
||||||
|
l = sizeof(t);
|
||||||
|
if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE,
|
||||||
|
(void*)&t, &l) != 0)
|
||||||
|
log_err("getsockopt(SO_TYPE) failed: %s",
|
||||||
|
wsa_strerror(WSAGetLastError()));
|
||||||
|
if(t == SOCK_STREAM) {
|
||||||
|
/* TCP socket */
|
||||||
|
events |= FD_CLOSE;
|
||||||
|
if( (ev->ev_events&EV_WRITE) )
|
||||||
|
events |= FD_CONNECT;
|
||||||
|
l = sizeof(b);
|
||||||
|
if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN,
|
||||||
|
(void*)&b, &l) != 0)
|
||||||
|
log_err("getsockopt(SO_ACCEPTCONN) failed: %s",
|
||||||
|
wsa_strerror(WSAGetLastError()));
|
||||||
|
if(b) /* TCP accept socket */
|
||||||
|
events |= FD_ACCEPT;
|
||||||
|
}
|
||||||
|
ev->hEvent = WSACreateEvent();
|
||||||
|
if(ev->hEvent == WSA_INVALID_EVENT)
|
||||||
|
log_err("WSACreateEvent failed: %s",
|
||||||
|
wsa_strerror(WSAGetLastError()));
|
||||||
|
/* automatically sets fd to nonblocking mode.
|
||||||
|
* nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */
|
||||||
|
if(WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) {
|
||||||
|
log_err("WSAEventSelect failed: %s",
|
||||||
|
wsa_strerror(WSAGetLastError()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tv && (ev->ev_events&EV_TIMEOUT)) {
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
struct timeval *now = ev->ev_base->time_tv;
|
||||||
|
ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
|
||||||
|
ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
|
||||||
|
while(ev->ev_timeout.tv_usec > 1000000) {
|
||||||
|
ev->ev_timeout.tv_usec -= 1000000;
|
||||||
|
ev->ev_timeout.tv_sec++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
(void)rbtree_insert(ev->ev_base->times, &ev->node);
|
||||||
|
}
|
||||||
|
ev->added = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_del(struct event *ev)
|
||||||
|
{
|
||||||
|
if(!ev->added)
|
||||||
|
return 0;
|
||||||
|
log_assert(ev->added && ev->ev_base->max > 0)
|
||||||
|
/* remove item and compact the list */
|
||||||
|
ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1];
|
||||||
|
ev->ev_base->items[ev->ev_base->max-1] = NULL;
|
||||||
|
ev->ev_base->max--;
|
||||||
|
if(ev->idx < ev->ev_base->max)
|
||||||
|
ev->ev_base->items[ev->idx]->idx = ev->idx;
|
||||||
|
|
||||||
|
if((ev->ev_events&EV_TIMEOUT))
|
||||||
|
(void)rbtree_delete(ev->ev_base->times, &ev->node);
|
||||||
|
if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
|
||||||
|
if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0)
|
||||||
|
log_err("WSAEventSelect(disable) failed: %s",
|
||||||
|
wsa_strerror(WSAGetLastError()));
|
||||||
|
if(!WSACloseEvent(ev->hEvent))
|
||||||
|
log_err("WSACloseEvent failed: %s",
|
||||||
|
wsa_strerror(WSAGetLastError()));
|
||||||
|
}
|
||||||
|
ev->added = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** which base gets to handle signals */
|
||||||
|
static struct event_base* signal_base = NULL;
|
||||||
|
/** signal handler */
|
||||||
|
static RETSIGTYPE sigh(int sig)
|
||||||
|
{
|
||||||
|
struct event* ev;
|
||||||
|
if(!signal_base || sig < 0 || sig >= MAX_SIG)
|
||||||
|
return;
|
||||||
|
ev = signal_base->signals[sig];
|
||||||
|
if(!ev)
|
||||||
|
return;
|
||||||
|
fptr_ok(fptr_whitelist_event(ev->ev_callback));
|
||||||
|
(*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int signal_add(struct event *ev, struct timeval * ATTR_UNUSED(tv))
|
||||||
|
{
|
||||||
|
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
|
||||||
|
return -1;
|
||||||
|
signal_base = ev->ev_base;
|
||||||
|
ev->ev_base->signals[ev->ev_fd] = ev;
|
||||||
|
ev->added = 1;
|
||||||
|
if(signal(ev->ev_fd, sigh) == SIG_ERR) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int signal_del(struct event *ev)
|
||||||
|
{
|
||||||
|
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
|
||||||
|
return -1;
|
||||||
|
ev->ev_base->signals[ev->ev_fd] = NULL;
|
||||||
|
ev->added = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USE_WINSOCK */
|
||||||
193
util/winsock_event.h
Normal file
193
util/winsock_event.h
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
/*
|
||||||
|
* util/winsock_event.h - unbound event handling for winsock on windows
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008, NLnet Labs. All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is open source.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||||
|
* be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* This file contains interface functions with the WinSock2 API on Windows.
|
||||||
|
* It uses the winsock WSAWaitForMultipleEvents interface on a number of
|
||||||
|
* sockets.
|
||||||
|
*
|
||||||
|
* Note that windows can only wait for max 64 events at one time.
|
||||||
|
*
|
||||||
|
* Also, file descriptors cannot be waited for.
|
||||||
|
*
|
||||||
|
* Named pipes are not easily available (and are not usable in select() ).
|
||||||
|
* For interprocess communication, it is possible to wait for a hEvent to
|
||||||
|
* be signaled by another thread.
|
||||||
|
*
|
||||||
|
* When a socket becomes readable, then it will not be flagged as
|
||||||
|
* readable again until you have gotten WOULDBLOCK from a recv routine.
|
||||||
|
* That means the event handler must store the readability (edge notify)
|
||||||
|
* and process the incoming data until it blocks.
|
||||||
|
* The function performing recv then has to inform the event handler that
|
||||||
|
* the socket has blocked, and the event handler can mark it as such.
|
||||||
|
* Thus, this file transforms the edge notify from windows to a level notify
|
||||||
|
* that is compatible with UNIX.
|
||||||
|
* However, the WSAEventSelect page says that it does do level notify, as long
|
||||||
|
* as you call a recv/write/accept at least once when it is signalled.
|
||||||
|
*
|
||||||
|
* To stay 'fair', instead of emptying a socket completely, the event handler
|
||||||
|
* can test the other (marked as blocking) sockets for new events.
|
||||||
|
*
|
||||||
|
* Additionally, TCP accept sockets get special event support.
|
||||||
|
*
|
||||||
|
* Socket numbers are not starting small, they can be any number (say 33060).
|
||||||
|
* Therefore, bitmaps are not used, but arrays.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTIL_WINSOCK_EVENT_H
|
||||||
|
#define UTIL_WINSOCK_EVENT_H
|
||||||
|
|
||||||
|
#ifdef USE_WINSOCK
|
||||||
|
|
||||||
|
#ifndef HAVE_EVENT_BASE_FREE
|
||||||
|
#define HAVE_EVENT_BASE_FREE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** event timeout */
|
||||||
|
#define EV_TIMEOUT 0x01
|
||||||
|
/** event fd readable */
|
||||||
|
#define EV_READ 0x02
|
||||||
|
/** event fd writable */
|
||||||
|
#define EV_WRITE 0x04
|
||||||
|
/** event signal */
|
||||||
|
#define EV_SIGNAL 0x08
|
||||||
|
/** event must persist */
|
||||||
|
#define EV_PERSIST 0x10
|
||||||
|
|
||||||
|
/* needs our redblack tree */
|
||||||
|
#include "rbtree.h"
|
||||||
|
|
||||||
|
/** max number of signals to support */
|
||||||
|
#define MAX_SIG 32
|
||||||
|
|
||||||
|
/** The number of items that the winsock event handler can service.
|
||||||
|
* Windows cannot handle more anyway */
|
||||||
|
#define WSK_MAX_ITEMS 64
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event base for winsock event handler
|
||||||
|
*/
|
||||||
|
struct event_base
|
||||||
|
{
|
||||||
|
/** sorted by timeout (absolute), ptr */
|
||||||
|
rbtree_t* times;
|
||||||
|
/** array (first part in use) of handles to work on */
|
||||||
|
struct event** items;
|
||||||
|
/** number of items in use in array */
|
||||||
|
int max;
|
||||||
|
/** capacity of array, size of array in items */
|
||||||
|
int cap;
|
||||||
|
/** array of 0 - maxsig of ptr to event for it */
|
||||||
|
struct event** signals;
|
||||||
|
/** if we need to exit */
|
||||||
|
int need_to_exit;
|
||||||
|
/** where to store time in seconds */
|
||||||
|
uint32_t* time_secs;
|
||||||
|
/** where to store time in microseconds */
|
||||||
|
struct timeval* time_tv;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event structure. Has some of the event elements.
|
||||||
|
*/
|
||||||
|
struct event {
|
||||||
|
/** node in timeout rbtree */
|
||||||
|
rbnode_t node;
|
||||||
|
/** is event already added */
|
||||||
|
int added;
|
||||||
|
|
||||||
|
/** event base it belongs to */
|
||||||
|
struct event_base *ev_base;
|
||||||
|
/** fd to poll or -1 for timeouts. signal number for sigs. */
|
||||||
|
int ev_fd;
|
||||||
|
/** what events this event is interested in, see EV_.. above. */
|
||||||
|
short ev_events;
|
||||||
|
/** timeout value */
|
||||||
|
struct timeval ev_timeout;
|
||||||
|
|
||||||
|
/** callback to call: fd, eventbits, userarg */
|
||||||
|
void (*ev_callback)(int, short, void *arg);
|
||||||
|
/** callback user arg */
|
||||||
|
void *ev_arg;
|
||||||
|
|
||||||
|
/* ----- nonpublic part, for winsock_event only ----- */
|
||||||
|
/** index of this event in the items array (if added) */
|
||||||
|
int idx;
|
||||||
|
/** the event handle to wait for new events to become ready */
|
||||||
|
WSAEVENT hEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** create event base */
|
||||||
|
void *event_init(uint32_t* time_secs, struct timeval* time_tv);
|
||||||
|
/** get version */
|
||||||
|
const char *event_get_version(void);
|
||||||
|
/** get polling method (select,epoll) */
|
||||||
|
const char *event_get_method(void);
|
||||||
|
/** run select in a loop */
|
||||||
|
int event_base_dispatch(struct event_base *);
|
||||||
|
/** exit that loop */
|
||||||
|
int event_base_loopexit(struct event_base *, struct timeval *);
|
||||||
|
/** free event base. Free events yourself */
|
||||||
|
void event_base_free(struct event_base *);
|
||||||
|
/** set content of event */
|
||||||
|
void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
|
||||||
|
|
||||||
|
/** add event to a base. You *must* call this for every event. */
|
||||||
|
int event_base_set(struct event_base *, struct event *);
|
||||||
|
/** add event to make it active. You may not change it with event_set anymore */
|
||||||
|
int event_add(struct event *, struct timeval *);
|
||||||
|
/** remove event. You may change it again */
|
||||||
|
int event_del(struct event *);
|
||||||
|
|
||||||
|
#define evtimer_add(ev, tv) event_add(ev, tv)
|
||||||
|
#define evtimer_del(ev) event_del(ev)
|
||||||
|
|
||||||
|
/* uses different implementation. Cannot mix fd/timeouts and signals inside
|
||||||
|
* the same struct event. create several event structs for that. */
|
||||||
|
/** install signal handler */
|
||||||
|
int signal_add(struct event *, struct timeval *);
|
||||||
|
/** set signal event contents */
|
||||||
|
#define signal_set(ev, x, cb, arg) \
|
||||||
|
event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
|
||||||
|
/** remove signal handler */
|
||||||
|
int signal_del(struct event *);
|
||||||
|
|
||||||
|
/** compare events in tree, based on timevalue, ptr for uniqueness */
|
||||||
|
int mini_ev_cmp(const void* a, const void* b);
|
||||||
|
|
||||||
|
#endif /* USE_WINSOCK */
|
||||||
|
#endif /* UTIL_WINSOCK_EVENT_H */
|
||||||
Loading…
Reference in a new issue