Merge sslsplit-develop changes

pull/13/head
Soner Tari 6 years ago
parent a584363f62
commit d2e9ab4487

3
.gitignore vendored

@ -3,6 +3,8 @@
/sslproxy
/sslproxy.test
/extra/*.pyc
/extra/engine/*.dylib
/extra/engine/*.so
/extra/pki/dh*.param
/extra/pki/dsa.pem
/extra/pki/dsa.crt
@ -18,7 +20,6 @@
/extra/pki/server.pem
/extra/pki/server.crt
/extra/pki/server.key
/extra/pki/session.pem
/extra/pki/targets/*
/docs/

@ -247,6 +247,7 @@ OPENSSL_FIND:= $(wildcard \
endif
OPENSSL_AVAIL:= $(OPENSSL_FIND:/$(OPENSSL_PAT)=)
OPENSSL_FOUND:= $(word 1,$(OPENSSL_AVAIL))
OPENSSL:= $(OPENSSL_FOUND)/bin/openssl
ifndef OPENSSL_FOUND
$(error dependency 'OpenSSL' not found; \
install it or point OPENSSL_BASE to base path)
@ -356,6 +357,8 @@ endif
export VERSION
export OPENSSL
export OPENSSL_BASE
export OPENSSL_FOUND
export MKDIR
export WGET
@ -413,8 +416,8 @@ travis: test
test: TCPPFLAGS+=-D"TEST_ZEROUSR=\"$(shell id -u -n root||echo 0)\""
test: TCPPFLAGS+=-D"TEST_ZEROGRP=\"$(shell id -g -n root||echo 0)\""
test: $(TARGET).test
$(RM) extra/pki/session.pem
$(MAKE) -C extra/pki testreqs session
$(MAKE) -C extra/engine
$(MAKE) -C extra/pki testreqs
./$(TARGET).test
sudotest: test
@ -424,6 +427,7 @@ $(TARGET).test: $(TOBJS)
$(CC) $(LDFLAGS) $(TPKG_LDFLAGS) -o $@ $^ $(LIBS) $(TPKG_LIBS)
clean:
$(MAKE) -C extra/engine clean
$(RM) -f $(TARGET) $(TARGET).test *.o .*.o *.core *~
$(RM) -rf *.dSYM
@ -462,7 +466,7 @@ mantest: $(TARGET).1
$(MAN) -M . 1 $(TARGET)
$(RM) man1
copyright: *.c *.h *.1
copyright: *.c *.h *.1 *.5 extra/*/*.c
Mk/bin/copyright.py $^
$(PKGNAME)-$(VERSION).1.txt: $(TARGET).1

@ -62,6 +62,8 @@ def mangle(outfile, infile):
for fn in sys.argv[1:]:
with open(fn, 'r') as infile:
with open(fn + '~', 'w') as outfile:
mode = os.fstat(infile.fileno()).st_mode
os.fchmod(outfile.fileno(), mode)
mangle(outfile, infile)
os.rename(fn + '~', fn)

@ -0,0 +1,72 @@
#!/bin/sh
if [ -z "$SSL" ]; then
echo '$SSL not set, aborting' >&2
exit 1
fi
if [ -z "$EVENT" ]; then
echo '$EVENT not set, aborting' >&2
exit 1
fi
case "$SSL" in
openssl-0.9.*)
SSLURL=https://www.openssl.org/source/old/0.9.x/$SSL.tar.gz
;;
openssl-1.0.0*)
SSLURL=https://www.openssl.org/source/old/1.0.0/$SSL.tar.gz
;;
openssl-1.0.1*)
SSLURL=https://www.openssl.org/source/old/1.0.1/$SSL.tar.gz
;;
openssl-*)
SSLURL=https://www.openssl.org/source/$SSL.tar.gz
;;
libressl-*)
#SSLURL=https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/$SSL.tar.gz
SSLURL=http://ftp.fau.de/pub/OpenBSD/LibreSSL/$SSL.tar.gz
;;
*)
exit 1
;;
esac
case "$EVENT" in
libevent-2.1.8)
EVENTURL=https://github.com/libevent/libevent/releases/download/release-2.1.8-stable/libevent-2.1.8-stable.tar.gz
EVENTPATCH=Mk/patches/libevent-2.1.8.diff
;;
libevent-2.0.22)
EVENTURL=https://github.com/libevent/libevent/releases/download/release-2.0.22-stable/libevent-2.0.22-stable.tar.gz
;;
*)
exit 1
;;
esac
if [ ! -d "$HOME/opt/$SSL" ]; then
wget "$SSLURL" || exit 1
tar -xzvf "$SSL.tar.gz" || exit 1
cd "$SSL" || exit 1
./config shared \
-Wl,-rpath="$HOME/opt/$SSL/lib" \
--prefix="$HOME/opt/$SSL" \
--openssldir="$HOME/opt/$SSL" || exit 1
make && make install || { rm -rf "$HOME/opt/$SSL"; exit 1; }
cd ..
fi
export CPPFLAGS="-I$HOME/opt/$SSL/include"
export LDFLAGS="-L$HOME/opt/$SSL/lib"
if [ ! -d "$HOME/opt/$EVENT" ]; then
wget "$EVENTURL" || exit 1
tar -xzvf "$EVENT-stable.tar.gz" || exit 1
cd "$EVENT-stable" || exit 1
if [ -n "$EVENTPATCH" ]; then
patch -p0 < ../$EVENTPATCH || exit 1
fi
./configure --prefix="$HOME/opt/$EVENT" || exit 1
make && make install || { rm -rf "$HOME/opt/$EVENT"; exit 1; }
cd ..
fi

