summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaromil <jaromil@dyne.org>2013-03-05 13:20:21 (GMT)
committer Jaromil <jaromil@dyne.org>2013-03-05 13:20:21 (GMT)
commit11fa5eafe676d9739e0a41c2aad3ad6f6e696ff1 (patch)
tree082d5622326e6a71d5d3f3790dcc73fe71412e1c
parentfede1451017c1e481e9eb0ac64c5464a4f4a198b (diff)
updated to libpgm 5.2.122
-rw-r--r--configure.ac12
-rw-r--r--src/pgm/Makefile.am5
-rw-r--r--src/pgm/checksum.c25
-rw-r--r--src/pgm/engine.c26
-rw-r--r--src/pgm/error.c19
-rwxr-xr-xsrc/pgm/galois_generator.pl9
-rw-r--r--src/pgm/galois_tables.c7
-rw-r--r--src/pgm/get_nprocs.c4
-rw-r--r--src/pgm/getifaddrs.c338
-rw-r--r--src/pgm/getnetbyname.c16
-rw-r--r--src/pgm/getnodeaddr.c14
-rw-r--r--src/pgm/getprotobyname.c18
-rw-r--r--src/pgm/gsi.c37
-rw-r--r--src/pgm/hashtable.c3
-rw-r--r--src/pgm/histogram.c5
-rw-r--r--src/pgm/if.c186
-rw-r--r--src/pgm/impl/checksum.h78
-rw-r--r--src/pgm/impl/engine.h46
-rw-r--r--src/pgm/impl/errno.h42
-rw-r--r--src/pgm/impl/fixed.h145
-rw-r--r--src/pgm/impl/framework.h83
-rw-r--r--src/pgm/impl/galois.h146
-rw-r--r--src/pgm/impl/get_nprocs.h41
-rw-r--r--src/pgm/impl/getifaddrs.h79
-rw-r--r--src/pgm/impl/getnetbyname.h49
-rw-r--r--src/pgm/impl/getnodeaddr.h48
-rw-r--r--src/pgm/impl/getprotobyname.h49
-rw-r--r--src/pgm/impl/hashtable.h61
-rw-r--r--src/pgm/impl/histogram.h132
-rw-r--r--src/pgm/impl/i18n.h35
-rw-r--r--src/pgm/impl/indextoaddr.h44
-rw-r--r--src/pgm/impl/indextoname.h40
-rw-r--r--src/pgm/impl/inet_lnaof.h37
-rw-r--r--src/pgm/impl/inet_network.h46
-rw-r--r--src/pgm/impl/ip.h153
-rw-r--r--src/pgm/impl/list.h46
-rw-r--r--src/pgm/impl/math.h79
-rw-r--r--src/pgm/impl/md5.h64
-rw-r--r--src/pgm/impl/mem.h37
-rw-r--r--src/pgm/impl/messages.h361
-rw-r--r--src/pgm/impl/nametoindex.h43
-rw-r--r--src/pgm/impl/net.h57
-rw-r--r--src/pgm/impl/notify.h310
-rw-r--r--src/pgm/impl/packet_parse.h48
-rw-r--r--src/pgm/impl/packet_test.h43
-rw-r--r--src/pgm/impl/pgmMIB.h31
-rw-r--r--src/pgm/impl/pgmMIB_columns.h376
-rw-r--r--src/pgm/impl/pgmMIB_enums.h68
-rw-r--r--src/pgm/impl/processor.h51
-rw-r--r--src/pgm/impl/queue.h54
-rw-r--r--src/pgm/impl/rand.h53
-rw-r--r--src/pgm/impl/rate_control.h59
-rw-r--r--src/pgm/impl/receiver.h144
-rw-r--r--src/pgm/impl/reed_solomon.h54
-rw-r--r--src/pgm/impl/rwspinlock.h140
-rw-r--r--src/pgm/impl/rxw.h218
-rw-r--r--src/pgm/impl/security.h265
-rw-r--r--src/pgm/impl/slist.h55
-rw-r--r--src/pgm/impl/sn.h137
-rw-r--r--src/pgm/impl/sockaddr.h176
-rw-r--r--src/pgm/impl/socket.h189
-rw-r--r--src/pgm/impl/source.h78
-rw-r--r--src/pgm/impl/sqn_list.h41
-rw-r--r--src/pgm/impl/string.h62
-rw-r--r--src/pgm/impl/thread.h350
-rw-r--r--src/pgm/impl/ticket.h407
-rw-r--r--src/pgm/impl/time.h54
-rw-r--r--src/pgm/impl/timer.h61
-rw-r--r--src/pgm/impl/tsi.h42
-rw-r--r--src/pgm/impl/txw.h202
-rw-r--r--src/pgm/impl/wsastrerror.h40
-rw-r--r--src/pgm/indextoaddr.c7
-rw-r--r--src/pgm/indextoname.c14
-rw-r--r--src/pgm/inet_network.c3
-rw-r--r--src/pgm/list.c3
-rw-r--r--src/pgm/math.c5
-rw-r--r--src/pgm/md5.c3
-rw-r--r--src/pgm/mem.c9
-rw-r--r--src/pgm/messages.c3
-rw-r--r--src/pgm/nametoindex.c17
-rw-r--r--src/pgm/net.c9
-rw-r--r--src/pgm/packet_parse.c7
-rw-r--r--src/pgm/packet_test.c3
-rw-r--r--src/pgm/queue.c3
-rw-r--r--src/pgm/rand.c8
-rw-r--r--src/pgm/rate_control.c3
-rw-r--r--src/pgm/receiver.c5
-rw-r--r--src/pgm/recv.c36
-rw-r--r--src/pgm/reed_solomon.c19
-rw-r--r--src/pgm/rxw.c5
-rw-r--r--src/pgm/skbuff.c3
-rw-r--r--src/pgm/slist.c3
-rw-r--r--src/pgm/sockaddr.c250
-rw-r--r--src/pgm/socket.c46
-rw-r--r--src/pgm/source.c6
-rw-r--r--src/pgm/string.c22
-rw-r--r--src/pgm/thread.c105
-rw-r--r--src/pgm/time.c310
-rw-r--r--src/pgm/timer.c3
-rw-r--r--src/pgm/tsi.c3
-rw-r--r--src/pgm/txw.c3
-rw-r--r--src/pgm/wsastrerror.c50
102 files changed, 7037 insertions, 502 deletions
diff --git a/configure.ac b/configure.ac
index 79958ad..f45a0f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,6 +55,18 @@ AC_CHECK_TYPES([struct in_pktinfo, in_port_t], , , [#include <sys/types.h>
dnl AC_CHECK_HEADERS([stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h])
+# interface enumeration
+AC_CHECK_FUNCS([getifaddrs])
+AC_MSG_CHECKING([for struct ifreq.ifr_netmask])
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([[#include <sys/types.h>
+#include <ifaddrs.h>]],
+ [[struct ifreq ifr;
+ifr.ifr_netmask = (struct sockaddr*)0;]])],
+ [AC_MSG_RESULT([yes])
+ CFLAGS="$CFLAGS -DHAVE_STRUCT_IFREQ_IFR_NETMASK"],
+ [AC_MSG_RESULT([no])])
+
dnl ==============================================================
dnl compile with full warnings and debugging symbols
diff --git a/src/pgm/Makefile.am b/src/pgm/Makefile.am
index 2796eb4..4f61089 100644
--- a/src/pgm/Makefile.am
+++ b/src/pgm/Makefile.am
@@ -1,14 +1,14 @@
INCLUDES = -I$(top_builddir)/src -I$(top_builddir)/src/include
AM_CFLAGS = -std=gnu99 -D_REENTRANT -D_GNU_SOURCE -D__need_IOV_MAX \
--DCONFIG_16BIT_CHECKSUM -DCONFIG_HAVE_PROC -DCONFIG_HAVE_BACKTRACE \
+-DUSE_8BIT_CHECKSUM -DCONFIG_HAVE_PROC -DCONFIG_HAVE_BACKTRACE \
-DCONFIG_HAVE_PSELECT -DCONFIG_HAVE_POLL -DCONFIG_HAVE_EPOLL \
-DCONFIG_HAVE_CLOCK_GETTIME -DCONFIG_HAVE_CLOCK_NANOSLEEP \
-DCONFIG_HAVE_NANOSLEEP -DCONFIG_HAVE_USLEEP -DCONFIG_HAVE_RTC \
-DCONFIG_HAVE_IFR_NETMASK -DCONFIG_HAVE_GETIFADDRS \
-DCONFIG_HAVE_GETHOSTBYNAME2 -DCONFIG_HAVE_MCAST_JOIN \
-DCONFIG_HAVE_IP_MREQN -DCONFIG_HAVE_DSO_VISIBILITY \
--DCONFIG_BIND_INADDR_ANY -DCONFIG_GALOIS_MUL_LUT
+-DCONFIG_BIND_INADDR_ANY -DUSE_GALOIS_MUL_LUT
noinst_LTLIBRARIES = libpgm.la
@@ -41,6 +41,7 @@ libpgm_la_SOURCES = \
indextoname.c \
nametoindex.c \
inet_network.c \
+ inet_lnaof.c \
md5.c \
rand.c \
gsi.c \
diff --git a/src/pgm/checksum.c b/src/pgm/checksum.c
index c773b99..9b1aa3b 100644
--- a/src/pgm/checksum.c
+++ b/src/pgm/checksum.c
@@ -2,7 +2,7 @@
*
* PGM checksum routines
*
- * Copyright (c) 2006-2010 Miru Limited.
+ * Copyright (c) 2006-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
@@ -823,15 +826,15 @@ do_csum (
uint32_t csum
)
{
-#if defined(CONFIG_8BIT_CHECKSUM)
+#if defined( USE_8BIT_CHECKSUM )
return do_csum_8bit (addr, len, csum);
-#elif defined(CONFIG_16BIT_CHECKSUM)
+#elif defined( USE_16BIT_CHECKSUM )
return do_csum_16bit (addr, len, csum);
-#elif defined(CONFIG_32BIT_CHECKSUM)
+#elif defined( USE_32BIT_CHECKSUM )
return do_csum_32bit (addr, len, csum);
-#elif defined(CONFIG_64BIT_CHECKSUM)
+#elif defined( USE_64BIT_CHECKSUM )
return do_csum_64bit (addr, len, csum);
-#elif defined(CONFIG_VECTOR_CHECKSUM)
+#elif defined( USE_VECTOR_CHECKSUM )
return do_csum_vector (addr, len, csum);
#else
# error "checksum routine undefined"
@@ -896,15 +899,15 @@ pgm_compat_csum_partial_copy (
memcpy (dst, src, len);
return pgm_csum_partial (dst, len, csum);
#else
-# if defined(CONFIG_8BIT_CHECKSUM)
+# if defined( USE_8BIT_CHECKSUM )
return do_csumcpy_8bit (src, dst, len, csum);
-# elif defined(CONFIG_16BIT_CHECKSUM)
+# elif defined( USE_16BIT_CHECKSUM )
return do_csumcpy_16bit (src, dst, len, csum);
-# elif defined(CONFIG_32BIT_CHECKSUM)
+# elif defined( USE_32BIT_CHECKSUM )
return do_csumcpy_32bit (src, dst, len, csum);
-# elif defined(CONFIG_64BIT_CHECKSUM)
+# elif defined( USE_64BIT_CHECKSUM )
return do_csumcpy_64bit (src, dst, len, csum);
-# elif defined(CONFIG_VECTOR_CHECKSUM)
+# elif defined( USE_VECTOR_CHECKSUM )
return do_csumcpy_vector (src, dst, len, csum);
# else
memcpy (dst, src, len);
diff --git a/src/pgm/engine.c b/src/pgm/engine.c
index c480209..105a8d7 100644
--- a/src/pgm/engine.c
+++ b/src/pgm/engine.c
@@ -1,8 +1,16 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * PGM engine.
+ * PGM engine environment, i.e. bare minimum to get anything running.
+ * - WinSock on Windows,
+ * - Thread API to detect #cores,
+ * - Logging API for global lock and debug flags,
+ * - Memory API for debug flags,
+ * - PRNG API for global lock on global generator,
+ * - Timing API for calibration, device locking as appropriate,
+ * - PGM protocol# resolution,
+ * - Lock on global list of PGM sockets.
*
- * Copyright (c) 2006-2010 Miru Limited.
+ * Copyright (c) 2006-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,9 +27,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/* getprotobyname_r */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#ifndef _BSD_SOURCE
-# define _BSD_SOURCE 1
+# define _BSD_SOURCE 1 /* getprotobyname_r */
#endif
#ifndef _WIN32
@@ -113,8 +124,8 @@ pgm_init (
goto err_shutdown;
}
-# ifndef CONFIG_TARGET_WINE
-/* find WSARecvMsg API */
+/* Find WSARecvMsg API. Available in Windows XP and Wine 1.3.
+ */
if (NULL == pgm_WSARecvMsg) {
GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
DWORD cbBytesReturned;
@@ -140,13 +151,12 @@ pgm_init (
pgm_set_error (error,
PGM_ERROR_DOMAIN_ENGINE,
PGM_ERROR_FAILED,
- _("WSARecvMsg function not found."));
+ _("WSARecvMsg function not found, available in Windows XP or Wine 1.3."));
goto err_shutdown;
}
pgm_debug ("Retrieved address of WSARecvMsg.");
closesocket (sock);
}
-# endif
#endif /* _WIN32 */
/* find PGM protocol id overriding default value, use first value from NIS */
diff --git a/src/pgm/error.c b/src/pgm/error.c
index 3f3fe30..01bff15 100644
--- a/src/pgm/error.c
+++ b/src/pgm/error.c
@@ -1,8 +1,12 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * portable error reporting.
+ * Portable advanced error reporting. In addition to a basic error code
+ * this module provides a domain code and a textual description of the error.
+ * Text is localised per gettext() configuration and hence is generally
+ * limited to one language per process and an application restart is required
+ * to read updated catalogue translations.
*
- * Copyright (c) 2010 Miru Limited.
+ * Copyright (c) 2010-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +23,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#ifndef _WIN32
# include <netdb.h>
#endif
@@ -72,20 +79,20 @@ pgm_set_error (
...
)
{
- pgm_error_t *new;
+ pgm_error_t *new_err;
va_list args;
if (NULL == err)
return;
va_start (args, format);
- new = pgm_error_new_valist (error_domain, error_code, format, args);
+ new_err = pgm_error_new_valist (error_domain, error_code, format, args);
va_end (args);
if (NULL == *err)
- *err = new;
+ *err = new_err;
else
- pgm_warn (_(ERROR_OVERWRITTEN_WARNING), new->message);
+ pgm_warn (_(ERROR_OVERWRITTEN_WARNING), new_err->message);
}
void
diff --git a/src/pgm/galois_generator.pl b/src/pgm/galois_generator.pl
index b3f531d..a2ec258 100755
--- a/src/pgm/galois_generator.pl
+++ b/src/pgm/galois_generator.pl
@@ -2,7 +2,7 @@
#
# Galois field table generator.
#
-# Copyright (c) 2006-2010 Miru Limited.
+# Copyright (c) 2006-2011 Miru Limited.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -51,7 +51,7 @@ print<<MOO;
*
* Galois field tables
*
- * Copyright (c) 2006-2010 Miru Limited.
+ * Copyright (c) 2006-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -68,6 +68,9 @@ print<<MOO;
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
@@ -105,7 +108,7 @@ for (my $i = 0; $i < $GF_NO_ELEMENTS; $i++)
print<<MOO;
};
-#ifdef CONFIG_GALOIS_MUL_LUT
+#ifdef USE_GALOIS_MUL_LUT
const pgm_gf8_t pgm_gftable[PGM_GF_NO_ELEMENTS * PGM_GF_NO_ELEMENTS] =
{
MOO
diff --git a/src/pgm/galois_tables.c b/src/pgm/galois_tables.c
index 1850b79..d6a4d06 100644
--- a/src/pgm/galois_tables.c
+++ b/src/pgm/galois_tables.c
@@ -2,7 +2,7 @@
*
* Galois field tables
*
- * Copyright (c) 2006-2010 Miru Limited.
+ * Copyright (c) 2006-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
@@ -96,7 +99,7 @@ const pgm_gf8_t pgm_gfantilog[PGM_GF_NO_ELEMENTS] =
0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00
};
-#ifdef CONFIG_GALOIS_MUL_LUT
+#ifdef USE_GALOIS_MUL_LUT
const pgm_gf8_t pgm_gftable[PGM_GF_NO_ELEMENTS * PGM_GF_NO_ELEMENTS] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
diff --git a/src/pgm/get_nprocs.c b/src/pgm/get_nprocs.c
index 48646cc..65216a8 100644
--- a/src/pgm/get_nprocs.c
+++ b/src/pgm/get_nprocs.c
@@ -20,6 +20,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
diff --git a/src/pgm/getifaddrs.c b/src/pgm/getifaddrs.c
index fac38c5..584d669 100644
--- a/src/pgm/getifaddrs.c
+++ b/src/pgm/getifaddrs.c
@@ -1,8 +1,17 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * portable getifaddrs implementation.
+ * A portable getifaddrs implementation, an API to enumerate all system
+ * network interfaces.
*
- * Copyright (c) 2006-2010 Miru Limited.
+ * Note that Windows 7 introduces a feature to hide interfaces from
+ * enumeration which may cause confusion, see MSDN(getaddrinfo Function)
+ * for further details.
+ *
+ * No support is provided for dynamic interfaces, however interfaces are
+ * not cached and so closing a socket and creating anew would use any
+ * updated addressing.
+ *
+ * Copyright (c) 2006-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,17 +28,23 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <errno.h>
-#ifdef CONFIG_HAVE_GETIFADDRS
+#ifdef HAVE_GETIFADDRS
# include <sys/types.h>
# include <ifaddrs.h>
#endif
+#if defined( __CYGWIN__ )
+# include <sys/ioctl.h>
+#endif
#if defined( __sun )
# include <sys/sockio.h>
#endif
#if defined( _WIN32 )
# include <ws2tcpip.h>
-# include <iphlpapi.h>
+# include <iphlpapi.h> /* must be after Winsock2.h on early SDKs */
#endif
#include <impl/i18n.h>
#include <impl/framework.h>
@@ -48,13 +63,23 @@ struct _pgm_ifaddrs_t
/* Number of attempts to try enumerating the interface list */
#define MAX_TRIES 3
-#define DEFAULT_BUFFER_SIZE 4096
+#ifdef _WIN32
+/* MSDN(GetAdaptersAddresses Function) recommends pre-allocating a 15KB
+ * working buffer to reduce chances of a buffer overflow.
+ * NB: The article actually recommends 15,000 and not 15,360 bytes.
+ */
+# define DEFAULT_BUFFER_SIZE 15000
+#else
+# define DEFAULT_BUFFER_SIZE 4096
+#endif
+#ifdef SIOCGLIFCONF
/* returns TRUE on success setting ifap to a linked list of system interfaces,
* returns FALSE on failure and sets error appropriately.
+ *
+ * Long form of SIOCGIFCONF, Solaris solution to add IPv6 support.
*/
-#ifdef SIOCGLIFCONF
static
bool
_pgm_getlifaddrs (
@@ -213,7 +238,7 @@ again:
/* netmask */
if (SOCKET_ERROR != ioctlsocket (sock, SIOCGLIFNETMASK, lifr)) {
ift->_ifa.ifa_netmask = (void*)&ift->_netmask;
-# ifdef CONFIG_HAVE_IFR_NETMASK
+# ifdef HAVE_STRUCT_IFADDRS_IFR_NETMASK
memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_netmask, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_netmask));
# else
memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_addr, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_addr));
@@ -266,7 +291,7 @@ again:
/* netmask */
if (SOCKET_ERROR != ioctlsocket (sock6, SIOCGLIFNETMASK, lifr)) {
ift->_ifa.ifa_netmask = (void*)&ift->_netmask;
-# ifdef CONFIG_HAVE_IFR_NETMASK
+# ifdef HAVE_STRUCT_IFADDRS_IFR_NETMASK
memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_netmask, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_netmask));
# else
memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_addr, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_addr));
@@ -298,6 +323,14 @@ again:
#endif /* SIOCGLIFCONF */
#ifdef SIOCGIFCONF
+/* Popular socket option for enumerating interfaces. However returned
+ * structure is often harded coded for IPv4 addressing and so either
+ * an alternative or additional API is required for IPv6 support.
+ *
+ * Windows does not provide a support method for returning IPv6 addresses
+ * via a socket forcing use of iphlpapi.dll APIs.
+ */
+
static
bool
_pgm_getifaddrs (
@@ -335,7 +368,7 @@ _pgm_getifaddrs (
}
int if_count = ifc.ifc_len / sizeof(struct ifreq);
-# ifdef CONFIG_HAVE_IPV6_SIOCGIFADDR
+# ifdef HAVE_IPV6_SIOCGIFADDR
/* process IPv6 interfaces */
const SOCKET sock6 = socket (AF_INET6, SOCK_DGRAM, 0);
if (SOCKET_ERROR == sock6) {
@@ -367,7 +400,7 @@ _pgm_getifaddrs (
return FALSE;
}
if_count += ifc6.ifc_len / sizeof(struct ifreq);
-# endif /* CONFIG_HAVE_IPV6_SIOCGIFADDR */
+# endif /* HAVE_IPV6_SIOCGIFADDR */
/* alloc a contiguous block for entire list */
struct _pgm_ifaddrs_t* ifa = pgm_new0 (struct _pgm_ifaddrs_t, if_count);
@@ -404,7 +437,7 @@ _pgm_getifaddrs (
/* netmask */
if (SOCKET_ERROR != ioctlsocket (sock, SIOCGIFNETMASK, ifr)) {
ift->_ifa.ifa_netmask = (void*)&ift->_netmask;
-# ifdef CONFIG_HAVE_IFR_NETMASK
+# ifdef HAVE_STRUCT_IFADDRS_IFR_NETMASK
memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_netmask, pgm_sockaddr_len(&ifr->ifr_netmask));
# else
memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_addr, pgm_sockaddr_len(&ifr->ifr_addr));
@@ -421,7 +454,7 @@ _pgm_getifaddrs (
}
}
-# ifdef CONFIG_HAVE_IPV6_SIOCGIFADDR
+# ifdef HAVE_IPV6_SIOCGIFADDR
/* repeat everything for IPv6 */
ifr = ifc6.ifc_req;
ifr_end = (struct ifreq *)&ifc6.ifc_buf[ifc6.ifc_len];
@@ -458,7 +491,7 @@ _pgm_getifaddrs (
/* netmask */
if (SOCKET_ERROR != ioctlsocket (sock6, SIOCGIFNETMASK, ifr)) {
ift->_ifa.ifa_netmask = (void*)&ift->_netmask;
-# ifdef CONFIG_HAVE_IFR_NETMASK
+# ifdef HAVE_STRUCT_IFADDRS_IFR_NETMASK
memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_netmask, pgm_sockaddr_len(&ifr->ifr_netmask));
# else
memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_addr, pgm_sockaddr_len(&ifr->ifr_addr));
@@ -477,7 +510,7 @@ _pgm_getifaddrs (
pgm_warn (_("Closing IPv6 socket failed: %s"),
pgm_sock_strerror_s (errbuf, sizeof(errbuf), save_errno));
}
-# endif /* CONFIG_HAVE_IPV6_SIOCGIFADDR */
+# endif /* HAVE_IPV6_SIOCGIFADDR */
if (SOCKET_ERROR == closesocket (sock)) {
const int save_errno = pgm_get_last_sock_error();
@@ -498,7 +531,7 @@ _pgm_heap_alloc (
const size_t n_bytes
)
{
-# ifdef CONFIG_USE_HEAPALLOC
+# ifdef USE_HEAPALLOC
/* Does not appear very safe with re-entrant calls on XP */
return HeapAlloc (GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, n_bytes);
# else
@@ -512,7 +545,7 @@ _pgm_heap_free (
void* mem
)
{
-# ifdef CONFIG_USE_HEAPALLOC
+# ifdef USE_HEAPALLOC
HeapFree (GetProcessHeap(), 0, mem);
# else
pgm_free (mem);
@@ -522,6 +555,18 @@ _pgm_heap_free (
/* NB: IP_ADAPTER_INFO size varies size due to sizeof (time_t), the API assumes
* 4-byte datatype whilst compiler uses an 8-byte datatype. Size can be forced
* with -D_USE_32BIT_TIME_T with side effects to everything else.
+ *
+ * Only supports IPv4 addressing similar to SIOCGIFCONF socket option.
+ *
+ * Interfaces that are not "operationally up" will return the address 0.0.0.0,
+ * this includes adapters with static IP addresses but with disconnected cable.
+ * This is documented under the GetIpAddrTable API. Interface status can only
+ * be determined by the address, a separate flag is introduced with the
+ * GetAdapterAddresses API.
+ *
+ * The IPv4 loopback interface is not included.
+ *
+ * Available in Windows 2000 and Wine 1.0.
*/
static
@@ -643,6 +688,21 @@ _pgm_getadaptersinfo (
return TRUE;
}
+/* Supports both IPv4 and IPv6 addressing. The size of IP_ADAPTER_ADDRESSES
+ * changes between Windows XP, XP SP1, and Vista with additional members.
+ *
+ * Interfaces that are not "operationally up" will typically return a host
+ * IP address with the defined IPv4 link-local prefix 169.254.0.0/16.
+ * Adapters with a static configured IP address but down will return both
+ * the IPv4 link-local prefix and the static address.
+ *
+ * It is easier to say "not up" rather than "down" as this API returns six
+ * effective down status values: down, testing, unknown, dormant, not present,
+ * and lower layer down.
+ *
+ * Available in Windows XP and Wine 1.3.
+ */
+
static
bool
_pgm_getadaptersaddresses (
@@ -661,6 +721,7 @@ _pgm_getadaptersaddresses (
pgm_debug ("IP_ADAPTER_ADDRESSES buffer length %lu bytes.", dwSize);
pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_pgm_heap_alloc (dwSize);
dwRet = GetAdaptersAddresses (AF_UNSPEC,
+/* requires Windows XP SP1 */
GAA_FLAG_INCLUDE_PREFIX |
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_DNS_SERVER |
@@ -763,33 +824,170 @@ _pgm_getadaptersaddresses (
/* netmask */
ift->_ifa.ifa_netmask = (void*)&ift->_netmask;
-/* pre-Vista must hunt for matching prefix in linked list, otherwise use OnLinkPrefixLength */
- int prefixIndex = 0;
+/* pre-Vista must hunt for matching prefix in linked list, otherwise use
+ * OnLinkPrefixLength from IP_ADAPTER_UNICAST_ADDRESS structure.
+ * FirstPrefix requires Windows XP SP1, from SP1 to pre-Vista provides a
+ * single adapter prefix for each IP address. Vista and later provides
+ * host IP address prefix, subnet IP address, and subnet broadcast IP
+ * address. In addition there is a multicast and broadcast address prefix.
+ */
ULONG prefixLength = 0;
+
+#if defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 )
+/* For a unicast IPv4 address, any value greater than 32 is an illegal
+ * value. For a unicast IPv6 address, any value greater than 128 is an
+ * illegal value. A value of 255 is commonly used to represent an illegal
+ * value.
+ *
+ * Windows 7 SP1 returns 64 for Teredo links which is incorrect.
+ */
+
+#define IN6_IS_ADDR_TEREDO(addr) \
+ (((const uint32_t *)(addr))[0] == ntohl (0x20010000))
+
+ if (AF_INET6 == unicast->Address.lpSockaddr->sa_family &&
+/* TunnelType only applies to one interface on the adapter and no
+ * convenient method is provided to determine which.
+ */
+ TUNNEL_TYPE_TEREDO == adapter->TunnelType &&
+/* Test the interface with the known Teredo network prefix.
+ */
+ IN6_IS_ADDR_TEREDO( &((struct sockaddr_in6*)(unicast->Address.lpSockaddr))->sin6_addr) &&
+/* Test that this version is actually wrong, subsequent releases from Microsoft
+ * may resolve the issue.
+ */
+ 32 != unicast->OnLinkPrefixLength)
+ {
+ pgm_trace (PGM_LOG_ROLE_NETWORK,_("IPv6 Teredo tunneling adapter %s prefix length is an illegal value %lu, overriding to 32."),
+ adapter->AdapterName,
+ unicast->OnLinkPrefixLength);
+ prefixLength = 32;
+ }
+ else
+ prefixLength = unicast->OnLinkPrefixLength;
+#else
+/* The order of linked IP_ADAPTER_UNICAST_ADDRESS structures pointed to by
+ * the FirstUnicastAddress member does not have any relationship with the
+ * order of linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix
+ * member.
+ *
+ * Example enumeration:
+ * [ no subnet ]
+ * ::1/128 - address
+ * ff00::%1/8 - multicast (no IPv6 broadcast)
+ * 127.0.0.0/8 - subnet
+ * 127.0.0.1/32 - address
+ * 127.255.255.255/32 - subnet broadcast
+ * 224.0.0.0/4 - multicast
+ * 255.255.255.255/32 - broadcast
+ *
+ * Which differs from most adapters listing three IPv6:
+ * fe80::%10/64 - subnet
+ * fe80::51e9:5fe5:4202:325a%10/128 - address
+ * ff00::%10/8 - multicast
+ *
+ * !IfOperStatusUp IPv4 addresses are skipped:
+ * fe80::%13/64 - subnet
+ * fe80::d530:946d:e8df:8c91%13/128 - address
+ * ff00::%13/8 - multicast
+ * [ no subnet ]
+ * [ no address ]
+ * 224.0.0.0/4 - multicast
+ * 255.255.255.255/32 - broadcast
+ *
+ * On PTP links no multicast or broadcast addresses are returned:
+ * [ no subnet ]
+ * fe80::5efe:10.203.9.30/128 - address
+ * [ no multicast ]
+ * [ no multicast ]
+ * [ no broadcast ]
+ *
+ * Active primary IPv6 interfaces are a bit overloaded:
+ * ::/0 - default route
+ * 2001::/32 - global subnet
+ * 2001:0:4137:9e76:2443:d6:ba87:1a2a/128 - global address
+ * fe80::/64 - link-local subnet
+ * fe80::2443:d6:ba87:1a2a/128 - link-local address
+ * ff00::/8 - multicast
+ */
+
+#define IN_LINKLOCAL(a) ((((uint32_t) (a)) & 0xaffff0000) == 0xa9fe0000)
+
for (IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix;
prefix;
- prefix = prefix->Next, ++prefixIndex)
+ prefix = prefix->Next)
{
- if (prefixIndex == unicastIndex) {
- prefixLength = prefix->PrefixLength;
+ LPSOCKADDR lpSockaddr = prefix->Address.lpSockaddr;
+ if (lpSockaddr->sa_family != unicast->Address.lpSockaddr->sa_family)
+ continue;
+/* special cases */
+/* RFC2863: IPv4 interface not up */
+ if (AF_INET == lpSockaddr->sa_family &&
+ adapter->OperStatus != IfOperStatusUp)
+ {
+/* RFC3927: link-local IPv4 always has 16-bit CIDR */
+ if (IN_LINKLOCAL( ntohl (((struct sockaddr_in*)(unicast->Address.lpSockaddr))->sin_addr.s_addr)))
+ {
+ pgm_trace (PGM_LOG_ROLE_NETWORK,_("Assuming 16-bit prefix length for link-local IPv4 adapter %s."),
+ adapter->AdapterName);
+ prefixLength = 16;
+ }
+ else
+ {
+ pgm_trace (PGM_LOG_ROLE_NETWORK,_("Prefix length unavailable for IPv4 adapter %s."),
+ adapter->AdapterName);
+ }
break;
}
+/* default IPv6 route */
+ if (AF_INET6 == lpSockaddr->sa_family &&
+ 0 == prefix->PrefixLength &&
+ IN6_IS_ADDR_UNSPECIFIED( &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr))
+ {
+ pgm_trace (PGM_LOG_ROLE_NETWORK,_("Ingoring unspecified address prefix on IPv6 adapter %s."),
+ adapter->AdapterName);
+ continue;
+ }
+/* Assume unicast address for first prefix of operational adapter */
+ if (AF_INET == lpSockaddr->sa_family)
+ pgm_assert (!IN_MULTICAST( ntohl (((struct sockaddr_in*)(lpSockaddr))->sin_addr.s_addr)));
+ if (AF_INET6 == lpSockaddr->sa_family)
+ pgm_assert (!IN6_IS_ADDR_MULTICAST( &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr));
+/* Assume subnet or host IP address for XP backward compatibility */
+
+ prefixLength = prefix->PrefixLength;
+ break;
}
+#endif /* defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) */
/* map prefix to netmask */
ift->_ifa.ifa_netmask->sa_family = unicast->Address.lpSockaddr->sa_family;
switch (unicast->Address.lpSockaddr->sa_family) {
case AF_INET:
- if (0 == prefixLength) {
- pgm_trace (PGM_LOG_ROLE_NETWORK,_("IPv4 adapter %s prefix length is 0, overriding to 32."), adapter->AdapterName);
+ if (0 == prefixLength || prefixLength > 32) {
+ pgm_trace (PGM_LOG_ROLE_NETWORK,_("IPv4 adapter %s prefix length is an illegal value %lu, overriding to 32."),
+ adapter->AdapterName,
+ prefixLength);
prefixLength = 32;
}
+#if defined( _WIN32) && ( _WIN32_WINNT >= 0x0600 )
+/* Added in Vista, but no IPv6 equivalent. */
+ {
+ ULONG Mask;
+ ConvertLengthToIpv4Mask (prefixLength, &Mask);
+ ((struct sockaddr_in*)ift->_ifa.ifa_netmask)->sin_addr.s_addr = htonl( Mask );
+ }
+#else
+/* NB: left-shift of full bit-width is undefined in C standard. */
((struct sockaddr_in*)ift->_ifa.ifa_netmask)->sin_addr.s_addr = htonl( 0xffffffffU << ( 32 - prefixLength ) );
+#endif
break;
case AF_INET6:
- if (0 == prefixLength) {
- pgm_trace (PGM_LOG_ROLE_NETWORK,_("IPv6 adapter %s prefix length is 0, overriding to 128."), adapter->AdapterName);
+ if (0 == prefixLength || prefixLength > 128) {
+ pgm_trace (PGM_LOG_ROLE_NETWORK,_("IPv6 adapter %s prefix length is an illegal value %lu, overriding to 128."),
+ adapter->AdapterName,
+ prefixLength);
prefixLength = 128;
}
for (ULONG i = prefixLength, j = 0; i > 0; i -= 8, ++j)
@@ -813,6 +1011,68 @@ _pgm_getadaptersaddresses (
return TRUE;
}
#endif /* _WIN32 */
+#if defined( HAVE_GETIFADDRS )
+static
+bool
+_pgm_getifaddrs (
+ struct pgm_ifaddrs_t** restrict ifap,
+ pgm_error_t** restrict error
+ )
+{
+ struct ifaddrs *_ifap, *_ifa;
+ const int e = getifaddrs (&_ifap);
+ if (-1 == e) {
+ char errbuf[1024];
+ pgm_set_error (error,
+ PGM_ERROR_DOMAIN_IF,
+ pgm_error_from_errno (errno),
+ _("getifaddrs failed: %s"),
+ pgm_strerror_s (errbuf, sizeof (errbuf), errno));
+ return FALSE;
+ }
+
+ int n = 0, k = 0;
+ for (_ifa = _ifap; _ifa; _ifa = _ifa->ifa_next)
+ ++n;
+
+ struct _pgm_ifaddrs_t* ifa = pgm_new0 (struct _pgm_ifaddrs_t, n);
+ struct _pgm_ifaddrs_t* ift = ifa;
+ for (_ifa = _ifap; _ifa; _ifa = _ifa->ifa_next)
+ {
+/* ensure IP adapter */
+ if (NULL == _ifa->ifa_addr ||
+ (_ifa->ifa_addr->sa_family != AF_INET &&
+ _ifa->ifa_addr->sa_family != AF_INET6) )
+ {
+ continue;
+ }
+
+/* address */
+ ift->_ifa.ifa_addr = (void*)&ift->_addr;
+ memcpy (ift->_ifa.ifa_addr, _ifa->ifa_addr, pgm_sockaddr_len (_ifa->ifa_addr));
+
+/* name */
+ ift->_ifa.ifa_name = ift->_name;
+ pgm_strncpy_s (ift->_ifa.ifa_name, IF_NAMESIZE, _ifa->ifa_name, _TRUNCATE);
+
+/* flags */
+ ift->_ifa.ifa_flags = _ifa->ifa_flags;
+
+/* netmask */
+ ift->_ifa.ifa_netmask = (void*)&ift->_netmask;
+ memcpy (ift->_ifa.ifa_netmask, _ifa->ifa_netmask, pgm_sockaddr_len (_ifa->ifa_netmask));
+
+/* next */
+ if (k++ < (n - 1)) {
+ ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1);
+ ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next);
+ }
+ }
+ freeifaddrs (_ifap);
+ *ifap = (struct pgm_ifaddrs_t*)ifa;
+ return TRUE;
+}
+#endif /* HAVE_GETIFADDRS */
/* returns TRUE on success setting ifap to a linked list of system interfaces,
* returns FALSE on failure and sets error appropriately.
@@ -829,29 +1089,17 @@ pgm_getifaddrs (
pgm_debug ("pgm_getifaddrs (ifap:%p error:%p)",
(void*)ifap, (void*)error);
-#ifdef CONFIG_HAVE_GETIFADDRS
- const int e = getifaddrs ((struct ifaddrs**)ifap);
- if (-1 == e) {
- char errbuf[1024];
- pgm_set_error (error,
- PGM_ERROR_DOMAIN_IF,
- pgm_error_from_errno (errno),
- _("getifaddrs failed: %s"),
- pgm_strerror_s (errbuf, sizeof (errbuf), errno));
- return FALSE;
- }
- return TRUE;
-#elif defined(CONFIG_TARGET_WINE)
- return _pgm_getadaptersinfo (ifap, error);
-#elif defined(_WIN32)
+#if defined( HAVE_GETIFADDRS )
+ return _pgm_getifaddrs (ifap, error);
+#elif defined( _WIN32 )
return _pgm_getadaptersaddresses (ifap, error);
-#elif defined(SIOCGLIFCONF)
+#elif defined( SIOCGLIFCONF )
return _pgm_getlifaddrs (ifap, error);
-#elif defined(SIOCGIFCONF)
+#elif defined( SIOCGIFCONF )
return _pgm_getifaddrs (ifap, error);
#else
# error "Unsupported interface enumeration on this platform."
-#endif /* !CONFIG_HAVE_GETIFADDRS */
+#endif /* !HAVE_GETIFADDRS */
}
void
@@ -861,11 +1109,7 @@ pgm_freeifaddrs (
{
pgm_return_if_fail (NULL != ifa);
-#ifdef CONFIG_HAVE_GETIFADDRS
- freeifaddrs ((struct ifaddrs*)ifa);
-#else
pgm_free (ifa);
-#endif
}
/* eof */
diff --git a/src/pgm/getnetbyname.c b/src/pgm/getnetbyname.c
index 42c86fc..806bd14 100644
--- a/src/pgm/getnetbyname.c
+++ b/src/pgm/getnetbyname.c
@@ -1,8 +1,13 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * portable implementation of getnetbyname
+ * Portable implementation of getnetbyname, returns a network address
+ * from a given name. On Unix systems the mapping is managed by a
+ * system service and may be sourced from a network service, cached
+ * locally, or read directly from a local file. On systems without
+ * such a service or when IPv6 is required a local file is supported
+ * with compatible parsing of the network-name mapping format.
*
- * Copyright (c) 2010 Miru Limited.
+ * Copyright (c) 2010-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +24,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <stdio.h>
#include <impl/framework.h>
@@ -199,7 +207,7 @@ found:
return p;
}
-#ifdef CONFIG_HAVE_GETNETENT
+#ifdef HAVE_GETNETENT
static
struct pgm_netent_t*
_pgm_native_getnetbyname (
@@ -270,7 +278,7 @@ pgm_getnetbyname (
const char* name
)
{
-#ifdef CONFIG_HAVE_GETNETENT
+#ifdef HAVE_GETNETENT
char* netdb;
size_t envlen;
errno_t err;
diff --git a/src/pgm/getnodeaddr.c b/src/pgm/getnodeaddr.c
index ad021e2..e3bbeca 100644
--- a/src/pgm/getnodeaddr.c
+++ b/src/pgm/getnodeaddr.c
@@ -1,6 +1,10 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * portable function to return the nodes IP address.
+ * Portable function to return the nodes IP address. IPv6 addressing
+ * is often complicated on dual-stack machines that are configured to
+ * only resolve an IPv4 address against the node name. In such
+ * circumstances the primary IPv6 for the interface with that IPv4
+ * address is taken as the node address.
*
* Copyright (c) 2006-2011 Miru Limited.
*
@@ -19,6 +23,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <errno.h>
#ifndef _WIN32
# include <netdb.h>
@@ -56,10 +63,10 @@ pgm_getnodeaddr (
pgm_debug ("pgm_getnodeaddr (family:%s res:%p error:%p)",
pgm_family_string (family), (const void*)res, (const void*)error);
- char hostname[NI_MAXHOST + 1];
+ char hostname[NI_MAXHOST];
struct hostent* he;
- if (0 != gethostname (hostname, sizeof(hostname))) {
+ if (0 != gethostname (hostname, sizeof (hostname))) {
const int save_errno = pgm_get_last_sock_error();
char errbuf[1024];
pgm_set_error (error,
@@ -70,6 +77,7 @@ pgm_getnodeaddr (
);
return FALSE;
}
+ hostname[NI_MAXHOST - 1] = '\0';
struct addrinfo hints = {
.ai_family = family,
diff --git a/src/pgm/getprotobyname.c b/src/pgm/getprotobyname.c
index e725974..080ad00 100644
--- a/src/pgm/getprotobyname.c
+++ b/src/pgm/getprotobyname.c
@@ -1,8 +1,9 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * portable implementation of getprotobyname
+ * Portable implementation of getprotobyname. Returns the IP protocol
+ * number for the provided protocol name.
*
- * Copyright (c) 2010 Miru Limited.
+ * Copyright (c) 2010-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +20,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <stdio.h>
#include <impl/framework.h>
@@ -33,6 +37,10 @@ static char line[BUFSIZ+1];
static char *proto_aliases[MAXALIASES];
static struct pgm_protoent_t proto;
+/* re-entrant system APIs are preferred, unfortunately two different decls
+ * are often available.
+ */
+
static
struct pgm_protoent_t*
_pgm_native_getprotobyname (
@@ -46,12 +54,12 @@ _pgm_native_getprotobyname (
if (NULL == name)
return NULL;
-#ifdef CONFIG_HAVE_GETPROTOBYNAME_R
+#if defined( HAVE_GETPROTOBYNAME_R ) && defined( GETPROTOBYNAME_R_STRUCT_PROTOENT_P )
char buf[BUFSIZ];
struct protoent protobuf;
if (NULL == (pe = getprotobyname_r (name, &protobuf, buf, BUFSIZ)))
return NULL;
-#elif defined(CONFIG_HAVE_GETPROTOBYNAME_R2)
+#elif defined( HAVE_GETPROTOBYNAME_R )
char buf[BUFSIZ];
struct protoent protobuf;
if (0 != getprotobyname_r (name, &protobuf, buf, BUFSIZ, &pe) || NULL == pe)
@@ -59,7 +67,7 @@ _pgm_native_getprotobyname (
#else
if (NULL == (pe = getprotobyname (name)))
return NULL;
-#endif
+#endif /* HAVE_GETPROTOBYNAME_R */
len = strlen (pe->p_name) + 1;
if (len > BUFSIZ)
return NULL;
diff --git a/src/pgm/gsi.c b/src/pgm/gsi.c
index 099a82e..121d022 100644
--- a/src/pgm/gsi.c
+++ b/src/pgm/gsi.c
@@ -2,7 +2,7 @@
*
* global session ID helper functions.
*
- * Copyright (c) 2006-2010 Miru Limited.
+ * Copyright (c) 2006-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <errno.h>
#include <stdio.h>
#ifndef _WIN32
@@ -47,20 +50,12 @@ pgm_gsi_create_from_data (
pgm_return_val_if_fail (NULL != data, FALSE);
pgm_return_val_if_fail (length > 1, FALSE);
-#ifdef CONFIG_HAVE_GLIB_CHECKSUM
- GChecksum* checksum = g_checksum_new (G_CHECKSUM_MD5);
- pgm_return_val_if_fail (NULL != checksum, FALSE);
- g_checksum_update (checksum, data, length);
- memcpy (gsi, g_checksum_get_string (checksum) + 10, 6);
- g_checksum_free (checksum);
-#else
struct pgm_md5_t ctx;
char resblock[16];
pgm_md5_init_ctx (&ctx);
pgm_md5_process_bytes (&ctx, data, length);
pgm_md5_finish_ctx (&ctx, resblock);
memcpy (gsi, resblock + 10, 6);
-#endif
return TRUE;
}
@@ -94,8 +89,18 @@ pgm_gsi_create_from_hostname (
{
pgm_return_val_if_fail (NULL != gsi, FALSE);
+/* POSIX gethostname silently fails if the buffer is too short. We use NI_MAXHOST
+ * as the highest common denominator, at 1025 bytes including terminating null byte.
+ *
+ * WinSock namespace providers have a 256 byte limit (MSDN), DNS names are limited to
+ * 63 bytes per component, and 15 bytes for NetBIOS names (MAX_COMPUTERNAME_LENGTH).
+ * http://msdn.microsoft.com/en-us/library/ms738527(v=VS.85).aspx
+ * http://msdn.microsoft.com/en-us/library/ms724220(VS.85).aspx
+ * SUSv2 guarantees 255 bytes (excluding terminating null byte).
+ * POSIX.1-2001 guarantees HOST_NAME_MAX, on Linux is defined to 64.
+ */
char hostname[NI_MAXHOST];
- int retval = gethostname (hostname, sizeof(hostname));
+ int retval = gethostname (hostname, sizeof (hostname));
if (0 != retval) {
const int save_errno = pgm_get_last_sock_error();
char errbuf[1024];
@@ -108,6 +113,9 @@ pgm_gsi_create_from_hostname (
return FALSE;
}
+/* force a trailing null byte */
+ hostname[NI_MAXHOST - 1] = '\0';
+
return pgm_gsi_create_from_string (gsi, hostname, -1);
}
@@ -212,10 +220,19 @@ pgm_gsi_equal (
const void* restrict p2
)
{
+#ifdef __cplusplus
+ union {
+ pgm_gsi_t gsi;
+ uint16_t s[3];
+ } _u1, _u2, *u1 = &_u1, *u2 = &_u2;
+ memcpy (&_u1.gsi, p1, sizeof (pgm_gsi_t));
+ memcpy (&_u2.gsi, p2, sizeof (pgm_gsi_t));
+#else
const union {
pgm_gsi_t gsi;
uint16_t s[3];
} *u1 = p1, *u2 = p2;
+#endif
/* pre-conditions */
pgm_assert (NULL != p1);
diff --git a/src/pgm/hashtable.c b/src/pgm/hashtable.c
index f6f2e2f..7d9bf88 100644
--- a/src/pgm/hashtable.c
+++ b/src/pgm/hashtable.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
diff --git a/src/pgm/histogram.c b/src/pgm/histogram.c
index 783d5c2..37cbd54 100644
--- a/src/pgm/histogram.c
+++ b/src/pgm/histogram.c
@@ -2,7 +2,7 @@
*
* Histograms.
*
- * Copyright (c) 2009-2010 Miru Limited.
+ * Copyright (c) 2009-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <limits.h>
#include <math.h>
#include <stdlib.h>
diff --git a/src/pgm/if.c b/src/pgm/if.c
index 7b291fc..7c9e7d0 100644
--- a/src/pgm/if.c
+++ b/src/pgm/if.c
@@ -2,7 +2,7 @@
*
* network interface handling.
*
- * Copyright (c) 2006-2010 Miru Limited.
+ * Copyright (c) 2006-2012 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
@@ -33,6 +37,7 @@
#endif
#include <impl/i18n.h>
#include <impl/framework.h>
+#include <impl/inet_lnaof.h>
#include <pgm/if.h>
@@ -99,54 +104,76 @@ pgm_if_print_all (void)
if (!pgm_getifaddrs (&ifap, NULL))
return;
+ pgm_info (_("IP Configuration"));
+
for (ifa = ifap; ifa; ifa = ifa->ifa_next)
{
- const unsigned int i = NULL == ifa->ifa_addr ? 0 : pgm_if_nametoindex (ifa->ifa_addr->sa_family, ifa->ifa_name);
- char rname[IF_NAMESIZE * 2 + 3];
- char buf[IF_NAMESIZE * 2 + 3];
-
- pgm_if_indextoname (i, rname);
- pgm_snprintf_s (buf, sizeof (buf), _TRUNCATE, "%s (%s)",
- ifa->ifa_name ? ifa->ifa_name : "(null)", rname);
-
+/* no address */
if (NULL == ifa->ifa_addr ||
(ifa->ifa_addr->sa_family != AF_INET &&
ifa->ifa_addr->sa_family != AF_INET6) )
{
- pgm_info (_("#%d name %-15.15s ---- %-46.46s scope 0 status %s loop %s b/c %s m/c %s"),
- i,
- buf,
- "",
- ifa->ifa_flags & IFF_UP ? "UP " : "DOWN",
- ifa->ifa_flags & IFF_LOOPBACK ? "YES" : "NO ",
- ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ",
- ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO "
- );
continue;
}
- char saddr[INET6_ADDRSTRLEN];
- getnameinfo (ifa->ifa_addr, pgm_sockaddr_len(ifa->ifa_addr),
- saddr, sizeof(saddr),
+/* interface index */
+ const unsigned int idx = NULL == ifa->ifa_addr ? 0 : pgm_if_nametoindex (ifa->ifa_addr->sa_family, ifa->ifa_name);
+
+/* decode flags */
+ char flags[1024];
+ if (ifa->ifa_flags & IFF_UP)
+ strcpy (flags, "UP");
+ else
+ flags[0] = '\0';
+ if (ifa->ifa_flags & IFF_LOOPBACK) {
+ if (flags[0])
+ strcat (flags, ",LOOPBACK");
+ else
+ strcpy (flags, "LOOPBACK");
+ }
+ if (ifa->ifa_flags & IFF_BROADCAST) {
+ if (flags[0])
+ strcat (flags, ",BROADCAST");
+ else
+ strcpy (flags, "BROADCAST");
+ }
+ if (ifa->ifa_flags & IFF_MULTICAST) {
+ if (flags[0])
+ strcat (flags, ",MULTICAST");
+ else
+ strcpy (flags, "MULTICAST");
+ }
+ pgm_info (_("%s: index=%u flags=%u<%s>"),
+ ifa->ifa_name ? ifa->ifa_name : "(null)", idx, ifa->ifa_flags, flags);
+
+ char addr[INET6_ADDRSTRLEN];
+ getnameinfo (ifa->ifa_addr, pgm_sockaddr_len (ifa->ifa_addr),
+ addr, sizeof (addr),
NULL, 0,
NI_NUMERICHOST);
- pgm_info (_("#%d name %-15.15s IPv%i %-46.46s scope %u status %s loop %s b/c %s m/c %s"),
- i,
- buf,
- ifa->ifa_addr->sa_family == AF_INET ? 4 : 6,
- saddr,
- (unsigned)pgm_sockaddr_scope_id(ifa->ifa_addr),
- ifa->ifa_flags & IFF_UP ? "UP " : "DOWN",
- ifa->ifa_flags & IFF_LOOPBACK ? "YES" : "NO ",
- ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ",
- ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO "
- );
+
+ if (AF_INET6 == ifa->ifa_addr->sa_family) {
+ pgm_info (_("\tinet6 %s prefixlen %u scopeid 0x%x"),
+ addr,
+ (unsigned)pgm_sockaddr_prefixlen (ifa->ifa_netmask),
+ (unsigned)pgm_sockaddr_scope_id (ifa->ifa_addr));
+ } else {
+ char netmask[INET_ADDRSTRLEN];
+ getnameinfo (ifa->ifa_netmask, pgm_sockaddr_len (ifa->ifa_netmask),
+ netmask, sizeof (netmask),
+ NULL, 0,
+ NI_NUMERICHOST);
+ pgm_info (_("\tinet %s netmask %s"),
+ addr,
+ netmask);
+ }
}
pgm_freeifaddrs (ifap);
/* discover default network parameter */
- if (pgm_getaddrinfo ("", NULL, &res, NULL)) {
+ if (pgm_getaddrinfo ("", NULL, &res, NULL))
+ {
char network[INET6_ADDRSTRLEN], group[INET6_ADDRSTRLEN];
struct sockaddr_storage ifaddr;
struct sockaddr* addr = (struct sockaddr*)&res->ai_recv_addrs[0].gsr_group;
@@ -170,56 +197,8 @@ pgm_if_print_all (void)
pgm_info (_("Default network: \"%s;%s\""), network, group);
pgm_freeaddrinfo (res);
}
-}
-
-/* Equivalent to the description of inet_lnaof(), extract the host
- * address out of an IP address.
- * hostaddr = inet_lnaof(addr)
- *
- * nb: lnaof = local network address of
- *
- * returns TRUE if host address is defined, FALSE if only network address.
- */
-static inline
-bool
-pgm_inet_lnaof (
- struct in_addr* restrict dst, /* host byte order */
- const struct in_addr* restrict src,
- const struct in_addr* restrict netmask
- )
-{
- bool has_lna = FALSE;
-
- pgm_assert (NULL != dst);
- pgm_assert (NULL != src);
- pgm_assert (NULL != netmask);
-
- dst->s_addr = src->s_addr & netmask->s_addr;
- has_lna = (0 != (src->s_addr & ~netmask->s_addr));
-
- return has_lna;
-}
-
-static inline
-bool
-pgm_inet6_lnaof (
- struct in6_addr* restrict dst,
- const struct in6_addr* restrict src,
- const struct in6_addr* restrict netmask
- )
-{
- bool has_lna = FALSE;
-
- pgm_assert (NULL != dst);
- pgm_assert (NULL != src);
- pgm_assert (NULL != netmask);
-
- for (unsigned i = 0; i < 16; i++) {
- dst->s6_addr[i] = src->s6_addr[i] & netmask->s6_addr[i];
- has_lna |= (0 != (src->s6_addr[i] & !netmask->s6_addr[i]));
- }
-
- return has_lna;
+ else
+ pgm_warn (_("Failed to discover default network parameters, verify hostname configuration."));
}
static inline
@@ -328,7 +307,9 @@ parse_interface (
(const void*)ir,
(const void*)error);
-/* strip any square brackets for IPv6 early evaluation */
+/* Strip any square brackets for IPv6 early evaluation. RFC 2732 defines the
+ * term "ipv6reference" for a IPv6 literal address enclosed in square brackets.
+ */
if (AF_INET != family &&
'[' == ifname[0])
{
@@ -342,7 +323,9 @@ parse_interface (
}
}
-/* network address: in_addr in host byte order */
+/* Network address: e.g. 172.16.0.0, fc00::, or even fec0::%qe0 for scope.
+ * For IPv4 use compatibiltiy API with in_addr in host byte order.
+ */
if (AF_INET6 != family && 0 == pgm_inet_network (ifname, &in_addr))
{
#ifdef IF_DEBUG
@@ -357,6 +340,7 @@ parse_interface (
ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : "");
return FALSE;
}
+/* promote to sockaddr and avoid type punning */
struct sockaddr_in s4;
memset (&s4, 0, sizeof(s4));
s4.sin_family = AF_INET;
@@ -366,6 +350,9 @@ parse_interface (
check_inet_network = TRUE;
check_addr = TRUE;
}
+/* For IPv6 use an internal API that mimicks inet_network but works with sockaddr
+ * instead of in6_addr, the promotion is required to save the scope identifier.
+ */
if (AF_INET != family && 0 == pgm_sa6_network (ifname, &sa6_addr))
{
if (IN6_IS_ADDR_MULTICAST(&sa6_addr.sin6_addr)) {
@@ -382,7 +369,7 @@ parse_interface (
check_addr = TRUE;
}
-/* numeric host with scope id */
+/* numeric host with scope id, e.g. abcd::1%eth0 */
if (!check_addr)
{
char errbuf[1024];
@@ -440,7 +427,8 @@ parse_interface (
}
}
-/* network name into network address, can be expensive with NSS network lookup
+/* Network name into network address, can be expensive with NSS network lookup.
+ * Limitation as per the man page NETWORKS(5):
*
* Only Class A, B or C networks are supported, partitioned networks
* (i.e. network/26 or network/28) are not supported by this facility.
@@ -478,7 +466,7 @@ parse_interface (
break;
}
case AF_INET6: {
-#ifdef CONFIG_HAVE_GETNETENT
+#ifdef HAVE_GETNETENT
pgm_set_error (error,
PGM_ERROR_DOMAIN_IF,
PGM_ERROR_NODEV,
@@ -506,7 +494,7 @@ parse_interface (
check_inet6_network = TRUE;
check_addr = TRUE;
break;
-#endif
+#endif /* HAVE_GETNETENT */
}
default:
pgm_set_error (error,
@@ -667,7 +655,8 @@ parse_interface (
}
const unsigned ifindex = pgm_if_nametoindex (ifa->ifa_addr->sa_family, ifa->ifa_name);
- pgm_assert (0 != ifindex);
+/* Some faulty systems may fail, handle this situation without raising an assertion. */
+ const bool has_valid_if_name = (ifindex > 0);
/* check numeric host */
if (check_addr)
@@ -676,6 +665,8 @@ parse_interface (
{
if (0 == pgm_sockaddr_cmp (ifa->ifa_addr, (const struct sockaddr*)&addr[i]))
{
+ if (!has_valid_if_name)
+ pgm_warn (_("Interface %s does not resolve to an interface index, multicast traffic will follow the systems routing table and may appear on a different network than specified."), ir->ir_name);
pgm_strncpy_s (ir->ir_name, IF_NAMESIZE, ifa->ifa_name, _TRUNCATE);
ir->ir_flags = ifa->ifa_flags;
if (ir->ir_flags & IFF_LOOPBACK)
@@ -702,6 +693,10 @@ parse_interface (
if (!pgm_inet_lnaof (&lna, &in_addr, &netmask) &&
is_in_net (&ifaddr, &in_addr, &netmask))
{
+ if (!has_valid_if_name) {
+ pgm_warn (_("Skipping matching network device %s that fails reverse interface name lookup."), ir->ir_name);
+ goto skip_inet_network;
+ }
pgm_strncpy_s (ir->ir_name, IF_NAMESIZE, ifa->ifa_name, _TRUNCATE);
ir->ir_flags = ifa->ifa_flags;
if (ir->ir_flags & IFF_LOOPBACK) {
@@ -743,6 +738,10 @@ parse_interface (
if (!pgm_inet6_lnaof (&lna, &sa6_addr.sin6_addr, &netmask) &&
is_in_net6 (&ifaddr, &sa6_addr.sin6_addr, &netmask))
{
+ if (!has_valid_if_name) {
+ pgm_warn (_("Skipping matching network device %s that fails reverse interface name lookup."), ir->ir_name);
+ goto skip_inet_network;
+ }
pgm_strncpy_s (ir->ir_name, IF_NAMESIZE, ifa->ifa_name, _TRUNCATE);
ir->ir_flags = ifa->ifa_flags;
if (ir->ir_flags & IFF_LOOPBACK) {
@@ -780,6 +779,9 @@ skip_inet_network:
if (0 != strcmp (ifname, ifa->ifa_name))
continue;
+/* skip devices that fail reverse name lookup */
+ if (!has_valid_if_name)
+ continue;
ir->ir_flags = ifa->ifa_flags;
/* skip loopback and non-multicast capable devices */
if ((ir->ir_flags & IFF_LOOPBACK) || !(ir->ir_flags & IFF_MULTICAST))
@@ -924,7 +926,7 @@ parse_group (
return FALSE;
}
case AF_INET6: {
-#ifdef CONFIG_HAVE_GETNETENT
+#ifdef HAVE_GETNETENT
pgm_set_error (error,
PGM_ERROR_DOMAIN_IF,
PGM_ERROR_NODEV,
@@ -952,7 +954,7 @@ parse_group (
_("IP address class conflict when resolving network name %s%s%s, expected IPv6 multicast."),
group ? "\"" : "", group ? group : "(null)", group ? "\"" : "");
return FALSE;
-#endif /* CONFIG_HAVE_GETNETENT */
+#endif /* HAVE_GETNETENT */
}
default:
pgm_set_error (error,
diff --git a/src/pgm/impl/checksum.h b/src/pgm/impl/checksum.h
new file mode 100644
index 0000000..ac7e990
--- /dev/null
+++ b/src/pgm/impl/checksum.h
@@ -0,0 +1,78 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * PGM checksum routines
+ *
+ * Copyright (c) 2006-2008 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_CHECKSUM_H__
+#define __PGM_IMPL_CHECKSUM_H__
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+uint16_t pgm_inet_checksum (const void*, uint16_t, uint16_t);
+uint16_t pgm_csum_fold (uint32_t) PGM_GNUC_CONST;
+uint32_t pgm_csum_block_add (uint32_t, uint32_t, const uint16_t) PGM_GNUC_CONST;
+uint32_t pgm_compat_csum_partial (const void*, uint16_t, uint32_t);
+uint32_t pgm_compat_csum_partial_copy (const void*restrict, void*restrict, uint16_t, uint32_t);
+
+static inline uint32_t add32_with_carry (uint32_t, uint32_t) PGM_GNUC_CONST;
+
+#if defined( __i386__ ) || defined( __i386 ) || defined( __x86_64__ ) || defined( __amd64 )
+static inline uint32_t add32_with_carry (uint32_t a, uint32_t b)
+{
+ __asm__ ( "addl %2, %0 \n\t"
+ "adcl $0, %0"
+ : "=r" (a) /* output operands */
+ : "0" (a), "r" (b)); /* input operands */
+ return a;
+}
+#elif defined( __sparc__ ) || defined( __sparc ) || defined( __sparcv9 )
+static inline uint32_t add32_with_carry (uint32_t a, uint32_t b)
+{
+ __asm__ ( "addcc %2, %0, %0 \n\t"
+ "addx %0, %%g0, %0"
+ : "=r" (a) /* output operands */
+ : "0" (a), "r" (b) /* input operands */
+ : "cc"); /* list of clobbered registers */
+ return a;
+}
+#else
+static inline uint32_t add32_with_carry (uint32_t a, uint32_t b)
+{
+ a += b;
+ a = (a >> 16) + (a & 0xffff);
+ return a;
+}
+#endif
+
+# define pgm_csum_partial pgm_compat_csum_partial
+# define pgm_csum_partial_copy pgm_compat_csum_partial_copy
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_CHECKSUM_H__ */
+
diff --git a/src/pgm/impl/engine.h b/src/pgm/impl/engine.h
new file mode 100644
index 0000000..bfa8f4b
--- /dev/null
+++ b/src/pgm/impl/engine.h
@@ -0,0 +1,46 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * PGM engine.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_ENGINE_H__
+#define __PGM_IMPL_ENGINE_H__
+
+#ifdef _WIN32
+# include <ws2tcpip.h>
+# include <mswsock.h>
+#endif
+#include <impl/framework.h>
+
+PGM_BEGIN_DECLS
+
+#ifdef _WIN32
+extern LPFN_WSARECVMSG pgm_WSARecvMsg;
+#endif
+
+#ifdef PGM_DEBUG
+extern unsigned pgm_loss_rate;
+#endif
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_ENGINE_H__ */
diff --git a/src/pgm/impl/errno.h b/src/pgm/impl/errno.h
new file mode 100644
index 0000000..fcd37b2
--- /dev/null
+++ b/src/pgm/impl/errno.h
@@ -0,0 +1,42 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * Portable error code return type for selected CRT API.
+ *
+ * Copyright (c) 2011 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_ERRNO_H__
+#define __PGM_IMPL_ERRNO_H__
+
+#ifndef _MSC_VER
+# define errno_t int
+#endif
+
+PGM_BEGIN_DECLS
+
+/* nc */
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_ERRNO_H__ */
diff --git a/src/pgm/impl/fixed.h b/src/pgm/impl/fixed.h
new file mode 100644
index 0000000..36df39f
--- /dev/null
+++ b/src/pgm/impl/fixed.h
@@ -0,0 +1,145 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * 8-bit and 16-bit shift fixed point math
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_FIXED_H__
+#define __PGM_IMPL_FIXED_H__
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+static inline uint_fast32_t pgm_fp8 (unsigned) PGM_GNUC_CONST;
+static inline uint_fast32_t pgm_fp16 (unsigned) PGM_GNUC_CONST;
+static inline unsigned pgm_fp8tou (uint_fast32_t) PGM_GNUC_CONST;
+static inline unsigned pgm_fp16tou (uint_fast32_t) PGM_GNUC_CONST;
+static inline uint_fast32_t pgm_fp8mul (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST;
+static inline uint_fast32_t pgm_fp16mul (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST;
+static inline uint_fast32_t pgm_fp8div (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST;
+static inline uint_fast32_t pgm_fp16div (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST;
+static inline uint_fast32_t pgm_fp16pow (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST;
+
+static inline
+uint_fast32_t
+pgm_fp8 (
+ unsigned v
+ )
+{
+ return (uint32_t)(v << 8);
+}
+
+static inline
+uint_fast32_t
+pgm_fp16 (
+ unsigned v
+ )
+{
+ return (uint_fast32_t)(v << 16);
+}
+
+static inline
+unsigned
+pgm_fp8tou (
+ uint_fast32_t f
+ )
+{
+ return (f + (1 << 7)) >> 8;
+}
+
+static inline
+unsigned
+pgm_fp16tou (
+ uint_fast32_t f
+ )
+{
+ return (f + (1 << 15)) >> 16;
+}
+
+static inline
+uint_fast32_t
+pgm_fp8mul (
+ uint_fast32_t a,
+ uint_fast32_t b
+ )
+{
+ return ( a * b + 128 ) >> 8;
+}
+
+static inline
+uint_fast32_t
+pgm_fp16mul (
+ uint_fast32_t a,
+ uint_fast32_t b
+ )
+{
+ return ( a * b + 32768 ) >> 16;
+}
+
+static inline
+uint_fast32_t
+pgm_fp8div (
+ uint_fast32_t a,
+ uint_fast32_t b
+ )
+{
+ return ( ( (a << 9) / b ) + 1 ) / 2;
+}
+
+static inline
+uint_fast32_t
+pgm_fp16div (
+ uint_fast32_t a,
+ uint_fast32_t b
+ )
+{
+ return ( ( (a << 17) / b ) + 1 ) / 2;
+}
+
+static inline
+uint_fast32_t
+pgm_fp16pow (
+ uint_fast32_t x,
+ uint_fast32_t y
+ )
+{
+ uint_fast32_t result = pgm_fp16 (1);
+/* C89 version */
+ uint_fast32_t i;
+ for (i = x;
+ y;
+ y >>= 1)
+ {
+ if (y & 1)
+ result = (result * i + 32768) >> 16;
+ i = (i * i + 32768) >> 16;
+ }
+ return result;
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_FIXED_H__ */
diff --git a/src/pgm/impl/framework.h b/src/pgm/impl/framework.h
new file mode 100644
index 0000000..0d9ed53
--- /dev/null
+++ b/src/pgm/impl/framework.h
@@ -0,0 +1,83 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * Framework collection.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_FRAMEWORK_H__
+#define __PGM_IMPL_FRAMEWORK_H__
+
+#define __PGM_IMPL_FRAMEWORK_H_INSIDE__
+
+#include <pgm/atomic.h>
+#include <pgm/error.h>
+#include <pgm/gsi.h>
+#include <pgm/list.h>
+#include <pgm/macros.h>
+#include <pgm/mem.h>
+#include <pgm/messages.h>
+#include <pgm/msgv.h>
+#include <pgm/packet.h>
+#include <pgm/skbuff.h>
+#include <pgm/socket.h>
+#include <pgm/time.h>
+#include <pgm/tsi.h>
+#include <pgm/types.h>
+
+#include <impl/checksum.h>
+#include <impl/errno.h>
+#include <impl/fixed.h>
+#include <impl/galois.h>
+#include <impl/getifaddrs.h>
+#include <impl/get_nprocs.h>
+#include <impl/getnetbyname.h>
+#include <impl/getnodeaddr.h>
+#include <impl/getprotobyname.h>
+#include <impl/hashtable.h>
+#include <impl/histogram.h>
+#include <impl/indextoaddr.h>
+#include <impl/indextoname.h>
+#include <impl/inet_network.h>
+#include <impl/ip.h>
+#include <impl/list.h>
+#include <impl/math.h>
+#include <impl/md5.h>
+#include <impl/messages.h>
+#include <impl/nametoindex.h>
+#include <impl/notify.h>
+#include <impl/processor.h>
+#include <impl/queue.h>
+#include <impl/rand.h>
+#include <impl/rate_control.h>
+#include <impl/reed_solomon.h>
+#include <impl/security.h>
+#include <impl/slist.h>
+#include <impl/sn.h>
+#include <impl/sockaddr.h>
+#include <impl/string.h>
+#include <impl/thread.h>
+#include <impl/time.h>
+#include <impl/tsi.h>
+#include <impl/wsastrerror.h>
+
+#undef __PGM_IMPL_FRAMEWORK_H_INSIDE__
+
+#endif /* __PGM_IMPL_FRAMEWORK_H__ */
diff --git a/src/pgm/impl/galois.h b/src/pgm/impl/galois.h
new file mode 100644
index 0000000..5c43dad
--- /dev/null
+++ b/src/pgm/impl/galois.h
@@ -0,0 +1,146 @@
+/*
+ * Galois field maths.
+ *
+ * Copyright (c) 2006-2008 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_GALOIS_H__
+#define __PGM_IMPL_GALOIS_H__
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+/* 8 bit wide galois field integer: GF(2⁸) */
+#ifdef _MSC_VER
+typedef uint8_t pgm_gf8_t;
+#else
+typedef uint8_t __attribute__((__may_alias__)) pgm_gf8_t;
+#endif
+
+/* E denotes the encoding symbol length in bytes.
+ * S denotes the symbol size in units of m-bit elements. When m = 8,
+ * then S and E are equal.
+ */
+#define PGM_GF_ELEMENT_BYTES sizeof(pgm_gf8_t)
+
+/* m defines the length of the elements in the finite field, in bits.
+ * m belongs to {2..16}.
+ */
+#define PGM_GF_ELEMENT_BITS ( 8 * PGM_GF_ELEMENT_BYTES )
+
+/* q defines the number of elements in the finite field.
+ */
+#define PGM_GF_NO_ELEMENTS ( 1 << PGM_GF_ELEMENT_BITS )
+#define PGM_GF_MAX ( PGM_GF_NO_ELEMENTS - 1 )
+
+
+extern const pgm_gf8_t pgm_gflog[PGM_GF_NO_ELEMENTS];
+extern const pgm_gf8_t pgm_gfantilog[PGM_GF_NO_ELEMENTS];
+
+#ifdef USE_GALOIS_MUL_LUT
+extern const pgm_gf8_t pgm_gftable[PGM_GF_NO_ELEMENTS * PGM_GF_NO_ELEMENTS];
+#endif
+
+/* In a finite field with characteristic 2, addition and subtraction are
+ * identical, and are accomplished using the XOR operator.
+ */
+static inline
+pgm_gf8_t
+pgm_gfadd (
+ pgm_gf8_t a,
+ pgm_gf8_t b
+ )
+{
+ return a ^ b;
+}
+
+static inline
+pgm_gf8_t
+pgm_gfadd_equals (
+ pgm_gf8_t a,
+ pgm_gf8_t b
+ )
+{
+ return a ^= b;
+}
+
+static inline
+pgm_gf8_t
+pgm_gfsub (
+ pgm_gf8_t a,
+ pgm_gf8_t b
+ )
+{
+ return pgm_gfadd (a, b);
+}
+
+static inline
+pgm_gf8_t
+pgm_gfsub_equals (
+ pgm_gf8_t a,
+ pgm_gf8_t b
+ )
+{
+ return pgm_gfadd_equals (a, b);
+}
+
+static inline
+pgm_gf8_t
+pgm_gfmul (
+ pgm_gf8_t a,
+ pgm_gf8_t b
+ )
+{
+ if (PGM_UNLIKELY( !(a && b) )) {
+ return 0;
+ }
+
+#ifdef USE_GALOIS_MUL_LUT
+ return pgm_gftable[ (uint16_t)a << 8 | (uint16_t)b ];
+#else
+ const unsigned sum = pgm_gflog[ a ] + pgm_gflog[ b ];
+ return sum >= PGM_GF_MAX ? pgm_gfantilog[ sum - PGM_GF_MAX ] : pgm_gfantilog[ sum ];
+#endif
+}
+
+static inline
+pgm_gf8_t
+pgm_gfdiv (
+ pgm_gf8_t a,
+ pgm_gf8_t b
+ )
+{
+/* C89 version */
+ const int sum = pgm_gflog[ a ] - pgm_gflog[ b ];
+ if (PGM_UNLIKELY( !a )) {
+ return 0;
+ }
+
+ return sum < 0 ? pgm_gfantilog[ sum + PGM_GF_MAX ] : pgm_gfantilog[ sum ];
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_GALOIS_H__ */
diff --git a/src/pgm/impl/get_nprocs.h b/src/pgm/impl/get_nprocs.h
new file mode 100644
index 0000000..2d0b413
--- /dev/null
+++ b/src/pgm/impl/get_nprocs.h
@@ -0,0 +1,41 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable function to return number of available, online, or
+ * configured processors.
+ *
+ * Copyright (c) 2011 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_GET_NPROCS_H__
+#define __PGM_IMPL_GET_NPROCS_H__
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL int pgm_get_nprocs (void);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_GET_NPROCS_H__ */
diff --git a/src/pgm/impl/getifaddrs.h b/src/pgm/impl/getifaddrs.h
new file mode 100644
index 0000000..a70a9eb
--- /dev/null
+++ b/src/pgm/impl/getifaddrs.h
@@ -0,0 +1,79 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable getifaddrs
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_GETIFADDRS_H__
+#define __PGM_IMPL_GETIFADDRS_H__
+
+#ifndef _WIN32
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <net/if.h>
+#else
+# include <ws2tcpip.h>
+#endif
+
+struct pgm_ifaddrs_t;
+
+#include <pgm/types.h>
+#include <pgm/error.h>
+
+PGM_BEGIN_DECLS
+
+#ifndef IF_NAMESIZE
+# ifdef IFNAMSIZ
+# define IF_NAMESIZE IFNAMSIZ
+# elif defined(MAX_INTERFACE_NAME_LEN)
+# define IF_NAMESIZE MAX_INTERFACE_NAME_LEN
+# elif defined(_WIN32)
+/* 40 for UUID, 256 for device path */
+# define IF_NAMESIZE 256
+# else
+# define IF_NAMESIZE 16
+# endif
+#endif
+
+struct pgm_ifaddrs_t
+{
+ struct pgm_ifaddrs_t* ifa_next; /* Pointer to the next structure. */
+
+ char* ifa_name; /* Name of this network interface. */
+ unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */
+
+#ifdef ifa_addr
+# undef ifa_addr
+#endif
+ struct sockaddr* ifa_addr; /* Network address of this interface. */
+ struct sockaddr* ifa_netmask; /* Netmask of this interface. */
+};
+
+bool pgm_getifaddrs (struct pgm_ifaddrs_t**restrict, pgm_error_t**restrict);
+void pgm_freeifaddrs (struct pgm_ifaddrs_t*);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_GETIFADDRS_H__ */
diff --git a/src/pgm/impl/getnetbyname.h b/src/pgm/impl/getnetbyname.h
new file mode 100644
index 0000000..87fbd61
--- /dev/null
+++ b/src/pgm/impl/getnetbyname.h
@@ -0,0 +1,49 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable getnetbyname
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_GETNETBYNAME_H__
+#define __PGM_IMPL_GETNETBYNAME_H__
+
+struct pgm_netent_t;
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_netent_t
+{
+ char* n_name; /* Official network name */
+ char** n_aliases; /* Alias list */
+ struct sockaddr_storage n_net; /* Network address */
+};
+
+struct pgm_netent_t* pgm_getnetbyname (const char*);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_GETNETBYNAME_H__ */
diff --git a/src/pgm/impl/getnodeaddr.h b/src/pgm/impl/getnodeaddr.h
new file mode 100644
index 0000000..f28ecea
--- /dev/null
+++ b/src/pgm/impl/getnodeaddr.h
@@ -0,0 +1,48 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable function to return node IP address.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_GETNODEADDR_H__
+#define __PGM_IMPL_GETNODEADDR_H__
+
+#ifndef _WIN32
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netdb.h>
+#endif
+#include <pgm/types.h>
+#include <pgm/error.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL bool pgm_getnodeaddr (const sa_family_t, struct addrinfo**restrict, pgm_error_t**restrict);
+PGM_GNUC_INTERNAL void pgm_freenodeaddr (struct addrinfo*);
+PGM_GNUC_INTERNAL bool pgm_get_multicast_enabled_node_addr (const sa_family_t, struct sockaddr*restrict, const socklen_t, pgm_error_t**restrict);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_GETNODEADDR_H__ */
diff --git a/src/pgm/impl/getprotobyname.h b/src/pgm/impl/getprotobyname.h
new file mode 100644
index 0000000..be4a9aa
--- /dev/null
+++ b/src/pgm/impl/getprotobyname.h
@@ -0,0 +1,49 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable getprotobyname
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_GETPROTOBYNAME_H__
+#define __PGM_IMPL_GETPROTOBYNAME_H__
+
+struct pgm_protoent_t;
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_protoent_t
+{
+ char* p_name; /* Official protocol name */
+ char** p_aliases; /* Alias list */
+ int p_proto; /* Protocol number */
+};
+
+struct pgm_protoent_t* pgm_getprotobyname (const char*);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_GETPROTOBYNAME_H__ */
diff --git a/src/pgm/impl/hashtable.h b/src/pgm/impl/hashtable.h
new file mode 100644
index 0000000..0545831
--- /dev/null
+++ b/src/pgm/impl/hashtable.h
@@ -0,0 +1,61 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable hash table.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_HASHTABLE_H__
+#define __PGM_IMPL_HASHTABLE_H__
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+typedef struct pgm_hashtable_t pgm_hashtable_t;
+typedef uint_fast32_t pgm_hash_t;
+
+typedef pgm_hash_t (*pgm_hashfunc_t) (const void*);
+typedef bool (*pgm_equalfunc_t) (const void*restrict, const void*restrict);
+
+PGM_GNUC_INTERNAL pgm_hashtable_t* pgm_hashtable_new (pgm_hashfunc_t, pgm_equalfunc_t);
+PGM_GNUC_INTERNAL void pgm_hashtable_destroy (pgm_hashtable_t*);
+PGM_GNUC_INTERNAL void pgm_hashtable_insert (pgm_hashtable_t*restrict, const void*restrict, void*restrict);
+PGM_GNUC_INTERNAL bool pgm_hashtable_remove (pgm_hashtable_t*restrict, const void*restrict);
+PGM_GNUC_INTERNAL void pgm_hashtable_remove_all (pgm_hashtable_t*);
+PGM_GNUC_INTERNAL void* pgm_hashtable_lookup (const pgm_hashtable_t*restrict, const void*restrict);
+PGM_GNUC_INTERNAL void* pgm_hashtable_lookup_extended (const pgm_hashtable_t*restrict, const void*restrict, void*restrict);
+PGM_GNUC_INTERNAL void pgm_hashtable_unref (pgm_hashtable_t*);
+
+/* Hash Functions
+ */
+
+PGM_GNUC_INTERNAL bool pgm_str_equal (const void*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL pgm_hash_t pgm_str_hash (const void*) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_int_equal (const void*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL pgm_hash_t pgm_int_hash (const void*) PGM_GNUC_WARN_UNUSED_RESULT;
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_HASHTABLE_H__ */
diff --git a/src/pgm/impl/histogram.h b/src/pgm/impl/histogram.h
new file mode 100644
index 0000000..2f8764d
--- /dev/null
+++ b/src/pgm/impl/histogram.h
@@ -0,0 +1,132 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * histograms.
+ *
+ * Copyright (c) 2009-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_HISTOGRAM_H__
+#define __PGM_IMPL_HISTOGRAM_H__
+
+#include <pgm/types.h>
+#include <pgm/time.h>
+#include <impl/slist.h>
+#include <impl/string.h>
+
+PGM_BEGIN_DECLS
+
+typedef int pgm_sample_t;
+typedef int pgm_count_t;
+
+struct pgm_sample_set_t {
+ pgm_count_t* counts;
+ unsigned counts_len;
+ int64_t sum;
+ int64_t square_sum;
+};
+
+typedef struct pgm_sample_set_t pgm_sample_set_t;
+
+struct pgm_histogram_t {
+ const char* restrict histogram_name;
+ unsigned bucket_count;
+ pgm_sample_t declared_min;
+ pgm_sample_t declared_max;
+ pgm_sample_t* restrict ranges;
+ pgm_sample_set_t sample;
+ bool is_registered;
+ pgm_slist_t histograms_link;
+};
+
+typedef struct pgm_histogram_t pgm_histogram_t;
+
+#define PGM_HISTOGRAM_DEFINE(name, minimum, maximum, count) \
+ static pgm_count_t counts[ (count) ]; \
+ static pgm_sample_t ranges[ (count) + 1 ]; \
+ static pgm_histogram_t counter = { \
+ .histogram_name = (name), \
+ .bucket_count = (count), \
+ .declared_min = (minimum), \
+ .declared_max = (maximum), \
+ .ranges = ranges, \
+ .sample = { \
+ .counts = counts, \
+ .counts_len = (count), \
+ .sum = 0, \
+ .square_sum = 0 \
+ }, \
+ .is_registered = FALSE \
+ }
+
+#ifdef USE_HISTOGRAMS
+
+# define PGM_HISTOGRAM_TIMES(name, sample) do { \
+ PGM_HISTOGRAM_DEFINE(name, pgm_msecs(1), pgm_secs(10), 50); \
+ if (!counter.is_registered) { \
+ memset (counts, 0, sizeof(counts)); \
+ memset (ranges, 0, sizeof(ranges)); \
+ pgm_histogram_init (&counter); \
+ } \
+ pgm_histogram_add_time (&counter, sample); \
+ } while (0)
+
+# define PGM_HISTOGRAM_COUNTS(name, sample) do { \
+ PGM_HISTOGRAM_DEFINE(name, 1, 1000000, 50); \
+ if (!counter.is_registered) { \
+ memset (counts, 0, sizeof(counts)); \
+ memset (ranges, 0, sizeof(ranges)); \
+ pgm_histogram_init (&counter); \
+ } \
+ pgm_histogram_add (&counter, (sample)); \
+ } while (0)
+
+#else
+
+# define PGM_HISTOGRAM_TIMES(name, sample)
+# define PGM_HISTOGRAM_COUNTS(name, sample)
+
+#endif /* USE_HISTOGRAMS */
+
+
+extern pgm_slist_t* pgm_histograms;
+
+void pgm_histogram_init (pgm_histogram_t*);
+void pgm_histogram_add (pgm_histogram_t*, int);
+void pgm_histogram_write_html_graph_all (pgm_string_t*);
+
+static inline
+void
+pgm_histogram_add_time (
+ pgm_histogram_t*const histogram,
+ pgm_time_t sample_time
+ )
+{
+ pgm_histogram_add (histogram, (int)pgm_to_msecs (sample_time));
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_HISTOGRAM_H__ */
+
+/* eof */
diff --git a/src/pgm/impl/i18n.h b/src/pgm/impl/i18n.h
new file mode 100644
index 0000000..d55737b
--- /dev/null
+++ b/src/pgm/impl/i18n.h
@@ -0,0 +1,35 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * i18n & l10n support
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_I18N_H__
+#define __PGM_IMPL_I18N_H__
+
+#ifdef HAVE_GETTEXT
+# include <libintl.h>
+# define _(String) dgettext (GETTEXT_PACKAGE, String)
+#else
+# define _(String) (String)
+#endif
+
+#endif /* __PGM_IMPL_I18N_H__ */
diff --git a/src/pgm/impl/indextoaddr.h b/src/pgm/impl/indextoaddr.h
new file mode 100644
index 0000000..99c1445
--- /dev/null
+++ b/src/pgm/impl/indextoaddr.h
@@ -0,0 +1,44 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable interface index to socket address function.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_INDEXTOADDR_H__
+#define __PGM_IMPL_INDEXTOADDR_H__
+
+#ifndef _WIN32
+# include <sys/socket.h>
+#endif
+#include <pgm/types.h>
+#include <pgm/error.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL bool pgm_if_indextoaddr (const unsigned, const sa_family_t, const uint32_t, struct sockaddr*restrict, pgm_error_t**restrict);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_INDEXTOADDR_H__ */
diff --git a/src/pgm/impl/indextoname.h b/src/pgm/impl/indextoname.h
new file mode 100644
index 0000000..bc36a19
--- /dev/null
+++ b/src/pgm/impl/indextoname.h
@@ -0,0 +1,40 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * Windows interface index to interface name function.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_INDEXTONAME_H__
+#define __PGM_IMPL_INDEXTONAME_H__
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL char* pgm_if_indextoname (unsigned, char*);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_INDEXTONAME_H__ */
diff --git a/src/pgm/impl/inet_lnaof.h b/src/pgm/impl/inet_lnaof.h
new file mode 100644
index 0000000..b68d400
--- /dev/null
+++ b/src/pgm/impl/inet_lnaof.h
@@ -0,0 +1,37 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * Portable implementation of inet_lnaof.
+ *
+ * Copyright (c) 2006-2012 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_INET_LNAOF_H__
+#define __PGM_INET_LNAOF_H__
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+bool pgm_inet_lnaof (struct in_addr* restrict dst, const struct in_addr* restrict src, const struct in_addr* restrict netmask);
+bool pgm_inet6_lnaof (struct in6_addr* restrict dst, const struct in6_addr* restrict src, const struct in6_addr* restrict netmask);
+
+PGM_END_DECLS
+
+#endif /* __PGM_INET_LNAOF_H__ */
diff --git a/src/pgm/impl/inet_network.h b/src/pgm/impl/inet_network.h
new file mode 100644
index 0000000..7086d02
--- /dev/null
+++ b/src/pgm/impl/inet_network.h
@@ -0,0 +1,46 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable implementations of inet_network and inet_network6.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_INET_NETWORK_H__
+#define __PGM_IMPL_INET_NETWORK_H__
+
+#ifndef _WIN32
+# include <netinet/in.h>
+#endif
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL int pgm_inet_network (const char*restrict, struct in_addr*restrict);
+PGM_GNUC_INTERNAL int pgm_inet6_network (const char*restrict, struct in6_addr*restrict);
+PGM_GNUC_INTERNAL int pgm_sa6_network (const char*restrict, struct sockaddr_in6*restrict);
+PGM_GNUC_INTERNAL struct in_addr pgm_inet_makeaddr (uint32_t, uint32_t);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_INET_NETWORK_H__ */
diff --git a/src/pgm/impl/ip.h b/src/pgm/impl/ip.h
new file mode 100644
index 0000000..a8fbe10
--- /dev/null
+++ b/src/pgm/impl/ip.h
@@ -0,0 +1,153 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * Internet header for protocol version 4, RFC 791.
+ *
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 4. Neither the name of the University 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 REGENTS 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.
+ *
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_IP_H__
+#define __PGM_IMPL_IP_H__
+
+#ifndef _WIN32
+# include <netinet/in.h>
+# include <sys/param.h>
+#endif
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+/* Byte alignment for packet memory maps.
+ * NB: Solaris and OpenSolaris don't support #pragma pack(push) even on x86.
+ */
+#if defined( __GNUC__ ) && !defined( __sun ) && !defined( __CYGWIN__ )
+# pragma pack(push)
+#endif
+#pragma pack(1)
+
+/* RFC 791 */
+
+/* nb: first four bytes are forced bitfields for win32 "feature" */
+struct pgm_ip
+{
+#if (defined( __sun ) && defined( _BIT_FIELDS_LTOH )) || (!defined( __sun ) && __BYTE_ORDER == __LITTLE_ENDIAN)
+ unsigned ip_hl:4; /* header length */
+ unsigned ip_v:4; /* version */
+#else
+ unsigned ip_v:4; /* version */
+ unsigned ip_hl:4; /* header length */
+#endif
+ unsigned ip_tos:8; /* type of service */
+ unsigned ip_len:16; /* total length */
+ uint16_t ip_id; /* identification */
+ uint16_t ip_off; /* fragment offset field */
+ uint8_t ip_ttl; /* time to live */
+ uint8_t ip_p; /* protocol */
+ uint16_t ip_sum; /* checksum */
+ struct in_addr ip_src, ip_dst; /* source and dest address */
+};
+
+PGM_STATIC_ASSERT(sizeof(struct pgm_ip) == 20);
+
+/* RFC 2460 */
+#ifdef ip6_vfc
+# undef ip6_vfc
+#endif
+#ifdef ip6_plen
+# undef ip6_plen
+#endif
+#ifdef ip6_nxt
+# undef ip6_nxt
+#endif
+#ifdef ip6_hops
+# undef ip6_hops
+#endif
+struct pgm_ip6_hdr
+{
+ uint32_t ip6_vfc; /* version:4, traffic class:8, flow label:20 */
+ uint16_t ip6_plen; /* payload length: packet length - 40 */
+ uint8_t ip6_nxt; /* next header type */
+ uint8_t ip6_hops; /* hop limit */
+ struct in6_addr ip6_src, ip6_dst; /* source and dest address */
+};
+
+PGM_STATIC_ASSERT(sizeof(struct pgm_ip6_hdr) == 40);
+
+#define PGM_IPOPT_EOL 0 /* end of option list */
+#define PGM_IPOPT_NOP 1 /* no operation */
+#define PGM_IPOPT_RR 7 /* record packet route */
+#define PGM_IPOPT_TS 68 /* timestamp */
+#define PGM_IPOPT_SECURITY 130 /* provide s, c, h, tcc */
+#define PGM_IPOPT_LSRR 131 /* loose source route */
+#define PGM_IPOPT_ESO 133
+#define PGM_IPOPT_CIPSO 134
+#define PGM_IPOPT_SATID 136 /* satnet id */
+#define PGM_IPOPT_SSRR 137 /* strict source route */
+#define PGM_IPOPT_RA 148 /* router alert */
+
+/* RFC 768 */
+struct pgm_udphdr
+{
+ in_port_t uh_sport; /* source port */
+ in_port_t uh_dport; /* destination port */
+ uint16_t uh_ulen; /* udp length */
+ uint16_t uh_sum; /* udp checksum */
+};
+
+PGM_STATIC_ASSERT(sizeof(struct pgm_udphdr) == 8);
+
+#if defined( __GNUC__ ) && !defined( __sun ) && !defined( __CYGWIN__ )
+# pragma pack(pop)
+#else
+# pragma pack()
+#endif
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_IP_H__ */
diff --git a/src/pgm/impl/list.h b/src/pgm/impl/list.h
new file mode 100644
index 0000000..1ba680e
--- /dev/null
+++ b/src/pgm/impl/list.h
@@ -0,0 +1,46 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable doubly-linked list.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_LIST_H__
+#define __PGM_IMPL_LIST_H__
+
+#include <pgm/types.h>
+#include <pgm/list.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL pgm_list_t* pgm_list_append (pgm_list_t*restrict, void*restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL pgm_list_t* pgm_list_prepend_link (pgm_list_t*restrict, pgm_list_t*restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL pgm_list_t* pgm_list_remove_link (pgm_list_t*, pgm_list_t*) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL pgm_list_t* pgm_list_delete_link (pgm_list_t*, pgm_list_t*) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL pgm_list_t* pgm_list_last (pgm_list_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL unsigned pgm_list_length (pgm_list_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT;
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_LIST_H__ */
diff --git a/src/pgm/impl/math.h b/src/pgm/impl/math.h
new file mode 100644
index 0000000..83751c1
--- /dev/null
+++ b/src/pgm/impl/math.h
@@ -0,0 +1,79 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * Shared math routines.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_MATH_H__
+#define __PGM_IMPL_MATH_H__
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+/* fast log base 2 of power of 2
+ */
+
+static inline unsigned pgm_power2_log2 (unsigned) PGM_GNUC_CONST;
+
+static inline
+unsigned
+pgm_power2_log2 (
+ unsigned v
+ )
+{
+ static const unsigned int b[] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 };
+ unsigned int r = (v & b[0]) != 0;
+/* C89 version */
+ unsigned i;
+ for (i = 4; i > 0; i--)
+ r |= ((v & b[i]) != 0) << i;
+ return r;
+}
+
+/* nearest power of 2
+ */
+
+static inline size_t pgm_nearest_power (size_t, size_t) PGM_GNUC_CONST;
+
+static inline
+size_t
+pgm_nearest_power (
+ size_t b,
+ size_t v
+ )
+{
+ if (v > (SIZE_MAX/2))
+ return SIZE_MAX;
+ while (b < v)
+ b <<= 1;
+ return b;
+}
+
+unsigned pgm_spaced_primes_closest (unsigned) PGM_GNUC_PURE;
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_MATH_H__ */
diff --git a/src/pgm/impl/md5.h b/src/pgm/impl/md5.h
new file mode 100644
index 0000000..3d30b12
--- /dev/null
+++ b/src/pgm/impl/md5.h
@@ -0,0 +1,64 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * MD5 hashing algorithm.
+ *
+ * MD5 original source GNU C Library:
+ * Includes functions to compute MD5 message digest of files or memory blocks
+ * according to the definition of MD5 in RFC 1321 from April 1992.
+ *
+ * Copyright (C) 1995, 1996, 2001, 2003 Free Software Foundation, Inc.
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_MD5_H__
+#define __PGM_IMPL_MD5_H__
+
+struct pgm_md5_t;
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_md5_t
+{
+ uint32_t A;
+ uint32_t B;
+ uint32_t C;
+ uint32_t D;
+
+ uint32_t total[2];
+ uint32_t buflen;
+ char buffer[128]
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+ __attribute__ ((__aligned__ (__alignof__ (uint32_t))))
+#endif
+ ;
+};
+
+PGM_GNUC_INTERNAL void pgm_md5_init_ctx (struct pgm_md5_t*);
+PGM_GNUC_INTERNAL void pgm_md5_process_bytes (struct pgm_md5_t*restrict, const void*restrict, size_t);
+PGM_GNUC_INTERNAL void* pgm_md5_finish_ctx (struct pgm_md5_t*restrict, void*restrict);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_MD5_H__ */
diff --git a/src/pgm/impl/mem.h b/src/pgm/impl/mem.h
new file mode 100644
index 0000000..cb081e6
--- /dev/null
+++ b/src/pgm/impl/mem.h
@@ -0,0 +1,37 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable fail fast memory allocation.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_MEM_H__
+#define __PGM_IMPL_MEM_H__
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL void pgm_mem_init (void);
+PGM_GNUC_INTERNAL void pgm_mem_shutdown (void);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_MEM_H__ */
diff --git a/src/pgm/impl/messages.h b/src/pgm/impl/messages.h
new file mode 100644
index 0000000..812393f
--- /dev/null
+++ b/src/pgm/impl/messages.h
@@ -0,0 +1,361 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * basic message reporting.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_MESSAGES_H__
+#define __PGM_IMPL_MESSAGES_H__
+
+#ifdef _MSC_VER
+# include <pgm/wininttypes.h>
+#else
+# include <inttypes.h>
+#endif
+#include <pgm/zinttypes.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <pgm/types.h>
+#include <pgm/messages.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL void pgm__log (const int, const char*, ...) PGM_GNUC_PRINTF (2, 3);
+PGM_GNUC_INTERNAL void pgm__logv (const int, const char*, va_list) PGM_GNUC_PRINTF (2, 0);
+
+#if defined( HAVE_ISO_VARARGS )
+
+/* debug trace level only valid in debug mode */
+# ifdef PGM_DEBUG
+# define pgm_debug(...) \
+ do { \
+ if (pgm_min_log_level == PGM_LOG_LEVEL_DEBUG) \
+ pgm__log (PGM_LOG_LEVEL_DEBUG, __VA_ARGS__); \
+ } while (0)
+# else
+# define pgm_debug(...) while (0)
+# endif /* !PGM_DEBUG */
+
+# define pgm_trace(r,...) \
+ do { \
+ if (pgm_min_log_level <= PGM_LOG_LEVEL_TRACE && pgm_log_mask & (r)) \
+ pgm__log (PGM_LOG_LEVEL_TRACE, __VA_ARGS__); \
+ } while (0)
+# define pgm_minor(...) \
+ do { \
+ if (pgm_min_log_level <= PGM_LOG_LEVEL_MINOR) \
+ pgm__log (PGM_LOG_LEVEL_MINOR, __VA_ARGS__); \
+ } while (0)
+# define pgm_info(...) \
+ do { \
+ if (pgm_min_log_level <= PGM_LOG_LEVEL_NORMAL) \
+ pgm__log (PGM_LOG_LEVEL_NORMAL, __VA_ARGS__); \
+ } while (0)
+# define pgm_warn(...) \
+ do { \
+ if (pgm_min_log_level <= PGM_LOG_LEVEL_WARNING) \
+ pgm__log (PGM_LOG_LEVEL_WARNING, __VA_ARGS__); \
+ } while (0)
+# define pgm_error(...) \
+ do { \
+ if (pgm_min_log_level <= PGM_LOG_LEVEL_ERROR) \
+ pgm__log (PGM_LOG_LEVEL_ERROR, __VA_ARGS__); \
+ } while (0)
+# define pgm_fatal(...) \
+ do { \
+ pgm__log (PGM_LOG_LEVEL_FATAL, __VA_ARGS__); \
+ } while (0)
+
+#elif defined( HAVE_GNUC_VARARGS )
+
+# ifdef PGM_DEBUG
+# define pgm_debug(f...) \
+ do { \
+ if (pgm_min_log_level == PGM_LOG_LEVEL_DEBUG) \
+ pgm__log (PGM_LOG_LEVEL_DEBUG, f); \
+ } while (0)
+# else
+# define pgm_debug(f...) while (0)
+# endif /* !PGM_DEBUG */
+
+# define pgm_trace(r,f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_TRACE && pgm_log_mask & (r)) \
+ pgm__log (PGM_LOG_LEVEL_TRACE, f)
+# define pgm_minor(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_MINOR) pgm__log (PGM_LOG_LEVEL_MINOR, f)
+# define pgm_info(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_NORMAL) pgm__log (PGM_LOG_LEVEL_NORMAL, f)
+# define pgm_warn(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_WARNING) pgm__log (PGM_LOG_LEVEL_WARNING, f)
+# define pgm_error(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_ERROR) pgm__log (PGM_LOG_LEVEL_ERROR, f)
+# define pgm_fatal(f...) pgm__log (PGM_LOG_LEVEL_FATAL, f)
+
+#else /* no varargs macros */
+
+/* declare for GCC attributes */
+static inline void pgm_debug (const char*, ...) PGM_GNUC_PRINTF (1, 2);
+static inline void pgm_trace (const int, const char*, ...) PGM_GNUC_PRINTF (2, 3);
+static inline void pgm_minor (const char*, ...) PGM_GNUC_PRINTF (1, 2);
+static inline void pgm_info (const char*, ...) PGM_GNUC_PRINTF (1, 2);
+static inline void pgm_warn (const char*, ...) PGM_GNUC_PRINTF (1, 2);
+static inline void pgm_error (const char*, ...) PGM_GNUC_PRINTF (1, 2);
+static inline void pgm_fatal (const char*, ...) PGM_GNUC_PRINTF (1, 2);
+
+static inline void pgm_debug (const char* format, ...) {
+ if (PGM_LOG_LEVEL_DEBUG == pgm_min_log_level) {
+ va_list args;
+ va_start (args, format);
+ pgm__logv (PGM_LOG_LEVEL_DEBUG, format, args);
+ va_end (args);
+ }
+}
+
+static inline void pgm_trace (const int role, const char* format, ...) {
+ if (PGM_LOG_LEVEL_TRACE >= pgm_min_log_level && pgm_log_mask & role) {
+ va_list args;
+ va_start (args, format);
+ pgm__logv (PGM_LOG_LEVEL_TRACE, format, args);
+ va_end (args);
+ }
+}
+
+static inline void pgm_minor (const char* format, ...) {
+ if (PGM_LOG_LEVEL_MINOR >= pgm_min_log_level) {
+ va_list args;
+ va_start (args, format);
+ pgm__logv (PGM_LOG_LEVEL_MINOR, format, args);
+ va_end (args);
+ }
+}
+
+static inline void pgm_info (const char* format, ...) {
+ if (PGM_LOG_LEVEL_NORMAL >= pgm_min_log_level) {
+ va_list args;
+ va_start (args, format);
+ pgm__logv (PGM_LOG_LEVEL_NORMAL, format, args);
+ va_end (args);
+ }
+}
+
+static inline void pgm_warn (const char* format, ...) {
+ if (PGM_LOG_LEVEL_WARNING >= pgm_min_log_level) {
+ va_list args;
+ va_start (args, format);
+ pgm__logv (PGM_LOG_LEVEL_WARNING, format, args);
+ va_end (args);
+ }
+}
+
+static inline void pgm_error (const char* format, ...) {
+ if (PGM_LOG_LEVEL_ERROR >= pgm_min_log_level) {
+ va_list args;
+ va_start (args, format);
+ pgm__logv (PGM_LOG_LEVEL_WARNING, format, args);
+ va_end (args);
+ }
+}
+
+static inline void pgm_fatal (const char* format, ...) {
+ va_list args;
+ va_start (args, format);
+ pgm__logv (PGM_LOG_LEVEL_FATAL, format, args);
+ va_end (args);
+}
+
+#endif /* varargs */
+
+#define pgm_warn_if_reached() \
+ do { \
+ pgm_warn ("file %s: line %d (%s): code should not be reached", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+ } while (0)
+#define pgm_warn_if_fail(expr) \
+ do { \
+ if (PGM_LIKELY (expr)); \
+ else \
+ pgm_warn ("file %s: line %d (%s): runtime check failed: (%s)", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \
+ } while (0)
+
+
+#ifdef PGM_DISABLE_ASSERT
+
+# define pgm_assert(expr) while (0)
+# define pgm_assert_not_reached() while (0)
+# define pgm_assert_cmpint(n1, cmp, n2) while (0)
+# define pgm_assert_cmpuint(n1, cmp, n2) while (0)
+
+#elif defined(__GNUC__)
+
+# define pgm_assert(expr) \
+ do { \
+ if (PGM_LIKELY(expr)); \
+ else { \
+ pgm_fatal ("file %s: line %d (%s): assertion failed: (%s)", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \
+ abort (); \
+ } \
+ } while (0)
+# define pgm_assert_not_reached() \
+ do { \
+ pgm_fatal ("file %s: line %d (%s): should not be reached", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+ abort (); \
+ } while (0)
+# define pgm_assert_cmpint(n1, cmp, n2) \
+ do { \
+ const int64_t _n1 = (n1), _n2 = (n2); \
+ if (PGM_LIKELY(_n1 cmp _n2)); \
+ else { \
+ pgm_fatal ("file %s: line %d (%s): assertion failed (%s): (%" PRIi64 " %s %" PRIi64 ")", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \
+ abort (); \
+ } \
+ } while (0)
+# define pgm_assert_cmpuint(n1, cmp, n2) \
+ do { \
+ const uint64_t _n1 = (n1), _n2 = (n2); \
+ if (PGM_LIKELY(_n1 cmp _n2)); \
+ else { \
+ pgm_fatal ("file %s: line %d (%s): assertion failed (%s): (%" PRIu64 " %s %" PRIu64 ")", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \
+ abort (); \
+ } \
+ } while (0)
+
+#else
+
+# define pgm_assert(expr) \
+ do { \
+ if (PGM_LIKELY(expr)); \
+ else { \
+ pgm_fatal ("file %s: line %d: assertion failed: (%s)", \
+ __FILE__, __LINE__, #expr); \
+ abort (); \
+ } \
+ } while (0)
+# define pgm_assert_not_reached() \
+ do { \
+ pgm_fatal ("file %s: line %d: assertion failed: (%s)", \
+ __FILE__, __LINE__); \
+ abort (); \
+ } while (0)
+# define pgm_assert_cmpint(n1, cmp, n2) \
+ do { \
+ const int64_t _n1 = (n1), _n2 = (n2); \
+ if (PGM_LIKELY(_n1 cmp _n2)); \
+ else { \
+ pgm_fatal ("file %s: line %d: assertion failed (%s): (%" PRIi64 " %s %" PRIi64 ")", \
+ __FILE__, __LINE__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \
+ abort (); \
+ } \
+ } while (0)
+# define pgm_assert_cmpuint(n1, cmp, n2) \
+ do { \
+ const uint64_t _n1 = (n1), _n2 = (n2); \
+ if (PGM_LIKELY(_n1 cmp _n2)); \
+ else { \
+ pgm_fatal ("file %s: line %d: assertion failed (%s): (%" PRIu64 " %s %" PRIu64 ")", \
+ __FILE__, __LINE__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \
+ abort (); \
+ } \
+ } while (0)
+
+#endif /* !PGM_DISABLE_ASSERT */
+
+#ifdef PGM_DISABLE_CHECKS
+
+# define pgm_return_if_fail(expr) while (0)
+# define pgm_return_val_if_fail(expr, val) while (0)
+# define pgm_return_if_reached() return
+# define pgm_return_val_if_reached(val) return (val)
+
+#elif defined(__GNUC__)
+
+# define pgm_return_if_fail(expr) \
+ do { \
+ if (PGM_LIKELY(expr)); \
+ else { \
+ pgm_warn ("file %s: line %d (%s): assertion `%s' failed", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \
+ return; \
+ } \
+ } while (0)
+# define pgm_return_val_if_fail(expr, val) \
+ do { \
+ if (PGM_LIKELY(expr)); \
+ else { \
+ pgm_warn ("file %s: line %d (%s): assertion `%s' failed", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \
+ return (val); \
+ } \
+ } while (0)
+# define pgm_return_if_reached() \
+ do { \
+ pgm_warn ("file %s: line %d (%s): should not be reached", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+ return; \
+ } while (0)
+# define pgm_return_val_if_reached(val) \
+ do { \
+ pgm_warn ("file %s: line %d (%s): should not be reached", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+ return (val); \
+ } while (0)
+
+#else
+
+# define pgm_return_if_fail(expr) \
+ do { \
+ if (PGM_LIKELY(expr)); \
+ else { \
+ pgm_warn ("file %s: line %d: assertion `%s' failed", \
+ __FILE__, __LINE__, #expr); \
+ return; \
+ } \
+ } while (0)
+# define pgm_return_val_if_fail(expr, val) \
+ do { \
+ if (PGM_LIKELY(expr)); \
+ else { \
+ pgm_warn ("file %s: line %d: assertion `%s' failed", \
+ __FILE__, __LINE__, #expr); \
+ return (val); \
+ } \
+ } while (0)
+# define pgm_return_if_reached() \
+ do { \
+ pgm_warn ("file %s: line %d): should not be reached", \
+ __FILE__, __LINE__); \
+ return; \
+ } while (0)
+# define pgm_return_val_if_reached(val) \
+ do { \
+ pgm_warn ("file %s: line %d: should not be reached", \
+ __FILE__, __LINE__); \
+ return (val); \
+ } while (0)
+
+#endif /* !PGM_DISABLE_CHECKS */
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_MESSAGES_H__ */
diff --git a/src/pgm/impl/nametoindex.h b/src/pgm/impl/nametoindex.h
new file mode 100644
index 0000000..4e36e56
--- /dev/null
+++ b/src/pgm/impl/nametoindex.h
@@ -0,0 +1,43 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * Windows interface name to interface index function.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_NAMETOINDEX_H__
+#define __PGM_IMPL_NAMETOINDEX_H__
+
+#ifndef _WIN32
+# include <sys/socket.h>
+#endif
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL unsigned pgm_if_nametoindex (const sa_family_t, const char*);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_NAMETOINDEX_H__ */
diff --git a/src/pgm/impl/net.h b/src/pgm/impl/net.h
new file mode 100644
index 0000000..35ab302
--- /dev/null
+++ b/src/pgm/impl/net.h
@@ -0,0 +1,57 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * network send wrapper.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_NET_H__
+#define __PGM_IMPL_NET_H__
+
+#ifndef _WIN32
+# include <sys/socket.h>
+#endif
+#include <impl/framework.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL ssize_t pgm_sendto_hops (pgm_sock_t*restrict, bool, pgm_rate_t*restrict, bool, int, const void*restrict, size_t, const struct sockaddr*restrict, socklen_t);
+PGM_GNUC_INTERNAL int pgm_set_nonblocking (SOCKET fd[2]);
+
+static inline
+ssize_t
+pgm_sendto (
+ pgm_sock_t*restrict sock,
+ bool use_rate_limit,
+ pgm_rate_t*restrict minor_rate_control,
+ bool use_router_alert,
+ const void*restrict buf,
+ size_t len,
+ const struct sockaddr*restrict to,
+ socklen_t tolen
+ )
+{
+ return pgm_sendto_hops (sock, use_rate_limit, minor_rate_control, use_router_alert, -1, buf, len, to, tolen);
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_NET_H__ */
+
diff --git a/src/pgm/impl/notify.h b/src/pgm/impl/notify.h
new file mode 100644
index 0000000..e4a189c
--- /dev/null
+++ b/src/pgm/impl/notify.h
@@ -0,0 +1,310 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * Low kernel overhead event notify mechanism, or standard pipes.
+ *
+ * Copyright (c) 2008-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_NOTIFY_H__
+#define __PGM_IMPL_NOTIFY_H__
+
+typedef struct pgm_notify_t pgm_notify_t;
+
+#ifndef _WIN32
+# include <fcntl.h>
+# include <unistd.h>
+# ifdef HAVE_EVENTFD
+# include <sys/eventfd.h>
+# endif
+#else /* _WIN32 */
+# include <memory.h>
+# include <ws2tcpip.h>
+#endif
+#include <pgm/types.h>
+#include <impl/messages.h>
+#include <impl/sockaddr.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_notify_t {
+#if defined( HAVE_EVENTFD )
+ int eventfd;
+#elif !defined( _WIN32 )
+ int pipefd[2];
+#else
+ SOCKET s[2];
+#endif /* _WIN32 */
+};
+
+#if defined( HAVE_EVENTFD )
+# define PGM_NOTIFY_INIT { -1 }
+#elif !defined( _WIN32 )
+# define PGM_NOTIFY_INIT { { -1, -1 } }
+#else
+# define PGM_NOTIFY_INIT { { INVALID_SOCKET, INVALID_SOCKET } }
+#endif
+
+
+static inline
+bool
+pgm_notify_is_valid (
+ pgm_notify_t* notify
+ )
+{
+ if (PGM_UNLIKELY(NULL == notify))
+ return FALSE;
+#if defined( HAVE_EVENTFD )
+ if (PGM_UNLIKELY(-1 == notify->eventfd))
+ return FALSE;
+#elif !defined( _WIN32 )
+ if (PGM_UNLIKELY(-1 == notify->pipefd[0] || -1 == notify->pipefd[1]))
+ return FALSE;
+#else
+ if (PGM_UNLIKELY(INVALID_SOCKET == notify->s[0] || INVALID_SOCKET == notify->s[1]))
+ return FALSE;
+#endif /* _WIN32 */
+ return TRUE;
+}
+
+static inline
+int
+pgm_notify_init (
+ pgm_notify_t* notify
+ )
+{
+#if defined( HAVE_EVENTFD )
+ pgm_assert (NULL != notify);
+ notify->eventfd = -1;
+ int retval = eventfd (0, 0);
+ if (-1 == retval)
+ return retval;
+ notify->eventfd = retval;
+ const int fd_flags = fcntl (notify->eventfd, F_GETFL);
+ if (-1 != fd_flags)
+ retval = fcntl (notify->eventfd, F_SETFL, fd_flags | O_NONBLOCK);
+ return 0;
+#elif !defined( _WIN32 )
+ pgm_assert (NULL != notify);
+ notify->pipefd[0] = notify->pipefd[1] = -1;
+ int retval = pipe (notify->pipefd);
+ pgm_assert (0 == retval);
+/* set non-blocking */
+/* write-end */
+ int fd_flags = fcntl (notify->pipefd[1], F_GETFL);
+ if (fd_flags != -1)
+ retval = fcntl (notify->pipefd[1], F_SETFL, fd_flags | O_NONBLOCK);
+ pgm_assert (notify->pipefd[1]);
+/* read-end */
+ fd_flags = fcntl (notify->pipefd[0], F_GETFL);
+ if (fd_flags != -1)
+ retval = fcntl (notify->pipefd[0], F_SETFL, fd_flags | O_NONBLOCK);
+ pgm_assert (notify->pipefd[0]);
+ return retval;
+#else
+/* use loopback sockets to simulate a pipe suitable for win32/select() */
+ struct sockaddr_in addr;
+ SOCKET listener;
+ int sockerr;
+ int addrlen = sizeof (addr);
+ unsigned long one = 1;
+
+ pgm_assert (NULL != notify);
+ notify->s[0] = notify->s[1] = INVALID_SOCKET;
+
+ listener = socket (AF_INET, SOCK_STREAM, 0);
+ pgm_assert (listener != INVALID_SOCKET);
+
+ memset (&addr, 0, sizeof (addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
+ pgm_assert (addr.sin_addr.s_addr != INADDR_NONE);
+
+ sockerr = bind (listener, (const struct sockaddr*)&addr, sizeof (addr));
+ pgm_assert (sockerr != SOCKET_ERROR);
+
+ sockerr = getsockname (listener, (struct sockaddr*)&addr, &addrlen);
+ pgm_assert (sockerr != SOCKET_ERROR);
+
+// Listen for incoming connections.
+ sockerr = listen (listener, 1);
+ pgm_assert (sockerr != SOCKET_ERROR);
+
+// Create the socket.
+ notify->s[1] = WSASocket (AF_INET, SOCK_STREAM, 0, NULL, 0, 0);
+ pgm_assert (notify->s[1] != INVALID_SOCKET);
+
+// Connect to the remote peer.
+ sockerr = connect (notify->s[1], (struct sockaddr*)&addr, addrlen);
+/* Failure may be delayed from bind and may be due to socket exhaustion as explained
+ * in MSDN(bind Function).
+ */
+ pgm_assert (sockerr != SOCKET_ERROR);
+
+// Accept connection.
+ notify->s[0] = accept (listener, NULL, NULL);
+ pgm_assert (notify->s[0] != INVALID_SOCKET);
+
+// Set read-end to non-blocking mode
+ sockerr = ioctlsocket (notify->s[0], FIONBIO, &one);
+ pgm_assert (sockerr != SOCKET_ERROR);
+
+// We don't need the listening socket anymore. Close it.
+ sockerr = closesocket (listener);
+ pgm_assert (sockerr != SOCKET_ERROR);
+
+ return 0;
+#endif /* HAVE_EVENTFD */
+}
+
+static inline
+int
+pgm_notify_destroy (
+ pgm_notify_t* notify
+ )
+{
+ pgm_assert (NULL != notify);
+
+#if defined( HAVE_EVENTFD )
+ if (-1 != notify->eventfd) {
+ close (notify->eventfd);
+ notify->eventfd = -1;
+ }
+#elif !defined( _WIN32 )
+ if (-1 != notify->pipefd[0]) {
+ close (notify->pipefd[0]);
+ notify->pipefd[0] = -1;
+ }
+ if (-1 != notify->pipefd[1]) {
+ close (notify->pipefd[1]);
+ notify->pipefd[1] = -1;
+ }
+#else
+ if (INVALID_SOCKET != notify->s[0]) {
+ closesocket (notify->s[0]);
+ notify->s[0] = INVALID_SOCKET;
+ }
+ if (INVALID_SOCKET != notify->s[1]) {
+ closesocket (notify->s[1]);
+ notify->s[1] = INVALID_SOCKET;
+ }
+#endif /* HAVE_EVENTFD */
+ return 0;
+}
+
+static inline
+int
+pgm_notify_send (
+ pgm_notify_t* notify
+ )
+{
+#if defined( HAVE_EVENTFD )
+ uint64_t u = 1;
+ pgm_assert (NULL != notify);
+ pgm_assert (-1 != notify->eventfd);
+ ssize_t s = write (notify->eventfd, &u, sizeof(u));
+ return (s == sizeof(u));
+#elif !defined( _WIN32 )
+ const char one = '1';
+ pgm_assert (NULL != notify);
+ pgm_assert (-1 != notify->pipefd[1]);
+ return (1 == write (notify->pipefd[1], &one, sizeof(one)));
+#else
+ const char one = '1';
+ pgm_assert (NULL != notify);
+ pgm_assert (INVALID_SOCKET != notify->s[1]);
+ return (1 == send (notify->s[1], &one, sizeof(one), 0));
+#endif /* HAVE_EVENTFD */
+}
+
+static inline
+int
+pgm_notify_read (
+ pgm_notify_t* notify
+ )
+{
+#if defined( HAVE_EVENTFD )
+ uint64_t u;
+ pgm_assert (NULL != notify);
+ pgm_assert (-1 != notify->eventfd);
+ return (sizeof(u) == read (notify->eventfd, &u, sizeof(u)));
+#elif !defined( _WIN32 )
+ char buf;
+ pgm_assert (NULL != notify);
+ pgm_assert (-1 != notify->pipefd[0]);
+ return (sizeof(buf) == read (notify->pipefd[0], &buf, sizeof(buf)));
+#else
+ char buf;
+ pgm_assert (NULL != notify);
+ pgm_assert (INVALID_SOCKET != notify->s[0]);
+ return (sizeof(buf) == recv (notify->s[0], &buf, sizeof(buf), 0));
+#endif /* HAVE_EVENTFD */
+}
+
+static inline
+void
+pgm_notify_clear (
+ pgm_notify_t* notify
+ )
+{
+#if defined( HAVE_EVENTFD )
+ uint64_t u;
+ pgm_assert (NULL != notify);
+ pgm_assert (-1 != notify->eventfd);
+ while (sizeof(u) == read (notify->eventfd, &u, sizeof(u)));
+#elif !defined( _WIN32 )
+ char buf;
+ pgm_assert (NULL != notify);
+ pgm_assert (-1 != notify->pipefd[0]);
+ while (sizeof(buf) == read (notify->pipefd[0], &buf, sizeof(buf)));
+#else
+ char buf;
+ pgm_assert (NULL != notify);
+ pgm_assert (INVALID_SOCKET != notify->s[0]);
+ while (sizeof(buf) == recv (notify->s[0], &buf, sizeof(buf), 0));
+#endif /* HAVE_EVENTFD */
+}
+
+static inline
+SOCKET
+pgm_notify_get_socket (
+ pgm_notify_t* notify
+ )
+{
+ pgm_assert (NULL != notify);
+
+#if defined( HAVE_EVENTFD )
+ pgm_assert (-1 != notify->eventfd);
+ return notify->eventfd;
+#elif !defined( _WIN32 )
+ pgm_assert (-1 != notify->pipefd[0]);
+ return notify->pipefd[0];
+#else
+ pgm_assert (INVALID_SOCKET != notify->s[0]);
+ return notify->s[0];
+#endif /* HAVE_EVENTFD */
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_NOTIFY_H__ */
diff --git a/src/pgm/impl/packet_parse.h b/src/pgm/impl/packet_parse.h
new file mode 100644
index 0000000..c05d838
--- /dev/null
+++ b/src/pgm/impl/packet_parse.h
@@ -0,0 +1,48 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * PGM packet formats, RFC 3208.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_PACKET_PARSE_H__
+#define __PGM_IMPL_PACKET_PARSE_H__
+
+#ifndef _WIN32
+# include <sys/socket.h>
+#endif
+#include <impl/framework.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL bool pgm_parse_raw (struct pgm_sk_buff_t*const restrict, struct sockaddr*const restrict, pgm_error_t**restrict);
+PGM_GNUC_INTERNAL bool pgm_parse_udp_encap (struct pgm_sk_buff_t*const restrict, pgm_error_t**restrict);
+PGM_GNUC_INTERNAL bool pgm_verify_spm (const struct pgm_sk_buff_t* const);
+PGM_GNUC_INTERNAL bool pgm_verify_spmr (const struct pgm_sk_buff_t* const);
+PGM_GNUC_INTERNAL bool pgm_verify_nak (const struct pgm_sk_buff_t* const);
+PGM_GNUC_INTERNAL bool pgm_verify_nnak (const struct pgm_sk_buff_t* const);
+PGM_GNUC_INTERNAL bool pgm_verify_ncf (const struct pgm_sk_buff_t* const);
+PGM_GNUC_INTERNAL bool pgm_verify_poll (const struct pgm_sk_buff_t* const);
+PGM_GNUC_INTERNAL bool pgm_verify_polr (const struct pgm_sk_buff_t* const);
+PGM_GNUC_INTERNAL bool pgm_verify_ack (const struct pgm_sk_buff_t* const);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_PACKET_PARSE_H__ */
diff --git a/src/pgm/impl/packet_test.h b/src/pgm/impl/packet_test.h
new file mode 100644
index 0000000..56d20aa
--- /dev/null
+++ b/src/pgm/impl/packet_test.h
@@ -0,0 +1,43 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * PGM packet formats, RFC 3208.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_PACKET_TEST_H__
+#define __PGM_IMPL_PACKET_TEST_H__
+
+#ifndef _WIN32
+# include <netinet/in.h>
+#endif
+#include <impl/framework.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL bool pgm_print_packet (const void*, size_t);
+PGM_GNUC_INTERNAL const char* pgm_type_string (uint8_t) PGM_GNUC_WARN_UNUSED_RESULT PGM_GNUC_CONST;
+PGM_GNUC_INTERNAL const char* pgm_udpport_string (in_port_t) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL const char* pgm_gethostbyaddr (const struct in_addr*) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_ipopt_print (const void*, size_t);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_PACKET_TEST_H__ */
diff --git a/src/pgm/impl/pgmMIB.h b/src/pgm/impl/pgmMIB.h
new file mode 100644
index 0000000..43fb9d5
--- /dev/null
+++ b/src/pgm/impl/pgmMIB.h
@@ -0,0 +1,31 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ * : mib2c.notify.conf,v 5.3 2004/04/15 12:29:19 dts12 Exp $
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_MIB_H__
+#define __PGM_IMPL_MIB_H__
+
+#include <impl/framework.h>
+
+PGM_BEGIN_DECLS
+
+/* function declarations */
+PGM_GNUC_INTERNAL bool pgm_mib_init (pgm_error_t**);
+
+PGM_GNUC_INTERNAL int send_pgmStart_trap(void);
+PGM_GNUC_INTERNAL int send_pgmStop_trap(void);
+PGM_GNUC_INTERNAL int send_pgmNewSourceTrap_trap(void);
+PGM_GNUC_INTERNAL int send_pgmClosedSourceTrap_trap(void);
+PGM_GNUC_INTERNAL int send_pgmNewReceiverTrap_trap(void);
+PGM_GNUC_INTERNAL int send_pgmClosedReceiverTrap_trap(void);
+PGM_GNUC_INTERNAL int send_pgmNakFailuresTrap_trap(void);
+PGM_GNUC_INTERNAL int send_pgmNewDlrSourceTrap_trap(void);
+PGM_GNUC_INTERNAL int send_pgmClosedDlrSourceTrap_trap(void);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_MIB_H__ */
diff --git a/src/pgm/impl/pgmMIB_columns.h b/src/pgm/impl/pgmMIB_columns.h
new file mode 100644
index 0000000..5113a04
--- /dev/null
+++ b/src/pgm/impl/pgmMIB_columns.h
@@ -0,0 +1,376 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ * : mib2c.column_defines.conf,v 5.1 2002/05/08 05:42:47 hardaker Exp $
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef PGMMIB_COLUMNS_H
+#define PGMMIB_COLUMNS_H
+
+/* column number definitions for table pgmNeIfConfigTable */
+ #define COLUMN_PGMNEIFCONFIGINDEX 1
+ #define COLUMN_PGMNEIFPGMENABLE 2
+ #define COLUMN_PGMNEIFNAKRPTINTERVAL 3
+ #define COLUMN_PGMNEIFNAKRPTRATE 4
+ #define COLUMN_PGMNEIFNAKRDATAINTERVAL 5
+ #define COLUMN_PGMNEIFNAKELIMINATEINTERVAL 6
+
+/* column number definitions for table pgmNeIfPerformanceTable */
+ #define COLUMN_PGMNEIFPERFORMANCEINDEX 1
+ #define COLUMN_PGMNEIFREXMITSTATES 2
+ #define COLUMN_PGMNEIFREXMITTIMEDOUT 3
+ #define COLUMN_PGMNEIFINSPMS 4
+ #define COLUMN_PGMNEIFOUTSPMS 5
+ #define COLUMN_PGMNEIFINPARITYSPMS 6
+ #define COLUMN_PGMNEIFOUTPARITYSPMS 7
+ #define COLUMN_PGMNEIFINRDATA 8
+ #define COLUMN_PGMNEIFOUTRDATA 9
+ #define COLUMN_PGMNEIFINPARITYRDATA 10
+ #define COLUMN_PGMNEIFOUTPARITYRDATA 11
+ #define COLUMN_PGMNEIFINRDATANOSESSIONERRORS 12
+ #define COLUMN_PGMNEIFUNIQUENAKS 13
+ #define COLUMN_PGMNEIFINNAKS 14
+ #define COLUMN_PGMNEIFOUTNAKS 15
+ #define COLUMN_PGMNEIFUNIQUEPARITYNAKS 16
+ #define COLUMN_PGMNEIFINPARITYNAKS 17
+ #define COLUMN_PGMNEIFOUTPARITYNAKS 18
+ #define COLUMN_PGMNEIFINNAKNOSESSIONERRORS 19
+ #define COLUMN_PGMNEIFINNAKSEQERRORS 20
+ #define COLUMN_PGMNEIFINPARITYNAKTGERRORS 21
+ #define COLUMN_PGMNEIFINNNAKS 22
+ #define COLUMN_PGMNEIFOUTNNAKS 23
+ #define COLUMN_PGMNEIFINPARITYNNAKS 24
+ #define COLUMN_PGMNEIFOUTPARITYNNAKS 25
+ #define COLUMN_PGMNEIFINNNAKNOSESSIONERRORS 26
+ #define COLUMN_PGMNEIFINNCFS 27
+ #define COLUMN_PGMNEIFOUTNCFS 28
+ #define COLUMN_PGMNEIFINPARITYNCFS 29
+ #define COLUMN_PGMNEIFOUTPARITYNCFS 30
+ #define COLUMN_PGMNEIFINNCFNOSESSIONERRORS 31
+ #define COLUMN_PGMNEIFINREDIRECTNCFS 32
+ #define COLUMN_PGMNEIFMALFORMED 33
+ #define COLUMN_PGMNEIFSPMFROMSOURCE 34
+ #define COLUMN_PGMNEIFSPMBADSQN 35
+ #define COLUMN_PGMNEIFSPMERROR 36
+ #define COLUMN_PGMNEIFPOLLRANDOMIGNORE 37
+ #define COLUMN_PGMNEIFPOLLTSISTATEERROR 38
+ #define COLUMN_PGMNEIFPOLLPARENTERROR 39
+ #define COLUMN_PGMNEIFPOLLTYPEERROR 40
+ #define COLUMN_PGMNEIFPOLLERROR 41
+ #define COLUMN_PGMNEIFPOLLSUCCESS 42
+ #define COLUMN_PGMNEIFPOLLORIGINATED 43
+ #define COLUMN_PGMNEIFPOLRNOSTATE 44
+ #define COLUMN_PGMNEIFPOLRERROR 45
+ #define COLUMN_PGMNEIFPOLRPARITYERROR 46
+ #define COLUMN_PGMNEIFPOLRSUCCESS 47
+ #define COLUMN_PGMNEIFPOLRORIGINATED 48
+ #define COLUMN_PGMNEIFNCFERROR 49
+ #define COLUMN_PGMNEIFNCFPARITYERROR 50
+ #define COLUMN_PGMNEIFNCFPARTIALPARITY 51
+ #define COLUMN_PGMNEIFNCFRECEIVED 52
+ #define COLUMN_PGMNEIFNCFANTICIPATED 53
+ #define COLUMN_PGMNEIFNCFREDIRECTING 54
+ #define COLUMN_PGMNEIFNAKELIMINATED 55
+ #define COLUMN_PGMNEIFNAKERROR 56
+ #define COLUMN_PGMNEIFNAKPARITYERROR 57
+ #define COLUMN_PGMNEIFNNAKELIMINATED 58
+ #define COLUMN_PGMNEIFNNAKERROR 59
+ #define COLUMN_PGMNEIFNNAKPARITYERROR 60
+ #define COLUMN_PGMNEIFNNAKCONGESTIONREPORTS 61
+ #define COLUMN_PGMNEIFNAKRETRYEXPIRED 62
+ #define COLUMN_PGMNEIFNAKRETRYEXPIREDDLR 63
+ #define COLUMN_PGMNEIFNAKFORWARDEDDLR 64
+ #define COLUMN_PGMNEIFNAKRETRANSMITTED 65
+ #define COLUMN_PGMNEIFRDATAELIMINATEDOIF 66
+ #define COLUMN_PGMNEIFRDATAELIMINATEDSQN 67
+ #define COLUMN_PGMNEIFINRDATAFRAGMENTS 68
+ #define COLUMN_PGMNEIFRDATAFRAGMENTSNOSESSIONERRORS 69
+ #define COLUMN_PGMNEIFRDATAFRAGMENTSELIMINATEDOIF 70
+ #define COLUMN_PGMNEIFRDATAFRAGMENTSELIMINATEDSQN 71
+ #define COLUMN_PGMNEIFOUTRDATAFRAGMENTS 72
+
+/* column number definitions for table pgmNeTsiTable */
+ #define COLUMN_PGMNETSIGLOBALID 1
+ #define COLUMN_PGMNETSIDATASOURCEPORT 2
+ #define COLUMN_PGMNETSISTATEBITS 3
+ #define COLUMN_PGMNETSIDATADESTINATIONPORT 4
+ #define COLUMN_PGMNETSISOURCEADDRESS 5
+ #define COLUMN_PGMNETSIGROUPADDRESS 6
+ #define COLUMN_PGMNETSIUPSTREAMADDRESS 7
+ #define COLUMN_PGMNETSIUPSTREAMIFINDEX 8
+ #define COLUMN_PGMNETSIDLRADDRESS 9
+
+/* column number definitions for table pgmNeTsiPerformanceTable */
+ #define COLUMN_PGMNETSIPERFORMANCEGLOBALID 1
+ #define COLUMN_PGMNETSIPERFORMANCEDATASOURCEPORT 2
+ #define COLUMN_PGMNETSISESSIONTRAILEDGESEQ 3
+ #define COLUMN_PGMNETSISESSIONINCRSEQ 4
+ #define COLUMN_PGMNETSILEADEDGESEQ 5
+ #define COLUMN_PGMNETSIINSPMS 6
+ #define COLUMN_PGMNETSIOUTSPMS 7
+ #define COLUMN_PGMNETSIINPARITYSPMS 8
+ #define COLUMN_PGMNETSIOUTPARITYSPMS 9
+ #define COLUMN_PGMNETSITOTALREXMITSTATES 10
+ #define COLUMN_PGMNETSITOTALREXMITTIMEDOUT 11
+ #define COLUMN_PGMNETSIINRDATA 12
+ #define COLUMN_PGMNETSIOUTRDATA 13
+ #define COLUMN_PGMNETSIINPARITYRDATA 14
+ #define COLUMN_PGMNETSIOUTPARITYRDATA 15
+ #define COLUMN_PGMNETSIINRDATANOSTATEERRORS 16
+ #define COLUMN_PGMNETSIUNIQUENAKS 17
+ #define COLUMN_PGMNETSIINNAKS 18
+ #define COLUMN_PGMNETSIOUTNAKS 19
+ #define COLUMN_PGMNETSIUNIQUEPARITYNAKS 20
+ #define COLUMN_PGMNETSIINPARITYNAKS 21
+ #define COLUMN_PGMNETSIOUTPARITYNAKS 22
+ #define COLUMN_PGMNETSIINNAKSEQERRORS 23
+ #define COLUMN_PGMNETSIINNNAKS 24
+ #define COLUMN_PGMNETSIOUTNNAKS 25
+ #define COLUMN_PGMNETSIINPARITYNNAKS 26
+ #define COLUMN_PGMNETSIOUTPARITYNNAKS 27
+ #define COLUMN_PGMNETSIINNCFS 28
+ #define COLUMN_PGMNETSIOUTNCFS 29
+ #define COLUMN_PGMNETSIINPARITYNCFS 30
+ #define COLUMN_PGMNETSIOUTPARITYNCFS 31
+ #define COLUMN_PGMNETSISPMSEQUENCENUMBER 32
+ #define COLUMN_PGMNETSITRANSMISSIONGROUPSIZE 33
+ #define COLUMN_PGMNETSITIMEOUT 34
+ #define COLUMN_PGMNETSILASTTTL 35
+ #define COLUMN_PGMNETSILINKLOSSRATE 36
+ #define COLUMN_PGMNETSIPATHLOSSRATE 37
+ #define COLUMN_PGMNETSIRECEIVERLOSSRATE 38
+ #define COLUMN_PGMNETSICONGESTIONREPORTLEAD 39
+ #define COLUMN_PGMNETSICONGESTIONREPORTWORSTRECEIVER 40
+
+/* column number definitions for table pgmNeTsiRtxTable */
+ #define COLUMN_PGMNETSIRTXSEQUENCENUMBER 1
+ #define COLUMN_PGMNETSIRTXSEQUENCENUMBERTYPE 2
+ #define COLUMN_PGMNETSIRTXREQPARITYTGCOUNT 4
+ #define COLUMN_PGMNETSIRTXTIMEOUT 5
+ #define COLUMN_PGMNETSIRTXSTATEBITS 6
+
+/* column number definitions for table pgmNeTsiRtxIfTable */
+ #define COLUMN_PGMNETSIRTXIFINDEX 1
+ #define COLUMN_PGMNETSIRTXIFPACKETCOUNT 2
+
+/* column number definitions for table pgmNeTsiPolrTable */
+ #define COLUMN_PGMNETSIPOLRSOURCE 1
+ #define COLUMN_PGMNETSIPOLRSEQUENCENUMBER 2
+
+/* column number definitions for table pgmNeTsiPollTable */
+ #define COLUMN_PGMNETSIPOLLTYPE 1
+ #define COLUMN_PGMNETSIPOLLSEQUENCE 2
+ #define COLUMN_PGMNETSIPOLLCHILDBACKOFF 3
+ #define COLUMN_PGMNETSIPOLLMASK 4
+ #define COLUMN_PGMNETSIPOLLPERIOD 5
+ #define COLUMN_PGMNETSIPOLLCOUNT 6
+ #define COLUMN_PGMNETSIPOLLTIMEOUT 7
+
+/* column number definitions for table pgmSourceTable */
+ #define COLUMN_PGMSOURCEGLOBALID 1
+ #define COLUMN_PGMSOURCESOURCEPORT 2
+ #define COLUMN_PGMSOURCESOURCEADDRESS 3
+ #define COLUMN_PGMSOURCEGROUPADDRESS 4
+ #define COLUMN_PGMSOURCEDESTPORT 5
+ #define COLUMN_PGMSOURCESOURCEGSI 6
+ #define COLUMN_PGMSOURCESOURCEPORTNUMBER 7
+
+/* column number definitions for table pgmSourceConfigTable */
+ #define COLUMN_PGMSOURCECONFIGGLOBALID 1
+ #define COLUMN_PGMSOURCECONFIGSOURCEPORT 2
+ #define COLUMN_PGMSOURCETTL 3
+ #define COLUMN_PGMSOURCEADVMODE 4
+ #define COLUMN_PGMSOURCELATEJOIN 5
+ #define COLUMN_PGMSOURCETXWMAXRTE 6
+ #define COLUMN_PGMSOURCETXWSECS 7
+ #define COLUMN_PGMSOURCETXWADVSECS 8
+ #define COLUMN_PGMSOURCEADVIVL 9
+ #define COLUMN_PGMSOURCESPMIVL 10
+ #define COLUMN_PGMSOURCESPMHEARTBEATIVLMIN 11
+ #define COLUMN_PGMSOURCESPMHEARTBEATIVLMAX 12
+ #define COLUMN_PGMSOURCERDATABACKOFFIVL 13
+ #define COLUMN_PGMSOURCEFEC 14
+ #define COLUMN_PGMSOURCEFECTRANSMISSIONGRPSIZE 15
+ #define COLUMN_PGMSOURCEFECPROACTIVEPARITYSIZE 16
+ #define COLUMN_PGMSOURCESPMPATHADDRESS 17
+
+/* column number definitions for table pgmSourcePerformanceTable */
+ #define COLUMN_PGMSOURCEPERFORMANCEGLOBALID 1
+ #define COLUMN_PGMSOURCEPERFORMANCESOURCEPORT 2
+ #define COLUMN_PGMSOURCEDATABYTESSENT 3
+ #define COLUMN_PGMSOURCEDATAMSGSSENT 4
+ #define COLUMN_PGMSOURCEBYTESBUFFERED 5
+ #define COLUMN_PGMSOURCEMSGSBUFFERED 6
+ #define COLUMN_PGMSOURCEBYTESRETRANSMITTED 7
+ #define COLUMN_PGMSOURCEMSGSRETRANSMITTED 8
+ #define COLUMN_PGMSOURCEBYTESSENT 9
+ #define COLUMN_PGMSOURCERAWNAKSRECEIVED 10
+ #define COLUMN_PGMSOURCENAKSIGNORED 11
+ #define COLUMN_PGMSOURCECKSUMERRORS 12
+ #define COLUMN_PGMSOURCEMALFORMEDNAKS 13
+ #define COLUMN_PGMSOURCEPACKETSDISCARDED 14
+ #define COLUMN_PGMSOURCENAKSRCVD 15
+ #define COLUMN_PGMSOURCEPARITYBYTESRETRANSMITTED 16
+ #define COLUMN_PGMSOURCESELECTIVEBYTESRETRANSMITED 17
+ #define COLUMN_PGMSOURCEPARITYMSGSRETRANSMITTED 18
+ #define COLUMN_PGMSOURCESELECTIVEMSGSRETRANSMITTED 19
+ #define COLUMN_PGMSOURCEBYTESADMIT 20
+ #define COLUMN_PGMSOURCEMSGSADMIT 21
+ #define COLUMN_PGMSOURCEPARITYNAKPACKETSRECEIVED 22
+ #define COLUMN_PGMSOURCESELECTIVENAKPACKETSRECEIVED 23
+ #define COLUMN_PGMSOURCEPARITYNAKSRECEIVED 24
+ #define COLUMN_PGMSOURCESELECTIVENAKSRECEIVED 25
+ #define COLUMN_PGMSOURCEPARITYNAKSIGNORED 26
+ #define COLUMN_PGMSOURCESELECTIVENAKSIGNORED 27
+ #define COLUMN_PGMSOURCEACKERRORS 28
+ #define COLUMN_PGMSOURCEPGMCCACKER 29
+ #define COLUMN_PGMSOURCETRANSMISSIONCURRENTRATE 30
+ #define COLUMN_PGMSOURCEACKPACKETSRECEIVED 31
+ #define COLUMN_PGMSOURCENNAKPACKETSRECEIVED 32
+ #define COLUMN_PGMSOURCEPARITYNNAKPACKETSRECEIVED 33
+ #define COLUMN_PGMSOURCESELECTIVENNAKPACKETSRECEIVED 34
+ #define COLUMN_PGMSOURCENNAKSRECEIVED 35
+ #define COLUMN_PGMSOURCEPARITYNNAKSRECEIVED 36
+ #define COLUMN_PGMSOURCESELECTIVENNAKSRECEIVED 37
+ #define COLUMN_PGMSOURCENNAKERRORS 38
+
+/* column number definitions for table pgmReceiverTable */
+ #define COLUMN_PGMRECEIVERGLOBALID 1
+ #define COLUMN_PGMRECEIVERSOURCEPORT 2
+ #define COLUMN_PGMRECEIVERINSTANCE 3
+ #define COLUMN_PGMRECEIVERGROUPADDRESS 4
+ #define COLUMN_PGMRECEIVERDESTPORT 5
+ #define COLUMN_PGMRECEIVERSOURCEADDRESS 6
+ #define COLUMN_PGMRECEIVERLASTHOP 7
+ #define COLUMN_PGMRECEIVERSOURCEGSI 8
+ #define COLUMN_PGMRECEIVERSOURCEPORTNUMBER 9
+ #define COLUMN_PGMRECEIVERUNIQUEINSTANCE 10
+
+/* column number definitions for table pgmReceiverConfigTable */
+ #define COLUMN_PGMRECEIVERCONFIGGLOBALID 1
+ #define COLUMN_PGMRECEIVERCONFIGSOURCEPORT 2
+ #define COLUMN_PGMRECEIVERCONFIGINSTANCE 3
+ #define COLUMN_PGMRECEIVERNAKBACKOFFIVL 4
+ #define COLUMN_PGMRECEIVERNAKREPEATIVL 5
+ #define COLUMN_PGMRECEIVERNAKNCFRETRIES 6
+ #define COLUMN_PGMRECEIVERNAKRDATAIVL 7
+ #define COLUMN_PGMRECEIVERNAKDATARETRIES 8
+ #define COLUMN_PGMRECEIVERSENDNAKS 9
+ #define COLUMN_PGMRECEIVERLATEJOIN 10
+ #define COLUMN_PGMRECEIVERNAKTTL 11
+ #define COLUMN_PGMRECEIVERDELIVERYORDER 12
+ #define COLUMN_PGMRECEIVERMCASTNAKS 13
+ #define COLUMN_PGMRECEIVERNAKFAILURETHRESHOLDTIMER 14
+ #define COLUMN_PGMRECEIVERNAKFAILURETHRESHOLD 15
+
+/* column number definitions for table pgmReceiverPerformanceTable */
+ #define COLUMN_PGMRECEIVERPERFORMANCEGLOBALID 1
+ #define COLUMN_PGMRECEIVERPERFORMANCESOURCEPORT 2
+ #define COLUMN_PGMRECEIVERPERFORMANCEINSTANCE 3
+ #define COLUMN_PGMRECEIVERDATABYTESRECEIVED 4
+ #define COLUMN_PGMRECEIVERDATAMSGSRECEIVED 5
+ #define COLUMN_PGMRECEIVERNAKSSENT 6
+ #define COLUMN_PGMRECEIVERNAKSRETRANSMITTED 7
+ #define COLUMN_PGMRECEIVERNAKFAILURES 8
+ #define COLUMN_PGMRECEIVERBYTESRECEIVED 9
+ #define COLUMN_PGMRECEIVERNAKSSUPPRESSED 10
+ #define COLUMN_PGMRECEIVERCKSUMERRORS 11
+ #define COLUMN_PGMRECEIVERMALFORMEDSPMS 12
+ #define COLUMN_PGMRECEIVERMALFORMEDODATA 13
+ #define COLUMN_PGMRECEIVERMALFORMEDRDATA 14
+ #define COLUMN_PGMRECEIVERMALFORMEDNCFS 15
+ #define COLUMN_PGMRECEIVERPACKETSDISCARDED 16
+ #define COLUMN_PGMRECEIVERLOSSES 17
+ #define COLUMN_PGMRECEIVERBYTESDELIVEREDTOAPP 18
+ #define COLUMN_PGMRECEIVERMSGSDELIVEREDTOAPP 19
+ #define COLUMN_PGMRECEIVERDUPSPMS 20
+ #define COLUMN_PGMRECEIVERDUPDATAS 21
+ #define COLUMN_PGMRECEIVERDUPPARITIES 22
+ #define COLUMN_PGMRECEIVERNAKPACKETSSENT 23
+ #define COLUMN_PGMRECEIVERPARITYNAKPACKETSSENT 24
+ #define COLUMN_PGMRECEIVERSELECTIVENAKPACKETSSENT 25
+ #define COLUMN_PGMRECEIVERPARITYNAKSSENT 26
+ #define COLUMN_PGMRECEIVERSELECTIVENAKSSENT 27
+ #define COLUMN_PGMRECEIVERPARITYNAKSRETRANSMITTED 28
+ #define COLUMN_PGMRECEIVERSELECTIVENAKSRETRANSMITTED 29
+ #define COLUMN_PGMRECEIVERNAKSFAILED 30
+ #define COLUMN_PGMRECEIVERPARITYNAKSFAILED 31
+ #define COLUMN_PGMRECEIVERSELECTIVENAKSFAILED 32
+ #define COLUMN_PGMRECEIVERNAKSFAILEDRXWADVANCED 33
+ #define COLUMN_PGMRECEIVERNAKSFALEDNCFRETRIESEXCEEDED 34
+ #define COLUMN_PGMRECEIVERNAKSFAILEDDATARETRIESEXCEEDED 35
+ #define COLUMN_PGMRECEIVERNAKSFAILEDGENEXPIRED 36
+ #define COLUMN_PGMRECEIVERNAKFAILURESDELIVERED 37
+ #define COLUMN_PGMRECEIVERPARITYNAKSSUPPRESSED 38
+ #define COLUMN_PGMRECEIVERSELECTIVENAKSSUPPRESSED 39
+ #define COLUMN_PGMRECEIVERNAKERRORS 40
+ #define COLUMN_PGMRECEIVEROUTSTANDINGPARITYNAKS 41
+ #define COLUMN_PGMRECEIVEROUTSTANDINGSELECTIVENAKS 42
+ #define COLUMN_PGMRECEIVERLASTACTIVITY 43
+ #define COLUMN_PGMRECEIVERNAKSVCTIMEMIN 44
+ #define COLUMN_PGMRECEIVERNAKSVCTIMEMEAN 45
+ #define COLUMN_PGMRECEIVERNAKSVCTIMEMAX 46
+ #define COLUMN_PGMRECEIVERNAKFAILTIMEMIN 47
+ #define COLUMN_PGMRECEIVERNAKFAILTIMEMEAN 48
+ #define COLUMN_PGMRECEIVERNAKFAILTIMEMAX 49
+ #define COLUMN_PGMRECEIVERNAKTRANSMITMIN 50
+ #define COLUMN_PGMRECEIVERNAKTRANSMITMEAN 51
+ #define COLUMN_PGMRECEIVERNAKTRANSMITMAX 52
+ #define COLUMN_PGMRECEIVERACKSSENT 53
+ #define COLUMN_PGMRECEIVERRXWTRAIL 54
+ #define COLUMN_PGMRECEIVERRXWLEAD 55
+ #define COLUMN_PGMRECEIVERNAKFAILURESLASTINTERVAL 56
+ #define COLUMN_PGMRECEIVERLASTINTERVALNAKFAILURES 57
+
+/* column number definitions for table pgmDlrSourceTable */
+ #define COLUMN_PGMDLRSOURCEGLOBALID 1
+ #define COLUMN_PGMDLRSOURCESOURCEPORT 2
+ #define COLUMN_PGMDLRSOURCEGROUPADDRESS 3
+ #define COLUMN_PGMDLRSOURCESOURCEGSI 4
+ #define COLUMN_PGMDLRSOURCESOURCEPORTNUMBER 5
+
+/* column number definitions for table pgmDlrSourceConfigTable */
+ #define COLUMN_PGMDLRSOURCECONFIGGLOBALID 1
+ #define COLUMN_PGMDLRSOURCECONFIGSOURCEPORT 2
+ #define COLUMN_PGMDLRSOURCEGROUPTTL 3
+ #define COLUMN_PGMDLRSOURCERDATABACKOFFIVL 4
+
+/* column number definitions for table pgmDlrSourcePerformanceTable */
+ #define COLUMN_PGMDLRSOURCEPERFORMANCEGLOBALID 1
+ #define COLUMN_PGMDLRSOURCEPERFORMANCESOURCEPORT 2
+ #define COLUMN_PGMDLRSOURCERDATAMSGSSENT 3
+ #define COLUMN_PGMDLRSOURCERDATABYTESSENT 4
+ #define COLUMN_PGMDLRSOURCEBYTESSENT 5
+ #define COLUMN_PGMDLRSOURCENAKSRCVD 6
+ #define COLUMN_PGMDLRSOURCENAKSIGNORED 7
+ #define COLUMN_PGMDLRSOURCENAKERRORS 8
+ #define COLUMN_PGMDLRSOURCEDISCARDS 9
+ #define COLUMN_PGMDLRSOURCECKSUMERRORS 10
+ #define COLUMN_PGMDLRSOURCENNAKSSENT 11
+ #define COLUMN_PGMDLRSOURCEBYTESBUFFERED 12
+ #define COLUMN_PGMDLRSOURCEMSGSBUFFERED 13
+ #define COLUMN_PGMDLRSOURCEPARITYBYTESRETRANSMITTED 14
+ #define COLUMN_PGMDLRSOURCESELECTIVEBYTESRETRANSMITED 15
+ #define COLUMN_PGMDLRSOURCEPARITYMSGSRETRANSMITTED 16
+ #define COLUMN_PGMDLRSOURCESELECTIVEMSGSRETRANSMITTED 17
+ #define COLUMN_PGMDLRSOURCEBYTESADMIT 18
+ #define COLUMN_PGMDLRSOURCEMSGSADMIT 19
+ #define COLUMN_PGMDLRSOURCENAKPACKETSRECEIVED 20
+ #define COLUMN_PGMDLRSOURCEPARITYNAKPACKETSRECEIVED 21
+ #define COLUMN_PGMDLRSOURCESELECTIVENAKPACKETSRECEIVED 22
+ #define COLUMN_PGMDLRSOURCEPARITYNAKSRECEIVED 23
+ #define COLUMN_PGMDLRSOURCESELECTIVENAKSRECEIVED 24
+ #define COLUMN_PGMDLRSOURCEPARITYNAKSIGNORED 25
+ #define COLUMN_PGMDLRSOURCESELECTIVENAKSIGNORED 26
+ #define COLUMN_PGMDLRSOURCEACKERRORS 27
+ #define COLUMN_PGMDLRSOURCENNAKERRORS 28
+ #define COLUMN_PGMDLRSOURCEACKPACKETSRECEIVED 29
+ #define COLUMN_PGMDLRSOURCENNAKPACKETSRECEIVED 30
+ #define COLUMN_PGMDLRSOURCEPARITYNNAKPACKETSRECEIVED 31
+ #define COLUMN_PGMDLRSOURCESELECTIVENNAKPACKETSRECEIVED 32
+ #define COLUMN_PGMDLRSOURCENNAKSRECEIVED 33
+ #define COLUMN_PGMDLRSOURCEPARITYNNAKSRECEIVED 34
+ #define COLUMN_PGMDLRSOURCESELECTIVENNAKSRECEIVED 35
+#endif /* PGMMIB_COLUMNS_H */
diff --git a/src/pgm/impl/pgmMIB_enums.h b/src/pgm/impl/pgmMIB_enums.h
new file mode 100644
index 0000000..070613c
--- /dev/null
+++ b/src/pgm/impl/pgmMIB_enums.h
@@ -0,0 +1,68 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ * : mib2c.column_enums.conf,v 5.2 2003/02/22 04:09:25 hardaker Exp $
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef PGMMIB_ENUMS_H
+#define PGMMIB_ENUMS_H
+
+/* enums for column pgmNeIfPgmEnable */
+ #define PGMNEIFPGMENABLE_ENABLE 1
+ #define PGMNEIFPGMENABLE_DISABLE 2
+
+/* enums for column pgmNeTsiStateBits */
+ #define PGMNETSISTATEBITS_INITIALISING 0
+ #define PGMNETSISTATEBITS_SPMSQNSTATEVALID 1
+ #define PGMNETSISTATEBITS_DLRCANPROVIDEPARITY 2
+
+/* enums for column pgmNeTsiRtxSequenceNumberType */
+ #define PGMNETSIRTXSEQUENCENUMBERTYPE_SELECTIVE 1
+ #define PGMNETSIRTXSEQUENCENUMBERTYPE_TG 2
+
+/* enums for column pgmNeTsiRtxStateBits */
+ #define PGMNETSIRTXSTATEBITS_INITIALISING 0
+ #define PGMNETSIRTXSTATEBITS_ELIMINATING 1
+ #define PGMNETSIRTXSTATEBITS_REDIRECTING 2
+ #define PGMNETSIRTXSTATEBITS_STATECREATEDBYNULLNAK 3
+ #define PGMNETSIRTXSTATEBITS_LISTNAKENTRY 4
+ #define PGMNETSIRTXSTATEBITS_PARITYSTATE 5
+
+/* enums for column pgmNeTsiPollType */
+ #define PGMNETSIPOLLTYPE_GENERAL 1
+ #define PGMNETSIPOLLTYPE_DLR 2
+
+/* enums for column pgmSourceAdvMode */
+ #define PGMSOURCEADVMODE_DATA 1
+ #define PGMSOURCEADVMODE_TIME 2
+ #define PGMSOURCEADVMODE_APPLCTRL 3
+ #define PGMSOURCEADVMODE_OTHER 4
+
+/* enums for column pgmSourceLateJoin */
+ #define PGMSOURCELATEJOIN_ENABLE 1
+ #define PGMSOURCELATEJOIN_DISABLE 2
+
+/* enums for column pgmSourceFEC */
+ #define PGMSOURCEFEC_DISABLED 1
+ #define PGMSOURCEFEC_ENABLEDFIXEDPACKETSIZE 2
+ #define PGMSOURCEFEC_ENABLEDVARIABLEPACKETSIZE 3
+
+/* enums for column pgmReceiverSendNaks */
+ #define PGMRECEIVERSENDNAKS_ENABLED 1
+ #define PGMRECEIVERSENDNAKS_DISABLED 2
+
+/* enums for column pgmReceiverLateJoin */
+ #define PGMRECEIVERLATEJOIN_ENABLED 1
+ #define PGMRECEIVERLATEJOIN_DISABLED 2
+
+/* enums for column pgmReceiverDeliveryOrder */
+ #define PGMRECEIVERDELIVERYORDER_UNORDERED 1
+ #define PGMRECEIVERDELIVERYORDER_ORDERED 2
+
+/* enums for column pgmReceiverMcastNaks */
+ #define PGMRECEIVERMCASTNAKS_ENABLED 1
+ #define PGMRECEIVERMCASTNAKS_DISABLED 2
+
+#endif /* PGMMIB_ENUMS_H */
diff --git a/src/pgm/impl/processor.h b/src/pgm/impl/processor.h
new file mode 100644
index 0000000..07f34b7
--- /dev/null
+++ b/src/pgm/impl/processor.h
@@ -0,0 +1,51 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * Processor macros for cross-platform, cross-compiler froyo.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_PROCESSOR_H__
+#define __PGM_IMPL_PROCESSOR_H__
+
+/* Memory prefetch */
+#if defined( __SUNPRO_C ) || defined( __SUNPRO_CC )
+# include <sun_prefetch.h>
+
+# define pgm_prefetch(addr) sun_prefetch_read_many ((void*)addr)
+# define pgm_prefetchw(addr) sun_prefetch_write_many (addr)
+
+#elif defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+
+# define pgm_prefetch(addr) __builtin_prefetch (addr, 0 /* read */, 0 /* no temporal locality */)
+# define pgm_prefetchw(addr) __builtin_prefetch (addr, 1 /* write */, 3 /* high temporal */)
+
+#else
+
+# define pgm_prefetch(addr) (addr)
+# define pgm_prefetchw(addr) (addr)
+
+#endif
+
+#endif /* __PGM_IMPL_PROCESSOR_H__ */
diff --git a/src/pgm/impl/queue.h b/src/pgm/impl/queue.h
new file mode 100644
index 0000000..58ca058
--- /dev/null
+++ b/src/pgm/impl/queue.h
@@ -0,0 +1,54 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable double-ended queue.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_QUEUE_H__
+#define __PGM_IMPL_QUEUE_H__
+
+typedef struct pgm_queue_t pgm_queue_t;
+
+#include <pgm/types.h>
+#include <pgm/list.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_queue_t
+{
+ pgm_list_t* head; /* head & tail equal on 1 element */
+ pgm_list_t* tail;
+ unsigned length;
+};
+
+PGM_GNUC_INTERNAL bool pgm_queue_is_empty (const pgm_queue_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_queue_push_head_link (pgm_queue_t*restrict, pgm_list_t*restrict);
+PGM_GNUC_INTERNAL pgm_list_t* pgm_queue_pop_tail_link (pgm_queue_t*);
+PGM_GNUC_INTERNAL pgm_list_t* pgm_queue_peek_tail_link (pgm_queue_t*) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_queue_unlink (pgm_queue_t*restrict, pgm_list_t*restrict);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_QUEUE_H__ */
diff --git a/src/pgm/impl/rand.h b/src/pgm/impl/rand.h
new file mode 100644
index 0000000..62962d0
--- /dev/null
+++ b/src/pgm/impl/rand.h
@@ -0,0 +1,53 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable weak pseudo-random generator.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_RAND_H__
+#define __PGM_IMPL_RAND_H__
+
+typedef struct pgm_rand_t pgm_rand_t;
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_rand_t {
+ uint32_t seed;
+};
+
+PGM_GNUC_INTERNAL void pgm_rand_create (pgm_rand_t*);
+PGM_GNUC_INTERNAL uint32_t pgm_rand_int (pgm_rand_t*);
+PGM_GNUC_INTERNAL int32_t pgm_rand_int_range (pgm_rand_t*, int32_t, int32_t);
+PGM_GNUC_INTERNAL uint32_t pgm_random_int (void);
+PGM_GNUC_INTERNAL int32_t pgm_random_int_range (int32_t, int32_t);
+
+PGM_GNUC_INTERNAL void pgm_rand_init (void);
+PGM_GNUC_INTERNAL void pgm_rand_shutdown (void);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_RAND_H__ */
diff --git a/src/pgm/impl/rate_control.h b/src/pgm/impl/rate_control.h
new file mode 100644
index 0000000..7b06c6f
--- /dev/null
+++ b/src/pgm/impl/rate_control.h
@@ -0,0 +1,59 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * Rate regulation.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_RATE_CONTROL_H__
+#define __PGM_IMPL_RATE_CONTROL_H__
+
+typedef struct pgm_rate_t pgm_rate_t;
+
+#include <pgm/types.h>
+#include <pgm/time.h>
+#include <impl/thread.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_rate_t {
+ ssize_t rate_per_sec;
+ ssize_t rate_per_msec;
+ size_t iphdr_len;
+
+ ssize_t rate_limit; /* signed for math */
+ pgm_time_t last_rate_check;
+ pgm_spinlock_t spinlock;
+};
+
+PGM_GNUC_INTERNAL void pgm_rate_create (pgm_rate_t*, const ssize_t, const size_t, const uint16_t);
+PGM_GNUC_INTERNAL void pgm_rate_destroy (pgm_rate_t*);
+PGM_GNUC_INTERNAL bool pgm_rate_check2 (pgm_rate_t*, pgm_rate_t*, const size_t, const bool);
+PGM_GNUC_INTERNAL bool pgm_rate_check (pgm_rate_t*, const size_t, const bool);
+PGM_GNUC_INTERNAL pgm_time_t pgm_rate_remaining2 (pgm_rate_t*, pgm_rate_t*, const size_t);
+PGM_GNUC_INTERNAL pgm_time_t pgm_rate_remaining (pgm_rate_t*, const size_t);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_RATE_CONTROL_H__ */
diff --git a/src/pgm/impl/receiver.h b/src/pgm/impl/receiver.h
new file mode 100644
index 0000000..a93c293
--- /dev/null
+++ b/src/pgm/impl/receiver.h
@@ -0,0 +1,144 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * PGM receiver socket.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_RECEIVER_H__
+#define __PGM_IMPL_RECEIVER_H__
+
+typedef struct pgm_peer_t pgm_peer_t;
+
+#ifndef _WIN32
+# include <sys/socket.h>
+#endif
+#include <impl/framework.h>
+#include <impl/rxw.h>
+
+PGM_BEGIN_DECLS
+
+/* Performance Counters */
+
+enum {
+ PGM_PC_RECEIVER_DATA_BYTES_RECEIVED,
+ PGM_PC_RECEIVER_DATA_MSGS_RECEIVED,
+ PGM_PC_RECEIVER_NAK_FAILURES,
+ PGM_PC_RECEIVER_BYTES_RECEIVED,
+/* PGM_PC_RECEIVER_CKSUM_ERRORS, */ /* inherently same as source */
+ PGM_PC_RECEIVER_MALFORMED_SPMS,
+ PGM_PC_RECEIVER_MALFORMED_ODATA,
+ PGM_PC_RECEIVER_MALFORMED_RDATA,
+ PGM_PC_RECEIVER_MALFORMED_NCFS,
+ PGM_PC_RECEIVER_PACKETS_DISCARDED,
+ PGM_PC_RECEIVER_LOSSES,
+/* PGM_PC_RECEIVER_BYTES_DELIVERED_TO_APP, */
+/* PGM_PC_RECEIVER_MSGS_DELIVERED_TO_APP, */
+ PGM_PC_RECEIVER_DUP_SPMS,
+ PGM_PC_RECEIVER_DUP_DATAS,
+ PGM_PC_RECEIVER_PARITY_NAK_PACKETS_SENT,
+ PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT,
+ PGM_PC_RECEIVER_PARITY_NAKS_SENT,
+ PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT,
+ PGM_PC_RECEIVER_PARITY_NAKS_RETRANSMITTED,
+ PGM_PC_RECEIVER_SELECTIVE_NAKS_RETRANSMITTED,
+ PGM_PC_RECEIVER_PARITY_NAKS_FAILED,
+ PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED,
+ PGM_PC_RECEIVER_NAKS_FAILED_RXW_ADVANCED,
+ PGM_PC_RECEIVER_NAKS_FAILED_NCF_RETRIES_EXCEEDED,
+ PGM_PC_RECEIVER_NAKS_FAILED_DATA_RETRIES_EXCEEDED,
+/* PGM_PC_RECEIVER_NAKS_FAILED_GEN_EXPIRED */
+ PGM_PC_RECEIVER_NAK_FAILURES_DELIVERED,
+ PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED,
+ PGM_PC_RECEIVER_NAK_ERRORS,
+/* PGM_PC_RECEIVER_LAST_ACTIVITY, */
+/* PGM_PC_RECEIVER_NAK_SVC_TIME_MIN, */
+ PGM_PC_RECEIVER_NAK_SVC_TIME_MEAN,
+/* PGM_PC_RECEIVER_NAK_SVC_TIME_MAX, */
+/* PGM_PC_RECEIVER_NAK_FAIL_TIME_MIN, */
+ PGM_PC_RECEIVER_NAK_FAIL_TIME_MEAN,
+/* PGM_PC_RECEIVER_NAK_FAIL_TIME_MAX, */
+/* PGM_PC_RECEIVER_TRANSMIT_MIN, */
+ PGM_PC_RECEIVER_TRANSMIT_MEAN,
+/* PGM_PC_RECEIVER_TRANSMIT_MAX, */
+ PGM_PC_RECEIVER_ACKS_SENT,
+
+/* marker */
+ PGM_PC_RECEIVER_MAX
+};
+
+struct pgm_peer_t {
+ volatile uint32_t ref_count; /* atomic integer */
+
+ pgm_tsi_t tsi;
+ struct sockaddr_storage group_nla;
+ struct sockaddr_storage nla, local_nla; /* nla = advertised, local_nla = from packet */
+ struct sockaddr_storage poll_nla; /* from parent to direct poll-response */
+ struct sockaddr_storage redirect_nla; /* from dlr */
+ pgm_time_t polr_expiry;
+ pgm_time_t spmr_expiry;
+ pgm_time_t spmr_tstamp;
+
+ pgm_rxw_t* restrict window;
+ pgm_list_t peers_link;
+ pgm_slist_t pending_link;
+
+ unsigned is_fec_enabled:1;
+ unsigned has_proactive_parity:1; /* indicating availability from this source */
+ unsigned has_ondemand_parity:1;
+
+ uint32_t spm_sqn;
+ pgm_time_t expiry;
+
+ pgm_time_t ack_rb_expiry; /* 0 = no ACK pending */
+ pgm_time_t ack_last_tstamp; /* in source time reference */
+ pgm_list_t ack_link;
+
+ uint32_t last_poll_sqn;
+ uint16_t last_poll_round;
+ pgm_time_t last_packet;
+ pgm_time_t last_data_tstamp; /* local timestamp of ack_last_tstamp */
+ unsigned last_commit;
+ uint32_t lost_count;
+ uint32_t last_cumulative_losses;
+ volatile uint32_t cumulative_stats[PGM_PC_RECEIVER_MAX];
+ uint32_t snap_stats[PGM_PC_RECEIVER_MAX];
+
+ uint32_t min_fail_time;
+ uint32_t max_fail_time;
+};
+
+PGM_GNUC_INTERNAL pgm_peer_t* pgm_new_peer (pgm_sock_t*const restrict, const pgm_tsi_t*const restrict, const struct sockaddr*const restrict, const socklen_t, const struct sockaddr*const restrict, const socklen_t, const pgm_time_t);
+PGM_GNUC_INTERNAL void pgm_peer_unref (pgm_peer_t*);
+PGM_GNUC_INTERNAL int pgm_flush_peers_pending (pgm_sock_t*const restrict, struct pgm_msgv_t**restrict, const struct pgm_msgv_t*const, size_t*const restrict, unsigned*const restrict);
+PGM_GNUC_INTERNAL bool pgm_peer_has_pending (pgm_peer_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_peer_set_pending (pgm_sock_t*const restrict, pgm_peer_t*const restrict);
+PGM_GNUC_INTERNAL bool pgm_check_peer_state (pgm_sock_t*const, const pgm_time_t);
+PGM_GNUC_INTERNAL void pgm_set_reset_error (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_msgv_t*const restrict);
+PGM_GNUC_INTERNAL pgm_time_t pgm_min_receiver_expiry (pgm_sock_t*, pgm_time_t) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_on_peer_nak (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_on_data (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_on_ncf (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_on_spm (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_on_poll (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_RECEIVER_H__ */
diff --git a/src/pgm/impl/reed_solomon.h b/src/pgm/impl/reed_solomon.h
new file mode 100644
index 0000000..595e7b5
--- /dev/null
+++ b/src/pgm/impl/reed_solomon.h
@@ -0,0 +1,54 @@
+/*
+ * Reed-Solomon forward error correction based on Vandermonde matrices
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_REED_SOLOMON_H__
+#define __PGM_IMPL_REED_SOLOMON_H__
+
+typedef struct pgm_rs_t pgm_rs_t;
+
+#include <pgm/types.h>
+#include <impl/galois.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_rs_t {
+ uint8_t n, k; /* RS(n, k) */
+ pgm_gf8_t* GM;
+ pgm_gf8_t* RM;
+};
+
+#define PGM_RS_DEFAULT_N 255
+
+PGM_GNUC_INTERNAL void pgm_rs_create (pgm_rs_t*, const uint8_t, const uint8_t);
+PGM_GNUC_INTERNAL void pgm_rs_destroy (pgm_rs_t*);
+PGM_GNUC_INTERNAL void pgm_rs_encode (pgm_rs_t*restrict, const pgm_gf8_t**restrict, const uint8_t, pgm_gf8_t*restrict, const uint16_t);
+PGM_GNUC_INTERNAL void pgm_rs_decode_parity_inline (pgm_rs_t*restrict, pgm_gf8_t**restrict, const uint8_t*restrict, const uint16_t);
+PGM_GNUC_INTERNAL void pgm_rs_decode_parity_appended (pgm_rs_t*restrict, pgm_gf8_t**restrict, const uint8_t*restrict, const uint16_t);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_REED_SOLOMON_H__ */
diff --git a/src/pgm/impl/rwspinlock.h b/src/pgm/impl/rwspinlock.h
new file mode 100644
index 0000000..476a9db
--- /dev/null
+++ b/src/pgm/impl/rwspinlock.h
@@ -0,0 +1,140 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * read-write spinlock.
+ *
+ * Copyright (c) 2011 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_RWSPINLOCK_H__
+#define __PGM_IMPL_RWSPINLOCK_H__
+
+typedef struct pgm_rwspinlock_t pgm_rwspinlock_t;
+
+#include <pgm/types.h>
+#include <impl/ticket.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_rwspinlock_t {
+ pgm_ticket_t lock;
+ volatile uint32_t readers;
+};
+
+
+/* read-write lock */
+
+static inline void pgm_rwspinlock_init (pgm_rwspinlock_t* rwspinlock) {
+ pgm_ticket_init (&rwspinlock->lock);
+ rwspinlock->readers = 0;
+}
+
+static inline void pgm_rwspinlock_free (pgm_rwspinlock_t* rwspinlock) {
+ pgm_ticket_free (&rwspinlock->lock);
+}
+
+static inline void pgm_rwspinlock_reader_lock (pgm_rwspinlock_t* rwspinlock) {
+ for (;;) {
+#if defined( _WIN32 ) || defined( __i386__ ) || defined( __i386 ) || defined( __x86_64__ ) || defined( __amd64 )
+ unsigned spins = 0;
+ while (!pgm_ticket_is_unlocked (&rwspinlock->lock))
+ if (!pgm_smp_system || (++spins > PGM_ADAPTIVE_MUTEX_SPINCOUNT))
+# ifdef _WIN32
+ SwitchToThread();
+# else
+ sched_yield();
+# endif
+ else /* hyper-threading pause */
+# ifdef _MSC_VER
+/* not implemented in Mingw */
+ YieldProcessor();
+# else
+ __asm volatile ("pause" ::: "memory");
+# endif
+#else
+ while (!pgm_ticket_is_unlocked (&rwspinlock->lock))
+ sched_yield();
+#endif
+/* speculative lock */
+ pgm_atomic_inc32 (&rwspinlock->readers);
+ if (pgm_ticket_is_unlocked (&rwspinlock->lock))
+ return;
+ pgm_atomic_dec32 (&rwspinlock->readers);
+ }
+}
+
+static inline bool pgm_rwspinlock_reader_trylock (pgm_rwspinlock_t* rwspinlock) {
+ pgm_atomic_inc32 (&rwspinlock->readers);
+ if (pgm_ticket_is_unlocked (&rwspinlock->lock))
+ return TRUE;
+ pgm_atomic_dec32 (&rwspinlock->readers);
+ return FALSE;
+}
+
+static inline void pgm_rwspinlock_reader_unlock (pgm_rwspinlock_t* rwspinlock) {
+ pgm_atomic_dec32 (&rwspinlock->readers);
+}
+
+static inline void pgm_rwspinlock_writer_lock (pgm_rwspinlock_t* rwspinlock) {
+#if defined( _WIN32 ) || defined( __i386__ ) || defined( __i386 ) || defined( __x86_64__ ) || defined( __amd64 )
+ unsigned spins = 0;
+ pgm_ticket_lock (&rwspinlock->lock);
+ while (rwspinlock->readers)
+ if (!pgm_smp_system || (++spins > PGM_ADAPTIVE_MUTEX_SPINCOUNT))
+# ifdef _WIN32
+ SwitchToThread();
+# else
+ sched_yield();
+# endif
+ else /* hyper-threading pause */
+# ifdef _MSC_VER
+ YieldProcessor();
+# else
+ __asm volatile ("pause" ::: "memory");
+# endif
+#else
+ pgm_ticket_lock (&rwspinlock->lock);
+ while (rwspinlock->readers)
+ sched_yield();
+#endif
+}
+
+static inline bool pgm_rwspinlock_writer_trylock (pgm_rwspinlock_t* rwspinlock) {
+ if (rwspinlock->readers)
+ return FALSE;
+ if (!pgm_ticket_trylock (&rwspinlock->lock))
+ return FALSE;
+ if (rwspinlock->readers) {
+ pgm_ticket_unlock (&rwspinlock->lock);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static inline void pgm_rwspinlock_writer_unlock (pgm_rwspinlock_t* rwspinlock) {
+ pgm_ticket_unlock (&rwspinlock->lock);
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_RWSPINLOCK_H__ */
diff --git a/src/pgm/impl/rxw.h b/src/pgm/impl/rxw.h
new file mode 100644
index 0000000..4727aa2
--- /dev/null
+++ b/src/pgm/impl/rxw.h
@@ -0,0 +1,218 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * basic receive window.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_RXW_H__
+#define __PGM_IMPL_RXW_H__
+
+typedef struct pgm_rxw_state_t pgm_rxw_state_t;
+typedef struct pgm_rxw_t pgm_rxw_t;
+
+#include <impl/framework.h>
+
+PGM_BEGIN_DECLS
+
+enum
+{
+ PGM_PKT_STATE_ERROR = 0,
+ PGM_PKT_STATE_BACK_OFF, /* PGM protocol recovery states */
+ PGM_PKT_STATE_WAIT_NCF,
+ PGM_PKT_STATE_WAIT_DATA,
+ PGM_PKT_STATE_HAVE_DATA, /* data received waiting to commit to application layer */
+ PGM_PKT_STATE_HAVE_PARITY, /* contains parity information not original data */
+ PGM_PKT_STATE_COMMIT_DATA, /* commited data waiting for purging */
+ PGM_PKT_STATE_LOST_DATA /* if recovery fails, but packet has not yet been commited */
+};
+
+enum
+{
+ PGM_RXW_OK = 0,
+ PGM_RXW_INSERTED,
+ PGM_RXW_APPENDED,
+ PGM_RXW_UPDATED,
+ PGM_RXW_MISSING,
+ PGM_RXW_DUPLICATE,
+ PGM_RXW_MALFORMED,
+ PGM_RXW_BOUNDS,
+ PGM_RXW_SLOW_CONSUMER,
+ PGM_RXW_UNKNOWN
+};
+
+/* must be smaller than PGM skbuff control buffer */
+struct pgm_rxw_state_t {
+ pgm_time_t timer_expiry;
+ int pkt_state;
+
+ uint8_t nak_transmit_count; /* 8-bit for size constraints */
+ uint8_t ncf_retry_count;
+ uint8_t data_retry_count;
+
+/* only valid on tg_sqn::pkt_sqn = 0 */
+ unsigned is_contiguous:1; /* transmission group */
+};
+
+struct pgm_rxw_t {
+ const pgm_tsi_t* tsi;
+
+ pgm_queue_t ack_backoff_queue;
+ pgm_queue_t nak_backoff_queue;
+ pgm_queue_t wait_ncf_queue;
+ pgm_queue_t wait_data_queue;
+/* window context counters */
+ uint32_t lost_count; /* failed to repair */
+ uint32_t fragment_count; /* incomplete apdu */
+ uint32_t parity_count; /* parity for repairs */
+ uint32_t committed_count; /* but still in window */
+
+ uint16_t max_tpdu; /* maximum packet size */
+ uint32_t lead, trail;
+ uint32_t rxw_trail, rxw_trail_init;
+ uint32_t commit_lead;
+ unsigned is_constrained:1;
+ unsigned is_defined:1;
+ unsigned has_event:1; /* edge triggered */
+ unsigned is_fec_available:1;
+ pgm_rs_t rs;
+ uint32_t tg_size; /* transmission group size for parity recovery */
+ uint8_t tg_sqn_shift;
+
+ uint32_t bitmap; /* receive status of last 32 packets */
+ uint32_t data_loss; /* p */
+ uint32_t ack_c_p; /* constant Cᵨ */
+
+/* counters all guint32 */
+ uint32_t min_fill_time; /* restricted from pgm_time_t */
+ uint32_t max_fill_time;
+ uint32_t min_nak_transmit_count;
+ uint32_t max_nak_transmit_count;
+ uint32_t cumulative_losses;
+ uint32_t bytes_delivered;
+ uint32_t msgs_delivered;
+
+ size_t size; /* in bytes */
+ unsigned alloc; /* in pkts */
+/* C90 and older */
+ struct pgm_sk_buff_t* pdata[1];
+};
+
+
+PGM_GNUC_INTERNAL pgm_rxw_t* pgm_rxw_create (const pgm_tsi_t*const, const uint16_t, const unsigned, const unsigned, const ssize_t, const uint32_t) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_rxw_destroy (pgm_rxw_t*const);
+PGM_GNUC_INTERNAL int pgm_rxw_add (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const pgm_time_t, const pgm_time_t) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_rxw_add_ack (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const pgm_time_t);
+PGM_GNUC_INTERNAL void pgm_rxw_remove_ack (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict);
+PGM_GNUC_INTERNAL void pgm_rxw_remove_commit (pgm_rxw_t*const);
+PGM_GNUC_INTERNAL ssize_t pgm_rxw_readv (pgm_rxw_t*const restrict, struct pgm_msgv_t** restrict, const unsigned) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL unsigned pgm_rxw_remove_trail (pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL unsigned pgm_rxw_update (pgm_rxw_t*const, const uint32_t, const uint32_t, const pgm_time_t, const pgm_time_t) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_rxw_update_fec (pgm_rxw_t*const, const uint8_t);
+PGM_GNUC_INTERNAL int pgm_rxw_confirm (pgm_rxw_t*const, const uint32_t, const pgm_time_t, const pgm_time_t, const pgm_time_t) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_rxw_lost (pgm_rxw_t*const, const uint32_t);
+PGM_GNUC_INTERNAL void pgm_rxw_state (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const int);
+PGM_GNUC_INTERNAL struct pgm_sk_buff_t* pgm_rxw_peek (pgm_rxw_t*const, const uint32_t) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL const char* pgm_pkt_state_string (const int) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL const char* pgm_rxw_returns_string (const int) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_rxw_dump (const pgm_rxw_t*const);
+
+/* declare for GCC attributes */
+static inline unsigned pgm_rxw_max_length (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline uint32_t pgm_rxw_length (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline size_t pgm_rxw_size (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline bool pgm_rxw_is_empty (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline bool pgm_rxw_is_full (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline uint32_t pgm_rxw_lead (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline uint32_t pgm_rxw_next_lead (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+
+static inline
+unsigned
+pgm_rxw_max_length (
+ const pgm_rxw_t* const window
+ )
+{
+ pgm_assert (NULL != window);
+ return window->alloc;
+}
+
+static inline
+uint32_t
+pgm_rxw_length (
+ const pgm_rxw_t* const window
+ )
+{
+ pgm_assert (NULL != window);
+ return ( 1 + window->lead ) - window->trail;
+}
+
+static inline
+size_t
+pgm_rxw_size (
+ const pgm_rxw_t* const window
+ )
+{
+ pgm_assert (NULL != window);
+ return window->size;
+}
+
+static inline
+bool
+pgm_rxw_is_empty (
+ const pgm_rxw_t* const window
+ )
+{
+ pgm_assert (NULL != window);
+ return pgm_rxw_length (window) == 0;
+}
+
+static inline
+bool
+pgm_rxw_is_full (
+ const pgm_rxw_t* const window
+ )
+{
+ pgm_assert (NULL != window);
+ return pgm_rxw_length (window) == pgm_rxw_max_length (window);
+}
+
+static inline
+uint32_t
+pgm_rxw_lead (
+ const pgm_rxw_t* const window
+ )
+{
+ pgm_assert (NULL != window);
+ return window->lead;
+}
+
+static inline
+uint32_t
+pgm_rxw_next_lead (
+ const pgm_rxw_t* const window
+ )
+{
+ pgm_assert (NULL != window);
+ return (uint32_t)(pgm_rxw_lead (window) + 1);
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_RXW_H__ */
diff --git a/src/pgm/impl/security.h b/src/pgm/impl/security.h
new file mode 100644
index 0000000..603fdf7
--- /dev/null
+++ b/src/pgm/impl/security.h
@@ -0,0 +1,265 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable security-enhanced CRT functions.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_SECURITY_H__
+#define __PGM_IMPL_SECURITY_H__
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <impl/i18n.h>
+#include <impl/errno.h>
+#include <impl/string.h>
+
+PGM_BEGIN_DECLS
+
+#ifdef HAVE_FTIME
+static inline
+errno_t
+# if !defined( _WIN32 )
+pgm_ftime_s (struct timeb *timeptr)
+# elif !defined( _MSC_VER )
+pgm_ftime_s (struct _timeb *timeptr)
+# else
+/* force 64-bit structure in case _USE_32BIT_TIME_T is defined */
+pgm_ftime_s (struct __timeb64 *timeptr)
+# endif
+{
+# if !defined( _WIN32 )
+ return ftime (timeptr);
+# elif !defined( _MSC_VER )
+/* MinGW does not export a 32-bit or 64-bit specific API */
+ _ftime (timeptr);
+ return 0;
+# elif defined( _CRT_SECURE_NO_WARNINGS )
+/* validates timeptr is not NULL, otherwise returns EINVAL */
+ return _ftime64_s (timeptr);
+# else
+/* no return value, but errno is set to EINVAL if timeptr is NULL */
+ _ftime64 (timeptr);
+ return 0;
+# endif
+}
+#endif /* HAVE_FTIME */
+
+#ifndef _TRUNCATE
+# define _TRUNCATE (size_t)-1
+#endif
+
+static inline
+errno_t
+pgm_strncpy_s (char *dest, size_t size, const char *src, size_t count)
+{
+#ifndef _CRT_SECURE_NO_WARNINGS
+ if (_TRUNCATE == count) {
+ strncpy (dest, src, size);
+ if (size > 0)
+ dest[size - 1] = 0;
+ return 0;
+ }
+ strncpy (dest, src, count + 1);
+ dest[count] = 0;
+ return 0;
+#else
+ return strncpy_s (dest, size, src, count);
+#endif
+}
+
+static inline int pgm_vsnprintf_s (char*, size_t, size_t, const char*, va_list) PGM_GNUC_PRINTF(4, 0);
+
+static inline
+int
+pgm_vsnprintf_s (char *str, size_t size, size_t count, const char *format, va_list ap)
+{
+#if !defined( _WIN32 )
+ if (_TRUNCATE == count) {
+ const int retval = vsnprintf (str, size, format, ap);
+ if (size > 0)
+ str[size - 1] = 0;
+ return retval;
+ }
+ const int retval = vsnprintf (str, count + 1, format, ap);
+ str[count] = 0;
+ return retval;
+#elif !defined( _CRT_SECURE_NO_WARNINGS )
+ if (_TRUNCATE == count) {
+ const int retval = _vsnprintf (str, size, format, ap);
+ if (size > 0)
+ str[size - 1] = 0;
+ return retval;
+ }
+ const int retval = _vsnprintf (str, count + 1, format, ap);
+ str[count] = 0;
+ return retval;
+#else
+ return _vsnprintf_s (str, size, count, format, ap);
+#endif
+}
+
+#ifndef _CRT_SECURE_NO_WARNINGS
+/* decl required for defining attributes */
+static inline int pgm_snprintf_s (char*, size_t, size_t, const char*, ...) PGM_GNUC_PRINTF(4, 5);
+static inline int pgm_sscanf_s (const char*, const char*, ...) PGM_GNUC_SCANF(2, 3);
+
+static inline
+int
+pgm_snprintf_s (char *str, size_t size, size_t count, const char *format, ...)
+{
+ va_list ap;
+ int retval;
+
+ va_start (ap, format);
+ retval = pgm_vsnprintf_s (str, size, count, format, ap);
+ va_end (ap);
+ return retval;
+}
+
+static inline
+int
+pgm_sscanf_s (const char *buffer, const char *format, ...)
+{
+ va_list ap;
+ int retval;
+
+ va_start (ap, format);
+ retval = vsscanf (buffer, format, ap);
+ va_end (ap);
+ return retval;
+}
+#else
+# define pgm_snprintf_s _snprintf_s
+# define pgm_sscanf_s sscanf_s
+#endif /* _CRT_SECURE_NO_WARNINGS */
+
+static inline
+char*
+pgm_strerror_s (char *buffer, size_t size, int errnum)
+{
+#if defined( _CRT_SECURE_NO_WARNINGS )
+ if (0 != strerror_s (buffer, size, errnum))
+ pgm_snprintf_s (buffer, size, _TRUNCATE, _("Unknown error %d"), errnum);
+ return buffer;
+#elif defined( _WIN32 )
+ pgm_strncpy_s (buffer, size, strerror (errnum), _TRUNCATE);
+ return buffer;
+#elif defined( HAVE_GNU_STRERROR_R ) && defined( STRERROR_R_CHAR_P )
+/* GNU-specific, failure is noted within buffer contents */
+ return strerror_r (errnum, buffer, size);
+#else
+/* XSI-compliant */
+ if (0 != strerror_r (errnum, buffer, size))
+ pgm_snprintf_s (buffer, size, _TRUNCATE, _("Unknown error %d"), errnum);
+ return buffer;
+#endif
+}
+
+static inline
+errno_t
+pgm_fopen_s (FILE **pFile, const char *filename, const char *mode)
+{
+#ifndef _CRT_SECURE_NO_WARNINGS
+ FILE* stream;
+
+ if (NULL == (stream = fopen (filename, mode)))
+ return errno;
+ *pFile = stream;
+ return 0;
+#else
+ return fopen_s (pFile, filename, mode);
+#endif
+}
+
+/* Security-only APIs */
+
+static inline
+errno_t
+pgm_dupenv_s (char **buffer, size_t *count, const char* name)
+{
+#ifndef _CRT_SECURE_NO_WARNINGS
+ const char *val = getenv (name);
+/* not found */
+ if (NULL == val) {
+ *buffer = NULL;
+ *count = 0;
+ return 0;
+ }
+ *buffer = pgm_strdup (val);
+/* out of memory */
+ if (NULL == *buffer) {
+ *buffer = NULL;
+ *count = 0;
+ return errno; /* ENOMEM */
+ }
+ *count = strlen (*buffer) + 1;
+ return 0;
+#else
+ char *pValue;
+ const errno_t err = _dupenv_s (&pValue, count, name);
+ if (err) return err;
+ *buffer = pgm_strdup (pValue);
+ free (pValue);
+ return err;
+#endif /* _CRT_SECURE_NO_WARNINGS */
+}
+
+/* Win32 specific APIs */
+
+#ifdef _WIN32
+static inline
+errno_t
+pgm_wcstombs_s (size_t *retval, char *dest, size_t size, const wchar_t *src, size_t count)
+{
+# ifndef _CRT_SECURE_NO_WARNINGS
+ size_t characters;
+ if (_TRUNCATE == count) {
+ characters = wcstombs (dest, src, size);
+/* may invalidate last multi-byte character */
+ if (size > 0)
+ dest[size - 1] = 0;
+ } else {
+ characters = wcstombs (dest, src, count + 1);
+ dest[count] = 0;
+ }
+ if ((size_t)-1 == characters) {
+ *retval = 0;
+ return errno;
+ }
+ *retval = characters;
+ return 0;
+# else
+ return wcstombs_s (retval, dest, size, src, count);
+# endif /* _CRT_SECURE_NO_WARNINGS */
+}
+
+#endif /* _WIN32 */
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_SECURITY_H__ */
diff --git a/src/pgm/impl/slist.h b/src/pgm/impl/slist.h
new file mode 100644
index 0000000..41d53b4
--- /dev/null
+++ b/src/pgm/impl/slist.h
@@ -0,0 +1,55 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable singly-linked list.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_SLIST_H__
+#define __PGM_IMPL_SLIST_H__
+
+typedef struct pgm_slist_t pgm_slist_t;
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_slist_t
+{
+ void* restrict data;
+ struct pgm_slist_t* restrict next;
+};
+
+PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_append (pgm_slist_t*restrict, void*restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_prepend (pgm_slist_t*restrict, void*restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_prepend_link (pgm_slist_t*restrict, pgm_slist_t*restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_remove (pgm_slist_t*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_remove_first (pgm_slist_t*) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_slist_free (pgm_slist_t*);
+PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_last (pgm_slist_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL unsigned pgm_slist_length (pgm_slist_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT;
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_SLIST_H__ */
diff --git a/src/pgm/impl/sn.h b/src/pgm/impl/sn.h
new file mode 100644
index 0000000..bfa369c
--- /dev/null
+++ b/src/pgm/impl/sn.h
@@ -0,0 +1,137 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * serial number arithmetic: rfc 1982
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_SN_H__
+#define __PGM_IMPL_SN_H__
+
+#include <pgm/types.h>
+#include <impl/messages.h>
+
+PGM_BEGIN_DECLS
+
+#define PGM_UINT32_SIGN_BIT (1UL<<31)
+#define PGM_UINT64_SIGN_BIT (1ULL<<63)
+
+/* declare for GCC attributes */
+static inline bool pgm_uint32_lt (const uint32_t, const uint32_t) PGM_GNUC_CONST;
+static inline bool pgm_uint32_lte (const uint32_t, const uint32_t) PGM_GNUC_CONST;
+static inline bool pgm_uint32_gt (const uint32_t, const uint32_t) PGM_GNUC_CONST;
+static inline bool pgm_uint32_gte (const uint32_t, const uint32_t) PGM_GNUC_CONST;
+static inline bool pgm_uint64_lt (const uint64_t, const uint64_t) PGM_GNUC_CONST;
+static inline bool pgm_uint64_lte (const uint64_t, const uint64_t) PGM_GNUC_CONST;
+static inline bool pgm_uint64_gt (const uint64_t, const uint64_t) PGM_GNUC_CONST;
+static inline bool pgm_uint64_gte (const uint64_t, const uint64_t) PGM_GNUC_CONST;
+
+/* 32 bit */
+static inline
+bool pgm_uint32_lt (
+ const uint32_t s,
+ const uint32_t t
+ )
+{
+ pgm_assert (sizeof(int) >= 4);
+ return ((s - t) & PGM_UINT32_SIGN_BIT) != 0;
+}
+
+static inline
+bool
+pgm_uint32_lte (
+ const uint32_t s,
+ const uint32_t t
+ )
+{
+ pgm_assert (sizeof(int) >= 4);
+ return s == t || ((s - t) & PGM_UINT32_SIGN_BIT) != 0;
+}
+
+static inline
+bool
+pgm_uint32_gt (
+ const uint32_t s,
+ const uint32_t t
+ )
+{
+ pgm_assert (sizeof(int) >= 4);
+ return ((t - s) & PGM_UINT32_SIGN_BIT) != 0;
+}
+
+static inline
+bool
+pgm_uint32_gte (
+ const uint32_t s,
+ const uint32_t t
+ )
+{
+ pgm_assert (sizeof(int) >= 4);
+ return s == t || ((t - s) & PGM_UINT32_SIGN_BIT) != 0;
+}
+
+/* 64 bit */
+static inline
+bool
+pgm_uint64_lt (
+ const uint64_t s,
+ const uint64_t t
+ )
+{
+ return ((s - t) & PGM_UINT64_SIGN_BIT) != 0;
+}
+
+static inline
+bool
+pgm_uint64_lte (
+ const uint64_t s,
+ const uint64_t t
+ )
+{
+ return s == t || ((s - t) & PGM_UINT64_SIGN_BIT) != 0;
+}
+
+static inline
+bool
+pgm_uint64_gt (
+ const uint64_t s,
+ const uint64_t t
+ )
+{
+ return ((t - s) & PGM_UINT64_SIGN_BIT) != 0;
+}
+
+static inline
+bool
+pgm_uint64_gte (
+ const uint64_t s,
+ const uint64_t t
+ )
+{
+ return s == t || ((t - s) & PGM_UINT64_SIGN_BIT) != 0;
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_SN_H__ */
diff --git a/src/pgm/impl/sockaddr.h b/src/pgm/impl/sockaddr.h
new file mode 100644
index 0000000..ac25a33
--- /dev/null
+++ b/src/pgm/impl/sockaddr.h
@@ -0,0 +1,176 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * struct sockaddr functions independent of in or in6.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_SOCKADDR_H__
+#define __PGM_IMPL_SOCKADDR_H__
+
+#ifndef _WIN32
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netdb.h>
+#endif
+#if defined( __APPLE__ ) || defined( __FreeBSD__ )
+/* incomplete RFC 3678 API support */
+# include <pgm/in.h>
+#endif
+#include <pgm/types.h>
+#include <impl/security.h>
+#include <impl/wsastrerror.h>
+
+PGM_BEGIN_DECLS
+
+/* fallback values where not directly supported */
+#ifndef MSG_DONTWAIT
+# define MSG_DONTWAIT 0
+#endif
+#ifndef MSG_ERRQUEUE
+# define MSG_ERRQUEUE 0x2000
+#endif
+
+#ifndef _WIN32
+# define SOCKET int
+# define INVALID_SOCKET (int)-1
+# define SOCKET_ERROR (int)-1
+# define PGM_SOCK_EAGAIN EAGAIN
+# define PGM_SOCK_ECONNRESET ECONNRESET
+# define PGM_SOCK_EHOSTUNREACH EHOSTUNREACH
+# define PGM_SOCK_EINTR EINTR
+# define PGM_SOCK_EINVAL EINVAL
+# define PGM_SOCK_ENETUNREACH ENETUNREACH
+# define PGM_SOCK_ENOBUFS ENOBUFS
+# define closesocket close
+# define ioctlsocket ioctl
+# define pgm_error_from_sock_errno pgm_error_from_errno
+
+static inline
+int
+pgm_get_last_sock_error (void)
+{
+ return errno;
+}
+
+static inline
+void
+pgm_set_last_sock_error (int errnum)
+{
+ errno = errnum;
+}
+
+static inline
+char*
+pgm_sock_strerror_s (char *buffer, size_t size, int errnum)
+{
+ return pgm_strerror_s (buffer, size, errnum);
+}
+
+static inline
+char*
+pgm_gai_strerror_s (char* buffer, size_t size, int errnum)
+{
+ pgm_strncpy_s (buffer, size, gai_strerror (errnum), _TRUNCATE);
+ return buffer;
+}
+
+#else
+# define PGM_SOCK_EAGAIN WSAEWOULDBLOCK
+# define PGM_SOCK_ECONNRESET WSAECONNRESET
+# define PGM_SOCK_EHOSTUNREACH WSAEHOSTUNREACH
+# define PGM_SOCK_EINTR WSAEINTR
+# define PGM_SOCK_EINVAL WSAEINVAL
+# define PGM_SOCK_ENETUNREACH WSAENETUNREACH
+# define PGM_SOCK_ENOBUFS WSAENOBUFS
+# define pgm_get_last_sock_error() WSAGetLastError()
+# define pgm_set_last_sock_error(e) WSASetLastError(e)
+# define pgm_error_from_sock_errno pgm_error_from_wsa_errno
+
+static inline
+char*
+pgm_sock_strerror_s (char *buffer, size_t size, int errnum)
+{
+ pgm_strncpy_s (buffer, size, pgm_wsastrerror (errnum), _TRUNCATE);
+ return buffer;
+}
+
+static inline
+char*
+pgm_gai_strerror_s (char* buffer, size_t size, int errnum)
+{
+/* Windows maps EAI error codes onto WSA error codes */
+ return pgm_sock_strerror_s (buffer, size, errnum);
+}
+
+#endif
+
+PGM_GNUC_INTERNAL sa_family_t pgm_sockaddr_family (const struct sockaddr* sa);
+PGM_GNUC_INTERNAL in_port_t pgm_sockaddr_port (const struct sockaddr* sa);
+PGM_GNUC_INTERNAL socklen_t pgm_sockaddr_len (const struct sockaddr* sa);
+PGM_GNUC_INTERNAL socklen_t pgm_sockaddr_storage_len (const struct sockaddr_storage* ss);
+PGM_GNUC_INTERNAL uint8_t pgm_sockaddr_prefixlen (const struct sockaddr* sa);
+PGM_GNUC_INTERNAL uint32_t pgm_sockaddr_scope_id (const struct sockaddr* sa);
+PGM_GNUC_INTERNAL int pgm_sockaddr_ntop (const struct sockaddr*restrict sa, char*restrict dst, size_t ulen);
+PGM_GNUC_INTERNAL int pgm_sockaddr_pton (const char*restrict src, struct sockaddr*restrict dst);
+PGM_GNUC_INTERNAL int pgm_sockaddr_is_addr_multicast (const struct sockaddr* sa);
+PGM_GNUC_INTERNAL int pgm_sockaddr_is_addr_unspecified (const struct sockaddr* sa);
+PGM_GNUC_INTERNAL int pgm_sockaddr_cmp (const struct sockaddr*restrict sa1, const struct sockaddr*restrict sa2);
+PGM_GNUC_INTERNAL int pgm_sockaddr_hdrincl (const SOCKET s, const sa_family_t sa_family, const bool v);
+PGM_GNUC_INTERNAL int pgm_sockaddr_pktinfo (const SOCKET s, const sa_family_t sa_family, const bool v);
+PGM_GNUC_INTERNAL int pgm_sockaddr_router_alert (const SOCKET s, const sa_family_t sa_family, const bool v);
+PGM_GNUC_INTERNAL int pgm_sockaddr_tos (const SOCKET s, const sa_family_t sa_family, const int tos);
+PGM_GNUC_INTERNAL int pgm_sockaddr_join_group (const SOCKET s, const sa_family_t sa_family, const struct group_req* gr);
+PGM_GNUC_INTERNAL int pgm_sockaddr_leave_group (const SOCKET s, const sa_family_t sa_family, const struct group_req* gr);
+PGM_GNUC_INTERNAL int pgm_sockaddr_block_source (const SOCKET s, const sa_family_t sa_family, const struct group_source_req* gsr);
+PGM_GNUC_INTERNAL int pgm_sockaddr_unblock_source (const SOCKET s, const sa_family_t sa_family, const struct group_source_req* gsr);
+PGM_GNUC_INTERNAL int pgm_sockaddr_join_source_group (const SOCKET s, const sa_family_t sa_family, const struct group_source_req* gsr);
+PGM_GNUC_INTERNAL int pgm_sockaddr_leave_source_group (const SOCKET s, const sa_family_t sa_family, const struct group_source_req* gsr);
+#ifndef GROUP_FILTER_SIZE
+# define GROUP_FILTER_SIZE(numsrc) (sizeof (struct group_filter) \
+ - sizeof (struct sockaddr_storage) \
+ + ((numsrc) \
+ * sizeof (struct sockaddr_storage)))
+#endif
+#ifndef IP_MSFILTER_SIZE
+# define IP_MSFILTER_SIZE(numsrc) (sizeof (struct ip_msfilter) \
+ - sizeof (struct in_addr) \
+ + ((numsrc) \
+ * sizeof (struct in_addr)))
+#endif
+PGM_GNUC_INTERNAL int pgm_sockaddr_msfilter (const SOCKET s, const sa_family_t sa_family, const struct group_filter* gf_list);
+PGM_GNUC_INTERNAL int pgm_sockaddr_multicast_if (const SOCKET s, const struct sockaddr* address, const unsigned ifindex);
+PGM_GNUC_INTERNAL int pgm_sockaddr_multicast_loop (const SOCKET s, const sa_family_t sa_family, const bool v);
+PGM_GNUC_INTERNAL int pgm_sockaddr_multicast_hops (const SOCKET s, const sa_family_t sa_family, const unsigned hops);
+PGM_GNUC_INTERNAL void pgm_sockaddr_nonblocking (const SOCKET s, const bool v);
+
+PGM_GNUC_INTERNAL const char* pgm_inet_ntop (int af, const void*restrict src, char*restrict dst, socklen_t size);
+PGM_GNUC_INTERNAL int pgm_inet_pton (int af, const char*restrict src, void*restrict dst);
+
+PGM_GNUC_INTERNAL int pgm_nla_to_sockaddr (const void*restrict nla, struct sockaddr*restrict sa);
+PGM_GNUC_INTERNAL int pgm_sockaddr_to_nla (const struct sockaddr*restrict sa, void*restrict nla);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_SOCKADDR_H__ */
diff --git a/src/pgm/impl/socket.h b/src/pgm/impl/socket.h
new file mode 100644
index 0000000..b5c7877
--- /dev/null
+++ b/src/pgm/impl/socket.h
@@ -0,0 +1,189 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * PGM socket.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_SOCKET_H__
+#define __PGM_IMPL_SOCKET_H__
+
+struct pgm_sock_t;
+
+#include <impl/framework.h>
+#include <impl/txw.h>
+#include <impl/source.h>
+
+PGM_BEGIN_DECLS
+
+#ifndef IP_MAX_MEMBERSHIPS
+# define IP_MAX_MEMBERSHIPS 20
+#endif
+
+struct pgm_sock_t {
+ sa_family_t family; /* communications domain */
+ int socket_type;
+ int protocol;
+ pgm_tsi_t tsi;
+ in_port_t dport;
+ in_port_t udp_encap_ucast_port;
+ in_port_t udp_encap_mcast_port;
+ uint32_t rand_node_id; /* node identifier */
+
+ pgm_rwlock_t lock; /* running / destroyed */
+ pgm_mutex_t receiver_mutex; /* receiver API */
+ pgm_mutex_t source_mutex; /* source API */
+ pgm_spinlock_t txw_spinlock; /* transmit window */
+ pgm_mutex_t send_mutex; /* non-router alert socket */
+ pgm_mutex_t timer_mutex; /* next timer expiration */
+
+ bool is_bound;
+ bool is_connected;
+ bool is_destroyed;
+ bool is_reset;
+ bool is_abort_on_reset;
+
+ bool can_send_data; /* and SPMs */
+ bool can_send_nak; /* muted receiver */
+ bool can_recv_data; /* send-only */
+ bool is_edge_triggered_recv;
+ bool is_nonblocking;
+
+ struct group_source_req send_gsr; /* multicast */
+ struct sockaddr_storage send_addr; /* unicast nla */
+ SOCKET send_sock;
+ SOCKET send_with_router_alert_sock;
+ struct group_source_req recv_gsr[IP_MAX_MEMBERSHIPS]; /* sa_family = 0 terminated */
+ unsigned recv_gsr_len;
+ SOCKET recv_sock;
+
+ size_t max_apdu;
+ uint16_t max_tpdu;
+ uint16_t max_tsdu; /* excluding optional var_pktlen word */
+ uint16_t max_tsdu_fragment;
+ size_t iphdr_len;
+ bool use_multicast_loop; /* and reuseaddr for UDP encapsulation */
+ unsigned hops;
+ unsigned txw_sqns, txw_secs;
+ unsigned rxw_sqns, rxw_secs;
+ ssize_t txw_max_rte, rxw_max_rte;
+ ssize_t odata_max_rte;
+ ssize_t rdata_max_rte;
+ size_t sndbuf, rcvbuf; /* setsockopt (SO_SNDBUF/SO_RCVBUF) */
+
+ pgm_txw_t* restrict window;
+ pgm_rate_t rate_control;
+ pgm_rate_t odata_rate_control;
+ pgm_rate_t rdata_rate_control;
+ pgm_time_t adv_ivl; /* advancing with data */
+ unsigned adv_mode; /* 0 = time, 1 = data */
+ bool is_controlled_spm;
+ bool is_controlled_odata;
+ bool is_controlled_rdata;
+
+ bool use_cr; /* congestion reports */
+ bool use_pgmcc; /* congestion control */
+ bool is_pending_crqst;
+ unsigned ack_c; /* constant C */
+ unsigned ack_c_p; /* constant Cᵨ */
+ uint32_t ssthresh; /* slow-start threshold */
+ uint32_t tokens;
+ uint32_t cwnd_size; /* congestion window size */
+ uint32_t ack_rx_max;
+ uint32_t ack_bitmap;
+ uint32_t acks_after_loss;
+ uint32_t suspended_sqn;
+ bool is_congested;
+ pgm_time_t ack_expiry;
+ pgm_time_t ack_expiry_ivl;
+ pgm_time_t next_crqst;
+ pgm_time_t crqst_ivl;
+ pgm_time_t ack_bo_ivl;
+ struct sockaddr_storage acker_nla;
+ uint64_t acker_loss;
+
+ pgm_notify_t ack_notify;
+ pgm_notify_t rdata_notify;
+
+ pgm_hash_t last_hash_key;
+ void* restrict last_hash_value;
+ unsigned last_commit;
+ size_t blocklen; /* length of buffer blocked */
+ bool is_apdu_eagain; /* writer-lock on window_lock exists as send would block */
+ bool is_spm_eagain; /* writer-lock in receiver */
+
+ struct {
+ size_t data_pkt_offset;
+ size_t data_bytes_offset;
+ uint32_t first_sqn;
+ struct pgm_sk_buff_t* skb; /* references external buffer */
+ size_t tsdu_length;
+ uint32_t unfolded_odata;
+ size_t apdu_length;
+ unsigned vector_index;
+ size_t vector_offset;
+ bool is_rate_limited;
+ } pkt_dontwait_state;
+
+ uint32_t spm_sqn;
+ unsigned spm_ambient_interval; /* microseconds */
+ unsigned* restrict spm_heartbeat_interval; /* zero terminated, zero lead-pad */
+ unsigned spm_heartbeat_state; /* indexof spm_heartbeat_interval */
+ unsigned spm_heartbeat_len;
+ unsigned peer_expiry; /* from absence of SPMs */
+ unsigned spmr_expiry; /* waiting for peer SPMRs */
+
+ pgm_rand_t rand_; /* for calculating nak_rb_ivl from nak_bo_ivl */
+ unsigned nak_data_retries, nak_ncf_retries;
+ pgm_time_t nak_bo_ivl, nak_rpt_ivl, nak_rdata_ivl;
+ pgm_time_t next_heartbeat_spm, next_ambient_spm;
+
+ bool use_proactive_parity;
+ bool use_ondemand_parity;
+ bool use_var_pktlen;
+ uint8_t rs_n;
+ uint8_t rs_k;
+ uint8_t rs_proactive_h; /* 0 <= proactive-h <= ( n - k ) */
+ uint8_t tg_sqn_shift;
+ struct pgm_sk_buff_t* restrict rx_buffer;
+
+ pgm_rwlock_t peers_lock;
+ pgm_hashtable_t* restrict peers_hashtable; /* fast lookup */
+ pgm_list_t* restrict peers_list; /* easy iteration */
+ pgm_slist_t* restrict peers_pending; /* rxw: have or lost data */
+ pgm_notify_t pending_notify; /* timer to rx */
+ bool is_pending_read;
+ pgm_time_t next_poll;
+
+ uint32_t cumulative_stats[PGM_PC_SOURCE_MAX];
+ uint32_t snap_stats[PGM_PC_SOURCE_MAX];
+ pgm_time_t snap_time;
+};
+
+
+/* global variables */
+extern pgm_rwlock_t pgm_sock_list_lock;
+extern pgm_slist_t* pgm_sock_list;
+
+size_t pgm_pkt_offset (bool, sa_family_t);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_SOCKET_H__ */
diff --git a/src/pgm/impl/source.h b/src/pgm/impl/source.h
new file mode 100644
index 0000000..4d462e9
--- /dev/null
+++ b/src/pgm/impl/source.h
@@ -0,0 +1,78 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * PGM source socket.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_SOURCE_H__
+#define __PGM_IMPL_SOURCE_H__
+
+#include <impl/framework.h>
+#include <impl/receiver.h>
+
+PGM_BEGIN_DECLS
+
+/* Performance Counters */
+enum {
+ PGM_PC_SOURCE_DATA_BYTES_SENT,
+ PGM_PC_SOURCE_DATA_MSGS_SENT, /* msgs = packets not APDUs */
+/* PGM_PC_SOURCE_BYTES_BUFFERED, */ /* tx window contents in bytes */
+/* PGM_PC_SOURCE_MSGS_BUFFERED, */
+ PGM_PC_SOURCE_BYTES_SENT,
+/* PGM_PC_SOURCE_RAW_NAKS_RECEIVED, */
+ PGM_PC_SOURCE_CKSUM_ERRORS,
+ PGM_PC_SOURCE_MALFORMED_NAKS,
+ PGM_PC_SOURCE_PACKETS_DISCARDED,
+ PGM_PC_SOURCE_PARITY_BYTES_RETRANSMITTED,
+ PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED,
+ PGM_PC_SOURCE_PARITY_MSGS_RETRANSMITTED,
+ PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED,
+ PGM_PC_SOURCE_PARITY_NAK_PACKETS_RECEIVED,
+ PGM_PC_SOURCE_SELECTIVE_NAK_PACKETS_RECEIVED, /* total packets */
+ PGM_PC_SOURCE_PARITY_NAKS_RECEIVED,
+ PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED, /* serial numbers */
+ PGM_PC_SOURCE_PARITY_NAKS_IGNORED,
+ PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED,
+ PGM_PC_SOURCE_ACK_ERRORS,
+/* PGM_PC_SOURCE_PGMCC_ACKER, */
+ PGM_PC_SOURCE_TRANSMISSION_CURRENT_RATE,
+ PGM_PC_SOURCE_ACK_PACKETS_RECEIVED,
+ PGM_PC_SOURCE_PARITY_NNAK_PACKETS_RECEIVED,
+ PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED,
+ PGM_PC_SOURCE_PARITY_NNAKS_RECEIVED,
+ PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED,
+ PGM_PC_SOURCE_NNAK_ERRORS,
+
+/* marker */
+ PGM_PC_SOURCE_MAX
+};
+
+PGM_GNUC_INTERNAL bool pgm_send_spm (pgm_sock_t*const, const int) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_on_deferred_nak (pgm_sock_t*const);
+PGM_GNUC_INTERNAL bool pgm_on_spmr (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_on_nak (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_on_nnak (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_on_ack (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT;
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_SOURCE_H__ */
+
diff --git a/src/pgm/impl/sqn_list.h b/src/pgm/impl/sqn_list.h
new file mode 100644
index 0000000..996caef
--- /dev/null
+++ b/src/pgm/impl/sqn_list.h
@@ -0,0 +1,41 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * PGM sequence list.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_SQN_LIST_H__
+#define __PGM_IMPL_SQN_LIST_H__
+
+struct pgm_sqn_list_t;
+
+#include <impl/framework.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_sqn_list_t {
+ uint8_t len;
+ uint32_t sqn[63]; /* list of sequence numbers */
+};
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_SQN_LIST_H__ */
diff --git a/src/pgm/impl/string.h b/src/pgm/impl/string.h
new file mode 100644
index 0000000..30f0d1b
--- /dev/null
+++ b/src/pgm/impl/string.h
@@ -0,0 +1,62 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable string manipulation functions.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_STRING_H__
+#define __PGM_IMPL_STRING_H__
+
+typedef struct pgm_string_t pgm_string_t;
+
+#include <stdarg.h>
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+struct pgm_string_t {
+ char* str;
+ size_t len;
+ size_t allocated_len;
+};
+
+PGM_GNUC_INTERNAL char* pgm_strdup (const char*) PGM_GNUC_MALLOC;
+PGM_GNUC_INTERNAL int pgm_printf_string_upper_bound (const char*, va_list) PGM_GNUC_PRINTF(1, 0);
+PGM_GNUC_INTERNAL int pgm_vasprintf (char**restrict, char const*restrict, va_list args) PGM_GNUC_PRINTF(2, 0);
+PGM_GNUC_INTERNAL char* pgm_strdup_vprintf (const char*, va_list) PGM_GNUC_PRINTF(1, 0) PGM_GNUC_MALLOC;
+PGM_GNUC_INTERNAL char* pgm_strconcat (const char*, ...) PGM_GNUC_MALLOC PGM_GNUC_NULL_TERMINATED;
+PGM_GNUC_INTERNAL char** pgm_strsplit (const char*restrict, const char*restrict, int) PGM_GNUC_MALLOC;
+PGM_GNUC_INTERNAL void pgm_strfreev (char**);
+
+PGM_GNUC_INTERNAL pgm_string_t* pgm_string_new (const char*);
+PGM_GNUC_INTERNAL char* pgm_string_free (pgm_string_t*, bool);
+PGM_GNUC_INTERNAL void pgm_string_printf (pgm_string_t*restrict, const char*restrict, ...) PGM_GNUC_PRINTF(2, 3);
+PGM_GNUC_INTERNAL pgm_string_t* pgm_string_append (pgm_string_t*restrict, const char*restrict);
+PGM_GNUC_INTERNAL pgm_string_t* pgm_string_append_c (pgm_string_t*, char);
+PGM_GNUC_INTERNAL void pgm_string_append_printf (pgm_string_t*restrict, const char*restrict, ...) PGM_GNUC_PRINTF(2, 3);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_STRING_H__ */
diff --git a/src/pgm/impl/thread.h b/src/pgm/impl/thread.h
new file mode 100644
index 0000000..ce29e1f
--- /dev/null
+++ b/src/pgm/impl/thread.h
@@ -0,0 +1,350 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * mutexes and locks.
+ *
+ * Copyright (c) 2010-2011 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_THREAD_H__
+#define __PGM_IMPL_THREAD_H__
+
+typedef struct pgm_mutex_t pgm_mutex_t;
+typedef struct pgm_spinlock_t pgm_spinlock_t;
+typedef struct pgm_cond_t pgm_cond_t;
+typedef struct pgm_rwlock_t pgm_rwlock_t;
+
+/* spins before yielding, 200 (Linux) - 4,000 (Windows)
+ */
+#define PGM_ADAPTIVE_MUTEX_SPINCOUNT 200
+
+/* On initialisation the number of available processors is queried to determine
+ * whether we should spin in locks or yield to other threads and processes.
+ */
+extern bool pgm_smp_system;
+
+#ifndef _WIN32
+# include <pthread.h>
+# include <unistd.h>
+# if defined( __sun )
+# include <thread.h>
+# endif
+#else
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+#ifdef __APPLE__
+# include <libkern/OSAtomic.h>
+#endif
+#include <pgm/types.h>
+#if defined( USE_TICKET_SPINLOCK )
+# include <impl/ticket.h>
+#endif
+#if defined( USE_DUMB_RWSPINLOCK )
+# include <impl/rwspinlock.h>
+#endif
+
+PGM_BEGIN_DECLS
+
+struct pgm_mutex_t {
+#ifndef _WIN32
+/* POSIX mutex */
+ pthread_mutex_t pthread_mutex;
+#else
+/* Windows process-private adaptive mutex */
+ CRITICAL_SECTION win32_crit;
+#endif /* !_WIN32 */
+};
+
+struct pgm_spinlock_t {
+#if defined( USE_TICKET_SPINLOCK )
+/* ticket based spinlock */
+ pgm_ticket_t ticket_lock;
+#elif defined( HAVE_PTHREAD_SPINLOCK )
+/* POSIX spinlock, not available on OSX */
+ pthread_spinlock_t pthread_spinlock;
+#elif defined( __APPLE__ )
+/* OSX native spinlock */
+ OSSpinLock darwin_spinlock;
+#elif defined( _WIN32 )
+/* Win32 friendly atomic-op based spinlock */
+ volatile LONG taken;
+#else
+/* GCC atomic-op based spinlock */
+ volatile uint32_t taken;
+#endif
+};
+
+struct pgm_cond_t {
+#ifndef _WIN32
+/* POSIX condition variable */
+ pthread_cond_t pthread_cond;
+#elif ( _WIN32_WINNT >= 0x0600 )
+/* Windows Vista+ condition variable */
+ CONDITION_VARIABLE win32_cond;
+#else
+/* Windows XP condition variable implementation */
+ CRITICAL_SECTION win32_crit;
+ size_t len;
+ size_t allocated_len;
+ HANDLE* phandle;
+#endif /* _WIN32 */
+};
+
+struct pgm_rwlock_t {
+#if defined( USE_DUMB_RWSPINLOCK )
+ pgm_rwspinlock_t rwspinlock;
+#elif !defined( _WIN32 )
+/* POSIX read-write lock */
+ pthread_rwlock_t pthread_rwlock;
+#elif ( _WIN32_WINNT >= 0x0600 )
+/* Windows Vista+ user-space slim read-write lock */
+ SRWLOCK win32_rwlock;
+#else
+/* Windows XP read-write lock implementation */
+ CRITICAL_SECTION win32_crit;
+ pgm_cond_t read_cond;
+ pgm_cond_t write_cond;
+ unsigned read_counter;
+ bool have_writer;
+ unsigned want_to_read;
+ unsigned want_to_write;
+#endif /* USE_DUMB_RWSPINLOCK */
+};
+
+PGM_GNUC_INTERNAL void pgm_mutex_init (pgm_mutex_t*);
+PGM_GNUC_INTERNAL void pgm_mutex_free (pgm_mutex_t*);
+
+static inline bool pgm_mutex_trylock (pgm_mutex_t* mutex) {
+#ifndef _WIN32
+ const int result = pthread_mutex_trylock (&mutex->pthread_mutex);
+ if (EBUSY == result)
+ return FALSE;
+ return TRUE;
+#else
+/* WARNING: returns TRUE if in same thread as lock */
+ return TryEnterCriticalSection (&mutex->win32_crit);
+#endif /* !_WIN32 */
+}
+
+/* call to pgm_mutex_lock on locked mutex or non-init pointer is undefined.
+ */
+
+static inline void pgm_mutex_lock (pgm_mutex_t* mutex) {
+#ifndef _WIN32
+ pthread_mutex_lock (&mutex->pthread_mutex);
+#else
+ EnterCriticalSection (&mutex->win32_crit);
+#endif /* !_WIN32 */
+}
+
+/* call to pgm_mutex_unlock on unlocked mutex or non-init pointer is undefined.
+ */
+
+static inline void pgm_mutex_unlock (pgm_mutex_t* mutex) {
+#ifndef _WIN32
+ pthread_mutex_unlock (&mutex->pthread_mutex);
+#else
+ LeaveCriticalSection (&mutex->win32_crit);
+#endif /* !_WIN32 */
+}
+
+PGM_GNUC_INTERNAL void pgm_spinlock_init (pgm_spinlock_t*);
+PGM_GNUC_INTERNAL void pgm_spinlock_free (pgm_spinlock_t*);
+
+static inline bool pgm_spinlock_trylock (pgm_spinlock_t* spinlock) {
+#if defined( USE_TICKET_SPINLOCK )
+ return pgm_ticket_trylock (&spinlock->ticket_lock);
+#elif defined( HAVE_PTHREAD_SPINLOCK )
+ const int result = pthread_spin_trylock (&spinlock->pthread_spinlock);
+ if (EBUSY == result)
+ return FALSE;
+ return TRUE;
+#elif defined( __APPLE__ )
+ return OSSpinLockTry (&spinlock->darwin_spinlock);
+#elif defined( _WIN32 )
+ const LONG prev = _InterlockedExchange (&spinlock->taken, 1);
+ return (0 == prev);
+#else /* GCC atomics */
+ const uint32_t prev = __sync_lock_test_and_set (&spinlock->taken, 1);
+ return (0 == prev);
+#endif
+}
+
+static inline void pgm_spinlock_lock (pgm_spinlock_t* spinlock) {
+#if defined( USE_TICKET_SPINLOCK )
+ pgm_ticket_lock (&spinlock->ticket_lock);
+#elif defined( HAVE_PTHREAD_SPINLOCK )
+ pthread_spin_lock (&spinlock->pthread_spinlock);
+#elif defined( __APPLE__ )
+/* Anderson's exponential back-off */
+ OSSpinLockLock (&spinlock->darwin_spinlock);
+#elif defined( _WIN32 )
+/* Segall and Rudolph bus-optimised spinlock acquire with Intel's recommendation
+ * for a pause instruction for hyper-threading.
+ */
+ unsigned spins = 0;
+ while (_InterlockedExchange (&spinlock->taken, 1))
+ while (spinlock->taken)
+ if (!pgm_smp_system || (++spins > PGM_ADAPTIVE_MUTEX_SPINCOUNT))
+ SwitchToThread();
+ else
+ YieldProcessor();
+#elif defined( __i386__ ) || defined( __i386 ) || defined( __x86_64__ ) || defined( __amd64 )
+/* GCC atomics with x86 pause */
+ unsigned spins = 0;
+ while (__sync_lock_test_and_set (&spinlock->taken, 1))
+ while (spinlock->taken)
+ if (!pgm_smp_system || (++spins > PGM_ADAPTIVE_MUTEX_SPINCOUNT))
+ sched_yield();
+ else
+ __asm volatile ("pause" ::: "memory");
+#else
+/* GCC atomics */
+ while (__sync_lock_test_and_set (&spinlock->taken, 1))
+ while (spinlock->taken)
+ sched_yield();
+#endif
+}
+
+static inline void pgm_spinlock_unlock (pgm_spinlock_t* spinlock) {
+#if defined( USE_TICKET_SPINLOCK )
+ pgm_ticket_unlock (&spinlock->ticket_lock);
+#elif defined( HAVE_PTHREAD_SPINLOCK )
+ pthread_spin_unlock (&spinlock->pthread_spinlock);
+#elif defined( __APPLE__ )
+ OSSpinLockUnlock (&spinlock->darwin_spinlock);
+#elif defined( _WIN32 )
+ _InterlockedExchange (&spinlock->taken, 0);
+#else /* GCC atomics */
+ __sync_lock_release (&spinlock->taken);
+#endif
+}
+
+PGM_GNUC_INTERNAL void pgm_cond_init (pgm_cond_t*);
+PGM_GNUC_INTERNAL void pgm_cond_signal (pgm_cond_t*);
+PGM_GNUC_INTERNAL void pgm_cond_broadcast (pgm_cond_t*);
+#ifndef _WIN32
+PGM_GNUC_INTERNAL void pgm_cond_wait (pgm_cond_t*, pthread_mutex_t*);
+#else
+PGM_GNUC_INTERNAL void pgm_cond_wait (pgm_cond_t*, CRITICAL_SECTION*);
+#endif
+PGM_GNUC_INTERNAL void pgm_cond_free (pgm_cond_t*);
+
+#if defined( _WIN32 ) && !( _WIN32_WINNT >= 0x600 ) && !defined( USE_DUMB_RWSPINLOCK )
+/* read-write lock implementation for Windows XP */
+PGM_GNUC_INTERNAL void pgm_rwlock_reader_lock (pgm_rwlock_t*);
+PGM_GNUC_INTERNAL bool pgm_rwlock_reader_trylock (pgm_rwlock_t*);
+PGM_GNUC_INTERNAL void pgm_rwlock_reader_unlock(pgm_rwlock_t*);
+PGM_GNUC_INTERNAL void pgm_rwlock_writer_lock (pgm_rwlock_t*);
+PGM_GNUC_INTERNAL bool pgm_rwlock_writer_trylock (pgm_rwlock_t*);
+PGM_GNUC_INTERNAL void pgm_rwlock_writer_unlock (pgm_rwlock_t*);
+#else
+static inline void pgm_rwlock_reader_lock (pgm_rwlock_t* rwlock) {
+# if defined( USE_DUMB_RWSPINLOCK )
+/* User-space read/write lock */
+ pgm_rwspinlock_reader_lock (&rwlock->rwspinlock);
+# elif defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 )
+/* Vista+ slim read/write lock */
+ AcquireSRWLockShared (&rwlock->win32_rwlock);
+# else
+/* POSIX read/write lock */
+ pthread_rwlock_rdlock (&rwlock->pthread_rwlock);
+# endif
+}
+static inline bool pgm_rwlock_reader_trylock (pgm_rwlock_t* rwlock) {
+# if defined( USE_DUMB_RWSPINLOCK )
+ return pgm_rwspinlock_reader_trylock (&rwlock->rwspinlock);
+# elif defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 )
+ return TryAcquireSRWLockShared (&rwlock->win32_rwlock);
+# else
+ return !pthread_rwlock_tryrdlock (&rwlock->pthread_rwlock);
+# endif
+}
+static inline void pgm_rwlock_reader_unlock(pgm_rwlock_t* rwlock) {
+# if defined( USE_DUMB_RWSPINLOCK )
+ pgm_rwspinlock_reader_unlock (&rwlock->rwspinlock);
+# elif defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 )
+ ReleaseSRWLockShared (&rwlock->win32_rwlock);
+# else
+ pthread_rwlock_unlock (&rwlock->pthread_rwlock);
+# endif
+}
+static inline void pgm_rwlock_writer_lock (pgm_rwlock_t* rwlock) {
+# if defined( USE_DUMB_RWSPINLOCK )
+ pgm_rwspinlock_writer_lock (&rwlock->rwspinlock);
+# elif defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 )
+ AcquireSRWLockExclusive (&rwlock->win32_rwlock);
+# else
+ pthread_rwlock_wrlock (&rwlock->pthread_rwlock);
+# endif
+}
+static inline bool pgm_rwlock_writer_trylock (pgm_rwlock_t* rwlock) {
+# if defined( USE_DUMB_RWSPINLOCK )
+ return pgm_rwspinlock_writer_trylock (&rwlock->rwspinlock);
+# elif defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 )
+ return TryAcquireSRWLockExclusive (&rwlock->win32_rwlock);
+# else
+ return !pthread_rwlock_trywrlock (&rwlock->pthread_rwlock);
+# endif
+}
+static inline void pgm_rwlock_writer_unlock (pgm_rwlock_t* rwlock) {
+# if defined( USE_DUMB_RWSPINLOCK )
+ pgm_rwspinlock_writer_unlock (&rwlock->rwspinlock);
+# elif defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 )
+ ReleaseSRWLockExclusive (&rwlock->win32_rwlock);
+# else
+ pthread_rwlock_unlock (&rwlock->pthread_rwlock);
+# endif
+}
+#endif
+
+PGM_GNUC_INTERNAL void pgm_rwlock_init (pgm_rwlock_t*);
+PGM_GNUC_INTERNAL void pgm_rwlock_free (pgm_rwlock_t*);
+
+PGM_GNUC_INTERNAL void pgm_thread_init (void);
+PGM_GNUC_INTERNAL void pgm_thread_shutdown (void);
+
+static inline
+void
+pgm_thread_yield (void)
+{
+#if defined( __sun )
+ thr_yield(); /* Solaris specific thread API */
+#elif !defined( _WIN32 )
+ sched_yield(); /* most Unix platforms */
+#else
+ SwitchToThread(); /* yields only current processor */
+# if 0
+ Sleep (1); /* If you specify 0 milliseconds, the thread will relinquish
+ * the remainder of its time slice to processes of equal priority.
+ *
+ * Specify > Sleep (1) to yield to any process.
+ */
+# endif
+#endif /* _WIN32 */
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_THREAD_H__ */
diff --git a/src/pgm/impl/ticket.h b/src/pgm/impl/ticket.h
new file mode 100644
index 0000000..9717e4a
--- /dev/null
+++ b/src/pgm/impl/ticket.h
@@ -0,0 +1,407 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * Ticket spinlocks per Jonathan Corbet on LKML and Leslie Lamport's
+ * Bakery algorithm.
+ *
+ * NB: CMPXCHG requires 80486 microprocessor.
+ *
+ * Copyright (c) 2011 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_TICKET_H__
+#define __PGM_IMPL_TICKET_H__
+
+typedef union pgm_ticket_t pgm_ticket_t;
+
+#if defined( __sun )
+# include <atomic.h>
+#elif defined( __APPLE__ )
+# include <libkern/OSAtomic.h>
+#elif defined( _WIN32 )
+# define VC_EXTRALEAN
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# if defined( _MSC_VER )
+/* not implemented in MinGW */
+# include <intrin.h>
+# endif
+#else
+# include <pthread.h>
+# include <unistd.h>
+#endif
+#include <pgm/types.h>
+#include <pgm/atomic.h>
+#include <impl/thread.h>
+
+PGM_BEGIN_DECLS
+
+/* Byte alignment for CAS friendly unions.
+ * NB: Solaris and OpenSolaris don't support #pragma pack(push) even on x86.
+ */
+#if defined( __GNUC__ ) && !defined( __sun ) && !defined( __CYGWIN__ )
+# pragma pack(push)
+#endif
+#pragma pack(1)
+
+union pgm_ticket_t {
+#if defined( _WIN64 )
+ volatile uint64_t pgm_tkt_data64;
+ struct {
+ volatile uint32_t pgm_un_ticket;
+ volatile uint32_t pgm_un_user;
+ } pgm_un;
+#else
+ volatile uint32_t pgm_tkt_data32;
+ struct {
+ volatile uint16_t pgm_un_ticket;
+ volatile uint16_t pgm_un_user;
+ } pgm_un;
+#endif
+};
+
+#define pgm_tkt_ticket pgm_un.pgm_un_ticket
+#define pgm_tkt_user pgm_un.pgm_un_user
+
+#if defined( __GNUC__ ) && !defined( __sun ) && !defined( __CYGWIN__ )
+# pragma pack(pop)
+#else
+# pragma pack()
+#endif
+
+/* additional required atomic ops */
+
+/* 32-bit word CAS, returns TRUE if swap occurred.
+ *
+ * if (*atomic == oldval) {
+ * *atomic = newval;
+ * return TRUE;
+ * }
+ * return FALSE;
+ *
+ * Sun Studio on x86 GCC-compatible assembler not implemented.
+ */
+
+static inline
+bool
+pgm_atomic_compare_and_exchange32 (
+ volatile uint32_t* atomic,
+ const uint32_t newval,
+ const uint32_t oldval
+ )
+{
+#if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
+/* GCC assembler */
+ uint8_t result;
+ __asm__ volatile ("lock; cmpxchgl %2, %0\n\t"
+ "setz %1\n\t"
+ : "+m" (*atomic), "=q" (result)
+ : "ir" (newval), "a" (oldval)
+ : "memory", "cc" );
+ return (bool)result;
+#elif defined( __SUNPRO_C ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
+/* GCC-compatible assembler */
+ uint8_t result;
+ __asm__ volatile ("lock; cmpxchgl %2, %0\n\t"
+ "setz %1\n\t"
+ : "+m" (*atomic), "=q" (result)
+ : "r" (newval), "a" (oldval)
+ : "memory", "cc" );
+ return (bool)result;
+#elif defined( __sun )
+/* Solaris intrinsic */
+ const uint32_t original = atomic_cas_32 (atomic, oldval, newval);
+ return (oldval == original);
+#elif defined( __APPLE__ )
+/* Darwin intrinsic */
+ return OSAtomicCompareAndSwap32Barrier ((int32_t)oldval, (int32_t)newval, (volatile int32_t*)atomic);
+#elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 )
+/* GCC 4.0.1 intrinsic */
+ return __sync_bool_compare_and_swap (atomic, oldval, newval);
+#elif defined( _WIN32 )
+/* Windows intrinsic */
+ const uint32_t original = _InterlockedCompareExchange ((volatile LONG*)atomic, newval, oldval);
+ return (oldval == original);
+#endif
+}
+
+#if defined( _WIN64 )
+/* returns TRUE if swap occurred
+ */
+
+static inline
+bool
+pgm_atomic_compare_and_exchange64 (
+ volatile uint64_t* atomic,
+ const uint64_t newval,
+ const uint64_t oldval
+ )
+{
+/* Windows intrinsic */
+ const uint64_t original = _InterlockedCompareExchange64 ((volatile LONGLONG*)atomic, newval, oldval);
+ return (oldval == original);
+}
+
+/* returns original atomic value
+ */
+
+static inline
+uint32_t
+pgm_atomic_fetch_and_inc32 (
+ volatile uint32_t* atomic
+ )
+{
+ const uint32_t nv = _InterlockedIncrement ((volatile LONG*)atomic);
+ return nv - 1;
+}
+
+/* 64-bit word load
+ */
+
+static inline
+uint64_t
+pgm_atomic_read64 (
+ const volatile uint64_t* atomic
+ )
+{
+ return *atomic;
+}
+
+#else
+/* 16-bit word addition.
+ */
+
+static inline
+void
+pgm_atomic_add16 (
+ volatile uint16_t* atomic,
+ const uint16_t val
+ )
+{
+# if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
+ __asm__ volatile ("lock; addw %1, %0"
+ : "=m" (*atomic)
+ : "ir" (val), "m" (*atomic)
+ : "memory", "cc" );
+# elif defined( __SUNPRO_C ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
+ __asm__ volatile ("lock; addw %0, %1"
+ :
+ : "r" (val), "m" (*atomic)
+ : "memory", "cc" );
+# elif defined( __sun )
+ atomic_add_16 (atomic, val);
+# elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 )
+/* interchangable with __sync_fetch_and_add () */
+ __sync_add_and_fetch (atomic, val);
+# elif defined( __APPLE__ )
+# error "There is no OSAtomicAdd16Barrier() on Darwin."
+# elif defined( _WIN32 )
+/* there is no _InterlockedExchangeAdd16() */
+ _ReadWriteBarrier();
+ __asm {
+ mov ecx, atomic
+ mov ax, val
+ lock add ax, word ptr [ecx]
+ }
+ _ReadWriteBarrier();
+# endif
+}
+
+/* 16-bit word addition returning original atomic value.
+ */
+
+static inline
+uint16_t
+pgm_atomic_fetch_and_add16 (
+ volatile uint16_t* atomic,
+ const uint16_t val
+ )
+{
+# if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
+ uint16_t result;
+ __asm__ volatile ("lock; xaddw %0, %1"
+ : "=r" (result), "=m" (*atomic)
+ : "0" (val), "m" (*atomic)
+ : "memory", "cc" );
+ return result;
+# elif defined( __SUNPRO_C ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
+ uint16_t result = val;
+ __asm__ volatile ("lock; xaddw %0, %1"
+ : "+r" (result)
+ : "m" (*atomic)
+ : "memory", "cc" );
+ return result;
+# elif defined( __sun )
+ const uint16_t nv = atomic_add_16_nv (atomic, val);
+ return nv - val;
+# elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 )
+ return __sync_fetch_and_add (atomic, val);
+# elif defined( __APPLE__ )
+# error "There is no OSAtomicAdd16Barrier() on Darwin."
+# elif defined( _WIN32 )
+/* there is no _InterlockedExchangeAdd16() */
+ uint16_t result;
+ _ReadWriteBarrier();
+ __asm {
+ mov ecx, atomic
+ mov ax, val
+ lock xadd word ptr [ecx], ax
+ mov result, ax
+ }
+ _ReadWriteBarrier();
+ return result;
+# endif
+}
+
+/* 16-bit word increment.
+ */
+
+static inline
+void
+pgm_atomic_inc16 (
+ volatile uint16_t* atomic
+ )
+{
+# if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
+ __asm__ volatile ("lock; incw %0"
+ : "+m" (*atomic)
+ :
+ : "memory", "cc" );
+# elif defined( __SUNPRO_C ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
+ __asm__ volatile ("lock; incw %0"
+ : "+m" (*atomic)
+ :
+ : "memory", "cc" );
+# elif defined( __sun )
+ atomic_inc_16 (atomic);
+# elif defined( _WIN32 )
+/* _InterlockedIncrement16() operates on 32-bit boundaries */
+ _ReadWriteBarrier();
+ __asm {
+ mov ecx, atomic
+ lock inc word ptr [ecx]
+ }
+ _ReadWriteBarrier();
+# else
+/* there is no OSAtomicIncrement16Barrier() on Darwin. */
+ pgm_atomic_add16 (atomic, 1);
+# endif
+}
+
+/* 16-bit word increment returning original atomic value.
+ */
+
+static inline
+uint16_t
+pgm_atomic_fetch_and_inc16 (
+ volatile uint16_t* atomic
+ )
+{
+/* _InterlockedIncrement16() operates on 32-bit boundaries.
+ * there is no OSAtomicIncrement16Barrier() on Darwin.
+ * there is no xincw instruction on x86.
+ */
+ return pgm_atomic_fetch_and_add16 (atomic, 1);
+}
+#endif /* !_WIN64 */
+
+
+/* ticket spinlocks */
+
+static inline void pgm_ticket_init (pgm_ticket_t* ticket) {
+#ifdef _WIN64
+ ticket->pgm_tkt_data64 = 0;
+#else
+ ticket->pgm_tkt_data32 = 0;
+#endif
+}
+
+static inline void pgm_ticket_free (pgm_ticket_t* ticket) {
+/* nop */
+ (void)ticket;
+}
+
+static inline bool pgm_ticket_trylock (pgm_ticket_t* ticket) {
+#ifdef _WIN64
+ const uint32_t user = ticket->pgm_tkt_user;
+#else
+ const uint16_t user = ticket->pgm_tkt_user;
+#endif
+ pgm_ticket_t exchange, comparand;
+ comparand.pgm_tkt_user = comparand.pgm_tkt_ticket = exchange.pgm_tkt_ticket = user;
+ exchange.pgm_tkt_user = user + 1;
+#ifdef _WIN64
+ return pgm_atomic_compare_and_exchange64 (&ticket->pgm_tkt_data64, exchange.pgm_tkt_data64, comparand.pgm_tkt_data64);
+#else
+ return pgm_atomic_compare_and_exchange32 (&ticket->pgm_tkt_data32, exchange.pgm_tkt_data32, comparand.pgm_tkt_data32);
+#endif
+}
+
+static inline void pgm_ticket_lock (pgm_ticket_t* ticket) {
+#ifdef _WIN64
+ const uint32_t user = pgm_atomic_fetch_and_inc32 (&ticket->pgm_tkt_user);
+#else
+ const uint16_t user = pgm_atomic_fetch_and_inc16 (&ticket->pgm_tkt_user);
+#endif
+#if defined( _WIN32 ) || defined( __i386__ ) || defined( __i386 ) || defined( __x86_64__ ) || defined( __amd64 )
+ unsigned spins = 0;
+ while (ticket->pgm_tkt_ticket != user)
+ if (!pgm_smp_system || (++spins > PGM_ADAPTIVE_MUTEX_SPINCOUNT))
+# ifdef _WIN32
+ SwitchToThread();
+# else
+ sched_yield();
+# endif
+ else /* hyper-threading pause */
+# ifdef _MSC_VER
+ YieldProcessor();
+# else
+ __asm volatile ("pause" ::: "memory");
+# endif
+#else
+ while (ticket->pgm_tkt_ticket != user)
+ sched_yield();
+#endif
+}
+
+static inline void pgm_ticket_unlock (pgm_ticket_t* ticket) {
+#ifdef _WIN64
+ pgm_atomic_inc32 (&ticket->pgm_tkt_ticket);
+#else
+ pgm_atomic_inc16 (&ticket->pgm_tkt_ticket);
+#endif
+}
+
+static inline bool pgm_ticket_is_unlocked (pgm_ticket_t* ticket) {
+ pgm_ticket_t copy;
+#ifdef _WIN64
+ copy.pgm_tkt_data64 = pgm_atomic_read64 (&ticket->pgm_tkt_data64);
+#else
+ copy.pgm_tkt_data32 = pgm_atomic_read32 (&ticket->pgm_tkt_data32);
+#endif
+ return (copy.pgm_tkt_ticket == copy.pgm_tkt_user);
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_TICKET_H__ */
diff --git a/src/pgm/impl/time.h b/src/pgm/impl/time.h
new file mode 100644
index 0000000..3bada21
--- /dev/null
+++ b/src/pgm/impl/time.h
@@ -0,0 +1,54 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * high resolution timers.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_TIME_H__
+#define __PGM_IMPL_TIME_H__
+
+#include <pgm/types.h>
+#include <pgm/error.h>
+#include <pgm/time.h>
+
+PGM_BEGIN_DECLS
+
+typedef pgm_time_t (*pgm_time_update_func)(void);
+
+#define pgm_time_after(a,b) ( (a) > (b) )
+#define pgm_time_before(a,b) ( pgm_time_after((b),(a)) )
+
+#define pgm_time_after_eq(a,b) ( (a) >= (b) )
+#define pgm_time_before_eq(a,b) ( pgm_time_after_eq((b),(a)) )
+
+extern pgm_time_update_func pgm_time_update_now;
+
+PGM_GNUC_INTERNAL bool pgm_time_init (pgm_error_t**) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_time_shutdown (void);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_TIME_H__ */
+
diff --git a/src/pgm/impl/timer.h b/src/pgm/impl/timer.h
new file mode 100644
index 0000000..db4434c
--- /dev/null
+++ b/src/pgm/impl/timer.h
@@ -0,0 +1,61 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * PGM timer thread.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_TIMER_H__
+#define __PGM_IMPL_TIMER_H__
+
+#include <impl/framework.h>
+#include <impl/socket.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL bool pgm_timer_prepare (pgm_sock_t*const);
+PGM_GNUC_INTERNAL bool pgm_timer_check (pgm_sock_t*const);
+PGM_GNUC_INTERNAL pgm_time_t pgm_timer_expiration (pgm_sock_t*const);
+PGM_GNUC_INTERNAL bool pgm_timer_dispatch (pgm_sock_t*const);
+
+static inline
+void
+pgm_timer_lock (
+ pgm_sock_t* const sock
+ )
+{
+ if (sock->can_send_data)
+ pgm_mutex_lock (&sock->timer_mutex);
+}
+
+static inline
+void
+pgm_timer_unlock (
+ pgm_sock_t* const sock
+ )
+{
+ if (sock->can_send_data)
+ pgm_mutex_unlock (&sock->timer_mutex);
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_TIMER_H__ */
+
diff --git a/src/pgm/impl/tsi.h b/src/pgm/impl/tsi.h
new file mode 100644
index 0000000..fe7dcdf
--- /dev/null
+++ b/src/pgm/impl/tsi.h
@@ -0,0 +1,42 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * transport session ID helper functions
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_TSI_H__
+#define __PGM_IMPL_TSI_H__
+
+#include <pgm/types.h>
+#include <pgm/tsi.h>
+#include <impl/hashtable.h>
+
+PGM_BEGIN_DECLS
+
+PGM_GNUC_INTERNAL pgm_hash_t pgm_tsi_hash (const void*) PGM_GNUC_WARN_UNUSED_RESULT;
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_TSI_H__ */
diff --git a/src/pgm/impl/txw.h b/src/pgm/impl/txw.h
new file mode 100644
index 0000000..2ffcb8a
--- /dev/null
+++ b/src/pgm/impl/txw.h
@@ -0,0 +1,202 @@
+/* vim:ts=8:sts=4:sw=4:noai:noexpandtab
+ *
+ * basic transmit window.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_TXW_H__
+#define __PGM_IMPL_TXW_H__
+
+typedef struct pgm_txw_state_t pgm_txw_state_t;
+typedef struct pgm_txw_t pgm_txw_t;
+
+#include <impl/framework.h>
+
+PGM_BEGIN_DECLS
+
+/* must be smaller than PGM skbuff control buffer */
+struct pgm_txw_state_t {
+ uint32_t unfolded_checksum; /* first 32-bit word must be checksum */
+
+ unsigned waiting_retransmit:1; /* in retransmit queue */
+ unsigned retransmit_count:15;
+ unsigned nak_elimination_count:16;
+
+ uint8_t pkt_cnt_requested; /* # parity packets to send */
+ uint8_t pkt_cnt_sent; /* # parity packets already sent */
+};
+
+struct pgm_txw_t {
+ const pgm_tsi_t* restrict tsi;
+
+/* option: lockless atomics */
+ volatile uint32_t lead;
+ volatile uint32_t trail;
+
+ pgm_queue_t retransmit_queue;
+
+ pgm_rs_t rs;
+ uint8_t tg_sqn_shift;
+ struct pgm_sk_buff_t* restrict parity_buffer;
+
+/* Advance with data */
+ pgm_time_t adv_ivl_expiry;
+ unsigned increment_window_naks;
+ unsigned adv_secs; /* TXW_ADV_SECS */
+ unsigned adv_sqns; /* TXW_ADV_SECS in sequences */
+
+ unsigned is_fec_enabled:1;
+ unsigned adv_mode:1; /* 0 = advance by time, 1 = advance by data */
+
+ size_t size; /* window content size in bytes */
+ unsigned alloc; /* length of pdata[] */
+/* C90 and older */
+ struct pgm_sk_buff_t* pdata[1];
+};
+
+PGM_GNUC_INTERNAL pgm_txw_t* pgm_txw_create (const pgm_tsi_t*const, const uint16_t, const uint32_t, const unsigned, const ssize_t, const bool, const uint8_t, const uint8_t) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_txw_shutdown (pgm_txw_t*const);
+PGM_GNUC_INTERNAL void pgm_txw_add (pgm_txw_t*const restrict, struct pgm_sk_buff_t*const restrict);
+PGM_GNUC_INTERNAL struct pgm_sk_buff_t* pgm_txw_peek (const pgm_txw_t*const, const uint32_t) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL bool pgm_txw_retransmit_push (pgm_txw_t*const, const uint32_t, const bool, const uint8_t) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL struct pgm_sk_buff_t* pgm_txw_retransmit_try_peek (pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+PGM_GNUC_INTERNAL void pgm_txw_retransmit_remove_head (pgm_txw_t*const);
+PGM_GNUC_INTERNAL uint32_t pgm_txw_get_unfolded_checksum (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE;
+PGM_GNUC_INTERNAL void pgm_txw_set_unfolded_checksum (struct pgm_sk_buff_t*const, const uint32_t);
+PGM_GNUC_INTERNAL void pgm_txw_inc_retransmit_count (struct pgm_sk_buff_t*const);
+PGM_GNUC_INTERNAL bool pgm_txw_retransmit_is_empty (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+
+/* declare for GCC attributes */
+static inline size_t pgm_txw_max_length (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline uint32_t pgm_txw_length (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline size_t pgm_txw_size (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline bool pgm_txw_is_empty (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline bool pgm_txw_is_full (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline uint32_t pgm_txw_lead (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline uint32_t pgm_txw_lead_atomic (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline uint32_t pgm_txw_next_lead (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline uint32_t pgm_txw_trail (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT;
+static inline uint32_t pgm_txw_trail_atomic (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT;
+
+static inline
+size_t
+pgm_txw_max_length (
+ const pgm_txw_t*const window
+ )
+{
+ pgm_assert (NULL != window);
+ return window->alloc;
+}
+
+static inline
+uint32_t
+pgm_txw_length (
+ const pgm_txw_t*const window
+ )
+{
+ pgm_assert (NULL != window);
+ return ( 1 + window->lead ) - window->trail;
+}
+
+static inline
+size_t
+pgm_txw_size (
+ const pgm_txw_t*const window
+ )
+{
+ pgm_assert (NULL != window);
+ return window->size;
+}
+
+static inline
+bool
+pgm_txw_is_empty (
+ const pgm_txw_t*const window
+ )
+{
+ pgm_assert (NULL != window);
+ return (0 == pgm_txw_length (window));
+}
+
+static inline
+bool
+pgm_txw_is_full (
+ const pgm_txw_t*const window
+ )
+{
+ pgm_assert (NULL != window);
+ return (pgm_txw_length (window) == pgm_txw_max_length (window));
+}
+
+static inline
+uint32_t
+pgm_txw_lead (
+ const pgm_txw_t*const window
+ )
+{
+ pgm_assert (NULL != window);
+ return window->lead;
+}
+
+/* atomics may rely on global variables and so cannot be defined __pure__ */
+static inline
+uint32_t
+pgm_txw_lead_atomic (
+ const pgm_txw_t*const window
+ )
+{
+ pgm_assert (NULL != window);
+ return pgm_atomic_read32 (&window->lead);
+}
+
+static inline
+uint32_t
+pgm_txw_next_lead (
+ const pgm_txw_t*const window
+ )
+{
+ pgm_assert (NULL != window);
+ return (uint32_t)(pgm_txw_lead (window) + 1);
+}
+
+static inline
+uint32_t
+pgm_txw_trail (
+ const pgm_txw_t*const window
+ )
+{
+ pgm_assert (NULL != window);
+ return window->trail;
+}
+
+static inline
+uint32_t
+pgm_txw_trail_atomic (
+ const pgm_txw_t*const window
+ )
+{
+ pgm_assert (NULL != window);
+ return pgm_atomic_read32 (&window->trail);
+}
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_TXW_H__ */
diff --git a/src/pgm/impl/wsastrerror.h b/src/pgm/impl/wsastrerror.h
new file mode 100644
index 0000000..ecb8543
--- /dev/null
+++ b/src/pgm/impl/wsastrerror.h
@@ -0,0 +1,40 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * Winsock Error strings.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION)
+# error "Only <framework.h> can be included directly."
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+#ifndef __PGM_IMPL_WSASTRERROR_H__
+#define __PGM_IMPL_WSASTRERROR_H__
+
+#include <pgm/types.h>
+
+PGM_BEGIN_DECLS
+
+char* pgm_wsastrerror (const int);
+char* pgm_adapter_strerror (const int);
+char* pgm_win_strerror (char*, size_t, const int);
+
+PGM_END_DECLS
+
+#endif /* __PGM_IMPL_WSASTRERROR_H__ */
diff --git a/src/pgm/indextoaddr.c b/src/pgm/indextoaddr.c
index a2cf434..9c28664 100644
--- a/src/pgm/indextoaddr.c
+++ b/src/pgm/indextoaddr.c
@@ -1,6 +1,8 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * portable interface index to socket address function.
+ * Portable interface index to socket address function. The underlying
+ * socket implementation may manage separate numerical spaces for each
+ * address family.
*
* Copyright (c) 2006-2011 Miru Limited.
*
@@ -19,6 +21,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/i18n.h>
#include <impl/framework.h>
diff --git a/src/pgm/indextoname.c b/src/pgm/indextoname.c
index 3b11cb9..9e51545 100644
--- a/src/pgm/indextoname.c
+++ b/src/pgm/indextoname.c
@@ -1,6 +1,8 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * Windows interface index to interface name function.
+ * Interface index to interface name function. Defined as part of RFC2553
+ * for IPv6 basic socket extensions, but also available for IPv4 addresses
+ * on many platforms.
*
* Copyright (c) 2006-2011 Miru Limited.
*
@@ -19,6 +21,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#ifdef _WIN32
# include <ws2tcpip.h>
# include <iphlpapi.h>
@@ -35,9 +40,14 @@ pgm_if_indextoname (
char* ifname
)
{
-#ifndef _WIN32
+#if !defined( _WIN32 )
+/* Vista+ implements if_indextoname for IPv6 */
return if_indextoname (ifindex, ifname);
#else
+/* Windows maintains a few different numbers for each interface, the
+ * number returned by GetIfEntry has shown to be the same as that
+ * determined by GetAdaptersAddresses and GetAdaptersInfo.
+ */
pgm_return_val_if_fail (NULL != ifname, NULL);
MIB_IFROW ifRow = { .dwIndex = ifindex };
diff --git a/src/pgm/inet_network.c b/src/pgm/inet_network.c
index 820deba..030fd40 100644
--- a/src/pgm/inet_network.c
+++ b/src/pgm/inet_network.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <ctype.h>
#include <impl/framework.h>
diff --git a/src/pgm/list.c b/src/pgm/list.c
index 345f3cf..a25305b 100644
--- a/src/pgm/list.c
+++ b/src/pgm/list.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
diff --git a/src/pgm/math.c b/src/pgm/math.c
index c2a1b4e..2543245 100644
--- a/src/pgm/math.c
+++ b/src/pgm/math.c
@@ -2,7 +2,7 @@
*
* portable math.
*
- * Copyright (c) 2010 Miru Limited.
+ * Copyright (c) 2010-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
diff --git a/src/pgm/md5.c b/src/pgm/md5.c
index 185eb2f..ef9ca1c 100644
--- a/src/pgm/md5.c
+++ b/src/pgm/md5.c
@@ -23,6 +23,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
diff --git a/src/pgm/mem.c b/src/pgm/mem.c
index b4adcf0..5697baf 100644
--- a/src/pgm/mem.c
+++ b/src/pgm/mem.c
@@ -1,6 +1,8 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * portable fail fast memory allocation.
+ * Portable fail fast memory allocation.
+ *
+ * Run with PGM_DEBUG=gc-friendly to appease most memory profilers.
*
* Copyright (c) 2010-2011 Miru Limited.
*
@@ -19,6 +21,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <ctype.h>
#include <stdio.h>
#include <string.h>
@@ -93,7 +98,7 @@ pgm_parse_debug_string (
}
else
{
- while (string) {
+ while (*string) {
const char* q = strpbrk (string, ":;, \t");
if (!q)
q = string + strlen (string);
diff --git a/src/pgm/messages.c b/src/pgm/messages.c
index f5b3c3f..7b2557d 100644
--- a/src/pgm/messages.c
+++ b/src/pgm/messages.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <stdarg.h>
#include <stdio.h>
#ifndef _WIN32
diff --git a/src/pgm/nametoindex.c b/src/pgm/nametoindex.c
index ac8abbb..fd7a7de 100644
--- a/src/pgm/nametoindex.c
+++ b/src/pgm/nametoindex.c
@@ -1,6 +1,7 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * Windows interface name to interface index function.
+ * Interface name to interface index function. Defined as part of RFC2553
+ * for IPv6 basic socket extensions.
*
* Copyright (c) 2006-2011 Miru Limited.
*
@@ -19,6 +20,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#ifdef _WIN32
# include <ws2tcpip.h>
# include <iphlpapi.h>
@@ -40,7 +44,7 @@ _pgm_heap_alloc (
const size_t n_bytes
)
{
-# ifdef CONFIG_USE_HEAPALLOC
+# ifdef USE_HEAPALLOC
return HeapAlloc (GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, n_bytes);
# else
return pgm_malloc (n_bytes);
@@ -53,7 +57,7 @@ _pgm_heap_free (
void* mem
)
{
-# ifdef CONFIG_USE_HEAPALLOC
+# ifdef USE_HEAPALLOC
HeapFree (GetProcessHeap(), 0, mem);
# else
pgm_free (mem);
@@ -65,6 +69,8 @@ _pgm_heap_free (
* adapters via GetAdaptersInfo().
*
* On error returns zero, no errors are defined.
+ *
+ * Requires Windows 2000 or Wine 1.0.
*/
static
@@ -144,6 +150,8 @@ _pgm_getadaptersinfo_nametoindex (
* adapters via GetAdaptersAddresses().
*
* On error returns zero, no errors are defined.
+ *
+ * Requires Windows XP or Wine 1.3.
*/
static
@@ -241,9 +249,8 @@ pgm_if_nametoindex (
pgm_return_val_if_fail (NULL != ifname, 0);
#ifndef _WIN32
+/* Vista+ implements if_nametoindex for IPv6 */
return if_nametoindex (ifname);
-#elif defined(CONFIG_TARGET_WINE)
- return _pgm_getadaptersinfo_nametoindex (iffamily, ifname);
#else
return _pgm_getadaptersaddresses_nametoindex (iffamily, ifname);
#endif
diff --git a/src/pgm/net.c b/src/pgm/net.c
index d1a75c5..17e7cdc 100644
--- a/src/pgm/net.c
+++ b/src/pgm/net.c
@@ -19,8 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <errno.h>
-#ifdef CONFIG_HAVE_POLL
+#ifdef HAVE_POLL
# include <poll.h>
#endif
#ifndef _WIN32
@@ -113,7 +116,7 @@ pgm_sendto_hops (
save_errno != PGM_SOCK_EHOSTUNREACH && /* No route to host */
save_errno != PGM_SOCK_EAGAIN)) /* would block on non-blocking send */
{
-#ifdef CONFIG_HAVE_POLL
+#ifdef HAVE_POLL
/* poll for cleared socket */
struct pollfd p = {
.fd = send_sock,
@@ -135,7 +138,7 @@ pgm_sendto_hops (
.tv_usec = 500 /* ms */ * 1000
};
const int ready = select (n_fds, NULL, &writefds, NULL, &tv);
-#endif /* CONFIG_HAVE_POLL */
+#endif /* HAVE_POLL */
if (ready > 0)
{
sent = sendto (send_sock, buf, len, 0, to, (socklen_t)tolen);
diff --git a/src/pgm/packet_parse.c b/src/pgm/packet_parse.c
index 49213ea..b25d7d8 100644
--- a/src/pgm/packet_parse.c
+++ b/src/pgm/packet_parse.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/i18n.h>
#include <impl/framework.h>
#include <impl/packet_parse.h>
@@ -152,7 +155,7 @@ pgm_parse_raw (
return FALSE;
}
-#ifndef CONFIG_HOST_ORDER_IP_LEN
+#ifndef HAVE_HOST_ORDER_IP_LEN
size_t packet_length = ntohs (ip->ip_len); /* total packet length */
#else
size_t packet_length = ip->ip_len; /* total packet length */
@@ -193,7 +196,7 @@ pgm_parse_raw (
#endif
/* fragmentation offset, bit 0: 0, bit 1: do-not-fragment, bit 2: more-fragments */
-#ifndef CONFIG_HOST_ORDER_IP_OFF
+#ifndef HAVE_HOST_ORDER_IP_OFF
const uint16_t offset = ntohs (ip->ip_off);
#else
const uint16_t offset = ip->ip_off;
diff --git a/src/pgm/packet_test.c b/src/pgm/packet_test.c
index e9ddc69..26bc518 100644
--- a/src/pgm/packet_test.c
+++ b/src/pgm/packet_test.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <ctype.h>
#include <stdio.h>
#ifndef _WIN32
diff --git a/src/pgm/queue.c b/src/pgm/queue.c
index 88bd088..11e1c31 100644
--- a/src/pgm/queue.c
+++ b/src/pgm/queue.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
diff --git a/src/pgm/rand.c b/src/pgm/rand.c
index 0a40f70..6820e91 100644
--- a/src/pgm/rand.c
+++ b/src/pgm/rand.c
@@ -1,6 +1,7 @@
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
*
- * portable weak pseudo-random generator.
+ * Portable weak pseudo-random generator. Performance is explicitly
+ * chosen in preference to randomness.
*
* Copyright (c) 2010-2011 Miru Limited.
*
@@ -19,6 +20,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#ifndef _WIN32
# include <errno.h>
# include <stdio.h>
@@ -72,7 +76,7 @@ pgm_rand_create (
FILE* fp;
do {
fp = fopen ("/dev/urandom", "rb");
- } while (PGM_UNLIKELY(EINTR == errno));
+ } while (PGM_UNLIKELY(NULL == fp && EINTR == errno));
if (fp) {
size_t items_read;
do {
diff --git a/src/pgm/rate_control.c b/src/pgm/rate_control.c
index 9dc5224..f3a0752 100644
--- a/src/pgm/rate_control.c
+++ b/src/pgm/rate_control.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
diff --git a/src/pgm/receiver.c b/src/pgm/receiver.c
index b3215b6..762cd9e 100644
--- a/src/pgm/receiver.c
+++ b/src/pgm/receiver.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <errno.h>
#include <impl/i18n.h>
#include <impl/framework.h>
@@ -2166,7 +2169,7 @@ pgm_on_data (
0;
/* advance data pointer to payload */
- pgm_skb_pull (skb, sizeof(struct pgm_data) + opt_total_length);
+ pgm_skb_pull (skb, (uint16_t)(sizeof(struct pgm_data) + opt_total_length));
if (opt_total_length > 0 && /* there are options */
get_pgm_options (skb) && /* valid options */
diff --git a/src/pgm/recv.c b/src/pgm/recv.c
index db7c4e0..18980a6 100644
--- a/src/pgm/recv.c
+++ b/src/pgm/recv.c
@@ -2,7 +2,7 @@
*
* Transport recv API.
*
- * Copyright (c) 2006-2010 Miru Limited.
+ * Copyright (c) 2006-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
@@ -60,7 +64,7 @@
# define PGM_CMSG_LEN(len) WSA_CMSG_LEN(len)
#endif
-#ifdef CONFIG_HAVE_WSACMSGHDR
+#ifdef HAVE_WSACMSGHDR
# ifdef __GNU__
/* as listed in MSDN */
# define pgm_cmsghdr wsacmsghdr
@@ -103,18 +107,12 @@ recvskb (
if (PGM_UNLIKELY(sock->is_destroyed))
return 0;
-#ifdef CONFIG_TARGET_WINE
- socklen_t fromlen = src_addrlen;
- const ssize_t len = recvfrom (sock->recv_sock, skb->head, sock->max_tpdu, 0, src_addr, &fromlen);
- if (len <= 0)
- return len;
-#else
struct pgm_iovec iov = {
.iov_base = skb->head,
.iov_len = sock->max_tpdu
};
char aux[ 1024 ];
-# ifndef _WIN32
+#ifndef _WIN32
struct msghdr msg = {
.msg_name = src_addr,
.msg_namelen = src_addrlen,
@@ -127,7 +125,7 @@ recvskb (
ssize_t len = recvmsg (sock->recv_sock, &msg, flags);
if (len <= 0)
return len;
-# else /* !_WIN32 */
+#else /* !_WIN32 */
WSAMSG msg = {
.name = (LPSOCKADDR)src_addr,
.namelen = src_addrlen,
@@ -141,8 +139,7 @@ recvskb (
if (SOCKET_ERROR == pgm_WSARecvMsg (sock->recv_sock, &msg, &len, NULL, NULL)) {
return SOCKET_ERROR;
}
-# endif /* !_WIN32 */
-#endif /* !CONFIG_TARGET_WINE */
+#endif /* !_WIN32 */
#ifdef PGM_DEBUG
if (PGM_UNLIKELY(pgm_loss_rate > 0)) {
@@ -162,10 +159,6 @@ recvskb (
skb->zero_padded = 0;
skb->tail = (char*)skb->data + len;
-#ifdef CONFIG_TARGET_WINE
- pgm_assert (pgm_sockaddr_len (&sock->recv_gsr[0].gsr_group) <= dst_addrlen);
- memcpy (dst_addr, &sock->recv_gsr[0].gsr_group, pgm_sockaddr_len (&sock->recv_gsr[0].gsr_group));
-#else
if (sock->udp_encap_ucast_port ||
AF_INET6 == pgm_sockaddr_family (src_addr))
{
@@ -240,7 +233,6 @@ recvskb (
}
}
}
-#endif
return len;
}
@@ -493,7 +485,7 @@ on_downstream (
memcpy (&(*source)->group_nla, dst_addr, pgm_sockaddr_len(dst_addr));
break;
-#ifdef CONFIG_PGM_POLLING
+#ifdef USE_PGM_PROTOCOL_POLL
case PGM_POLL:
if (PGM_UNLIKELY(!pgm_on_poll (sock, *source, skb)))
goto out_discarded;
@@ -588,7 +580,7 @@ wait_for_event (
/* tight loop on blocked send */
pgm_on_deferred_nak (sock);
-#ifdef CONFIG_HAVE_POLL
+#ifdef HAVE_POLL
struct pollfd fds[ n_fds ];
memset (fds, 0, sizeof(fds));
const int status = pgm_poll_info (sock, fds, &n_fds, POLLIN);
@@ -598,7 +590,7 @@ wait_for_event (
FD_ZERO(&readfds);
const int status = pgm_select_info (sock, &readfds, NULL, &n_fds);
pgm_assert (-1 != status);
-#endif /* CONFIG_HAVE_POLL */
+#endif /* HAVE_POLL */
/* flush any waiting notifications */
if (sock->is_pending_read) {
@@ -612,7 +604,7 @@ wait_for_event (
else
timeout = (int)pgm_timer_expiration (sock);
-#ifdef CONFIG_HAVE_POLL
+#ifdef HAVE_POLL
const int ready = poll (fds, n_fds, timeout /* μs */ / 1000 /* to ms */);
#else
struct timeval tv_timeout = {
@@ -620,7 +612,7 @@ wait_for_event (
.tv_usec = timeout > 1000000L ? (timeout % 1000000L) : timeout
};
const int ready = select (n_fds, &readfds, NULL, NULL, &tv_timeout);
-#endif
+#endif /* HAVE_POLL */
if (PGM_UNLIKELY(SOCKET_ERROR == ready)) {
pgm_debug ("block returned errno=%i",errno);
return EFAULT;
diff --git a/src/pgm/reed_solomon.c b/src/pgm/reed_solomon.c
index 6a2d179..7a6ce4a 100644
--- a/src/pgm/reed_solomon.c
+++ b/src/pgm/reed_solomon.c
@@ -24,6 +24,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
@@ -47,7 +50,7 @@ _pgm_gf_vec_addmul (
if (PGM_UNLIKELY(b == 0))
return;
-#ifdef CONFIG_GALOIS_MUL_LUT
+#ifdef USE_GALOIS_MUL_LUT
const pgm_gf8_t* gfmul_b = &pgm_gftable[ (uint16_t)b << 8 ];
#endif
@@ -56,7 +59,7 @@ _pgm_gf_vec_addmul (
if (count8)
{
while (count8--) {
-#ifdef CONFIG_GALOIS_MUL_LUT
+#ifdef USE_GALOIS_MUL_LUT
d[i ] ^= gfmul_b[ s[i ] ];
d[i+1] ^= gfmul_b[ s[i+1] ];
d[i+2] ^= gfmul_b[ s[i+2] ];
@@ -83,7 +86,7 @@ _pgm_gf_vec_addmul (
}
while (len--) {
-#ifdef CONFIG_GALOIS_MUL_LUT
+#ifdef USE_GALOIS_MUL_LUT
d[i] ^= gfmul_b[ s[i] ];
#else
d[i] ^= gfmul( b, s[i] );
@@ -130,7 +133,7 @@ _pgm_matmul (
/* Generic square matrix inversion
*/
-#ifdef CONFIG_XOR_SWAP
+#ifdef USE_XOR_SWAP
/* whilst cute the xor swap is quite slow */
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
#else
@@ -360,7 +363,7 @@ pgm_rs_create (
*
* Be careful, Harry!
*/
-#ifdef CONFIG_PREFER_MALLOC
+#ifdef USE_MALLOC_MATRIX
pgm_gf8_t* V = pgm_new0 (pgm_gf8_t, n * k);
#else
pgm_gf8_t* V = pgm_newa (pgm_gf8_t, n * k);
@@ -398,7 +401,7 @@ pgm_rs_create (
*/
_pgm_matmul (V_kn, V_kk, rs->GM + (k * k), n - k, k, k);
-#ifdef CONFIG_PREFER_MALLOC
+#ifdef USE_MALLOC_MATRIX
pgm_free (V);
#endif
@@ -498,7 +501,7 @@ pgm_rs_decode_parity_inline (
if (offsets[ j ] < rs->k)
continue;
-#ifdef CONFIG_PREFER_MALLOC
+#ifdef USE_MALLOC_MATRIX
pgm_gf8_t* erasure = repairs[ j ] = pgm_malloc0 (len);
#else
pgm_gf8_t* erasure = repairs[ j ] = pgm_alloca (len);
@@ -519,7 +522,7 @@ pgm_rs_decode_parity_inline (
continue;
memcpy (block[ j ], repairs[ j ], len * sizeof(pgm_gf8_t));
-#ifdef CONFIG_PREFER_MALLOC
+#ifdef USE_MALLOC_MATRIX
pgm_free (repairs[ j ]);
#endif
}
diff --git a/src/pgm/rxw.c b/src/pgm/rxw.c
index 8f1b26a..7a0a2c6 100644
--- a/src/pgm/rxw.c
+++ b/src/pgm/rxw.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/i18n.h>
#include <impl/framework.h>
#include <impl/rxw.h>
@@ -326,7 +329,7 @@ pgm_rxw_add (
/* protocol sanity check: valid trail pointer wrt. sequence */
if (PGM_UNLIKELY(skb->sequence - ntohl (skb->pgm_data->data_trail) >= ((UINT32_MAX/2)-1)))
- return PGM_RXW_MALFORMED;
+ return PGM_RXW_BOUNDS;
/* verify fragment header for original data, parity packets include a
* parity fragment header
diff --git a/src/pgm/skbuff.c b/src/pgm/skbuff.c
index a791194..ff08de9 100644
--- a/src/pgm/skbuff.c
+++ b/src/pgm/skbuff.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
#include "pgm/skbuff.h"
diff --git a/src/pgm/slist.c b/src/pgm/slist.c
index 4b0d8f5..1ff45bc 100644
--- a/src/pgm/slist.c
+++ b/src/pgm/slist.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/framework.h>
diff --git a/src/pgm/sockaddr.c b/src/pgm/sockaddr.c
index c53c959..503f7dc 100644
--- a/src/pgm/sockaddr.c
+++ b/src/pgm/sockaddr.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <errno.h>
#ifndef _WIN32
# include <sys/socket.h>
@@ -28,24 +31,35 @@
/* FreeBSD */
-#ifndef IPV6_ADD_MEMBERSHIP
-# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
-# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+#if !defined( IPV6_ADD_MEMBERSHIP )
+# if defined( IPV6_JOIN_GROUP )
+# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+# else
+# error "Neither IPV6_ADD_MEMBERSHIP or IPV6_JOIN_GROUP defined."
+# endif
#endif
/* OpenSolaris differences */
-#if !defined(_WIN32) && !defined(MCAST_MSFILTER)
+#if !defined( _WIN32 ) && !defined( MCAST_MSFILTER )
# include <sys/ioctl.h>
#endif
-#ifndef SOL_IP
+#if !defined( SOL_IP )
+/* IPPROTO_IP is often an enum value whilst SOL_IP is a pre-processor definition */
# define SOL_IP IPPROTO_IP
#endif
-#ifndef SOL_IPV6
+#if !defined( SOL_IPV6 )
# define SOL_IPV6 IPPROTO_IPV6
#endif
#ifndef IP_MAX_MEMBERSHIPS
+/* NB: New platforms may have very high membership limit but not exported for evaluation. */
# define IP_MAX_MEMBERSHIPS 20
#endif
+static uint8_t pgm_in_mask2len (const struct in_addr*);
+static uint8_t pgm_in6_mask2len (const struct in6_addr*);
+static void pgm_in_len2mask (const uint8_t, struct in_addr*);
+
+
PGM_GNUC_INTERNAL
sa_family_t
pgm_sockaddr_family (
@@ -114,6 +128,89 @@ pgm_sockaddr_storage_len (
return ss_len;
}
+static
+uint8_t
+pgm_in_mask2len (
+ const struct in_addr* mask
+ )
+{
+ unsigned x, y;
+ const uint8_t* p;
+
+ p = (const uint8_t*)mask;
+ for (x = 0; x < sizeof (*mask); x++) {
+ if (p[x] != 0xff)
+ break;
+ }
+ y = 0;
+ if (x < sizeof (*mask)) {
+ for (y = 0; y < 8; y++) {
+ if ((p[x] & (0x80 >> y)) == 0)
+ break;
+ }
+ }
+ return x * 8 + y;
+}
+
+static
+uint8_t
+pgm_in6_mask2len (
+ const struct in6_addr* mask
+ )
+{
+ unsigned x, y;
+ const uint8_t* p;
+
+ p = (const uint8_t*)mask;
+ for (x = 0; x < sizeof (*mask); x++) {
+ if (p[x] != 0xff)
+ break;
+ }
+ y = 0;
+ if (x < sizeof (*mask)) {
+ for (y = 0; y < 8; y++) {
+ if ((p[x] & (0x80 >> y)) == 0)
+ break;
+ }
+ }
+ return x * 8 + y;
+}
+
+PGM_GNUC_INTERNAL
+uint8_t
+pgm_sockaddr_prefixlen (
+ const struct sockaddr* sa
+ )
+{
+ if (AF_INET6 == sa->sa_family) {
+ struct sockaddr_in6 s6;
+ memcpy (&s6, sa, sizeof(s6));
+ return pgm_in6_mask2len (&s6.sin6_addr);
+ } else {
+ struct sockaddr_in s4;
+ memcpy (&s4, sa, sizeof(s4));
+ return pgm_in_mask2len (&s4.sin_addr);
+ }
+}
+
+static
+void
+pgm_in_len2mask (
+ const uint8_t prefixlen,
+ struct in_addr* mask
+ )
+{
+ unsigned i;
+ uint8_t* p;
+
+ p = (uint8_t*)mask;
+ memset (mask, sizeof (*mask), 0);
+ for (i = 0; i < prefixlen / 8; i++)
+ p[i] = 0xff;
+ if (prefixlen % 8)
+ p[i] = (0xff00 >> (prefixlen % 8)) & 0xff;
+}
+
PGM_GNUC_INTERNAL
uint32_t
pgm_sockaddr_scope_id (
@@ -399,6 +496,10 @@ pgm_sockaddr_pktinfo (
* If no error occurs, pgm_sockaddr_router_alert returns zero. Otherwise, a
* value of SOCKET_ERROR is returned, and a specific error code can be
* retrieved by calling pgm_get_last_sock_error().
+ *
+ * The IP_ROUTER_ALERT option is not applicable here despite the name, it is
+ * for signaling a locally running router and does not alter the IP header of
+ * transmitted packets.
*/
PGM_GNUC_INTERNAL
@@ -410,28 +511,8 @@ pgm_sockaddr_router_alert (
)
{
int retval = SOCKET_ERROR;
-#ifdef CONFIG_IP_ROUTER_ALERT
-/* Linux:ip(7) "A boolean integer flag is zero when it is false, otherwise
- * true. Expects an integer flag."
- * Linux:ipv6(7) "Argument is a pointer to an integer."
- *
- * Sent on special queue to rsvpd on Linux and so best avoided.
- */
- const int optval = v ? 1 : 0;
- switch (sa_family) {
- case AF_INET:
- retval = setsockopt (s, IPPROTO_IP, IP_ROUTER_ALERT, (const char*)&optval, sizeof (optval));
- break;
-
- case AF_INET6:
- retval = setsockopt (s, IPPROTO_IPV6, IPV6_ROUTER_ALERT, (const char*)&optval, sizeof (optval));
- break;
-
- default: break;
- }
-#else
-# if defined(CONFIG_HAVE_IPOPTION)
+#if defined( HAVE_STRUCT_IPOPTION )
/* NB: struct ipoption is not very portable and requires a lot of additional headers.
*/
const struct ipoption router_alert = {
@@ -439,17 +520,17 @@ pgm_sockaddr_router_alert (
.ipopt_list = { PGM_IPOPT_RA, 0x04, 0x00, 0x00 }
};
const int optlen = v ? sizeof (router_alert) : 0;
-# else
+#else
/* manually set the IP option */
-# ifndef _WIN32
- const int ipopt_ra = (PGM_IPOPT_RA << 24) | (0x04 << 16);
- const int router_alert = htonl (ipopt_ra);
-# else
- const DWORD ipopt_ra = (PGM_IPOPT_RA << 24) | (0x04 << 16);
+# ifndef _WIN32
+ const uint32_t ipopt_ra = ((uint32_t)PGM_IPOPT_RA << 24) | (0x04 << 16);
+ const uint32_t router_alert = htonl (ipopt_ra);
+# else
+ const DWORD ipopt_ra = ((DWORD)PGM_IPOPT_RA << 24) | (0x04 << 16);
const DWORD router_alert = htonl (ipopt_ra);
-# endif
- const int optlen = v ? sizeof (router_alert) : 0;
# endif
+ const int optlen = v ? sizeof (router_alert) : 0;
+#endif
switch (sa_family) {
case AF_INET:
@@ -462,7 +543,6 @@ pgm_sockaddr_router_alert (
default: break;
}
-#endif
return retval;
}
@@ -532,7 +612,7 @@ pgm_sockaddr_join_group (
)
{
int retval = SOCKET_ERROR;
-#ifdef CONFIG_HAVE_MCAST_JOIN
+#if defined( HAVE_STRUCT_GROUP_REQ ) || ( defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) )
/* Solaris:ip(7P) "The following options take a struct ip_mreq_source as the
* parameter." Presumably with source field zeroed out.
* Solaris:ip6(7P) "Takes a struct group_req as the parameter."
@@ -546,9 +626,12 @@ pgm_sockaddr_join_group (
* Stevens: "MCAST_JOIN_GROUP has datatype group_req{}."
*
* RFC3678: Argument type struct group_req
+ *
+ * Note that not all platforms with MCAST_JOIN_GROUP defined actually support the
+ * socket option, such that testing is deferred to Autoconf.
*/
const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6;
- retval = setsockopt (s, recv_level, MCAST_JOIN_GROUP, gr, sizeof(struct group_req));
+ retval = setsockopt (s, recv_level, MCAST_JOIN_GROUP, (const char*)gr, sizeof(struct group_req));
#else
switch (sa_family) {
case AF_INET: {
@@ -567,7 +650,7 @@ pgm_sockaddr_join_group (
*
* RFC3678: Argument type struct ip_mreq
*/
-#ifdef CONFIG_HAVE_IP_MREQN
+# ifdef HAVE_STRUCT_IP_MREQN
struct ip_mreqn mreqn;
struct sockaddr_in ifaddr;
memset (&mreqn, 0, sizeof(mreqn));
@@ -577,7 +660,7 @@ pgm_sockaddr_join_group (
mreqn.imr_address.s_addr = ifaddr.sin_addr.s_addr;
mreqn.imr_ifindex = gr->gr_interface;
retval = setsockopt (s, SOL_IP, IP_ADD_MEMBERSHIP, (const char*)&mreqn, sizeof(mreqn));
-#else
+# else
struct ip_mreq mreq;
struct sockaddr_in ifaddr;
memset (&mreq, 0, sizeof(mreq));
@@ -586,7 +669,7 @@ pgm_sockaddr_join_group (
return -1;
mreq.imr_interface.s_addr = ifaddr.sin_addr.s_addr;
retval = setsockopt (s, SOL_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq));
-#endif /* !CONFIG_HAVE_IP_MREQN */
+# endif /* !HAVE_STRUCT_IP_MREQN */
break;
}
@@ -611,7 +694,7 @@ pgm_sockaddr_join_group (
default: break;
}
-#endif /* CONFIG_HAVE_MCAST_JOIN */
+#endif /* HAVE_STRUCT_GROUP_REQ */
return retval;
}
@@ -627,13 +710,13 @@ pgm_sockaddr_leave_group (
)
{
int retval = SOCKET_ERROR;
-#ifdef CONFIG_HAVE_MCAST_JOIN
+#if defined( HAVE_STRUCT_GROUP_REQ ) || ( defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) )
const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6;
- retval = setsockopt (s, recv_level, MCAST_LEAVE_GROUP, gr, sizeof(struct group_req));
+ retval = setsockopt (s, recv_level, MCAST_LEAVE_GROUP, (const char*)gr, sizeof(struct group_req));
#else
switch (sa_family) {
case AF_INET: {
-#ifdef CONFIG_HAVE_IP_MREQN
+# ifdef HAVE_STRUCT_IP_MREQN
struct ip_mreqn mreqn;
struct sockaddr_in ifaddr;
memset (&mreqn, 0, sizeof(mreqn));
@@ -643,7 +726,7 @@ pgm_sockaddr_leave_group (
mreqn.imr_address.s_addr = ifaddr.sin_addr.s_addr;
mreqn.imr_ifindex = gr->gr_interface;
retval = setsockopt (s, SOL_IP, IP_DROP_MEMBERSHIP, (const char*)&mreqn, sizeof(mreqn));
-#else
+# else
struct ip_mreq mreq;
struct sockaddr_in ifaddr;
memset (&mreq, 0, sizeof(mreq));
@@ -652,7 +735,7 @@ pgm_sockaddr_leave_group (
return -1;
mreq.imr_interface.s_addr = ifaddr.sin_addr.s_addr;
retval = setsockopt (s, SOL_IP, IP_DROP_MEMBERSHIP, (const char*)&mreq, sizeof(mreq));
-#endif /* !CONFIG_HAVE_IP_MREQN */
+# endif /* !HAVE_STRUCT_IP_MREQN */
break;
}
@@ -667,7 +750,7 @@ pgm_sockaddr_leave_group (
default: break;
}
-#endif /* CONFIG_HAVE_MCAST_JOIN */
+#endif /* HAVE_STRUCT_GROUP_REQ */
return retval;
}
@@ -683,10 +766,10 @@ pgm_sockaddr_block_source (
)
{
int retval = SOCKET_ERROR;
-#ifdef CONFIG_HAVE_MCAST_JOIN
+#if defined( HAVE_STRUCT_GROUP_REQ ) || ( defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) )
const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6;
- retval = setsockopt (s, recv_level, MCAST_BLOCK_SOURCE, gsr, sizeof(struct group_source_req));
-#elif defined(IP_BLOCK_SOURCE)
+ retval = setsockopt (s, recv_level, MCAST_BLOCK_SOURCE, (const char*)gsr, sizeof(struct group_source_req));
+#elif defined( IP_BLOCK_SOURCE )
switch (sa_family) {
case AF_INET: {
struct ip_mreq_source mreqs;
@@ -708,11 +791,11 @@ pgm_sockaddr_block_source (
default: break;
}
#else
-/* unused parameters */
+/* unused parameters, operation not supported on this platform. */
(void)s;
(void)sa_family;
(void)gsr;
-#endif /* CONFIG_HAVE_MCAST_JOIN */
+#endif /* HAVE_STRUCT_GROUP_REQ */
return retval;
}
@@ -728,10 +811,10 @@ pgm_sockaddr_unblock_source (
)
{
int retval = SOCKET_ERROR;
-#ifdef CONFIG_HAVE_MCAST_JOIN
+#if defined( HAVE_STRUCT_GROUP_REQ ) || ( defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) )
const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6;
- retval = setsockopt (s, recv_level, MCAST_UNBLOCK_SOURCE, gsr, sizeof(struct group_source_req));
-#elif defined(IP_UNBLOCK_SOURCE)
+ retval = setsockopt (s, recv_level, MCAST_UNBLOCK_SOURCE, (const char*)gsr, sizeof(struct group_source_req));
+#elif defined( IP_UNBLOCK_SOURCE )
switch (sa_family) {
case AF_INET: {
struct ip_mreq_source mreqs;
@@ -757,7 +840,7 @@ pgm_sockaddr_unblock_source (
(void)s;
(void)sa_family;
(void)gsr;
-#endif /* CONFIG_HAVE_MCAST_JOIN */
+#endif /* HAVE_STRUCT_GROUP_REQ */
return retval;
}
@@ -778,7 +861,7 @@ pgm_sockaddr_join_source_group (
)
{
int retval = SOCKET_ERROR;
-#ifdef CONFIG_HAVE_MCAST_JOIN
+#if defined( HAVE_STRUCT_GROUP_REQ ) || ( defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) )
/* Solaris:ip(7P) "The following options take a struct ip_mreq_source as the
* parameter."
* Solaris:ip6(7P) "Takes a struct group_source_req as the parameter."
@@ -794,8 +877,8 @@ pgm_sockaddr_join_source_group (
* RFC3678: Argument type struct group_source_req
*/
const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6;
- retval = setsockopt (s, recv_level, MCAST_JOIN_SOURCE_GROUP, gsr, sizeof(struct group_source_req));
-#elif defined(IP_ADD_SOURCE_MEMBERSHIP)
+ retval = setsockopt (s, recv_level, MCAST_JOIN_SOURCE_GROUP, (const char*)gsr, sizeof(struct group_source_req));
+#elif defined( IP_ADD_SOURCE_MEMBERSHIP )
switch (sa_family) {
case AF_INET: {
/* Solaris:ip(7P) "The following options take a struct ip_mreq as the
@@ -832,7 +915,7 @@ pgm_sockaddr_join_source_group (
}
#else
retval = pgm_sockaddr_join_group (s, sa_family, (const struct group_req*)gsr);
-#endif /* CONFIG_HAVE_MCAST_JOIN */
+#endif /* HAVE_STRUCT_GROUP_REQ */
return retval;
}
@@ -848,10 +931,10 @@ pgm_sockaddr_leave_source_group (
)
{
int retval = SOCKET_ERROR;
-#ifdef CONFIG_HAVE_MCAST_JOIN
+#if defined( HAVE_STRUCT_GROUP_REQ ) || ( defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) )
const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6;
- retval = setsockopt (s, recv_level, MCAST_LEAVE_SOURCE_GROUP, gsr, sizeof(struct group_source_req));
-#elif defined(IP_ADD_SOURCE_MEMBERSHIP)
+ retval = setsockopt (s, recv_level, MCAST_LEAVE_SOURCE_GROUP, (const char*)gsr, sizeof(struct group_source_req));
+#elif defined( IP_ADD_SOURCE_MEMBERSHIP )
switch (sa_family) {
case AF_INET: {
struct ip_mreq_source mreqs;
@@ -875,11 +958,10 @@ pgm_sockaddr_leave_source_group (
}
#else
retval = pgm_sockaddr_leave_group (s, sa_family, (const struct group_req*)gsr);
-#endif /* CONFIG_HAVE_MCAST_JOIN */
+#endif /* HAVE_STRUCT_GROUP_REQ */
return retval;
}
-#if defined(MCAST_MSFILTER) || defined(SIOCSMSFILTER)
/* Batch block and unblock sources.
*/
@@ -892,18 +974,24 @@ pgm_sockaddr_msfilter (
)
{
int retval = SOCKET_ERROR;
-# ifdef MCAST_MSFILTER
+#if defined( MCAST_MSFILTER )
+/* Linux 2.6 API pre-empting RFC3678 naming scheme */
const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6;
const socklen_t len = GROUP_FILTER_SIZE(gf_list->gf_numsrc);
retval = setsockopt (s, recv_level, MCAST_MSFILTER, (const char*)gf_list, len);
-# elif defined(SIOCSMSFILTER)
-/* Windows Vista and later */
+#elif defined( _WIN32 ) && ( _WIN32_WINNT >= 0x600 )
+/* Windows Server 2008+, note MSDN(GROUP_FILTER Structure) does not list
+ * desktop support. This contrasts to MSDN(Final-State-Based Multicast Programming)
+ * which does list support for Vista+.
+ *
+ * RFC3678 API for struct group_filter.
+ */
const socklen_t len = GROUP_FILTER_SIZE(gf_list->gf_numsrc);
u_long* filter = pgm_alloca (len);
memcpy (filter, gf_list, len);
retval = ioctlsocket (s, SIOCSMSFILTER, filter);
-# elif defined(IP_MSFILTER) || defined(SIO_SET_MULTICAST_FILTER)
-/* IPv4-only filter API */
+#elif defined( HAVE_STRUCT_IP_MSFILTER )
+/* IPv4-only filter API alternative */
if (AF_INET == sa_family) {
const socklen_t len = IP_MSFILTER_SIZE(gf_list->gf_numsrc);
struct ip_msfilter* filter = pgm_alloca (len);
@@ -919,16 +1007,22 @@ pgm_sockaddr_msfilter (
memcpy (&sa4, &gf_list->gf_slist[i], sizeof (sa4));
filter->imsf_slist[i].s_addr = sa4.sin_addr.s_addr;
}
-# ifdef IP_MSFILTER
- retval = ioctlsocket (s, IP_MSFILTER, (char*)filter);
-# else
+# if defined( SIO_SET_MULTICAST_FILTER )
+/* Windows XP */
retval = ioctlsocket (s, SIO_SET_MULTICAST_FILTER, (u_long*)filter);
-# endif
- }
+# elif defined( SIOCSIPMSFILTER )
+/* RFC3678 API for struct ip_msfilter */
+ retval = ioctlsocket (s, SIOCSIPMSFILTER, (const char*)filter);
+# elif defined( IP_MSFILTER )
+/* NB: Windows SDK for Vista+ defines a typedef IP_MSFILTER */
+ retval = ioctlsocket (s, IP_MSFILTER, (const char*)filter);
+# else
+/* Cygwin has no socket option defined */
# endif
+ }
+#endif
return retval;
}
-#endif /* MCAST_MSFILTER || SIOCSMSFILTER */
/* Specify outgoing interface.
*
@@ -1072,6 +1166,8 @@ pgm_sockaddr_multicast_loop (
* If no error occurs, pgm_sockaddr_multicast_hops returns zero. Otherwise, a
* value of SOCKET_ERROR is returned, and a specific error code can be
* retrieved by calling pgm_get_last_sock_error().
+ *
+ * Requires Wine 1.3, supported in Windows 9x/Me.
*/
PGM_GNUC_INTERNAL
diff --git a/src/pgm/socket.c b/src/pgm/socket.c
index feebd43..12e2ede 100644
--- a/src/pgm/socket.c
+++ b/src/pgm/socket.c
@@ -3,7 +3,7 @@
* PGM socket: manage incoming & outgoing sockets with ambient SPMs,
* transmit & receive windows.
*
- * Copyright (c) 2006-2010 Miru Limited.
+ * Copyright (c) 2006-2011 Miru Limited.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,11 +20,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <errno.h>
-#ifdef CONFIG_HAVE_POLL
+#ifdef HAVE_POLL
# include <poll.h>
#endif
-#ifdef CONFIG_HAVE_EPOLL
+#ifdef HAVE_EPOLL_CTL
# include <sys/epoll.h>
#endif
#include <stdio.h>
@@ -506,8 +509,10 @@ pgm_socket (
}
#endif
-/* request extra packet information to determine destination address on each packet */
-#ifndef CONFIG_TARGET_WINE
+/* Request extra packet information to determine destination address on each packet
+ *
+ * Requires Windows XP or Wine 1.3.
+ */
pgm_trace (PGM_LOG_ROLE_NETWORK,_("Request socket packet-info."));
const sa_family_t recv_family = new_sock->family;
if (SOCKET_ERROR == pgm_sockaddr_pktinfo (new_sock->recv_sock, recv_family, TRUE))
@@ -521,7 +526,6 @@ pgm_socket (
pgm_sock_strerror_s (errbuf, sizeof (errbuf), save_errno));
goto err_destroy;
}
-#endif
}
else
{
@@ -1161,7 +1165,6 @@ pgm_setsockopt (
/* 0 < hops < 256, hops == -1 use kernel default (ignored).
*/
case PGM_MULTICAST_HOPS:
-#ifndef CONFIG_TARGET_WINE
if (PGM_UNLIKELY(optlen != sizeof (int)))
break;
if (PGM_UNLIKELY(*(const int*)optval <= 0))
@@ -1174,7 +1177,6 @@ pgm_setsockopt (
SOCKET_ERROR == pgm_sockaddr_multicast_hops (sock->send_with_router_alert_sock, sock->family, sock->hops))
break;
}
-#endif
status = TRUE;
break;
@@ -2148,7 +2150,7 @@ pgm_bind3 (
struct sockaddr_storage ss;
} recv_addr, recv_addr2, send_addr, send_with_router_alert_addr;
-#ifdef CONFIG_BIND_INADDR_ANY
+#ifdef USE_BIND_INADDR_ANY
/* force default interface for bind-only, source address is still valid for multicast membership.
* effectively same as running getaddrinfo(hints = {ai_flags = AI_PASSIVE})
*/
@@ -2175,7 +2177,7 @@ pgm_bind3 (
}
else if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK))
{
- if (AF_INET6 == sock_family)
+ if (AF_INET6 == sock->family)
pgm_trace (PGM_LOG_ROLE_NETWORK,_("Binding receive socket to interface index %u scope %u"),
recv_req->ir_interface,
recv_req->ir_scope_id);
@@ -2184,7 +2186,7 @@ pgm_bind3 (
recv_req->ir_interface);
}
-#endif /* CONFIG_BIND_INADDR_ANY */
+#endif /* USE_BIND_INADDR_ANY */
memcpy (&recv_addr2.sa, &recv_addr.sa, pgm_sockaddr_len (&recv_addr.sa));
@@ -2356,9 +2358,6 @@ pgm_connect (
{
pgm_return_val_if_fail (sock != NULL, FALSE);
pgm_return_val_if_fail (sock->recv_gsr_len > 0, FALSE);
-#ifdef CONFIG_TARGET_WINE
- pgm_return_val_if_fail (sock->recv_gsr_len == 1, FALSE);
-#endif
for (unsigned i = 0; i < sock->recv_gsr_len; i++)
{
pgm_return_val_if_fail (sock->recv_gsr[i].gsr_group.ss_family == sock->recv_gsr[0].gsr_group.ss_family, FALSE);
@@ -2526,7 +2525,9 @@ pgm_select_info (
#endif
}
-#if defined(CONFIG_HAVE_POLL) || defined(CONFIG_HAVE_WSAPOLL)
+#if defined( HAVE_POLL ) || ( defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) )
+/* Windows Vista supports WSAPoll() interface for compatibility with poll(). */
+
/* add poll parameters for the receive socket(s)
*
* returns number of pollfd structures filled.
@@ -2540,18 +2541,23 @@ pgm_select_info (
# define PGM_POLLOUT POLLWRNORM
#endif
+#ifndef _WIN32
int
pgm_poll_info (
pgm_sock_t* const restrict sock,
-#ifndef _WIN32
struct pollfd* const restrict fds,
int* const restrict n_fds, /* in: #fds, out: used #fds */
+ const short events /* POLLIN, POLLOUT */
+ )
#else
+int
+pgm_wsapoll_info (
+ pgm_sock_t* const restrict sock,
WSAPOLLFD* const restrict fds,
ULONG* const restrict n_fds,
-#endif
const short events /* POLLIN, POLLOUT */
)
+#endif
{
#ifndef _WIN32
int nfds = 0;
@@ -2606,7 +2612,7 @@ pgm_poll_info (
return *n_fds = nfds;
}
-#endif /* CONFIG_HAVE_POLL */
+#endif /* defined( HAVE_POLL ) || ( defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) ) */
/* add epoll parameters for the recieve socket(s), events should
* be set to EPOLLIN to wait for incoming events (data), and EPOLLOUT to wait
@@ -2614,7 +2620,7 @@ pgm_poll_info (
*
* returns 0 on success, -1 on failure and sets errno appropriately.
*/
-#ifdef CONFIG_HAVE_EPOLL
+#ifdef HAVE_EPOLL_CTL
int
pgm_epoll_ctl (
pgm_sock_t* const sock,
@@ -2692,7 +2698,7 @@ pgm_epoll_ctl (
out:
return retval;
}
-#endif
+#endif /* HAVE_EPOLL_CTL */
static
const char*
diff --git a/src/pgm/source.c b/src/pgm/source.c
index ed552da..62de45e 100644
--- a/src/pgm/source.c
+++ b/src/pgm/source.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <errno.h>
#include <impl/i18n.h>
#include <impl/framework.h>
@@ -56,6 +59,9 @@ _pgm_popcount (
{
#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
return __builtin_popcount (n);
+#elif defined(_MSC_VER)
+# include <intrin.h>
+ return __popcnt (n);
#else
/* MIT HAKMEM 169 */
const uint32_t t = n - ((n >> 1) & 033333333333)
diff --git a/src/pgm/string.c b/src/pgm/string.c
index f2b4ab4..effc4f4 100644
--- a/src/pgm/string.c
+++ b/src/pgm/string.c
@@ -19,12 +19,17 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#if defined(CONFIG_HAVE_VASPRINTF) && !defined(_GNU_SOURCE)
-# define _GNU_SOURCE
+#ifdef HAVE_CONFIG_H
+# include <config.h>
#endif
+
+#if ( defined( HAVE_VASPRINTF ) || defined( HAVE_STPCPY ) ) && !defined( _GNU_SOURCE )
+# define _GNU_SOURCE /* vasprintf, stpcpy */
+#endif
+
#include <limits.h>
#include <stdarg.h>
-#include <stdio.h> /* _GNU_SOURCE for vasprintf */
+#include <stdio.h>
#include <string.h>
#include <impl/framework.h>
@@ -65,6 +70,7 @@ pgm_printf_string_upper_bound (
va_list args
)
{
+/* MinGW family supports vsnprintf and so limit platform separation to MSVC. */
#ifdef _MSC_VER
return _vscprintf (format, args) + 1;
#else
@@ -88,7 +94,7 @@ pgm_vasprintf (
pgm_return_val_if_fail (string != NULL, -1);
-#ifdef CONFIG_HAVE_VASPRINTF
+#ifdef HAVE_VASPRINTF
char *strp;
len = vasprintf (&strp, format, args);
if (len < 0) {
@@ -105,9 +111,9 @@ pgm_vasprintf (
va_list args2;
va_copy (args2, args);
# endif
- *string = pgm_malloc (pgm_printf_string_upper_bound (format, args));
-/* NB: must be able to handle NULL args, fails on GCC */
- len = vsprintf (*string, format, args2);
+ len = pgm_printf_string_upper_bound (format, args);
+ *string = pgm_malloc (len);
+ len = pgm_vsnprintf_s (*string, len, _TRUNCATE, format, args2);
va_end (args2);
#endif
return len;
@@ -136,7 +142,7 @@ pgm_stpcpy (
pgm_return_val_if_fail (dest != NULL, NULL);
pgm_return_val_if_fail (src != NULL, NULL);
-#ifdef CONFIG_HAVE_STPCPY
+#ifdef HAVE_STPCPY
return stpcpy (dest, src);
#else
char *d = dest;
diff --git a/src/pgm/thread.c b/src/pgm/thread.c
index dbe318c..f3c655d 100644
--- a/src/pgm/thread.c
+++ b/src/pgm/thread.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <errno.h>
#include <impl/framework.h>
@@ -32,7 +35,8 @@ bool pgm_smp_system PGM_GNUC_READ_MOSTLY = TRUE;
/* Locals */
-#if defined(_WIN32) && !defined(CONFIG_HAVE_WIN_COND)
+#if defined( _WIN32 ) && !( _WIN32_WINNT >= 0x0600 )
+/* Condition variable implementation for Windows XP */
static DWORD cond_event_tls = TLS_OUT_OF_INDEXES;
#endif
@@ -90,9 +94,6 @@ static volatile uint32_t thread_ref_count = 0;
#endif /* !_WIN32 */
-/* only needed for Win32 pre-Vista read-write locks
- */
-
PGM_GNUC_INTERNAL
void
pgm_thread_init (void)
@@ -100,7 +101,8 @@ pgm_thread_init (void)
if (pgm_atomic_exchange_and_add32 (&thread_ref_count, 1) > 0)
return;
-#if defined(_WIN32) && !defined(CONFIG_HAVE_WIN_COND)
+#if defined( _WIN32 ) && !( _WIN32_WINNT >= 0x0600 )
+/* Condition variable implementation for Windows XP */
win32_check_cmd (TLS_OUT_OF_INDEXES != (cond_event_tls = TlsAlloc ()));
#endif
@@ -117,7 +119,8 @@ pgm_thread_shutdown (void)
if (pgm_atomic_exchange_and_add32 (&thread_ref_count, (uint32_t)-1) != 1)
return;
-#if defined(_WIN32) && !defined(CONFIG_HAVE_WIN_COND)
+#if defined( _WIN32 ) && !( _WIN32_WINNT >= 0x0600 )
+/* Condition variable implementation for Windows XP */
TlsFree (cond_event_tls);
#endif
}
@@ -147,7 +150,7 @@ pgm_mutex_init (
pthread_mutexattr_destroy (&attr);
#elif !defined( _WIN32 )
posix_check_cmd (pthread_mutex_init (&mutex->pthread_mutex, NULL));
-#elif defined(CONFIG_HAVE_CRITICAL_SECTION_EX)
+#elif ( _WIN32_WINNT >= 0x0600 )
/* reduce memory consumption on mutexes on Vista+ */
InitializeCriticalSectionEx (&mutex->win32_crit, PGM_ADAPTIVE_MUTEX_SPINCOUNT, CRITICAL_SECTION_NO_DEBUG_INFO);
#else
@@ -187,9 +190,9 @@ pgm_spinlock_init (
{
pgm_assert (NULL != spinlock);
-#ifdef CONFIG_TICKET_SPINLOCK
+#ifdef USE_TICKET_SPINLOCK
pgm_ticket_init (&spinlock->ticket_lock);
-#elif defined( CONFIG_HAVE_POSIX_SPINLOCK )
+#elif defined( HAVE_PTHREAD_SPINLOCK )
posix_check_cmd (pthread_spin_init (&spinlock->pthread_spinlock, PTHREAD_PROCESS_PRIVATE));
#elif defined( __APPLE__ )
spinlock->darwin_spinlock = OS_SPINLOCK_INIT;
@@ -206,12 +209,12 @@ pgm_spinlock_free (
{
pgm_assert (NULL != spinlock);
-#ifdef CONFIG_TICKET_SPINLOCK
+#ifdef USE_TICKET_SPINLOCK
pgm_ticket_free (&spinlock->ticket_lock);
-#elif defined( CONFIG_HAVE_POSIX_SPINLOCK )
+#elif defined( HAVE_PTHREAD_SPINLOCK )
/* ignore return value */
pthread_spin_destroy (&spinlock->pthread_spinlock);
-#elif defined(__APPLE__)
+#elif defined( __APPLE__ )
/* NOP */
#else /* Win32/GCC atomics */
/* NOP */
@@ -227,22 +230,19 @@ pgm_cond_init (
pgm_assert (NULL != cond);
#ifndef _WIN32
+/* POSIX implementation of condition variables */
posix_check_cmd (pthread_cond_init (&cond->pthread_cond, NULL));
-#elif defined(CONFIG_HAVE_WIN_COND)
-/* requires Vista+ */
+#elif ( _WIN32_WINNT >= 0x600 )
+/* Vista+ condition variables */
InitializeConditionVariable (&cond->win32_cond);
#else
+/* Condition variable implementation for Windows XP */
cond->len = 0;
cond->allocated_len = pgm_nearest_power (1, 2 + 1);
cond->phandle = pgm_new (HANDLE, cond->allocated_len);
-# if defined(CONFIG_HAVE_CRITICAL_SECTION_EX)
-/* requires Vista+ */
- InitializeCriticalSectionEx (&cond->win32_crit, PGM_ADAPTIVE_MUTEX_SPINCOUNT, CRITICAL_SECTION_NO_DEBUG_INFO);
-# else
InitializeCriticalSection (&cond->win32_crit);
SetCriticalSectionSpinCount (&cond->win32_crit, PGM_ADAPTIVE_MUTEX_SPINCOUNT);
-# endif
-#endif /* !_WIN32 */
+#endif /* ( _WIN32 < 0x600 ) */
}
PGM_GNUC_INTERNAL
@@ -254,10 +254,13 @@ pgm_cond_signal (
pgm_assert (NULL != cond);
#ifndef _WIN32
+/* POSIX implementation of condition variables */
pthread_cond_signal (&cond->pthread_cond);
-#elif defined(CONFIG_HAVE_WIN_COND)
+#elif ( _WIN32_WINNT >= 0x600 )
+/* Vista+ condition variables */
WakeConditionVariable (&cond->win32_cond);
#else
+/* Condition variable implementation for Windows XP */
EnterCriticalSection (&cond->win32_crit);
if (cond->len > 0) {
SetEvent (cond->phandle[ 0 ]);
@@ -265,7 +268,7 @@ pgm_cond_signal (
cond->len--;
}
LeaveCriticalSection (&cond->win32_crit);
-#endif /* !_WIN32 */
+#endif /* ( _WIN32 < 0x600 ) */
}
PGM_GNUC_INTERNAL
@@ -277,19 +280,23 @@ pgm_cond_broadcast (
pgm_assert (NULL != cond);
#ifndef _WIN32
+/* POSIX implementation of condition variables */
pthread_cond_broadcast (&cond->pthread_cond);
-#elif defined(CONFIG_HAVE_WIN_COND)
+#elif ( _WIN32_WINNT >= 0x600 )
+/* Vista+ condition variables */
WakeAllConditionVariable (&cond->win32_cond);
#else
+/* Condition variable implementation for Windows XP */
EnterCriticalSection (&cond->win32_crit);
for (unsigned i = 0; i < cond->len; i++)
SetEvent (cond->phandle[ i ]);
cond->len = 0;
LeaveCriticalSection (&cond->win32_crit);
-#endif /* !_WIN32 */
+#endif /* ( _WIN32 < 0x600 ) */
}
#ifndef _WIN32
+/* POSIX implementation of condition variables */
PGM_GNUC_INTERNAL
void
pgm_cond_wait (
@@ -303,6 +310,7 @@ pgm_cond_wait (
pthread_cond_wait (&cond->pthread_cond, mutex);
}
#else
+/* Windows implementation of condition variables */
PGM_GNUC_INTERNAL
void
pgm_cond_wait (
@@ -313,9 +321,11 @@ pgm_cond_wait (
pgm_assert (NULL != cond);
pgm_assert (NULL != spinlock);
-# if defined(CONFIG_HAVE_WIN_COND)
+# if ( _WIN32_WINNT >= 0x600 )
+/* Vista+ condition variables */
SleepConditionVariableCS (&cond->win32_cond, spinlock, INFINITE);
# else
+/* Condition variable implementation for Windows XP */
DWORD status;
HANDLE event = TlsGetValue (cond_event_tls);
@@ -350,9 +360,9 @@ pgm_cond_wait (
win32_check_cmd (WAIT_FAILED != (status = WaitForSingleObject (event, 0)));
LeaveCriticalSection (&cond->win32_crit);
}
-# endif /* !CONFIG_HAVE_WIN_COND */
+# endif /* ( _WIN32_WINNT < 0x600 ) */
}
-#endif /* !_WIN32 */
+#endif /* defined( _WIN32 ) */
PGM_GNUC_INTERNAL
void
@@ -363,13 +373,16 @@ pgm_cond_free (
pgm_assert (NULL != cond);
#ifndef _WIN32
+/* POSIX implementation of condition variables */
posix_check_cmd (pthread_cond_destroy (&cond->pthread_cond));
-#elif defined(CONFIG_HAVE_WIN_COND)
+#elif ( _WIN32_WINNT >= 0x600 )
+/* Vista+ condition variables */
/* nop */
#else
+/* Condition variable implementation for Windows XP */
DeleteCriticalSection (&cond->win32_crit);
pgm_free (cond->phandle);
-#endif /* !_WIN32 */
+#endif
}
PGM_GNUC_INTERNAL
@@ -380,28 +393,25 @@ pgm_rwlock_init (
{
pgm_assert (NULL != rwlock);
-#if defined( CONFIG_DUMB_RWSPINLOCK )
+#if defined( USE_DUMB_RWSPINLOCK )
pgm_rwspinlock_init (&rwlock->rwspinlock);
-#elif defined( CONFIG_HAVE_WIN_SRW_LOCK )
-/* requires Vista+ */
- InitializeSRWLock (&rwlock->win32_rwlock);
#elif !defined( _WIN32 )
+/* POSIX read/write lock */
posix_check_cmd (pthread_rwlock_init (&rwlock->pthread_rwlock, NULL));
+#elif ( _WIN32_WINNT >= 0x600 )
+/* slim read/write lock on Vista+ */
+ InitializeSRWLock (&rwlock->win32_rwlock);
#else
-# if defined(CONFIG_HAVE_CRITICAL_SECTION_EX)
-/* requires Vista+ */
- InitializeCriticalSectionEx (&rwlock->win32_crit, PGM_ADAPTIVE_MUTEX_SPINCOUNT, CRITICAL_SECTION_NO_DEBUG_INFO);
-# else
+/* read/write lock implementation for XP */
InitializeCriticalSection (&rwlock->win32_crit);
SetCriticalSectionSpinCount (&rwlock->win32_crit, PGM_ADAPTIVE_MUTEX_SPINCOUNT);
-# endif
pgm_cond_init (&rwlock->read_cond);
pgm_cond_init (&rwlock->write_cond);
rwlock->read_counter = 0;
rwlock->have_writer = FALSE;
rwlock->want_to_read = 0;
rwlock->want_to_write = 0;
-#endif /* !CONFIG_HAVE_WIN_SRW_LOCK */
+#endif
}
PGM_GNUC_INTERNAL
@@ -412,20 +422,23 @@ pgm_rwlock_free (
{
pgm_assert (NULL != rwlock);
-#if defined( CONFIG_DUMB_RWSPINLOCK )
+#if defined( USE_DUMB_RWSPINLOCK )
pgm_rwspinlock_free (&rwlock->rwspinlock);
-#elif defined( CONFIG_HAVE_WIN_SRW_LOCK )
- /* nop */
-#elif !defined(_WIN32)
+#elif !defined( _WIN32 )
+/* POSIX read/write lock */
pthread_rwlock_destroy (&rwlock->pthread_rwlock);
+#elif ( _WIN32_WINNT >= 0x600 )
+/* slim read/write lock on Vista+ */
#else
+/* read/write lock implementation for XP */
pgm_cond_free (&rwlock->read_cond);
pgm_cond_free (&rwlock->write_cond);
DeleteCriticalSection (&rwlock->win32_crit);
-#endif /* !CONFIG_HAVE_WIN_SRW_LOCK */
+#endif
}
-#if !defined(CONFIG_DUMB_RWSPINLOCK) && !defined(CONFIG_HAVE_WIN_SRW_LOCK) && defined(_WIN32)
+#if defined( _WIN32 ) && !( _WIN32_WINNT >= 0x600 ) && !defined( USE_DUMB_RWSPINLOCK )
+/* read-write lock implementation for Windows XP */
static inline
void
_pgm_rwlock_signal (
@@ -540,7 +553,7 @@ pgm_rwlock_writer_unlock (
_pgm_rwlock_signal (rwlock);
LeaveCriticalSection (&rwlock->win32_crit);
}
-#endif /* !_WIN32 && !CONFIG_HAVE_WIN_SRW_LOCK */
+#endif /* defined( _WIN32 ) && !( _WIN32_WINNT >= 0x600 ) */
/* eof */
diff --git a/src/pgm/time.c b/src/pgm/time.c
index 322f57e..27bc7b8 100644
--- a/src/pgm/time.c
+++ b/src/pgm/time.c
@@ -21,6 +21,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <errno.h>
#include <stdlib.h>
#ifdef _WIN32
@@ -67,19 +70,23 @@ static UINT wTimerRes = 0;
static void pgm_time_conv (const pgm_time_t*const restrict, time_t*restrict);
static void pgm_time_conv_from_reset (const pgm_time_t*const restrict, time_t*restrict);
-#if defined(CONFIG_HAVE_CLOCK_GETTIME)
+#if defined(HAVE_CLOCK_GETTIME)
# include <time.h>
static pgm_time_t pgm_clock_update (void);
#endif
-#ifdef CONFIG_HAVE_FTIME
+#ifdef HAVE_FTIME
# include <sys/timeb.h>
static pgm_time_t pgm_ftime_update (void);
#endif
-#ifdef CONFIG_HAVE_GETTIMEOFDAY
+#ifdef HAVE_GETTIMEOFDAY
# include <sys/time.h>
static pgm_time_t pgm_gettimeofday_update (void);
#endif
-#ifdef CONFIG_HAVE_HPET
+#ifdef _WIN32
+static pgm_time_t pgm_mmtime_update (void);
+static pgm_time_t pgm_queryperformancecounter_update (void);
+#endif
+#ifdef HAVE_DEV_HPET
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>
@@ -139,7 +146,7 @@ static bool pgm_hpet_init (pgm_error_t**);
static bool pgm_hpet_shutdown (void);
static pgm_time_t pgm_hpet_update (void);
#endif
-#ifdef CONFIG_HAVE_RTC
+#ifdef HAVE_DEV_RTC
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>
@@ -153,17 +160,19 @@ static bool pgm_rtc_init (pgm_error_t**);
static bool pgm_rtc_shutdown (void);
static pgm_time_t pgm_rtc_update (void);
#endif
-#ifdef CONFIG_HAVE_TSC
+#ifdef HAVE_RDTSC
# include <stdio.h>
# include <string.h>
# if defined(__APPLE__) || defined(__FreeBSD__)
# include <sys/sysctl.h>
# elif defined(__sun)
# include <kstat.h>
+# elif defined(_MSC_VER)
+# include <intrin.h>
# endif
# define TSC_NS_SCALE 10 /* 2^10, carefully chosen */
# define TSC_US_SCALE 20
-static uint_fast32_t tsc_mhz PGM_GNUC_READ_MOSTLY = 0;
+static uint_fast32_t tsc_khz PGM_GNUC_READ_MOSTLY = 0;
static uint_fast32_t tsc_ns_mul PGM_GNUC_READ_MOSTLY = 0;
static uint_fast32_t tsc_us_mul PGM_GNUC_READ_MOSTLY = 0;
@@ -229,11 +238,7 @@ static pgm_time_t pgm_tsc_update (void);
PGM_GNUC_INTERNAL
bool
pgm_time_init (
-#ifndef _WIN32
pgm_error_t** error
-#else
- PGM_GNUC_UNUSED pgm_error_t** error
-#endif
)
{
char *pgm_timer;
@@ -243,14 +248,15 @@ pgm_time_init (
if (pgm_atomic_exchange_and_add32 (&time_ref_count, 1) > 0)
return TRUE;
-/* current time */
+/* user preferred time stamp function */
err = pgm_dupenv_s (&pgm_timer, &envlen, "PGM_TIMER");
if (0 != err || 0 == envlen) {
pgm_timer = pgm_strdup (
-#ifdef CONFIG_HAVE_TSC
- "TSC"
+/* default time stamp function */
+#if defined(_WIN32)
+ "MMTIME"
#else
- "GTOD"
+ "GETTIMEOFDAY"
#endif
);
}
@@ -258,58 +264,73 @@ pgm_time_init (
pgm_time_since_epoch = pgm_time_conv;
switch (pgm_timer[0]) {
-#ifdef CONFIG_HAVE_FTIME
+#ifdef HAVE_FTIME
case 'F':
pgm_minor (_("Using ftime() timer."));
pgm_time_update_now = pgm_ftime_update;
break;
#endif
-#ifdef CONFIG_HAVE_CLOCK_GETTIME
+#ifdef HAVE_CLOCK_GETTIME
case 'C':
pgm_minor (_("Using clock_gettime() timer."));
pgm_time_update_now = pgm_clock_update;
break;
#endif
-#ifdef CONFIG_HAVE_RTC
+#ifdef HAVE_DEV_RTC
case 'R':
pgm_minor (_("Using /dev/rtc timer."));
pgm_time_update_now = pgm_rtc_update;
pgm_time_since_epoch = pgm_time_conv_from_reset;
break;
#endif
-#ifdef CONFIG_HAVE_TSC
-# ifdef _WIN32
- default:
-# endif
+#ifdef HAVE_RDTSC
case 'T':
pgm_minor (_("Using TSC timer."));
pgm_time_update_now = pgm_tsc_update;
pgm_time_since_epoch = pgm_time_conv_from_reset;
break;
#endif
-#ifdef CONFIG_HAVE_HPET
+#ifdef HAVE_DEV_HPET
case 'H':
pgm_minor (_("Using HPET timer."));
pgm_time_update_now = pgm_hpet_update;
pgm_time_since_epoch = pgm_time_conv_from_reset;
break;
#endif
-
-#ifdef CONFIG_HAVE_GETTIMEOFDAY
-# ifndef _WIN32
- default:
-# endif
+#ifdef HAVE_GETTIMEOFDAY
case 'G':
pgm_minor (_("Using gettimeofday() timer."));
pgm_time_update_now = pgm_gettimeofday_update;
break;
#endif
+#ifdef _WIN32
+ case 'M':
+ pgm_minor (_("Using multi-media timer."));
+ pgm_time_update_now = pgm_mmtime_update;
+ pgm_time_since_epoch = pgm_time_conv_from_reset;
+ break;
+
+ case 'Q':
+ pgm_minor (_("Using QueryPerformanceCounter() timer."));
+ pgm_time_update_now = pgm_queryperformancecounter_update;
+ pgm_time_since_epoch = pgm_time_conv_from_reset;
+ break;
+#endif
+
+ default:
+ pgm_set_error (error,
+ PGM_ERROR_DOMAIN_TIME,
+ PGM_ERROR_FAILED,
+ _("Unsupported time stamp function: PGM_TIMER=%s"),
+ pgm_timer);
+ pgm_free (pgm_timer);
+ goto err_cleanup;
}
/* clean environment copy */
pgm_free (pgm_timer);
-#ifdef CONFIG_HAVE_RTC
+#ifdef HAVE_DEV_RTC
if (pgm_time_update_now == pgm_rtc_update)
{
pgm_error_t* sub_error = NULL;
@@ -319,12 +340,39 @@ pgm_time_init (
}
}
#endif
-#ifdef CONFIG_HAVE_TSC
+#ifdef _WIN32
+ if (pgm_time_update_now == pgm_queryperformancecounter_update)
+ {
+/* MSDN statement: The frequency cannot change while the system is running.
+ * http://msdn.microsoft.com/en-us/library/ms644905(v=vs.85).aspx
+ */
+ LARGE_INTEGER frequency;
+ if (QueryPerformanceFrequency (&frequency))
+ {
+ tsc_khz = (uint_fast32_t)(frequency.QuadPart / 1000LL);
+ pgm_minor (_("High-resolution performance counter frequency %lld Hz"),
+ frequency.QuadPart);
+ }
+ else
+ {
+ const DWORD save_errno = GetLastError();
+ char winstr[1024];
+ pgm_set_error (error,
+ PGM_ERROR_DOMAIN_TIME,
+ PGM_ERROR_FAILED,
+ _("No supported high-resolution performance counter: %s"),
+ pgm_win_strerror (winstr, sizeof (winstr), save_errno));
+ goto err_cleanup;
+ }
+ set_tsc_mul (tsc_khz);
+ }
+#endif /* _WIN32 */
+#ifdef HAVE_RDTSC
if (pgm_time_update_now == pgm_tsc_update)
{
char *rdtsc_frequency;
-#ifdef CONFIG_HAVE_PROC
+#ifdef HAVE_PROC_CPUINFO
/* attempt to parse clock ticks from kernel
*/
FILE *fp = fopen ("/proc/cpuinfo", "r");
@@ -335,32 +383,55 @@ pgm_time_init (
{
if (strstr (buffer, "cpu MHz")) {
const char *p = strchr (buffer, ':');
- if (p) tsc_mhz = atoi (p + 1) * 1000;
+ if (p) tsc_khz = atoi (p + 1) * 1000;
break;
}
}
fclose (fp);
}
#elif defined(_WIN32)
-/* iff reading TSC we could use HKLM/Hardware/Description/System/CentralProcessor/0/~Mhz
- *
- * MSDN statement: The frequency cannot change while the system is running.
- * http://msdn.microsoft.com/en-us/library/ms644905(v=vs.85).aspx
+/* core frequency HKLM/Hardware/Description/System/CentralProcessor/0/~Mhz
*/
- LARGE_INTEGER frequency;
- if (QueryPerformanceFrequency (&frequency))
+ HKEY hKey;
+ if (ERROR_SUCCESS == RegOpenKeyExA (HKEY_LOCAL_MACHINE,
+ "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
+ 0,
+ KEY_QUERY_VALUE,
+ &hKey))
{
- tsc_mhz = (uint_fast32_t)(frequency.QuadPart / 1000);
- }
- else
- {
- const DWORD save_errno = GetLastError();
- char winstr[1024];
- pgm_set_error (error,
- PGM_ERROR_DOMAIN_TIME,
- PGM_ERROR_FAILED,
- _("No supported high-resolution performance counter: %s"),
- pgm_win_strerror (winstr, sizeof (winstr), save_errno));
+ DWORD dwData = 0;
+ DWORD dwDataSize = sizeof (dwData);
+ if (ERROR_SUCCESS == RegQueryValueExA (hKey,
+ "~MHz",
+ NULL,
+ NULL,
+ (LPBYTE)&dwData,
+ &dwDataSize))
+ {
+ tsc_khz = dwData * 1000;
+ pgm_minor (_("Registry reports central processor frequency %u MHz"),
+ (unsigned)dwData);
+/* dump processor name for comparison aid of obtained frequency */
+ char szProcessorBrandString[48];
+ dwDataSize = sizeof (szProcessorBrandString);
+ if (ERROR_SUCCESS == RegQueryValueExA (hKey,
+ "ProcessorNameString",
+ NULL,
+ NULL,
+ (LPBYTE)szProcessorBrandString,
+ &dwDataSize))
+ {
+ pgm_minor (_("Processor Brand String \"%s\""), szProcessorBrandString);
+ }
+ }
+ else
+ {
+ const DWORD save_errno = GetLastError();
+ char winstr[1024];
+ pgm_warn (_("Registry query on HKLM\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\\~MHz failed: %s"),
+ pgm_win_strerror (winstr, sizeof (winstr), save_errno));
+ }
+ RegCloseKey (hKey);
}
#elif defined(__APPLE__)
/* nb: RDTSC is non-functional on Darwin */
@@ -368,14 +439,15 @@ pgm_time_init (
size_t len;
len = sizeof (cpufrequency);
if (0 == sysctlbyname ("hw.cpufrequency", &cpufrequency, &len, NULL, 0)) {
- tsc_mhz = (uint_fast32_t)(cpufrequency / 1000);
+ tsc_khz = (uint_fast32_t)(cpufrequency / 1000);
}
#elif defined(__FreeBSD__)
+/* frequency in Mhz */
unsigned long clockrate;
size_t len;
len = sizeof (clockrate);
if (0 == sysctlbyname ("hw.clockrate", &clockrate, &len, NULL, 0)) {
- tsc_mhz = (uint_fast32_t)(clockrate * 1000);
+ tsc_khz = (uint_fast32_t)(clockrate * 1000);
}
#elif defined(KSTAT_DATA_INT32)
/* ref: http://developers.sun.com/solaris/articles/kstatc.html */
@@ -389,7 +461,7 @@ pgm_time_init (
NULL != (kdata = kstat_data_lookup (ksp, "clock_MHz")) &&
KSTAT_DATA_INT32 == kdata->data_type)
{
- tsc_mhz = (uint_fast32_t)(kdata->value.i32 * 1000);
+ tsc_khz = (uint_fast32_t)(kdata->value.i32 * 1000);
kstat_close (kc);
}
#endif /* !_WIN32 */
@@ -400,13 +472,13 @@ pgm_time_init (
*/
err = pgm_dupenv_s (&rdtsc_frequency, &envlen, "RDTSC_FREQUENCY");
if (0 == err && envlen > 0) {
- tsc_mhz = atoi (rdtsc_frequency) * 1000;
+ tsc_khz = atoi (rdtsc_frequency) * 1000;
pgm_free (rdtsc_frequency);
}
#ifndef _WIN32
/* calibrate */
- if (0 >= tsc_mhz) {
+ if (0 >= tsc_khz) {
pgm_error_t* sub_error = NULL;
if (!pgm_tsc_init (&sub_error)) {
pgm_propagate_error (error, sub_error);
@@ -414,12 +486,12 @@ pgm_time_init (
}
}
#endif
- pgm_minor (_("TSC frequency set to %u MHz"), (unsigned)(tsc_mhz / 1000));
- set_tsc_mul (tsc_mhz);
+ pgm_minor (_("TSC frequency set at %u KHz"), (unsigned)(tsc_khz));
+ set_tsc_mul (tsc_khz);
}
-#endif /* CONFIG_HAVE_TSC */
+#endif /* HAVE_RDTSC */
-#ifdef CONFIG_HAVE_HPET
+#ifdef HAVE_DEV_HPET
if (pgm_time_update_now == pgm_hpet_update)
{
pgm_error_t* sub_error = NULL;
@@ -433,19 +505,26 @@ pgm_time_init (
pgm_time_update_now();
/* calculate relative time offset */
-#if defined(CONFIG_HAVE_RTC) || defined(CONFIG_HAVE_TSC)
+#if defined(HAVE_DEV_RTC) || defined(HAVE_RDTSC) || defined(HAVE_DEV_HPET) || defined(_WIN32)
if ( 0
-# ifdef CONFIG_HAVE_RTC
+# ifdef HAVE_DEV_RTC
|| pgm_time_update_now == pgm_rtc_update
# endif
-# ifdef CONFIG_HAVE_TSC
+# ifdef HAVE_RDTSC
|| pgm_time_update_now == pgm_tsc_update
# endif
+# ifdef HAVE_DEV_HPET
+ || pgm_time_update_now == pgm_hpet_update
+# endif
+# ifdef _WIN32
+ || pgm_time_update_now == pgm_mmtime_update
+ || pgm_time_update_now == pgm_queryperformancecounter_update
+# endif
)
{
-# if defined( CONFIG_HAVE_GETTIMEOFDAY )
+# if defined( HAVE_GETTIMEOFDAY )
rel_offset = pgm_gettimeofday_update() - pgm_time_update_now();
-# elif defined( CONFIG_HAVE_FTIME )
+# elif defined( HAVE_FTIME )
rel_offset = pgm_ftime_update() - pgm_time_update_now();
# else
# error "gettimeofday() or ftime() required to calculate counter offset"
@@ -471,15 +550,9 @@ pgm_time_init (
#endif
return TRUE;
-#if defined(CONFIG_HAVE_RTC) || (defined(CONFIG_HAVE_TSC) && !defined(_WIN32)) || defined(CONFIG_HAVE_HPET)
err_cleanup:
pgm_atomic_dec32 (&time_ref_count);
return FALSE;
-#endif
-#if !defined(CONFIG_HAVE_RTC) && !defined(CONFIG_HAVE_TSC) && !defined(CONFIG_HAVE_HPET)
-/* unused parameters */
- (void)error;
-#endif
}
/* returns TRUE if shutdown succeeded, returns FALSE on error.
@@ -500,18 +573,18 @@ pgm_time_shutdown (void)
timeEndPeriod (wTimerRes);
#endif
-#ifdef CONFIG_HAVE_RTC
+#ifdef HAVE_DEV_RTC
if (pgm_time_update_now == pgm_rtc_update)
retval = pgm_rtc_shutdown ();
#endif
-#ifdef CONFIG_HAVE_HPET
+#ifdef HAVE_DEV_HPET
if (pgm_time_update_now == pgm_hpet_update)
retval = pgm_hpet_shutdown ();
#endif
return retval;
}
-#ifdef CONFIG_HAVE_GETTIMEOFDAY
+#ifdef HAVE_GETTIMEOFDAY
static
pgm_time_t
pgm_gettimeofday_update (void)
@@ -527,9 +600,9 @@ pgm_gettimeofday_update (void)
else
return last = now;
}
-#endif /* CONFIG_HAVE_GETTIMEOFDAY */
+#endif /* HAVE_GETTIMEOFDAY */
-#ifdef CONFIG_HAVE_CLOCK_GETTIME
+#ifdef HAVE_CLOCK_GETTIME
static
pgm_time_t
pgm_clock_update (void)
@@ -545,9 +618,12 @@ pgm_clock_update (void)
else
return last = now;
}
-#endif /* CONFIG_HAVE_CLOCK_GETTIME */
+#endif /* HAVE_CLOCK_GETTIME */
-#ifdef CONFIG_HAVE_FTIME
+#ifdef HAVE_FTIME
+/* Note that _ftime32_s is implemented using GetSystemTimeAsFileTime().
+ * ref: CRT source code as shipped with Microsoft Visual Studio: crt/src/ftime.c
+ */
static
pgm_time_t
pgm_ftime_update (void)
@@ -569,9 +645,9 @@ pgm_ftime_update (void)
else
return last = now;
}
-#endif /* CONFIG_HAVE_FTIME */
+#endif /* HAVE_FTIME */
-#ifdef CONFIG_HAVE_RTC
+#ifdef HAVE_DEV_RTC
/* Old PC/AT-Compatible driver: /dev/rtc
*
* Not so speedy 8192 Hz timer, thats 122us resolution.
@@ -649,33 +725,69 @@ pgm_rtc_update (void)
rtc_count += data >> 8;
return rtc_count * 1000000UL / rtc_frequency;
}
-#endif /* CONFIG_HAVE_RTC */
+#endif /* HAVE_DEV_RTC */
+
+#ifdef _WIN32
+/* Multi-media like timer API, returns 100-nanoseconds intervals.
+ *
+ * Faster than QueryPerformanceCounter and hence deployed for SQL Server.
+ * http://blogs.msdn.com/b/psssql/archive/2008/12/16/how-it-works-sql-server-no-longer-uses-rdtsc-for-timings-in-sql-2008-and-sql-2005-service-pack-3-sp3.aspx
+ */
+static
+pgm_time_t
+pgm_mmtime_update (void)
+{
+ FILETIME ft;
+ int64_t aligned_ft;
+
+ GetSystemTimeAsFileTime (&ft);
+ memcpy (&aligned_ft, &ft, sizeof (int64_t));
+ return (pgm_time_t)( aligned_ft / 10 );
+}
+
+/* High-resolution performance counter.
+ *
+ * Microsoft performance note on API cost:
+ * http://blogs.msdn.com/b/psssql/archive/2006/11/27/sql-server-2005-sp2-will-introduce-new-messages-to-the-error-log-related-to-timing-activities.aspx
+ * "QueryPerformanceCounter is a more stable counter but very costly when called lots of times like SQL Server would do."
+ *
+ * Microsoft note on TSC drift affect on this API.
+ * http://support.microsoft.com/kb/895980
+ */
+static
+pgm_time_t
+pgm_queryperformancecounter_update (void)
+{
+ LARGE_INTEGER counter;
+
+ QueryPerformanceCounter (&counter);
+ return (pgm_time_t)counter.QuadPart;
+}
+#endif /* _WIN32 */
-#ifdef CONFIG_HAVE_TSC
+#ifdef HAVE_RDTSC
/* read time stamp counter (TSC), count of ticks from processor reset.
*
- * NB: On Windows this will usually be HPET or PIC timer interpolated with TSC.
+ * Microsoft notes on TSC drift:
+ * http://support.microsoft.com/kb/931279
+ * http://support.microsoft.com/kb/938448
*/
static inline
pgm_time_t
-rdtsc (void)
+pgm_rdtsc (void)
{
-# ifndef _WIN32
+# ifndef _MSC_VER
uint32_t lo, hi;
/* We cannot use "=A", since this would use %rax on x86_64 */
__asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
-
return (pgm_time_t)hi << 32 | lo;
# else
- LARGE_INTEGER counter;
-
- QueryPerformanceCounter (&counter);
- return (pgm_time_t)counter.QuadPart;
+ return (pgm_time_t)__rdtsc ();
# endif
}
@@ -693,7 +805,7 @@ pgm_tsc_init (
PGM_GNUC_UNUSED pgm_error_t** error
)
{
-# ifdef CONFIG_HAVE_PROC
+# ifdef HAVE_PROC_CPUINFO
/* Test for constant TSC from kernel
*/
FILE *fp = fopen ("/proc/cpuinfo", "r");
@@ -721,7 +833,7 @@ pgm_tsc_init (
pgm_time_update_now = pgm_gettimeofday_update;
return TRUE;
}
-# endif /* CONFIG_HAVE_PROC */
+# endif /* HAVE_PROC_CPUINFO */
pgm_time_t start, stop, elapsed;
const pgm_time_t calibration_usec = secs_to_usecs (4);
@@ -732,9 +844,9 @@ pgm_tsc_init (
pgm_info (_("Running a benchmark to measure system clock frequency..."));
- start = rdtsc();
+ start = pgm_rdtsc();
while (-1 == nanosleep (&req, &req) && EINTR == errno);
- stop = rdtsc();
+ stop = pgm_rdtsc();
if (stop < start)
{
@@ -751,17 +863,17 @@ pgm_tsc_init (
elapsed = stop - start;
if (elapsed > calibration_usec) {
/* cpu > 1 Ghz */
- tsc_mhz = (elapsed * 1000) / calibration_usec;
+ tsc_khz = (elapsed * 1000) / calibration_usec;
} else {
/* cpu < 1 Ghz */
- tsc_mhz = -( (calibration_usec * 1000) / elapsed );
+ tsc_khz = -( (calibration_usec * 1000) / elapsed );
}
pgm_info (_("Finished RDTSC test. To prevent the startup delay from this benchmark, "
"set the environment variable RDTSC_FREQUENCY to %" PRIuFAST32 " on this "
"system. This value is dependent upon the CPU clock speed and "
"architecture and should be determined separately for each server."),
- tsc_mhz / 1000);
+ tsc_khz);
return TRUE;
}
# endif
@@ -776,16 +888,16 @@ pgm_time_t
pgm_tsc_update (void)
{
static pgm_time_t last = 0;
- const pgm_time_t now = tsc_to_us (rdtsc());
+ const pgm_time_t now = tsc_to_us (pgm_rdtsc());
if (PGM_UNLIKELY(now < last))
return last;
else
return last = now;
}
-#endif
+#endif /* HAVE_RDTSC */
-#ifdef CONFIG_HAVE_HPET
+#ifdef HAVE_DEV_HPET
/* High Precision Event Timer (HPET) created as a system wide stable high resolution timer
* to replace dependency on core specific counters (TSC).
*
@@ -860,7 +972,7 @@ pgm_hpet_update (void)
hpet_last = hpet_count;
return hpet_to_us (hpet_offset + hpet_count);
}
-#endif /* CONFIG_HAVE_HPET */
+#endif /* HAVE_DEV_HPET */
/* convert from pgm_time_t to time_t with pgm_time_t in microseconds since the epoch.
*/
diff --git a/src/pgm/timer.c b/src/pgm/timer.c
index c0a8092..f1c7392 100644
--- a/src/pgm/timer.c
+++ b/src/pgm/timer.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/i18n.h>
#include <impl/framework.h>
#include <impl/timer.h>
diff --git a/src/pgm/tsi.c b/src/pgm/tsi.c
index 10638e2..2956d85 100644
--- a/src/pgm/tsi.c
+++ b/src/pgm/tsi.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <stdio.h>
#include <impl/framework.h>
diff --git a/src/pgm/txw.c b/src/pgm/txw.c
index 8961b0e..3bdcad1 100644
--- a/src/pgm/txw.c
+++ b/src/pgm/txw.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/i18n.h>
#include <impl/framework.h>
#include <impl/txw.h>
diff --git a/src/pgm/wsastrerror.c b/src/pgm/wsastrerror.c
index 7119a1d..397b2a3 100644
--- a/src/pgm/wsastrerror.c
+++ b/src/pgm/wsastrerror.c
@@ -17,19 +17,52 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include <impl/i18n.h>
#include <impl/framework.h>
-#ifdef _WIN32
-# include <ws2tcpip.h>
+#ifndef _WIN32
+/* compatibility stubs */
+
+char *
+pgm_wsastrerror (
+ const int wsa_errnum
+ )
+{
+ return _("Unknown.");
+}
+
+char*
+pgm_adapter_strerror (
+ const int adapter_errnum
+ )
+{
+ return _("Unknown.");
+}
+
+char*
+pgm_win_strerror (
+ char* buf,
+ size_t buflen,
+ const int win_errnum
+ )
+{
+ pgm_strncpy_s (buf, buflen, _("Unknown."), _TRUNCATE);
+ return buf;
+}
+
+#else
+# include <ws2tcpip.h>
char*
pgm_wsastrerror (
- const int wsa_errno
+ const int wsa_errnum
)
{
- switch (wsa_errno) {
+ switch (wsa_errnum) {
#ifdef WSA_INVALID_HANDLE
case WSA_INVALID_HANDLE: return _("Specified event object handle is invalid.");
#endif
@@ -321,10 +354,10 @@ pgm_wsastrerror (
char*
pgm_adapter_strerror (
- const int adapter_errno
+ const int adapter_errnum
)
{
- switch (adapter_errno) {
+ switch (adapter_errnum) {
#ifdef ERROR_ADDRESS_NOT_ASSOCIATED
case ERROR_ADDRESS_NOT_ASSOCIATED: return _("DHCP lease information was available.");
#endif
@@ -354,19 +387,20 @@ char*
pgm_win_strerror (
char* buf,
size_t buflen,
- const int win_errno
+ const int win_errnum
)
{
const DWORD nSize = (DWORD)buflen;
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
NULL, /* source */
- win_errno, /* message id */
+ win_errnum, /* message id */
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* language id */
(LPTSTR)buf,
nSize,
NULL); /* arguments */
return buf;
}
+
#endif /* _WIN32 */
/* eof */