@ -0,0 +1,103 @@
From 28b8075400c70b2d2da2ce07e590c2ec6d11783d Mon Sep 17 00:00:00 2001
From: Bernard Spil <brnrd@FreeBSD.org>
Date: Mon, 2 Apr 2018 13:18:27 +0200
Subject: [PATCH] Fix build with LibreSSL 2.7
LibreSSL 2.7 implements OpenSSL 1.1 API except for BIO_get_init()
See also: https://bugs.freebsd.org/226900
Signed-off-by: Bernard Spil <brnrd@FreeBSD.org>
Closes: #617 (cherry-pick)
--- openssl-compat.h.orig 2017-01-25 23:37:15 UTC
+++ openssl-compat.h
@@ -1,7 +1,8 @@
#ifndef OPENSSL_COMPAT_H
#define OPENSSL_COMPAT_H
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
static inline BIO_METHOD *BIO_meth_new(int type, const char *name)
{
@@ -30,6 +31,11 @@ static inline BIO_METHOD *BIO_meth_new(i
#define TLS_method SSLv23_method
-#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
+#endif /* (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) */
+
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20700000L
+#define BIO_get_init(b) (b)->init
+#endif
#endif /* OPENSSL_COMPAT_H */
--- sample/https-client.c.orig 2017-01-25 23:37:15 UTC
+++ sample/https-client.c
@@ -312,7 +312,8 @@ main(int argc, char **argv)
}
uri[sizeof(uri) - 1] = '\0';
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
// Initialize OpenSSL
SSL_library_init();
ERR_load_crypto_strings();
@@ -480,7 +481,8 @@ cleanup:
SSL_CTX_free(ssl_ctx);
if (type == HTTP && ssl)
SSL_free(ssl);
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
EVP_cleanup();
ERR_free_strings();
@@ -492,7 +494,8 @@ cleanup:
CRYPTO_cleanup_all_ex_data();
sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
-#endif /*OPENSSL_VERSION_NUMBER < 0x10100000L */
+#endif /* (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) */
#ifdef _WIN32
WSACleanup();
--- sample/le-proxy.c.orig 2017-01-25 23:37:15 UTC
+++ sample/le-proxy.c
@@ -259,7 +259,8 @@ main(int argc, char **argv)
if (use_ssl) {
int r;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
SSL_library_init();
ERR_load_crypto_strings();
SSL_load_error_strings();
--- sample/openssl_hostname_validation.c.orig 2017-01-25 23:37:15 UTC
+++ sample/openssl_hostname_validation.c
@@ -48,7 +48,8 @@ SOFTWARE.
#define HOSTNAME_MAX_SIZE 255
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
#define ASN1_STRING_get0_data ASN1_STRING_data
#endif
--- test/regress_ssl.c.orig 2017-01-25 23:37:15 UTC
+++ test/regress_ssl.c
@@ -186,7 +186,8 @@ get_ssl_ctx(void)
void
init_ssl(void)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
SSL_library_init();
ERR_load_crypto_strings();
SSL_load_error_strings();

@ -1,8 +1,13 @@
### SSLsplit develop
- Suppress Expect-CT header in order to avoid Certificate Transparency log
lookup failures (issue #205).
- Add -x option for activating an OpenSSL engine (issue #204, pull req #206).
- Add -f option for loading configuration from file (pull req #193).
- Add `sudotest` target with unit tests which require privileges to run.
- Add XNU headers for macOS High Sierra 10.13.1, 10.13.2 and 10.13.3.
- Fix crash when using LibreSSL (pull req #207).
- Minor bugfixes and improvements.

@ -89,10 +89,10 @@ SSLproxy implements a number of defenses against mechanisms which would
normally prevent MitM attacks or make them more difficult. SSLproxy can deny
OCSP requests in a generic way. For HTTP and HTTPS connections, SSLproxy
mangles headers to prevent server-instructed public key pinning (HPKP), avoid
strict transport security restrictions (HSTS), and prevent switching to
QUIC/SPDY, HTTP/2 or WebSockets (Upgrade, Alternate Protocols). HTTP
compression, encodings and keep-alive are disabled to make the logs more
readable.
strict transport security restrictions (HSTS), avoid Certificate Transparency
enforcement (Expect-CT) and prevent switching to QUIC/SPDY, HTTP/2 or
WebSockets (Upgrade, Alternate Protocols). HTTP compression, encodings and
keep-alive are disabled to make the logs more readable.
Another reason to disable persistent connections is to reduce file descriptor
usage. Accordingly, connections are closed if they remain idle for a certain

@ -0,0 +1,12 @@
# Security
Please report all security issues privately to
[Soner Tari](mailto:sonertari@gmail.com).
The maintainers pledge to act on all reported security issues in a timely and
professional manner, working with the reporter to reproduce, understand,
address and disclose vulnerabilities in a coordinated manner. For critical
vulnerabilities, we will prepare a bugfix release based on the last release,
obtain CVE numbers and notify distributions shipping affected packages in
advance of the release.

@ -34,10 +34,15 @@
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <time.h>
#include <check.h>
#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20501000L
#define TMP_SESS_FILE "extra/pki/session-libressl-2.5.0.pem"
#else
#define TMP_SESS_FILE "extra/pki/session.pem"
#endif
static SSL_SESSION *
ssl_session_from_file(const char *filename)
@ -50,6 +55,8 @@ ssl_session_from_file(const char *filename)
return NULL;
sess = PEM_read_SSL_SESSION(f, NULL, NULL, NULL);
fclose(f);
/* to avoid having to regenerate the session, just bump its time */
SSL_SESSION_set_time(sess, time(NULL) - 1);
return sess;
}

@ -58,6 +58,7 @@ START_TEST(cache_fkcrt_01)
fail_unless(!!c1, "loading certificate failed");
cachemgr_fkcrt_set(c1, c1);
c2 = cachemgr_fkcrt_get(c1);
fail_unless(!!c2, "cache did not return a certificate");
fail_unless(c2 == c1, "cache did not return same pointer");
X509_free(c1);
X509_free(c2);

@ -33,10 +33,16 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <check.h>
#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20501000L
#define TMP_SESS_FILE "extra/pki/session-libressl-2.5.0.pem"
#else
#define TMP_SESS_FILE "extra/pki/session.pem"
#endif
static SSL_SESSION *
ssl_session_from_file(const char *filename)
@ -49,6 +55,8 @@ ssl_session_from_file(const char *filename)
return NULL;
sess = PEM_read_SSL_SESSION(f, NULL, NULL, NULL);
fclose(f);
/* to avoid having to regenerate the session, just bump its time */
SSL_SESSION_set_time(sess, time(NULL) - 1);
return sess;
}

@ -59,6 +59,7 @@ START_TEST(cache_tgcrt_01)
fail_unless(!!c1, "loading certificate failed");
cachemgr_tgcrt_set("daniel.roe.ch", c1);
c2 = cachemgr_tgcrt_get("daniel.roe.ch");
fail_unless(!!c2, "cache did not return a certificate");
fail_unless(c2 == c1, "cache did not return same pointer");
cert_free(c1);
cert_free(c2);

@ -0,0 +1,33 @@
UNAME_S:= $(shell uname -s)
ifdef OPENSSL_FOUND
OPENSSL_BASE= $(OPENSSL_FOUND)
else
ifndef OPENSSL_BASE
OPENSSL_BASE= $(shell pkg-config --variable=prefix openssl)
endif
endif
ifeq ($(UNAME_S),Darwin)
SUFFIX:= dylib
#CFLAGS+= -arch i386
CFLAGS+= -arch x86_64
else
SUFFIX:= so
endif
CFLAGS+= -fPIC -I$(OPENSSL_BASE)/include
LDFLAGS+= -L$(OPENSSL_BASE)/lib
LIBS+= -lcrypto
TARGET= dummy-engine
all: $(TARGET).$(SUFFIX)
$(TARGET).$(SUFFIX): $(TARGET).c GNUmakefile
$(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
clean:
rm -f $(TARGET).$(SUFFIX)
.PHONY: all clean

@ -0,0 +1,61 @@
/*-
* SSLsplit - transparent SSL/TLS interception
* https://www.roe.ch/SSLsplit
*
* Copyright (c) 2009-2018, Daniel Roethlisberger <daniel@roe.ch>.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 COPYRIGHT HOLDER 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.
*/
/*
* Dummy OpenSSL engine. Does not do anything useful except being loadable.
* It deliberately builds fine even if engine support is unavailable.
*
* gcc -I/opt/local/include -fPIC -o dummy-engine.o -c dummy-engine.c
* gcc -L/opt/local/lib -shared -o dummy-engine.dylib -lcrypto dummy-engine.o
* openssl engine -t -c `pwd`/dummy-engine.dylib
*/
#include <stdio.h>
#include <openssl/conf.h>
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
static int
bind(ENGINE *engine, const char *id)
{
if (!ENGINE_set_id(engine, "dummy")) {
fprintf(stderr, "ENGINE_set_id() failed\n");
return 0;
}
if (!ENGINE_set_name(engine, "dummy engine")) {
fprintf(stderr, "ENGINE_set_name() failed\n");
return 0;
}
return 1;
}
IMPLEMENT_DYNAMIC_BIND_FN(bind)
IMPLEMENT_DYNAMIC_CHECK_FN()
#endif /* !OPENSSL_NO_ENGINE */

@ -0,0 +1,7 @@
all: snoop-nss-verify.so
snoop-nss-verify.so: snoop-nss-verify.c
$(CC) -shared -fPIC -o $@ $< -ldl
clean:
rm -f snoop-nss-verify.so

@ -0,0 +1,73 @@
/*-
* SSLsplit - transparent SSL/TLS interception
* https://www.roe.ch/SSLsplit
*
* Copyright (c) 2009-2018, Daniel Roethlisberger <daniel@roe.ch>.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 COPYRIGHT HOLDER 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.
*/
/*
* LD_PRELOAD library overlay to print calls to NSS CERT_PKIXVerifyCert() and
* their error code. This function is used by Chrome and other browsers using
* NSS to verify server certificates. This overlay is intended to help finding
* the root cause for certificate verification failures in Chrome, that are
* mapped to Chrome error codes in MapSecurityError():
* https://chromium.googlesource.com/chromium/src/+/master/net/cert/cert_verify_proc_nss.cc
*
* Usage on Linux:
* gcc -shared -fPIC -o snoop-nss-verify.so snoop-nss-verify.c -ldl
* LD_PRELOAD=./snoop-nss-verify.so /usr/bin/google-chrome
*/
#define _GNU_SOURCE
#include <sys/types.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#define CERTCertificate void
#define SECCertificateUsage int64_t
#define CERTValInParam void
#define CERTValOutParam void
#define SECStatus int /* actually enum */
SECStatus
CERT_PKIXVerifyCert(CERTCertificate *cert,
SECCertificateUsage usages,
CERTValInParam *paramsIn,
CERTValOutParam *paramsOut,
void *wincx)
{
typeof(CERT_PKIXVerifyCert) *original;
SECStatus rv;
original = dlsym(RTLD_NEXT, "CERT_PKIXVerifyCert");
rv = original(cert, usages, paramsIn, paramsOut, wincx);
fprintf(stderr,
"CERT_PKIXVerifyCert(%p, %"PRId64", %p, %p, %p) => %i\n",
cert, usages, paramsIn, paramsOut, wincx, rv);
return rv;
}

@ -0,0 +1,34 @@
-----BEGIN SSL SESSION PARAMETERS-----
MIIF2wIBAQICAwMEAswTBCAcR74muuDRYJktM+apiD6VBY++VkYtTyskq0AuHkeD
8QQw/AnKuLIX0HVQifQCMP399upNn0X0epRhogLI2FmUyRkITEscs3qqEEKQPouT
e0JHoQYCBFuGSRKiBAICASyjggS1MIIEsTCCA5mgAwIBAgIBKjANBgkqhkiG9w0B
AQsFADBJMQswCQYDVQQGEwJDSDEiMCAGA1UECgwZU1NMc3BsaXQgVGVzdCBDZXJ0
aWZpY2F0ZTEWMBQGA1UEAwwNZGFuaWVsLnJvZS5jaDAeFw0xODA4MjgyMzM3MjRa
Fw0xOTA4MjgyMzM3MjRaMEkxCzAJBgNVBAYTAkNIMSIwIAYDVQQKDBlTU0xzcGxp
dCBUZXN0IENlcnRpZmljYXRlMRYwFAYDVQQDDA1kYW5pZWwucm9lLmNoMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUmwWoteX9O8HSTleRps4yCPrEDA
fxafGOdWFjUDZxcf+7gMt0SHKOH3XfqrWEeP+G6m1MfRoQeHuEN0OsX0+4+FkQnv
xXN8fZh0gLFq2NmhUeqysNLnep3rYTqwMNGJ/Z0CBoXxTfezFhlJPdqx7lVnr2wu
7WHRnCIlY6pgaXHzPOF/P9qXMxKpjjU6NlVJC4pELPUJgSW9r9nBiIP6h/3AJct8
JZEUTysQzZcC5KfzFPFSEhu/WfnoNFpe9TLswuEgBzHJSJOI6vho5yVGtc77DwCi
1j5tFYDkW109FzZM5sL+Ee5lc2VNi11hGg36ujnBLDfYQBM+yIipu/3AVQIDAQAB
o4IBojCCAZ4wCQYDVR0TBAIwADAdBgNVHQ4EFgQUjbdZF2ENLvl4E3Adgs6GeiJD
sTswcQYDVR0jBGowaIAUjbdZF2ENLvl4E3Adgs6GeiJDsTuhTaRLMEkxCzAJBgNV
BAYTAkNIMSIwIAYDVQQKDBlTU0xzcGxpdCBUZXN0IENlcnRpZmljYXRlMRYwFAYD
VQQDDA1kYW5pZWwucm9lLmNoggEqMDoGCCsGAQUFBwEBBC4wLDAqBggrBgEFBQcw
AYYeaHR0cDovL2RhbmllbC5yb2UuY2gvdGVzdC9vY3NwMC4GA1UdHwQnMCUwI6Ah
oB+GHWh0dHA6Ly9kYW5pZWwucm9lLmNoL3Rlc3QvY3JsMIGSBgNVHREEgYowgYek
SzBJMQswCQYDVQQGEwJDSDEiMCAGA1UECgwZU1NMc3BsaXQgVGVzdCBDZXJ0aWZp
Y2F0ZTEWMBQGA1UEAwwNZGFuaWVsLnJvZS5jaIINZGFuaWVsLnJvZS5jaIcEfwAA
AYENZGFuaWVsQHJvZS5jaIIKd3d3LnJvZS5jaIIIKi5yb2UuY2gwDQYJKoZIhvcN
AQELBQADggEBAJarJbmOlJk/scb/sTd38v/y3GJ0Uho90RNJiBASokftJhBwHVVb
zuY+1sqA5uD/oIN4af3Mq8quG6e8ZbRv8q/Q1eBDHsxG1sQnKHLSZQQD1su/ovAw
690Qyhosk86obS91PdtB81wfzb/KLdsV3D+9CTCTLZXyqE8vTwq1csDvFSgFuyY2
NRxyPviyxaa9K6mM7KI0B8KPcwaOjfOj4Xjujr9Ejk9Sx2kBnpHHhtTCQ8k4oe/s
avn/R2GPWSUCcwIQ5OdtW7YhhQxXl9X435GtCU430JPnDmSjxGpveN5ZofsgVsDT
Ud07A8i3e915pltac5mtwtPqaxtIsUod3WmkAgQApQMCARKpBAICASyqgaMEgaAM
WyMM1IB1slH1ghDpOWuKeroyfgGeQGetuqUjt/R64h66U559fUGhw96SjPmFh6YG
dpkTry9kqIX35BJHZXj0NKQKwujfi5du5Ao/UpDDUK8PADlGX20LI5ElJt7lR8KX
2eIIk7zM7kIGxjEVznvwJX7e7L4y++tTWmGiB/FfF1FfffnsuBmbbIyKGkDlRv3q
a0GfcZvanfTsuyrim0jA
-----END SSL SESSION PARAMETERS-----

@ -0,0 +1,34 @@
-----BEGIN SSL SESSION PARAMETERS-----
MIIF4AIBAQICAwMEAsAwBCD99EQxVstbLQn6ooCm3xUqSFds8YTvPYyzEGSgyfCo
eQQwkceATL9ka1XD0DXyTSeZgrTlOCXdgrKQAMCUbuG79oz51k61TRD3YtI41A9g
N6rsoQYCBFt//ZSiBAICASyjggS1MIIEsTCCA5mgAwIBAgIBKjANBgkqhkiG9w0B
AQsFADBJMQswCQYDVQQGEwJDSDEiMCAGA1UECgwZU1NMc3BsaXQgVGVzdCBDZXJ0
aWZpY2F0ZTEWMBQGA1UEAwwNZGFuaWVsLnJvZS5jaDAeFw0xNjA3MTAxNDQ2Mjda
Fw0xNzA3MTAxNDQ2MjdaMEkxCzAJBgNVBAYTAkNIMSIwIAYDVQQKDBlTU0xzcGxp
dCBUZXN0IENlcnRpZmljYXRlMRYwFAYDVQQDDA1kYW5pZWwucm9lLmNoMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsmDmPE1fTVAj6ketPcQLm/GIarFk
75Ws6u+a33OfliUwl5jdOob2P7+iTI9jLjfCeQSOhN5oRi8wsD35ef0ZnORYe1MV
/bB4KOR8IjS3GPdQUO5Vl5wg9tijSnjvcBLdlM9BpLDk0lCUpAC1AJ9kHmdKUmUe
vmKtAl8f1URdm+MyProp7CcrRb0OXNDxCLLUiqUst85Ea88FbUaFLjO3vSKbSjP7
gpaWE0rzdBIM8b0bQTi/KrNpkRdi0bgNkHP1krfcpoVG1Dh1vXU1k8ojfN9I79BZ
rBZihw+dgriSgsntJ+GJ660qFGq7OKFg3qYb5F9CaelW8Cp9livQM611qwIDAQAB
o4IBojCCAZ4wCQYDVR0TBAIwADAdBgNVHQ4EFgQU9gOZ22GLXy9k7xPQx+8FebKe
w/0wcQYDVR0jBGowaIAU9gOZ22GLXy9k7xPQx+8FebKew/2hTaRLMEkxCzAJBgNV
BAYTAkNIMSIwIAYDVQQKDBlTU0xzcGxpdCBUZXN0IENlcnRpZmljYXRlMRYwFAYD
VQQDDA1kYW5pZWwucm9lLmNoggEqMDoGCCsGAQUFBwEBBC4wLDAqBggrBgEFBQcw
AYYeaHR0cDovL2RhbmllbC5yb2UuY2gvdGVzdC9vY3NwMC4GA1UdHwQnMCUwI6Ah
oB+GHWh0dHA6Ly9kYW5pZWwucm9lLmNoL3Rlc3QvY3JsMIGSBgNVHREEgYowgYek
SzBJMQswCQYDVQQGEwJDSDEiMCAGA1UECgwZU1NMc3BsaXQgVGVzdCBDZXJ0aWZp
Y2F0ZTEWMBQGA1UEAwwNZGFuaWVsLnJvZS5jaIINZGFuaWVsLnJvZS5jaIcEfwAA
AYENZGFuaWVsQHJvZS5jaIIKd3d3LnJvZS5jaIIIKi5yb2UuY2gwDQYJKoZIhvcN
AQELBQADggEBACWKufl7k92NsxvW9igq0UnXgenh4EMfYSMARmwHPylRvG4LxIwb
41deKXjQmxx6F0WLLlUWm4CQlPnCxnCPWSB1rXl0ynEES4dM7VBYtl8iqt6rGnKh
noECYnnnRcI7JGFE8s8+IAW/2839hNDwJZIZgF2DMe1VLV6eWPdKAv94Y6YHmwAp
oP4v67+psWOfj4Nd6T5sVgx8/lH8k4XytHCt91fXMdEEcRhPS5mLwgkYz83cp9eK
buY+ddcK3lcZYG9l9qA8ryRWYXvr2Ui5+fMpbLp5GUn2WF/fcKRbR3+Stb/Nsai6
mLBehp2NgQKMadeZnKwletsVJ13pplqT576kAgQApQMCAQqpBAICASyqgaMEgaAo
OJ0AEd8RMUttoTZnEiAcOfRkEFjjruP32TA985bq5ENIAtMhtULMV/hM+QWJTXup
pwA64f7yN9NvmEXaHJro5ZAac7CPFaPQn+smlSdeLcV8fq6P1+TPVjJT7ORJagqH
BO8xWgp7Xr7Pc7vfDHb1qsA21zBO67YBHH+NszphUG+8vHxVQVQqxMuWPN2yIpIy
G/V2qk9Ou2RoqtzAC5PAqwMEAQE=
-----END SSL SESSION PARAMETERS-----

10
log.c

@ -878,7 +878,7 @@ log_content_file_preinit(const char *logfile)
log_err_level_printf(LOG_CRIT, "Failed to realpath '%s': %s (%i)\n",
logfile, strerror(errno), errno);
close(content_file_fd);
connect_fd = -1;
content_file_fd = -1;
return -1;
}
return 0;
@ -911,14 +911,6 @@ log_content_file_reopencb(void)
return 0;
}
/*
static int
log_content_file_opencb(void *fh)
{
return 0;
}
*/
static void
log_content_file_closecb(void *fh)
{

@ -126,8 +126,9 @@ main_usage(void)
{
const char *dflt, *warn;
const char *usagefmt =
"Usage: %s [options...] [proxyspecs...]\n"
"Usage: %s [-D] [-f conffile] [-o opt=val] [options...] [proxyspecs...]\n"
" -f conffile use conffile to load configuration from\n"
" -o opt=val override conffile option opt with value val\n"
" -c pemfile use CA cert (and key) from pemfile to sign forged certs\n"
" -k pemfile use CA key (and cert) from pemfile to sign forged certs\n"
" -C pemfile use CA chain from pemfile (intermediate and root CA certs)\n"
@ -163,6 +164,12 @@ main_usage(void)
" -r proto only support one of " SSL_PROTO_SUPPORT_S "(default: all)\n"
" -R proto disable one of " SSL_PROTO_SUPPORT_S "(default: none)\n"
" -s ciphers use the given OpenSSL cipher suite spec (default: " DFLT_CIPHERS ")\n"
#ifndef OPENSSL_NO_ENGINE
" -x engine load OpenSSL engine with the given identifier\n"
#define OPT_x "x:"
#else /* OPENSSL_NO_ENGINE */
#define OPT_x
#endif /* OPENSSL_NO_ENGINE */
" -e engine specify default NAT engine to use (default: %s)\n"
" -E list available NAT engines and exit\n"
" -u user drop privileges to user (default if run as root: " DFLT_DROPUSER ")\n"
@ -306,8 +313,9 @@ main(int argc, char *argv[])
natengine = NULL;
}
while ((ch = getopt(argc, argv, OPT_g OPT_G OPT_Z OPT_i "k:c:C:K:t:OPa:"
"b:s:r:R:e:Eu:m:j:p:l:L:S:F:M:dD::VhW:w:q:f:I")) != -1) {
while ((ch = getopt(argc, argv, OPT_g OPT_G OPT_Z OPT_i OPT_x
"k:c:C:K:t:OPa:b:s:r:R:e:Eu:m:j:p:l:L:S:F:M:"
"dD::VhW:w:q:f:o:I")) != -1) {
switch (ch) {
case 'f':
if (opts->conffile)
@ -315,8 +323,16 @@ main(int argc, char *argv[])
opts->conffile = strdup(optarg);
if (!opts->conffile)
oom_die(argv0);
if (load_conffile(opts, argv0, &natengine) == -1) {
exit(EXIT_FAILURE);
}
fprintf(stderr, "Conf file: %s\n", opts->conffile);
break;
case 'o':
if (opts_set_option(opts, argv0, optarg, &natengine) == -1) {
exit(EXIT_FAILURE);
}
break;
case 'c':
opts_set_cacrt(opts, argv0, optarg);
break;
@ -354,10 +370,8 @@ main(int argc, char *argv[])
#endif /* !OPENSSL_NO_DH */
#ifndef OPENSSL_NO_ECDH
case 'G':
{
opts_set_ecdhcurve(opts, argv0, optarg);
break;
}
#endif /* !OPENSSL_NO_ECDH */
#ifdef SSL_OP_NO_COMPRESSION
case 'Z':
@ -373,6 +387,11 @@ main(int argc, char *argv[])
case 'R':
opts_disable_proto(opts, argv0, optarg);
break;
#ifndef OPENSSL_NO_ENGINE
case 'x':
opts_set_openssl_engine(opts, argv0, optarg);
break;
#endif /* !OPENSSL_NO_ENGINE */
case 'e':
if (natengine)
free(natengine);
@ -408,7 +427,7 @@ main(int argc, char *argv[])
case 'S':
opts_set_contentlogdir(opts, argv0, optarg);
break;
case 'F': {
case 'F':
opts_set_contentlogpathspec(opts, argv0, optarg);
break;
case 'W':
@ -417,7 +436,6 @@ main(int argc, char *argv[])
case 'w':
opts_set_certgendir_writegencerts(opts, argv0, optarg);
break;
}
#ifdef HAVE_LOCAL_PROCINFO
case 'i':
opts_set_lprocinfo(opts);
@ -452,12 +470,6 @@ main(int argc, char *argv[])
argv += optind;
proxyspec_parse(&argc, &argv, natengine, &opts->spec);
if (opts->conffile) {
if (load_conffile(opts, argv0, natengine) == -1) {
exit(EXIT_FAILURE);
}
}
/* usage checks before defaults */
if (opts->detach && OPTS_DEBUG(opts)) {
fprintf(stderr, "%s: -d and -D are mutually exclusive.\n",
@ -493,6 +505,14 @@ main(int argc, char *argv[])
argv0);
exit(EXIT_FAILURE);
}
#ifndef OPENSSL_NO_ENGINE
if (opts->openssl_engine &&
ssl_engine(opts->openssl_engine) == -1) {
fprintf(stderr, "%s: failed to enable OpenSSL engine"
" %s.\n", argv0, opts->openssl_engine);
exit(EXIT_FAILURE);
}
#endif /* !OPENSSL_NO_ENGINE */
if ((opts->cacrt || !opts->tgcrtdir) && !opts->cakey) {
fprintf(stderr, "%s: no CA key specified (-k).\n",
argv0);
@ -552,6 +572,19 @@ main(int argc, char *argv[])
}
#endif /* __APPLE__ */
}
/* usage checks after defaults */
if (opts->dropgroup && !opts->dropuser) {
fprintf(stderr, "%s: -m depends on -u.\n", argv0);
exit(EXIT_FAILURE);
}
/* debug log, part 1 */
if (OPTS_DEBUG(opts)) {
main_version();
}
/* generate leaf key */
if (opts_has_ssl_spec(opts) && opts->cakey && !opts->key) {
/*
* While browsers still generally accept it, use a leaf key
@ -572,7 +605,6 @@ main(int argc, char *argv[])
log_dbg_printf("Generated RSA key for leaf certs.\n");
}
}
if (opts->certgendir) {
char *keyid, *keyfn;
int prv;
@ -607,15 +639,8 @@ main(int argc, char *argv[])
fclose(keyf);
}
/* usage checks after defaults */
if (opts->dropgroup && !opts->dropuser) {
fprintf(stderr, "%s: -m depends on -u.\n", argv0);
exit(EXIT_FAILURE);
}
/* debugging */
/* debug log, part 2 */
if (OPTS_DEBUG(opts)) {
main_version();
opts_proto_dbg_dump(opts);
log_dbg_printf("proxyspecs:\n");
for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) {
@ -627,6 +652,12 @@ main(int argc, char *argv[])
log_dbg_printf("- %s\n", specstr);
free(specstr);
}
#ifndef OPENSSL_NO_ENGINE
if (opts->openssl_engine) {
log_dbg_printf("Loaded OpenSSL engine %s\n",
opts->openssl_engine);
}
#endif /* !OPENSSL_NO_ENGINE */
if (opts->cacrt) {
char *subj = ssl_x509_subject(opts->cacrt);
log_dbg_printf("Loaded CA: '%s'\n", subj);

@ -36,9 +36,6 @@
#include <event2/util.h>
/* The longest natengine is "netfilter" */
#define NATENGINE_SIZE 10
typedef int (*nat_lookup_cb_t)(struct sockaddr *, socklen_t *, evutil_socket_t,
struct sockaddr *, socklen_t);
typedef int (*nat_socket_cb_t)(evutil_socket_t);

694
opts.c

@ -109,6 +109,11 @@ opts_free(opts_t *opts)
if (opts->ciphers) {
free(opts->ciphers);
}
#ifndef OPENSSL_NO_ENGINE
if (opts->openssl_engine) {
free(opts->openssl_engine);
}
#endif /* !OPENSSL_NO_ENGINE */
if (opts->tgcrtdir) {
free(opts->tgcrtdir);
}
@ -317,17 +322,10 @@ proxyspec_parse(int *argc, char **argv[], const char *natengine, proxyspec_t **o
break;
case 2:
/* listenport */
if (strstr(addr, ":"))
af = AF_INET6;
else if (!strpbrk(addr, "abcdefghijklmnopqrstu"
"vwxyzABCDEFGHIJKLMNOP"
"QRSTUVWXYZ-"))
af = AF_INET;
else
af = AF_UNSPEC;
af = sys_sockaddr_parse(&spec->listen_addr,
&spec->listen_addrlen,
addr, **argv, af,
addr, **argv,
sys_get_af(addr),
EVUTIL_AI_PASSIVE);
if (af == -1) {
exit(EXIT_FAILURE);
@ -567,7 +565,7 @@ opts_set_cacrt(opts_t *opts, const char *argv0, const char *optarg)
opts->dh = ssl_dh_load(optarg);
}
#endif /* !OPENSSL_NO_DH */
fprintf(stderr, "CACert: %s\n", optarg);
log_dbg_printf("CACert: %s\n", optarg);
}
void
@ -602,7 +600,7 @@ opts_set_cakey(opts_t *opts, const char *argv0, const char *optarg)
opts->dh = ssl_dh_load(optarg);
}
#endif /* !OPENSSL_NO_DH */
fprintf(stderr, "CAKey: %s\n", optarg);
log_dbg_printf("CAKey: %s\n", optarg);
}
void
@ -621,7 +619,7 @@ opts_set_chain(opts_t *opts, const char *argv0, const char *optarg)
}
exit(EXIT_FAILURE);
}
fprintf(stderr, "CAChain: %s\n", optarg);
log_dbg_printf("CAChain: %s\n", optarg);
}
void
@ -647,7 +645,7 @@ opts_set_key(opts_t *opts, const char *argv0, const char *optarg)
opts->dh = ssl_dh_load(optarg);
}
#endif /* !OPENSSL_NO_DH */
fprintf(stderr, "LeafCerts: %s\n", optarg);
log_dbg_printf("LeafCerts: %s\n", optarg);
}
void
@ -656,7 +654,7 @@ opts_set_crl(opts_t *opts, const char *optarg)
if (opts->crlurl)
free(opts->crlurl);
opts->crlurl = strdup(optarg);
fprintf(stderr, "CRL: %s\n", opts->crlurl);
log_dbg_printf("CRL: %s\n", opts->crlurl);
}
void
@ -673,7 +671,7 @@ opts_set_tgcrtdir(opts_t *opts, const char *argv0, const char *optarg)
opts->tgcrtdir = strdup(optarg);
if (!opts->tgcrtdir)
oom_die(argv0);
fprintf(stderr, "TargetCertDir: %s\n", opts->tgcrtdir);
log_dbg_printf("TargetCertDir: %s\n", opts->tgcrtdir);
}
static void
@ -691,7 +689,8 @@ opts_set_certgendir_writegencerts(opts_t *opts, const char *argv0, const char *o
{
opts->certgen_writeall = 0;
set_certgendir(opts, argv0, optarg);
fprintf(stderr, "WriteGenCertsDir: certgendir=%s, writeall=%u\n", opts->certgendir, opts->certgen_writeall);
log_dbg_printf("WriteGenCertsDir: certgendir=%s, writeall=%u\n",
opts->certgendir, opts->certgen_writeall);
}
void
@ -699,7 +698,8 @@ opts_set_certgendir_writeall(opts_t *opts, const char *argv0, const char *optarg
{
opts->certgen_writeall = 1;
set_certgendir(opts, argv0, optarg);
fprintf(stderr, "WriteAllCertsDir: certgendir=%s, writeall=%u\n", opts->certgendir, opts->certgen_writeall);
log_dbg_printf("WriteAllCertsDir: certgendir=%s, writeall=%u\n",
opts->certgendir, opts->certgen_writeall);
}
void
@ -744,7 +744,7 @@ opts_set_clientcrt(opts_t *opts, const char *argv0, const char *optarg)
}
exit(EXIT_FAILURE);
}
fprintf(stderr, "ClientCert: %s\n", optarg);
log_dbg_printf("ClientCert: %s\n", optarg);
}
void
@ -765,7 +765,7 @@ opts_set_clientkey(opts_t *opts, const char *argv0, const char *optarg)
}
exit(EXIT_FAILURE);
}
fprintf(stderr, "ClientKey: %s\n", optarg);
log_dbg_printf("ClientKey: %s\n", optarg);
}
#ifndef OPENSSL_NO_DH
@ -787,7 +787,7 @@ opts_set_dh(opts_t *opts, const char *argv0, const char *optarg)
}
exit(EXIT_FAILURE);
}
fprintf(stderr, "DHGroupParams: %s\n", optarg);
log_dbg_printf("DHGroupParams: %s\n", optarg);
}
#endif /* !OPENSSL_NO_DH */
@ -808,7 +808,7 @@ opts_set_ecdhcurve(opts_t *opts, const char *argv0, const char *optarg)
opts->ecdhcurve = strdup(optarg);
if (!opts->ecdhcurve)
oom_die(argv0);
fprintf(stderr, "ECDHCurve: %s\n", opts->ecdhcurve);
log_dbg_printf("ECDHCurve: %s\n", opts->ecdhcurve);
}
#endif /* !OPENSSL_NO_ECDH */
@ -832,8 +832,21 @@ opts_set_ciphers(opts_t *opts, const char *argv0, const char *optarg)
opts->ciphers = strdup(optarg);
if (!opts->ciphers)
oom_die(argv0);
fprintf(stderr, "Ciphers: %s\n", opts->ciphers);
log_dbg_printf("Ciphers: %s\n", opts->ciphers);
}
#ifndef OPENSSL_NO_ENGINE
void
opts_set_openssl_engine(opts_t *opts, const char *argv0, const char *optarg)
{
if (opts->openssl_engine)
free(opts->openssl_engine);
opts->openssl_engine = strdup(optarg);
if (!opts->openssl_engine)
oom_die(argv0);
log_dbg_printf("OpenSSLEngine: %s\n", opts->openssl_engine);
}
#endif /* !OPENSSL_NO_ENGINE */
/*
* Parse SSL proto string in optarg and look up the corresponding SSL method.
@ -909,7 +922,7 @@ opts_force_proto(opts_t *opts, const char *argv0, const char *optarg)
argv0, optarg);
exit(EXIT_FAILURE);
}
fprintf(stderr, "ForceSSLProto: %s\n", optarg);
log_dbg_printf("ForceSSLProto: %s\n", optarg);
}
/*
@ -949,7 +962,7 @@ opts_disable_proto(opts_t *opts, const char *argv0, const char *optarg)
argv0, optarg);
exit(EXIT_FAILURE);
}
fprintf(stderr, "DisableSSLProto: %s\n", optarg);
log_dbg_printf("DisableSSLProto: %s\n", optarg);
}
void
@ -966,7 +979,7 @@ opts_set_user(opts_t *opts, const char *argv0, const char *optarg)
opts->dropuser = strdup(optarg);
if (!opts->dropuser)
oom_die(argv0);
fprintf(stderr, "User: %s\n", opts->dropuser);
log_dbg_printf("User: %s\n", opts->dropuser);
}
void
@ -984,7 +997,7 @@ opts_set_group(opts_t *opts, const char *argv0, const char *optarg)
opts->dropgroup = strdup(optarg);
if (!opts->dropgroup)
oom_die(argv0);
fprintf(stderr, "Group: %s\n", opts->dropgroup);
log_dbg_printf("Group: %s\n", opts->dropgroup);
}
void
@ -1007,7 +1020,7 @@ opts_set_jaildir(opts_t *opts, const char *argv0, const char *optarg)
strerror(errno), errno);
exit(EXIT_FAILURE);
}
fprintf(stderr, "Chroot: %s\n", opts->jaildir);
log_dbg_printf("Chroot: %s\n", opts->jaildir);
}
void
@ -1018,7 +1031,7 @@ opts_set_pidfile(opts_t *opts, const char *argv0, const char *optarg)
opts->pidfile = strdup(optarg);
if (!opts->pidfile)
oom_die(argv0);
fprintf(stderr, "PidFile: %s\n", opts->pidfile);
log_dbg_printf("PidFile: %s\n", opts->pidfile);
}
void
@ -1029,7 +1042,7 @@ opts_set_connectlog(opts_t *opts, const char *argv0, const char *optarg)
opts->connectlog = strdup(optarg);
if (!opts->connectlog)
oom_die(argv0);
fprintf(stderr, "ConnectLog: %s\n", opts->connectlog);
log_dbg_printf("ConnectLog: %s\n", opts->connectlog);
}
void
@ -1042,7 +1055,7 @@ opts_set_contentlog(opts_t *opts, const char *argv0, const char *optarg)
oom_die(argv0);
opts->contentlog_isdir = 0;
opts->contentlog_isspec = 0;
fprintf(stderr, "ContentLog: %s\n", opts->contentlog);
log_dbg_printf("ContentLog: %s\n", opts->contentlog);
}
void
@ -1067,18 +1080,18 @@ opts_set_contentlogdir(opts_t *opts, const char *argv0, const char *optarg)
}
opts->contentlog_isdir = 1;
opts->contentlog_isspec = 0;
fprintf(stderr, "ContentLogDir: %s\n", opts->contentlog);
log_dbg_printf("ContentLogDir: %s\n", opts->contentlog);
}
void
opts_set_contentlogpathspec(opts_t *opts, const char *argv0, const char *optarg)
static void
opts_set_logbasedir(const char *argv0, const char *optarg, char **basedir, char **log)
{
char *lhs, *rhs, *p, *q;
size_t n;
if (opts->contentlog_basedir)
free(opts->contentlog_basedir);
if (opts->contentlog)
free(opts->contentlog);
if (*basedir)
free(*basedir);
if (*log)
free(*log);
if (log_content_split_pathspec(optarg, &lhs,
&rhs) == -1) {
fprintf(stderr, "%s: Failed to split "
@ -1104,8 +1117,8 @@ opts_set_contentlogpathspec(opts_t *opts, const char *argv0, const char *optarg)
strerror(errno), errno);
exit(EXIT_FAILURE);
}
opts->contentlog_basedir = realpath(lhs, NULL);
if (!opts->contentlog_basedir) {
*basedir = realpath(lhs, NULL);
if (!*basedir) {
fprintf(stderr, "%s: Failed to "
"canonicalize '%s': "
"%s (%i)\n",
@ -1113,19 +1126,19 @@ opts_set_contentlogpathspec(opts_t *opts, const char *argv0, const char *optarg)
strerror(errno), errno);
exit(EXIT_FAILURE);
}
/* count '%' in opts->contentlog_basedir */
for (n = 0, p = opts->contentlog_basedir;
/* count '%' in basedir */
for (n = 0, p = *basedir;
*p;
p++) {
if (*p == '%')
n++;
}
free(lhs);
n += strlen(opts->contentlog_basedir);
n += strlen(*basedir);
if (!(lhs = malloc(n + 1)))
oom_die(argv0);
/* re-encoding % to %%, copying basedir to lhs */
for (p = opts->contentlog_basedir, q = lhs;
for (p = *basedir, q = lhs;
*p;
p++, q++) {
*q = *p;
@ -1134,14 +1147,21 @@ opts_set_contentlogpathspec(opts_t *opts, const char *argv0, const char *optarg)
}
*q = '\0';
/* lhs contains encoded realpathed basedir */
if (asprintf(&opts->contentlog,
if (asprintf(log,
"%s/%s", lhs, rhs) < 0)
oom_die(argv0);
opts->contentlog_isdir = 0;
opts->contentlog_isspec = 1;
free(lhs);
free(rhs);
fprintf(stderr, "ContentLogPathSpec: basedir=%s, %s\n", opts->contentlog_basedir, opts->contentlog);
}
void
opts_set_contentlogpathspec(opts_t *opts, const char *argv0, const char *optarg)
{
opts_set_logbasedir(argv0, optarg, &opts->contentlog_basedir, &opts->contentlog);
opts->contentlog_isdir = 0;
opts->contentlog_isspec = 1;
log_dbg_printf("ContentLogPathSpec: basedir=%s, %s\n",
opts->contentlog_basedir, opts->contentlog);
}
#ifdef HAVE_LOCAL_PROCINFO
@ -1166,7 +1186,7 @@ opts_set_masterkeylog(opts_t *opts, const char *argv0, const char *optarg)
opts->masterkeylog = strdup(optarg);
if (!opts->masterkeylog)
oom_die(argv0);
fprintf(stderr, "MasterKeyLog: %s\n", opts->masterkeylog);
log_dbg_printf("MasterKeyLog: %s\n", opts->masterkeylog);
}
void
@ -1209,7 +1229,7 @@ opts_set_debug_level(const char *optarg)
fprintf(stderr, "Invalid DebugLevel '%s', use 2-4\n", optarg);
exit(EXIT_FAILURE);
}
fprintf(stderr, "DebugLevel: %s\n", optarg);
log_dbg_printf("DebugLevel: %s\n", optarg);
}
void
@ -1273,7 +1293,7 @@ opts_unset_allow_wrong_host(opts_t *opts)
}
static int
check_value_yesno(char *value, char *name, int line_num)
check_value_yesno(const char *value, const char *name, int line_num)
{
/* Compare strlen(s2)+1 chars to match exactly */
if (!strncmp(value, "yes", 4)) {
@ -1281,21 +1301,328 @@ check_value_yesno(char *value, char *name, int line_num)
} else if (!strncmp(value, "no", 3)) {
return 0;
}
fprintf(stderr, "Error in conf file: Invalid '%s' value '%s' at line %d, use yes|no\n", name, value, line_num);
fprintf(stderr, "Error in conf: Invalid '%s' value '%s' at line %d, use yes|no\n", name, value, line_num);
return -1;
}
#define MAX_TOKEN 10
static int
set_option(opts_t *opts, const char *argv0, const char *name, char *value, char **natengine, int line_num)
{
int yes;
int retval = -1;
/* Compare strlen(s2)+1 chars to match exactly */
if (!strncmp(name, "CACert", 7)) {
opts_set_cacrt(opts, argv0, value);
} else if (!strncmp(name, "CAKey", 6)) {
opts_set_cakey(opts, argv0, value);
} else if (!strncmp(name, "ClientCert", 11)) {
opts_set_clientcrt(opts, argv0, value);
} else if (!strncmp(name, "ClientKey", 10)) {
opts_set_clientkey(opts, argv0, value);
} else if (!strncmp(name, "CAChain", 8)) {
opts_set_chain(opts, argv0, value);
} else if (!strncmp(name, "LeafCerts", 10)) {
opts_set_key(opts, argv0, value);
} else if (!strncmp(name, "CRL", 4)) {
opts_set_crl(opts, value);
} else if (!strncmp(name, "TargetCertDir", 14)) {
opts_set_tgcrtdir(opts, argv0, value);
} else if (!strncmp(name, "WriteGenCertsDir", 17)) {
opts_set_certgendir_writegencerts(opts, argv0, value);
} else if (!strncmp(name, "WriteAllCertsDir", 17)) {
opts_set_certgendir_writeall(opts, argv0, value);
} else if (!strncmp(name, "DenyOCSP", 9)) {
yes = check_value_yesno(value, "DenyOCSP", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_deny_ocsp(opts) : opts_unset_deny_ocsp(opts);
log_dbg_printf("DenyOCSP: %u\n", opts->deny_ocsp);
} else if (!strncmp(name, "Passthrough", 12)) {
yes = check_value_yesno(value, "Passthrough", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_passthrough(opts) : opts_unset_passthrough(opts);
log_dbg_printf("Passthrough: %u\n", opts->passthrough);
#ifndef OPENSSL_NO_DH
} else if (!strncmp(name, "DHGroupParams", 14)) {
opts_set_dh(opts, argv0, value);
#endif /* !OPENSSL_NO_DH */
#ifndef OPENSSL_NO_ECDH
} else if (!strncmp(name, "ECDHCurve", 10)) {
opts_set_ecdhcurve(opts, argv0, value);
#endif /* !OPENSSL_NO_ECDH */
#ifdef SSL_OP_NO_COMPRESSION
} else if (!strncmp(name, "SSLCompression", 15)) {
yes = check_value_yesno(value, "SSLCompression", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_sslcomp(opts) : opts_unset_sslcomp(opts);
log_dbg_printf("SSLCompression: %u\n", opts->sslcomp);
#endif /* SSL_OP_NO_COMPRESSION */
} else if (!strncmp(name, "ForceSSLProto", 14)) {
opts_force_proto(opts, argv0, value);
} else if (!strncmp(name, "DisableSSLProto", 16)) {
opts_disable_proto(opts, argv0, value);
} else if (!strncmp(name, "Ciphers", 8)) {
opts_set_ciphers(opts, argv0, value);
#ifndef OPENSSL_NO_ENGINE
} else if (!strncmp(name, "OpenSSLEngine", 14)) {
opts_set_openssl_engine(opts, argv0, value);
#endif /* !OPENSSL_NO_ENGINE */
} else if (!strncmp(name, "NATEngine", 10)) {
if (*natengine)
free(*natengine);
*natengine = strdup(value);
if (!*natengine)
goto leave;
log_dbg_printf("NATEngine: %s\n", *natengine);
} else if (!strncmp(name, "User", 5)) {
opts_set_user(opts, argv0, value);
} else if (!strncmp(name, "Group", 6)) {
opts_set_group(opts, argv0, value);
} else if (!strncmp(name, "Chroot", 7)) {
opts_set_jaildir(opts, argv0, value);
} else if (!strncmp(name, "PidFile", 8)) {
opts_set_pidfile(opts, argv0, value);
} else if (!strncmp(name, "ConnectLog", 11)) {
opts_set_connectlog(opts, argv0, value);
} else if (!strncmp(name, "ContentLog", 11)) {
opts_set_contentlog(opts, argv0, value);
} else if (!strncmp(name, "ContentLogDir", 14)) {
opts_set_contentlogdir(opts, argv0, value);
} else if (!strncmp(name, "ContentLogPathSpec", 19)) {
opts_set_contentlogpathspec(opts, argv0, value);
#ifdef HAVE_LOCAL_PROCINFO
} else if (!strncmp(name, "LogProcInfo", 11)) {
yes = check_value_yesno(value, "LogProcInfo", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_lprocinfo(opts) : opts_unset_lprocinfo(opts);
log_dbg_printf("LogProcInfo: %u\n", opts->lprocinfo);
#endif /* HAVE_LOCAL_PROCINFO */
} else if (!strncmp(name, "MasterKeyLog", 13)) {
opts_set_masterkeylog(opts, argv0, value);
} else if (!strncmp(name, "Daemon", 7)) {
yes = check_value_yesno(value, "Daemon", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_daemon(opts) : opts_unset_daemon(opts);
log_dbg_printf("Daemon: %u\n", opts->detach);
} else if (!strncmp(name, "Debug", 6)) {
yes = check_value_yesno(value, "Debug", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_debug(opts) : opts_unset_debug(opts);
log_dbg_printf("Debug: %u\n", opts->debug);
} else if (!strncmp(name, "DebugLevel", 11)) {
opts_set_debug_level(value);
} else if (!strncmp(name, "ProxySpec", 10)) {
/* Use MAX_TOKEN instead of computing the actual number of tokens in value */
char **argv = malloc(sizeof(char *) * MAX_TOKEN);
char **save_argv = argv;
int argc = 0;
char *p, *last = NULL;
for ((p = strtok_r(value, " ", &last)); p; (p = strtok_r(NULL, " ", &last))) {
/* Limit max # token */
if (argc < MAX_TOKEN) {
argv[argc++] = p;
} else {
break;
}
}
proxyspec_parse(&argc, &argv, *natengine, &opts->spec);
free(save_argv);
} else if (!strncasecmp(name, "VerifyPeer", 11)) {
yes = check_value_yesno(value, "VerifyPeer", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_verify_peer(opts) : opts_unset_verify_peer(opts);
log_dbg_printf("VerifyPeer: %u\n", opts->verify_peer);
} else if (!strncasecmp(name, "AllowWrongHost", 15)) {
yes = check_value_yesno(value, "AllowWrongHost", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_allow_wrong_host(opts) : opts_unset_allow_wrong_host(opts);
log_dbg_printf("AllowWrongHost: %u\n", opts->allow_wrong_host);
} else if (!strncasecmp(name, "ConnIdleTimeout", 16)) {
unsigned int i = atoi(value);
if (i >= 10 && i <= 3600) {
opts->conn_idle_timeout = i;
} else {
fprintf(stderr, "Invalid ConnIdleTimeout %s at line %d, use 10-3600\n", value, line_num);
goto leave;
}
log_dbg_printf("ConnIdleTimeout: %u\n", opts->conn_idle_timeout);
} else if (!strncasecmp(name, "ExpiredConnCheckPeriod", 23)) {
unsigned int i = atoi(value);
if (i >= 10 && i <= 60) {
opts->expired_conn_check_period = i;
} else {
fprintf(stderr, "Invalid ExpiredConnCheckPeriod %s at line %d, use 10-60\n", value, line_num);
goto leave;
}
log_dbg_printf("ExpiredConnCheckPeriod: %u\n", opts->expired_conn_check_period);
} else if (!strncasecmp(name, "SSLShutdownRetryDelay", 22)) {
unsigned int i = atoi(value);
if (i >= 100 && i <= 10000) {
opts->ssl_shutdown_retry_delay = i;
} else {
fprintf(stderr, "Invalid SSLShutdownRetryDelay %s at line %d, use 100-10000\n", value, line_num);
goto leave;
}
log_dbg_printf("SSLShutdownRetryDelay: %u\n", opts->ssl_shutdown_retry_delay);
} else if (!strncasecmp(name, "LogStats", 9)) {
yes = check_value_yesno(value, "LogStats", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_statslog(opts) : opts_unset_statslog(opts);
log_dbg_printf("LogStats: %u\n", opts->statslog);
} else if (!strncasecmp(name, "StatsPeriod", 12)) {
unsigned int i = atoi(value);
if (i >= 1 && i <= 10) {
opts->stats_period = i;
} else {
fprintf(stderr, "Invalid StatsPeriod %s at line %d, use 1-10\n", value, line_num);
goto leave;
}
log_dbg_printf("StatsPeriod: %u\n", opts->stats_period);
} else if (!strncasecmp(name, "RemoveHTTPAcceptEncoding", 25)) {
yes = check_value_yesno(value, "RemoveHTTPAcceptEncoding", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_remove_http_accept_encoding(opts) : opts_unset_remove_http_accept_encoding(opts);
log_dbg_printf("RemoveHTTPAcceptEncoding: %u\n", opts->remove_http_accept_encoding);
} else if (!strncasecmp(name, "RemoveHTTPReferer", 18)) {
yes = check_value_yesno(value, "RemoveHTTPReferer", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_remove_http_referer(opts) : opts_unset_remove_http_referer(opts);
log_dbg_printf("RemoveHTTPReferer: %u\n", opts->remove_http_referer);
} else {
fprintf(stderr, "Error in conf: Unknown option '%s' at line %d\n", name, line_num);
goto leave;
}
retval = 0;
leave:
return retval;
}
/*
* Separator param is needed for command line options only.
* Conf file option separator is ' '.
*/
static int
get_name_value(char **name, char **value, const char sep)
{
char *n, *v, *value_end;
int retval = -1;
/* Skip to the end of option name and terminate it with '\0' */
for (n = *name;; n++) {
/* White spaces possible around separator,
* if the command line option is passed between the quotes */
if (*n == ' ' || *n == '\t' || *n == sep) {
*n = '\0';
n++;
break;
}
if (*n == '\0') {
n = NULL;
break;
}
}
/* No option name */
if (n == NULL) {
fprintf(stderr, "Error in option: No option name\n");
goto leave;
}
/* White spaces possible before value and around separator,
* if the command line option is passed between the quotes */
while (*n == ' ' || *n == '\t' || *n == sep) {
n++;
}
*value = n;
/* Find end of value and terminate it with '\0'
* Find first occurrence of trailing white space */
value_end = NULL;
for (v = *value;; v++) {
if (*v == '\0') {
break;
}
if (*v == '\r' || *v == '\n') {
*v = '\0';
break;
}
if (*v == ' ' || *v == '\t') {
if (!value_end) {
value_end = v;
}
} else {
value_end = NULL;
}
}
if (value_end) {
*value_end = '\0';
}
retval = 0;
leave:
return retval;
}
int
load_conffile(opts_t *opts, const char *argv0, const char *prev_natengine)
opts_set_option(opts_t *opts, const char *argv0, const char *optarg, char **natengine)
{
FILE *f;
int rv, line_num, yes, retval;
char *name, *value;
int retval = -1;
char *line = strdup(optarg);
/* White spaces possible before option name,
* if the command line option is passed between the quotes */
for (name = line; *name == ' ' || *name == '\t'; name++);
/* Command line option separator is '=' */
retval = get_name_value(&name, &value, '=');
if (retval == 0) {
/* Line number param is for conf file, pass 0 for command line options */
retval = set_option(opts, argv0, name, value, natengine, 0);
}
if (line) {
free(line);
}
return retval;
}
int
load_conffile(opts_t *opts, const char *argv0, char **natengine)
{
int retval, line_num;
char *line, *name, *value;
size_t line_len;
char *n, *value, *v, *value_end;
char *line, *name;
char natengine[NATENGINE_SIZE];
FILE *f;
f = fopen(opts->conffile, "r");
if (!f) {
@ -1303,14 +1630,11 @@ load_conffile(opts_t *opts, const char *argv0, const char *prev_natengine)
return -1;
}
strncpy(natengine, prev_natengine, NATENGINE_SIZE);
line = NULL;
line_num = 0;
retval = -1;
while (!feof(f)) {
rv = getline(&line, &line_len, f);
if (rv == -1) {
if (getline(&line, &line_len, f) == -1) {
break;
}
if (line == NULL) {
@ -1328,256 +1652,16 @@ load_conffile(opts_t *opts, const char *argv0, const char *prev_natengine)
continue;
}
/* Skip to the end of option name and terminate it with '\0' */
for (n = name;; n++) {
if (*n == ' ' || *n == '\t') {
*n = '\0';
n++;
break;
}
if (*n == '\0') {
n = NULL;
break;
}
}
/* No value */
if (n == NULL) {
fprintf(stderr, "Error in conf file: No value at line %d\n", line_num);
goto leave;
}
/* Skip white space before value */
while (*n == ' ' || *n == '\t') {
n++;
}
value = n;
/* Find end of value and terminate it with '\0'
Find first occurrence of trailing white space */
value_end = NULL;
for (v = value;; v++) {
if (*v == '\0') {
break;
}
if (*v == '\r' || *v == '\n') {
*v = '\0';
break;
}
if (*v == ' ' || *v == '\t') {
if (!value_end) {
value_end = v;
}
} else {
value_end = NULL;
}
retval = get_name_value(&name, &value, ' ');
if (retval == 0) {
retval = set_option(opts, argv0, name, value, natengine, line_num);
}
if (value_end) {
*value_end = '\0';
}
/* Compare strlen(s2)+1 chars to match exactly */
if (!strncmp(name, "CACert", 7)) {
opts_set_cacrt(opts, argv0, value);
} else if (!strncmp(name, "CAKey", 6)) {
opts_set_cakey(opts, argv0, value);
} else if (!strncmp(name, "ClientCert", 11)) {
opts_set_clientcrt(opts, argv0, value);
} else if (!strncmp(name, "ClientKey", 10)) {
opts_set_clientkey(opts, argv0, value);
} else if (!strncmp(name, "CAChain", 8)) {
opts_set_chain(opts, argv0, value);
} else if (!strncmp(name, "LeafCerts", 10)) {
opts_set_key(opts, argv0, value);
} else if (!strncmp(name, "CRL", 4)) {
opts_set_crl(opts, value);
} else if (!strncmp(name, "TargetCertDir", 14)) {
opts_set_tgcrtdir(opts, argv0, value);
} else if (!strncmp(name, "WriteGenCertsDir", 17)) {
opts_set_certgendir_writegencerts(opts, argv0, value);
} else if (!strncmp(name, "WriteAllCertsDir", 17)) {
opts_set_certgendir_writeall(opts, argv0, value);
} else if (!strncmp(name, "DenyOCSP", 9)) {
yes = check_value_yesno(value, "DenyOCSP", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_deny_ocsp(opts) : opts_unset_deny_ocsp(opts);
fprintf(stderr, "DenyOCSP: %u\n", opts->deny_ocsp);
} else if (!strncmp(name, "Passthrough", 12)) {
yes = check_value_yesno(value, "Passthrough", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_passthrough(opts) : opts_unset_passthrough(opts);
fprintf(stderr, "Passthrough: %u\n", opts->passthrough);
#ifndef OPENSSL_NO_DH
} else if (!strncmp(name, "DHGroupParams", 14)) {
opts_set_dh(opts, argv0, value);
#endif /* !OPENSSL_NO_DH */
#ifndef OPENSSL_NO_ECDH
} else if (!strncmp(name, "ECDHCurve", 10)) {
opts_set_ecdhcurve(opts, argv0, value);
#endif /* !OPENSSL_NO_ECDH */
#ifdef SSL_OP_NO_COMPRESSION
} else if (!strncmp(name, "SSLCompression", 15)) {
yes = check_value_yesno(value, "SSLCompression", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_sslcomp(opts) : opts_unset_sslcomp(opts);
fprintf(stderr, "SSLCompression: %u\n", opts->sslcomp);
#endif /* SSL_OP_NO_COMPRESSION */
} else if (!strncmp(name, "ForceSSLProto", 14)) {
opts_force_proto(opts, argv0, value);
} else if (!strncmp(name, "DisableSSLProto", 16)) {
opts_disable_proto(opts, argv0, value);
} else if (!strncmp(name, "Ciphers", 8)) {
opts_set_ciphers(opts, argv0, value);
} else if (!strncmp(name, "NATEngine", 10)) {
strncpy(natengine, value, NATENGINE_SIZE);
fprintf(stderr, "NATEngine: %s\n", natengine);
} else if (!strncmp(name, "User", 5)) {
opts_set_user(opts, argv0, value);
} else if (!strncmp(name, "Group", 6)) {
opts_set_group(opts, argv0, value);
} else if (!strncmp(name, "Chroot", 7)) {
opts_set_jaildir(opts, argv0, value);
} else if (!strncmp(name, "PidFile", 8)) {
opts_set_pidfile(opts, argv0, value);
} else if (!strncmp(name, "ConnectLog", 11)) {
opts_set_connectlog(opts, argv0, value);
} else if (!strncmp(name, "ContentLog", 11)) {
opts_set_contentlog(opts, argv0, value);
} else if (!strncmp(name, "ContentLogDir", 14)) {
opts_set_contentlogdir(opts, argv0, value);
} else if (!strncmp(name, "ContentLogPathSpec", 19)) {
opts_set_contentlogpathspec(opts, argv0, value);
#ifdef HAVE_LOCAL_PROCINFO
} else if (!strncmp(name, "LogProcInfo", 11)) {
yes = check_value_yesno(value, "LogProcInfo", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_lprocinfo(opts) : opts_unset_lprocinfo(opts);
fprintf(stderr, "LogProcInfo: %u\n", opts->lprocinfo);
#endif /* HAVE_LOCAL_PROCINFO */
} else if (!strncmp(name, "MasterKeyLog", 13)) {
opts_set_masterkeylog(opts, argv0, value);
} else if (!strncmp(name, "Daemon", 7)) {
yes = check_value_yesno(value, "Daemon", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_daemon(opts) : opts_unset_daemon(opts);
fprintf(stderr, "Daemon: %u\n", opts->detach);
} else if (!strncmp(name, "Debug", 6)) {
yes = check_value_yesno(value, "Debug", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_debug(opts) : opts_unset_debug(opts);
fprintf(stderr, "Debug: %u\n", opts->debug);
} else if (!strncmp(name, "DebugLevel", 11)) {
opts_set_debug_level(value);
} else if (!strncmp(name, "ProxySpec", 10)) {
/* Use MAX_TOKEN instead of computing the actual number of tokens in value */
char **argv = malloc(sizeof(char *) * MAX_TOKEN);
char **save_argv = argv;
int argc = 0;
char *p, *last = NULL;
for ((p = strtok_r(value, " ", &last)); p; (p = strtok_r(NULL, " ", &last))) {
/* Limit max # token */
if (argc < MAX_TOKEN) {
argv[argc++] = p;
} else {
break;
}
}
proxyspec_parse(&argc, &argv, natengine, &opts->spec);
free(save_argv);
} else if (!strncasecmp(name, "ConnIdleTimeout", 16)) {
unsigned int i = atoi(value);
if (i >= 10 && i <= 3600) {
opts->conn_idle_timeout = i;
} else {
fprintf(stderr, "Invalid ConnIdleTimeout %s at line %d, use 10-3600\n", value, line_num);
goto leave;
}
fprintf(stderr, "ConnIdleTimeout: %u\n", opts->conn_idle_timeout);
} else if (!strncasecmp(name, "ExpiredConnCheckPeriod", 23)) {
unsigned int i = atoi(value);
if (i >= 10 && i <= 60) {
opts->expired_conn_check_period = i;
} else {
fprintf(stderr, "Invalid ExpiredConnCheckPeriod %s at line %d, use 10-60\n", value, line_num);
goto leave;
}
fprintf(stderr, "ExpiredConnCheckPeriod: %u\n", opts->expired_conn_check_period);
} else if (!strncasecmp(name, "SSLShutdownRetryDelay", 22)) {
unsigned int i = atoi(value);
if (i >= 100 && i <= 10000) {
opts->ssl_shutdown_retry_delay = i;
} else {
fprintf(stderr, "Invalid SSLShutdownRetryDelay %s at line %d, use 100-10000\n", value, line_num);
goto leave;
}
fprintf(stderr, "SSLShutdownRetryDelay: %u\n", opts->ssl_shutdown_retry_delay);
} else if (!strncasecmp(name, "LogStats", 9)) {
yes = check_value_yesno(value, "LogStats", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_statslog(opts) : opts_unset_statslog(opts);
fprintf(stderr, "LogStats: %u\n", opts->statslog);
} else if (!strncasecmp(name, "StatsPeriod", 12)) {
unsigned int i = atoi(value);
if (i >= 1 && i <= 10) {
opts->stats_period = i;
} else {
fprintf(stderr, "Invalid StatsPeriod %s at line %d, use 1-10\n", value, line_num);
goto leave;
}
fprintf(stderr, "StatsPeriod: %u\n", opts->stats_period);
} else if (!strncasecmp(name, "RemoveHTTPAcceptEncoding", 25)) {
yes = check_value_yesno(value, "RemoveHTTPAcceptEncoding", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_remove_http_accept_encoding(opts) : opts_unset_remove_http_accept_encoding(opts);
fprintf(stderr, "RemoveHTTPAcceptEncoding: %u\n", opts->remove_http_accept_encoding);
} else if (!strncasecmp(name, "RemoveHTTPReferer", 18)) {
yes = check_value_yesno(value, "RemoveHTTPReferer", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_remove_http_referer(opts) : opts_unset_remove_http_referer(opts);
fprintf(stderr, "RemoveHTTPReferer: %u\n", opts->remove_http_referer);
} else if (!strncasecmp(name, "VerifyPeer", 11)) {
yes = check_value_yesno(value, "VerifyPeer", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_verify_peer(opts) : opts_unset_verify_peer(opts);
fprintf(stderr, "VerifyPeer: %u\n", opts->verify_peer);
} else if (!strncasecmp(name, "AllowWrongHost", 15)) {
yes = check_value_yesno(value, "AllowWrongHost", line_num);
if (yes == -1) {
goto leave;
}
yes ? opts_set_allow_wrong_host(opts) : opts_unset_allow_wrong_host(opts);
fprintf(stderr, "AllowWrongHost: %u\n", opts->allow_wrong_host);
} else {
fprintf(stderr, "Error in conf file: Unknown option '%s' at line %d\n", name, line_num);
if (retval == -1) {
goto leave;
}
}
retval = 0;
leave:
fclose(f);
if (line) {

@ -92,6 +92,9 @@ typedef struct opts {
unsigned int lprocinfo : 1;
#endif /* HAVE_LOCAL_PROCINFO */
unsigned int certgen_writeall: 1;
#ifndef OPENSSL_NO_ENGINE
char *openssl_engine;
#endif /* !OPENSSL_NO_ENGINE */
char *ciphers;
char *certgendir;
char *tgcrtdir;
@ -153,8 +156,10 @@ void opts_set_chain(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_key(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_crl(opts_t *, const char *) NONNULL(1,2);
void opts_set_tgcrtdir(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_certgendir_writeall(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_certgendir_writegencerts(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_certgendir_writeall(opts_t *, const char *, const char *)
NONNULL(1,2,3);
void opts_set_certgendir_writegencerts(opts_t *, const char *, const char *)
NONNULL(1,2,3);
void opts_set_deny_ocsp(opts_t *) NONNULL(1);
void opts_set_passthrough(opts_t *) NONNULL(1);
void opts_set_clientcrt(opts_t *, const char *, const char *) NONNULL(1,2,3);
@ -169,14 +174,18 @@ void opts_unset_sslcomp(opts_t *) NONNULL(1);
void opts_force_proto(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_disable_proto(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_ciphers(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_openssl_engine(opts_t *, const char *, const char *)
NONNULL(1,2,3);
void opts_set_user(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_group(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_jaildir(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_pidfile(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_connectlog(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_contentlog(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_contentlogdir(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_contentlogpathspec(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_set_contentlogdir(opts_t *, const char *, const char *)
NONNULL(1,2,3);
void opts_set_contentlogpathspec(opts_t *, const char *, const char *)
NONNULL(1,2,3);
#ifdef HAVE_LOCAL_PROCINFO
void opts_set_lprocinfo(opts_t *) NONNULL(1);
#endif /* HAVE_LOCAL_PROCINFO */
@ -185,8 +194,10 @@ void opts_set_daemon(opts_t *) NONNULL(1);
void opts_set_debug(opts_t *) NONNULL(1);
void opts_set_debug_level(const char *) NONNULL(1);
void opts_set_statslog(opts_t *) NONNULL(1);
int opts_set_option(opts_t *, const char *, const char *, char **)
NONNULL(1,2,3);
int load_conffile(opts_t *, const char *, const char *) NONNULL(1,2,3);
int load_conffile(opts_t *, const char *, char **) NONNULL(1,2);
#endif /* !OPTS_H */
/* vim: set noet ft=c: */

@ -1651,6 +1651,10 @@ pxy_http_resphdr_filter_line(const char *line, pxy_conn_ctx_t *ctx)
/* HSTS: HTTP Strict Transport Security (RFC 6797)
* remove to allow users to accept bad certs */
!strncasecmp(line, "Strict-Transport-Security:", 26) ||
/* Expect-CT: Expect Certificate Transparency
* (draft-ietf-httpbis-expect-ct-latest)
* remove to prevent failed CT log lookups */
!strncasecmp(line, "Expect-CT:", 10) ||
/* Alternate Protocol
* remove to prevent switching to QUIC, SPDY et al */
!strncasecmp(line, "Alternate-Protocol:", 19) ||

98
ssl.c

@ -30,6 +30,7 @@
#include "log.h"
#include "defaults.h"
#include "attrib.h"
#include <sys/types.h>
#include <fcntl.h>
@ -39,7 +40,9 @@
#include <limits.h>
#include <openssl/crypto.h>
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif /* !OPENSSL_NO_ENGINE */
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
@ -93,31 +96,28 @@ ssl_ssl_cert_get(SSL *s)
int
DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{
/* If the fields p and g in d are NULL, the corresponding input
* parameters MUST be non-NULL. q may remain NULL.
*/
if ((dh->p == NULL && p == NULL)
|| (dh->g == NULL && g == NULL))
return 0;
if (p != NULL) {
BN_free(dh->p);
dh->p = p;
}
if (q != NULL) {
BN_free(dh->q);
dh->q = q;
}
if (g != NULL) {
BN_free(dh->g);
dh->g = g;
}
if (q != NULL) {
dh->length = BN_num_bits(q);
}
return 1;
/*
* If the fields p and g in d are NULL, the corresponding input
* parameters MUST be non-NULL. q may remain NULL.
*/
if ((dh->p == NULL && p == NULL) || (dh->g == NULL && g == NULL))
return 0;
if (p != NULL) {
BN_free(dh->p);
dh->p = p;
}
if (q != NULL) {
BN_free(dh->q);
dh->q = q;
dh->length = BN_num_bits(q);
}
if (g != NULL) {
BN_free(dh->g);
dh->g = g;
}
return 1;
}
#endif
@ -171,6 +171,11 @@ ssl_openssl_version(void)
#else /* !OPENSSL_THREADS */
fprintf(stderr, "OpenSSL is not thread-safe\n");
#endif /* !OPENSSL_THREADS */
#ifndef OPENSSL_NO_ENGINE
fprintf(stderr, "OpenSSL has engine support\n");
#else /* OPENSSL_NO_ENGINE */
fprintf(stderr, "OpenSSL has no engine support\n");
#endif /* OPENSSL_NO_ENGINE */
#ifdef SSL_MODE_RELEASE_BUFFERS
fprintf(stderr, "Using SSL_MODE_RELEASE_BUFFERS\n");
#else /* !SSL_MODE_RELEASE_BUFFERS */
@ -363,13 +368,26 @@ ssl_init(void)
return 0;
/* general initialization */
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG
#ifndef OPENSSL_NO_ENGINE
|OPENSSL_INIT_ENGINE_ALL_BUILTIN
#endif /* !OPENSSL_NO_ENGINE */
, NULL);
OPENSSL_init_ssl(0, NULL);
#else /* OPENSSL_VERSION_NUMBER < 0x10100000L */
SSL_library_init();
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
#ifdef PURIFY
CRYPTO_malloc_init();
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
#endif /* PURIFY */
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
OPENSSL_config(NULL);
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
/* thread-safety */
#if defined(OPENSSL_THREADS) && ((OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER))
@ -390,7 +408,7 @@ ssl_init(void)
#else /* !OPENSSL_NO_THREADID */
CRYPTO_THREADID_set_callback(ssl_thr_id_cb);
#endif /* !OPENSSL_NO_THREADID */
#endif /* OPENSSL_THREADS */
#endif /* OPENSSL_THREADS && OPENSSL_VERSION_NUMBER < 0x10100000L */
/* randomness */
#ifndef PURIFY
@ -482,7 +500,9 @@ ssl_fini(void)
free(ssl_mutex);
#endif
#if !defined(OPENSSL_NO_ENGINE) && ((OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER))
ENGINE_cleanup();
#endif /* !OPENSSL_NO_ENGINE && OPENSSL_VERSION_NUMBER < 0x10100000L */
CONF_modules_finish();
CONF_modules_unload(1);
CONF_modules_free();
@ -492,6 +512,27 @@ ssl_fini(void)
CRYPTO_cleanup_all_ex_data();
}
/*
* Look up an OpenSSL engine by ID or by full path and load it as default
* engine. This works globally, not on specific SSL_CTX or SSL instances.
* OpenSSL must already have been initialized when calling this function.
* Returns 0 on success, -1 on failure.
*/
#ifndef OPENSSL_NO_ENGINE
int
ssl_engine(const char *name) {
ENGINE *engine;
engine = ENGINE_by_id(name);
if (!engine)
return -1;
if (!ENGINE_set_default(engine, ENGINE_METHOD_ALL))
return -1;
return 0;
}
#endif /* !OPENSSL_NO_ENGINE */
/*
* Format raw SHA1 hash into newly allocated string, with or without colons.
*/
@ -527,14 +568,15 @@ ssl_ssl_state_to_str(SSL *ssl, const char *prepend)
char *str = NULL;
int rv;
rv = asprintf(&str, "%s%08x = %s%s%04x = %s (%s)\n",
rv = asprintf(&str, "%s%08x = %s%s%04x = %s (%s) [%s]\n",
prepend,
SSL_get_state(ssl),
(SSL_get_state(ssl) & SSL_ST_CONNECT) ? "SSL_ST_CONNECT|" : "",
(SSL_get_state(ssl) & SSL_ST_ACCEPT) ? "SSL_ST_ACCEPT|" : "",
SSL_get_state(ssl) & SSL_ST_MASK,
SSL_state_string(ssl),
SSL_state_string_long(ssl));
SSL_state_string_long(ssl),
SSL_is_server(ssl) ? "accept socket" : "connect socket");
return (rv < 0) ? NULL : str;
}

41
ssl.h

@ -38,6 +38,15 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
/*
* LibreSSL seems to ship engine support on a source code level, but it seems
* to be broken. Tested with LibreSSL 2.7.4 on OpenBSD and macOS. For now,
* disable engine support when building against LibreSSL.
*/
#if defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_NO_ENGINE)
#define OPENSSL_NO_ENGINE
#endif
#if (OPENSSL_VERSION_NUMBER < 0x10000000L) && !defined(OPENSSL_NO_THREADID)
#define OPENSSL_NO_THREADID
#endif
@ -71,11 +80,37 @@
#endif
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
#if LIBRESSL_VERSION_NUMBER >= 0x2050100fL
#define SSL_is_server(ssl) ((ssl)->server)
#else /* < LibreSSL 2.5.1 and OpenSSL < 1.1.0 */
#define SSL_is_server(ssl) ((ssl)->type != SSL_ST_CONNECT)
#endif /* < LibreSSL 2.5.1 and OpenSSL < 1.1.0 */
#define ASN1_STRING_get0_data(value) ASN1_STRING_data(value)
#define SSL_is_server(ssl) (ssl->type != SSL_ST_CONNECT)
#define X509_get_signature_nid(x509) (OBJ_obj2nid(x509->sig_alg->algorithm))
int DH_set0_pqg(DH *, BIGNUM *, BIGNUM *, BIGNUM *);
#endif /* < OpenSSL 1.1.0 */
#if OPENSSL_VERSION_NUMBER < 0x1000000fL
static inline int EVP_PKEY_base_id(const EVP_PKEY *pkey)
{
return EVP_PKEY_type(pkey->type);
}
static inline int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, const unsigned char **pk, int *ppklen, X509_ALGOR **pa, X509_PUBKEY *pub)
{
if (ppkalg)
*ppkalg = pub->algor->algorithm;
if (pk) {
*pk = pub->public_key->data;
*ppklen = pub->public_key->length;
}
if (pa)
*pa = pub->algor;
return 1;
}
#ifndef X509_get_X509_PUBKEY
#define X509_get_X509_PUBKEY(x) ((x)->cert_info->key
#endif
#endif /* OpenSSL < 1.0.0 */
/*
* The constructors returning a SSL_METHOD * were changed to return
@ -164,6 +199,10 @@ int ssl_init(void) WUNRES;
int ssl_reinit(void) WUNRES;
void ssl_fini(void);
#ifndef OPENSSL_NO_ENGINE
int ssl_engine(const char *) WUNRES;
#endif /* !OPENSSL_NO_ENGINE */
char * ssl_sha1_to_str(unsigned char *, int) NONNULL(1) MALLOC;
char * ssl_ssl_state_to_str(SSL *, const char *) NONNULL(1) MALLOC;

@ -29,13 +29,22 @@
#include "base64.h"
#include "ssl.h"
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <check.h>
#ifdef __APPLE__
#define DLSUFFIX "dylib"
#else
#define DLSUFFIX "so"
#endif
#define TESTKEY "extra/pki/server.key"
#define TESTCERT "extra/pki/server.crt"
#define TESTCERT2 "extra/pki/rsa.crt"
#define ENGINE "extra/engine/dummy-engine."DLSUFFIX
static void
ssl_setup(void)
@ -748,6 +757,21 @@ START_TEST(ssl_x509_refcount_inc_01)
}
END_TEST
#ifndef OPENSSL_NO_ENGINE
START_TEST(ssl_engine_01)
{
char cwd[PATH_MAX];
char *path;
fail_unless(getcwd(cwd, sizeof(cwd)) == cwd, "getcwd() failed");
fail_unless(asprintf(&path, "%s/"ENGINE, cwd) != -1 && !!path,
"constructing engine path failed");
fail_unless(ssl_engine(path) == 0, "loading OpenSSL engine failed");
free(path);
}
END_TEST
#endif /* !OPENSSL_NO_ENGINE */
Suite *
ssl_suite(void)
{
@ -757,12 +781,14 @@ ssl_suite(void)
s = suite_create("ssl");
tc = tcase_create("ssl_wildcardify");
tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown);
tcase_add_test(tc, ssl_wildcardify_01);
tcase_add_test(tc, ssl_wildcardify_02);
tcase_add_test(tc, ssl_wildcardify_03);
suite_add_tcase(s, tc);
tc = tcase_create("ssl_dnsname_match");
tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown);
tcase_add_test(tc, ssl_dnsname_match_01);
tcase_add_test(tc, ssl_dnsname_match_02);
tcase_add_test(tc, ssl_dnsname_match_03);
@ -782,6 +808,7 @@ ssl_suite(void)
suite_add_tcase(s, tc);
tc = tcase_create("ssl_tls_clienthello_parse");
tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown);
tcase_add_test(tc, ssl_tls_clienthello_parse_00);
tcase_add_test(tc, ssl_tls_clienthello_parse_01);
tcase_add_test(tc, ssl_tls_clienthello_parse_02);
@ -828,22 +855,36 @@ ssl_suite(void)
suite_add_tcase(s, tc);
tc = tcase_create("ssl_is_ocspreq");
tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown);
tcase_add_test(tc, ssl_is_ocspreq_01);
suite_add_tcase(s, tc);
tc = tcase_create("ssl_features");
tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown);
tcase_add_test(tc, ssl_features_01);
tcase_add_test(tc, ssl_features_02);
suite_add_tcase(s, tc);
tc = tcase_create("ssl_key_refcount_inc");
tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown);
tcase_add_test(tc, ssl_key_refcount_inc_01);
suite_add_tcase(s, tc);
tc = tcase_create("ssl_x509_refcount_inc");
tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown);
tcase_add_test(tc, ssl_x509_refcount_inc_01);
suite_add_tcase(s, tc);
#ifndef OPENSSL_NO_ENGINE
tc = tcase_create("ssl_engine");
tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown);
tcase_add_test(tc, ssl_engine_01);
suite_add_tcase(s, tc);
#else /* OPENSSL_NO_ENGINE */
fprintf(stderr, "1 test omitted because OpenSSL has no "
"engine support\n");
#endif /* OPENSSL_NO_ENGINE */
return s;
}

@ -29,25 +29,25 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH SSLPROXY 1 "12 May 2018"
.TH SSLPROXY 1 "15 Sep 2018"
.SH NAME
sslproxy \-\- transparent SSL/TLS proxy for decrypting and diverting network
traffic to other programs for deep SSL inspection
.SH SYNOPSIS
.na
.B sslproxy
[\fB-kCKqwWOPZdDgGsrReumjplILSFiMab\fP] \fB-c\fP \fIpem\fP
[\fB-kCKqwWOPZdDgGsrRxeumjplILSFiMab\fP] \fB-c\fP \fIpem\fP
\fIproxyspecs\fP [...]
.br
.B sslproxy
[\fB-kCKqwWOPZdDgGsrReumjplILSFiMab\fP] \fB-c\fP \fIpem\fP \fB-t\fP \fIdir\fP
[\fB-kCKqwWOPZdDgGsrRxeumjplILSFiMab\fP] \fB-c\fP \fIpem\fP \fB-t\fP \fIdir\fP
\fIproxyspecs\fP [...]
.br
.B sslproxy
[\fB-OPZwWdDgGsrReumjplILSFiMab\fP] \fB-t\fP \fIdir\fP
[\fB-OPZwWdDgGsrRxeumjplILSFiMab\fP] \fB-t\fP \fIdir\fP
\fIproxyspecs\fP [...]
.br
.B sslproxy [\fB-kCKwWOPZdDgGsrReumjplILSFiM\fP] -f \fIconffile\fP
.B sslproxy [\fB-kCKwWOPZdDgGsrRxeumjplILSFiM\fP] -f \fIconffile\fP
.br
.B sslproxy -E
.br
@ -107,7 +107,8 @@ OCSP requests in a generic way.
For HTTP and HTTPS connections, SSLsplit mangles headers to
prevent server-instructed public key pinning (HPKP),
avoid strict transport security restrictions (HSTS),
and prevent switching to QUIC/SPDY, HTTP/2 or WebSockets (Upgrade,
avoid Certificate Transparency enforcement (Expect-CT) and
prevent switching to QUIC/SPDY, HTTP/2 or WebSockets (Upgrade,
Alternate Protocols).
HTTP compression, encodings and keep-alive are disabled to make the logs more
readable.
@ -270,7 +271,7 @@ parsable by OpenSSL, or if the method is \fBPOST\fP and the \fBContent-Type\fP
is \fBapplication/ocsp-request\fP.
For this to be effective, SSLproxy must be handling traffic destined to the
port used by the OCSP server. In particular, SSLproxy must be configured to
receive traffic to all ports used by OCSP servers of targetted certificates
receive traffic to all ports used by OCSP servers of targeted certificates
within the \fIcertdir\fP specified by \fB-t\fP.
.TP
.B \-p \fIpidfile\fP
@ -353,6 +354,16 @@ configurations, also to perform DNS resolution.
Due to an Apple bug, \fB-u\fP cannot be used with \fBpf\fP proxyspecs on
Mac OS X.
.TP
.B \-x \fIengine\fP
Use the OpenSSL engine with identifier \fIengine\fP as a default engine. The
engine must be available within the OpenSSL ecosystem under the specified
identifier, that is, they must be loaded from the global OpenSSL configuration.
If \fIengine\fP is an absolute path, it will be interpreted as path to an
engine dynamically linked library and loaded by path, regardless of global
OpenSSL configuration.
This option is only available if built against a version of OpenSSL with engine
support.
.TP
.B \-V
Display version and compiled features information and exit.
.TP

@ -53,10 +53,12 @@ CAKey /etc/sslproxy/ca.key
# Disable SSL/TLS protocol version (default: none)
#DisableSSLProto tls10
# Cipher specification for both server and client SSL/TLS connections
# (default: ALL:-aNULL)
# Use the given OpenSSL cipher suite spec (default: ALL:-aNULL)
Ciphers ALL:!RC4
# OpenSSL engine to activate, either ID or full path to shared library
#OpenSSLEngine cloudhsm
# Specify default NAT engine to use
#NATEngine netfilter
@ -73,14 +75,14 @@ PidFile /var/run/sslproxy.pid
# Connect log: log one line summary per connection to logfile
#ConnectLog /var/log/sslproxy/connect.log
# Content log: full data to file or named pipe (excludes -S/-F)
# Content log: full data to file or named pipe (excludes ContentLogDir/ContentLogPathSpec)
#ContentLog /var/log/sslproxy/content.log
# Content log: full data to separate files in dir (excludes -L/-F)
# Content log: full data to separate files in dir (excludes ContentLog/ContentLogPathSpec)
#ContentLogDir /var/log/sslproxy/content
# Content log: full data to sep files with %% subst (excl. -L/-S)
#ContentLogPathSpec /var/log/sslproxy/%%X/%%u-%%s-%%d-%%T.log
# Content log: full data to sep files with % subst (excludes ContentLog/ContentLogDir)
#ContentLogPathSpec /var/log/sslproxy/%X/%u-%s-%d-%T.log
# Look up local process owning each connection for logging
#LogProcInfo yes
@ -123,7 +125,9 @@ RemoveHTTPReferer yes
# Verify peer using default certificates
VerifyPeer yes
# Allow wrong host names in certificates
# When disabled, never add the SNI to forged certificates, even if the SNI
# provided by the client does not match the server certificate's CN/SAN.
# Helps pass the wrong.host test at https://badssl.com.
AllowWrongHost no
# Proxy specifications

@ -1,29 +1,30 @@
.\"-
.\" SSLproxy - transparent SSL/TLS proxy for diverting packets to programs
.\" https://github.com/sonertari/SSLproxy
.\"
.\" Copyright (c) 2017-2018, Soner Tari <sonertari@gmail.com>
.\" All rights reserved.
.\" https://github.com/sonertari/SSLproxy
.\"
.\" 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.
.\" 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.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
.\"
.TH "sslproxy.conf" "5" "May 7, 2018" "sslproxy 0.5.7" "SSLproxy"
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 COPYRIGHT HOLDER 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.
.TH "sslproxy.conf" "5" "Sep 15, 2018" "sslproxy 0.5.7" "SSLproxy"
.SH "NAME"
.LP
\fBsslproxy.conf\fR \- Configuration file for SSLproxy
@ -109,10 +110,16 @@ Disable SSL/TLS protocol version.
Default: none
.TP
\fBCiphers STRING\fR
Cipher specification for both server and client SSL/TLS connections.
Use the given OpenSSL cipher suite spec.
.br
Default: ALL:-aNULL
.TP
\fBOpenSSLEngine STRING\fR
The OpenSSL engine to activate, either the ID or the full path to the shared
library implementing the engine. If an ID is given, the engine needs to be
known to the system-wide OpenSSL configuration. Only available if built
against a version of OpenSSL with engine support.
.TP
\fBNATEngine STRING\fR
Specify default NAT engine to use.
.TP
@ -142,7 +149,7 @@ Content log: full data to file or named pipe (excludes ContentLogDir/ContentLogP
Content log: full data to separate files in dir (excludes ContentLog/ContentLogPathSpec).
.TP
\fBContentLogPathSpec STRING\fR
Content log: full data to sep files with %% subst (excludes ContentLog/ContentLogDir).
Content log: full data to sep files with % subst (excludes ContentLog/ContentLogDir).
.TP
\fBLogProcInfo BOOL\fR
Look up local process owning each connection for logging.
@ -200,7 +207,7 @@ Verify peer using default certificates.
Default: yes
.TP
\fBAllowWrongHost BOOL\fR
Allow wrong host names in certificates.
When disabled, never add the SNI to forged certificates, even if the SNI provided by the client does not match the server certificate's CN/SAN. Helps pass the wrong.host test at https://badssl.com.
.br
Default: no
.TP

16
sys.c

@ -352,6 +352,22 @@ sys_group_str(gid_t gid)
return NULL;
}
/*
* Determine address family of addr
*/
int
sys_get_af(char *addr)
{
if (strstr(addr, ":"))
return AF_INET6;
else if (!strpbrk(addr, "abcdefghijklmnopqrstu"
"vwxyzABCDEFGHIJKLMNOP"
"QRSTUVWXYZ-"))
return AF_INET;
else
return AF_UNSPEC;
}
/*
* Parse an ascii host/IP and port tuple into a sockaddr_storage.
* On success, returns address family and fills in addr, addrlen.

@ -46,6 +46,7 @@ int sys_isgroup(const char *) NONNULL(1) WUNRES;
char * sys_user_str(uid_t) MALLOC;
char * sys_group_str(gid_t) MALLOC;
int sys_get_af(char *);
int sys_sockaddr_parse(struct sockaddr_storage *, socklen_t *,
char *, char *, int, int) NONNULL(1,2,3,4) WUNRES;
int sys_sockaddr_str(struct sockaddr *, socklen_t,

@ -72,6 +72,9 @@ XNU_RELS+= 3789.70.16 # 10.12.6
# macOS High Sierra
XNU_RELS+= 4570.1.46 # 10.13
XNU_RELS+= 4570.20.62 # 10.13.1
XNU_RELS+= 4570.31.3 # 10.13.2
XNU_RELS+= 4570.41.2 # 10.13.3
# defaults
XNURL?= https://opensource.apple.com/source/xnu/

@ -0,0 +1,367 @@
APPLE PUBLIC SOURCE LICENSE
Version 2.0 - August 6, 2003
Please read this License carefully before downloading this software.
By downloading or using this software, you are agreeing to be bound by
the terms of this License. If you do not or cannot agree to the terms
of this License, please do not download or use the software.
1. General; Definitions. This License applies to any program or other
work which Apple Computer, Inc. ("Apple") makes publicly available and
which contains a notice placed by Apple identifying such program or
work as "Original Code" and stating that it is subject to the terms of
this Apple Public Source License version 2.0 ("License"). As used in
this License:
1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
the grantor of rights, (i) claims of patents that are now or hereafter
acquired, owned by or assigned to Apple and (ii) that cover subject
matter contained in the Original Code, but only to the extent
necessary to use, reproduce and/or distribute the Original Code
without infringement; and (b) in the case where You are the grantor of
rights, (i) claims of patents that are now or hereafter acquired,
owned by or assigned to You and (ii) that cover subject matter in Your
Modifications, taken alone or in combination with Original Code.
1.2 "Contributor" means any person or entity that creates or
contributes to the creation of Modifications.
1.3 "Covered Code" means the Original Code, Modifications, the
combination of Original Code and any Modifications, and/or any
respective portions thereof.
1.4 "Externally Deploy" means: (a) to sublicense, distribute or
otherwise make Covered Code available, directly or indirectly, to
anyone other than You; and/or (b) to use Covered Code, alone or as
part of a Larger Work, in any way to provide a service, including but
not limited to delivery of content, through electronic communication
with a client other than You.
1.5 "Larger Work" means a work which combines Covered Code or portions
thereof with code not governed by the terms of this License.
1.6 "Modifications" mean any addition to, deletion from, and/or change
to, the substance and/or structure of the Original Code, any previous
Modifications, the combination of Original Code and any previous
Modifications, and/or any respective portions thereof. When code is
released as a series of files, a Modification is: (a) any addition to
or deletion from the contents of a file containing Covered Code;
and/or (b) any new file or other representation of computer program
statements that contains any part of Covered Code.
1.7 "Original Code" means (a) the Source Code of a program or other
work as originally made available by Apple under this License,
including the Source Code of any updates or upgrades to such programs
or works made available by Apple under this License, and that has been
expressly identified by Apple as such in the header file(s) of such
work; and (b) the object code compiled from such Source Code and
originally made available by Apple under this License.
1.8 "Source Code" means the human readable form of a program or other
work that is suitable for making modifications to it, including all
modules it contains, plus any associated interface definition files,
scripts used to control compilation and installation of an executable
(object code).
1.9 "You" or "Your" means an individual or a legal entity exercising
rights under this License. For legal entities, "You" or "Your"
includes any entity which controls, is controlled by, or is under
common control with, You, where "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of fifty percent
(50%) or more of the outstanding shares or beneficial ownership of
such entity.
2. Permitted Uses; Conditions & Restrictions. Subject to the terms
and conditions of this License, Apple hereby grants You, effective on
the date You accept this License and download the Original Code, a
world-wide, royalty-free, non-exclusive license, to the extent of
Apple's Applicable Patent Rights and copyrights covering the Original
Code, to do the following:
2.1 Unmodified Code. You may use, reproduce, display, perform,
internally distribute within Your organization, and Externally Deploy
verbatim, unmodified copies of the Original Code, for commercial or
non-commercial purposes, provided that in each instance:
(a) You must retain and reproduce in all copies of Original Code the
copyright and other proprietary notices and disclaimers of Apple as
they appear in the Original Code, and keep intact all notices in the
Original Code that refer to this License; and
(b) You must include a copy of this License with every copy of Source
Code of Covered Code and documentation You distribute or Externally
Deploy, and You may not offer or impose any terms on such Source Code
that alter or restrict this License or the recipients' rights
hereunder, except as permitted under Section 6.
2.2 Modified Code. You may modify Covered Code and use, reproduce,
display, perform, internally distribute within Your organization, and
Externally Deploy Your Modifications and Covered Code, for commercial
or non-commercial purposes, provided that in each instance You also
meet all of these conditions:
(a) You must satisfy all the conditions of Section 2.1 with respect to
the Source Code of the Covered Code;
(b) You must duplicate, to the extent it does not already exist, the
notice in Exhibit A in each file of the Source Code of all Your
Modifications, and cause the modified files to carry prominent notices
stating that You changed the files and the date of any change; and
(c) If You Externally Deploy Your Modifications, You must make
Source Code of all Your Externally Deployed Modifications either
available to those to whom You have Externally Deployed Your
Modifications, or publicly available. Source Code of Your Externally
Deployed Modifications must be released under the terms set forth in
this License, including the license grants set forth in Section 3
below, for as long as you Externally Deploy the Covered Code or twelve
(12) months from the date of initial External Deployment, whichever is
longer. You should preferably distribute the Source Code of Your
Externally Deployed Modifications electronically (e.g. download from a
web site).
2.3 Distribution of Executable Versions. In addition, if You
Externally Deploy Covered Code (Original Code and/or Modifications) in
object code, executable form only, You must include a prominent
notice, in the code itself as well as in related documentation,
stating that Source Code of the Covered Code is available under the
terms of this License with information on how and where to obtain such
Source Code.
2.4 Third Party Rights. You expressly acknowledge and agree that
although Apple and each Contributor grants the licenses to their
respective portions of the Covered Code set forth herein, no
assurances are provided by Apple or any Contributor that the Covered
Code does not infringe the patent or other intellectual property
rights of any other entity. Apple and each Contributor disclaim any
liability to You for claims brought by any other entity based on
infringement of intellectual property rights or otherwise. As a
condition to exercising the rights and licenses granted hereunder, You
hereby assume sole responsibility to secure any other intellectual
property rights needed, if any. For example, if a third party patent
license is required to allow You to distribute the Covered Code, it is
Your responsibility to acquire that license before distributing the
Covered Code.
3. Your Grants. In consideration of, and as a condition to, the
licenses granted to You under this License, You hereby grant to any
person or entity receiving or distributing Covered Code under this
License a non-exclusive, royalty-free, perpetual, irrevocable license,
under Your Applicable Patent Rights and other intellectual property
rights (other than patent) owned or controlled by You, to use,
reproduce, display, perform, modify, sublicense, distribute and
Externally Deploy Your Modifications of the same scope and extent as
Apple's licenses under Sections 2.1 and 2.2 above.
4. Larger Works. You may create a Larger Work by combining Covered
Code with other code not governed by the terms of this License and
distribute the Larger Work as a single product. In each such instance,
You must make sure the requirements of this License are fulfilled for
the Covered Code or any portion thereof.
5. Limitations on Patent License. Except as expressly stated in
Section 2, no other patent rights, express or implied, are granted by
Apple herein. Modifications and/or Larger Works may require additional
patent licenses from Apple which Apple may grant in its sole
discretion.
6. Additional Terms. You may choose to offer, and to charge a fee for,
warranty, support, indemnity or liability obligations and/or other
rights consistent with the scope of the license granted herein
("Additional Terms") to one or more recipients of Covered Code.
However, You may do so only on Your own behalf and as Your sole
responsibility, and not on behalf of Apple or any Contributor. You
must obtain the recipient's agreement that any such Additional Terms
are offered by You alone, and You hereby agree to indemnify, defend
and hold Apple and every Contributor harmless for any liability
incurred by or claims asserted against Apple or such Contributor by
reason of any such Additional Terms.
7. Versions of the License. Apple may publish revised and/or new
versions of this License from time to time. Each version will be given
a distinguishing version number. Once Original Code has been published
under a particular version of this License, You may continue to use it
under the terms of that version. You may also choose to use such
Original Code under the terms of any subsequent version of this
License published by Apple. No one other than Apple has the right to
modify the terms applicable to Covered Code created under this
License.
8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
part pre-release, untested, or not fully tested works. The Covered
Code may contain errors that could cause failures or loss of data, and
may be incomplete or contain inaccuracies. You expressly acknowledge
and agree that use of the Covered Code, or any portion thereof, is at
Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
You acknowledge that the Covered Code is not intended for use in the
operation of nuclear facilities, aircraft navigation, communication
systems, or air traffic control machines in which case the failure of
the Covered Code could lead to death, personal injury, or severe
physical or environmental damage.
9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
TO YOU. In no event shall Apple's total liability to You for all
damages (other than as may be required by applicable law) under this
License exceed the amount of fifty dollars ($50.00).
10. Trademarks. This License does not grant any rights to use the
trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
"QuickTime", "QuickTime Streaming Server" or any other trademarks,
service marks, logos or trade names belonging to Apple (collectively
"Apple Marks") or to any trademark, service mark, logo or trade name
belonging to any Contributor. You agree not to use any Apple Marks in
or as part of the name of products derived from the Original Code or
to endorse or promote products derived from the Original Code other
than as expressly permitted by and in strict compliance at all times
with Apple's third party trademark usage guidelines which are posted
at http://www.apple.com/legal/guidelinesfor3rdparties.html.
11. Ownership. Subject to the licenses granted under this License,
each Contributor retains all rights, title and interest in and to any
Modifications made by such Contributor. Apple retains all rights,
title and interest in and to the Original Code and any Modifications
made by or on behalf of Apple ("Apple Modifications"), and such Apple
Modifications will not be automatically subject to this License. Apple
may, at its sole discretion, choose to license such Apple
Modifications under this License, or on different terms from those
contained in this License or may choose not to license them at all.
12. Termination.
12.1 Termination. This License and the rights granted hereunder will
terminate:
(a) automatically without notice from Apple if You fail to comply with
any term(s) of this License and fail to cure such breach within 30
days of becoming aware of such breach;
(b) immediately in the event of the circumstances described in Section
13.5(b); or
(c) automatically without notice from Apple if You, at any time during
the term of this License, commence an action for patent infringement
against Apple; provided that Apple did not first commence
an action for patent infringement against You in that instance.
12.2 Effect of Termination. Upon termination, You agree to immediately
stop any further use, reproduction, modification, sublicensing and
distribution of the Covered Code. All sublicenses to the Covered Code
which have been properly granted prior to termination shall survive
any termination of this License. Provisions which, by their nature,
should remain in effect beyond the termination of this License shall
survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
12.2 and 13. No party will be liable to any other for compensation,
indemnity or damages of any sort solely as a result of terminating
this License in accordance with its terms, and termination of this
License will be without prejudice to any other right or remedy of
any party.
13. Miscellaneous.
13.1 Government End Users. The Covered Code is a "commercial item" as
defined in FAR 2.101. Government software and technical data rights in
the Covered Code include only those rights customarily provided to the
public as defined in this License. This customary commercial license
in technical data and software is provided in accordance with FAR
12.211 (Technical Data) and 12.212 (Computer Software) and, for
Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
Commercial Items) and 227.7202-3 (Rights in Commercial Computer
Software or Computer Software Documentation). Accordingly, all U.S.
Government End Users acquire Covered Code with only those rights set
forth herein.
13.2 Relationship of Parties. This License will not be construed as
creating an agency, partnership, joint venture or any other form of
legal association between or among You, Apple or any Contributor, and
You will not represent to the contrary, whether expressly, by
implication, appearance or otherwise.
13.3 Independent Development. Nothing in this License will impair
Apple's right to acquire, license, develop, have others develop for
it, market and/or distribute technology or products that perform the
same or similar functions as, or otherwise compete with,
Modifications, Larger Works, technology or products that You may
develop, produce, market or distribute.
13.4 Waiver; Construction. Failure by Apple or any Contributor to
enforce any provision of this License will not be deemed a waiver of
future enforcement of that or any other provision. Any law or
regulation which provides that the language of a contract shall be
construed against the drafter will not apply to this License.
13.5 Severability. (a) If for any reason a court of competent
jurisdiction finds any provision of this License, or portion thereof,
to be unenforceable, that provision of the License will be enforced to
the maximum extent permissible so as to effect the economic benefits
and intent of the parties, and the remainder of this License will
continue in full force and effect. (b) Notwithstanding the foregoing,
if applicable law prohibits or restricts You from fully and/or
specifically complying with Sections 2 and/or 3 or prevents the
enforceability of either of those Sections, this License will
immediately terminate and You must immediately discontinue any use of
the Covered Code and destroy all copies of it that are in your
possession or control.
13.6 Dispute Resolution. Any litigation or other dispute resolution
between You and Apple relating to this License shall take place in the
Northern District of California, and You and Apple hereby consent to
the personal jurisdiction of, and venue in, the state and federal
courts within that District with respect to this License. The
application of the United Nations Convention on Contracts for the
International Sale of Goods is expressly excluded.
13.7 Entire Agreement; Governing Law. This License constitutes the
entire agreement between the parties with respect to the subject
matter hereof. This License shall be governed by the laws of the
United States and the State of California, except that body of
California law concerning conflicts of law.
Where You are located in the province of Quebec, Canada, the following
clause applies: The parties hereby confirm that they have requested
that this License and all related documents be drafted in English. Les
parties ont exige que le present contrat et tous les documents
connexes soient rediges en anglais.
EXHIBIT A.
"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
Reserved.
This file contains Original Code and/or Modifications of Original Code
as defined in and that are subject to the Apple Public Source License
Version 2.0 (the 'License'). You may not use this file except in
compliance with the License. Please obtain a copy of the License at
http://www.opensource.apple.com/apsl/ and read it before using this
file.
The Original Code and all software distributed under the License are
distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
Please see the License for the specific language governing rights and
limitations under the License."

@ -0,0 +1,802 @@
/*
* Copyright (c) 2009-2010 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/* $NetBSD: tree.h,v 1.13 2006/08/27 22:32:38 christos Exp $ */
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#ifndef _LIBKERN_TREE_H_
#define _LIBKERN_TREE_H_
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
*
* A splay tree is a self-organizing data structure. Every operation
* on the tree causes a splay to happen. The splay moves the requested
* node to the root of the tree and partly rebalances it.
*
* This has the benefit that request locality causes faster lookups as
* the requested nodes move to the top of the tree. On the other hand,
* every lookup causes memory writes.
*
* The Balance Theorem bounds the total access time for m operations
* and n inserts on an initially empty tree as O((m + n)lg n). The
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
#define SPLAY_HEAD(name, type) \
struct name { \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ NULL }
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ENTRY(type) \
struct { \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return(NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \
elm = SPLAY_LEFT(elm, field); \
} \
} else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) { \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \
return ((head)->sph_root); \
} \
(head)->sph_root = (elm); \
return (NULL); \
} \
\
struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
} else { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
return (elm); \
} \
return (NULL); \
} \
\
void \
name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0){ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while (1) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) { \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-black tree */
#define RB_HEAD(name, type) \
struct name { \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ NULL }
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_PLACEHOLDER NULL
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
}
#define RB_COLOR_MASK (uintptr_t)0x1
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define _RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(name, elm, parent, field) do { \
name##_RB_SETPARENT(elm, parent); \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
name##_RB_SETCOLOR(elm, RB_RED); \
} while (/*CONSTCOND*/ 0)
#define RB_SET_BLACKRED(name, black, red, field) do { \
name##_RB_SETCOLOR(black, RB_BLACK); \
name##_RB_SETCOLOR(red, RB_RED); \
} while (/*CONSTCOND*/ 0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x) (void)(x)
#endif
#define RB_ROTATE_LEFT(name, head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
name##_RB_SETPARENT(RB_LEFT(tmp, field),(elm)); \
} \
RB_AUGMENT(elm); \
if (name##_RB_SETPARENT(tmp, name##_RB_GETPARENT(elm)) != NULL) { \
if ((elm) == RB_LEFT(name##_RB_GETPARENT(elm), field)) \
RB_LEFT(name##_RB_GETPARENT(elm), field) = (tmp); \
else \
RB_RIGHT(name##_RB_GETPARENT(elm), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
name##_RB_SETPARENT(elm, (tmp)); \
RB_AUGMENT(tmp); \
if ((name##_RB_GETPARENT(tmp))) \
RB_AUGMENT(name##_RB_GETPARENT(tmp)); \
} while (/*CONSTCOND*/ 0)
#define RB_ROTATE_RIGHT(name, head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
name##_RB_SETPARENT(RB_RIGHT(tmp, field), (elm)); \
} \
RB_AUGMENT(elm); \
if (name##_RB_SETPARENT(tmp, name##_RB_GETPARENT(elm)) != NULL) { \
if ((elm) == RB_LEFT(name##_RB_GETPARENT(elm), field)) \
RB_LEFT(name##_RB_GETPARENT(elm), field) = (tmp); \
else \
RB_RIGHT(name##_RB_GETPARENT(elm), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
name##_RB_SETPARENT(elm, tmp); \
RB_AUGMENT(tmp); \
if ((name##_RB_GETPARENT(tmp))) \
RB_AUGMENT(name##_RB_GETPARENT(tmp)); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
void name##_RB_INSERT_COLOR(struct name *, struct type *); \
void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
struct type *name##_RB_REMOVE(struct name *, struct type *); \
struct type *name##_RB_INSERT(struct name *, struct type *); \
struct type *name##_RB_FIND(struct name *, struct type *); \
struct type *name##_RB_NEXT(struct type *); \
struct type *name##_RB_MINMAX(struct name *, int); \
struct type *name##_RB_GETPARENT(struct type*); \
struct type *name##_RB_SETPARENT(struct type*, struct type*); \
int name##_RB_GETCOLOR(struct type*); \
void name##_RB_SETCOLOR(struct type*,int);
/* Generates prototypes (with storage class) and inline functions */
#define RB_PROTOTYPE_SC(_sc_, name, type, field, cmp) \
_sc_ void name##_RB_INSERT_COLOR(struct name *, struct type *); \
_sc_ void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *); \
_sc_ struct type *name##_RB_REMOVE(struct name *, struct type *); \
_sc_ struct type *name##_RB_INSERT(struct name *, struct type *); \
_sc_ struct type *name##_RB_FIND(struct name *, struct type *); \
_sc_ struct type *name##_RB_NEXT(struct type *); \
_sc_ struct type *name##_RB_MINMAX(struct name *, int); \
_sc_ struct type *name##_RB_GETPARENT(struct type*); \
_sc_ struct type *name##_RB_SETPARENT(struct type*, struct type*); \
_sc_ int name##_RB_GETCOLOR(struct type*); \
_sc_ void name##_RB_SETCOLOR(struct type*,int);
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
struct type *name##_RB_GETPARENT(struct type *elm) { \
struct type *parent = _RB_PARENT(elm, field); \
if( parent != NULL) { \
parent = (struct type*)((uintptr_t)parent & ~RB_COLOR_MASK);\
return( (struct type*) ( (parent == (struct type*) RB_PLACEHOLDER) ? NULL: parent));\
} \
return((struct type*)NULL); \
} \
int name##_RB_GETCOLOR(struct type *elm) { \
int color = 0; \
color = (int)((uintptr_t)_RB_PARENT(elm,field) & RB_COLOR_MASK);\
return(color); \
} \
void name##_RB_SETCOLOR(struct type *elm,int color) { \
struct type *parent = name##_RB_GETPARENT(elm); \
if(parent == (struct type*)NULL) \
parent = (struct type*) RB_PLACEHOLDER; \
_RB_PARENT(elm, field) = (struct type*)((uintptr_t)parent | (unsigned int)color);\
} \
struct type *name##_RB_SETPARENT(struct type *elm, struct type *parent) { \
int color = name##_RB_GETCOLOR(elm); \
_RB_PARENT(elm, field) = parent; \
if(color) name##_RB_SETCOLOR(elm, color); \
return(name##_RB_GETPARENT(elm)); \
} \
\
void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = name##_RB_GETPARENT(elm)) != NULL && \
name##_RB_GETCOLOR(parent) == RB_RED) { \
gparent = name##_RB_GETPARENT(parent); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (tmp && name##_RB_GETCOLOR(tmp) == RB_RED) { \
name##_RB_SETCOLOR(tmp, RB_BLACK); \
RB_SET_BLACKRED(name, parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(name, head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(name, parent, gparent, field); \
RB_ROTATE_RIGHT(name,head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (tmp && name##_RB_GETCOLOR(tmp) == RB_RED) { \
name##_RB_SETCOLOR(tmp, RB_BLACK); \
RB_SET_BLACKRED(name, parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(name, head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(name, parent, gparent, field); \
RB_ROTATE_LEFT(name, head, gparent, tmp, field); \
} \
} \
name##_RB_SETCOLOR(head->rbh_root, RB_BLACK); \
} \
\
void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || name##_RB_GETCOLOR(elm) == RB_BLACK) && \
elm != RB_ROOT(head)) { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (name##_RB_GETCOLOR(tmp) == RB_RED) { \
RB_SET_BLACKRED(name, tmp, parent, field); \
RB_ROTATE_LEFT(name, head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK)) {\
name##_RB_SETCOLOR(tmp, RB_RED); \
elm = parent; \
parent = name##_RB_GETPARENT(elm); \
} else { \
if (RB_RIGHT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)) \
!= NULL) \
name##_RB_SETCOLOR(oleft, RB_BLACK);\
name##_RB_SETCOLOR(tmp, RB_RED); \
RB_ROTATE_RIGHT(name, head, tmp, oleft, field);\
tmp = RB_RIGHT(parent, field); \
} \
name##_RB_SETCOLOR(tmp, (name##_RB_GETCOLOR(parent)));\
name##_RB_SETCOLOR(parent, RB_BLACK); \
if (RB_RIGHT(tmp, field)) \
name##_RB_SETCOLOR(RB_RIGHT(tmp, field),RB_BLACK);\
RB_ROTATE_LEFT(name, head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} else { \
tmp = RB_LEFT(parent, field); \
if (name##_RB_GETCOLOR(tmp) == RB_RED) { \
RB_SET_BLACKRED(name, tmp, parent, field); \
RB_ROTATE_RIGHT(name, head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK)) {\
name##_RB_SETCOLOR(tmp, RB_RED); \
elm = parent; \
parent = name##_RB_GETPARENT(elm); \
} else { \
if (RB_LEFT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)) \
!= NULL) \
name##_RB_SETCOLOR(oright, RB_BLACK);\
name##_RB_SETCOLOR(tmp, RB_RED); \
RB_ROTATE_LEFT(name, head, tmp, oright, field);\
tmp = RB_LEFT(parent, field); \
} \
name##_RB_SETCOLOR(tmp,(name##_RB_GETCOLOR(parent)));\
name##_RB_SETCOLOR(parent, RB_BLACK); \
if (RB_LEFT(tmp, field)) \
name##_RB_SETCOLOR(RB_LEFT(tmp, field), RB_BLACK);\
RB_ROTATE_RIGHT(name, head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
name##_RB_SETCOLOR(elm, RB_BLACK); \
} \
\
struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent, *old = elm; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else { \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field)) != NULL) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = name##_RB_GETPARENT(elm); \
color = name##_RB_GETCOLOR(elm); \
if (child) \
name##_RB_SETPARENT(child, parent); \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
if (name##_RB_GETPARENT(elm) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (name##_RB_GETPARENT(old)) { \
if (RB_LEFT(name##_RB_GETPARENT(old), field) == old)\
RB_LEFT(name##_RB_GETPARENT(old), field) = elm;\
else \
RB_RIGHT(name##_RB_GETPARENT(old), field) = elm;\
RB_AUGMENT(name##_RB_GETPARENT(old)); \
} else \
RB_ROOT(head) = elm; \
name##_RB_SETPARENT(RB_LEFT(old, field), elm); \
if (RB_RIGHT(old, field)) \
name##_RB_SETPARENT(RB_RIGHT(old, field), elm); \
if (parent) { \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = name##_RB_GETPARENT(left)) != NULL); \
} \
goto color; \
} \
parent = name##_RB_GETPARENT(elm); \
color = name##_RB_GETCOLOR(elm); \
if (child) \
name##_RB_SETPARENT(child, parent); \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \
} \
\
/* Inserts a node into the RB tree */ \
struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) { \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(name, elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
} \
\
/* Finds the node with the same key as elm */ \
struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
} \
\
/* ARGSUSED */ \
struct type * \
name##_RB_NEXT(struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) { \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} else { \
if (name##_RB_GETPARENT(elm) && \
(elm == RB_LEFT(name##_RB_GETPARENT(elm), field))) \
elm = name##_RB_GETPARENT(elm); \
else { \
while (name##_RB_GETPARENT(elm) && \
(elm == RB_RIGHT(name##_RB_GETPARENT(elm), field)))\
elm = name##_RB_GETPARENT(elm); \
elm = name##_RB_GETPARENT(elm); \
} \
} \
return (elm); \
} \
\
struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) { \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_PROTOTYPE_PREV(name, type, field, cmp) \
RB_PROTOTYPE(name, type, field, cmp) \
struct type *name##_RB_PREV(struct type *);
#define RB_PROTOTYPE_SC_PREV(_sc_, name, type, field, cmp) \
RB_PROTOTYPE_SC(_sc_, name, type, field, cmp) \
_sc_ struct type *name##_RB_PREV(struct type *);
#define RB_GENERATE_PREV(name, type, field, cmp) \
RB_GENERATE(name, type, field, cmp) \
struct type * \
name##_RB_PREV(struct type *elm) \
{ \
if (RB_LEFT(elm, field)) { \
elm = RB_LEFT(elm, field); \
while (RB_RIGHT(elm, field)) \
elm = RB_RIGHT(elm, field); \
} else { \
if (name##_RB_GETPARENT(elm) && \
(elm == RB_RIGHT(name##_RB_GETPARENT(elm), field))) \
elm = name##_RB_GETPARENT(elm); \
else { \
while (name##_RB_GETPARENT(elm) && \
(elm == RB_LEFT(name##_RB_GETPARENT(elm), field)))\
elm = name##_RB_GETPARENT(elm); \
elm = name##_RB_GETPARENT(elm); \
} \
} \
return (elm); \
} \
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_PREV(name, x, y) name##_RB_PREV(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#define RB_FOREACH_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_REVERSE_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_SAFE(x, name, head, y) \
for ((x) = RB_MIN(name, head); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#endif /* _LIBKERN_TREE_H_ */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,222 @@
/*
* Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1988, 1989, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 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.
*
* @(#)radix.h 8.2 (Berkeley) 10/31/94
* $FreeBSD: src/sys/net/radix.h,v 1.16.2.1 2000/05/03 19:17:11 wollman Exp $
*/
#ifndef _RADIX_H_
#define _RADIX_H_
#include <sys/appleapiopts.h>
#ifdef PRIVATE
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_RTABLE);
#endif
/*
* Radix search tree node layout.
*/
struct radix_node {
struct radix_mask *rn_mklist; /* list of masks contained in subtree */
struct radix_node *rn_parent; /* parent */
short rn_bit; /* bit offset; -1-index(netmask) */
char rn_bmask; /* node: mask for bit test*/
u_char rn_flags; /* enumerated next */
#define RNF_NORMAL 1 /* leaf contains normal route */
#define RNF_ROOT 2 /* leaf is root leaf for tree */
#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */
union {
struct { /* leaf only data: */
caddr_t rn_Key; /* object of search */
caddr_t rn_Mask; /* netmask, if present */
struct radix_node *rn_Dupedkey;
} rn_leaf;
struct { /* node only data: */
int rn_Off; /* where to start compare */
struct radix_node *rn_L;/* progeny */
struct radix_node *rn_R;/* progeny */
} rn_node;
} rn_u;
#ifdef RN_DEBUG
int rn_info;
struct radix_node *rn_twin;
struct radix_node *rn_ybro;
#endif
#if __arm__ && (__BIGGEST_ALIGNMENT__ > 4)
/* For the newer ARMv7k ABI where 64-bit types are 64-bit aligned, but pointers
* are 32-bit:
* Aligned to 64-bit since this is cast to rtentry, which is 64-bit aligned.
*/
} __attribute__ ((aligned(8)));
#else
};
#endif
#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey
#define rn_key rn_u.rn_leaf.rn_Key
#define rn_mask rn_u.rn_leaf.rn_Mask
#define rn_offset rn_u.rn_node.rn_Off
#define rn_left rn_u.rn_node.rn_L
#define rn_right rn_u.rn_node.rn_R
/*
* Annotations to tree concerning potential routes applying to subtrees.
*/
struct radix_mask {
short rm_bit; /* bit offset; -1-index(netmask) */
char rm_unused; /* cf. rn_bmask */
u_char rm_flags; /* cf. rn_flags */
struct radix_mask *rm_mklist; /* more masks to try */
union {
caddr_t rmu_mask; /* the mask */
struct radix_node *rmu_leaf; /* for normal routes */
} rm_rmu;
int rm_refs; /* # of references to this struct */
};
#define rm_mask rm_rmu.rmu_mask
#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */
#define MKGet(m) {\
if (rn_mkfreelist) {\
m = rn_mkfreelist; \
rn_mkfreelist = (m)->rm_mklist; \
} else \
R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\
#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}
typedef int walktree_f_t(struct radix_node *, void *);
typedef int rn_matchf_t(struct radix_node *, void *);
struct radix_node_head {
struct radix_node *rnh_treetop;
int rnh_addrsize; /* permit, but not require fixed keys */
int rnh_pktsize; /* permit, but not require fixed keys */
struct radix_node *(*rnh_addaddr) /* add based on sockaddr */
(void *v, void *mask,
struct radix_node_head *head, struct radix_node nodes[]);
struct radix_node *(*rnh_addpkt) /* add based on packet hdr */
(void *v, void *mask,
struct radix_node_head *head, struct radix_node nodes[]);
struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */
(void *v, void *mask, struct radix_node_head *head);
struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */
(void *v, void *mask, struct radix_node_head *head);
struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */
(void *v, struct radix_node_head *head);
/* locate based on sockaddr and rn_matchf_t() */
struct radix_node *(*rnh_matchaddr_args)
(void *v, struct radix_node_head *head,
rn_matchf_t *f, void *w);
struct radix_node *(*rnh_lookup) /* locate based on sockaddr */
(void *v, void *mask, struct radix_node_head *head);
/* locate based on sockaddr, mask and rn_matchf_t() */
struct radix_node *(*rnh_lookup_args)
(void *v, void *mask, struct radix_node_head *head,
rn_matchf_t *f, void *);
struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */
(void *v, struct radix_node_head *head);
int (*rnh_walktree) /* traverse tree */
(struct radix_node_head *head, walktree_f_t *f, void *w);
int (*rnh_walktree_from) /* traverse tree below a */
(struct radix_node_head *head, void *a, void *m,
walktree_f_t *f, void *w);
void (*rnh_close) /* do something when the last ref drops */
(struct radix_node *rn, struct radix_node_head *head);
struct radix_node rnh_nodes[3]; /* empty tree for common case */
int rnh_cnt; /* tree dimension */
};
#ifndef KERNEL
#define Bcmp(a, b, n) bcmp(((char *)(a)), ((char *)(b)), (n))
#define Bcopy(a, b, n) bcopy(((char *)(a)), ((char *)(b)), (unsigned)(n))
#define Bzero(p, n) bzero((char *)(p), (int)(n));
#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n)))
#define R_Free(p) free((char *)p);
#else
#define Bcmp(a, b, n) bcmp(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n))
#define Bcopy(a, b, n) bcopy(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n))
#define Bzero(p, n) bzero((caddr_t)(p), (unsigned)(n));
#define R_Malloc(p, t, n) (p = (t) _MALLOC((uint32_t)(n), M_RTABLE, M_WAITOK))
#define R_Free(p) FREE((caddr_t)p, M_RTABLE);
#endif /*KERNEL*/
void rn_init(void);
int rn_inithead(void **, int);
int rn_refines(void *, void *);
struct radix_node
*rn_addmask(void *, int, int),
*rn_addroute(void *, void *, struct radix_node_head *,
struct radix_node [2]),
*rn_delete(void *, void *, struct radix_node_head *),
*rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head),
*rn_lookup_args(void *v_arg, void *m_arg, struct radix_node_head *head,
rn_matchf_t *, void *),
*rn_match(void *, struct radix_node_head *),
*rn_match_args(void *, struct radix_node_head *, rn_matchf_t *, void *);
#endif /* PRIVATE */
#endif /* _RADIX_H_ */

@ -0,0 +1,367 @@
APPLE PUBLIC SOURCE LICENSE
Version 2.0 - August 6, 2003
Please read this License carefully before downloading this software.
By downloading or using this software, you are agreeing to be bound by
the terms of this License. If you do not or cannot agree to the terms
of this License, please do not download or use the software.
1. General; Definitions. This License applies to any program or other
work which Apple Computer, Inc. ("Apple") makes publicly available and
which contains a notice placed by Apple identifying such program or
work as "Original Code" and stating that it is subject to the terms of
this Apple Public Source License version 2.0 ("License"). As used in
this License:
1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
the grantor of rights, (i) claims of patents that are now or hereafter
acquired, owned by or assigned to Apple and (ii) that cover subject
matter contained in the Original Code, but only to the extent
necessary to use, reproduce and/or distribute the Original Code
without infringement; and (b) in the case where You are the grantor of
rights, (i) claims of patents that are now or hereafter acquired,
owned by or assigned to You and (ii) that cover subject matter in Your
Modifications, taken alone or in combination with Original Code.
1.2 "Contributor" means any person or entity that creates or
contributes to the creation of Modifications.
1.3 "Covered Code" means the Original Code, Modifications, the
combination of Original Code and any Modifications, and/or any
respective portions thereof.
1.4 "Externally Deploy" means: (a) to sublicense, distribute or
otherwise make Covered Code available, directly or indirectly, to
anyone other than You; and/or (b) to use Covered Code, alone or as
part of a Larger Work, in any way to provide a service, including but
not limited to delivery of content, through electronic communication
with a client other than You.
1.5 "Larger Work" means a work which combines Covered Code or portions
thereof with code not governed by the terms of this License.
1.6 "Modifications" mean any addition to, deletion from, and/or change
to, the substance and/or structure of the Original Code, any previous
Modifications, the combination of Original Code and any previous
Modifications, and/or any respective portions thereof. When code is
released as a series of files, a Modification is: (a) any addition to
or deletion from the contents of a file containing Covered Code;
and/or (b) any new file or other representation of computer program
statements that contains any part of Covered Code.
1.7 "Original Code" means (a) the Source Code of a program or other
work as originally made available by Apple under this License,
including the Source Code of any updates or upgrades to such programs
or works made available by Apple under this License, and that has been
expressly identified by Apple as such in the header file(s) of such
work; and (b) the object code compiled from such Source Code and
originally made available by Apple under this License.
1.8 "Source Code" means the human readable form of a program or other
work that is suitable for making modifications to it, including all
modules it contains, plus any associated interface definition files,
scripts used to control compilation and installation of an executable
(object code).
1.9 "You" or "Your" means an individual or a legal entity exercising
rights under this License. For legal entities, "You" or "Your"
includes any entity which controls, is controlled by, or is under
common control with, You, where "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of fifty percent
(50%) or more of the outstanding shares or beneficial ownership of
such entity.
2. Permitted Uses; Conditions & Restrictions. Subject to the terms
and conditions of this License, Apple hereby grants You, effective on
the date You accept this License and download the Original Code, a
world-wide, royalty-free, non-exclusive license, to the extent of
Apple's Applicable Patent Rights and copyrights covering the Original
Code, to do the following:
2.1 Unmodified Code. You may use, reproduce, display, perform,
internally distribute within Your organization, and Externally Deploy
verbatim, unmodified copies of the Original Code, for commercial or
non-commercial purposes, provided that in each instance:
(a) You must retain and reproduce in all copies of Original Code the
copyright and other proprietary notices and disclaimers of Apple as
they appear in the Original Code, and keep intact all notices in the
Original Code that refer to this License; and
(b) You must include a copy of this License with every copy of Source
Code of Covered Code and documentation You distribute or Externally
Deploy, and You may not offer or impose any terms on such Source Code
that alter or restrict this License or the recipients' rights
hereunder, except as permitted under Section 6.
2.2 Modified Code. You may modify Covered Code and use, reproduce,
display, perform, internally distribute within Your organization, and
Externally Deploy Your Modifications and Covered Code, for commercial
or non-commercial purposes, provided that in each instance You also
meet all of these conditions:
(a) You must satisfy all the conditions of Section 2.1 with respect to
the Source Code of the Covered Code;
(b) You must duplicate, to the extent it does not already exist, the
notice in Exhibit A in each file of the Source Code of all Your
Modifications, and cause the modified files to carry prominent notices
stating that You changed the files and the date of any change; and
(c) If You Externally Deploy Your Modifications, You must make
Source Code of all Your Externally Deployed Modifications either
available to those to whom You have Externally Deployed Your
Modifications, or publicly available. Source Code of Your Externally
Deployed Modifications must be released under the terms set forth in
this License, including the license grants set forth in Section 3
below, for as long as you Externally Deploy the Covered Code or twelve
(12) months from the date of initial External Deployment, whichever is
longer. You should preferably distribute the Source Code of Your
Externally Deployed Modifications electronically (e.g. download from a
web site).
2.3 Distribution of Executable Versions. In addition, if You
Externally Deploy Covered Code (Original Code and/or Modifications) in
object code, executable form only, You must include a prominent
notice, in the code itself as well as in related documentation,
stating that Source Code of the Covered Code is available under the
terms of this License with information on how and where to obtain such
Source Code.
2.4 Third Party Rights. You expressly acknowledge and agree that
although Apple and each Contributor grants the licenses to their
respective portions of the Covered Code set forth herein, no
assurances are provided by Apple or any Contributor that the Covered
Code does not infringe the patent or other intellectual property
rights of any other entity. Apple and each Contributor disclaim any
liability to You for claims brought by any other entity based on
infringement of intellectual property rights or otherwise. As a
condition to exercising the rights and licenses granted hereunder, You
hereby assume sole responsibility to secure any other intellectual
property rights needed, if any. For example, if a third party patent
license is required to allow You to distribute the Covered Code, it is
Your responsibility to acquire that license before distributing the
Covered Code.
3. Your Grants. In consideration of, and as a condition to, the
licenses granted to You under this License, You hereby grant to any
person or entity receiving or distributing Covered Code under this
License a non-exclusive, royalty-free, perpetual, irrevocable license,
under Your Applicable Patent Rights and other intellectual property
rights (other than patent) owned or controlled by You, to use,
reproduce, display, perform, modify, sublicense, distribute and
Externally Deploy Your Modifications of the same scope and extent as
Apple's licenses under Sections 2.1 and 2.2 above.
4. Larger Works. You may create a Larger Work by combining Covered
Code with other code not governed by the terms of this License and
distribute the Larger Work as a single product. In each such instance,
You must make sure the requirements of this License are fulfilled for
the Covered Code or any portion thereof.
5. Limitations on Patent License. Except as expressly stated in
Section 2, no other patent rights, express or implied, are granted by
Apple herein. Modifications and/or Larger Works may require additional
patent licenses from Apple which Apple may grant in its sole
discretion.
6. Additional Terms. You may choose to offer, and to charge a fee for,
warranty, support, indemnity or liability obligations and/or other
rights consistent with the scope of the license granted herein
("Additional Terms") to one or more recipients of Covered Code.
However, You may do so only on Your own behalf and as Your sole
responsibility, and not on behalf of Apple or any Contributor. You
must obtain the recipient's agreement that any such Additional Terms
are offered by You alone, and You hereby agree to indemnify, defend
and hold Apple and every Contributor harmless for any liability
incurred by or claims asserted against Apple or such Contributor by
reason of any such Additional Terms.
7. Versions of the License. Apple may publish revised and/or new
versions of this License from time to time. Each version will be given
a distinguishing version number. Once Original Code has been published
under a particular version of this License, You may continue to use it
under the terms of that version. You may also choose to use such
Original Code under the terms of any subsequent version of this
License published by Apple. No one other than Apple has the right to
modify the terms applicable to Covered Code created under this
License.
8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
part pre-release, untested, or not fully tested works. The Covered
Code may contain errors that could cause failures or loss of data, and
may be incomplete or contain inaccuracies. You expressly acknowledge
and agree that use of the Covered Code, or any portion thereof, is at
Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
You acknowledge that the Covered Code is not intended for use in the
operation of nuclear facilities, aircraft navigation, communication
systems, or air traffic control machines in which case the failure of
the Covered Code could lead to death, personal injury, or severe
physical or environmental damage.
9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
TO YOU. In no event shall Apple's total liability to You for all
damages (other than as may be required by applicable law) under this
License exceed the amount of fifty dollars ($50.00).
10. Trademarks. This License does not grant any rights to use the
trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
"QuickTime", "QuickTime Streaming Server" or any other trademarks,
service marks, logos or trade names belonging to Apple (collectively
"Apple Marks") or to any trademark, service mark, logo or trade name
belonging to any Contributor. You agree not to use any Apple Marks in
or as part of the name of products derived from the Original Code or
to endorse or promote products derived from the Original Code other
than as expressly permitted by and in strict compliance at all times
with Apple's third party trademark usage guidelines which are posted
at http://www.apple.com/legal/guidelinesfor3rdparties.html.
11. Ownership. Subject to the licenses granted under this License,
each Contributor retains all rights, title and interest in and to any
Modifications made by such Contributor. Apple retains all rights,
title and interest in and to the Original Code and any Modifications
made by or on behalf of Apple ("Apple Modifications"), and such Apple
Modifications will not be automatically subject to this License. Apple
may, at its sole discretion, choose to license such Apple
Modifications under this License, or on different terms from those
contained in this License or may choose not to license them at all.
12. Termination.
12.1 Termination. This License and the rights granted hereunder will
terminate:
(a) automatically without notice from Apple if You fail to comply with
any term(s) of this License and fail to cure such breach within 30
days of becoming aware of such breach;
(b) immediately in the event of the circumstances described in Section
13.5(b); or
(c) automatically without notice from Apple if You, at any time during
the term of this License, commence an action for patent infringement
against Apple; provided that Apple did not first commence
an action for patent infringement against You in that instance.
12.2 Effect of Termination. Upon termination, You agree to immediately
stop any further use, reproduction, modification, sublicensing and
distribution of the Covered Code. All sublicenses to the Covered Code
which have been properly granted prior to termination shall survive
any termination of this License. Provisions which, by their nature,
should remain in effect beyond the termination of this License shall
survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
12.2 and 13. No party will be liable to any other for compensation,
indemnity or damages of any sort solely as a result of terminating
this License in accordance with its terms, and termination of this
License will be without prejudice to any other right or remedy of
any party.
13. Miscellaneous.
13.1 Government End Users. The Covered Code is a "commercial item" as
defined in FAR 2.101. Government software and technical data rights in
the Covered Code include only those rights customarily provided to the
public as defined in this License. This customary commercial license
in technical data and software is provided in accordance with FAR
12.211 (Technical Data) and 12.212 (Computer Software) and, for
Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
Commercial Items) and 227.7202-3 (Rights in Commercial Computer
Software or Computer Software Documentation). Accordingly, all U.S.
Government End Users acquire Covered Code with only those rights set
forth herein.
13.2 Relationship of Parties. This License will not be construed as
creating an agency, partnership, joint venture or any other form of
legal association between or among You, Apple or any Contributor, and
You will not represent to the contrary, whether expressly, by
implication, appearance or otherwise.
13.3 Independent Development. Nothing in this License will impair
Apple's right to acquire, license, develop, have others develop for
it, market and/or distribute technology or products that perform the
same or similar functions as, or otherwise compete with,
Modifications, Larger Works, technology or products that You may
develop, produce, market or distribute.
13.4 Waiver; Construction. Failure by Apple or any Contributor to
enforce any provision of this License will not be deemed a waiver of
future enforcement of that or any other provision. Any law or
regulation which provides that the language of a contract shall be
construed against the drafter will not apply to this License.
13.5 Severability. (a) If for any reason a court of competent
jurisdiction finds any provision of this License, or portion thereof,
to be unenforceable, that provision of the License will be enforced to
the maximum extent permissible so as to effect the economic benefits
and intent of the parties, and the remainder of this License will
continue in full force and effect. (b) Notwithstanding the foregoing,
if applicable law prohibits or restricts You from fully and/or
specifically complying with Sections 2 and/or 3 or prevents the
enforceability of either of those Sections, this License will
immediately terminate and You must immediately discontinue any use of
the Covered Code and destroy all copies of it that are in your
possession or control.
13.6 Dispute Resolution. Any litigation or other dispute resolution
between You and Apple relating to this License shall take place in the
Northern District of California, and You and Apple hereby consent to
the personal jurisdiction of, and venue in, the state and federal
courts within that District with respect to this License. The
application of the United Nations Convention on Contracts for the
International Sale of Goods is expressly excluded.
13.7 Entire Agreement; Governing Law. This License constitutes the
entire agreement between the parties with respect to the subject
matter hereof. This License shall be governed by the laws of the
United States and the State of California, except that body of
California law concerning conflicts of law.
Where You are located in the province of Quebec, Canada, the following
clause applies: The parties hereby confirm that they have requested
that this License and all related documents be drafted in English. Les
parties ont exige que le present contrat et tous les documents
connexes soient rediges en anglais.
EXHIBIT A.
"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
Reserved.
This file contains Original Code and/or Modifications of Original Code
as defined in and that are subject to the Apple Public Source License
Version 2.0 (the 'License'). You may not use this file except in
compliance with the License. Please obtain a copy of the License at
http://www.opensource.apple.com/apsl/ and read it before using this
file.
The Original Code and all software distributed under the License are
distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
Please see the License for the specific language governing rights and
limitations under the License."

@ -0,0 +1,802 @@
/*
* Copyright (c) 2009-2010 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/* $NetBSD: tree.h,v 1.13 2006/08/27 22:32:38 christos Exp $ */
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#ifndef _LIBKERN_TREE_H_
#define _LIBKERN_TREE_H_
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
*
* A splay tree is a self-organizing data structure. Every operation
* on the tree causes a splay to happen. The splay moves the requested
* node to the root of the tree and partly rebalances it.
*
* This has the benefit that request locality causes faster lookups as
* the requested nodes move to the top of the tree. On the other hand,
* every lookup causes memory writes.
*
* The Balance Theorem bounds the total access time for m operations
* and n inserts on an initially empty tree as O((m + n)lg n). The
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
#define SPLAY_HEAD(name, type) \
struct name { \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ NULL }
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ENTRY(type) \
struct { \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return(NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \
elm = SPLAY_LEFT(elm, field); \
} \
} else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) { \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \
return ((head)->sph_root); \
} \
(head)->sph_root = (elm); \
return (NULL); \
} \
\
struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
} else { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
return (elm); \
} \
return (NULL); \
} \
\
void \
name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0){ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while (1) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) { \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-black tree */
#define RB_HEAD(name, type) \
struct name { \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ NULL }
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_PLACEHOLDER NULL
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
}
#define RB_COLOR_MASK (uintptr_t)0x1
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define _RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(name, elm, parent, field) do { \
name##_RB_SETPARENT(elm, parent); \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
name##_RB_SETCOLOR(elm, RB_RED); \
} while (/*CONSTCOND*/ 0)
#define RB_SET_BLACKRED(name, black, red, field) do { \
name##_RB_SETCOLOR(black, RB_BLACK); \
name##_RB_SETCOLOR(red, RB_RED); \
} while (/*CONSTCOND*/ 0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x) (void)(x)
#endif
#define RB_ROTATE_LEFT(name, head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
name##_RB_SETPARENT(RB_LEFT(tmp, field),(elm)); \
} \
RB_AUGMENT(elm); \
if (name##_RB_SETPARENT(tmp, name##_RB_GETPARENT(elm)) != NULL) { \
if ((elm) == RB_LEFT(name##_RB_GETPARENT(elm), field)) \
RB_LEFT(name##_RB_GETPARENT(elm), field) = (tmp); \
else \
RB_RIGHT(name##_RB_GETPARENT(elm), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
name##_RB_SETPARENT(elm, (tmp)); \
RB_AUGMENT(tmp); \
if ((name##_RB_GETPARENT(tmp))) \
RB_AUGMENT(name##_RB_GETPARENT(tmp)); \
} while (/*CONSTCOND*/ 0)
#define RB_ROTATE_RIGHT(name, head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
name##_RB_SETPARENT(RB_RIGHT(tmp, field), (elm)); \
} \
RB_AUGMENT(elm); \
if (name##_RB_SETPARENT(tmp, name##_RB_GETPARENT(elm)) != NULL) { \
if ((elm) == RB_LEFT(name##_RB_GETPARENT(elm), field)) \
RB_LEFT(name##_RB_GETPARENT(elm), field) = (tmp); \
else \
RB_RIGHT(name##_RB_GETPARENT(elm), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
name##_RB_SETPARENT(elm, tmp); \
RB_AUGMENT(tmp); \
if ((name##_RB_GETPARENT(tmp))) \
RB_AUGMENT(name##_RB_GETPARENT(tmp)); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
void name##_RB_INSERT_COLOR(struct name *, struct type *); \
void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
struct type *name##_RB_REMOVE(struct name *, struct type *); \
struct type *name##_RB_INSERT(struct name *, struct type *); \
struct type *name##_RB_FIND(struct name *, struct type *); \
struct type *name##_RB_NEXT(struct type *); \
struct type *name##_RB_MINMAX(struct name *, int); \
struct type *name##_RB_GETPARENT(struct type*); \
struct type *name##_RB_SETPARENT(struct type*, struct type*); \
int name##_RB_GETCOLOR(struct type*); \
void name##_RB_SETCOLOR(struct type*,int);
/* Generates prototypes (with storage class) and inline functions */
#define RB_PROTOTYPE_SC(_sc_, name, type, field, cmp) \
_sc_ void name##_RB_INSERT_COLOR(struct name *, struct type *); \
_sc_ void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *); \
_sc_ struct type *name##_RB_REMOVE(struct name *, struct type *); \
_sc_ struct type *name##_RB_INSERT(struct name *, struct type *); \
_sc_ struct type *name##_RB_FIND(struct name *, struct type *); \
_sc_ struct type *name##_RB_NEXT(struct type *); \
_sc_ struct type *name##_RB_MINMAX(struct name *, int); \
_sc_ struct type *name##_RB_GETPARENT(struct type*); \
_sc_ struct type *name##_RB_SETPARENT(struct type*, struct type*); \
_sc_ int name##_RB_GETCOLOR(struct type*); \
_sc_ void name##_RB_SETCOLOR(struct type*,int);
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
struct type *name##_RB_GETPARENT(struct type *elm) { \
struct type *parent = _RB_PARENT(elm, field); \
if( parent != NULL) { \
parent = (struct type*)((uintptr_t)parent & ~RB_COLOR_MASK);\
return( (struct type*) ( (parent == (struct type*) RB_PLACEHOLDER) ? NULL: parent));\
} \
return((struct type*)NULL); \
} \
int name##_RB_GETCOLOR(struct type *elm) { \
int color = 0; \
color = (int)((uintptr_t)_RB_PARENT(elm,field) & RB_COLOR_MASK);\
return(color); \
} \
void name##_RB_SETCOLOR(struct type *elm,int color) { \
struct type *parent = name##_RB_GETPARENT(elm); \
if(parent == (struct type*)NULL) \
parent = (struct type*) RB_PLACEHOLDER; \
_RB_PARENT(elm, field) = (struct type*)((uintptr_t)parent | (unsigned int)color);\
} \
struct type *name##_RB_SETPARENT(struct type *elm, struct type *parent) { \
int color = name##_RB_GETCOLOR(elm); \
_RB_PARENT(elm, field) = parent; \
if(color) name##_RB_SETCOLOR(elm, color); \
return(name##_RB_GETPARENT(elm)); \
} \
\
void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = name##_RB_GETPARENT(elm)) != NULL && \
name##_RB_GETCOLOR(parent) == RB_RED) { \
gparent = name##_RB_GETPARENT(parent); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (tmp && name##_RB_GETCOLOR(tmp) == RB_RED) { \
name##_RB_SETCOLOR(tmp, RB_BLACK); \
RB_SET_BLACKRED(name, parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(name, head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(name, parent, gparent, field); \
RB_ROTATE_RIGHT(name,head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (tmp && name##_RB_GETCOLOR(tmp) == RB_RED) { \
name##_RB_SETCOLOR(tmp, RB_BLACK); \
RB_SET_BLACKRED(name, parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(name, head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(name, parent, gparent, field); \
RB_ROTATE_LEFT(name, head, gparent, tmp, field); \
} \
} \
name##_RB_SETCOLOR(head->rbh_root, RB_BLACK); \
} \
\
void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || name##_RB_GETCOLOR(elm) == RB_BLACK) && \
elm != RB_ROOT(head)) { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (name##_RB_GETCOLOR(tmp) == RB_RED) { \
RB_SET_BLACKRED(name, tmp, parent, field); \
RB_ROTATE_LEFT(name, head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK)) {\
name##_RB_SETCOLOR(tmp, RB_RED); \
elm = parent; \
parent = name##_RB_GETPARENT(elm); \
} else { \
if (RB_RIGHT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)) \
!= NULL) \
name##_RB_SETCOLOR(oleft, RB_BLACK);\
name##_RB_SETCOLOR(tmp, RB_RED); \
RB_ROTATE_RIGHT(name, head, tmp, oleft, field);\
tmp = RB_RIGHT(parent, field); \
} \
name##_RB_SETCOLOR(tmp, (name##_RB_GETCOLOR(parent)));\
name##_RB_SETCOLOR(parent, RB_BLACK); \
if (RB_RIGHT(tmp, field)) \
name##_RB_SETCOLOR(RB_RIGHT(tmp, field),RB_BLACK);\
RB_ROTATE_LEFT(name, head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} else { \
tmp = RB_LEFT(parent, field); \
if (name##_RB_GETCOLOR(tmp) == RB_RED) { \
RB_SET_BLACKRED(name, tmp, parent, field); \
RB_ROTATE_RIGHT(name, head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK)) {\
name##_RB_SETCOLOR(tmp, RB_RED); \
elm = parent; \
parent = name##_RB_GETPARENT(elm); \
} else { \
if (RB_LEFT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)) \
!= NULL) \
name##_RB_SETCOLOR(oright, RB_BLACK);\
name##_RB_SETCOLOR(tmp, RB_RED); \
RB_ROTATE_LEFT(name, head, tmp, oright, field);\
tmp = RB_LEFT(parent, field); \
} \
name##_RB_SETCOLOR(tmp,(name##_RB_GETCOLOR(parent)));\
name##_RB_SETCOLOR(parent, RB_BLACK); \
if (RB_LEFT(tmp, field)) \
name##_RB_SETCOLOR(RB_LEFT(tmp, field), RB_BLACK);\
RB_ROTATE_RIGHT(name, head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
name##_RB_SETCOLOR(elm, RB_BLACK); \
} \
\
struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent, *old = elm; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else { \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field)) != NULL) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = name##_RB_GETPARENT(elm); \
color = name##_RB_GETCOLOR(elm); \
if (child) \
name##_RB_SETPARENT(child, parent); \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
if (name##_RB_GETPARENT(elm) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (name##_RB_GETPARENT(old)) { \
if (RB_LEFT(name##_RB_GETPARENT(old), field) == old)\
RB_LEFT(name##_RB_GETPARENT(old), field) = elm;\
else \
RB_RIGHT(name##_RB_GETPARENT(old), field) = elm;\
RB_AUGMENT(name##_RB_GETPARENT(old)); \
} else \
RB_ROOT(head) = elm; \
name##_RB_SETPARENT(RB_LEFT(old, field), elm); \
if (RB_RIGHT(old, field)) \
name##_RB_SETPARENT(RB_RIGHT(old, field), elm); \
if (parent) { \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = name##_RB_GETPARENT(left)) != NULL); \
} \
goto color; \
} \
parent = name##_RB_GETPARENT(elm); \
color = name##_RB_GETCOLOR(elm); \
if (child) \
name##_RB_SETPARENT(child, parent); \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \
} \
\
/* Inserts a node into the RB tree */ \
struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) { \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(name, elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
} \
\
/* Finds the node with the same key as elm */ \
struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
} \
\
/* ARGSUSED */ \
struct type * \
name##_RB_NEXT(struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) { \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} else { \
if (name##_RB_GETPARENT(elm) && \
(elm == RB_LEFT(name##_RB_GETPARENT(elm), field))) \
elm = name##_RB_GETPARENT(elm); \
else { \
while (name##_RB_GETPARENT(elm) && \
(elm == RB_RIGHT(name##_RB_GETPARENT(elm), field)))\
elm = name##_RB_GETPARENT(elm); \
elm = name##_RB_GETPARENT(elm); \
} \
} \
return (elm); \
} \
\
struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) { \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_PROTOTYPE_PREV(name, type, field, cmp) \
RB_PROTOTYPE(name, type, field, cmp) \
struct type *name##_RB_PREV(struct type *);
#define RB_PROTOTYPE_SC_PREV(_sc_, name, type, field, cmp) \
RB_PROTOTYPE_SC(_sc_, name, type, field, cmp) \
_sc_ struct type *name##_RB_PREV(struct type *);
#define RB_GENERATE_PREV(name, type, field, cmp) \
RB_GENERATE(name, type, field, cmp) \
struct type * \
name##_RB_PREV(struct type *elm) \
{ \
if (RB_LEFT(elm, field)) { \
elm = RB_LEFT(elm, field); \
while (RB_RIGHT(elm, field)) \
elm = RB_RIGHT(elm, field); \
} else { \
if (name##_RB_GETPARENT(elm) && \
(elm == RB_RIGHT(name##_RB_GETPARENT(elm), field))) \
elm = name##_RB_GETPARENT(elm); \
else { \
while (name##_RB_GETPARENT(elm) && \
(elm == RB_LEFT(name##_RB_GETPARENT(elm), field)))\
elm = name##_RB_GETPARENT(elm); \
elm = name##_RB_GETPARENT(elm); \
} \
} \
return (elm); \
} \
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_PREV(name, x, y) name##_RB_PREV(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#define RB_FOREACH_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_REVERSE_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_SAFE(x, name, head, y) \
for ((x) = RB_MIN(name, head); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#endif /* _LIBKERN_TREE_H_ */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,222 @@
/*
* Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1988, 1989, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 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.
*
* @(#)radix.h 8.2 (Berkeley) 10/31/94
* $FreeBSD: src/sys/net/radix.h,v 1.16.2.1 2000/05/03 19:17:11 wollman Exp $
*/
#ifndef _RADIX_H_
#define _RADIX_H_
#include <sys/appleapiopts.h>
#ifdef PRIVATE
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_RTABLE);
#endif
/*
* Radix search tree node layout.
*/
struct radix_node {
struct radix_mask *rn_mklist; /* list of masks contained in subtree */
struct radix_node *rn_parent; /* parent */
short rn_bit; /* bit offset; -1-index(netmask) */
char rn_bmask; /* node: mask for bit test*/
u_char rn_flags; /* enumerated next */
#define RNF_NORMAL 1 /* leaf contains normal route */
#define RNF_ROOT 2 /* leaf is root leaf for tree */
#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */
union {
struct { /* leaf only data: */
caddr_t rn_Key; /* object of search */
caddr_t rn_Mask; /* netmask, if present */
struct radix_node *rn_Dupedkey;
} rn_leaf;
struct { /* node only data: */
int rn_Off; /* where to start compare */
struct radix_node *rn_L;/* progeny */
struct radix_node *rn_R;/* progeny */
} rn_node;
} rn_u;
#ifdef RN_DEBUG
int rn_info;
struct radix_node *rn_twin;
struct radix_node *rn_ybro;
#endif
#if __arm__ && (__BIGGEST_ALIGNMENT__ > 4)
/* For the newer ARMv7k ABI where 64-bit types are 64-bit aligned, but pointers
* are 32-bit:
* Aligned to 64-bit since this is cast to rtentry, which is 64-bit aligned.
*/
} __attribute__ ((aligned(8)));
#else
};
#endif
#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey
#define rn_key rn_u.rn_leaf.rn_Key
#define rn_mask rn_u.rn_leaf.rn_Mask
#define rn_offset rn_u.rn_node.rn_Off
#define rn_left rn_u.rn_node.rn_L
#define rn_right rn_u.rn_node.rn_R
/*
* Annotations to tree concerning potential routes applying to subtrees.
*/
struct radix_mask {
short rm_bit; /* bit offset; -1-index(netmask) */
char rm_unused; /* cf. rn_bmask */
u_char rm_flags; /* cf. rn_flags */
struct radix_mask *rm_mklist; /* more masks to try */
union {
caddr_t rmu_mask; /* the mask */
struct radix_node *rmu_leaf; /* for normal routes */
} rm_rmu;
int rm_refs; /* # of references to this struct */
};
#define rm_mask rm_rmu.rmu_mask
#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */
#define MKGet(m) {\
if (rn_mkfreelist) {\
m = rn_mkfreelist; \
rn_mkfreelist = (m)->rm_mklist; \
} else \
R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\
#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}
typedef int walktree_f_t(struct radix_node *, void *);
typedef int rn_matchf_t(struct radix_node *, void *);
struct radix_node_head {
struct radix_node *rnh_treetop;
int rnh_addrsize; /* permit, but not require fixed keys */
int rnh_pktsize; /* permit, but not require fixed keys */
struct radix_node *(*rnh_addaddr) /* add based on sockaddr */
(void *v, void *mask,
struct radix_node_head *head, struct radix_node nodes[]);
struct radix_node *(*rnh_addpkt) /* add based on packet hdr */
(void *v, void *mask,
struct radix_node_head *head, struct radix_node nodes[]);
struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */
(void *v, void *mask, struct radix_node_head *head);
struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */
(void *v, void *mask, struct radix_node_head *head);
struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */
(void *v, struct radix_node_head *head);
/* locate based on sockaddr and rn_matchf_t() */
struct radix_node *(*rnh_matchaddr_args)
(void *v, struct radix_node_head *head,
rn_matchf_t *f, void *w);
struct radix_node *(*rnh_lookup) /* locate based on sockaddr */
(void *v, void *mask, struct radix_node_head *head);
/* locate based on sockaddr, mask and rn_matchf_t() */
struct radix_node *(*rnh_lookup_args)
(void *v, void *mask, struct radix_node_head *head,
rn_matchf_t *f, void *);
struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */
(void *v, struct radix_node_head *head);
int (*rnh_walktree) /* traverse tree */
(struct radix_node_head *head, walktree_f_t *f, void *w);
int (*rnh_walktree_from) /* traverse tree below a */
(struct radix_node_head *head, void *a, void *m,
walktree_f_t *f, void *w);
void (*rnh_close) /* do something when the last ref drops */
(struct radix_node *rn, struct radix_node_head *head);
struct radix_node rnh_nodes[3]; /* empty tree for common case */
int rnh_cnt; /* tree dimension */
};
#ifndef KERNEL
#define Bcmp(a, b, n) bcmp(((char *)(a)), ((char *)(b)), (n))
#define Bcopy(a, b, n) bcopy(((char *)(a)), ((char *)(b)), (unsigned)(n))
#define Bzero(p, n) bzero((char *)(p), (int)(n));
#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n)))
#define R_Free(p) free((char *)p);
#else
#define Bcmp(a, b, n) bcmp(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n))
#define Bcopy(a, b, n) bcopy(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n))
#define Bzero(p, n) bzero((caddr_t)(p), (unsigned)(n));
#define R_Malloc(p, t, n) (p = (t) _MALLOC((uint32_t)(n), M_RTABLE, M_WAITOK))
#define R_Free(p) FREE((caddr_t)p, M_RTABLE);
#endif /*KERNEL*/
void rn_init(void);
int rn_inithead(void **, int);
int rn_refines(void *, void *);
struct radix_node
*rn_addmask(void *, int, int),
*rn_addroute(void *, void *, struct radix_node_head *,
struct radix_node [2]),
*rn_delete(void *, void *, struct radix_node_head *),
*rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head),
*rn_lookup_args(void *v_arg, void *m_arg, struct radix_node_head *head,
rn_matchf_t *, void *),
*rn_match(void *, struct radix_node_head *),
*rn_match_args(void *, struct radix_node_head *, rn_matchf_t *, void *);
#endif /* PRIVATE */
#endif /* _RADIX_H_ */

@ -0,0 +1,367 @@
APPLE PUBLIC SOURCE LICENSE
Version 2.0 - August 6, 2003
Please read this License carefully before downloading this software.
By downloading or using this software, you are agreeing to be bound by
the terms of this License. If you do not or cannot agree to the terms
of this License, please do not download or use the software.
1. General; Definitions. This License applies to any program or other
work which Apple Computer, Inc. ("Apple") makes publicly available and
which contains a notice placed by Apple identifying such program or
work as "Original Code" and stating that it is subject to the terms of
this Apple Public Source License version 2.0 ("License"). As used in
this License:
1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
the grantor of rights, (i) claims of patents that are now or hereafter
acquired, owned by or assigned to Apple and (ii) that cover subject
matter contained in the Original Code, but only to the extent
necessary to use, reproduce and/or distribute the Original Code
without infringement; and (b) in the case where You are the grantor of
rights, (i) claims of patents that are now or hereafter acquired,
owned by or assigned to You and (ii) that cover subject matter in Your
Modifications, taken alone or in combination with Original Code.
1.2 "Contributor" means any person or entity that creates or
contributes to the creation of Modifications.
1.3 "Covered Code" means the Original Code, Modifications, the
combination of Original Code and any Modifications, and/or any
respective portions thereof.
1.4 "Externally Deploy" means: (a) to sublicense, distribute or
otherwise make Covered Code available, directly or indirectly, to
anyone other than You; and/or (b) to use Covered Code, alone or as
part of a Larger Work, in any way to provide a service, including but
not limited to delivery of content, through electronic communication
with a client other than You.
1.5 "Larger Work" means a work which combines Covered Code or portions
thereof with code not governed by the terms of this License.
1.6 "Modifications" mean any addition to, deletion from, and/or change
to, the substance and/or structure of the Original Code, any previous
Modifications, the combination of Original Code and any previous
Modifications, and/or any respective portions thereof. When code is
released as a series of files, a Modification is: (a) any addition to
or deletion from the contents of a file containing Covered Code;
and/or (b) any new file or other representation of computer program
statements that contains any part of Covered Code.
1.7 "Original Code" means (a) the Source Code of a program or other
work as originally made available by Apple under this License,
including the Source Code of any updates or upgrades to such programs
or works made available by Apple under this License, and that has been
expressly identified by Apple as such in the header file(s) of such
work; and (b) the object code compiled from such Source Code and
originally made available by Apple under this License.
1.8 "Source Code" means the human readable form of a program or other
work that is suitable for making modifications to it, including all
modules it contains, plus any associated interface definition files,
scripts used to control compilation and installation of an executable
(object code).
1.9 "You" or "Your" means an individual or a legal entity exercising
rights under this License. For legal entities, "You" or "Your"
includes any entity which controls, is controlled by, or is under
common control with, You, where "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of fifty percent
(50%) or more of the outstanding shares or beneficial ownership of
such entity.
2. Permitted Uses; Conditions & Restrictions. Subject to the terms
and conditions of this License, Apple hereby grants You, effective on
the date You accept this License and download the Original Code, a
world-wide, royalty-free, non-exclusive license, to the extent of
Apple's Applicable Patent Rights and copyrights covering the Original
Code, to do the following:
2.1 Unmodified Code. You may use, reproduce, display, perform,
internally distribute within Your organization, and Externally Deploy
verbatim, unmodified copies of the Original Code, for commercial or
non-commercial purposes, provided that in each instance:
(a) You must retain and reproduce in all copies of Original Code the
copyright and other proprietary notices and disclaimers of Apple as
they appear in the Original Code, and keep intact all notices in the
Original Code that refer to this License; and
(b) You must include a copy of this License with every copy of Source
Code of Covered Code and documentation You distribute or Externally
Deploy, and You may not offer or impose any terms on such Source Code
that alter or restrict this License or the recipients' rights
hereunder, except as permitted under Section 6.
2.2 Modified Code. You may modify Covered Code and use, reproduce,
display, perform, internally distribute within Your organization, and
Externally Deploy Your Modifications and Covered Code, for commercial
or non-commercial purposes, provided that in each instance You also
meet all of these conditions:
(a) You must satisfy all the conditions of Section 2.1 with respect to
the Source Code of the Covered Code;
(b) You must duplicate, to the extent it does not already exist, the
notice in Exhibit A in each file of the Source Code of all Your
Modifications, and cause the modified files to carry prominent notices
stating that You changed the files and the date of any change; and
(c) If You Externally Deploy Your Modifications, You must make
Source Code of all Your Externally Deployed Modifications either
available to those to whom You have Externally Deployed Your
Modifications, or publicly available. Source Code of Your Externally
Deployed Modifications must be released under the terms set forth in
this License, including the license grants set forth in Section 3
below, for as long as you Externally Deploy the Covered Code or twelve
(12) months from the date of initial External Deployment, whichever is
longer. You should preferably distribute the Source Code of Your
Externally Deployed Modifications electronically (e.g. download from a
web site).
2.3 Distribution of Executable Versions. In addition, if You
Externally Deploy Covered Code (Original Code and/or Modifications) in
object code, executable form only, You must include a prominent
notice, in the code itself as well as in related documentation,
stating that Source Code of the Covered Code is available under the
terms of this License with information on how and where to obtain such
Source Code.
2.4 Third Party Rights. You expressly acknowledge and agree that
although Apple and each Contributor grants the licenses to their
respective portions of the Covered Code set forth herein, no
assurances are provided by Apple or any Contributor that the Covered
Code does not infringe the patent or other intellectual property
rights of any other entity. Apple and each Contributor disclaim any
liability to You for claims brought by any other entity based on
infringement of intellectual property rights or otherwise. As a
condition to exercising the rights and licenses granted hereunder, You
hereby assume sole responsibility to secure any other intellectual
property rights needed, if any. For example, if a third party patent
license is required to allow You to distribute the Covered Code, it is
Your responsibility to acquire that license before distributing the
Covered Code.
3. Your Grants. In consideration of, and as a condition to, the
licenses granted to You under this License, You hereby grant to any
person or entity receiving or distributing Covered Code under this
License a non-exclusive, royalty-free, perpetual, irrevocable license,
under Your Applicable Patent Rights and other intellectual property
rights (other than patent) owned or controlled by You, to use,
reproduce, display, perform, modify, sublicense, distribute and
Externally Deploy Your Modifications of the same scope and extent as
Apple's licenses under Sections 2.1 and 2.2 above.
4. Larger Works. You may create a Larger Work by combining Covered
Code with other code not governed by the terms of this License and
distribute the Larger Work as a single product. In each such instance,
You must make sure the requirements of this License are fulfilled for
the Covered Code or any portion thereof.
5. Limitations on Patent License. Except as expressly stated in
Section 2, no other patent rights, express or implied, are granted by
Apple herein. Modifications and/or Larger Works may require additional
patent licenses from Apple which Apple may grant in its sole
discretion.
6. Additional Terms. You may choose to offer, and to charge a fee for,
warranty, support, indemnity or liability obligations and/or other
rights consistent with the scope of the license granted herein
("Additional Terms") to one or more recipients of Covered Code.
However, You may do so only on Your own behalf and as Your sole
responsibility, and not on behalf of Apple or any Contributor. You
must obtain the recipient's agreement that any such Additional Terms
are offered by You alone, and You hereby agree to indemnify, defend
and hold Apple and every Contributor harmless for any liability
incurred by or claims asserted against Apple or such Contributor by
reason of any such Additional Terms.
7. Versions of the License. Apple may publish revised and/or new
versions of this License from time to time. Each version will be given
a distinguishing version number. Once Original Code has been published
under a particular version of this License, You may continue to use it
under the terms of that version. You may also choose to use such
Original Code under the terms of any subsequent version of this
License published by Apple. No one other than Apple has the right to
modify the terms applicable to Covered Code created under this
License.
8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
part pre-release, untested, or not fully tested works. The Covered
Code may contain errors that could cause failures or loss of data, and
may be incomplete or contain inaccuracies. You expressly acknowledge
and agree that use of the Covered Code, or any portion thereof, is at
Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
You acknowledge that the Covered Code is not intended for use in the
operation of nuclear facilities, aircraft navigation, communication
systems, or air traffic control machines in which case the failure of
the Covered Code could lead to death, personal injury, or severe
physical or environmental damage.
9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
TO YOU. In no event shall Apple's total liability to You for all
damages (other than as may be required by applicable law) under this
License exceed the amount of fifty dollars ($50.00).
10. Trademarks. This License does not grant any rights to use the
trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
"QuickTime", "QuickTime Streaming Server" or any other trademarks,
service marks, logos or trade names belonging to Apple (collectively
"Apple Marks") or to any trademark, service mark, logo or trade name
belonging to any Contributor. You agree not to use any Apple Marks in
or as part of the name of products derived from the Original Code or
to endorse or promote products derived from the Original Code other
than as expressly permitted by and in strict compliance at all times
with Apple's third party trademark usage guidelines which are posted
at http://www.apple.com/legal/guidelinesfor3rdparties.html.
11. Ownership. Subject to the licenses granted under this License,
each Contributor retains all rights, title and interest in and to any
Modifications made by such Contributor. Apple retains all rights,
title and interest in and to the Original Code and any Modifications
made by or on behalf of Apple ("Apple Modifications"), and such Apple
Modifications will not be automatically subject to this License. Apple
may, at its sole discretion, choose to license such Apple
Modifications under this License, or on different terms from those
contained in this License or may choose not to license them at all.
12. Termination.
12.1 Termination. This License and the rights granted hereunder will
terminate:
(a) automatically without notice from Apple if You fail to comply with
any term(s) of this License and fail to cure such breach within 30
days of becoming aware of such breach;
(b) immediately in the event of the circumstances described in Section
13.5(b); or
(c) automatically without notice from Apple if You, at any time during
the term of this License, commence an action for patent infringement
against Apple; provided that Apple did not first commence
an action for patent infringement against You in that instance.
12.2 Effect of Termination. Upon termination, You agree to immediately
stop any further use, reproduction, modification, sublicensing and
distribution of the Covered Code. All sublicenses to the Covered Code
which have been properly granted prior to termination shall survive
any termination of this License. Provisions which, by their nature,
should remain in effect beyond the termination of this License shall
survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
12.2 and 13. No party will be liable to any other for compensation,
indemnity or damages of any sort solely as a result of terminating
this License in accordance with its terms, and termination of this
License will be without prejudice to any other right or remedy of
any party.
13. Miscellaneous.
13.1 Government End Users. The Covered Code is a "commercial item" as
defined in FAR 2.101. Government software and technical data rights in
the Covered Code include only those rights customarily provided to the
public as defined in this License. This customary commercial license
in technical data and software is provided in accordance with FAR
12.211 (Technical Data) and 12.212 (Computer Software) and, for
Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
Commercial Items) and 227.7202-3 (Rights in Commercial Computer
Software or Computer Software Documentation). Accordingly, all U.S.
Government End Users acquire Covered Code with only those rights set
forth herein.
13.2 Relationship of Parties. This License will not be construed as
creating an agency, partnership, joint venture or any other form of
legal association between or among You, Apple or any Contributor, and
You will not represent to the contrary, whether expressly, by
implication, appearance or otherwise.
13.3 Independent Development. Nothing in this License will impair
Apple's right to acquire, license, develop, have others develop for
it, market and/or distribute technology or products that perform the
same or similar functions as, or otherwise compete with,
Modifications, Larger Works, technology or products that You may
develop, produce, market or distribute.
13.4 Waiver; Construction. Failure by Apple or any Contributor to
enforce any provision of this License will not be deemed a waiver of
future enforcement of that or any other provision. Any law or
regulation which provides that the language of a contract shall be
construed against the drafter will not apply to this License.
13.5 Severability. (a) If for any reason a court of competent
jurisdiction finds any provision of this License, or portion thereof,
to be unenforceable, that provision of the License will be enforced to
the maximum extent permissible so as to effect the economic benefits
and intent of the parties, and the remainder of this License will
continue in full force and effect. (b) Notwithstanding the foregoing,
if applicable law prohibits or restricts You from fully and/or
specifically complying with Sections 2 and/or 3 or prevents the
enforceability of either of those Sections, this License will
immediately terminate and You must immediately discontinue any use of
the Covered Code and destroy all copies of it that are in your
possession or control.
13.6 Dispute Resolution. Any litigation or other dispute resolution
between You and Apple relating to this License shall take place in the
Northern District of California, and You and Apple hereby consent to
the personal jurisdiction of, and venue in, the state and federal
courts within that District with respect to this License. The
application of the United Nations Convention on Contracts for the
International Sale of Goods is expressly excluded.
13.7 Entire Agreement; Governing Law. This License constitutes the
entire agreement between the parties with respect to the subject
matter hereof. This License shall be governed by the laws of the
United States and the State of California, except that body of
California law concerning conflicts of law.
Where You are located in the province of Quebec, Canada, the following
clause applies: The parties hereby confirm that they have requested
that this License and all related documents be drafted in English. Les
parties ont exige que le present contrat et tous les documents
connexes soient rediges en anglais.
EXHIBIT A.
"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
Reserved.
This file contains Original Code and/or Modifications of Original Code
as defined in and that are subject to the Apple Public Source License
Version 2.0 (the 'License'). You may not use this file except in
compliance with the License. Please obtain a copy of the License at
http://www.opensource.apple.com/apsl/ and read it before using this
file.
The Original Code and all software distributed under the License are
distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
Please see the License for the specific language governing rights and
limitations under the License."

@ -0,0 +1,802 @@
/*
* Copyright (c) 2009-2010 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/* $NetBSD: tree.h,v 1.13 2006/08/27 22:32:38 christos Exp $ */
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#ifndef _LIBKERN_TREE_H_
#define _LIBKERN_TREE_H_
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
*
* A splay tree is a self-organizing data structure. Every operation
* on the tree causes a splay to happen. The splay moves the requested
* node to the root of the tree and partly rebalances it.
*
* This has the benefit that request locality causes faster lookups as
* the requested nodes move to the top of the tree. On the other hand,
* every lookup causes memory writes.
*
* The Balance Theorem bounds the total access time for m operations
* and n inserts on an initially empty tree as O((m + n)lg n). The
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
#define SPLAY_HEAD(name, type) \
struct name { \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ NULL }
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ENTRY(type) \
struct { \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return(NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \
elm = SPLAY_LEFT(elm, field); \
} \
} else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) { \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \
return ((head)->sph_root); \
} \
(head)->sph_root = (elm); \
return (NULL); \
} \
\
struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
} else { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
return (elm); \
} \
return (NULL); \
} \
\
void \
name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0){ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while (1) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) { \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-black tree */
#define RB_HEAD(name, type) \
struct name { \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ NULL }
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_PLACEHOLDER NULL
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
}
#define RB_COLOR_MASK (uintptr_t)0x1
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define _RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(name, elm, parent, field) do { \
name##_RB_SETPARENT(elm, parent); \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
name##_RB_SETCOLOR(elm, RB_RED); \
} while (/*CONSTCOND*/ 0)
#define RB_SET_BLACKRED(name, black, red, field) do { \
name##_RB_SETCOLOR(black, RB_BLACK); \
name##_RB_SETCOLOR(red, RB_RED); \
} while (/*CONSTCOND*/ 0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x) (void)(x)
#endif
#define RB_ROTATE_LEFT(name, head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
name##_RB_SETPARENT(RB_LEFT(tmp, field),(elm)); \
} \
RB_AUGMENT(elm); \
if (name##_RB_SETPARENT(tmp, name##_RB_GETPARENT(elm)) != NULL) { \
if ((elm) == RB_LEFT(name##_RB_GETPARENT(elm), field)) \
RB_LEFT(name##_RB_GETPARENT(elm), field) = (tmp); \
else \
RB_RIGHT(name##_RB_GETPARENT(elm), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
name##_RB_SETPARENT(elm, (tmp)); \
RB_AUGMENT(tmp); \
if ((name##_RB_GETPARENT(tmp))) \
RB_AUGMENT(name##_RB_GETPARENT(tmp)); \
} while (/*CONSTCOND*/ 0)
#define RB_ROTATE_RIGHT(name, head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
name##_RB_SETPARENT(RB_RIGHT(tmp, field), (elm)); \
} \
RB_AUGMENT(elm); \
if (name##_RB_SETPARENT(tmp, name##_RB_GETPARENT(elm)) != NULL) { \
if ((elm) == RB_LEFT(name##_RB_GETPARENT(elm), field)) \
RB_LEFT(name##_RB_GETPARENT(elm), field) = (tmp); \
else \
RB_RIGHT(name##_RB_GETPARENT(elm), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
name##_RB_SETPARENT(elm, tmp); \
RB_AUGMENT(tmp); \
if ((name##_RB_GETPARENT(tmp))) \
RB_AUGMENT(name##_RB_GETPARENT(tmp)); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
void name##_RB_INSERT_COLOR(struct name *, struct type *); \
void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
struct type *name##_RB_REMOVE(struct name *, struct type *); \
struct type *name##_RB_INSERT(struct name *, struct type *); \
struct type *name##_RB_FIND(struct name *, struct type *); \
struct type *name##_RB_NEXT(struct type *); \
struct type *name##_RB_MINMAX(struct name *, int); \
struct type *name##_RB_GETPARENT(struct type*); \
struct type *name##_RB_SETPARENT(struct type*, struct type*); \
int name##_RB_GETCOLOR(struct type*); \
void name##_RB_SETCOLOR(struct type*,int);
/* Generates prototypes (with storage class) and inline functions */
#define RB_PROTOTYPE_SC(_sc_, name, type, field, cmp) \
_sc_ void name##_RB_INSERT_COLOR(struct name *, struct type *); \
_sc_ void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *); \
_sc_ struct type *name##_RB_REMOVE(struct name *, struct type *); \
_sc_ struct type *name##_RB_INSERT(struct name *, struct type *); \
_sc_ struct type *name##_RB_FIND(struct name *, struct type *); \
_sc_ struct type *name##_RB_NEXT(struct type *); \
_sc_ struct type *name##_RB_MINMAX(struct name *, int); \
_sc_ struct type *name##_RB_GETPARENT(struct type*); \
_sc_ struct type *name##_RB_SETPARENT(struct type*, struct type*); \
_sc_ int name##_RB_GETCOLOR(struct type*); \
_sc_ void name##_RB_SETCOLOR(struct type*,int);
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
struct type *name##_RB_GETPARENT(struct type *elm) { \
struct type *parent = _RB_PARENT(elm, field); \
if( parent != NULL) { \
parent = (struct type*)((uintptr_t)parent & ~RB_COLOR_MASK);\
return( (struct type*) ( (parent == (struct type*) RB_PLACEHOLDER) ? NULL: parent));\
} \
return((struct type*)NULL); \
} \
int name##_RB_GETCOLOR(struct type *elm) { \
int color = 0; \
color = (int)((uintptr_t)_RB_PARENT(elm,field) & RB_COLOR_MASK);\
return(color); \
} \
void name##_RB_SETCOLOR(struct type *elm,int color) { \
struct type *parent = name##_RB_GETPARENT(elm); \
if(parent == (struct type*)NULL) \
parent = (struct type*) RB_PLACEHOLDER; \
_RB_PARENT(elm, field) = (struct type*)((uintptr_t)parent | (unsigned int)color);\
} \
struct type *name##_RB_SETPARENT(struct type *elm, struct type *parent) { \
int color = name##_RB_GETCOLOR(elm); \
_RB_PARENT(elm, field) = parent; \
if(color) name##_RB_SETCOLOR(elm, color); \
return(name##_RB_GETPARENT(elm)); \
} \
\
void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = name##_RB_GETPARENT(elm)) != NULL && \
name##_RB_GETCOLOR(parent) == RB_RED) { \
gparent = name##_RB_GETPARENT(parent); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (tmp && name##_RB_GETCOLOR(tmp) == RB_RED) { \
name##_RB_SETCOLOR(tmp, RB_BLACK); \
RB_SET_BLACKRED(name, parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(name, head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(name, parent, gparent, field); \
RB_ROTATE_RIGHT(name,head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (tmp && name##_RB_GETCOLOR(tmp) == RB_RED) { \
name##_RB_SETCOLOR(tmp, RB_BLACK); \
RB_SET_BLACKRED(name, parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(name, head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(name, parent, gparent, field); \
RB_ROTATE_LEFT(name, head, gparent, tmp, field); \
} \
} \
name##_RB_SETCOLOR(head->rbh_root, RB_BLACK); \
} \
\
void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || name##_RB_GETCOLOR(elm) == RB_BLACK) && \
elm != RB_ROOT(head)) { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (name##_RB_GETCOLOR(tmp) == RB_RED) { \
RB_SET_BLACKRED(name, tmp, parent, field); \
RB_ROTATE_LEFT(name, head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK)) {\
name##_RB_SETCOLOR(tmp, RB_RED); \
elm = parent; \
parent = name##_RB_GETPARENT(elm); \
} else { \
if (RB_RIGHT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)) \
!= NULL) \
name##_RB_SETCOLOR(oleft, RB_BLACK);\
name##_RB_SETCOLOR(tmp, RB_RED); \
RB_ROTATE_RIGHT(name, head, tmp, oleft, field);\
tmp = RB_RIGHT(parent, field); \
} \
name##_RB_SETCOLOR(tmp, (name##_RB_GETCOLOR(parent)));\
name##_RB_SETCOLOR(parent, RB_BLACK); \
if (RB_RIGHT(tmp, field)) \
name##_RB_SETCOLOR(RB_RIGHT(tmp, field),RB_BLACK);\
RB_ROTATE_LEFT(name, head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} else { \
tmp = RB_LEFT(parent, field); \
if (name##_RB_GETCOLOR(tmp) == RB_RED) { \
RB_SET_BLACKRED(name, tmp, parent, field); \
RB_ROTATE_RIGHT(name, head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK)) {\
name##_RB_SETCOLOR(tmp, RB_RED); \
elm = parent; \
parent = name##_RB_GETPARENT(elm); \
} else { \
if (RB_LEFT(tmp, field) == NULL || \
name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)) \
!= NULL) \
name##_RB_SETCOLOR(oright, RB_BLACK);\
name##_RB_SETCOLOR(tmp, RB_RED); \
RB_ROTATE_LEFT(name, head, tmp, oright, field);\
tmp = RB_LEFT(parent, field); \
} \
name##_RB_SETCOLOR(tmp,(name##_RB_GETCOLOR(parent)));\
name##_RB_SETCOLOR(parent, RB_BLACK); \
if (RB_LEFT(tmp, field)) \
name##_RB_SETCOLOR(RB_LEFT(tmp, field), RB_BLACK);\
RB_ROTATE_RIGHT(name, head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
name##_RB_SETCOLOR(elm, RB_BLACK); \
} \
\
struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent, *old = elm; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else { \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field)) != NULL) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = name##_RB_GETPARENT(elm); \
color = name##_RB_GETCOLOR(elm); \
if (child) \
name##_RB_SETPARENT(child, parent); \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
if (name##_RB_GETPARENT(elm) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (name##_RB_GETPARENT(old)) { \
if (RB_LEFT(name##_RB_GETPARENT(old), field) == old)\
RB_LEFT(name##_RB_GETPARENT(old), field) = elm;\
else \
RB_RIGHT(name##_RB_GETPARENT(old), field) = elm;\
RB_AUGMENT(name##_RB_GETPARENT(old)); \
} else \
RB_ROOT(head) = elm; \
name##_RB_SETPARENT(RB_LEFT(old, field), elm); \
if (RB_RIGHT(old, field)) \
name##_RB_SETPARENT(RB_RIGHT(old, field), elm); \
if (parent) { \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = name##_RB_GETPARENT(left)) != NULL); \
} \
goto color; \
} \
parent = name##_RB_GETPARENT(elm); \
color = name##_RB_GETCOLOR(elm); \
if (child) \
name##_RB_SETPARENT(child, parent); \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \
} \
\
/* Inserts a node into the RB tree */ \
struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) { \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(name, elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
} \
\
/* Finds the node with the same key as elm */ \
struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
} \
\
/* ARGSUSED */ \
struct type * \
name##_RB_NEXT(struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) { \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} else { \
if (name##_RB_GETPARENT(elm) && \
(elm == RB_LEFT(name##_RB_GETPARENT(elm), field))) \
elm = name##_RB_GETPARENT(elm); \
else { \
while (name##_RB_GETPARENT(elm) && \
(elm == RB_RIGHT(name##_RB_GETPARENT(elm), field)))\
elm = name##_RB_GETPARENT(elm); \
elm = name##_RB_GETPARENT(elm); \
} \
} \
return (elm); \
} \
\
struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) { \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_PROTOTYPE_PREV(name, type, field, cmp) \
RB_PROTOTYPE(name, type, field, cmp) \
struct type *name##_RB_PREV(struct type *);
#define RB_PROTOTYPE_SC_PREV(_sc_, name, type, field, cmp) \
RB_PROTOTYPE_SC(_sc_, name, type, field, cmp) \
_sc_ struct type *name##_RB_PREV(struct type *);
#define RB_GENERATE_PREV(name, type, field, cmp) \
RB_GENERATE(name, type, field, cmp) \
struct type * \
name##_RB_PREV(struct type *elm) \
{ \
if (RB_LEFT(elm, field)) { \
elm = RB_LEFT(elm, field); \
while (RB_RIGHT(elm, field)) \
elm = RB_RIGHT(elm, field); \
} else { \
if (name##_RB_GETPARENT(elm) && \
(elm == RB_RIGHT(name##_RB_GETPARENT(elm), field))) \
elm = name##_RB_GETPARENT(elm); \
else { \
while (name##_RB_GETPARENT(elm) && \
(elm == RB_LEFT(name##_RB_GETPARENT(elm), field)))\
elm = name##_RB_GETPARENT(elm); \
elm = name##_RB_GETPARENT(elm); \
} \
} \
return (elm); \
} \
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_PREV(name, x, y) name##_RB_PREV(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#define RB_FOREACH_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_REVERSE_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_SAFE(x, name, head, y) \
for ((x) = RB_MIN(name, head); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#endif /* _LIBKERN_TREE_H_ */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,222 @@
/*
* Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1988, 1989, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 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.
*
* @(#)radix.h 8.2 (Berkeley) 10/31/94
* $FreeBSD: src/sys/net/radix.h,v 1.16.2.1 2000/05/03 19:17:11 wollman Exp $
*/
#ifndef _RADIX_H_
#define _RADIX_H_
#include <sys/appleapiopts.h>
#ifdef PRIVATE
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_RTABLE);
#endif
/*
* Radix search tree node layout.
*/
struct radix_node {
struct radix_mask *rn_mklist; /* list of masks contained in subtree */
struct radix_node *rn_parent; /* parent */
short rn_bit; /* bit offset; -1-index(netmask) */
char rn_bmask; /* node: mask for bit test*/
u_char rn_flags; /* enumerated next */
#define RNF_NORMAL 1 /* leaf contains normal route */
#define RNF_ROOT 2 /* leaf is root leaf for tree */
#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */
union {
struct { /* leaf only data: */
caddr_t rn_Key; /* object of search */
caddr_t rn_Mask; /* netmask, if present */
struct radix_node *rn_Dupedkey;
} rn_leaf;
struct { /* node only data: */
int rn_Off; /* where to start compare */
struct radix_node *rn_L;/* progeny */
struct radix_node *rn_R;/* progeny */
} rn_node;
} rn_u;
#ifdef RN_DEBUG
int rn_info;
struct radix_node *rn_twin;
struct radix_node *rn_ybro;
#endif
#if __arm__ && (__BIGGEST_ALIGNMENT__ > 4)
/* For the newer ARMv7k ABI where 64-bit types are 64-bit aligned, but pointers
* are 32-bit:
* Aligned to 64-bit since this is cast to rtentry, which is 64-bit aligned.
*/
} __attribute__ ((aligned(8)));
#else
};
#endif
#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey
#define rn_key rn_u.rn_leaf.rn_Key
#define rn_mask rn_u.rn_leaf.rn_Mask
#define rn_offset rn_u.rn_node.rn_Off
#define rn_left rn_u.rn_node.rn_L
#define rn_right rn_u.rn_node.rn_R
/*
* Annotations to tree concerning potential routes applying to subtrees.
*/
struct radix_mask {
short rm_bit; /* bit offset; -1-index(netmask) */
char rm_unused; /* cf. rn_bmask */
u_char rm_flags; /* cf. rn_flags */
struct radix_mask *rm_mklist; /* more masks to try */
union {
caddr_t rmu_mask; /* the mask */
struct radix_node *rmu_leaf; /* for normal routes */
} rm_rmu;
int rm_refs; /* # of references to this struct */
};
#define rm_mask rm_rmu.rmu_mask
#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */
#define MKGet(m) {\
if (rn_mkfreelist) {\
m = rn_mkfreelist; \
rn_mkfreelist = (m)->rm_mklist; \
} else \
R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\
#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}
typedef int walktree_f_t(struct radix_node *, void *);
typedef int rn_matchf_t(struct radix_node *, void *);
struct radix_node_head {
struct radix_node *rnh_treetop;
int rnh_addrsize; /* permit, but not require fixed keys */
int rnh_pktsize; /* permit, but not require fixed keys */
struct radix_node *(*rnh_addaddr) /* add based on sockaddr */
(void *v, void *mask,
struct radix_node_head *head, struct radix_node nodes[]);
struct radix_node *(*rnh_addpkt) /* add based on packet hdr */
(void *v, void *mask,
struct radix_node_head *head, struct radix_node nodes[]);
struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */
(void *v, void *mask, struct radix_node_head *head);
struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */
(void *v, void *mask, struct radix_node_head *head);
struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */
(void *v, struct radix_node_head *head);
/* locate based on sockaddr and rn_matchf_t() */
struct radix_node *(*rnh_matchaddr_args)
(void *v, struct radix_node_head *head,
rn_matchf_t *f, void *w);
struct radix_node *(*rnh_lookup) /* locate based on sockaddr */
(void *v, void *mask, struct radix_node_head *head);
/* locate based on sockaddr, mask and rn_matchf_t() */
struct radix_node *(*rnh_lookup_args)
(void *v, void *mask, struct radix_node_head *head,
rn_matchf_t *f, void *);
struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */
(void *v, struct radix_node_head *head);
int (*rnh_walktree) /* traverse tree */
(struct radix_node_head *head, walktree_f_t *f, void *w);
int (*rnh_walktree_from) /* traverse tree below a */
(struct radix_node_head *head, void *a, void *m,
walktree_f_t *f, void *w);
void (*rnh_close) /* do something when the last ref drops */
(struct radix_node *rn, struct radix_node_head *head);
struct radix_node rnh_nodes[3]; /* empty tree for common case */
int rnh_cnt; /* tree dimension */
};
#ifndef KERNEL
#define Bcmp(a, b, n) bcmp(((char *)(a)), ((char *)(b)), (n))
#define Bcopy(a, b, n) bcopy(((char *)(a)), ((char *)(b)), (unsigned)(n))
#define Bzero(p, n) bzero((char *)(p), (int)(n));
#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n)))
#define R_Free(p) free((char *)p);
#else
#define Bcmp(a, b, n) bcmp(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n))
#define Bcopy(a, b, n) bcopy(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n))
#define Bzero(p, n) bzero((caddr_t)(p), (unsigned)(n));
#define R_Malloc(p, t, n) (p = (t) _MALLOC((uint32_t)(n), M_RTABLE, M_WAITOK))
#define R_Free(p) FREE((caddr_t)p, M_RTABLE);
#endif /*KERNEL*/
void rn_init(void);
int rn_inithead(void **, int);
int rn_refines(void *, void *);
struct radix_node
*rn_addmask(void *, int, int),
*rn_addroute(void *, void *, struct radix_node_head *,
struct radix_node [2]),
*rn_delete(void *, void *, struct radix_node_head *),
*rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head),
*rn_lookup_args(void *v_arg, void *m_arg, struct radix_node_head *head,
rn_matchf_t *, void *),
*rn_match(void *, struct radix_node_head *),
*rn_match_args(void *, struct radix_node_head *, rn_matchf_t *, void *);
#endif /* PRIVATE */
#endif /* _RADIX_H_ */
Loading…
Cancel
Save