summaryrefslogtreecommitdiffstats
path: root/lib/isc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 18:37:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 18:37:14 +0000
commitea648e70a989cca190cd7403fe892fd2dcc290b4 (patch)
treee2b6b1c647da68b0d4d66082835e256eb30970e8 /lib/isc
parentInitial commit. (diff)
downloadbind9-ea648e70a989cca190cd7403fe892fd2dcc290b4.tar.xz
bind9-ea648e70a989cca190cd7403fe892fd2dcc290b4.zip
Adding upstream version 1:9.11.5.P4+dfsg.upstream/1%9.11.5.P4+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--lib/isc/Atffile5
-rw-r--r--lib/isc/Kyuafile4
-rw-r--r--lib/isc/Makefile.in146
-rw-r--r--lib/isc/aes.c208
-rw-r--r--lib/isc/alpha/Makefile.in17
-rw-r--r--lib/isc/alpha/include/Makefile.in17
-rw-r--r--lib/isc/alpha/include/isc/Makefile.in34
-rw-r--r--lib/isc/alpha/include/isc/atomic.h180
-rw-r--r--lib/isc/api13
-rw-r--r--lib/isc/app_api.c253
-rw-r--r--lib/isc/assertions.c133
-rw-r--r--lib/isc/backtrace-emptytbl.c29
-rw-r--r--lib/isc/backtrace.c290
-rw-r--r--lib/isc/base32.c419
-rw-r--r--lib/isc/base64.c247
-rw-r--r--lib/isc/bind9.c27
-rw-r--r--lib/isc/buffer.c649
-rw-r--r--lib/isc/bufferlist.c57
-rw-r--r--lib/isc/chacha_private.h229
-rw-r--r--lib/isc/commandline.c271
-rw-r--r--lib/isc/counter.c134
-rw-r--r--lib/isc/crc64.c141
-rw-r--r--lib/isc/entropy.c1288
-rw-r--r--lib/isc/error.c100
-rw-r--r--lib/isc/event.c102
-rw-r--r--lib/isc/fsaccess.c99
-rw-r--r--lib/isc/hash.c579
-rw-r--r--lib/isc/heap.c280
-rw-r--r--lib/isc/hex.c195
-rw-r--r--lib/isc/hmacmd5.c423
-rw-r--r--lib/isc/hmacsha.c1575
-rw-r--r--lib/isc/ht.c346
-rw-r--r--lib/isc/httpd.c1273
-rw-r--r--lib/isc/ia64/Makefile.in17
-rw-r--r--lib/isc/ia64/include/Makefile.in17
-rw-r--r--lib/isc/ia64/include/isc/Makefile.in34
-rw-r--r--lib/isc/ia64/include/isc/atomic.h96
-rw-r--r--lib/isc/include/Makefile.in17
-rw-r--r--lib/isc/include/isc/Makefile.in59
-rw-r--r--lib/isc/include/isc/aes.h47
-rw-r--r--lib/isc/include/isc/app.h385
-rw-r--r--lib/isc/include/isc/assertions.h118
-rw-r--r--lib/isc/include/isc/backtrace.h126
-rw-r--r--lib/isc/include/isc/base32.h135
-rw-r--r--lib/isc/include/isc/base64.h92
-rw-r--r--lib/isc/include/isc/bind9.h28
-rw-r--r--lib/isc/include/isc/boolean.h22
-rw-r--r--lib/isc/include/isc/buffer.h1047
-rw-r--r--lib/isc/include/isc/bufferlist.h79
-rw-r--r--lib/isc/include/isc/commandline.h58
-rw-r--r--lib/isc/include/isc/counter.h85
-rw-r--r--lib/isc/include/isc/crc64.h56
-rw-r--r--lib/isc/include/isc/deprecated.h22
-rw-r--r--lib/isc/include/isc/entropy.h309
-rw-r--r--lib/isc/include/isc/errno.h28
-rw-r--r--lib/isc/include/isc/error.h57
-rw-r--r--lib/isc/include/isc/event.h118
-rw-r--r--lib/isc/include/isc/eventclass.h46
-rw-r--r--lib/isc/include/isc/file.h398
-rw-r--r--lib/isc/include/isc/formatcheck.h33
-rw-r--r--lib/isc/include/isc/fsaccess.h173
-rw-r--r--lib/isc/include/isc/hash.h250
-rw-r--r--lib/isc/include/isc/heap.h167
-rw-r--r--lib/isc/include/isc/hex.h91
-rw-r--r--lib/isc/include/isc/hmacmd5.h87
-rw-r--r--lib/isc/include/isc/hmacsha.h185
-rw-r--r--lib/isc/include/isc/ht.h158
-rw-r--r--lib/isc/include/isc/httpd.h85
-rw-r--r--lib/isc/include/isc/int.h41
-rw-r--r--lib/isc/include/isc/interfaceiter.h128
-rw-r--r--lib/isc/include/isc/ipv6.h142
-rw-r--r--lib/isc/include/isc/iterated_hash.h41
-rw-r--r--lib/isc/include/isc/json.h44
-rw-r--r--lib/isc/include/isc/lang.h26
-rw-r--r--lib/isc/include/isc/lex.h442
-rw-r--r--lib/isc/include/isc/lfsr.h125
-rw-r--r--lib/isc/include/isc/lib.h43
-rw-r--r--lib/isc/include/isc/likely.h26
-rw-r--r--lib/isc/include/isc/list.h191
-rw-r--r--lib/isc/include/isc/log.h920
-rw-r--r--lib/isc/include/isc/magic.h36
-rw-r--r--lib/isc/include/isc/md5.h98
-rw-r--r--lib/isc/include/isc/mem.h755
-rw-r--r--lib/isc/include/isc/meminfo.h32
-rw-r--r--lib/isc/include/isc/msgcat.h124
-rw-r--r--lib/isc/include/isc/msgs.h188
-rw-r--r--lib/isc/include/isc/mutexblock.h64
-rw-r--r--lib/isc/include/isc/netaddr.h188
-rw-r--r--lib/isc/include/isc/netscope.h38
-rw-r--r--lib/isc/include/isc/ondestroy.h110
-rw-r--r--lib/isc/include/isc/os.h31
-rw-r--r--lib/isc/include/isc/parseint.h59
-rw-r--r--lib/isc/include/isc/platform.h.in412
-rw-r--r--lib/isc/include/isc/pool.h144
-rw-r--r--lib/isc/include/isc/portset.h137
-rw-r--r--lib/isc/include/isc/print.h102
-rw-r--r--lib/isc/include/isc/queue.h161
-rw-r--r--lib/isc/include/isc/quota.h112
-rw-r--r--lib/isc/include/isc/radix.h232
-rw-r--r--lib/isc/include/isc/random.h124
-rw-r--r--lib/isc/include/isc/ratelimiter.h147
-rw-r--r--lib/isc/include/isc/refcount.h304
-rw-r--r--lib/isc/include/isc/regex.h34
-rw-r--r--lib/isc/include/isc/region.h97
-rw-r--r--lib/isc/include/isc/resource.h90
-rw-r--r--lib/isc/include/isc/result.h115
-rw-r--r--lib/isc/include/isc/resultclass.h44
-rw-r--r--lib/isc/include/isc/rwlock.h148
-rw-r--r--lib/isc/include/isc/safe.h53
-rw-r--r--lib/isc/include/isc/serial.h71
-rw-r--r--lib/isc/include/isc/sha1.h76
-rw-r--r--lib/isc/include/isc/sha2.h159
-rw-r--r--lib/isc/include/isc/sockaddr.h241
-rw-r--r--lib/isc/include/isc/socket.h1272
-rw-r--r--lib/isc/include/isc/stats.h137
-rw-r--r--lib/isc/include/isc/stdatomic.h146
-rw-r--r--lib/isc/include/isc/stdio.h74
-rw-r--r--lib/isc/include/isc/stdlib.h33
-rw-r--r--lib/isc/include/isc/string.h233
-rw-r--r--lib/isc/include/isc/symtab.h137
-rw-r--r--lib/isc/include/isc/task.h827
-rw-r--r--lib/isc/include/isc/taskpool.h152
-rw-r--r--lib/isc/include/isc/timer.h426
-rw-r--r--lib/isc/include/isc/tm.h41
-rw-r--r--lib/isc/include/isc/types.h133
-rw-r--r--lib/isc/include/isc/util.h247
-rw-r--r--lib/isc/include/isc/version.h21
-rw-r--r--lib/isc/include/isc/xml.h35
-rw-r--r--lib/isc/include/pk11/Makefile.in38
-rw-r--r--lib/isc/include/pk11/README.site72
-rw-r--r--lib/isc/include/pk11/constants.h107
-rw-r--r--lib/isc/include/pk11/internal.h40
-rw-r--r--lib/isc/include/pk11/pk11.h302
-rw-r--r--lib/isc/include/pk11/result.h51
-rw-r--r--lib/isc/include/pk11/site.h112
-rw-r--r--lib/isc/include/pkcs11/Makefile.in38
-rw-r--r--lib/isc/include/pkcs11/eddsa.h33
-rw-r--r--lib/isc/include/pkcs11/pkcs11.h264
-rw-r--r--lib/isc/include/pkcs11/pkcs11f.h938
-rw-r--r--lib/isc/include/pkcs11/pkcs11t.h2006
-rw-r--r--lib/isc/inet_aton.c187
-rw-r--r--lib/isc/inet_ntop.c196
-rw-r--r--lib/isc/inet_pton.c204
-rw-r--r--lib/isc/iterated_hash.c42
-rw-r--r--lib/isc/lex.c1051
-rw-r--r--lib/isc/lfsr.c155
-rw-r--r--lib/isc/lib.c97
-rw-r--r--lib/isc/log.c1761
-rw-r--r--lib/isc/md5.c395
-rw-r--r--lib/isc/mem.c3015
-rw-r--r--lib/isc/mips/Makefile.in17
-rw-r--r--lib/isc/mips/include/Makefile.in17
-rw-r--r--lib/isc/mips/include/isc/Makefile.in34
-rw-r--r--lib/isc/mips/include/isc/atomic.h90
-rw-r--r--lib/isc/mutexblock.c51
-rw-r--r--lib/isc/netaddr.c458
-rw-r--r--lib/isc/netscope.c64
-rw-r--r--lib/isc/nls/Makefile.in29
-rw-r--r--lib/isc/nls/msgcat.c121
-rw-r--r--lib/isc/noatomic/Makefile.in17
-rw-r--r--lib/isc/noatomic/include/Makefile.in17
-rw-r--r--lib/isc/noatomic/include/isc/Makefile.in34
-rw-r--r--lib/isc/noatomic/include/isc/atomic.h18
-rw-r--r--lib/isc/nothreads/Makefile.in32
-rw-r--r--lib/isc/nothreads/condition.c17
-rw-r--r--lib/isc/nothreads/include/Makefile.in17
-rw-r--r--lib/isc/nothreads/include/isc/Makefile.in34
-rw-r--r--lib/isc/nothreads/include/isc/condition.h52
-rw-r--r--lib/isc/nothreads/include/isc/mutex.h31
-rw-r--r--lib/isc/nothreads/include/isc/once.h27
-rw-r--r--lib/isc/nothreads/include/isc/thread.h40
-rw-r--r--lib/isc/nothreads/mutex.c18
-rw-r--r--lib/isc/nothreads/thread.c26
-rw-r--r--lib/isc/ondestroy.c79
-rw-r--r--lib/isc/parseint.c73
-rw-r--r--lib/isc/pk11.c1399
-rw-r--r--lib/isc/pk11_result.c95
-rw-r--r--lib/isc/pool.c171
-rw-r--r--lib/isc/portset.c140
-rw-r--r--lib/isc/powerpc/Makefile.in17
-rw-r--r--lib/isc/powerpc/include/Makefile.in17
-rw-r--r--lib/isc/powerpc/include/isc/Makefile.in34
-rw-r--r--lib/isc/powerpc/include/isc/atomic.h193
-rw-r--r--lib/isc/print.c706
-rw-r--r--lib/isc/pthreads/Makefile.in30
-rw-r--r--lib/isc/pthreads/condition.c74
-rw-r--r--lib/isc/pthreads/include/Makefile.in17
-rw-r--r--lib/isc/pthreads/include/isc/Makefile.in34
-rw-r--r--lib/isc/pthreads/include/isc/condition.h58
-rw-r--r--lib/isc/pthreads/include/isc/mutex.h138
-rw-r--r--lib/isc/pthreads/include/isc/once.h43
-rw-r--r--lib/isc/pthreads/include/isc/thread.h63
-rw-r--r--lib/isc/pthreads/mutex.c302
-rw-r--r--lib/isc/pthreads/thread.c103
-rw-r--r--lib/isc/quota.c94
-rw-r--r--lib/isc/radix.c728
-rw-r--r--lib/isc/random.c415
-rw-r--r--lib/isc/ratelimiter.c375
-rw-r--r--lib/isc/refcount.c32
-rw-r--r--lib/isc/regex.c368
-rw-r--r--lib/isc/region.c38
-rw-r--r--lib/isc/result.c312
-rw-r--r--lib/isc/rwlock.c982
-rw-r--r--lib/isc/safe.c83
-rw-r--r--lib/isc/serial.c55
-rw-r--r--lib/isc/sha1.c456
-rw-r--r--lib/isc/sha2.c1767
-rw-r--r--lib/isc/sockaddr.c507
-rw-r--r--lib/isc/socket_api.c400
-rw-r--r--lib/isc/sparc64/Makefile.in17
-rw-r--r--lib/isc/sparc64/include/Makefile.in17
-rw-r--r--lib/isc/sparc64/include/isc/Makefile.in29
-rw-r--r--lib/isc/sparc64/include/isc/atomic.h122
-rw-r--r--lib/isc/stats.c454
-rw-r--r--lib/isc/string.c313
-rw-r--r--lib/isc/strtoul.c117
-rw-r--r--lib/isc/symtab.c303
-rw-r--r--lib/isc/task.c2327
-rw-r--r--lib/isc/task_p.h33
-rw-r--r--lib/isc/taskpool.c182
-rw-r--r--lib/isc/tests/Atffile33
-rw-r--r--lib/isc/tests/Kyuafile32
-rw-r--r--lib/isc/tests/Makefile.in177
-rw-r--r--lib/isc/tests/aes_test.c294
-rw-r--r--lib/isc/tests/atomic_test.c354
-rw-r--r--lib/isc/tests/buffer_test.c203
-rw-r--r--lib/isc/tests/counter_test.c64
-rw-r--r--lib/isc/tests/errno_test.c105
-rw-r--r--lib/isc/tests/file_test.c136
-rw-r--r--lib/isc/tests/hash_test.c2038
-rw-r--r--lib/isc/tests/heap_test.c87
-rw-r--r--lib/isc/tests/ht_test.c362
-rw-r--r--lib/isc/tests/inet_ntop_test.c62
-rw-r--r--lib/isc/tests/isctest.c194
-rw-r--r--lib/isc/tests/isctest.h64
-rw-r--r--lib/isc/tests/lex_test.c111
-rw-r--r--lib/isc/tests/mem_test.c272
-rw-r--r--lib/isc/tests/netaddr_test.c157
-rw-r--r--lib/isc/tests/parse_test.c64
-rw-r--r--lib/isc/tests/pool_test.c179
-rw-r--r--lib/isc/tests/print_test.c184
-rw-r--r--lib/isc/tests/queue_test.c137
-rw-r--r--lib/isc/tests/radix_test.c89
-rw-r--r--lib/isc/tests/random_test.c670
-rw-r--r--lib/isc/tests/regex_test.c1121
-rw-r--r--lib/isc/tests/result_test.c56
-rw-r--r--lib/isc/tests/safe_test.c112
-rw-r--r--lib/isc/tests/sockaddr_test.c166
-rw-r--r--lib/isc/tests/socket_test.c923
-rw-r--r--lib/isc/tests/symtab_test.c140
-rw-r--r--lib/isc/tests/task_test.c1474
-rw-r--r--lib/isc/tests/taskpool_test.c204
-rw-r--r--lib/isc/tests/testdata/file/keep0
-rw-r--r--lib/isc/tests/time_test.c46
-rw-r--r--lib/isc/tests/timer_test.c593
-rw-r--r--lib/isc/timer.c1191
-rw-r--r--lib/isc/timer_p.h25
-rw-r--r--lib/isc/tm.c439
-rw-r--r--lib/isc/unix/Makefile.in44
-rw-r--r--lib/isc/unix/app.c1038
-rw-r--r--lib/isc/unix/dir.c259
-rw-r--r--lib/isc/unix/entropy.c603
-rw-r--r--lib/isc/unix/errno.c24
-rw-r--r--lib/isc/unix/errno2result.c125
-rw-r--r--lib/isc/unix/errno2result.h35
-rw-r--r--lib/isc/unix/file.c781
-rw-r--r--lib/isc/unix/fsaccess.c87
-rw-r--r--lib/isc/unix/ifiter_getifaddrs.c228
-rw-r--r--lib/isc/unix/ifiter_ioctl.c931
-rw-r--r--lib/isc/unix/ifiter_sysctl.c300
-rw-r--r--lib/isc/unix/include/Makefile.in17
-rw-r--r--lib/isc/unix/include/isc/Makefile.in35
-rw-r--r--lib/isc/unix/include/isc/dir.h84
-rw-r--r--lib/isc/unix/include/isc/keyboard.h46
-rw-r--r--lib/isc/unix/include/isc/net.h417
-rw-r--r--lib/isc/unix/include/isc/netdb.h50
-rw-r--r--lib/isc/unix/include/isc/offset.h26
-rw-r--r--lib/isc/unix/include/isc/stat.h46
-rw-r--r--lib/isc/unix/include/isc/stdtime.h57
-rw-r--r--lib/isc/unix/include/isc/strerror.h38
-rw-r--r--lib/isc/unix/include/isc/syslog.h40
-rw-r--r--lib/isc/unix/include/isc/time.h361
-rw-r--r--lib/isc/unix/include/pkcs11/Makefile.in31
-rw-r--r--lib/isc/unix/include/pkcs11/cryptoki.h66
-rw-r--r--lib/isc/unix/interfaceiter.c306
-rw-r--r--lib/isc/unix/ipv6.c20
-rw-r--r--lib/isc/unix/keyboard.c121
-rw-r--r--lib/isc/unix/meminfo.c40
-rw-r--r--lib/isc/unix/net.c913
-rw-r--r--lib/isc/unix/os.c87
-rw-r--r--lib/isc/unix/pk11_api.c681
-rw-r--r--lib/isc/unix/resource.c227
-rw-r--r--lib/isc/unix/socket.c6848
-rw-r--r--lib/isc/unix/socket_p.h26
-rw-r--r--lib/isc/unix/stdio.c151
-rw-r--r--lib/isc/unix/stdtime.c80
-rw-r--r--lib/isc/unix/strerror.c67
-rw-r--r--lib/isc/unix/syslog.c77
-rw-r--r--lib/isc/unix/time.c500
-rw-r--r--lib/isc/version.c21
-rw-r--r--lib/isc/win32/DLLMain.c51
-rw-r--r--lib/isc/win32/Makefile.in34
-rw-r--r--lib/isc/win32/app.c481
-rw-r--r--lib/isc/win32/condition.c255
-rw-r--r--lib/isc/win32/dir.c307
-rw-r--r--lib/isc/win32/entropy.c299
-rw-r--r--lib/isc/win32/errno.c21
-rw-r--r--lib/isc/win32/errno2result.c118
-rw-r--r--lib/isc/win32/errno2result.h35
-rw-r--r--lib/isc/win32/file.c928
-rw-r--r--lib/isc/win32/fsaccess.c365
-rw-r--r--lib/isc/win32/include/Makefile.in17
-rw-r--r--lib/isc/win32/include/isc/Makefile.in30
-rw-r--r--lib/isc/win32/include/isc/atomic.h75
-rw-r--r--lib/isc/win32/include/isc/bind_registry.h43
-rw-r--r--lib/isc/win32/include/isc/bindevt.h84
-rw-r--r--lib/isc/win32/include/isc/condition.h60
-rw-r--r--lib/isc/win32/include/isc/dir.h73
-rw-r--r--lib/isc/win32/include/isc/ipv6.h120
-rw-r--r--lib/isc/win32/include/isc/keyboard.h42
-rw-r--r--lib/isc/win32/include/isc/mutex.h48
-rw-r--r--lib/isc/win32/include/isc/net.h431
-rw-r--r--lib/isc/win32/include/isc/netdb.h47
-rw-r--r--lib/isc/win32/include/isc/ntgroups.h28
-rw-r--r--lib/isc/win32/include/isc/ntpaths.h66
-rw-r--r--lib/isc/win32/include/isc/offset.h24
-rw-r--r--lib/isc/win32/include/isc/once.h36
-rw-r--r--lib/isc/win32/include/isc/platform.h.in157
-rw-r--r--lib/isc/win32/include/isc/stat.h57
-rw-r--r--lib/isc/win32/include/isc/stdtime.h55
-rw-r--r--lib/isc/win32/include/isc/strerror.h35
-rw-r--r--lib/isc/win32/include/isc/syslog.h38
-rw-r--r--lib/isc/win32/include/isc/thread.h98
-rw-r--r--lib/isc/win32/include/isc/time.h357
-rw-r--r--lib/isc/win32/include/isc/win32os.h40
-rw-r--r--lib/isc/win32/include/pkcs11/Makefile.in26
-rw-r--r--lib/isc/win32/include/pkcs11/cryptoki.h66
-rw-r--r--lib/isc/win32/interfaceiter.c543
-rw-r--r--lib/isc/win32/ipv6.c20
-rw-r--r--lib/isc/win32/keyboard.c82
-rw-r--r--lib/isc/win32/libgen.h19
-rw-r--r--lib/isc/win32/libisc.def.exclude42
-rw-r--r--lib/isc/win32/libisc.def.in836
-rw-r--r--lib/isc/win32/libisc.dsp.in949
-rw-r--r--lib/isc/win32/libisc.dsw29
-rw-r--r--lib/isc/win32/libisc.mak.in2398
-rw-r--r--lib/isc/win32/libisc.vcxproj.filters.in675
-rw-r--r--lib/isc/win32/libisc.vcxproj.in530
-rw-r--r--lib/isc/win32/libisc.vcxproj.user3
-rw-r--r--lib/isc/win32/meminfo.c26
-rw-r--r--lib/isc/win32/net.c341
-rw-r--r--lib/isc/win32/netdb.h182
-rw-r--r--lib/isc/win32/ntgroups.c177
-rw-r--r--lib/isc/win32/ntpaths.c157
-rw-r--r--lib/isc/win32/once.c44
-rw-r--r--lib/isc/win32/os.c38
-rw-r--r--lib/isc/win32/pk11_api.c675
-rw-r--r--lib/isc/win32/resource.c65
-rw-r--r--lib/isc/win32/socket.c4277
-rw-r--r--lib/isc/win32/stdio.c150
-rw-r--r--lib/isc/win32/stdtime.c30
-rw-r--r--lib/isc/win32/strerror.c452
-rw-r--r--lib/isc/win32/syslog.c174
-rw-r--r--lib/isc/win32/syslog.h69
-rw-r--r--lib/isc/win32/thread.c89
-rw-r--r--lib/isc/win32/time.c388
-rw-r--r--lib/isc/win32/unistd.h53
-rw-r--r--lib/isc/win32/version.c21
-rw-r--r--lib/isc/win32/win32os.c117
-rw-r--r--lib/isc/x86_32/Makefile.in17
-rw-r--r--lib/isc/x86_32/include/Makefile.in17
-rw-r--r--lib/isc/x86_32/include/isc/Makefile.in34
-rw-r--r--lib/isc/x86_32/include/isc/atomic.h192
-rw-r--r--lib/isc/x86_64/Makefile.in17
-rw-r--r--lib/isc/x86_64/include/Makefile.in17
-rw-r--r--lib/isc/x86_64/include/isc/Makefile.in34
-rw-r--r--lib/isc/x86_64/include/isc/atomic.h139
-rw-r--r--lib/isccc/Makefile.in84
-rw-r--r--lib/isccc/alist.c307
-rw-r--r--lib/isccc/api13
-rw-r--r--lib/isccc/base64.c73
-rw-r--r--lib/isccc/cc.c1084
-rw-r--r--lib/isccc/ccmsg.c230
-rw-r--r--lib/isccc/include/Makefile.in17
-rw-r--r--lib/isccc/include/isccc/Makefile.in39
-rw-r--r--lib/isccc/include/isccc/alist.h81
-rw-r--r--lib/isccc/include/isccc/base64.h78
-rw-r--r--lib/isccc/include/isccc/cc.h129
-rw-r--r--lib/isccc/include/isccc/ccmsg.h143
-rw-r--r--lib/isccc/include/isccc/events.h43
-rw-r--r--lib/isccc/include/isccc/lib.h48
-rw-r--r--lib/isccc/include/isccc/result.h66
-rw-r--r--lib/isccc/include/isccc/sexpr.h118
-rw-r--r--lib/isccc/include/isccc/symtab.h130
-rw-r--r--lib/isccc/include/isccc/symtype.h37
-rw-r--r--lib/isccc/include/isccc/types.h52
-rw-r--r--lib/isccc/include/isccc/util.h220
-rw-r--r--lib/isccc/include/isccc/version.h21
-rw-r--r--lib/isccc/lib.c71
-rw-r--r--lib/isccc/result.c94
-rw-r--r--lib/isccc/sexpr.c301
-rw-r--r--lib/isccc/symtab.c287
-rw-r--r--lib/isccc/version.c21
-rw-r--r--lib/isccc/win32/DLLMain.c50
-rw-r--r--lib/isccc/win32/libisccc.def70
-rw-r--r--lib/isccc/win32/libisccc.dsp.in201
-rw-r--r--lib/isccc/win32/libisccc.dsw29
-rw-r--r--lib/isccc/win32/libisccc.mak.in540
-rw-r--r--lib/isccc/win32/libisccc.vcxproj.filters.in93
-rw-r--r--lib/isccc/win32/libisccc.vcxproj.in141
-rw-r--r--lib/isccc/win32/libisccc.vcxproj.user3
-rw-r--r--lib/isccc/win32/version.c21
-rw-r--r--lib/isccfg/Atffile5
-rw-r--r--lib/isccfg/Kyuafile4
-rw-r--r--lib/isccfg/Makefile.in83
-rw-r--r--lib/isccfg/aclconf.c906
-rw-r--r--lib/isccfg/api13
-rw-r--r--lib/isccfg/dnsconf.c63
-rw-r--r--lib/isccfg/include/Makefile.in17
-rw-r--r--lib/isccfg/include/isccfg/Makefile.in40
-rw-r--r--lib/isccfg/include/isccfg/aclconf.h93
-rw-r--r--lib/isccfg/include/isccfg/cfg.h559
-rw-r--r--lib/isccfg/include/isccfg/dnsconf.h29
-rw-r--r--lib/isccfg/include/isccfg/grammar.h561
-rw-r--r--lib/isccfg/include/isccfg/log.h48
-rw-r--r--lib/isccfg/include/isccfg/namedconf.h56
-rw-r--r--lib/isccfg/include/isccfg/version.h21
-rw-r--r--lib/isccfg/log.c45
-rw-r--r--lib/isccfg/namedconf.c4013
-rw-r--r--lib/isccfg/parser.c3282
-rw-r--r--lib/isccfg/tests/Atffile5
-rw-r--r--lib/isccfg/tests/Kyuafile4
-rw-r--r--lib/isccfg/tests/Makefile.in54
-rw-r--r--lib/isccfg/tests/parser_test.c192
-rw-r--r--lib/isccfg/version.c22
-rw-r--r--lib/isccfg/win32/DLLMain.c53
-rw-r--r--lib/isccfg/win32/libisccfg.def165
-rw-r--r--lib/isccfg/win32/libisccfg.dsp.in169
-rw-r--r--lib/isccfg/win32/libisccfg.dsw29
-rw-r--r--lib/isccfg/win32/libisccfg.mak.in490
-rw-r--r--lib/isccfg/win32/libisccfg.vcxproj.filters.in66
-rw-r--r--lib/isccfg/win32/libisccfg.vcxproj.in132
-rw-r--r--lib/isccfg/win32/libisccfg.vcxproj.user3
-rw-r--r--lib/isccfg/win32/version.c22
444 files changed, 115810 insertions, 0 deletions
diff --git a/lib/isc/Atffile b/lib/isc/Atffile
new file mode 100644
index 0000000..1edb838
--- /dev/null
+++ b/lib/isc/Atffile
@@ -0,0 +1,5 @@
+Content-Type: application/X-atf-atffile; version="1"
+
+prop: test-suite = bind9
+
+tp: tests
diff --git a/lib/isc/Kyuafile b/lib/isc/Kyuafile
new file mode 100644
index 0000000..0739e3a
--- /dev/null
+++ b/lib/isc/Kyuafile
@@ -0,0 +1,4 @@
+syntax(2)
+test_suite('bind9')
+
+include('tests/Kyuafile')
diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in
new file mode 100644
index 0000000..ba53ef1
--- /dev/null
+++ b/lib/isc/Makefile.in
@@ -0,0 +1,146 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+@LIBISC_API@
+
+@BIND9_MAKE_INCLUDES@
+
+PROVIDER = @PKCS11_PROVIDER@
+
+CINCLUDES = -I${srcdir}/unix/include \
+ -I${srcdir}/@ISC_THREAD_DIR@/include \
+ -I${srcdir}/@ISC_ARCH_DIR@/include \
+ -I./include \
+ -I${srcdir}/include ${DNS_INCLUDES} @ISC_OPENSSL_INC@
+CDEFINES = @CRYPTO@ -DPK11_LIB_LOCATION=\"${PROVIDER}\"
+CWARNINGS =
+
+# Alphabetically
+UNIXOBJS = @ISC_ISCIPV6_O@ @ISC_ISCPK11_API_O@ \
+ unix/app.@O@ unix/dir.@O@ unix/entropy.@O@ unix/errno.@O@ \
+ unix/errno2result.@O@ unix/file.@O@ unix/fsaccess.@O@ \
+ unix/interfaceiter.@O@ unix/keyboard.@O@ unix/meminfo.@O@ \
+ unix/net.@O@ unix/os.@O@ unix/resource.@O@ unix/socket.@O@ \
+ unix/stdio.@O@ unix/stdtime.@O@ unix/strerror.@O@ \
+ unix/syslog.@O@ unix/time.@O@
+
+NLSOBJS = nls/msgcat.@O@
+
+THREADOPTOBJS = @ISC_THREAD_DIR@/condition.@O@ @ISC_THREAD_DIR@/mutex.@O@
+
+THREADOBJS = @THREADOPTOBJS@ @ISC_THREAD_DIR@/thread.@O@
+
+WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/errno.@O@ \
+ win32/file.@O@ win32/fsaccess.@O@ \
+ win32/meminfo.@O@ win32/once.@O@ \
+ win32/stdtime.@O@ win32/thread.@O@ win32/time.@O@
+
+# Alphabetically
+OBJS = @ISC_EXTRA_OBJS@ @ISC_PK11_O@ @ISC_PK11_RESULT_O@ \
+ aes.@O@ assertions.@O@ backtrace.@O@ base32.@O@ base64.@O@ \
+ bind9.@O@ buffer.@O@ bufferlist.@O@ \
+ commandline.@O@ counter.@O@ crc64.@O@ error.@O@ event.@O@ \
+ hash.@O@ ht.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ \
+ hmacsha.@O@ httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \
+ lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
+ md5.@O@ mem.@O@ mutexblock.@O@ \
+ netaddr.@O@ netscope.@O@ pool.@O@ ondestroy.@O@ \
+ parseint.@O@ portset.@O@ quota.@O@ radix.@O@ random.@O@ \
+ ratelimiter.@O@ refcount.@O@ region.@O@ regex.@O@ result.@O@ \
+ rwlock.@O@ \
+ safe.@O@ serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ stats.@O@ \
+ string.@O@ strtoul.@O@ symtab.@O@ task.@O@ taskpool.@O@ \
+ tm.@O@ timer.@O@ version.@O@ \
+ ${UNIXOBJS} ${NLSOBJS} ${THREADOBJS}
+SYMTBLOBJS = backtrace-emptytbl.@O@
+
+CHACHASRCS = chacha_private.h
+
+# Alphabetically
+SRCS = @ISC_EXTRA_SRCS@ @ISC_PK11_C@ @ISC_PK11_RESULT_C@ \
+ aes.c assertions.c backtrace.c base32.c base64.c bind9.c \
+ buffer.c bufferlist.c commandline.c counter.c crc64.c \
+ error.c event.c hash.c ht.c heap.c hex.c hmacmd5.c \
+ hmacsha.c httpd.c inet_aton.c iterated_hash.c \
+ lex.c lfsr.c lib.c log.c \
+ md5.c mem.c mutexblock.c \
+ netaddr.c netscope.c pool.c ondestroy.c \
+ parseint.c portset.c quota.c radix.c random.c ${CHACHASRCS} \
+ ratelimiter.c refcount.c region.c regex.c result.c rwlock.c \
+ safe.c serial.c sha1.c sha2.c sockaddr.c stats.c string.c \
+ strtoul.c symtab.c task.c taskpool.c timer.c \
+ tm.c version.c
+
+LIBS = @ISC_OPENSSL_LIBS@ @LIBS@
+
+# Note: the order of SUBDIRS is important.
+# Attempt to disable parallel processing.
+.NOTPARALLEL:
+.NO_PARALLEL:
+SUBDIRS = include unix nls @ISC_THREAD_DIR@ @ISC_ARCH_DIR@
+TARGETS = timestamp
+TESTDIRS = @UNITTESTS@
+
+@BIND9_MAKE_RULES@
+
+safe.@O@: safe.c
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} @CCNOOPT@ \
+ -c ${srcdir}/safe.c
+
+version.@O@: version.c
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \
+ -DVERSION=\"${VERSION}\" \
+ -DLIBINTERFACE=${LIBINTERFACE} \
+ -DLIBREVISION=${LIBREVISION} \
+ -DLIBAGE=${LIBAGE} \
+ -c ${srcdir}/version.c
+
+libisc.@SA@: ${OBJS} ${SYMTBLOBJS}
+ ${AR} ${ARFLAGS} $@ ${OBJS} ${SYMTBLOBJS}
+ ${RANLIB} $@
+
+libisc-nosymtbl.@SA@: ${OBJS}
+ ${AR} ${ARFLAGS} $@ ${OBJS}
+ ${RANLIB} $@
+
+libisc.la: ${OBJS} ${SYMTBLOBJS}
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} ${SYMTBLOBJS} ${LIBS}
+
+libisc-nosymtbl.la: ${OBJS}
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-nosymtbl.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} ${LIBS}
+
+timestamp: libisc.@A@ libisc-nosymtbl.@A@
+ touch timestamp
+
+testdirs: libisc.@A@ libisc-nosymtbl.@A@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+
+install:: timestamp installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_LIBRARY} libisc.@A@ ${DESTDIR}${libdir}
+
+uninstall::
+ ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${libdir}/libisc.@A@
+
+clean distclean::
+ rm -f libisc.@A@ libisc-nosymtbl.@A@ libisc.la \
+ libisc-nosymtbl.la timestamp
diff --git a/lib/isc/aes.c b/lib/isc/aes.c
new file mode 100644
index 0000000..2ca07f6
--- /dev/null
+++ b/lib/isc/aes.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file isc/aes.c */
+
+#include <config.h>
+
+#include <isc/assertions.h>
+#include <isc/aes.h>
+#include <isc/platform.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#ifdef ISC_PLATFORM_WANTAES
+#if HAVE_OPENSSL_EVP_AES
+
+#include <openssl/opensslv.h>
+#include <openssl/evp.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#define EVP_CIPHER_CTX_new() &(_context), EVP_CIPHER_CTX_init(&_context)
+#define EVP_CIPHER_CTX_free(c) RUNTIME_CHECK(EVP_CIPHER_CTX_cleanup(c) == 1)
+#endif
+
+void
+isc_aes128_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ EVP_CIPHER_CTX _context;
+#endif
+ EVP_CIPHER_CTX *c;
+ int len;
+
+ c = EVP_CIPHER_CTX_new();
+ RUNTIME_CHECK(c != NULL);
+ RUNTIME_CHECK(EVP_EncryptInit(c, EVP_aes_128_ecb(), key, NULL) == 1);
+ EVP_CIPHER_CTX_set_padding(c, 0);
+ RUNTIME_CHECK(EVP_EncryptUpdate(c, out, &len, in,
+ ISC_AES_BLOCK_LENGTH) == 1);
+ RUNTIME_CHECK(len == ISC_AES_BLOCK_LENGTH);
+ EVP_CIPHER_CTX_free(c);
+}
+
+void
+isc_aes192_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ EVP_CIPHER_CTX _context;
+#endif
+ EVP_CIPHER_CTX *c;
+ int len;
+
+ c = EVP_CIPHER_CTX_new();
+ RUNTIME_CHECK(c != NULL);
+ RUNTIME_CHECK(EVP_EncryptInit(c, EVP_aes_192_ecb(), key, NULL) == 1);
+ EVP_CIPHER_CTX_set_padding(c, 0);
+ RUNTIME_CHECK(EVP_EncryptUpdate(c, out, &len, in,
+ ISC_AES_BLOCK_LENGTH) == 1);
+ RUNTIME_CHECK(len == ISC_AES_BLOCK_LENGTH);
+ EVP_CIPHER_CTX_free(c);
+}
+
+void
+isc_aes256_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ EVP_CIPHER_CTX _context;
+#endif
+ EVP_CIPHER_CTX *c;
+ int len;
+
+ c = EVP_CIPHER_CTX_new();
+ RUNTIME_CHECK(c != NULL);
+ RUNTIME_CHECK(EVP_EncryptInit(c, EVP_aes_256_ecb(), key, NULL) == 1);
+ EVP_CIPHER_CTX_set_padding(c, 0);
+ RUNTIME_CHECK(EVP_EncryptUpdate(c, out, &len, in,
+ ISC_AES_BLOCK_LENGTH) == 1);
+ RUNTIME_CHECK(len == ISC_AES_BLOCK_LENGTH);
+ EVP_CIPHER_CTX_free(c);
+}
+
+#elif HAVE_OPENSSL_AES
+
+#include <openssl/aes.h>
+
+void
+isc_aes128_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out)
+{
+ AES_KEY k;
+
+ RUNTIME_CHECK(AES_set_encrypt_key(key, 128, &k) == 0);
+ AES_encrypt(in, out, &k);
+}
+
+void
+isc_aes192_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out)
+{
+ AES_KEY k;
+
+ RUNTIME_CHECK(AES_set_encrypt_key(key, 192, &k) == 0);
+ AES_encrypt(in, out, &k);
+}
+
+void
+isc_aes256_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out)
+{
+ AES_KEY k;
+
+ RUNTIME_CHECK(AES_set_encrypt_key(key, 256, &k) == 0);
+ AES_encrypt(in, out, &k);
+}
+
+#elif PKCS11CRYPTO
+
+#include <pk11/pk11.h>
+#include <pk11/internal.h>
+
+static CK_BBOOL truevalue = TRUE;
+static CK_BBOOL falsevalue = FALSE;
+
+static void isc_aes_crypt(const unsigned char *key, CK_ULONG keylen,
+ const unsigned char *in, unsigned char *out);
+
+void
+isc_aes128_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out)
+{
+ isc_aes_crypt(key, ISC_AES128_KEYLENGTH, in, out);
+}
+
+void
+isc_aes192_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out)
+{
+ isc_aes_crypt(key, ISC_AES192_KEYLENGTH, in, out);
+}
+
+void
+isc_aes256_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out)
+{
+ isc_aes_crypt(key, ISC_AES256_KEYLENGTH, in, out);
+}
+
+static void
+isc_aes_crypt(const unsigned char *key, CK_ULONG keylen,
+ const unsigned char *in, unsigned char *out)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_AES_ECB, NULL, 0 };
+ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+ CK_KEY_TYPE keyType = CKK_AES;
+ CK_ATTRIBUTE keyTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_ENCRYPT, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_VALUE, NULL, keylen }
+ };
+ CK_ULONG blocklen;
+ CK_BYTE_PTR pData;
+ pk11_context_t ctx;
+
+ DE_CONST(key, keyTemplate[5].pValue);
+ RUNTIME_CHECK(pk11_get_session(&ctx, OP_AES, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ ctx.object = CK_INVALID_HANDLE;
+ PK11_FATALCHECK(pkcs_C_CreateObject,
+ (ctx.session, keyTemplate,
+ (CK_ULONG) 6, &ctx.object));
+ INSIST(ctx.object != CK_INVALID_HANDLE);
+ PK11_FATALCHECK(pkcs_C_EncryptInit,
+ (ctx.session, &mech, ctx.object));
+
+ DE_CONST(in, pData);
+ blocklen = (CK_ULONG) ISC_AES_BLOCK_LENGTH;
+ PK11_FATALCHECK(pkcs_C_Encrypt,
+ (ctx.session,
+ pData, (CK_ULONG) ISC_AES_BLOCK_LENGTH,
+ out, &blocklen));
+ RUNTIME_CHECK(blocklen == (CK_ULONG) ISC_AES_BLOCK_LENGTH);
+
+ (void) pkcs_C_DestroyObject(ctx.session, ctx.object);
+ ctx.object = CK_INVALID_HANDLE;
+ pk11_return_session(&ctx);
+
+}
+
+#endif
+#endif /* ISC_PLATFORM_WANTAES */
diff --git a/lib/isc/alpha/Makefile.in b/lib/isc/alpha/Makefile.in
new file mode 100644
index 0000000..419cf9f
--- /dev/null
+++ b/lib/isc/alpha/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/alpha/include/Makefile.in b/lib/isc/alpha/include/Makefile.in
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/lib/isc/alpha/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/alpha/include/isc/Makefile.in b/lib/isc/alpha/include/isc/Makefile.in
new file mode 100644
index 0000000..97b6b41
--- /dev/null
+++ b/lib/isc/alpha/include/isc/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
diff --git a/lib/isc/alpha/include/isc/atomic.h b/lib/isc/alpha/include/isc/atomic.h
new file mode 100644
index 0000000..e704fef
--- /dev/null
+++ b/lib/isc/alpha/include/isc/atomic.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * This code was written based on FreeBSD's kernel source whose copyright
+ * follows:
+ */
+
+/*-
+ * Copyright (c) 1998 Doug Rabson
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/sys/alpha/include/atomic.h,v 1.18.6.1 2004/09/13 21:52:04 wilko Exp $
+ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <inttypes.h>
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEOSFASM
+#include <c_asm.h>
+
+#pragma intrinsic(asm)
+
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value. Memory access ordering around this function
+ * can be critical, so we add explicit memory block instructions at the
+ * beginning and the end of it (same for other functions).
+ */
+static inline int32_t
+isc_atomic_xadd(int32_t *p, int32_t val) {
+ return (asm("mb;"
+ "1:"
+ "ldl_l %t0, 0(%a0);" /* load old value */
+ "mov %t0, %v0;" /* copy the old value */
+ "addl %t0, %a1, %t0;" /* calculate new value */
+ "stl_c %t0, 0(%a0);" /* attempt to store */
+ "beq %t0, 1b;" /* spin if failed */
+ "mb;",
+ p, val));
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(int32_t *p, int32_t val) {
+ (void)asm("mb;"
+ "1:"
+ "ldl_l %t0, 0(%a0);" /* load old value */
+ "mov %a1, %t0;" /* value to store */
+ "stl_c %t0, 0(%a0);" /* attempt to store */
+ "beq %t0, 1b;" /* spin if failed */
+ "mb;",
+ p, val);
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+static inline int32_t
+isc_atomic_cmpxchg(int32_t *p, int32_t cmpval, int32_t val) {
+
+ return(asm("mb;"
+ "1:"
+ "ldl_l %t0, 0(%a0);" /* load old value */
+ "mov %t0, %v0;" /* copy the old value */
+ "cmpeq %t0, %a1, %t0;" /* compare */
+ "beq %t0, 2f;" /* exit if not equal */
+ "mov %a2, %t0;" /* value to store */
+ "stl_c %t0, 0(%a0);" /* attempt to store */
+ "beq %t0, 1b;" /* if it failed, spin */
+ "2:"
+ "mb;",
+ p, cmpval, val));
+}
+#elif defined (ISC_PLATFORM_USEGCCASM)
+static inline int32_t
+isc_atomic_xadd(int32_t *p, int32_t val) {
+ int32_t temp, prev;
+
+ __asm__ volatile(
+ "mb;"
+ "1:"
+ "ldl_l %0, %1;" /* load old value */
+ "mov %0, %2;" /* copy the old value */
+ "addl %0, %3, %0;" /* calculate new value */
+ "stl_c %0, %1;" /* attempt to store */
+ "beq %0, 1b;" /* spin if failed */
+ "mb;"
+ : "=&r"(temp), "+m"(*p), "=&r"(prev)
+ : "r"(val)
+ : "memory");
+
+ return (prev);
+}
+
+static inline void
+isc_atomic_store(int32_t *p, int32_t val) {
+ int32_t temp;
+
+ __asm__ volatile(
+ "mb;"
+ "1:"
+ "ldl_l %0, %1;" /* load old value */
+ "mov %2, %0;" /* value to store */
+ "stl_c %0, %1;" /* attempt to store */
+ "beq %0, 1b;" /* if it failed, spin */
+ "mb;"
+ : "=&r"(temp), "+m"(*p)
+ : "r"(val)
+ : "memory");
+}
+
+static inline int32_t
+isc_atomic_cmpxchg(int32_t *p, int32_t cmpval, int32_t val) {
+ int32_t temp, prev;
+
+ __asm__ volatile(
+ "mb;"
+ "1:"
+ "ldl_l %0, %1;" /* load old value */
+ "mov %0, %2;" /* copy the old value */
+ "cmpeq %0, %3, %0;" /* compare */
+ "beq %0, 2f;" /* exit if not equal */
+ "mov %4, %0;" /* value to store */
+ "stl_c %0, %1;" /* attempt to store */
+ "beq %0, 1b;" /* if it failed, spin */
+ "2:"
+ "mb;"
+ : "=&r"(temp), "+m"(*p), "=&r"(prev)
+ : "r"(cmpval), "r"(val)
+ : "memory");
+
+ return (prev);
+}
+#else
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/api b/lib/isc/api
new file mode 100644
index 0000000..7b1b2b1
--- /dev/null
+++ b/lib/isc/api
@@ -0,0 +1,13 @@
+# LIBINTERFACE ranges
+# 9.6: 50-59, 110-119
+# 9.7: 60-79
+# 9.8: 80-89, 120-129
+# 9.9: 90-109, 170-179
+# 9.9-sub: 130-139, 150-159, 200-209
+# 9.10: 140-149, 190-199
+# 9.10-sub: 180-189
+# 9.11: 160-169,1100-1199
+# 9.12: 1200-1299
+LIBINTERFACE = 1100
+LIBREVISION = 0
+LIBAGE = 0
diff --git a/lib/isc/app_api.c b/lib/isc/app_api.c
new file mode 100644
index 0000000..425eb5a
--- /dev/null
+++ b/lib/isc/app_api.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <unistd.h>
+
+#include <isc/app.h>
+#include <isc/magic.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/util.h>
+
+static isc_mutex_t createlock;
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_appctxcreatefunc_t appctx_createfunc = NULL;
+static bool is_running = false;
+
+#define ISCAPI_APPMETHODS_VALID(m) ISC_MAGIC_VALID(m, ISCAPI_APPMETHODS_MAGIC)
+
+static void
+initialize(void) {
+ RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_register(isc_appctxcreatefunc_t createfunc) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
+
+ LOCK(&createlock);
+ if (appctx_createfunc == NULL)
+ appctx_createfunc = createfunc;
+ else
+ result = ISC_R_EXISTS;
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+isc_result_t
+isc_appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) {
+ isc_result_t result;
+
+ if (isc_bind9)
+ return (isc__appctx_create(mctx, ctxp));
+
+ LOCK(&createlock);
+
+ REQUIRE(appctx_createfunc != NULL);
+ result = (*appctx_createfunc)(mctx, ctxp);
+
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+void
+isc_appctx_destroy(isc_appctx_t **ctxp) {
+ REQUIRE(ctxp != NULL && ISCAPI_APPCTX_VALID(*ctxp));
+
+ if (isc_bind9)
+ isc__appctx_destroy(ctxp);
+ else
+ (*ctxp)->methods->ctxdestroy(ctxp);
+
+ ENSURE(*ctxp == NULL);
+}
+
+isc_result_t
+isc_app_ctxstart(isc_appctx_t *ctx) {
+ REQUIRE(ISCAPI_APPCTX_VALID(ctx));
+
+ if (isc_bind9)
+ return (isc__app_ctxstart(ctx));
+
+ return (ctx->methods->ctxstart(ctx));
+}
+
+isc_result_t
+isc_app_ctxrun(isc_appctx_t *ctx) {
+ REQUIRE(ISCAPI_APPCTX_VALID(ctx));
+
+ if (isc_bind9)
+ return (isc__app_ctxrun(ctx));
+
+ return (ctx->methods->ctxrun(ctx));
+}
+
+isc_result_t
+isc_app_ctxonrun(isc_appctx_t *ctx, isc_mem_t *mctx,
+ isc_task_t *task, isc_taskaction_t action,
+ void *arg)
+{
+ REQUIRE(ISCAPI_APPCTX_VALID(ctx));
+
+ if (isc_bind9)
+ return (isc__app_ctxonrun(ctx, mctx, task, action, arg));
+
+ return (ctx->methods->ctxonrun(ctx, mctx, task, action, arg));
+}
+
+isc_result_t
+isc_app_ctxsuspend(isc_appctx_t *ctx) {
+ REQUIRE(ISCAPI_APPCTX_VALID(ctx));
+
+ if (isc_bind9)
+ return (isc__app_ctxsuspend(ctx));
+
+ return (ctx->methods->ctxsuspend(ctx));
+}
+
+isc_result_t
+isc_app_ctxshutdown(isc_appctx_t *ctx) {
+ REQUIRE(ISCAPI_APPCTX_VALID(ctx));
+
+ if (isc_bind9)
+ return (isc__app_ctxshutdown(ctx));
+
+ return (ctx->methods->ctxshutdown(ctx));
+}
+
+void
+isc_app_ctxfinish(isc_appctx_t *ctx) {
+ REQUIRE(ISCAPI_APPCTX_VALID(ctx));
+
+ if (isc_bind9)
+ isc__app_ctxfinish(ctx);
+
+ ctx->methods->ctxfinish(ctx);
+}
+
+void
+isc_appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr) {
+ REQUIRE(ISCAPI_APPCTX_VALID(ctx));
+ REQUIRE(taskmgr != NULL);
+
+ if (isc_bind9)
+ isc__appctx_settaskmgr(ctx, taskmgr);
+
+ ctx->methods->settaskmgr(ctx, taskmgr);
+}
+
+void
+isc_appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr) {
+ REQUIRE(ISCAPI_APPCTX_VALID(ctx));
+ REQUIRE(socketmgr != NULL);
+
+ if (isc_bind9)
+ isc__appctx_setsocketmgr(ctx, socketmgr);
+
+ ctx->methods->setsocketmgr(ctx, socketmgr);
+}
+
+void
+isc_appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr) {
+ REQUIRE(ISCAPI_APPCTX_VALID(ctx));
+ REQUIRE(timermgr != NULL);
+
+ if (isc_bind9)
+ isc__appctx_settimermgr(ctx, timermgr);
+
+ ctx->methods->settimermgr(ctx, timermgr);
+}
+
+isc_result_t
+isc_app_start(void) {
+ if (isc_bind9)
+ return (isc__app_start());
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+isc_result_t
+isc_app_onrun(isc_mem_t *mctx, isc_task_t *task,
+ isc_taskaction_t action, void *arg)
+{
+ if (isc_bind9)
+ return (isc__app_onrun(mctx, task, action, arg));
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+isc_result_t
+isc_app_run() {
+ if (isc_bind9) {
+ isc_result_t result;
+
+ is_running = true;
+ result = isc__app_run();
+ is_running = false;
+
+ return (result);
+ }
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+bool
+isc_app_isrunning() {
+ return (is_running);
+}
+
+isc_result_t
+isc_app_shutdown(void) {
+ if (isc_bind9)
+ return (isc__app_shutdown());
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+isc_result_t
+isc_app_reload(void) {
+ if (isc_bind9)
+ return (isc__app_reload());
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+void
+isc_app_finish(void) {
+ if (!isc_bind9)
+ return;
+
+ isc__app_finish();
+}
+
+void
+isc_app_block(void) {
+ if (!isc_bind9)
+ return;
+
+ isc__app_block();
+}
+
+void
+isc_app_unblock(void) {
+ if (!isc_bind9)
+ return;
+
+ isc__app_unblock();
+}
diff --git a/lib/isc/assertions.c b/lib/isc/assertions.c
new file mode 100644
index 0000000..b52342e
--- /dev/null
+++ b/lib/isc/assertions.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isc/assertions.h>
+#include <isc/backtrace.h>
+#include <isc/msgs.h>
+#include <isc/print.h>
+#include <isc/result.h>
+
+/*
+ * The maximum number of stack frames to dump on assertion failure.
+ */
+#ifndef BACKTRACE_MAXFRAME
+#define BACKTRACE_MAXFRAME 128
+#endif
+
+/*%
+ * Forward.
+ */
+static void
+default_callback(const char *, int, isc_assertiontype_t, const char *);
+
+static isc_assertioncallback_t isc_assertion_failed_cb = default_callback;
+
+/*%
+ * Public.
+ */
+
+/*% assertion failed handler */
+/* coverity[+kill] */
+void
+isc_assertion_failed(const char *file, int line, isc_assertiontype_t type,
+ const char *cond)
+{
+ isc_assertion_failed_cb(file, line, type, cond);
+ abort();
+ /* NOTREACHED */
+}
+
+/*% Set callback. */
+void
+isc_assertion_setcallback(isc_assertioncallback_t cb) {
+ if (cb == NULL)
+ isc_assertion_failed_cb = default_callback;
+ else
+ isc_assertion_failed_cb = cb;
+}
+
+/*% Type to Text */
+const char *
+isc_assertion_typetotext(isc_assertiontype_t type) {
+ const char *result;
+
+ /*
+ * These strings have purposefully not been internationalized
+ * because they are considered to essentially be keywords of
+ * the ISC development environment.
+ */
+ switch (type) {
+ case isc_assertiontype_require:
+ result = "REQUIRE";
+ break;
+ case isc_assertiontype_ensure:
+ result = "ENSURE";
+ break;
+ case isc_assertiontype_insist:
+ result = "INSIST";
+ break;
+ case isc_assertiontype_invariant:
+ result = "INVARIANT";
+ break;
+ default:
+ result = NULL;
+ }
+ return (result);
+}
+
+/*
+ * Private.
+ */
+
+static void
+default_callback(const char *file, int line, isc_assertiontype_t type,
+ const char *cond)
+{
+ void *tracebuf[BACKTRACE_MAXFRAME];
+ int i, nframes;
+ const char *logsuffix = ".";
+ const char *fname;
+ isc_result_t result;
+
+ result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME, &nframes);
+ if (result == ISC_R_SUCCESS && nframes > 0)
+ logsuffix = ", back trace";
+
+ fprintf(stderr, "%s:%d: %s(%s) %s%s\n",
+ file, line, isc_assertion_typetotext(type), cond,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"), logsuffix);
+ if (result == ISC_R_SUCCESS) {
+ for (i = 0; i < nframes; i++) {
+ unsigned long offset;
+
+ fname = NULL;
+ result = isc_backtrace_getsymbol(tracebuf[i], &fname,
+ &offset);
+ if (result == ISC_R_SUCCESS) {
+ fprintf(stderr, "#%d %p in %s()+0x%lx\n", i,
+ tracebuf[i], fname, offset);
+ } else {
+ fprintf(stderr, "#%d %p in ??\n", i,
+ tracebuf[i]);
+ }
+ }
+ }
+ fflush(stderr);
+}
diff --git a/lib/isc/backtrace-emptytbl.c b/lib/isc/backtrace-emptytbl.c
new file mode 100644
index 0000000..5822cfb
--- /dev/null
+++ b/lib/isc/backtrace-emptytbl.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+/*
+ * This file defines an empty (default) symbol table used in backtrace.c
+ * If the application wants to have a complete symbol table, it should redefine
+ * isc__backtrace_symtable with the complete table in some way, and link the
+ * version of the library not including this definition
+ * (e.g. libisc-nosymbol.a).
+ */
+
+#include <config.h>
+
+#include <isc/backtrace.h>
+
+LIBISC_EXTERNAL_DATA const int isc__backtrace_nsymbols = 0;
+LIBISC_EXTERNAL_DATA const
+ isc_backtrace_symmap_t isc__backtrace_symtable[] = { { NULL, "" } };
diff --git a/lib/isc/backtrace.c b/lib/isc/backtrace.c
new file mode 100644
index 0000000..0ea1455
--- /dev/null
+++ b/lib/isc/backtrace.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_LIBCTRACE
+#include <execinfo.h>
+#endif
+
+#include <isc/backtrace.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#ifdef ISC_PLATFORM_USEBACKTRACE
+/*
+ * Getting a back trace of a running process is tricky and highly platform
+ * dependent. Our current approach is as follows:
+ * 1. If the system library supports the "backtrace()" function, use it.
+ * 2. Otherwise, if the compiler is gcc and the architecture is x86_64 or IA64,
+ * then use gcc's (hidden) Unwind_Backtrace() function. Note that this
+ * function doesn't work for C programs on many other architectures.
+ * 3. Otherwise, if the architecture x86 or x86_64, try to unwind the stack
+ * frame following frame pointers. This assumes the executable binary
+ * compiled with frame pointers; this is not always true for x86_64 (rather,
+ * compiler optimizations often disable frame pointers). The validation
+ * checks in getnextframeptr() hopefully rejects bogus values stored in
+ * the RBP register in such a case. If the backtrace function itself crashes
+ * due to this problem, the whole package should be rebuilt with
+ * --disable-backtrace.
+ */
+#ifdef HAVE_LIBCTRACE
+#define BACKTRACE_LIBC
+#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__ia64__))
+#define BACKTRACE_GCC
+#elif defined(WIN32)
+#define BACKTRACE_WIN32
+#elif defined(__x86_64__) || defined(__i386__)
+#define BACKTRACE_X86STACK
+#else
+#define BACKTRACE_DISABLED
+#endif /* HAVE_LIBCTRACE */
+#else /* !ISC_PLATFORM_USEBACKTRACE */
+#define BACKTRACE_DISABLED
+#endif /* ISC_PLATFORM_USEBACKTRACE */
+
+#ifdef BACKTRACE_LIBC
+isc_result_t
+isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
+ int n;
+
+ /*
+ * Validate the arguments: intentionally avoid using REQUIRE().
+ * See notes in backtrace.h.
+ */
+ if (addrs == NULL || nframes == NULL)
+ return (ISC_R_FAILURE);
+
+ /*
+ * backtrace(3) includes this function itself in the address array,
+ * which should be eliminated from the returned sequence.
+ */
+ n = backtrace(addrs, maxaddrs);
+ if (n < 2)
+ return (ISC_R_NOTFOUND);
+ n--;
+ memmove(addrs, &addrs[1], sizeof(void *) * n);
+ *nframes = n;
+ return (ISC_R_SUCCESS);
+}
+#elif defined(BACKTRACE_GCC)
+extern int _Unwind_Backtrace(void* fn, void* a);
+extern void* _Unwind_GetIP(void* ctx);
+
+typedef struct {
+ void **result;
+ int max_depth;
+ int skip_count;
+ int count;
+} trace_arg_t;
+
+static int
+btcallback(void *uc, void *opq) {
+ trace_arg_t *arg = (trace_arg_t *)opq;
+
+ if (arg->skip_count > 0)
+ arg->skip_count--;
+ else
+ arg->result[arg->count++] = (void *)_Unwind_GetIP(uc);
+ if (arg->count == arg->max_depth)
+ return (5); /* _URC_END_OF_STACK */
+
+ return (0); /* _URC_NO_REASON */
+}
+
+isc_result_t
+isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
+ trace_arg_t arg;
+
+ /* Argument validation: see above. */
+ if (addrs == NULL || nframes == NULL)
+ return (ISC_R_FAILURE);
+
+ arg.skip_count = 1;
+ arg.result = addrs;
+ arg.max_depth = maxaddrs;
+ arg.count = 0;
+ _Unwind_Backtrace(btcallback, &arg);
+
+ *nframes = arg.count;
+
+ return (ISC_R_SUCCESS);
+}
+#elif defined(BACKTRACE_WIN32)
+isc_result_t
+isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
+ unsigned long ftc = (unsigned long)maxaddrs;
+
+ *nframes = (int)CaptureStackBackTrace(1, ftc, addrs, NULL);
+ return ISC_R_SUCCESS;
+}
+#elif defined(BACKTRACE_X86STACK)
+#ifdef __x86_64__
+static unsigned long
+getrbp(void) {
+ __asm("movq %rbp, %rax\n");
+}
+#endif
+
+static void **
+getnextframeptr(void **sp) {
+ void **newsp = (void **)*sp;
+
+ /*
+ * Perform sanity check for the new frame pointer, derived from
+ * google glog. This can actually be bogus depending on compiler.
+ */
+
+ /* prohibit the stack frames from growing downwards */
+ if (newsp <= sp)
+ return (NULL);
+
+ /* A heuristics to reject "too large" frame: this actually happened. */
+ if ((char *)newsp - (char *)sp > 100000)
+ return (NULL);
+
+ /*
+ * Not sure if other checks used in glog are needed at this moment.
+ * For our purposes we don't have to consider non-contiguous frames,
+ * for example.
+ */
+
+ return (newsp);
+}
+
+isc_result_t
+isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
+ int i = 0;
+ void **sp;
+
+ /* Argument validation: see above. */
+ if (addrs == NULL || nframes == NULL)
+ return (ISC_R_FAILURE);
+
+#ifdef __x86_64__
+ sp = (void **)getrbp();
+ if (sp == NULL)
+ return (ISC_R_NOTFOUND);
+ /*
+ * sp is the frame ptr of this function itself due to the call to
+ * getrbp(), so need to unwind one frame for consistency.
+ */
+ sp = getnextframeptr(sp);
+#else
+ /*
+ * i386: the frame pointer is stored 2 words below the address for the
+ * first argument. Note that the body of this function cannot be
+ * inlined since it depends on the address of the function argument.
+ */
+ sp = (void **)&addrs - 2;
+#endif
+
+ while (sp != NULL && i < maxaddrs) {
+ addrs[i++] = *(sp + 1);
+ sp = getnextframeptr(sp);
+ }
+
+ *nframes = i;
+
+ return (ISC_R_SUCCESS);
+}
+#elif defined(BACKTRACE_DISABLED)
+isc_result_t
+isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
+ /* Argument validation: see above. */
+ if (addrs == NULL || nframes == NULL)
+ return (ISC_R_FAILURE);
+
+ UNUSED(maxaddrs);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+#endif
+
+isc_result_t
+isc_backtrace_getsymbolfromindex(int idx, const void **addrp,
+ const char **symbolp)
+{
+ REQUIRE(addrp != NULL && *addrp == NULL);
+ REQUIRE(symbolp != NULL && *symbolp == NULL);
+
+ if (idx < 0 || idx >= isc__backtrace_nsymbols)
+ return (ISC_R_RANGE);
+
+ *addrp = isc__backtrace_symtable[idx].addr;
+ *symbolp = isc__backtrace_symtable[idx].symbol;
+ return (ISC_R_SUCCESS);
+}
+
+static int
+symtbl_compare(const void *addr, const void *entryarg) {
+ const isc_backtrace_symmap_t *entry = entryarg;
+ const isc_backtrace_symmap_t *end =
+ &isc__backtrace_symtable[isc__backtrace_nsymbols - 1];
+
+ if (isc__backtrace_nsymbols == 1 || entry == end) {
+ if (addr >= entry->addr) {
+ /*
+ * If addr is equal to or larger than that of the last
+ * entry of the table, we cannot be sure if this is
+ * within a valid range so we consider it valid.
+ */
+ return (0);
+ }
+ return (-1);
+ }
+
+ /* entry + 1 is a valid entry from now on. */
+ if (addr < entry->addr)
+ return (-1);
+ else if (addr >= (entry + 1)->addr)
+ return (1);
+ return (0);
+}
+
+isc_result_t
+isc_backtrace_getsymbol(const void *addr, const char **symbolp,
+ unsigned long *offsetp)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_backtrace_symmap_t *found;
+
+ /*
+ * Validate the arguments: intentionally avoid using REQUIRE().
+ * See notes in backtrace.h.
+ */
+ if (symbolp == NULL || *symbolp != NULL || offsetp == NULL)
+ return (ISC_R_FAILURE);
+
+ if (isc__backtrace_nsymbols < 1)
+ return (ISC_R_NOTFOUND);
+
+ /*
+ * Search the table for the entry that meets:
+ * entry.addr <= addr < next_entry.addr.
+ */
+ found = bsearch(addr, isc__backtrace_symtable, isc__backtrace_nsymbols,
+ sizeof(isc__backtrace_symtable[0]), symtbl_compare);
+ if (found == NULL)
+ result = ISC_R_NOTFOUND;
+ else {
+ *symbolp = found->symbol;
+ *offsetp = (unsigned long) ((const char *)addr -
+ (char *)found->addr);
+ }
+
+ return (result);
+}
diff --git a/lib/isc/base32.c b/lib/isc/base32.c
new file mode 100644
index 0000000..bb8c2e1
--- /dev/null
+++ b/lib/isc/base32.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/base32.h>
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define RETERR(x) do { \
+ isc_result_t _r = (x); \
+ if (_r != ISC_R_SUCCESS) \
+ return (_r); \
+ } while (0)
+
+
+/*@{*/
+/*!
+ * These static functions are also present in lib/dns/rdata.c. I'm not
+ * sure where they should go. -- bwelling
+ */
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target);
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
+
+/*@}*/
+
+static const char base32[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=abcdefghijklmnopqrstuvwxyz234567";
+static const char base32hex[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
+
+static isc_result_t
+base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
+ isc_buffer_t *target, const char base[], char pad)
+{
+ char buf[9];
+ unsigned int loops = 0;
+
+ if (wordlength >= 0 && wordlength < 8)
+ wordlength = 8;
+
+ memset(buf, 0, sizeof(buf));
+ while (source->length > 0) {
+ buf[0] = base[((source->base[0]>>3)&0x1f)]; /* 5 + */
+ if (source->length == 1) {
+ buf[1] = base[(source->base[0]<<2)&0x1c];
+ buf[2] = buf[3] = buf[4] = pad;
+ buf[5] = buf[6] = buf[7] = pad;
+ RETERR(str_totext(buf, target));
+ break;
+ }
+ buf[1] = base[((source->base[0]<<2)&0x1c)| /* 3 = 8 */
+ ((source->base[1]>>6)&0x03)]; /* 2 + */
+ buf[2] = base[((source->base[1]>>1)&0x1f)]; /* 5 + */
+ if (source->length == 2) {
+ buf[3] = base[(source->base[1]<<4)&0x10];
+ buf[4] = buf[5] = buf[6] = buf[7] = pad;
+ RETERR(str_totext(buf, target));
+ break;
+ }
+ buf[3] = base[((source->base[1]<<4)&0x10)| /* 1 = 8 */
+ ((source->base[2]>>4)&0x0f)]; /* 4 + */
+ if (source->length == 3) {
+ buf[4] = base[(source->base[2]<<1)&0x1e];
+ buf[5] = buf[6] = buf[7] = pad;
+ RETERR(str_totext(buf, target));
+ break;
+ }
+ buf[4] = base[((source->base[2]<<1)&0x1e)| /* 4 = 8 */
+ ((source->base[3]>>7)&0x01)]; /* 1 + */
+ buf[5] = base[((source->base[3]>>2)&0x1f)]; /* 5 + */
+ if (source->length == 4) {
+ buf[6] = base[(source->base[3]<<3)&0x18];
+ buf[7] = pad;
+ RETERR(str_totext(buf, target));
+ break;
+ }
+ buf[6] = base[((source->base[3]<<3)&0x18)| /* 2 = 8 */
+ ((source->base[4]>>5)&0x07)]; /* 3 + */
+ buf[7] = base[source->base[4]&0x1f]; /* 5 = 8 */
+ RETERR(str_totext(buf, target));
+ isc_region_consume(source, 5);
+
+ loops++;
+ if (source->length != 0 && wordlength >= 0 &&
+ (int)((loops + 1) * 8) >= wordlength)
+ {
+ loops = 0;
+ RETERR(str_totext(wordbreak, target));
+ }
+ }
+ if (source->length > 0)
+ isc_region_consume(source, source->length);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base32_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target)
+{
+ return (base32_totext(source, wordlength, wordbreak, target,
+ base32, '='));
+}
+
+isc_result_t
+isc_base32hex_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target)
+{
+ return (base32_totext(source, wordlength, wordbreak, target,
+ base32hex, '='));
+}
+
+isc_result_t
+isc_base32hexnp_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target)
+{
+ return (base32_totext(source, wordlength, wordbreak, target,
+ base32hex, 0));
+}
+
+/*%
+ * State of a base32 decoding process in progress.
+ */
+typedef struct {
+ int length; /*%< Desired length of binary data or -1 */
+ isc_buffer_t *target; /*%< Buffer for resulting binary data */
+ int digits; /*%< Number of buffered base32 digits */
+ bool seen_end; /*%< True if "=" end marker seen */
+ int val[8];
+ const char *base; /*%< Which encoding we are using */
+ int seen_32; /*%< Number of significant bytes if non zero */
+ bool pad; /*%< Expect padding */
+} base32_decode_ctx_t;
+
+static inline void
+base32_decode_init(base32_decode_ctx_t *ctx, int length, const char base[],
+ bool pad, isc_buffer_t *target)
+{
+ ctx->digits = 0;
+ ctx->seen_end = false;
+ ctx->seen_32 = 0;
+ ctx->length = length;
+ ctx->target = target;
+ ctx->base = base;
+ ctx->pad = pad;
+}
+
+static inline isc_result_t
+base32_decode_char(base32_decode_ctx_t *ctx, int c) {
+ const char *s;
+ unsigned int last;
+
+ if (ctx->seen_end)
+ return (ISC_R_BADBASE32);
+ if ((s = strchr(ctx->base, c)) == NULL)
+ return (ISC_R_BADBASE32);
+ last = (unsigned int)(s - ctx->base);
+
+ /*
+ * Handle lower case.
+ */
+ if (last > 32)
+ last -= 33;
+
+ /*
+ * Check that padding is contiguous.
+ */
+ if (last != 32 && ctx->seen_32 != 0)
+ return (ISC_R_BADBASE32);
+
+ /*
+ * If padding is not permitted flag padding as a error.
+ */
+ if (last == 32 && !ctx->pad)
+ return (ISC_R_BADBASE32);
+
+ /*
+ * Check that padding starts at the right place and that
+ * bits that should be zero are.
+ * Record how many significant bytes in answer (seen_32).
+ */
+ if (last == 32 && ctx->seen_32 == 0)
+ switch (ctx->digits) {
+ case 0:
+ case 1:
+ return (ISC_R_BADBASE32);
+ case 2:
+ if ((ctx->val[1]&0x03) != 0)
+ return (ISC_R_BADBASE32);
+ ctx->seen_32 = 1;
+ break;
+ case 3:
+ return (ISC_R_BADBASE32);
+ case 4:
+ if ((ctx->val[3]&0x0f) != 0)
+ return (ISC_R_BADBASE32);
+ ctx->seen_32 = 3;
+ break;
+ case 5:
+ if ((ctx->val[4]&0x01) != 0)
+ return (ISC_R_BADBASE32);
+ ctx->seen_32 = 3;
+ break;
+ case 6:
+ return (ISC_R_BADBASE32);
+ case 7:
+ if ((ctx->val[6]&0x07) != 0)
+ return (ISC_R_BADBASE32);
+ ctx->seen_32 = 4;
+ break;
+ }
+
+ /*
+ * Zero fill pad values.
+ */
+ ctx->val[ctx->digits++] = (last == 32) ? 0 : last;
+
+ if (ctx->digits == 8) {
+ int n = 5;
+ unsigned char buf[5];
+
+ if (ctx->seen_32 != 0) {
+ ctx->seen_end = true;
+ n = ctx->seen_32;
+ }
+ buf[0] = (ctx->val[0]<<3)|(ctx->val[1]>>2);
+ buf[1] = (ctx->val[1]<<6)|(ctx->val[2]<<1)|(ctx->val[3]>>4);
+ buf[2] = (ctx->val[3]<<4)|(ctx->val[4]>>1);
+ buf[3] = (ctx->val[4]<<7)|(ctx->val[5]<<2)|(ctx->val[6]>>3);
+ buf[4] = (ctx->val[6]<<5)|(ctx->val[7]);
+ RETERR(mem_tobuffer(ctx->target, buf, n));
+ if (ctx->length >= 0) {
+ if (n > ctx->length)
+ return (ISC_R_BADBASE32);
+ else
+ ctx->length -= n;
+ }
+ ctx->digits = 0;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+base32_decode_finish(base32_decode_ctx_t *ctx) {
+
+ if (ctx->length > 0)
+ return (ISC_R_UNEXPECTEDEND);
+ /*
+ * Add missing padding if required.
+ */
+ if (!ctx->pad && ctx->digits != 0) {
+ ctx->pad = true;
+ do {
+ RETERR(base32_decode_char(ctx, '='));
+ } while (ctx->digits != 0);
+ }
+ if (ctx->digits != 0)
+ return (ISC_R_BADBASE32);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+base32_tobuffer(isc_lex_t *lexer, const char base[], bool pad,
+ isc_buffer_t *target, int length)
+{
+ base32_decode_ctx_t ctx;
+ isc_textregion_t *tr;
+ isc_token_t token;
+ bool eol;
+
+ base32_decode_init(&ctx, length, base, pad, target);
+
+ while (!ctx.seen_end && (ctx.length != 0)) {
+ unsigned int i;
+
+ if (length > 0)
+ eol = false;
+ else
+ eol = true;
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string, eol));
+ if (token.type != isc_tokentype_string)
+ break;
+ tr = &token.value.as_textregion;
+ for (i = 0; i < tr->length; i++)
+ RETERR(base32_decode_char(&ctx, tr->base[i]));
+ }
+ if (ctx.length < 0 && !ctx.seen_end)
+ isc_lex_ungettoken(lexer, &token);
+ RETERR(base32_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+ return (base32_tobuffer(lexer, base32, true, target, length));
+}
+
+isc_result_t
+isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+ return (base32_tobuffer(lexer, base32hex, true, target, length));
+}
+
+isc_result_t
+isc_base32hexnp_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+ return (base32_tobuffer(lexer, base32hex, false, target, length));
+}
+
+static isc_result_t
+base32_decodestring(const char *cstr, const char base[], bool pad,
+ isc_buffer_t *target)
+{
+ base32_decode_ctx_t ctx;
+
+ base32_decode_init(&ctx, -1, base, pad, target);
+ for (;;) {
+ int c = *cstr++;
+ if (c == '\0')
+ break;
+ if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
+ continue;
+ RETERR(base32_decode_char(&ctx, c));
+ }
+ RETERR(base32_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base32_decodestring(const char *cstr, isc_buffer_t *target) {
+ return (base32_decodestring(cstr, base32, true, target));
+}
+
+isc_result_t
+isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) {
+ return (base32_decodestring(cstr, base32hex, true, target));
+}
+
+isc_result_t
+isc_base32hexnp_decodestring(const char *cstr, isc_buffer_t *target) {
+ return (base32_decodestring(cstr, base32hex, false, target));
+}
+
+static isc_result_t
+base32_decoderegion(isc_region_t *source, const char base[],
+ bool pad, isc_buffer_t *target)
+{
+ base32_decode_ctx_t ctx;
+
+ base32_decode_init(&ctx, -1, base, pad, target);
+ while (source->length != 0) {
+ int c = *source->base;
+ RETERR(base32_decode_char(&ctx, c));
+ isc_region_consume(source, 1);
+ }
+ RETERR(base32_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) {
+ return (base32_decoderegion(source, base32, true, target));
+}
+
+isc_result_t
+isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) {
+ return (base32_decoderegion(source, base32hex, true, target));
+}
+
+isc_result_t
+isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target) {
+ return (base32_decoderegion(source, base32hex, false, target));
+}
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+ unsigned int l;
+ isc_region_t region;
+
+ isc_buffer_availableregion(target, &region);
+ l = strlen(source);
+
+ if (l > region.length)
+ return (ISC_R_NOSPACE);
+
+ memmove(region.base, source, l);
+ isc_buffer_add(target, l);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
+ isc_region_t tr;
+
+ isc_buffer_availableregion(target, &tr);
+ if (length > tr.length)
+ return (ISC_R_NOSPACE);
+ memmove(tr.base, base, length);
+ isc_buffer_add(target, length);
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/base64.c b/lib/isc/base64.c
new file mode 100644
index 0000000..c7a1722
--- /dev/null
+++ b/lib/isc/base64.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/base64.h>
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define RETERR(x) do { \
+ isc_result_t _r = (x); \
+ if (_r != ISC_R_SUCCESS) \
+ return (_r); \
+ } while (0)
+
+
+/*@{*/
+/*!
+ * These static functions are also present in lib/dns/rdata.c. I'm not
+ * sure where they should go. -- bwelling
+ */
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target);
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
+
+static const char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+/*@}*/
+
+isc_result_t
+isc_base64_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target)
+{
+ char buf[5];
+ unsigned int loops = 0;
+
+ if (wordlength < 4)
+ wordlength = 4;
+
+ memset(buf, 0, sizeof(buf));
+ while (source->length > 2) {
+ buf[0] = base64[(source->base[0]>>2)&0x3f];
+ buf[1] = base64[((source->base[0]<<4)&0x30)|
+ ((source->base[1]>>4)&0x0f)];
+ buf[2] = base64[((source->base[1]<<2)&0x3c)|
+ ((source->base[2]>>6)&0x03)];
+ buf[3] = base64[source->base[2]&0x3f];
+ RETERR(str_totext(buf, target));
+ isc_region_consume(source, 3);
+
+ loops++;
+ if (source->length != 0 &&
+ (int)((loops + 1) * 4) >= wordlength)
+ {
+ loops = 0;
+ RETERR(str_totext(wordbreak, target));
+ }
+ }
+ if (source->length == 2) {
+ buf[0] = base64[(source->base[0]>>2)&0x3f];
+ buf[1] = base64[((source->base[0]<<4)&0x30)|
+ ((source->base[1]>>4)&0x0f)];
+ buf[2] = base64[((source->base[1]<<2)&0x3c)];
+ buf[3] = '=';
+ RETERR(str_totext(buf, target));
+ isc_region_consume(source, 2);
+ } else if (source->length == 1) {
+ buf[0] = base64[(source->base[0]>>2)&0x3f];
+ buf[1] = base64[((source->base[0]<<4)&0x30)];
+ buf[2] = buf[3] = '=';
+ RETERR(str_totext(buf, target));
+ isc_region_consume(source, 1);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * State of a base64 decoding process in progress.
+ */
+typedef struct {
+ int length; /*%< Desired length of binary data or -1 */
+ isc_buffer_t *target; /*%< Buffer for resulting binary data */
+ int digits; /*%< Number of buffered base64 digits */
+ bool seen_end; /*%< True if "=" end marker seen */
+ int val[4];
+} base64_decode_ctx_t;
+
+static inline void
+base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target)
+{
+ ctx->digits = 0;
+ ctx->seen_end = false;
+ ctx->length = length;
+ ctx->target = target;
+}
+
+static inline isc_result_t
+base64_decode_char(base64_decode_ctx_t *ctx, int c) {
+ const char *s;
+
+ if (ctx->seen_end)
+ return (ISC_R_BADBASE64);
+ if ((s = strchr(base64, c)) == NULL)
+ return (ISC_R_BADBASE64);
+ ctx->val[ctx->digits++] = (int)(s - base64);
+ if (ctx->digits == 4) {
+ int n;
+ unsigned char buf[3];
+ if (ctx->val[0] == 64 || ctx->val[1] == 64)
+ return (ISC_R_BADBASE64);
+ if (ctx->val[2] == 64 && ctx->val[3] != 64)
+ return (ISC_R_BADBASE64);
+ /*
+ * Check that bits that should be zero are.
+ */
+ if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0)
+ return (ISC_R_BADBASE64);
+ /*
+ * We don't need to test for ctx->val[2] != 64 as
+ * the bottom two bits of 64 are zero.
+ */
+ if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0)
+ return (ISC_R_BADBASE64);
+ n = (ctx->val[2] == 64) ? 1 :
+ (ctx->val[3] == 64) ? 2 : 3;
+ if (n != 3) {
+ ctx->seen_end = true;
+ if (ctx->val[2] == 64)
+ ctx->val[2] = 0;
+ if (ctx->val[3] == 64)
+ ctx->val[3] = 0;
+ }
+ buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4);
+ buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2);
+ buf[2] = (ctx->val[2]<<6)|(ctx->val[3]);
+ RETERR(mem_tobuffer(ctx->target, buf, n));
+ if (ctx->length >= 0) {
+ if (n > ctx->length)
+ return (ISC_R_BADBASE64);
+ else
+ ctx->length -= n;
+ }
+ ctx->digits = 0;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+base64_decode_finish(base64_decode_ctx_t *ctx) {
+ if (ctx->length > 0)
+ return (ISC_R_UNEXPECTEDEND);
+ if (ctx->digits != 0)
+ return (ISC_R_BADBASE64);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+ base64_decode_ctx_t ctx;
+ isc_textregion_t *tr;
+ isc_token_t token;
+ bool eol;
+
+ base64_decode_init(&ctx, length, target);
+
+ while (!ctx.seen_end && (ctx.length != 0)) {
+ unsigned int i;
+
+ if (length > 0)
+ eol = false;
+ else
+ eol = true;
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string, eol));
+ if (token.type != isc_tokentype_string)
+ break;
+ tr = &token.value.as_textregion;
+ for (i = 0; i < tr->length; i++)
+ RETERR(base64_decode_char(&ctx, tr->base[i]));
+ }
+ if (ctx.length < 0 && !ctx.seen_end)
+ isc_lex_ungettoken(lexer, &token);
+ RETERR(base64_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base64_decodestring(const char *cstr, isc_buffer_t *target) {
+ base64_decode_ctx_t ctx;
+
+ base64_decode_init(&ctx, -1, target);
+ for (;;) {
+ int c = *cstr++;
+ if (c == '\0')
+ break;
+ if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
+ continue;
+ RETERR(base64_decode_char(&ctx, c));
+ }
+ RETERR(base64_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+ unsigned int l;
+ isc_region_t region;
+
+ isc_buffer_availableregion(target, &region);
+ l = strlen(source);
+
+ if (l > region.length)
+ return (ISC_R_NOSPACE);
+
+ memmove(region.base, source, l);
+ isc_buffer_add(target, l);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
+ isc_region_t tr;
+
+ isc_buffer_availableregion(target, &tr);
+ if (length > tr.length)
+ return (ISC_R_NOSPACE);
+ memmove(tr.base, base, length);
+ isc_buffer_add(target, length);
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/bind9.c b/lib/isc/bind9.c
new file mode 100644
index 0000000..e5b2fef
--- /dev/null
+++ b/lib/isc/bind9.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/bind9.h>
+
+/*
+ * This determines whether we are using the libisc/libdns libraries
+ * in BIND9 or in some other application. It is initialized to true
+ * and remains unchanged for BIND9 and related tools; export library
+ * clients will run isc_lib_register(), which sets it to false,
+ * overriding certain BIND9 behaviors.
+ */
+LIBISC_EXTERNAL_DATA bool isc_bind9 = true;
diff --git a/lib/isc/buffer.c b/lib/isc/buffer.c
new file mode 100644
index 0000000..9de1e06
--- /dev/null
+++ b/lib/isc/buffer.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include <isc/buffer.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+void
+isc__buffer_init(isc_buffer_t *b, void *base, unsigned int length) {
+ /*
+ * Make 'b' refer to the 'length'-byte region starting at 'base'.
+ * XXXDCL see the comment in buffer.h about base being const.
+ */
+
+ REQUIRE(b != NULL);
+
+ ISC__BUFFER_INIT(b, base, length);
+}
+
+void
+isc__buffer_initnull(isc_buffer_t *b) {
+ /*
+ * Initialize a new buffer which has no backing store. This can
+ * later be grown as needed and swapped in place.
+ */
+
+ ISC__BUFFER_INIT(b, NULL, 0);
+}
+
+void
+isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length) {
+ /*
+ * Re-initialize the buffer enough to reconfigure the base of the
+ * buffer. We will swap in the new buffer, after copying any
+ * data we contain into the new buffer and adjusting all of our
+ * internal pointers.
+ *
+ * The buffer must not be smaller than the length of the original
+ * buffer.
+ */
+ REQUIRE(b->length <= length);
+ REQUIRE(base != NULL);
+ REQUIRE(!b->autore);
+
+ if (b->length > 0U) {
+ (void)memmove(base, b->base, b->length);
+ }
+
+ b->base = base;
+ b->length = length;
+}
+
+void
+isc__buffer_invalidate(isc_buffer_t *b) {
+ /*
+ * Make 'b' an invalid buffer.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(!ISC_LINK_LINKED(b, link));
+ REQUIRE(b->mctx == NULL);
+
+ ISC__BUFFER_INVALIDATE(b);
+}
+
+void
+isc_buffer_setautorealloc(isc_buffer_t *b, bool enable) {
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->mctx != NULL);
+ b->autore = enable;
+}
+
+void
+isc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_REGION(b, r);
+}
+
+void
+isc__buffer_usedregion(const isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the used region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_USEDREGION(b, r);
+}
+
+void
+isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the available region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_AVAILABLEREGION(b, r);
+}
+
+void
+isc__buffer_add(isc_buffer_t *b, unsigned int n) {
+ /*
+ * Increase the 'used' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used + n <= b->length);
+
+ ISC__BUFFER_ADD(b, n);
+}
+
+void
+isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
+ /*
+ * Decrease the 'used' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used >= n);
+
+ ISC__BUFFER_SUBTRACT(b, n);
+}
+
+void
+isc__buffer_clear(isc_buffer_t *b) {
+ /*
+ * Make the used region empty.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+
+ ISC__BUFFER_CLEAR(b);
+}
+
+void
+isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the consumed region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_CONSUMEDREGION(b, r);
+}
+
+void
+isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the remaining region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_REMAININGREGION(b, r);
+}
+
+void
+isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the active region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_ACTIVEREGION(b, r);
+}
+
+void
+isc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
+ /*
+ * Sets the end of the active region 'n' bytes after current.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->current + n <= b->used);
+
+ ISC__BUFFER_SETACTIVE(b, n);
+}
+
+void
+isc__buffer_first(isc_buffer_t *b) {
+ /*
+ * Make the consumed region empty.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+
+ ISC__BUFFER_FIRST(b);
+}
+
+void
+isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
+ /*
+ * Increase the 'consumed' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->current + n <= b->used);
+
+ ISC__BUFFER_FORWARD(b, n);
+}
+
+void
+isc__buffer_back(isc_buffer_t *b, unsigned int n) {
+ /*
+ * Decrease the 'consumed' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(n <= b->current);
+
+ ISC__BUFFER_BACK(b, n);
+}
+
+void
+isc_buffer_compact(isc_buffer_t *b) {
+ unsigned int length;
+ void *src;
+
+ /*
+ * Compact the used region by moving the remaining region so it occurs
+ * at the start of the buffer. The used region is shrunk by the size
+ * of the consumed region, and the consumed region is then made empty.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+
+ src = isc_buffer_current(b);
+ length = isc_buffer_remaininglength(b);
+ if (length > 0U) {
+ (void)memmove(b->base, src, (size_t)length);
+ }
+
+ if (b->active > b->current)
+ b->active -= b->current;
+ else
+ b->active = 0;
+ b->current = 0;
+ b->used = length;
+}
+
+uint8_t
+isc_buffer_getuint8(isc_buffer_t *b) {
+ unsigned char *cp;
+ uint8_t result;
+
+ /*
+ * Read an unsigned 8-bit integer from 'b' and return it.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 1);
+
+ cp = isc_buffer_current(b);
+ b->current += 1;
+ result = ((uint8_t)(cp[0]));
+
+ return (result);
+}
+
+void
+isc__buffer_putuint8(isc_buffer_t *b, uint8_t val) {
+ isc_result_t result;
+ REQUIRE(ISC_BUFFER_VALID(b));
+ if (ISC_UNLIKELY(b->autore)) {
+ result = isc_buffer_reserve(&b, 1);
+ REQUIRE(result == ISC_R_SUCCESS);
+ }
+ REQUIRE(isc_buffer_availablelength(b) >= 1);
+
+ ISC__BUFFER_PUTUINT8(b, val);
+}
+
+uint16_t
+isc_buffer_getuint16(isc_buffer_t *b) {
+ unsigned char *cp;
+ uint16_t result;
+
+ /*
+ * Read an unsigned 16-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 2);
+
+ cp = isc_buffer_current(b);
+ b->current += 2;
+ result = ((unsigned int)(cp[0])) << 8;
+ result |= ((unsigned int)(cp[1]));
+
+ return (result);
+}
+
+void
+isc__buffer_putuint16(isc_buffer_t *b, uint16_t val) {
+ isc_result_t result;
+ REQUIRE(ISC_BUFFER_VALID(b));
+ if (ISC_UNLIKELY(b->autore)) {
+ result = isc_buffer_reserve(&b, 2);
+ REQUIRE(result == ISC_R_SUCCESS);
+ }
+ REQUIRE(isc_buffer_availablelength(b) >= 2);
+
+ ISC__BUFFER_PUTUINT16(b, val);
+}
+
+void
+isc__buffer_putuint24(isc_buffer_t *b, uint32_t val) {
+ isc_result_t result;
+ REQUIRE(ISC_BUFFER_VALID(b));
+ if (ISC_UNLIKELY(b->autore)) {
+ result = isc_buffer_reserve(&b, 3);
+ REQUIRE(result == ISC_R_SUCCESS);
+ }
+ REQUIRE(isc_buffer_availablelength(b) >= 3);
+
+ ISC__BUFFER_PUTUINT24(b, val);
+}
+
+uint32_t
+isc_buffer_getuint32(isc_buffer_t *b) {
+ unsigned char *cp;
+ uint32_t result;
+
+ /*
+ * Read an unsigned 32-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 4);
+
+ cp = isc_buffer_current(b);
+ b->current += 4;
+ result = ((unsigned int)(cp[0])) << 24;
+ result |= ((unsigned int)(cp[1])) << 16;
+ result |= ((unsigned int)(cp[2])) << 8;
+ result |= ((unsigned int)(cp[3]));
+
+ return (result);
+}
+
+void
+isc__buffer_putuint32(isc_buffer_t *b, uint32_t val) {
+ isc_result_t result;
+ REQUIRE(ISC_BUFFER_VALID(b));
+ if (ISC_UNLIKELY(b->autore)) {
+ result = isc_buffer_reserve(&b, 4);
+ REQUIRE(result == ISC_R_SUCCESS);
+ }
+ REQUIRE(isc_buffer_availablelength(b) >= 4);
+
+ ISC__BUFFER_PUTUINT32(b, val);
+}
+
+uint64_t
+isc_buffer_getuint48(isc_buffer_t *b) {
+ unsigned char *cp;
+ uint64_t result;
+
+ /*
+ * Read an unsigned 48-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 6);
+
+ cp = isc_buffer_current(b);
+ b->current += 6;
+ result = ((int64_t)(cp[0])) << 40;
+ result |= ((int64_t)(cp[1])) << 32;
+ result |= ((int64_t)(cp[2])) << 24;
+ result |= ((int64_t)(cp[3])) << 16;
+ result |= ((int64_t)(cp[4])) << 8;
+ result |= ((int64_t)(cp[5]));
+
+ return (result);
+}
+
+void
+isc__buffer_putuint48(isc_buffer_t *b, uint64_t val) {
+ isc_result_t result;
+ uint16_t valhi;
+ uint32_t vallo;
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ if (ISC_UNLIKELY(b->autore)) {
+ result = isc_buffer_reserve(&b, 6);
+ REQUIRE(result == ISC_R_SUCCESS);
+ }
+ REQUIRE(isc_buffer_availablelength(b) >= 6);
+
+ valhi = (uint16_t)(val >> 32);
+ vallo = (uint32_t)(val & 0xFFFFFFFF);
+ ISC__BUFFER_PUTUINT16(b, valhi);
+ ISC__BUFFER_PUTUINT32(b, vallo);
+}
+
+void
+isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
+ unsigned int length)
+{
+ isc_result_t result;
+ REQUIRE(ISC_BUFFER_VALID(b));
+ if (ISC_UNLIKELY(b->autore)) {
+ result = isc_buffer_reserve(&b, length);
+ REQUIRE(result == ISC_R_SUCCESS);
+ }
+ REQUIRE(isc_buffer_availablelength(b) >= length);
+
+ ISC__BUFFER_PUTMEM(b, base, length);
+}
+
+void
+isc__buffer_putstr(isc_buffer_t *b, const char *source) {
+ unsigned int l;
+ unsigned char *cp;
+ isc_result_t result;
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(source != NULL);
+
+ /*
+ * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
+ */
+ l = strlen(source);
+ if (ISC_UNLIKELY(b->autore)) {
+ result = isc_buffer_reserve(&b, l);
+ REQUIRE(result == ISC_R_SUCCESS);
+ }
+ REQUIRE(isc_buffer_availablelength(b) >= l);
+
+ cp = isc_buffer_used(b);
+ memmove(cp, source, l);
+ b->used += l;
+}
+
+void
+isc_buffer_putdecint(isc_buffer_t *b, int64_t v) {
+ unsigned int l=0;
+ unsigned char *cp;
+ char buf[21];
+ isc_result_t result;
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+
+ /* xxxwpk do it more low-level way ? */
+ l = snprintf(buf, 21, "%" PRId64, v);
+ RUNTIME_CHECK(l <= 21);
+ if (ISC_UNLIKELY(b->autore)) {
+ result = isc_buffer_reserve(&b, l);
+ REQUIRE(result == ISC_R_SUCCESS);
+ }
+ REQUIRE(isc_buffer_availablelength(b) >= l);
+
+ cp = isc_buffer_used(b);
+ memmove(cp, buf, l);
+ b->used += l;
+}
+
+isc_result_t
+isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **dstp, const isc_buffer_t *src) {
+ isc_buffer_t *dst = NULL;
+ isc_region_t region;
+ isc_result_t result;
+
+ REQUIRE(dstp != NULL && *dstp == NULL);
+ REQUIRE(ISC_BUFFER_VALID(src));
+
+ isc_buffer_usedregion(src, &region);
+
+ result = isc_buffer_allocate(mctx, &dst, region.length);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = isc_buffer_copyregion(dst, &region);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS); /* NOSPACE is impossible */
+ *dstp = dst;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
+ unsigned char *base;
+ unsigned int available;
+ isc_result_t result;
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ /*
+ * XXXDCL
+ */
+ base = isc_buffer_used(b);
+ available = isc_buffer_availablelength(b);
+ if (ISC_UNLIKELY(b->autore)) {
+ result = isc_buffer_reserve(&b, r->length);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ if (r->length > available)
+ return (ISC_R_NOSPACE);
+ if (r->length > 0U) {
+ memmove(base, r->base, r->length);
+ b->used += r->length;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
+ unsigned int length)
+{
+ isc_buffer_t *dbuf;
+ unsigned char * bdata;
+ REQUIRE(dynbuffer != NULL);
+ REQUIRE(*dynbuffer == NULL);
+
+ dbuf = isc_mem_get(mctx, sizeof(isc_buffer_t));
+ if (dbuf == NULL)
+ return (ISC_R_NOMEMORY);
+
+ bdata = isc_mem_get(mctx, length);
+ if (bdata == NULL) {
+ isc_mem_put(mctx, dbuf, sizeof(isc_buffer_t));
+ return (ISC_R_NOMEMORY);
+ }
+
+ isc_buffer_init(dbuf, bdata, length);
+ dbuf->mctx = mctx;
+
+ ENSURE(ISC_BUFFER_VALID(dbuf));
+
+ *dynbuffer = dbuf;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_buffer_reallocate(isc_buffer_t **dynbuffer, unsigned int length) {
+ unsigned char *bdata;
+
+ REQUIRE(dynbuffer != NULL);
+ REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
+ REQUIRE((*dynbuffer)->mctx != NULL);
+
+ if ((*dynbuffer)->length > length)
+ return (ISC_R_NOSPACE);
+
+ /*
+ * XXXMUKS: This is far more expensive than plain realloc() as
+ * it doesn't remap pages, but does ordinary copy. So is
+ * isc_mem_reallocate(), which has additional issues.
+ */
+ bdata = isc_mem_get((*dynbuffer)->mctx, length);
+ if (bdata == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memmove(bdata, (*dynbuffer)->base, (*dynbuffer)->length);
+ isc_mem_put((*dynbuffer)->mctx, (*dynbuffer)->base,
+ (*dynbuffer)->length);
+
+ (*dynbuffer)->base = bdata;
+ (*dynbuffer)->length = length;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_buffer_reserve(isc_buffer_t **dynbuffer, unsigned int size) {
+ uint64_t len;
+
+ REQUIRE(dynbuffer != NULL);
+ REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
+
+ len = (*dynbuffer)->length;
+ if ((len - (*dynbuffer)->used) >= size)
+ return (ISC_R_SUCCESS);
+
+ if ((*dynbuffer)->mctx == NULL)
+ return (ISC_R_NOSPACE);
+
+ /* Round to nearest buffer size increment */
+ len = size + (*dynbuffer)->used;
+ len = (len + ISC_BUFFER_INCR - 1 - ((len - 1) % ISC_BUFFER_INCR));
+
+ /* Cap at UINT_MAX */
+ if (len > UINT_MAX) {
+ len = UINT_MAX;
+ }
+
+ if ((len - (*dynbuffer)->used) < size)
+ return (ISC_R_NOMEMORY);
+
+ return (isc_buffer_reallocate(dynbuffer, (unsigned int) len));
+}
+
+void
+isc_buffer_free(isc_buffer_t **dynbuffer) {
+ isc_buffer_t *dbuf;
+ isc_mem_t *mctx;
+
+ REQUIRE(dynbuffer != NULL);
+ REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
+ REQUIRE((*dynbuffer)->mctx != NULL);
+
+ dbuf = *dynbuffer;
+ *dynbuffer = NULL; /* destroy external reference */
+ mctx = dbuf->mctx;
+ dbuf->mctx = NULL;
+
+ isc_mem_put(mctx, dbuf->base, dbuf->length);
+ isc_buffer_invalidate(dbuf);
+ isc_mem_put(mctx, dbuf, sizeof(isc_buffer_t));
+}
diff --git a/lib/isc/bufferlist.c b/lib/isc/bufferlist.c
new file mode 100644
index 0000000..f6ebdea
--- /dev/null
+++ b/lib/isc/bufferlist.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/buffer.h>
+#include <isc/bufferlist.h>
+#include <isc/util.h>
+
+unsigned int
+isc_bufferlist_usedcount(isc_bufferlist_t *bl) {
+ isc_buffer_t *buffer;
+ unsigned int length;
+
+ REQUIRE(bl != NULL);
+
+ length = 0;
+ buffer = ISC_LIST_HEAD(*bl);
+ while (buffer != NULL) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ length += isc_buffer_usedlength(buffer);
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ return (length);
+}
+
+unsigned int
+isc_bufferlist_availablecount(isc_bufferlist_t *bl) {
+ isc_buffer_t *buffer;
+ unsigned int length;
+
+ REQUIRE(bl != NULL);
+
+ length = 0;
+ buffer = ISC_LIST_HEAD(*bl);
+ while (buffer != NULL) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ length += isc_buffer_availablelength(buffer);
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ return (length);
+}
diff --git a/lib/isc/chacha_private.h b/lib/isc/chacha_private.h
new file mode 100644
index 0000000..a6653c6
--- /dev/null
+++ b/lib/isc/chacha_private.h
@@ -0,0 +1,229 @@
+/*
+ * Taken from OpenBSD CVS src/lib/libc/crypt/chacha_private.h on
+ * May 12, 2014.
+ */
+
+/*
+chacha-merged.c version 20080118
+D. J. Bernstein
+Public domain.
+*/
+
+typedef unsigned char u8;
+typedef unsigned int u32;
+
+typedef struct
+{
+ u32 input[16]; /* could be compressed */
+} chacha_ctx;
+
+#define U8C(v) (v##U)
+#define U32C(v) (v##U)
+
+#define U8V(v) ((u8)(v) & U8C(0xFF))
+#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
+
+#define ROTL32(v, n) \
+ (U32V((v) << (n)) | ((v) >> (32 - (n))))
+
+#define U8TO32_LITTLE(p) \
+ (((u32)((p)[0]) ) | \
+ ((u32)((p)[1]) << 8) | \
+ ((u32)((p)[2]) << 16) | \
+ ((u32)((p)[3]) << 24))
+
+#define U32TO8_LITTLE(p, v) \
+ do { \
+ (p)[0] = U8V((v) ); \
+ (p)[1] = U8V((v) >> 8); \
+ (p)[2] = U8V((v) >> 16); \
+ (p)[3] = U8V((v) >> 24); \
+ } while (0)
+
+#define ROTATE(v,c) (ROTL32(v,c))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) (U32V((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+
+#define QUARTERROUND(a,b,c,d) \
+ a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
+ c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
+ a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
+ c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
+
+static const char sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
+ '2', '-', 'b', 'y', 't', 'e', ' ', 'k' };
+static const char tau[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '1',
+ '6', '-', 'b', 'y', 't', 'e', ' ', 'k' };
+
+static void
+chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
+{
+ const char *constants;
+
+ UNUSED(ivbits);
+
+ x->input[4] = U8TO32_LITTLE(k + 0);
+ x->input[5] = U8TO32_LITTLE(k + 4);
+ x->input[6] = U8TO32_LITTLE(k + 8);
+ x->input[7] = U8TO32_LITTLE(k + 12);
+ if (kbits == 256) { /* recommended */
+ k += 16;
+ constants = sigma;
+ } else { /* kbits == 128 */
+ constants = tau;
+ }
+ x->input[8] = U8TO32_LITTLE(k + 0);
+ x->input[9] = U8TO32_LITTLE(k + 4);
+ x->input[10] = U8TO32_LITTLE(k + 8);
+ x->input[11] = U8TO32_LITTLE(k + 12);
+ x->input[0] = U8TO32_LITTLE(constants + 0);
+ x->input[1] = U8TO32_LITTLE(constants + 4);
+ x->input[2] = U8TO32_LITTLE(constants + 8);
+ x->input[3] = U8TO32_LITTLE(constants + 12);
+}
+
+static void
+chacha_ivsetup(chacha_ctx *x,const u8 *iv)
+{
+ x->input[12] = 0;
+ x->input[13] = 0;
+ x->input[14] = U8TO32_LITTLE(iv + 0);
+ x->input[15] = U8TO32_LITTLE(iv + 4);
+}
+
+static void
+chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
+{
+ u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+ u8 *ctarget = NULL;
+ u8 tmp[64];
+ u_int i;
+
+ if (!bytes) return;
+
+ j0 = x->input[0];
+ j1 = x->input[1];
+ j2 = x->input[2];
+ j3 = x->input[3];
+ j4 = x->input[4];
+ j5 = x->input[5];
+ j6 = x->input[6];
+ j7 = x->input[7];
+ j8 = x->input[8];
+ j9 = x->input[9];
+ j10 = x->input[10];
+ j11 = x->input[11];
+ j12 = x->input[12];
+ j13 = x->input[13];
+ j14 = x->input[14];
+ j15 = x->input[15];
+
+ for (;;) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i) tmp[i] = m[i];
+ m = tmp;
+ ctarget = c;
+ c = tmp;
+ }
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+ for (i = 20;i > 0;i -= 2) {
+ QUARTERROUND( x0, x4, x8,x12)
+ QUARTERROUND( x1, x5, x9,x13)
+ QUARTERROUND( x2, x6,x10,x14)
+ QUARTERROUND( x3, x7,x11,x15)
+ QUARTERROUND( x0, x5,x10,x15)
+ QUARTERROUND( x1, x6,x11,x12)
+ QUARTERROUND( x2, x7, x8,x13)
+ QUARTERROUND( x3, x4, x9,x14)
+ }
+ x0 = PLUS(x0,j0);
+ x1 = PLUS(x1,j1);
+ x2 = PLUS(x2,j2);
+ x3 = PLUS(x3,j3);
+ x4 = PLUS(x4,j4);
+ x5 = PLUS(x5,j5);
+ x6 = PLUS(x6,j6);
+ x7 = PLUS(x7,j7);
+ x8 = PLUS(x8,j8);
+ x9 = PLUS(x9,j9);
+ x10 = PLUS(x10,j10);
+ x11 = PLUS(x11,j11);
+ x12 = PLUS(x12,j12);
+ x13 = PLUS(x13,j13);
+ x14 = PLUS(x14,j14);
+ x15 = PLUS(x15,j15);
+
+#ifndef KEYSTREAM_ONLY
+ x0 = XOR(x0,U8TO32_LITTLE(m + 0));
+ x1 = XOR(x1,U8TO32_LITTLE(m + 4));
+ x2 = XOR(x2,U8TO32_LITTLE(m + 8));
+ x3 = XOR(x3,U8TO32_LITTLE(m + 12));
+ x4 = XOR(x4,U8TO32_LITTLE(m + 16));
+ x5 = XOR(x5,U8TO32_LITTLE(m + 20));
+ x6 = XOR(x6,U8TO32_LITTLE(m + 24));
+ x7 = XOR(x7,U8TO32_LITTLE(m + 28));
+ x8 = XOR(x8,U8TO32_LITTLE(m + 32));
+ x9 = XOR(x9,U8TO32_LITTLE(m + 36));
+ x10 = XOR(x10,U8TO32_LITTLE(m + 40));
+ x11 = XOR(x11,U8TO32_LITTLE(m + 44));
+ x12 = XOR(x12,U8TO32_LITTLE(m + 48));
+ x13 = XOR(x13,U8TO32_LITTLE(m + 52));
+ x14 = XOR(x14,U8TO32_LITTLE(m + 56));
+ x15 = XOR(x15,U8TO32_LITTLE(m + 60));
+#endif
+
+ j12 = PLUSONE(j12);
+ if (!j12) {
+ j13 = PLUSONE(j13);
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+
+ U32TO8_LITTLE(c + 0,x0);
+ U32TO8_LITTLE(c + 4,x1);
+ U32TO8_LITTLE(c + 8,x2);
+ U32TO8_LITTLE(c + 12,x3);
+ U32TO8_LITTLE(c + 16,x4);
+ U32TO8_LITTLE(c + 20,x5);
+ U32TO8_LITTLE(c + 24,x6);
+ U32TO8_LITTLE(c + 28,x7);
+ U32TO8_LITTLE(c + 32,x8);
+ U32TO8_LITTLE(c + 36,x9);
+ U32TO8_LITTLE(c + 40,x10);
+ U32TO8_LITTLE(c + 44,x11);
+ U32TO8_LITTLE(c + 48,x12);
+ U32TO8_LITTLE(c + 52,x13);
+ U32TO8_LITTLE(c + 56,x14);
+ U32TO8_LITTLE(c + 60,x15);
+
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i) ctarget[i] = c[i];
+ }
+ x->input[12] = j12;
+ x->input[13] = j13;
+ return;
+ }
+ bytes -= 64;
+ c += 64;
+#ifndef KEYSTREAM_ONLY
+ m += 64;
+#endif
+ }
+}
diff --git a/lib/isc/commandline.c b/lib/isc/commandline.c
new file mode 100644
index 0000000..efee967
--- /dev/null
+++ b/lib/isc/commandline.c
@@ -0,0 +1,271 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * 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. 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.
+ */
+
+
+/*! \file
+ * This file was adapted from the NetBSD project's source tree, RCS ID:
+ * NetBSD: getopt.c,v 1.15 1999/09/20 04:39:37 lukem Exp
+ *
+ * The primary change has been to rename items to the ISC namespace
+ * and format in the ISC coding style.
+ */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/commandline.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/*% Index into parent argv vector. */
+LIBISC_EXTERNAL_DATA int isc_commandline_index = 1;
+/*% Character checked for validity. */
+LIBISC_EXTERNAL_DATA int isc_commandline_option;
+/*% Argument associated with option. */
+LIBISC_EXTERNAL_DATA char *isc_commandline_argument;
+/*% For printing error messages. */
+LIBISC_EXTERNAL_DATA char *isc_commandline_progname;
+/*% Print error messages. */
+LIBISC_EXTERNAL_DATA bool isc_commandline_errprint = true;
+/*% Reset processing. */
+LIBISC_EXTERNAL_DATA bool isc_commandline_reset = true;
+
+static char endopt = '\0';
+
+#define BADOPT '?'
+#define BADARG ':'
+#define ENDOPT &endopt
+
+/*!
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+isc_commandline_parse(int argc, char * const *argv, const char *options) {
+ static char *place = ENDOPT;
+ const char *option; /* Index into *options of option. */
+
+ REQUIRE(argc >= 0 && argv != NULL && options != NULL);
+
+ /*
+ * Update scanning pointer, either because a reset was requested or
+ * the previous argv was finished.
+ */
+ if (isc_commandline_reset || *place == '\0') {
+ if (isc_commandline_reset) {
+ isc_commandline_index = 1;
+ isc_commandline_reset = false;
+ }
+
+ if (isc_commandline_progname == NULL)
+ isc_commandline_progname = argv[0];
+
+ if (isc_commandline_index >= argc ||
+ *(place = argv[isc_commandline_index]) != '-') {
+ /*
+ * Index out of range or points to non-option.
+ */
+ place = ENDOPT;
+ return (-1);
+ }
+
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ /*
+ * Found '--' to signal end of options. Advance
+ * index to next argv, the first non-option.
+ */
+ isc_commandline_index++;
+ place = ENDOPT;
+ return (-1);
+ }
+ }
+
+ isc_commandline_option = *place++;
+ option = strchr(options, isc_commandline_option);
+
+ /*
+ * Ensure valid option has been passed as specified by options string.
+ * '-:' is never a valid command line option because it could not
+ * distinguish ':' from the argument specifier in the options string.
+ */
+ if (isc_commandline_option == ':' || option == NULL) {
+ if (*place == '\0')
+ isc_commandline_index++;
+
+ if (isc_commandline_errprint && *options != ':')
+ fprintf(stderr, "%s: %s -- %c\n",
+ isc_commandline_progname,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_COMMANDLINE,
+ ISC_MSG_ILLEGALOPT,
+ "illegal option"),
+ isc_commandline_option);
+
+ return (BADOPT);
+ }
+
+ if (*++option != ':') {
+ /*
+ * Option does not take an argument.
+ */
+ isc_commandline_argument = NULL;
+
+ /*
+ * Skip to next argv if at the end of the current argv.
+ */
+ if (*place == '\0')
+ ++isc_commandline_index;
+
+ } else {
+ /*
+ * Option needs an argument.
+ */
+ if (*place != '\0')
+ /*
+ * Option is in this argv, -D1 style.
+ */
+ isc_commandline_argument = place;
+
+ else if (argc > ++isc_commandline_index)
+ /*
+ * Option is next argv, -D 1 style.
+ */
+ isc_commandline_argument = argv[isc_commandline_index];
+
+ else {
+ /*
+ * Argument needed, but no more argv.
+ */
+ place = ENDOPT;
+
+ /*
+ * Silent failure with "missing argument" return
+ * when ':' starts options string, per historical spec.
+ */
+ if (*options == ':')
+ return (BADARG);
+
+ if (isc_commandline_errprint)
+ fprintf(stderr, "%s: %s -- %c\n",
+ isc_commandline_progname,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_COMMANDLINE,
+ ISC_MSG_OPTNEEDARG,
+ "option requires "
+ "an argument"),
+ isc_commandline_option);
+
+ return (BADOPT);
+ }
+
+ place = ENDOPT;
+
+ /*
+ * Point to argv that follows argument.
+ */
+ isc_commandline_index++;
+ }
+
+ return (isc_commandline_option);
+}
+
+isc_result_t
+isc_commandline_strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp,
+ char ***argvp, unsigned int n)
+{
+ isc_result_t result;
+
+ restart:
+ /* Discard leading whitespace. */
+ while (*s == ' ' || *s == '\t')
+ s++;
+
+ if (*s == '\0') {
+ /* We have reached the end of the string. */
+ *argcp = n;
+ *argvp = isc_mem_get(mctx, n * sizeof(char *));
+ if (*argvp == NULL)
+ return (ISC_R_NOMEMORY);
+ } else {
+ char *p = s;
+ while (*p != ' ' && *p != '\t' && *p != '\0' && *p != '{') {
+ if (*p == '\n') {
+ *p = ' ';
+ goto restart;
+ }
+ p++;
+ }
+
+ /* do "grouping", items between { and } are one arg */
+ if (*p == '{') {
+ char *t = p;
+ /*
+ * shift all characters to left by 1 to get rid of '{'
+ */
+ while (*t != '\0') {
+ t++;
+ *(t-1) = *t;
+ }
+ while (*p != '\0' && *p != '}') {
+ p++;
+ }
+ /* get rid of '}' character */
+ if (*p == '}') {
+ *p = '\0';
+ p++;
+ }
+ /* normal case, no "grouping" */
+ } else if (*p != '\0')
+ *p++ = '\0';
+
+ result = isc_commandline_strtoargv(mctx, p,
+ argcp, argvp, n + 1);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ (*argvp)[n] = s;
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/counter.c b/lib/isc/counter.c
new file mode 100644
index 0000000..8c70051
--- /dev/null
+++ b/lib/isc/counter.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <isc/counter.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/util.h>
+
+#define COUNTER_MAGIC ISC_MAGIC('C', 'n', 't', 'r')
+#define VALID_COUNTER(r) ISC_MAGIC_VALID(r, COUNTER_MAGIC)
+
+struct isc_counter {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ unsigned int references;
+ unsigned int limit;
+ unsigned int used;
+};
+
+isc_result_t
+isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp) {
+ isc_result_t result;
+ isc_counter_t *counter;
+
+ REQUIRE(counterp != NULL && *counterp == NULL);
+
+ counter = isc_mem_get(mctx, sizeof(*counter));
+ if (counter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = isc_mutex_init(&counter->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, counter, sizeof(*counter));
+ return (result);
+ }
+
+ counter->mctx = NULL;
+ isc_mem_attach(mctx, &counter->mctx);
+
+ counter->references = 1;
+ counter->limit = limit;
+ counter->used = 0;
+
+ counter->magic = COUNTER_MAGIC;
+ *counterp = counter;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_counter_increment(isc_counter_t *counter) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ LOCK(&counter->lock);
+ counter->used++;
+ if (counter->limit != 0 && counter->used >= counter->limit)
+ result = ISC_R_QUOTA;
+ UNLOCK(&counter->lock);
+
+ return (result);
+}
+
+unsigned int
+isc_counter_used(isc_counter_t *counter) {
+ REQUIRE(VALID_COUNTER(counter));
+
+ return (counter->used);
+}
+
+void
+isc_counter_setlimit(isc_counter_t *counter, int limit) {
+ REQUIRE(VALID_COUNTER(counter));
+
+ LOCK(&counter->lock);
+ counter->limit = limit;
+ UNLOCK(&counter->lock);
+}
+
+void
+isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp) {
+ REQUIRE(VALID_COUNTER(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ LOCK(&source->lock);
+ source->references++;
+ INSIST(source->references > 0);
+ UNLOCK(&source->lock);
+
+ *targetp = source;
+}
+
+static void
+destroy(isc_counter_t *counter) {
+ counter->magic = 0;
+ isc_mutex_destroy(&counter->lock);
+ isc_mem_putanddetach(&counter->mctx, counter, sizeof(*counter));
+}
+
+void
+isc_counter_detach(isc_counter_t **counterp) {
+ isc_counter_t *counter;
+ bool want_destroy = false;
+
+ REQUIRE(counterp != NULL && *counterp != NULL);
+ counter = *counterp;
+ REQUIRE(VALID_COUNTER(counter));
+
+ *counterp = NULL;
+
+ LOCK(&counter->lock);
+ INSIST(counter->references > 0);
+ counter->references--;
+ if (counter->references == 0)
+ want_destroy = true;
+ UNLOCK(&counter->lock);
+
+ if (want_destroy)
+ destroy(counter);
+}
diff --git a/lib/isc/crc64.c b/lib/isc/crc64.c
new file mode 100644
index 0000000..1db2d5d
--- /dev/null
+++ b/lib/isc/crc64.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include "config.h"
+
+#include <inttypes.h>
+
+#include <isc/assertions.h>
+#include <isc/crc64.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+/*%<
+ * ECMA-182 CRC64 polynomial.
+ */
+static const uint64_t crc64_table[256] = {
+ 0x0000000000000000ULL, 0x42F0E1EBA9EA3693ULL, 0x85E1C3D753D46D26ULL,
+ 0xC711223CFA3E5BB5ULL, 0x493366450E42ECDFULL, 0x0BC387AEA7A8DA4CULL,
+ 0xCCD2A5925D9681F9ULL, 0x8E224479F47CB76AULL, 0x9266CC8A1C85D9BEULL,
+ 0xD0962D61B56FEF2DULL, 0x17870F5D4F51B498ULL, 0x5577EEB6E6BB820BULL,
+ 0xDB55AACF12C73561ULL, 0x99A54B24BB2D03F2ULL, 0x5EB4691841135847ULL,
+ 0x1C4488F3E8F96ED4ULL, 0x663D78FF90E185EFULL, 0x24CD9914390BB37CULL,
+ 0xE3DCBB28C335E8C9ULL, 0xA12C5AC36ADFDE5AULL, 0x2F0E1EBA9EA36930ULL,
+ 0x6DFEFF5137495FA3ULL, 0xAAEFDD6DCD770416ULL, 0xE81F3C86649D3285ULL,
+ 0xF45BB4758C645C51ULL, 0xB6AB559E258E6AC2ULL, 0x71BA77A2DFB03177ULL,
+ 0x334A9649765A07E4ULL, 0xBD68D2308226B08EULL, 0xFF9833DB2BCC861DULL,
+ 0x388911E7D1F2DDA8ULL, 0x7A79F00C7818EB3BULL, 0xCC7AF1FF21C30BDEULL,
+ 0x8E8A101488293D4DULL, 0x499B3228721766F8ULL, 0x0B6BD3C3DBFD506BULL,
+ 0x854997BA2F81E701ULL, 0xC7B97651866BD192ULL, 0x00A8546D7C558A27ULL,
+ 0x4258B586D5BFBCB4ULL, 0x5E1C3D753D46D260ULL, 0x1CECDC9E94ACE4F3ULL,
+ 0xDBFDFEA26E92BF46ULL, 0x990D1F49C77889D5ULL, 0x172F5B3033043EBFULL,
+ 0x55DFBADB9AEE082CULL, 0x92CE98E760D05399ULL, 0xD03E790CC93A650AULL,
+ 0xAA478900B1228E31ULL, 0xE8B768EB18C8B8A2ULL, 0x2FA64AD7E2F6E317ULL,
+ 0x6D56AB3C4B1CD584ULL, 0xE374EF45BF6062EEULL, 0xA1840EAE168A547DULL,
+ 0x66952C92ECB40FC8ULL, 0x2465CD79455E395BULL, 0x3821458AADA7578FULL,
+ 0x7AD1A461044D611CULL, 0xBDC0865DFE733AA9ULL, 0xFF3067B657990C3AULL,
+ 0x711223CFA3E5BB50ULL, 0x33E2C2240A0F8DC3ULL, 0xF4F3E018F031D676ULL,
+ 0xB60301F359DBE0E5ULL, 0xDA050215EA6C212FULL, 0x98F5E3FE438617BCULL,
+ 0x5FE4C1C2B9B84C09ULL, 0x1D14202910527A9AULL, 0x93366450E42ECDF0ULL,
+ 0xD1C685BB4DC4FB63ULL, 0x16D7A787B7FAA0D6ULL, 0x5427466C1E109645ULL,
+ 0x4863CE9FF6E9F891ULL, 0x0A932F745F03CE02ULL, 0xCD820D48A53D95B7ULL,
+ 0x8F72ECA30CD7A324ULL, 0x0150A8DAF8AB144EULL, 0x43A04931514122DDULL,
+ 0x84B16B0DAB7F7968ULL, 0xC6418AE602954FFBULL, 0xBC387AEA7A8DA4C0ULL,
+ 0xFEC89B01D3679253ULL, 0x39D9B93D2959C9E6ULL, 0x7B2958D680B3FF75ULL,
+ 0xF50B1CAF74CF481FULL, 0xB7FBFD44DD257E8CULL, 0x70EADF78271B2539ULL,
+ 0x321A3E938EF113AAULL, 0x2E5EB66066087D7EULL, 0x6CAE578BCFE24BEDULL,
+ 0xABBF75B735DC1058ULL, 0xE94F945C9C3626CBULL, 0x676DD025684A91A1ULL,
+ 0x259D31CEC1A0A732ULL, 0xE28C13F23B9EFC87ULL, 0xA07CF2199274CA14ULL,
+ 0x167FF3EACBAF2AF1ULL, 0x548F120162451C62ULL, 0x939E303D987B47D7ULL,
+ 0xD16ED1D631917144ULL, 0x5F4C95AFC5EDC62EULL, 0x1DBC74446C07F0BDULL,
+ 0xDAAD56789639AB08ULL, 0x985DB7933FD39D9BULL, 0x84193F60D72AF34FULL,
+ 0xC6E9DE8B7EC0C5DCULL, 0x01F8FCB784FE9E69ULL, 0x43081D5C2D14A8FAULL,
+ 0xCD2A5925D9681F90ULL, 0x8FDAB8CE70822903ULL, 0x48CB9AF28ABC72B6ULL,
+ 0x0A3B7B1923564425ULL, 0x70428B155B4EAF1EULL, 0x32B26AFEF2A4998DULL,
+ 0xF5A348C2089AC238ULL, 0xB753A929A170F4ABULL, 0x3971ED50550C43C1ULL,
+ 0x7B810CBBFCE67552ULL, 0xBC902E8706D82EE7ULL, 0xFE60CF6CAF321874ULL,
+ 0xE224479F47CB76A0ULL, 0xA0D4A674EE214033ULL, 0x67C58448141F1B86ULL,
+ 0x253565A3BDF52D15ULL, 0xAB1721DA49899A7FULL, 0xE9E7C031E063ACECULL,
+ 0x2EF6E20D1A5DF759ULL, 0x6C0603E6B3B7C1CAULL, 0xF6FAE5C07D3274CDULL,
+ 0xB40A042BD4D8425EULL, 0x731B26172EE619EBULL, 0x31EBC7FC870C2F78ULL,
+ 0xBFC9838573709812ULL, 0xFD39626EDA9AAE81ULL, 0x3A28405220A4F534ULL,
+ 0x78D8A1B9894EC3A7ULL, 0x649C294A61B7AD73ULL, 0x266CC8A1C85D9BE0ULL,
+ 0xE17DEA9D3263C055ULL, 0xA38D0B769B89F6C6ULL, 0x2DAF4F0F6FF541ACULL,
+ 0x6F5FAEE4C61F773FULL, 0xA84E8CD83C212C8AULL, 0xEABE6D3395CB1A19ULL,
+ 0x90C79D3FEDD3F122ULL, 0xD2377CD44439C7B1ULL, 0x15265EE8BE079C04ULL,
+ 0x57D6BF0317EDAA97ULL, 0xD9F4FB7AE3911DFDULL, 0x9B041A914A7B2B6EULL,
+ 0x5C1538ADB04570DBULL, 0x1EE5D94619AF4648ULL, 0x02A151B5F156289CULL,
+ 0x4051B05E58BC1E0FULL, 0x87409262A28245BAULL, 0xC5B073890B687329ULL,
+ 0x4B9237F0FF14C443ULL, 0x0962D61B56FEF2D0ULL, 0xCE73F427ACC0A965ULL,
+ 0x8C8315CC052A9FF6ULL, 0x3A80143F5CF17F13ULL, 0x7870F5D4F51B4980ULL,
+ 0xBF61D7E80F251235ULL, 0xFD913603A6CF24A6ULL, 0x73B3727A52B393CCULL,
+ 0x31439391FB59A55FULL, 0xF652B1AD0167FEEAULL, 0xB4A25046A88DC879ULL,
+ 0xA8E6D8B54074A6ADULL, 0xEA16395EE99E903EULL, 0x2D071B6213A0CB8BULL,
+ 0x6FF7FA89BA4AFD18ULL, 0xE1D5BEF04E364A72ULL, 0xA3255F1BE7DC7CE1ULL,
+ 0x64347D271DE22754ULL, 0x26C49CCCB40811C7ULL, 0x5CBD6CC0CC10FAFCULL,
+ 0x1E4D8D2B65FACC6FULL, 0xD95CAF179FC497DAULL, 0x9BAC4EFC362EA149ULL,
+ 0x158E0A85C2521623ULL, 0x577EEB6E6BB820B0ULL, 0x906FC95291867B05ULL,
+ 0xD29F28B9386C4D96ULL, 0xCEDBA04AD0952342ULL, 0x8C2B41A1797F15D1ULL,
+ 0x4B3A639D83414E64ULL, 0x09CA82762AAB78F7ULL, 0x87E8C60FDED7CF9DULL,
+ 0xC51827E4773DF90EULL, 0x020905D88D03A2BBULL, 0x40F9E43324E99428ULL,
+ 0x2CFFE7D5975E55E2ULL, 0x6E0F063E3EB46371ULL, 0xA91E2402C48A38C4ULL,
+ 0xEBEEC5E96D600E57ULL, 0x65CC8190991CB93DULL, 0x273C607B30F68FAEULL,
+ 0xE02D4247CAC8D41BULL, 0xA2DDA3AC6322E288ULL, 0xBE992B5F8BDB8C5CULL,
+ 0xFC69CAB42231BACFULL, 0x3B78E888D80FE17AULL, 0x7988096371E5D7E9ULL,
+ 0xF7AA4D1A85996083ULL, 0xB55AACF12C735610ULL, 0x724B8ECDD64D0DA5ULL,
+ 0x30BB6F267FA73B36ULL, 0x4AC29F2A07BFD00DULL, 0x08327EC1AE55E69EULL,
+ 0xCF235CFD546BBD2BULL, 0x8DD3BD16FD818BB8ULL, 0x03F1F96F09FD3CD2ULL,
+ 0x41011884A0170A41ULL, 0x86103AB85A2951F4ULL, 0xC4E0DB53F3C36767ULL,
+ 0xD8A453A01B3A09B3ULL, 0x9A54B24BB2D03F20ULL, 0x5D45907748EE6495ULL,
+ 0x1FB5719CE1045206ULL, 0x919735E51578E56CULL, 0xD367D40EBC92D3FFULL,
+ 0x1476F63246AC884AULL, 0x568617D9EF46BED9ULL, 0xE085162AB69D5E3CULL,
+ 0xA275F7C11F7768AFULL, 0x6564D5FDE549331AULL, 0x279434164CA30589ULL,
+ 0xA9B6706FB8DFB2E3ULL, 0xEB46918411358470ULL, 0x2C57B3B8EB0BDFC5ULL,
+ 0x6EA7525342E1E956ULL, 0x72E3DAA0AA188782ULL, 0x30133B4B03F2B111ULL,
+ 0xF7021977F9CCEAA4ULL, 0xB5F2F89C5026DC37ULL, 0x3BD0BCE5A45A6B5DULL,
+ 0x79205D0E0DB05DCEULL, 0xBE317F32F78E067BULL, 0xFCC19ED95E6430E8ULL,
+ 0x86B86ED5267CDBD3ULL, 0xC4488F3E8F96ED40ULL, 0x0359AD0275A8B6F5ULL,
+ 0x41A94CE9DC428066ULL, 0xCF8B0890283E370CULL, 0x8D7BE97B81D4019FULL,
+ 0x4A6ACB477BEA5A2AULL, 0x089A2AACD2006CB9ULL, 0x14DEA25F3AF9026DULL,
+ 0x562E43B4931334FEULL, 0x913F6188692D6F4BULL, 0xD3CF8063C0C759D8ULL,
+ 0x5DEDC41A34BBEEB2ULL, 0x1F1D25F19D51D821ULL,
+ 0xD80C07CD676F8394ULL, 0x9AFCE626CE85B507ULL
+};
+
+void
+isc_crc64_init(uint64_t *crc) {
+ REQUIRE(crc != NULL);
+
+ *crc = 0xffffffffffffffffULL;
+}
+
+void
+isc_crc64_update(uint64_t *crc, const void *data, size_t len) {
+ const unsigned char *p = data;
+ int i;
+
+ REQUIRE(crc != NULL);
+ REQUIRE(data != NULL);
+
+ while (len-- > 0U) {
+ i = ((int) (*crc >> 56) ^ *p++) & 0xff;
+ *crc = crc64_table[i] ^ (*crc << 8);
+ }
+}
+
+
+void
+isc_crc64_final(uint64_t *crc) {
+ REQUIRE(crc != NULL);
+
+ *crc ^= 0xffffffffffffffffULL;
+}
diff --git a/lib/isc/entropy.c b/lib/isc/entropy.c
new file mode 100644
index 0000000..ab2f617
--- /dev/null
+++ b/lib/isc/entropy.c
@@ -0,0 +1,1288 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file
+ * \brief
+ * This is the system independent part of the entropy module. It is
+ * compiled via inclusion from the relevant OS source file, ie,
+ * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c.
+ *
+ * \author Much of this code is modeled after the NetBSD /dev/random implementation,
+ * written by Michael Graff <explorer@netbsd.org>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/buffer.h>
+#include <isc/entropy.h>
+#include <isc/keyboard.h>
+#include <isc/list.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/safe.h>
+#include <isc/sha1.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#ifdef PKCS11CRYPTO
+#include <pk11/pk11.h>
+#endif
+
+#define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
+#define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
+
+#define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
+#define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
+
+/***
+ *** "constants." Do not change these unless you _really_ know what
+ *** you are doing.
+ ***/
+
+/*%
+ * Size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
+ */
+#define RND_POOLWORDS 128
+/*% Pool in bytes. */
+#define RND_POOLBYTES (RND_POOLWORDS * 4)
+/*% Pool in bits. */
+#define RND_POOLBITS (RND_POOLWORDS * 32)
+
+/*%
+ * Number of bytes returned per hash. This must be true:
+ * threshold * 2 <= digest_size_in_bytes
+ */
+#define RND_ENTROPY_THRESHOLD 10
+#define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
+
+/*%
+ * Size of the input event queue in samples.
+ */
+#define RND_EVENTQSIZE 32
+
+/*%
+ * The number of times we'll "reseed" for pseudorandom seeds. This is an
+ * extremely weak pseudorandom seed. If the caller is using lots of
+ * pseudorandom data and they cannot provide a stronger random source,
+ * there is little we can do other than hope they're smart enough to
+ * call _adddata() with something better than we can come up with.
+ */
+#define RND_INITIALIZE 128
+
+/*% Entropy Pool */
+typedef struct {
+ uint32_t cursor; /*%< current add point in the pool */
+ uint32_t entropy; /*%< current entropy estimate in bits */
+ uint32_t pseudo; /*%< bits extracted in pseudorandom */
+ uint32_t rotate; /*%< how many bits to rotate by */
+ uint32_t pool[RND_POOLWORDS]; /*%< random pool data */
+} isc_entropypool_t;
+
+struct isc_entropy {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ unsigned int refcnt;
+ uint32_t initialized;
+ uint32_t initcount;
+ isc_entropypool_t pool;
+ unsigned int nsources;
+ isc_entropysource_t *nextsource;
+ ISC_LIST(isc_entropysource_t) sources;
+};
+
+/*% Sample Queue */
+typedef struct {
+ uint32_t last_time; /*%< last time recorded */
+ uint32_t last_delta; /*%< last delta value */
+ uint32_t last_delta2; /*%< last delta2 value */
+ uint32_t nsamples; /*%< number of samples filled in */
+ uint32_t *samples; /*%< the samples */
+ uint32_t *extra; /*%< extra samples added in */
+} sample_queue_t;
+
+typedef struct {
+ sample_queue_t samplequeue;
+} isc_entropysamplesource_t;
+
+typedef struct {
+ bool start_called;
+ isc_entropystart_t startfunc;
+ isc_entropyget_t getfunc;
+ isc_entropystop_t stopfunc;
+ void *arg;
+ sample_queue_t samplequeue;
+} isc_cbsource_t;
+
+typedef struct {
+ FILESOURCE_HANDLE_TYPE handle;
+} isc_entropyfilesource_t;
+
+struct isc_entropysource {
+ unsigned int magic;
+ unsigned int type;
+ isc_entropy_t *ent;
+ uint32_t total; /*%< entropy from this source */
+ ISC_LINK(isc_entropysource_t) link;
+ char name[32];
+ bool bad;
+ bool warn_keyboard;
+ isc_keyboard_t kbd;
+ union {
+ isc_entropysamplesource_t sample;
+ isc_entropyfilesource_t file;
+ isc_cbsource_t callback;
+ isc_entropyusocketsource_t usocket;
+ } sources;
+};
+
+#define ENTROPY_SOURCETYPE_SAMPLE 1 /*%< Type is a sample source */
+#define ENTROPY_SOURCETYPE_FILE 2 /*%< Type is a file source */
+#define ENTROPY_SOURCETYPE_CALLBACK 3 /*%< Type is a callback source */
+#define ENTROPY_SOURCETYPE_USOCKET 4 /*%< Type is a Unix socket source */
+
+/*@{*/
+/*%
+ * The random pool "taps"
+ */
+#define TAP1 99
+#define TAP2 59
+#define TAP3 31
+#define TAP4 9
+#define TAP5 7
+/*@}*/
+
+/*@{*/
+/*%
+ * Declarations for function provided by the system dependent sources that
+ * include this file.
+ */
+static void
+fillpool(isc_entropy_t *, unsigned int, bool);
+
+static int
+wait_for_sources(isc_entropy_t *);
+
+static void
+destroyfilesource(isc_entropyfilesource_t *source);
+
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source);
+
+/*@}*/
+
+static void
+samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
+ REQUIRE(sq->samples != NULL);
+ REQUIRE(sq->extra != NULL);
+
+ isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
+ isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
+ sq->samples = NULL;
+ sq->extra = NULL;
+}
+
+static isc_result_t
+samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
+ sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
+ if (sq->samples == NULL)
+ return (ISC_R_NOMEMORY);
+
+ sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
+ if (sq->extra == NULL) {
+ isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
+ sq->samples = NULL;
+ return (ISC_R_NOMEMORY);
+ }
+
+ sq->nsamples = 0;
+
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Add in entropy, even when the value we're adding in could be
+ * very large.
+ */
+static inline void
+add_entropy(isc_entropy_t *ent, uint32_t entropy) {
+ /* clamp input. Yes, this must be done. */
+ entropy = ISC_MIN(entropy, RND_POOLBITS);
+ /* Add in the entropy we already have. */
+ entropy += ent->pool.entropy;
+ /* Clamp. */
+ ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
+}
+
+/*%
+ * Decrement the amount of entropy the pool has.
+ */
+static inline void
+subtract_entropy(isc_entropy_t *ent, uint32_t entropy) {
+ entropy = ISC_MIN(entropy, ent->pool.entropy);
+ ent->pool.entropy -= entropy;
+}
+
+/*!
+ * Add in entropy, even when the value we're adding in could be
+ * very large.
+ */
+static inline void
+add_pseudo(isc_entropy_t *ent, uint32_t pseudo) {
+ /* clamp input. Yes, this must be done. */
+ pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
+ /* Add in the pseudo we already have. */
+ pseudo += ent->pool.pseudo;
+ /* Clamp. */
+ ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
+}
+
+/*!
+ * Decrement the amount of pseudo the pool has.
+ */
+static inline void
+subtract_pseudo(isc_entropy_t *ent, uint32_t pseudo) {
+ pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
+ ent->pool.pseudo -= pseudo;
+}
+
+/*!
+ * Add one word to the pool, rotating the input as needed.
+ */
+static inline void
+entropypool_add_word(isc_entropypool_t *rp, uint32_t val) {
+ /*
+ * Steal some values out of the pool, and xor them into the
+ * word we were given.
+ *
+ * Mix the new value into the pool using xor. This will
+ * prevent the actual values from being known to the caller
+ * since the previous values are assumed to be unknown as well.
+ */
+ val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
+ val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
+ val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
+ val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
+ val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
+ if (rp->rotate == 0)
+ rp->pool[rp->cursor++] ^= val;
+ else
+ rp->pool[rp->cursor++] ^=
+ ((val << rp->rotate) | (val >> (32 - rp->rotate)));
+
+ /*
+ * If we have looped around the pool, increment the rotate
+ * variable so the next value will get xored in rotated to
+ * a different position.
+ * Increment by a value that is relatively prime to the word size
+ * to try to spread the bits throughout the pool quickly when the
+ * pool is empty.
+ */
+ if (rp->cursor == RND_POOLWORDS) {
+ rp->cursor = 0;
+ rp->rotate = (rp->rotate + 7) & 31;
+ }
+}
+
+/*!
+ * Add a buffer's worth of data to the pool.
+ *
+ * Requires that the lock is held on the entropy pool.
+ */
+static void
+entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
+ uint32_t entropy)
+{
+ uint32_t val;
+ unsigned long addr;
+ uint8_t *buf;
+
+ /* Silly MSVC in 64 bit mode complains here... */
+#ifdef _WIN64
+ addr = (unsigned long)((unsigned long long)p);
+#else
+ addr = (unsigned long)p;
+#endif
+ buf = p;
+
+ if ((addr & 0x03U) != 0U) {
+ val = 0;
+ switch (len) {
+ case 3:
+ val = *buf++;
+ len--;
+ /* FALLTHROUGH */
+ case 2:
+ val = val << 8 | *buf++;
+ len--;
+ /* FALLTHROUGH */
+ case 1:
+ val = val << 8 | *buf++;
+ len--;
+ }
+
+ entropypool_add_word(&ent->pool, val);
+ }
+
+ for (; len > 3; len -= 4) {
+ val = *((uint32_t *)buf);
+
+ entropypool_add_word(&ent->pool, val);
+ buf += 4;
+ }
+
+ if (len != 0) {
+ val = 0;
+ switch (len) {
+ case 3:
+ val = *buf++;
+ /* FALLTHROUGH */
+ case 2:
+ val = val << 8 | *buf++;
+ /* FALLTHROUGH */
+ case 1:
+ val = val << 8 | *buf++;
+ }
+
+ entropypool_add_word(&ent->pool, val);
+ }
+
+ add_entropy(ent, entropy);
+ subtract_pseudo(ent, entropy);
+}
+
+static inline void
+reseed(isc_entropy_t *ent) {
+ isc_time_t t;
+ pid_t pid;
+
+ if (ent->initcount == 0) {
+ pid = getpid();
+ entropypool_adddata(ent, &pid, sizeof(pid), 0);
+ pid = getppid();
+ entropypool_adddata(ent, &pid, sizeof(pid), 0);
+ }
+
+ /*!
+ * After we've reseeded 100 times, only add new timing info every
+ * 50 requests. This will keep us from using lots and lots of
+ * CPU just to return bad pseudorandom data anyway.
+ */
+ if (ent->initcount > 100)
+ if ((ent->initcount % 50) != 0)
+ return;
+
+ TIME_NOW(&t);
+ entropypool_adddata(ent, &t, sizeof(t), 0);
+ ent->initcount++;
+}
+
+static inline unsigned int
+estimate_entropy(sample_queue_t *sq, uint32_t t) {
+ int32_t delta;
+ int32_t delta2;
+ int32_t delta3;
+
+ /*!
+ * If the time counter has overflowed, calculate the real difference.
+ * If it has not, it is simpler.
+ */
+ if (t < sq->last_time)
+ delta = UINT_MAX - sq->last_time + t;
+ else
+ delta = sq->last_time - t;
+
+ if (delta < 0)
+ delta = -delta;
+
+ /*
+ * Calculate the second and third order differentials
+ */
+ delta2 = sq->last_delta - delta;
+ if (delta2 < 0)
+ delta2 = -delta2;
+
+ delta3 = sq->last_delta2 - delta2;
+ if (delta3 < 0)
+ delta3 = -delta3;
+
+ sq->last_time = t;
+ sq->last_delta = delta;
+ sq->last_delta2 = delta2;
+
+ /*
+ * If any delta is 0, we got no entropy. If all are non-zero, we
+ * might have something.
+ */
+ if (delta == 0 || delta2 == 0 || delta3 == 0)
+ return 0;
+
+ /*
+ * We could find the smallest delta and claim we got log2(delta)
+ * bits, but for now return that we found 1 bit.
+ */
+ return 1;
+}
+
+static unsigned int
+crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
+ unsigned int ns;
+ unsigned int added;
+
+ if (sq->nsamples < 6)
+ return (0);
+
+ added = 0;
+ sq->last_time = sq->samples[0];
+ sq->last_delta = 0;
+ sq->last_delta2 = 0;
+
+ /*
+ * Prime the values by adding in the first 4 samples in. This
+ * should completely initialize the delta calculations.
+ */
+ for (ns = 0; ns < 4; ns++)
+ (void)estimate_entropy(sq, sq->samples[ns]);
+
+ for (ns = 4; ns < sq->nsamples; ns++)
+ added += estimate_entropy(sq, sq->samples[ns]);
+
+ entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
+ entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
+
+ /*
+ * Move the last 4 samples into the first 4 positions, and start
+ * adding new samples from that point.
+ */
+ for (ns = 0; ns < 4; ns++) {
+ sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
+ sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
+ }
+
+ sq->nsamples = 4;
+
+ return (added);
+}
+
+static unsigned int
+get_from_callback(isc_entropysource_t *source, unsigned int desired,
+ bool blocking)
+{
+ isc_entropy_t *ent = source->ent;
+ isc_cbsource_t *cbs = &source->sources.callback;
+ unsigned int added;
+ unsigned int got;
+ isc_result_t result;
+
+ if (desired == 0)
+ return (0);
+
+ if (source->bad)
+ return (0);
+
+ if (!cbs->start_called && cbs->startfunc != NULL) {
+ result = cbs->startfunc(source, cbs->arg, blocking);
+ if (result != ISC_R_SUCCESS)
+ return (0);
+ cbs->start_called = true;
+ }
+
+ added = 0;
+ result = ISC_R_SUCCESS;
+ while (desired > 0 && result == ISC_R_SUCCESS) {
+ result = cbs->getfunc(source, cbs->arg, blocking);
+ if (result == ISC_R_QUEUEFULL) {
+ got = crunchsamples(ent, &cbs->samplequeue);
+ added += got;
+ desired -= ISC_MIN(got, desired);
+ result = ISC_R_SUCCESS;
+ } else if (result != ISC_R_SUCCESS &&
+ result != ISC_R_NOTBLOCKING)
+ source->bad = true;
+
+ }
+
+ return (added);
+}
+
+/*
+ * Extract some number of bytes from the random pool, decreasing the
+ * estimate of randomness as each byte is extracted.
+ *
+ * Do this by stiring the pool and returning a part of hash as randomness.
+ * Note that no secrets are given away here since parts of the hash are
+ * xored together before returned.
+ *
+ * Honor the request from the caller to only return good data, any data,
+ * etc.
+ */
+isc_result_t
+isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
+ unsigned int *returned, unsigned int flags)
+{
+ unsigned int i;
+ isc_sha1_t hash;
+ unsigned char digest[ISC_SHA1_DIGESTLENGTH];
+ uint32_t remain, deltae, count, total;
+ uint8_t *buf;
+ bool goodonly, partial, blocking;
+
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(data != NULL);
+ REQUIRE(length > 0);
+
+ goodonly = (flags & ISC_ENTROPY_GOODONLY);
+ partial = (flags & ISC_ENTROPY_PARTIAL);
+ blocking = (flags & ISC_ENTROPY_BLOCKING);
+
+ REQUIRE(!partial || returned != NULL);
+
+ LOCK(&ent->lock);
+
+ remain = length;
+ buf = data;
+ total = 0;
+ while (remain != 0) {
+ count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
+
+ /*
+ * If we are extracting good data only, make certain we
+ * have enough data in our pool for this pass. If we don't,
+ * get some, and fail if we can't, and partial returns
+ * are not ok.
+ */
+ if (goodonly) {
+ unsigned int fillcount;
+
+ fillcount = ISC_MAX(remain * 8, count * 8);
+
+ /*
+ * If, however, we have at least THRESHOLD_BITS
+ * of entropy in the pool, don't block here. It is
+ * better to drain the pool once in a while and
+ * then refill it than it is to constantly keep the
+ * pool full.
+ */
+ if (ent->pool.entropy >= THRESHOLD_BITS)
+ fillpool(ent, fillcount, false);
+ else
+ fillpool(ent, fillcount, blocking);
+
+ /*
+ * Verify that we got enough entropy to do one
+ * extraction. If we didn't, bail.
+ */
+ if (ent->pool.entropy < THRESHOLD_BITS) {
+ if (!partial)
+ goto zeroize;
+ else
+ goto partial_output;
+ }
+ } else {
+ /*
+ * If we've extracted half our pool size in bits
+ * since the last refresh, try to refresh here.
+ */
+ if (ent->initialized < THRESHOLD_BITS)
+ fillpool(ent, THRESHOLD_BITS, blocking);
+ else
+ fillpool(ent, 0, false);
+
+ /*
+ * If we've not initialized with enough good random
+ * data, seed with our crappy code.
+ */
+ if (ent->initialized < THRESHOLD_BITS)
+ reseed(ent);
+ }
+
+ isc_sha1_init(&hash);
+ isc_sha1_update(&hash, (void *)(ent->pool.pool),
+ RND_POOLBYTES);
+ isc_sha1_final(&hash, digest);
+
+ /*
+ * Stir the extracted data (all of it) back into the pool.
+ */
+ entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
+
+ for (i = 0; i < count; i++)
+ buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
+
+ buf += count;
+ remain -= count;
+
+ deltae = count * 8;
+ deltae = ISC_MIN(deltae, ent->pool.entropy);
+ total += deltae;
+ subtract_entropy(ent, deltae);
+ add_pseudo(ent, count * 8);
+ }
+
+ partial_output:
+ isc_safe_memwipe(digest, sizeof(digest));
+
+ if (returned != NULL)
+ *returned = (length - remain);
+
+ UNLOCK(&ent->lock);
+
+ return (ISC_R_SUCCESS);
+
+ zeroize:
+ /* put the entropy we almost extracted back */
+ add_entropy(ent, total);
+ isc_safe_memwipe(data, length);
+ isc_safe_memwipe(digest, sizeof(digest));
+ if (returned != NULL)
+ *returned = 0;
+
+ UNLOCK(&ent->lock);
+
+ return (ISC_R_NOENTROPY);
+}
+
+static void
+isc_entropypool_init(isc_entropypool_t *pool) {
+ pool->cursor = RND_POOLWORDS - 1;
+ pool->entropy = 0;
+ pool->pseudo = 0;
+ pool->rotate = 0;
+ memset(pool->pool, 0, RND_POOLBYTES);
+}
+
+static void
+isc_entropypool_invalidate(isc_entropypool_t *pool) {
+ pool->cursor = 0;
+ pool->entropy = 0;
+ pool->pseudo = 0;
+ pool->rotate = 0;
+ memset(pool->pool, 0, RND_POOLBYTES);
+}
+
+isc_result_t
+isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
+ isc_result_t result;
+ isc_entropy_t *ent;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(entp != NULL && *entp == NULL);
+
+ ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
+ if (ent == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * We need a lock.
+ */
+ result = isc_mutex_init(&ent->lock);
+ if (result != ISC_R_SUCCESS)
+ goto errout;
+
+ /*
+ * From here down, no failures will/can occur.
+ */
+ ISC_LIST_INIT(ent->sources);
+ ent->nextsource = NULL;
+ ent->nsources = 0;
+ ent->mctx = NULL;
+ isc_mem_attach(mctx, &ent->mctx);
+ ent->refcnt = 1;
+ ent->initialized = 0;
+ ent->initcount = 0;
+ ent->magic = ENTROPY_MAGIC;
+
+ isc_entropypool_init(&ent->pool);
+
+ *entp = ent;
+ return (ISC_R_SUCCESS);
+
+ errout:
+ isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
+
+ return (result);
+}
+
+/*!
+ * Requires "ent" be locked.
+ */
+static void
+destroysource(isc_entropysource_t **sourcep) {
+ isc_entropysource_t *source;
+ isc_entropy_t *ent;
+ isc_cbsource_t *cbs;
+
+ source = *sourcep;
+ *sourcep = NULL;
+ ent = source->ent;
+
+ ISC_LIST_UNLINK(ent->sources, source, link);
+ ent->nextsource = NULL;
+ REQUIRE(ent->nsources > 0);
+ ent->nsources--;
+
+ switch (source->type) {
+ case ENTROPY_SOURCETYPE_FILE:
+ if (! source->bad)
+ destroyfilesource(&source->sources.file);
+ break;
+ case ENTROPY_SOURCETYPE_USOCKET:
+ if (! source->bad)
+ destroyusocketsource(&source->sources.usocket);
+ break;
+ case ENTROPY_SOURCETYPE_SAMPLE:
+ samplequeue_release(ent, &source->sources.sample.samplequeue);
+ break;
+ case ENTROPY_SOURCETYPE_CALLBACK:
+ cbs = &source->sources.callback;
+ if (cbs->start_called && cbs->stopfunc != NULL) {
+ cbs->stopfunc(source, cbs->arg);
+ cbs->start_called = false;
+ }
+ samplequeue_release(ent, &cbs->samplequeue);
+ break;
+ }
+
+ isc_safe_memwipe(source, sizeof(*source));
+ isc_mem_put(ent->mctx, source, sizeof(*source));
+}
+
+static inline bool
+destroy_check(isc_entropy_t *ent) {
+ isc_entropysource_t *source;
+
+ if (ent->refcnt > 0)
+ return (false);
+
+ source = ISC_LIST_HEAD(ent->sources);
+ while (source != NULL) {
+ switch (source->type) {
+ case ENTROPY_SOURCETYPE_FILE:
+ case ENTROPY_SOURCETYPE_USOCKET:
+ break;
+ default:
+ return (false);
+ }
+ source = ISC_LIST_NEXT(source, link);
+ }
+
+ return (true);
+}
+
+static void
+destroy(isc_entropy_t **entp) {
+ isc_entropy_t *ent;
+ isc_entropysource_t *source;
+ isc_mem_t *mctx;
+
+ REQUIRE(entp != NULL && *entp != NULL);
+ ent = *entp;
+ *entp = NULL;
+
+ LOCK(&ent->lock);
+
+ REQUIRE(ent->refcnt == 0);
+
+ /*
+ * Here, detach non-sample sources.
+ */
+ source = ISC_LIST_HEAD(ent->sources);
+ while (source != NULL) {
+ switch(source->type) {
+ case ENTROPY_SOURCETYPE_FILE:
+ case ENTROPY_SOURCETYPE_USOCKET:
+ destroysource(&source);
+ break;
+ }
+ source = ISC_LIST_HEAD(ent->sources);
+ }
+
+ /*
+ * If there are other types of sources, we've found a bug.
+ */
+ REQUIRE(ISC_LIST_EMPTY(ent->sources));
+
+ mctx = ent->mctx;
+
+ isc_entropypool_invalidate(&ent->pool);
+
+ UNLOCK(&ent->lock);
+
+ DESTROYLOCK(&ent->lock);
+
+ isc_safe_memwipe(ent, sizeof(*ent));
+ isc_mem_put(mctx, ent, sizeof(*ent));
+ isc_mem_detach(&mctx);
+}
+
+void
+isc_entropy_destroysource(isc_entropysource_t **sourcep) {
+ isc_entropysource_t *source;
+ isc_entropy_t *ent;
+ bool killit;
+
+ REQUIRE(sourcep != NULL);
+ REQUIRE(VALID_SOURCE(*sourcep));
+
+ source = *sourcep;
+ *sourcep = NULL;
+
+ ent = source->ent;
+ REQUIRE(VALID_ENTROPY(ent));
+
+ LOCK(&ent->lock);
+
+ destroysource(&source);
+
+ killit = destroy_check(ent);
+
+ UNLOCK(&ent->lock);
+
+ if (killit)
+ destroy(&ent);
+}
+
+isc_result_t
+isc_entropy_createcallbacksource(isc_entropy_t *ent,
+ isc_entropystart_t start,
+ isc_entropyget_t get,
+ isc_entropystop_t stop,
+ void *arg,
+ isc_entropysource_t **sourcep)
+{
+ isc_result_t result;
+ isc_entropysource_t *source;
+ isc_cbsource_t *cbs;
+
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(get != NULL);
+ REQUIRE(sourcep != NULL && *sourcep == NULL);
+
+ LOCK(&ent->lock);
+
+ source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+ if (source == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto errout;
+ }
+ source->bad = false;
+
+ cbs = &source->sources.callback;
+
+ result = samplesource_allocate(ent, &cbs->samplequeue);
+ if (result != ISC_R_SUCCESS)
+ goto errout;
+
+ cbs->start_called = false;
+ cbs->startfunc = start;
+ cbs->getfunc = get;
+ cbs->stopfunc = stop;
+ cbs->arg = arg;
+
+ /*
+ * From here down, no failures can occur.
+ */
+ source->magic = SOURCE_MAGIC;
+ source->type = ENTROPY_SOURCETYPE_CALLBACK;
+ source->ent = ent;
+ source->total = 0;
+ memset(source->name, 0, sizeof(source->name));
+ ISC_LINK_INIT(source, link);
+
+ /*
+ * Hook it into the entropy system.
+ */
+ ISC_LIST_APPEND(ent->sources, source, link);
+ ent->nsources++;
+
+ *sourcep = source;
+
+ UNLOCK(&ent->lock);
+ return (ISC_R_SUCCESS);
+
+ errout:
+ if (source != NULL)
+ isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
+
+ UNLOCK(&ent->lock);
+
+ return (result);
+}
+
+void
+isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
+ isc_entropysource_t *source;
+ isc_cbsource_t *cbs;
+
+ REQUIRE(VALID_ENTROPY(ent));
+
+ LOCK(&ent->lock);
+
+ source = ISC_LIST_HEAD(ent->sources);
+ while (source != NULL) {
+ if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
+ cbs = &source->sources.callback;
+ if (cbs->start_called && cbs->stopfunc != NULL) {
+ cbs->stopfunc(source, cbs->arg);
+ cbs->start_called = false;
+ }
+ }
+
+ source = ISC_LIST_NEXT(source, link);
+ }
+
+ UNLOCK(&ent->lock);
+}
+
+isc_result_t
+isc_entropy_createsamplesource(isc_entropy_t *ent,
+ isc_entropysource_t **sourcep)
+{
+ isc_result_t result;
+ isc_entropysource_t *source;
+ sample_queue_t *sq;
+
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(sourcep != NULL && *sourcep == NULL);
+
+ LOCK(&ent->lock);
+
+ source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+ if (source == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto errout;
+ }
+
+ sq = &source->sources.sample.samplequeue;
+ result = samplesource_allocate(ent, sq);
+ if (result != ISC_R_SUCCESS)
+ goto errout;
+
+ /*
+ * From here down, no failures can occur.
+ */
+ source->magic = SOURCE_MAGIC;
+ source->type = ENTROPY_SOURCETYPE_SAMPLE;
+ source->ent = ent;
+ source->total = 0;
+ memset(source->name, 0, sizeof(source->name));
+ ISC_LINK_INIT(source, link);
+
+ /*
+ * Hook it into the entropy system.
+ */
+ ISC_LIST_APPEND(ent->sources, source, link);
+ ent->nsources++;
+
+ *sourcep = source;
+
+ UNLOCK(&ent->lock);
+ return (ISC_R_SUCCESS);
+
+ errout:
+ if (source != NULL)
+ isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
+
+ UNLOCK(&ent->lock);
+
+ return (result);
+}
+
+/*!
+ * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
+ * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
+ * queue was full when this function was called.
+ */
+static isc_result_t
+addsample(sample_queue_t *sq, uint32_t sample, uint32_t extra) {
+ if (sq->nsamples >= RND_EVENTQSIZE)
+ return (ISC_R_NOMORE);
+
+ sq->samples[sq->nsamples] = sample;
+ sq->extra[sq->nsamples] = extra;
+ sq->nsamples++;
+
+ if (sq->nsamples >= RND_EVENTQSIZE)
+ return (ISC_R_QUEUEFULL);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_entropy_addsample(isc_entropysource_t *source, uint32_t sample,
+ uint32_t extra)
+{
+ isc_entropy_t *ent;
+ sample_queue_t *sq;
+ unsigned int entropy;
+ isc_result_t result;
+
+ REQUIRE(VALID_SOURCE(source));
+
+ ent = source->ent;
+
+ LOCK(&ent->lock);
+
+ sq = &source->sources.sample.samplequeue;
+ result = addsample(sq, sample, extra);
+ if (result == ISC_R_QUEUEFULL) {
+ entropy = crunchsamples(ent, sq);
+ add_entropy(ent, entropy);
+ }
+
+ UNLOCK(&ent->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc_entropy_addcallbacksample(isc_entropysource_t *source, uint32_t sample,
+ uint32_t extra)
+{
+ sample_queue_t *sq;
+ isc_result_t result;
+
+ REQUIRE(VALID_SOURCE(source));
+ REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
+
+ sq = &source->sources.callback.samplequeue;
+ result = addsample(sq, sample, extra);
+
+ return (result);
+}
+
+void
+isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
+ uint32_t entropy)
+{
+ REQUIRE(VALID_ENTROPY(ent));
+
+ LOCK(&ent->lock);
+
+ entropypool_adddata(ent, data, length, entropy);
+
+ if (ent->initialized < THRESHOLD_BITS)
+ ent->initialized = THRESHOLD_BITS;
+
+ UNLOCK(&ent->lock);
+}
+
+static void
+dumpstats(isc_entropy_t *ent, FILE *out) {
+ fprintf(out,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
+ ISC_MSG_ENTROPYSTATS,
+ "Entropy pool %p: refcnt %u cursor %u,"
+ " rotate %u entropy %u pseudo %u nsources %u"
+ " nextsource %p initialized %u initcount %u\n"),
+ ent, ent->refcnt,
+ ent->pool.cursor, ent->pool.rotate,
+ ent->pool.entropy, ent->pool.pseudo,
+ ent->nsources, ent->nextsource, ent->initialized,
+ ent->initcount);
+}
+
+/*
+ * This function ignores locking. Use at your own risk.
+ */
+void
+isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
+ REQUIRE(VALID_ENTROPY(ent));
+
+ LOCK(&ent->lock);
+ dumpstats(ent, out);
+ UNLOCK(&ent->lock);
+}
+
+unsigned int
+isc_entropy_status(isc_entropy_t *ent) {
+ unsigned int estimate;
+
+ LOCK(&ent->lock);
+ estimate = ent->pool.entropy;
+ UNLOCK(&ent->lock);
+
+ return estimate;
+}
+
+void
+isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(entp != NULL && *entp == NULL);
+
+ LOCK(&ent->lock);
+
+ ent->refcnt++;
+ *entp = ent;
+
+ UNLOCK(&ent->lock);
+}
+
+void
+isc_entropy_detach(isc_entropy_t **entp) {
+ isc_entropy_t *ent;
+ bool killit;
+
+ REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
+ ent = *entp;
+ *entp = NULL;
+
+ LOCK(&ent->lock);
+
+ REQUIRE(ent->refcnt > 0);
+ ent->refcnt--;
+
+ killit = destroy_check(ent);
+
+ UNLOCK(&ent->lock);
+
+ if (killit)
+ destroy(&ent);
+}
+
+static isc_result_t
+kbdstart(isc_entropysource_t *source, void *arg, bool blocking) {
+ /*
+ * The intent of "first" is to provide a warning message only once
+ * during the run of a program that might try to gather keyboard
+ * entropy multiple times.
+ */
+ static bool first = true;
+
+ UNUSED(arg);
+
+ if (! blocking)
+ return (ISC_R_NOENTROPY);
+
+ if (first) {
+ if (source->warn_keyboard)
+ fprintf(stderr, "You must use the keyboard to create "
+ "entropy, since your system is lacking\n"
+ "/dev/random (or equivalent)\n\n");
+ first = false;
+ }
+ fprintf(stderr, "start typing:\n");
+
+ return (isc_keyboard_open(&source->kbd));
+}
+
+static void
+kbdstop(isc_entropysource_t *source, void *arg) {
+
+ UNUSED(arg);
+
+ if (! isc_keyboard_canceled(&source->kbd))
+ fprintf(stderr, "stop typing.\r\n");
+
+ (void)isc_keyboard_close(&source->kbd, 3);
+}
+
+static isc_result_t
+kbdget(isc_entropysource_t *source, void *arg, bool blocking) {
+ isc_result_t result;
+ isc_time_t t;
+ uint32_t sample;
+ uint32_t extra;
+ unsigned char c;
+
+ UNUSED(arg);
+
+ if (!blocking)
+ return (ISC_R_NOTBLOCKING);
+
+ result = isc_keyboard_getchar(&source->kbd, &c);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ TIME_NOW(&t);
+
+ sample = isc_time_nanoseconds(&t);
+ extra = c;
+
+ result = isc_entropy_addcallbacksample(source, sample, extra);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "\r\n");
+ return (result);
+ }
+
+ fprintf(stderr, ".");
+ fflush(stderr);
+
+ return (result);
+}
+
+isc_result_t
+isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
+ const char *randomfile, int use_keyboard)
+{
+ isc_result_t result;
+ isc_result_t final_result = ISC_R_NOENTROPY;
+ bool userfile = true;
+
+ REQUIRE(VALID_ENTROPY(ectx));
+ REQUIRE(source != NULL && *source == NULL);
+ REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
+ use_keyboard == ISC_ENTROPY_KEYBOARDNO ||
+ use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
+
+#ifdef PKCS11CRYPTO
+ if (randomfile != NULL)
+ pk11_rand_seed_fromfile(randomfile);
+#endif
+
+#ifdef PATH_RANDOMDEV
+ if (randomfile == NULL) {
+ randomfile = PATH_RANDOMDEV;
+ userfile = false;
+ }
+#endif
+
+ if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
+ result = isc_entropy_createfilesource(ectx, randomfile);
+ if (result == ISC_R_SUCCESS &&
+ use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
+ use_keyboard = ISC_ENTROPY_KEYBOARDNO;
+ if (result != ISC_R_SUCCESS && userfile)
+ return (result);
+
+ final_result = result;
+ }
+
+ if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
+ result = isc_entropy_createcallbacksource(ectx, kbdstart,
+ kbdget, kbdstop,
+ NULL, source);
+ if (result == ISC_R_SUCCESS)
+ (*source)->warn_keyboard =
+ (use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
+
+ if (final_result != ISC_R_SUCCESS)
+ final_result = result;
+ }
+
+ /*
+ * final_result is ISC_R_SUCCESS if at least one source of entropy
+ * could be started, otherwise it is the error from the most recently
+ * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
+ * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
+ */
+ return (final_result);
+}
diff --git a/lib/isc/error.c b/lib/isc/error.c
new file mode 100644
index 0000000..b0fe500
--- /dev/null
+++ b/lib/isc/error.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isc/error.h>
+#include <isc/msgs.h>
+#include <isc/print.h>
+
+/*% Default unexpected callback. */
+static void
+default_unexpected_callback(const char *, int, const char *, va_list)
+ ISC_FORMAT_PRINTF(3, 0);
+
+/*% Default fatal callback. */
+static void
+default_fatal_callback(const char *, int, const char *, va_list)
+ ISC_FORMAT_PRINTF(3, 0);
+
+/*% unexpected_callback */
+static isc_errorcallback_t unexpected_callback = default_unexpected_callback;
+static isc_errorcallback_t fatal_callback = default_fatal_callback;
+
+void
+isc_error_setunexpected(isc_errorcallback_t cb) {
+ if (cb == NULL)
+ unexpected_callback = default_unexpected_callback;
+ else
+ unexpected_callback = cb;
+}
+
+void
+isc_error_setfatal(isc_errorcallback_t cb) {
+ if (cb == NULL)
+ fatal_callback = default_fatal_callback;
+ else
+ fatal_callback = cb;
+}
+
+void
+isc_error_unexpected(const char *file, int line, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ (unexpected_callback)(file, line, format, args);
+ va_end(args);
+}
+
+void
+isc_error_fatal(const char *file, int line, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ (fatal_callback)(file, line, format, args);
+ va_end(args);
+ abort();
+}
+
+void
+isc_error_runtimecheck(const char *file, int line, const char *expression) {
+ isc_error_fatal(file, line, "RUNTIME_CHECK(%s) %s", expression,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+}
+
+static void
+default_unexpected_callback(const char *file, int line, const char *format,
+ va_list args)
+{
+ fprintf(stderr, "%s:%d: ", file, line);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
+
+static void
+default_fatal_callback(const char *file, int line, const char *format,
+ va_list args)
+{
+ fprintf(stderr, "%s:%d: %s: ", file, line,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FATALERROR, "fatal error"));
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
diff --git a/lib/isc/event.c b/lib/isc/event.c
new file mode 100644
index 0000000..500b6fd
--- /dev/null
+++ b/lib/isc/event.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*!
+ * \file
+ */
+
+#include <config.h>
+
+#include <isc/event.h>
+#include <isc/mem.h>
+#include <isc/util.h>
+
+/***
+ *** Events.
+ ***/
+
+static void
+destroy(isc_event_t *event) {
+ isc_mem_t *mctx = event->ev_destroy_arg;
+
+ isc_mem_put(mctx, event, event->ev_size);
+}
+
+isc_event_t *
+isc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
+ isc_taskaction_t action, void *arg, size_t size)
+{
+ isc_event_t *event;
+
+ REQUIRE(size >= sizeof(struct isc_event));
+ REQUIRE(action != NULL);
+
+ event = isc_mem_get(mctx, size);
+ if (event == NULL)
+ return (NULL);
+
+ ISC_EVENT_INIT(event, size, 0, NULL, type, action, arg,
+ sender, destroy, mctx);
+
+ return (event);
+}
+
+isc_event_t *
+isc_event_constallocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
+ isc_taskaction_t action, const void *arg, size_t size)
+{
+ isc_event_t *event;
+ void *deconst_arg;
+
+ REQUIRE(size >= sizeof(struct isc_event));
+ REQUIRE(action != NULL);
+
+ event = isc_mem_get(mctx, size);
+ if (event == NULL)
+ return (NULL);
+
+ /*
+ * Removing the const attribute from "arg" is the best of two
+ * evils here. If the event->ev_arg member is made const, then
+ * it affects a great many users of the task/event subsystem
+ * which are not passing in an "arg" which starts its life as
+ * const. Changing isc_event_allocate() and isc_task_onshutdown()
+ * to not have "arg" prototyped as const (which is quite legitimate,
+ * because neither of those functions modify arg) can cause
+ * compiler whining anytime someone does want to use a const
+ * arg that they themselves never modify, such as with
+ * gcc -Wwrite-strings and using a string "arg".
+ */
+ DE_CONST(arg, deconst_arg);
+
+ ISC_EVENT_INIT(event, size, 0, NULL, type, action, deconst_arg,
+ sender, destroy, mctx);
+
+ return (event);
+}
+
+void
+isc_event_free(isc_event_t **eventp) {
+ isc_event_t *event;
+
+ REQUIRE(eventp != NULL);
+ event = *eventp;
+ REQUIRE(event != NULL);
+
+ REQUIRE(!ISC_LINK_LINKED(event, ev_link));
+ REQUIRE(!ISC_LINK_LINKED(event, ev_ratelink));
+
+ if (event->ev_destroy != NULL)
+ (event->ev_destroy)(event);
+
+ *eventp = NULL;
+}
diff --git a/lib/isc/fsaccess.c b/lib/isc/fsaccess.c
new file mode 100644
index 0000000..deaffd8
--- /dev/null
+++ b/lib/isc/fsaccess.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file
+ * \brief
+ * This file contains the OS-independent functionality of the API.
+ */
+
+#include <stdbool.h>
+
+#include <isc/fsaccess.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+/*!
+ * Shorthand. Maybe ISC__FSACCESS_PERMISSIONBITS should not even be in
+ * <isc/fsaccess.h>. Could check consistency with sizeof(isc_fsaccess_t)
+ * and the number of bits in each function.
+ */
+#define STEP (ISC__FSACCESS_PERMISSIONBITS)
+#define GROUP (STEP)
+#define OTHER (STEP * 2)
+
+void
+isc_fsaccess_add(int trustee, int permission, isc_fsaccess_t *access) {
+ REQUIRE(trustee <= 0x7);
+ REQUIRE(permission <= 0xFF);
+
+ if ((trustee & ISC_FSACCESS_OWNER) != 0)
+ *access |= permission;
+
+ if ((trustee & ISC_FSACCESS_GROUP) != 0)
+ *access |= (permission << GROUP);
+
+ if ((trustee & ISC_FSACCESS_OTHER) != 0)
+ *access |= (permission << OTHER);
+}
+
+void
+isc_fsaccess_remove(int trustee, int permission, isc_fsaccess_t *access) {
+ REQUIRE(trustee <= 0x7);
+ REQUIRE(permission <= 0xFF);
+
+
+ if ((trustee & ISC_FSACCESS_OWNER) != 0)
+ *access &= ~permission;
+
+ if ((trustee & ISC_FSACCESS_GROUP) != 0)
+ *access &= ~(permission << GROUP);
+
+ if ((trustee & ISC_FSACCESS_OTHER) != 0)
+ *access &= ~(permission << OTHER);
+}
+
+static isc_result_t
+check_bad_bits(isc_fsaccess_t access, bool is_dir) {
+ isc_fsaccess_t bits;
+
+ /*
+ * Check for disallowed user bits.
+ */
+ if (is_dir)
+ bits = ISC_FSACCESS_READ |
+ ISC_FSACCESS_WRITE |
+ ISC_FSACCESS_EXECUTE;
+ else
+ bits = ISC_FSACCESS_CREATECHILD |
+ ISC_FSACCESS_ACCESSCHILD |
+ ISC_FSACCESS_DELETECHILD |
+ ISC_FSACCESS_LISTDIRECTORY;
+
+ /*
+ * Set group bad bits.
+ */
+ bits |= bits << STEP;
+ /*
+ * Set other bad bits.
+ */
+ bits |= bits << STEP;
+
+ if ((access & bits) != 0) {
+ if (is_dir)
+ return (ISC_R_NOTFILE);
+ else
+ return (ISC_R_NOTDIRECTORY);
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/hash.c b/lib/isc/hash.c
new file mode 100644
index 0000000..54be2fa
--- /dev/null
+++ b/lib/isc/hash.c
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file
+ * Some portion of this code was derived from universal hash function
+ * libraries of Rice University.
+\section license UH Universal Hashing Library
+
+Copyright ((c)) 2002, Rice University
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of Rice University (RICE) 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 RICE and the contributors on an "as is"
+basis, without any representations or warranties of any kind, express
+or implied including, but not limited to, representations or
+warranties of non-infringement, merchantability or fitness for a
+particular purpose. In no event shall RICE 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.
+*/
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/entropy.h>
+#include <isc/hash.h>
+#include <isc/mem.h>
+#include <isc/magic.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/random.h>
+#include <isc/refcount.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define HASH_MAGIC ISC_MAGIC('H', 'a', 's', 'h')
+#define VALID_HASH(h) ISC_MAGIC_VALID((h), HASH_MAGIC)
+
+/*%
+ * A large 32-bit prime number that specifies the range of the hash output.
+ */
+#define PRIME32 0xFFFFFFFB /* 2^32 - 5 */
+
+/*@{*/
+/*%
+ * Types of random seed and hash accumulator. Perhaps they can be system
+ * dependent.
+ */
+typedef uint32_t hash_accum_t;
+typedef uint16_t hash_random_t;
+/*@}*/
+
+/*% isc hash structure */
+struct isc_hash {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ bool initialized;
+ isc_refcount_t refcnt;
+ isc_entropy_t *entropy; /*%< entropy source */
+ size_t limit; /*%< upper limit of key length */
+ size_t vectorlen; /*%< size of the vector below */
+ hash_random_t *rndvector; /*%< random vector for universal hashing */
+};
+
+static isc_mutex_t createlock;
+static isc_once_t once = ISC_ONCE_INIT;
+
+LIBISC_EXTERNAL_DATA isc_hash_t *isc_hashctx = NULL;
+
+static unsigned char maptolower[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+isc_result_t
+isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy,
+ size_t limit, isc_hash_t **hctxp)
+{
+ isc_result_t result;
+ isc_hash_t *hctx;
+ size_t vlen;
+ hash_random_t *rv;
+ hash_accum_t overflow_limit;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(hctxp != NULL && *hctxp == NULL);
+
+ /*
+ * Overflow check. Since our implementation only does a modulo
+ * operation at the last stage of hash calculation, the accumulator
+ * must not overflow.
+ */
+ overflow_limit =
+ 1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8);
+ if (overflow_limit < (limit + 1) * 0xff)
+ return (ISC_R_RANGE);
+
+ hctx = isc_mem_get(mctx, sizeof(isc_hash_t));
+ if (hctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ vlen = sizeof(hash_random_t) * (limit + 1);
+ rv = isc_mem_get(mctx, vlen);
+ if (rv == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto errout;
+ }
+
+ /*
+ * We need a lock.
+ */
+ result = isc_mutex_init(&hctx->lock);
+ if (result != ISC_R_SUCCESS)
+ goto errout;
+
+ /*
+ * From here down, no failures will/can occur.
+ */
+ hctx->magic = HASH_MAGIC;
+ hctx->mctx = NULL;
+ isc_mem_attach(mctx, &hctx->mctx);
+ hctx->initialized = false;
+ result = isc_refcount_init(&hctx->refcnt, 1);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+ hctx->entropy = NULL;
+ hctx->limit = limit;
+ hctx->vectorlen = vlen;
+ hctx->rndvector = rv;
+
+ if (entropy != NULL)
+ isc_entropy_attach(entropy, &hctx->entropy);
+
+ *hctxp = hctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup_lock:
+ DESTROYLOCK(&hctx->lock);
+ errout:
+ isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
+ if (rv != NULL)
+ isc_mem_put(mctx, rv, vlen);
+
+ return (result);
+}
+
+static void
+initialize_lock(void) {
+ RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(mctx != NULL);
+ INSIST(isc_hashctx == NULL);
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS);
+
+ LOCK(&createlock);
+
+ if (isc_hashctx == NULL)
+ result = isc_hash_ctxcreate(mctx, entropy, limit,
+ &isc_hashctx);
+
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+void
+isc_hash_ctxinit(isc_hash_t *hctx) {
+ LOCK(&hctx->lock);
+
+ if (hctx->initialized == true)
+ goto out;
+
+ if (hctx->entropy != NULL) {
+ isc_result_t result;
+
+ result = isc_entropy_getdata(hctx->entropy,
+ hctx->rndvector,
+ (unsigned int)hctx->vectorlen,
+ NULL, 0);
+ INSIST(result == ISC_R_SUCCESS);
+ } else {
+ uint32_t pr;
+ size_t i, copylen;
+ unsigned char *p;
+
+ p = (unsigned char *)hctx->rndvector;
+ for (i = 0; i < hctx->vectorlen; i += copylen, p += copylen) {
+ isc_random_get(&pr);
+ if (i + sizeof(pr) <= hctx->vectorlen)
+ copylen = sizeof(pr);
+ else
+ copylen = hctx->vectorlen - i;
+
+ memmove(p, &pr, copylen);
+ }
+ INSIST(p == (unsigned char *)hctx->rndvector +
+ hctx->vectorlen);
+ }
+
+ hctx->initialized = true;
+
+ out:
+ UNLOCK(&hctx->lock);
+}
+
+void
+isc_hash_init(void) {
+ INSIST(isc_hashctx != NULL && VALID_HASH(isc_hashctx));
+
+ isc_hash_ctxinit(isc_hashctx);
+}
+
+void
+isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp) {
+ REQUIRE(VALID_HASH(hctx));
+ REQUIRE(hctxp != NULL && *hctxp == NULL);
+
+ isc_refcount_increment(&hctx->refcnt, NULL);
+ *hctxp = hctx;
+}
+
+static void
+destroy(isc_hash_t **hctxp) {
+ isc_hash_t *hctx;
+ isc_mem_t *mctx;
+
+ REQUIRE(hctxp != NULL && *hctxp != NULL);
+ hctx = *hctxp;
+ *hctxp = NULL;
+
+ LOCK(&hctx->lock);
+
+ isc_refcount_destroy(&hctx->refcnt);
+
+ mctx = hctx->mctx;
+ if (hctx->entropy != NULL)
+ isc_entropy_detach(&hctx->entropy);
+ if (hctx->rndvector != NULL)
+ isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen);
+
+ UNLOCK(&hctx->lock);
+
+ DESTROYLOCK(&hctx->lock);
+
+ memset(hctx, 0, sizeof(isc_hash_t));
+ isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
+ isc_mem_detach(&mctx);
+}
+
+void
+isc_hash_ctxdetach(isc_hash_t **hctxp) {
+ isc_hash_t *hctx;
+ unsigned int refs;
+
+ REQUIRE(hctxp != NULL && VALID_HASH(*hctxp));
+ hctx = *hctxp;
+
+ isc_refcount_decrement(&hctx->refcnt, &refs);
+ if (refs == 0)
+ destroy(&hctx);
+
+ *hctxp = NULL;
+}
+
+void
+isc_hash_destroy(void) {
+ unsigned int refs;
+
+ INSIST(isc_hashctx != NULL && VALID_HASH(isc_hashctx));
+
+ isc_refcount_decrement(&isc_hashctx->refcnt, &refs);
+ INSIST(refs == 0);
+
+ destroy(&isc_hashctx);
+}
+
+static inline unsigned int
+hash_calc(isc_hash_t *hctx, const unsigned char *key, unsigned int keylen,
+ bool case_sensitive)
+{
+ hash_accum_t partial_sum = 0;
+ hash_random_t *p = hctx->rndvector;
+ unsigned int i = 0;
+
+ /* Make it sure that the hash context is initialized. */
+ if (hctx->initialized == false)
+ isc_hash_ctxinit(hctx);
+
+ if (case_sensitive) {
+ for (i = 0; i < keylen; i++)
+ partial_sum += key[i] * (hash_accum_t)p[i];
+ } else {
+ for (i = 0; i < keylen; i++)
+ partial_sum += maptolower[key[i]] * (hash_accum_t)p[i];
+ }
+
+ partial_sum += p[i];
+
+ return ((unsigned int)(partial_sum % PRIME32));
+}
+
+unsigned int
+isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
+ unsigned int keylen, bool case_sensitive)
+{
+ REQUIRE(hctx != NULL && VALID_HASH(hctx));
+ REQUIRE(keylen <= hctx->limit);
+
+ return (hash_calc(hctx, key, keylen, case_sensitive));
+}
+
+unsigned int
+isc_hash_calc(const unsigned char *key, unsigned int keylen,
+ bool case_sensitive)
+{
+ INSIST(isc_hashctx != NULL && VALID_HASH(isc_hashctx));
+ REQUIRE(keylen <= isc_hashctx->limit);
+
+ return (hash_calc(isc_hashctx, key, keylen, case_sensitive));
+}
+
+void
+isc__hash_setvec(const uint16_t *vec) {
+ int i;
+ hash_random_t *p;
+
+ if (isc_hashctx == NULL)
+ return;
+
+ p = isc_hashctx->rndvector;
+ for (i = 0; i < 256; i++) {
+ p[i] = vec[i];
+ }
+}
+
+static uint32_t fnv_offset_basis;
+static isc_once_t fnv_once = ISC_ONCE_INIT;
+static bool fnv_initialized = false;
+
+static void
+fnv_initialize(void) {
+ /*
+ * This function should not leave fnv_offset_basis set to
+ * 0. Also, after this function has been called, if it is called
+ * again, it should not change fnv_offset_basis.
+ */
+ while (fnv_offset_basis == 0) {
+ isc_random_get(&fnv_offset_basis);
+ }
+
+ fnv_initialized = true;
+}
+
+const void *
+isc_hash_get_initializer(void) {
+ if (ISC_UNLIKELY(!fnv_initialized))
+ RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
+
+ return (&fnv_offset_basis);
+}
+
+void
+isc_hash_set_initializer(const void *initializer) {
+ REQUIRE(initializer != NULL);
+
+ /*
+ * Ensure that fnv_initialize() is not called after
+ * isc_hash_set_initializer() is called.
+ */
+ if (ISC_UNLIKELY(!fnv_initialized))
+ RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
+
+ fnv_offset_basis = *((const unsigned int *) initializer);
+}
+
+uint32_t
+isc_hash_function(const void *data, size_t length,
+ bool case_sensitive,
+ const uint32_t *previous_hashp)
+{
+ uint32_t hval;
+ const unsigned char *bp;
+ const unsigned char *be;
+
+ REQUIRE(length == 0 || data != NULL);
+
+ if (ISC_UNLIKELY(!fnv_initialized))
+ RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
+
+ hval = ISC_UNLIKELY(previous_hashp != NULL) ?
+ *previous_hashp : fnv_offset_basis;
+
+ if (length == 0)
+ return (hval);
+
+ bp = (const unsigned char *) data;
+ be = bp + length;
+
+ /*
+ * Fowler-Noll-Vo FNV-1a hash function.
+ *
+ * NOTE: A random FNV offset basis is used by default to avoid
+ * collision attacks as the hash function is reversible. This
+ * makes the mapping non-deterministic, but the distribution in
+ * the domain is still uniform.
+ */
+
+ if (case_sensitive) {
+ while (bp <= be - 4) {
+ hval ^= bp[0];
+ hval *= 16777619;
+ hval ^= bp[1];
+ hval *= 16777619;
+ hval ^= bp[2];
+ hval *= 16777619;
+ hval ^= bp[3];
+ hval *= 16777619;
+ bp += 4;
+ }
+ while (bp < be) {
+ hval ^= *bp++;
+ hval *= 16777619;
+ }
+ } else {
+ while (bp <= be - 4) {
+ hval ^= maptolower[bp[0]];
+ hval *= 16777619;
+ hval ^= maptolower[bp[1]];
+ hval *= 16777619;
+ hval ^= maptolower[bp[2]];
+ hval *= 16777619;
+ hval ^= maptolower[bp[3]];
+ hval *= 16777619;
+ bp += 4;
+ }
+ while (bp < be) {
+ hval ^= maptolower[*bp++];
+ hval *= 16777619;
+ }
+ }
+
+ return (hval);
+}
+
+uint32_t
+isc_hash_function_reverse(const void *data, size_t length,
+ bool case_sensitive,
+ const uint32_t *previous_hashp)
+{
+ uint32_t hval;
+ const unsigned char *bp;
+ const unsigned char *be;
+
+ REQUIRE(length == 0 || data != NULL);
+
+ if (ISC_UNLIKELY(!fnv_initialized))
+ RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
+
+ hval = ISC_UNLIKELY(previous_hashp != NULL) ?
+ *previous_hashp : fnv_offset_basis;
+
+ if (length == 0)
+ return (hval);
+
+ bp = (const unsigned char *) data;
+ be = bp + length;
+
+ /*
+ * Fowler-Noll-Vo FNV-1a hash function.
+ *
+ * NOTE: A random FNV offset basis is used by default to avoid
+ * collision attacks as the hash function is reversible. This
+ * makes the mapping non-deterministic, but the distribution in
+ * the domain is still uniform.
+ */
+
+ if (case_sensitive) {
+ while (be >= bp + 4) {
+ be -= 4;
+ hval ^= be[3];
+ hval *= 16777619;
+ hval ^= be[2];
+ hval *= 16777619;
+ hval ^= be[1];
+ hval *= 16777619;
+ hval ^= be[0];
+ hval *= 16777619;
+ }
+ while (--be >= bp) {
+ hval ^= *be;
+ hval *= 16777619;
+ }
+ } else {
+ while (be >= bp + 4) {
+ be -= 4;
+ hval ^= maptolower[be[3]];
+ hval *= 16777619;
+ hval ^= maptolower[be[2]];
+ hval *= 16777619;
+ hval ^= maptolower[be[1]];
+ hval *= 16777619;
+ hval ^= maptolower[be[0]];
+ hval *= 16777619;
+ }
+ while (--be >= bp) {
+ hval ^= maptolower[*be];
+ hval *= 16777619;
+ }
+ }
+
+ return (hval);
+}
diff --git a/lib/isc/heap.c b/lib/isc/heap.c
new file mode 100644
index 0000000..22fa81c
--- /dev/null
+++ b/lib/isc/heap.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file
+ * Heap implementation of priority queues adapted from the following:
+ *
+ * \li "Introduction to Algorithms," Cormen, Leiserson, and Rivest,
+ * MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7.
+ *
+ * \li "Algorithms," Second Edition, Sedgewick, Addison-Wesley, 1988,
+ * ISBN 0-201-06673-4, chapter 11.
+ */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/heap.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/string.h> /* Required for memmove. */
+#include <isc/util.h>
+
+/*@{*/
+/*%
+ * Note: to make heap_parent and heap_left easy to compute, the first
+ * element of the heap array is not used; i.e. heap subscripts are 1-based,
+ * not 0-based. The parent is index/2, and the left-child is index*2.
+ * The right child is index*2+1.
+ */
+#define heap_parent(i) ((i) >> 1)
+#define heap_left(i) ((i) << 1)
+/*@}*/
+
+#define SIZE_INCREMENT 1024
+
+#define HEAP_MAGIC ISC_MAGIC('H', 'E', 'A', 'P')
+#define VALID_HEAP(h) ISC_MAGIC_VALID(h, HEAP_MAGIC)
+
+/*%
+ * When the heap is in a consistent state, the following invariant
+ * holds true: for every element i > 1, heap_parent(i) has a priority
+ * higher than or equal to that of i.
+ */
+#define HEAPCONDITION(i) ((i) == 1 || \
+ ! heap->compare(heap->array[(i)], \
+ heap->array[heap_parent(i)]))
+
+/*% ISC heap structure. */
+struct isc_heap {
+ unsigned int magic;
+ isc_mem_t * mctx;
+ unsigned int size;
+ unsigned int size_increment;
+ unsigned int last;
+ void **array;
+ isc_heapcompare_t compare;
+ isc_heapindex_t index;
+};
+
+#ifdef ISC_HEAP_CHECK
+static void
+heap_check(isc_heap_t *heap) {
+ unsigned int i;
+ for (i = 1; i <= heap->last; i++) {
+ INSIST(HEAPCONDITION(i));
+ }
+}
+#else
+#define heap_check(x) (void)0
+#endif
+
+isc_result_t
+isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare,
+ isc_heapindex_t idx, unsigned int size_increment,
+ isc_heap_t **heapp)
+{
+ isc_heap_t *heap;
+
+ REQUIRE(heapp != NULL && *heapp == NULL);
+ REQUIRE(compare != NULL);
+
+ heap = isc_mem_get(mctx, sizeof(*heap));
+ if (heap == NULL)
+ return (ISC_R_NOMEMORY);
+ heap->magic = HEAP_MAGIC;
+ heap->size = 0;
+ heap->mctx = NULL;
+ isc_mem_attach(mctx, &heap->mctx);
+ if (size_increment == 0)
+ heap->size_increment = SIZE_INCREMENT;
+ else
+ heap->size_increment = size_increment;
+ heap->last = 0;
+ heap->array = NULL;
+ heap->compare = compare;
+ heap->index = idx;
+
+ *heapp = heap;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_heap_destroy(isc_heap_t **heapp) {
+ isc_heap_t *heap;
+
+ REQUIRE(heapp != NULL);
+ heap = *heapp;
+ REQUIRE(VALID_HEAP(heap));
+
+ if (heap->array != NULL)
+ isc_mem_put(heap->mctx, heap->array,
+ heap->size * sizeof(void *));
+ heap->magic = 0;
+ isc_mem_putanddetach(&heap->mctx, heap, sizeof(*heap));
+
+ *heapp = NULL;
+}
+
+static bool
+resize(isc_heap_t *heap) {
+ void **new_array;
+ unsigned int new_size;
+
+ REQUIRE(VALID_HEAP(heap));
+
+ new_size = heap->size + heap->size_increment;
+ new_array = isc_mem_get(heap->mctx, new_size * sizeof(void *));
+ if (new_array == NULL)
+ return (false);
+ if (heap->array != NULL) {
+ memmove(new_array, heap->array, heap->size * sizeof(void *));
+ isc_mem_put(heap->mctx, heap->array,
+ heap->size * sizeof(void *));
+ }
+ heap->size = new_size;
+ heap->array = new_array;
+
+ return (true);
+}
+
+static void
+float_up(isc_heap_t *heap, unsigned int i, void *elt) {
+ unsigned int p;
+
+ for (p = heap_parent(i) ;
+ i > 1 && heap->compare(elt, heap->array[p]) ;
+ i = p, p = heap_parent(i)) {
+ heap->array[i] = heap->array[p];
+ if (heap->index != NULL)
+ (heap->index)(heap->array[i], i);
+ }
+ heap->array[i] = elt;
+ if (heap->index != NULL)
+ (heap->index)(heap->array[i], i);
+
+ INSIST(HEAPCONDITION(i));
+ heap_check(heap);
+}
+
+static void
+sink_down(isc_heap_t *heap, unsigned int i, void *elt) {
+ unsigned int j, size, half_size;
+ size = heap->last;
+ half_size = size / 2;
+ while (i <= half_size) {
+ /* Find the smallest of the (at most) two children. */
+ j = heap_left(i);
+ if (j < size && heap->compare(heap->array[j+1],
+ heap->array[j]))
+ j++;
+ if (heap->compare(elt, heap->array[j]))
+ break;
+ heap->array[i] = heap->array[j];
+ if (heap->index != NULL)
+ (heap->index)(heap->array[i], i);
+ i = j;
+ }
+ heap->array[i] = elt;
+ if (heap->index != NULL)
+ (heap->index)(heap->array[i], i);
+
+ INSIST(HEAPCONDITION(i));
+ heap_check(heap);
+}
+
+isc_result_t
+isc_heap_insert(isc_heap_t *heap, void *elt) {
+ unsigned int new_last;
+
+ REQUIRE(VALID_HEAP(heap));
+
+ heap_check(heap);
+ new_last = heap->last + 1;
+ RUNTIME_CHECK(new_last > 0); /* overflow check */
+ if (new_last >= heap->size && !resize(heap))
+ return (ISC_R_NOMEMORY);
+ heap->last = new_last;
+
+ float_up(heap, new_last, elt);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_heap_delete(isc_heap_t *heap, unsigned int idx) {
+ void *elt;
+ bool less;
+
+ REQUIRE(VALID_HEAP(heap));
+ REQUIRE(idx >= 1 && idx <= heap->last);
+
+ heap_check(heap);
+ if (heap->index != NULL)
+ (heap->index)(heap->array[idx], 0);
+ if (idx == heap->last) {
+ heap->array[heap->last] = NULL;
+ heap->last--;
+ heap_check(heap);
+ } else {
+ elt = heap->array[heap->last];
+ heap->array[heap->last] = NULL;
+ heap->last--;
+
+ less = heap->compare(elt, heap->array[idx]);
+ heap->array[idx] = elt;
+ if (less)
+ float_up(heap, idx, heap->array[idx]);
+ else
+ sink_down(heap, idx, heap->array[idx]);
+ }
+}
+
+void
+isc_heap_increased(isc_heap_t *heap, unsigned int idx) {
+ REQUIRE(VALID_HEAP(heap));
+ REQUIRE(idx >= 1 && idx <= heap->last);
+
+ float_up(heap, idx, heap->array[idx]);
+}
+
+void
+isc_heap_decreased(isc_heap_t *heap, unsigned int idx) {
+ REQUIRE(VALID_HEAP(heap));
+ REQUIRE(idx >= 1 && idx <= heap->last);
+
+ sink_down(heap, idx, heap->array[idx]);
+}
+
+void *
+isc_heap_element(isc_heap_t *heap, unsigned int idx) {
+ REQUIRE(VALID_HEAP(heap));
+ REQUIRE(idx >= 1);
+
+ heap_check(heap);
+ if (idx <= heap->last)
+ return (heap->array[idx]);
+ return (NULL);
+}
+
+void
+isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap) {
+ unsigned int i;
+
+ REQUIRE(VALID_HEAP(heap));
+ REQUIRE(action != NULL);
+
+ for (i = 1 ; i <= heap->last ; i++)
+ (action)(heap->array[i], uap);
+}
diff --git a/lib/isc/hex.c b/lib/isc/hex.c
new file mode 100644
index 0000000..6d231ab
--- /dev/null
+++ b/lib/isc/hex.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+
+#include <isc/buffer.h>
+#include <isc/hex.h>
+#include <isc/lex.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define RETERR(x) do { \
+ isc_result_t _r = (x); \
+ if (_r != ISC_R_SUCCESS) \
+ return (_r); \
+ } while (0)
+
+
+/*
+ * BEW: These static functions are copied from lib/dns/rdata.c.
+ */
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target);
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
+
+static const char hex[] = "0123456789ABCDEF";
+
+isc_result_t
+isc_hex_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target)
+{
+ char buf[3];
+ unsigned int loops = 0;
+
+ if (wordlength < 2)
+ wordlength = 2;
+
+ memset(buf, 0, sizeof(buf));
+ while (source->length > 0) {
+ buf[0] = hex[(source->base[0] >> 4) & 0xf];
+ buf[1] = hex[(source->base[0]) & 0xf];
+ RETERR(str_totext(buf, target));
+ isc_region_consume(source, 1);
+
+ loops++;
+ if (source->length != 0 &&
+ (int)((loops + 1) * 2) >= wordlength)
+ {
+ loops = 0;
+ RETERR(str_totext(wordbreak, target));
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * State of a hex decoding process in progress.
+ */
+typedef struct {
+ int length; /*%< Desired length of binary data or -1 */
+ isc_buffer_t *target; /*%< Buffer for resulting binary data */
+ int digits; /*%< Number of buffered hex digits */
+ int val[2];
+} hex_decode_ctx_t;
+
+static inline void
+hex_decode_init(hex_decode_ctx_t *ctx, int length, isc_buffer_t *target)
+{
+ ctx->digits = 0;
+ ctx->length = length;
+ ctx->target = target;
+}
+
+static inline isc_result_t
+hex_decode_char(hex_decode_ctx_t *ctx, int c) {
+ const char *s;
+
+ if ((s = strchr(hex, toupper(c))) == NULL)
+ return (ISC_R_BADHEX);
+ ctx->val[ctx->digits++] = (int)(s - hex);
+ if (ctx->digits == 2) {
+ unsigned char num;
+
+ num = (ctx->val[0] << 4) + (ctx->val[1]);
+ RETERR(mem_tobuffer(ctx->target, &num, 1));
+ if (ctx->length >= 0) {
+ if (ctx->length == 0)
+ return (ISC_R_BADHEX);
+ else
+ ctx->length -= 1;
+ }
+ ctx->digits = 0;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+hex_decode_finish(hex_decode_ctx_t *ctx) {
+ if (ctx->length > 0)
+ return (ISC_R_UNEXPECTEDEND);
+ if (ctx->digits != 0)
+ return (ISC_R_BADHEX);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+ hex_decode_ctx_t ctx;
+ isc_textregion_t *tr;
+ isc_token_t token;
+ bool eol;
+
+ hex_decode_init(&ctx, length, target);
+
+ while (ctx.length != 0) {
+ unsigned int i;
+
+ if (length > 0)
+ eol = false;
+ else
+ eol = true;
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string, eol));
+ if (token.type != isc_tokentype_string)
+ break;
+ tr = &token.value.as_textregion;
+ for (i = 0; i < tr->length; i++)
+ RETERR(hex_decode_char(&ctx, tr->base[i]));
+ }
+ if (ctx.length < 0)
+ isc_lex_ungettoken(lexer, &token);
+ RETERR(hex_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_hex_decodestring(const char *cstr, isc_buffer_t *target) {
+ hex_decode_ctx_t ctx;
+
+ hex_decode_init(&ctx, -1, target);
+ for (;;) {
+ int c = *cstr++;
+ if (c == '\0')
+ break;
+ if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
+ continue;
+ RETERR(hex_decode_char(&ctx, c));
+ }
+ RETERR(hex_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+ unsigned int l;
+ isc_region_t region;
+
+ isc_buffer_availableregion(target, &region);
+ l = strlen(source);
+
+ if (l > region.length)
+ return (ISC_R_NOSPACE);
+
+ memmove(region.base, source, l);
+ isc_buffer_add(target, l);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
+ isc_region_t tr;
+
+ isc_buffer_availableregion(target, &tr);
+ if (length > tr.length)
+ return (ISC_R_NOSPACE);
+ memmove(tr.base, base, length);
+ isc_buffer_add(target, length);
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/hmacmd5.c b/lib/isc/hmacmd5.c
new file mode 100644
index 0000000..0aa270d
--- /dev/null
+++ b/lib/isc/hmacmd5.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id: hmacmd5.c,v 1.16 2009/02/06 23:47:42 tbox Exp $ */
+
+/*! \file
+ * This code implements the HMAC-MD5 keyed hash algorithm
+ * described in RFC2104.
+ */
+
+#include "config.h"
+
+#include <pk11/site.h>
+
+#ifndef PK11_MD5_DISABLE
+
+#include <stdbool.h>
+
+#include <isc/assertions.h>
+#include <isc/hmacmd5.h>
+#include <isc/md5.h>
+#include <isc/platform.h>
+#include <isc/safe.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#if PKCS11CRYPTO
+#include <pk11/internal.h>
+#include <pk11/pk11.h>
+#endif
+
+#ifdef ISC_PLATFORM_OPENSSLHASH
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#define HMAC_CTX_new() &(ctx->_ctx), HMAC_CTX_init(&(ctx->_ctx))
+#define HMAC_CTX_free(ptr) HMAC_CTX_cleanup(ptr)
+#endif
+
+void
+isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ ctx->ctx = HMAC_CTX_new();
+ RUNTIME_CHECK(ctx->ctx != NULL);
+ RUNTIME_CHECK(HMAC_Init_ex(ctx->ctx, (const void *) key,
+ (int) len, EVP_md5(), NULL) == 1);
+}
+
+void
+isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
+ if (ctx->ctx == NULL)
+ return;
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+}
+
+void
+isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ RUNTIME_CHECK(HMAC_Update(ctx->ctx, buf, (int) len) == 1);
+}
+
+void
+isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
+ RUNTIME_CHECK(HMAC_Final(ctx->ctx, digest, NULL) == 1);
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+}
+
+#elif PKCS11CRYPTO
+
+#ifndef PK11_MD5_HMAC_REPLACE
+
+static CK_BBOOL truevalue = TRUE;
+static CK_BBOOL falsevalue = FALSE;
+
+void
+isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_MD5_HMAC, NULL, 0 };
+ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+ CK_KEY_TYPE keyType = CKK_MD5_HMAC;
+ CK_ATTRIBUTE keyTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_VALUE, NULL, (CK_ULONG) len }
+ };
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_MD5_DIGESTLENGTH];
+
+ if (len < ISC_MD5_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_MD5_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_MD5_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
+ DE_CONST(key, keyTemplate[5].pValue);
+#endif
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ ctx->object = CK_INVALID_HANDLE;
+ PK11_FATALCHECK(pkcs_C_CreateObject,
+ (ctx->session, keyTemplate,
+ (CK_ULONG) 6, &ctx->object));
+ INSIST(ctx->object != CK_INVALID_HANDLE);
+ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
+}
+
+void
+isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
+ CK_BYTE garbage[ISC_MD5_DIGESTLENGTH];
+ CK_ULONG len = ISC_MD5_DIGESTLENGTH;
+
+ if (ctx->handle == NULL)
+ return;
+ (void) pkcs_C_SignFinal(ctx->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+}
+
+void
+isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_SignUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
+ CK_RV rv;
+ CK_ULONG len = ISC_MD5_DIGESTLENGTH;
+
+ PK11_FATALCHECK(pkcs_C_SignFinal,
+ (ctx->session, (CK_BYTE_PTR) digest, &len));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+}
+#else
+/* Replace missing CKM_MD5_HMAC PKCS#11 mechanism */
+
+#define PADLEN 64
+#define IPAD 0x36
+#define OPAD 0x5C
+
+void
+isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
+ unsigned char ipad[PADLEN];
+ unsigned int i;
+
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ RUNTIME_CHECK((ctx->key = pk11_mem_get(PADLEN)) != NULL);
+ if (len > PADLEN) {
+ CK_BYTE_PTR kPart;
+ CK_ULONG kl;
+
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ DE_CONST(key, kPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, kPart, (CK_ULONG) len));
+ kl = ISC_MD5_DIGESTLENGTH;
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (ctx->session, (CK_BYTE_PTR) ctx->key, &kl));
+ } else
+ memmove(ctx->key, key, len);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ memset(ipad, IPAD, PADLEN);
+ for (i = 0; i < PADLEN; i++)
+ ipad[i] ^= ctx->key[i];
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, ipad, (CK_ULONG) PADLEN));
+}
+
+void
+isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
+ if (ctx->key != NULL)
+ pk11_mem_put(ctx->key, PADLEN);
+ ctx->key = NULL;
+ isc_md5_invalidate(ctx);
+}
+
+void
+isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
+ CK_ULONG len = ISC_MD5_DIGESTLENGTH;
+ CK_BYTE opad[PADLEN];
+ unsigned int i;
+
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (ctx->session, (CK_BYTE_PTR) digest,
+ (CK_ULONG_PTR) &len));
+ memset(opad, OPAD, PADLEN);
+ for (i = 0; i < PADLEN; i++)
+ opad[i] ^= ctx->key[i];
+ pk11_mem_put(ctx->key, PADLEN);
+ ctx->key = NULL;
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, opad, (CK_ULONG) PADLEN));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, (CK_BYTE_PTR) digest, len));
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (ctx->session,
+ (CK_BYTE_PTR) digest,
+ (CK_ULONG_PTR) &len));
+ pk11_return_session(ctx);
+}
+#endif
+
+#else
+
+#define PADLEN 64
+#define IPAD 0x36
+#define OPAD 0x5C
+
+/*!
+ * Start HMAC-MD5 process. Initialize an md5 context and digest the key.
+ */
+void
+isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[PADLEN];
+ int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_md5_t md5ctx;
+ isc_md5_init(&md5ctx);
+ isc_md5_update(&md5ctx, key, len);
+ isc_md5_final(&md5ctx, ctx->key);
+ } else
+ memmove(ctx->key, key, len);
+
+ isc_md5_init(&ctx->md5ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < PADLEN; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_md5_update(&ctx->md5ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
+ isc_md5_invalidate(&ctx->md5ctx);
+ isc_safe_memwipe(ctx->key, sizeof(ctx->key));
+}
+
+/*!
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_md5_update(&ctx->md5ctx, buf, len);
+}
+
+/*!
+ * Compute signature - finalize MD5 operation and reapply MD5.
+ */
+void
+isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
+ unsigned char opad[PADLEN];
+ int i;
+
+ isc_md5_final(&ctx->md5ctx, digest);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < PADLEN; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_md5_init(&ctx->md5ctx);
+ isc_md5_update(&ctx->md5ctx, opad, sizeof(opad));
+ isc_md5_update(&ctx->md5ctx, digest, ISC_MD5_DIGESTLENGTH);
+ isc_md5_final(&ctx->md5ctx, digest);
+ isc_hmacmd5_invalidate(ctx);
+}
+
+#endif /* !ISC_PLATFORM_OPENSSLHASH */
+
+/*!
+ * Verify signature - finalize MD5 operation and reapply MD5, then
+ * compare to the supplied digest.
+ */
+bool
+isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest) {
+ return (isc_hmacmd5_verify2(ctx, digest, ISC_MD5_DIGESTLENGTH));
+}
+
+bool
+isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_MD5_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_MD5_DIGESTLENGTH);
+ isc_hmacmd5_sign(ctx, newdigest);
+ return (isc_safe_memequal(digest, newdigest, len));
+}
+
+/*
+ * Check for MD5 support; if it does not work, raise a fatal error.
+ *
+ * Use the first test vector from RFC 2104, with a second round using
+ * a too-short key.
+ *
+ * Standard use is testing 0 and expecting result true.
+ * Testing use is testing 1..4 and expecting result false.
+ */
+bool
+isc_hmacmd5_check(int testing) {
+ isc_hmacmd5_t ctx;
+ unsigned char key[] = { /* 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b */
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+ };
+ unsigned char input[] = { /* "Hi There" */
+ 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65
+ };
+ unsigned char expected[] = {
+ 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c,
+ 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d
+ };
+ unsigned char expected2[] = {
+ 0xad, 0xb8, 0x48, 0x05, 0xb8, 0x8d, 0x03, 0xe5,
+ 0x90, 0x1e, 0x4b, 0x05, 0x69, 0xce, 0x35, 0xea
+ };
+ bool result;
+
+ /*
+ * Introduce a fault for testing.
+ */
+ switch (testing) {
+ case 0:
+ default:
+ break;
+ case 1:
+ key[0] ^= 0x01;
+ break;
+ case 2:
+ input[0] ^= 0x01;
+ break;
+ case 3:
+ expected[0] ^= 0x01;
+ break;
+ case 4:
+ expected2[0] ^= 0x01;
+ break;
+ }
+
+ /*
+ * These functions do not return anything; any failure will be fatal.
+ */
+ isc_hmacmd5_init(&ctx, key, 16U);
+ isc_hmacmd5_update(&ctx, input, 8U);
+ result = isc_hmacmd5_verify2(&ctx, expected, sizeof(expected));
+ if (!result) {
+ return (result);
+ }
+
+ /* Second round using a byte key */
+ isc_hmacmd5_init(&ctx, key, 1U);
+ isc_hmacmd5_update(&ctx, input, 8U);
+ return (isc_hmacmd5_verify2(&ctx, expected2, sizeof(expected2)));
+}
+
+#else /* !PK11_MD5_DISABLE */
+#ifdef WIN32
+/* Make the Visual Studio linker happy */
+#include <isc/util.h>
+
+void isc_hmacmd5_init() { INSIST(0); }
+void isc_hmacmd5_invalidate() { INSIST(0); }
+void isc_hmacmd5_sign() { INSIST(0); }
+void isc_hmacmd5_update() { INSIST(0); }
+void isc_hmacmd5_verify() { INSIST(0); }
+void isc_hmacmd5_verify2() { INSIST(0); }
+void isc_hmacmd5_check() { INSIST(0); }
+#endif
+#endif /* PK11_MD5_DISABLE */
diff --git a/lib/isc/hmacsha.c b/lib/isc/hmacsha.c
new file mode 100644
index 0000000..2839f4f
--- /dev/null
+++ b/lib/isc/hmacsha.c
@@ -0,0 +1,1575 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id$ */
+
+/*
+ * This code implements the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, HMAC-SHA384
+ * and HMAC-SHA512 keyed hash algorithm described in RFC 2104 and
+ * draft-ietf-dnsext-tsig-sha-01.txt.
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+
+#include <isc/assertions.h>
+#include <isc/hmacsha.h>
+#include <isc/platform.h>
+#include <isc/safe.h>
+#include <isc/sha1.h>
+#include <isc/sha2.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#if PKCS11CRYPTO
+#include <pk11/internal.h>
+#include <pk11/pk11.h>
+#endif
+
+#ifdef ISC_PLATFORM_OPENSSLHASH
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#define HMAC_CTX_new() &(ctx->_ctx), HMAC_CTX_init(&(ctx->_ctx))
+#define HMAC_CTX_free(ptr) HMAC_CTX_cleanup(ptr)
+#endif
+
+void
+isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ ctx->ctx = HMAC_CTX_new();
+ RUNTIME_CHECK(ctx->ctx != NULL);
+ RUNTIME_CHECK(HMAC_Init_ex(ctx->ctx, (const void *) key,
+ (int) len, EVP_sha1(), NULL) == 1);
+}
+
+void
+isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) {
+ if (ctx->ctx == NULL)
+ return;
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+}
+
+void
+isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ RUNTIME_CHECK(HMAC_Update(ctx->ctx, buf, (int) len) == 1);
+}
+
+void
+isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA1_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA1_DIGESTLENGTH);
+
+ RUNTIME_CHECK(HMAC_Final(ctx->ctx, newdigest, NULL) == 1);
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+
+void
+isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ ctx->ctx = HMAC_CTX_new();
+ RUNTIME_CHECK(ctx->ctx != NULL);
+ RUNTIME_CHECK(HMAC_Init_ex(ctx->ctx, (const void *) key,
+ (int) len, EVP_sha224(), NULL) == 1);
+}
+
+void
+isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) {
+ if (ctx->ctx == NULL)
+ return;
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+}
+
+void
+isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ RUNTIME_CHECK(HMAC_Update(ctx->ctx, buf, (int) len) == 1);
+}
+
+void
+isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA224_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA224_DIGESTLENGTH);
+
+ RUNTIME_CHECK(HMAC_Final(ctx->ctx, newdigest, NULL) == 1);
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+
+void
+isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ ctx->ctx = HMAC_CTX_new();
+ RUNTIME_CHECK(ctx->ctx != NULL);
+ RUNTIME_CHECK(HMAC_Init_ex(ctx->ctx, (const void *) key,
+ (int) len, EVP_sha256(), NULL) == 1);
+}
+
+void
+isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) {
+ if (ctx->ctx == NULL)
+ return;
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+}
+
+void
+isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ RUNTIME_CHECK(HMAC_Update(ctx->ctx, buf, (int) len) == 1);
+}
+
+void
+isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA256_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA256_DIGESTLENGTH);
+
+ RUNTIME_CHECK(HMAC_Final(ctx->ctx, newdigest, NULL) == 1);
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+
+void
+isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ ctx->ctx = HMAC_CTX_new();
+ RUNTIME_CHECK(ctx->ctx != NULL);
+ RUNTIME_CHECK(HMAC_Init_ex(ctx->ctx, (const void *) key,
+ (int) len, EVP_sha384(), NULL) == 1);
+}
+
+void
+isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) {
+ if (ctx->ctx == NULL)
+ return;
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+}
+
+void
+isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ RUNTIME_CHECK(HMAC_Update(ctx->ctx, buf, (int) len) == 1);
+}
+
+void
+isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA384_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA384_DIGESTLENGTH);
+
+ RUNTIME_CHECK(HMAC_Final(ctx->ctx, newdigest, NULL) == 1);
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+
+void
+isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ ctx->ctx = HMAC_CTX_new();
+ RUNTIME_CHECK(ctx->ctx != NULL);
+ RUNTIME_CHECK(HMAC_Init_ex(ctx->ctx, (const void *) key,
+ (int) len, EVP_sha512(), NULL) == 1);
+}
+
+void
+isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) {
+ if (ctx->ctx == NULL)
+ return;
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+}
+
+void
+isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ RUNTIME_CHECK(HMAC_Update(ctx->ctx, buf, (int) len) == 1);
+}
+
+void
+isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA512_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA512_DIGESTLENGTH);
+
+ RUNTIME_CHECK(HMAC_Final(ctx->ctx, newdigest, NULL) == 1);
+ HMAC_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+
+#elif PKCS11CRYPTO
+
+#if defined(PK11_SHA_1_HMAC_REPLACE) || \
+ defined(PK11_SHA224_HMAC_REPLACE) || \
+ defined(PK11_SHA256_HMAC_REPLACE) || \
+ defined(PK11_SHA384_HMAC_REPLACE) || \
+ defined(PK11_SHA512_HMAC_REPLACE)
+#define IPAD 0x36
+#define OPAD 0x5C
+#endif
+
+#if !defined(PK11_SHA_1_HMAC_REPLACE) && \
+ !defined(PK11_SHA224_HMAC_REPLACE) && \
+ !defined(PK11_SHA256_HMAC_REPLACE) && \
+ !defined(PK11_SHA384_HMAC_REPLACE) && \
+ !defined(PK11_SHA512_HMAC_REPLACE)
+static CK_BBOOL truevalue = TRUE;
+static CK_BBOOL falsevalue = FALSE;
+#endif
+
+#ifndef PK11_SHA_1_HMAC_REPLACE
+void
+isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA_1_HMAC, NULL, 0 };
+ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+ CK_KEY_TYPE keyType = CKK_SHA_1_HMAC;
+ CK_ATTRIBUTE keyTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_VALUE, NULL, (CK_ULONG) len }
+ };
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_SHA1_DIGESTLENGTH];
+
+ if (len < ISC_SHA1_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_SHA1_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_SHA1_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
+ DE_CONST(key, keyTemplate[5].pValue);
+#endif
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ ctx->object = CK_INVALID_HANDLE;
+ PK11_FATALCHECK(pkcs_C_CreateObject,
+ (ctx->session, keyTemplate,
+ (CK_ULONG) 6, &ctx->object));
+ INSIST(ctx->object != CK_INVALID_HANDLE);
+ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
+}
+
+void
+isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) {
+ CK_BYTE garbage[ISC_SHA1_DIGESTLENGTH];
+ CK_ULONG len = ISC_SHA1_DIGESTLENGTH;
+
+ if (ctx->handle == NULL)
+ return;
+ (void) pkcs_C_SignFinal(ctx->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+}
+
+void
+isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_SignUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) {
+ CK_RV rv;
+ CK_BYTE newdigest[ISC_SHA1_DIGESTLENGTH];
+ CK_ULONG psl = ISC_SHA1_DIGESTLENGTH;
+
+ REQUIRE(len <= ISC_SHA1_DIGESTLENGTH);
+
+ PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#else
+void
+isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA_1, NULL, 0 };
+ unsigned char ipad[ISC_SHA1_BLOCK_LENGTH];
+ unsigned int i;
+
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ RUNTIME_CHECK((ctx->key = pk11_mem_get(ISC_SHA1_BLOCK_LENGTH))
+ != NULL);
+ if (len > ISC_SHA1_BLOCK_LENGTH) {
+ CK_BYTE_PTR kPart;
+ CK_ULONG kl;
+
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ DE_CONST(key, kPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, kPart, (CK_ULONG) len));
+ kl = ISC_SHA1_DIGESTLENGTH;
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (ctx->session, (CK_BYTE_PTR) ctx->key, &kl));
+ } else
+ memmove(ctx->key, key, len);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ memset(ipad, IPAD, ISC_SHA1_BLOCK_LENGTH);
+ for (i = 0; i < ISC_SHA1_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, ipad,
+ (CK_ULONG) ISC_SHA1_BLOCK_LENGTH));
+}
+
+void
+isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) {
+ if (ctx->key != NULL)
+ pk11_mem_put(ctx->key, ISC_SHA1_BLOCK_LENGTH);
+ ctx->key = NULL;
+ isc_sha1_invalidate(ctx);
+}
+
+void
+isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) {
+ CK_RV rv;
+ CK_BYTE newdigest[ISC_SHA1_DIGESTLENGTH];
+ CK_ULONG psl = ISC_SHA1_DIGESTLENGTH;
+ CK_MECHANISM mech = { CKM_SHA_1, NULL, 0 };
+ CK_BYTE opad[ISC_SHA1_BLOCK_LENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA1_DIGESTLENGTH);
+
+ PK11_FATALCHECK(pkcs_C_DigestFinal, (ctx->session, newdigest, &psl));
+ memset(opad, OPAD, ISC_SHA1_BLOCK_LENGTH);
+ for (i = 0; i < ISC_SHA1_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+ pk11_mem_put(ctx->key, ISC_SHA1_BLOCK_LENGTH);
+ ctx->key = NULL;
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, opad,
+ (CK_ULONG) ISC_SHA1_BLOCK_LENGTH));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, (CK_BYTE_PTR) newdigest, psl));
+ PK11_FATALCHECK(pkcs_C_DigestFinal, (ctx->session, newdigest, &psl));
+ pk11_return_session(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#endif
+
+#ifndef PK11_SHA224_HMAC_REPLACE
+void
+isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA224_HMAC, NULL, 0 };
+ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+ CK_KEY_TYPE keyType = CKK_SHA224_HMAC;
+ CK_ATTRIBUTE keyTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_VALUE, NULL, (CK_ULONG) len }
+ };
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_SHA224_DIGESTLENGTH];
+
+ if (len < ISC_SHA224_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_SHA224_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_SHA224_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
+ DE_CONST(key, keyTemplate[5].pValue);
+#endif
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ ctx->object = CK_INVALID_HANDLE;
+ PK11_FATALCHECK(pkcs_C_CreateObject,
+ (ctx->session, keyTemplate,
+ (CK_ULONG) 6, &ctx->object));
+ INSIST(ctx->object != CK_INVALID_HANDLE);
+ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
+}
+
+void
+isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) {
+ CK_BYTE garbage[ISC_SHA224_DIGESTLENGTH];
+ CK_ULONG len = ISC_SHA224_DIGESTLENGTH;
+
+ if (ctx->handle == NULL)
+ return;
+ (void) pkcs_C_SignFinal(ctx->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+}
+
+void
+isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_SignUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) {
+ CK_RV rv;
+ CK_BYTE newdigest[ISC_SHA224_DIGESTLENGTH];
+ CK_ULONG psl = ISC_SHA224_DIGESTLENGTH;
+
+ REQUIRE(len <= ISC_SHA224_DIGESTLENGTH);
+
+ PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#else
+void
+isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA224, NULL, 0 };
+ unsigned char ipad[ISC_SHA224_BLOCK_LENGTH];
+ unsigned int i;
+
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ RUNTIME_CHECK((ctx->key = pk11_mem_get(ISC_SHA224_BLOCK_LENGTH))
+ != NULL);
+ if (len > ISC_SHA224_BLOCK_LENGTH) {
+ CK_BYTE_PTR kPart;
+ CK_ULONG kl;
+
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ DE_CONST(key, kPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, kPart, (CK_ULONG) len));
+ kl = ISC_SHA224_DIGESTLENGTH;
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (ctx->session, (CK_BYTE_PTR) ctx->key, &kl));
+ } else
+ memmove(ctx->key, key, len);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ memset(ipad, IPAD, ISC_SHA224_BLOCK_LENGTH);
+ for (i = 0; i < ISC_SHA224_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, ipad,
+ (CK_ULONG) ISC_SHA224_BLOCK_LENGTH));
+}
+
+void
+isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) {
+ if (ctx->key != NULL)
+ pk11_mem_put(ctx->key, ISC_SHA224_BLOCK_LENGTH);
+ ctx->key = NULL;
+ isc_sha224_invalidate(ctx);
+}
+
+void
+isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) {
+ CK_RV rv;
+ CK_BYTE newdigest[ISC_SHA224_DIGESTLENGTH];
+ CK_ULONG psl = ISC_SHA224_DIGESTLENGTH;
+ CK_MECHANISM mech = { CKM_SHA224, NULL, 0 };
+ CK_BYTE opad[ISC_SHA224_BLOCK_LENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA224_DIGESTLENGTH);
+
+ PK11_FATALCHECK(pkcs_C_DigestFinal, (ctx->session, newdigest, &psl));
+ memset(opad, OPAD, ISC_SHA224_BLOCK_LENGTH);
+ for (i = 0; i < ISC_SHA224_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+ pk11_mem_put(ctx->key, ISC_SHA224_BLOCK_LENGTH);
+ ctx->key = NULL;
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, opad,
+ (CK_ULONG) ISC_SHA224_BLOCK_LENGTH));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, (CK_BYTE_PTR) newdigest, psl));
+ PK11_FATALCHECK(pkcs_C_DigestFinal, (ctx->session, newdigest, &psl));
+ pk11_return_session(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#endif
+
+#ifndef PK11_SHA256_HMAC_REPLACE
+void
+isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA256_HMAC, NULL, 0 };
+ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+ CK_KEY_TYPE keyType = CKK_SHA256_HMAC;
+ CK_ATTRIBUTE keyTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_VALUE, NULL, (CK_ULONG) len }
+ };
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_SHA256_DIGESTLENGTH];
+
+ if (len < ISC_SHA256_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_SHA256_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_SHA256_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
+ DE_CONST(key, keyTemplate[5].pValue);
+#endif
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ ctx->object = CK_INVALID_HANDLE;
+ PK11_FATALCHECK(pkcs_C_CreateObject,
+ (ctx->session, keyTemplate,
+ (CK_ULONG) 6, &ctx->object));
+ INSIST(ctx->object != CK_INVALID_HANDLE);
+ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
+}
+
+void
+isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) {
+ CK_BYTE garbage[ISC_SHA256_DIGESTLENGTH];
+ CK_ULONG len = ISC_SHA256_DIGESTLENGTH;
+
+ if (ctx->handle == NULL)
+ return;
+ (void) pkcs_C_SignFinal(ctx->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+}
+
+void
+isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_SignUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) {
+ CK_RV rv;
+ CK_BYTE newdigest[ISC_SHA256_DIGESTLENGTH];
+ CK_ULONG psl = ISC_SHA256_DIGESTLENGTH;
+
+ REQUIRE(len <= ISC_SHA256_DIGESTLENGTH);
+
+ PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#else
+void
+isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA256, NULL, 0 };
+ unsigned char ipad[ISC_SHA256_BLOCK_LENGTH];
+ unsigned int i;
+
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ RUNTIME_CHECK((ctx->key = pk11_mem_get(ISC_SHA256_BLOCK_LENGTH))
+ != NULL);
+ if (len > ISC_SHA256_BLOCK_LENGTH) {
+ CK_BYTE_PTR kPart;
+ CK_ULONG kl;
+
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ DE_CONST(key, kPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, kPart, (CK_ULONG) len));
+ kl = ISC_SHA256_DIGESTLENGTH;
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (ctx->session, (CK_BYTE_PTR) ctx->key, &kl));
+ } else
+ memmove(ctx->key, key, len);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ memset(ipad, IPAD, ISC_SHA256_BLOCK_LENGTH);
+ for (i = 0; i < ISC_SHA256_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, ipad,
+ (CK_ULONG) ISC_SHA256_BLOCK_LENGTH));
+}
+
+void
+isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) {
+ if (ctx->key != NULL)
+ pk11_mem_put(ctx->key, ISC_SHA256_BLOCK_LENGTH);
+ ctx->key = NULL;
+ isc_sha256_invalidate(ctx);
+}
+
+void
+isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) {
+ CK_RV rv;
+ CK_BYTE newdigest[ISC_SHA256_DIGESTLENGTH];
+ CK_ULONG psl = ISC_SHA256_DIGESTLENGTH;
+ CK_MECHANISM mech = { CKM_SHA256, NULL, 0 };
+ CK_BYTE opad[ISC_SHA256_BLOCK_LENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA256_DIGESTLENGTH);
+
+ PK11_FATALCHECK(pkcs_C_DigestFinal, (ctx->session, newdigest, &psl));
+ memset(opad, OPAD, ISC_SHA256_BLOCK_LENGTH);
+ for (i = 0; i < ISC_SHA256_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+ pk11_mem_put(ctx->key, ISC_SHA256_BLOCK_LENGTH);
+ ctx->key = NULL;
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, opad,
+ (CK_ULONG) ISC_SHA256_BLOCK_LENGTH));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, (CK_BYTE_PTR) newdigest, psl));
+ PK11_FATALCHECK(pkcs_C_DigestFinal, (ctx->session, newdigest, &psl));
+ pk11_return_session(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#endif
+
+#ifndef PK11_SHA384_HMAC_REPLACE
+void
+isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA384_HMAC, NULL, 0 };
+ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+ CK_KEY_TYPE keyType = CKK_SHA384_HMAC;
+ CK_ATTRIBUTE keyTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_VALUE, NULL, (CK_ULONG) len }
+ };
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_SHA384_DIGESTLENGTH];
+
+ if (len < ISC_SHA384_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_SHA384_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_SHA384_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
+ DE_CONST(key, keyTemplate[5].pValue);
+#endif
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ ctx->object = CK_INVALID_HANDLE;
+ PK11_FATALCHECK(pkcs_C_CreateObject,
+ (ctx->session, keyTemplate,
+ (CK_ULONG) 6, &ctx->object));
+ INSIST(ctx->object != CK_INVALID_HANDLE);
+ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
+}
+
+void
+isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) {
+ CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH];
+ CK_ULONG len = ISC_SHA384_DIGESTLENGTH;
+
+ if (ctx->handle == NULL)
+ return;
+ (void) pkcs_C_SignFinal(ctx->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+}
+
+void
+isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_SignUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) {
+ CK_RV rv;
+ CK_BYTE newdigest[ISC_SHA384_DIGESTLENGTH];
+ CK_ULONG psl = ISC_SHA384_DIGESTLENGTH;
+
+ REQUIRE(len <= ISC_SHA384_DIGESTLENGTH);
+
+ PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#else
+void
+isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA384, NULL, 0 };
+ unsigned char ipad[ISC_SHA384_BLOCK_LENGTH];
+ unsigned int i;
+
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ RUNTIME_CHECK((ctx->key = pk11_mem_get(ISC_SHA384_BLOCK_LENGTH))
+ != NULL);
+ if (len > ISC_SHA384_BLOCK_LENGTH) {
+ CK_BYTE_PTR kPart;
+ CK_ULONG kl;
+
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ DE_CONST(key, kPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, kPart, (CK_ULONG) len));
+ kl = ISC_SHA384_DIGESTLENGTH;
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (ctx->session, (CK_BYTE_PTR) ctx->key, &kl));
+ } else
+ memmove(ctx->key, key, len);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ memset(ipad, IPAD, ISC_SHA384_BLOCK_LENGTH);
+ for (i = 0; i < ISC_SHA384_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, ipad,
+ (CK_ULONG) ISC_SHA384_BLOCK_LENGTH));
+}
+
+void
+isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) {
+ if (ctx->key != NULL)
+ pk11_mem_put(ctx->key, ISC_SHA384_BLOCK_LENGTH);
+ ctx->key = NULL;
+ isc_sha384_invalidate(ctx);
+}
+
+void
+isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) {
+ CK_RV rv;
+ CK_BYTE newdigest[ISC_SHA384_DIGESTLENGTH];
+ CK_ULONG psl = ISC_SHA384_DIGESTLENGTH;
+ CK_MECHANISM mech = { CKM_SHA384, NULL, 0 };
+ CK_BYTE opad[ISC_SHA384_BLOCK_LENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA384_DIGESTLENGTH);
+
+ PK11_FATALCHECK(pkcs_C_DigestFinal, (ctx->session, newdigest, &psl));
+ memset(opad, OPAD, ISC_SHA384_BLOCK_LENGTH);
+ for (i = 0; i < ISC_SHA384_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+ pk11_mem_put(ctx->key, ISC_SHA384_BLOCK_LENGTH);
+ ctx->key = NULL;
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, opad,
+ (CK_ULONG) ISC_SHA384_BLOCK_LENGTH));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, (CK_BYTE_PTR) newdigest, psl));
+ PK11_FATALCHECK(pkcs_C_DigestFinal, (ctx->session, newdigest, &psl));
+ pk11_return_session(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#endif
+
+#ifndef PK11_SHA512_HMAC_REPLACE
+void
+isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA512_HMAC, NULL, 0 };
+ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+ CK_KEY_TYPE keyType = CKK_SHA512_HMAC;
+ CK_ATTRIBUTE keyTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_VALUE, NULL, (CK_ULONG) len }
+ };
+#ifdef PK11_PAD_HMAC_KEYS
+ CK_BYTE keypad[ISC_SHA512_DIGESTLENGTH];
+
+ if (len < ISC_SHA512_DIGESTLENGTH) {
+ memset(keypad, 0, ISC_SHA512_DIGESTLENGTH);
+ memmove(keypad, key, len);
+ keyTemplate[5].pValue = keypad;
+ keyTemplate[5].ulValueLen = ISC_SHA512_DIGESTLENGTH;
+ } else
+ DE_CONST(key, keyTemplate[5].pValue);
+#else
+ DE_CONST(key, keyTemplate[5].pValue);
+#endif
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ ctx->object = CK_INVALID_HANDLE;
+ PK11_FATALCHECK(pkcs_C_CreateObject,
+ (ctx->session, keyTemplate,
+ (CK_ULONG) 6, &ctx->object));
+ INSIST(ctx->object != CK_INVALID_HANDLE);
+ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
+}
+
+void
+isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) {
+ CK_BYTE garbage[ISC_SHA512_DIGESTLENGTH];
+ CK_ULONG len = ISC_SHA512_DIGESTLENGTH;
+
+ if (ctx->handle == NULL)
+ return;
+ (void) pkcs_C_SignFinal(ctx->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+}
+
+void
+isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_SignUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
+ CK_RV rv;
+ CK_BYTE newdigest[ISC_SHA512_DIGESTLENGTH];
+ CK_ULONG psl = ISC_SHA512_DIGESTLENGTH;
+
+ REQUIRE(len <= ISC_SHA512_DIGESTLENGTH);
+
+ PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl));
+ if (ctx->object != CK_INVALID_HANDLE)
+ (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
+ ctx->object = CK_INVALID_HANDLE;
+ pk11_return_session(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#else
+void
+isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA512, NULL, 0 };
+ unsigned char ipad[ISC_SHA512_BLOCK_LENGTH];
+ unsigned int i;
+
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ RUNTIME_CHECK((ctx->key = pk11_mem_get(ISC_SHA512_BLOCK_LENGTH))
+ != NULL);
+ if (len > ISC_SHA512_BLOCK_LENGTH) {
+ CK_BYTE_PTR kPart;
+ CK_ULONG kl;
+
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ DE_CONST(key, kPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, kPart, (CK_ULONG) len));
+ kl = ISC_SHA512_DIGESTLENGTH;
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (ctx->session, (CK_BYTE_PTR) ctx->key, &kl));
+ } else
+ memmove(ctx->key, key, len);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ memset(ipad, IPAD, ISC_SHA512_BLOCK_LENGTH);
+ for (i = 0; i < ISC_SHA512_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, ipad,
+ (CK_ULONG) ISC_SHA512_BLOCK_LENGTH));
+}
+
+void
+isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) {
+ if (ctx->key != NULL)
+ pk11_mem_put(ctx->key, ISC_SHA512_BLOCK_LENGTH);
+ ctx->key = NULL;
+ isc_sha512_invalidate(ctx);
+}
+
+void
+isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
+ CK_RV rv;
+ CK_BYTE newdigest[ISC_SHA512_DIGESTLENGTH];
+ CK_ULONG psl = ISC_SHA512_DIGESTLENGTH;
+ CK_MECHANISM mech = { CKM_SHA512, NULL, 0 };
+ CK_BYTE opad[ISC_SHA512_BLOCK_LENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA512_DIGESTLENGTH);
+
+ PK11_FATALCHECK(pkcs_C_DigestFinal, (ctx->session, newdigest, &psl));
+ memset(opad, OPAD, ISC_SHA512_BLOCK_LENGTH);
+ for (i = 0; i < ISC_SHA512_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+ pk11_mem_put(ctx->key, ISC_SHA512_BLOCK_LENGTH);
+ ctx->key = NULL;
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, opad,
+ (CK_ULONG) ISC_SHA512_BLOCK_LENGTH));
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, (CK_BYTE_PTR) newdigest, psl));
+ PK11_FATALCHECK(pkcs_C_DigestFinal, (ctx->session, newdigest, &psl));
+ pk11_return_session(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#endif
+
+#else
+
+#define IPAD 0x36
+#define OPAD 0x5C
+
+/*
+ * Start HMAC-SHA1 process. Initialize an sha1 context and digest the key.
+ */
+void
+isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[ISC_SHA1_BLOCK_LENGTH];
+ unsigned int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_sha1_t sha1ctx;
+ isc_sha1_init(&sha1ctx);
+ isc_sha1_update(&sha1ctx, key, len);
+ isc_sha1_final(&sha1ctx, ctx->key);
+ } else
+ memmove(ctx->key, key, len);
+
+ isc_sha1_init(&ctx->sha1ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < ISC_SHA1_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_sha1_update(&ctx->sha1ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) {
+ isc_sha1_invalidate(&ctx->sha1ctx);
+ isc_safe_memwipe(ctx, sizeof(*ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_sha1_update(&ctx->sha1ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA1 operation and reapply SHA1.
+ */
+void
+isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char opad[ISC_SHA1_BLOCK_LENGTH];
+ unsigned char newdigest[ISC_SHA1_DIGESTLENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA1_DIGESTLENGTH);
+ isc_sha1_final(&ctx->sha1ctx, newdigest);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < ISC_SHA1_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_sha1_init(&ctx->sha1ctx);
+ isc_sha1_update(&ctx->sha1ctx, opad, sizeof(opad));
+ isc_sha1_update(&ctx->sha1ctx, newdigest, ISC_SHA1_DIGESTLENGTH);
+ isc_sha1_final(&ctx->sha1ctx, newdigest);
+ isc_hmacsha1_invalidate(ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+
+/*
+ * Start HMAC-SHA224 process. Initialize an sha224 context and digest the key.
+ */
+void
+isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[ISC_SHA224_BLOCK_LENGTH];
+ unsigned int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_sha224_t sha224ctx;
+ isc_sha224_init(&sha224ctx);
+ isc_sha224_update(&sha224ctx, key, len);
+ isc_sha224_final(ctx->key, &sha224ctx);
+ } else
+ memmove(ctx->key, key, len);
+
+ isc_sha224_init(&ctx->sha224ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < ISC_SHA224_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_sha224_update(&ctx->sha224ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) {
+ isc_safe_memwipe(ctx, sizeof(*ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_sha224_update(&ctx->sha224ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA224 operation and reapply SHA224.
+ */
+void
+isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char opad[ISC_SHA224_BLOCK_LENGTH];
+ unsigned char newdigest[ISC_SHA224_DIGESTLENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA224_DIGESTLENGTH);
+ isc_sha224_final(newdigest, &ctx->sha224ctx);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < ISC_SHA224_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_sha224_init(&ctx->sha224ctx);
+ isc_sha224_update(&ctx->sha224ctx, opad, sizeof(opad));
+ isc_sha224_update(&ctx->sha224ctx, newdigest, ISC_SHA224_DIGESTLENGTH);
+ isc_sha224_final(newdigest, &ctx->sha224ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+
+/*
+ * Start HMAC-SHA256 process. Initialize an sha256 context and digest the key.
+ */
+void
+isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[ISC_SHA256_BLOCK_LENGTH];
+ unsigned int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_sha256_t sha256ctx;
+ isc_sha256_init(&sha256ctx);
+ isc_sha256_update(&sha256ctx, key, len);
+ isc_sha256_final(ctx->key, &sha256ctx);
+ } else
+ memmove(ctx->key, key, len);
+
+ isc_sha256_init(&ctx->sha256ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < ISC_SHA256_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_sha256_update(&ctx->sha256ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) {
+ isc_safe_memwipe(ctx, sizeof(*ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_sha256_update(&ctx->sha256ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA256 operation and reapply SHA256.
+ */
+void
+isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char opad[ISC_SHA256_BLOCK_LENGTH];
+ unsigned char newdigest[ISC_SHA256_DIGESTLENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA256_DIGESTLENGTH);
+ isc_sha256_final(newdigest, &ctx->sha256ctx);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < ISC_SHA256_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_sha256_init(&ctx->sha256ctx);
+ isc_sha256_update(&ctx->sha256ctx, opad, sizeof(opad));
+ isc_sha256_update(&ctx->sha256ctx, newdigest, ISC_SHA256_DIGESTLENGTH);
+ isc_sha256_final(newdigest, &ctx->sha256ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+
+/*
+ * Start HMAC-SHA384 process. Initialize an sha384 context and digest the key.
+ */
+void
+isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[ISC_SHA384_BLOCK_LENGTH];
+ unsigned int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_sha384_t sha384ctx;
+ isc_sha384_init(&sha384ctx);
+ isc_sha384_update(&sha384ctx, key, len);
+ isc_sha384_final(ctx->key, &sha384ctx);
+ } else
+ memmove(ctx->key, key, len);
+
+ isc_sha384_init(&ctx->sha384ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < ISC_SHA384_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_sha384_update(&ctx->sha384ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) {
+ isc_safe_memwipe(ctx, sizeof(*ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_sha384_update(&ctx->sha384ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA384 operation and reapply SHA384.
+ */
+void
+isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char opad[ISC_SHA384_BLOCK_LENGTH];
+ unsigned char newdigest[ISC_SHA384_DIGESTLENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA384_DIGESTLENGTH);
+ isc_sha384_final(newdigest, &ctx->sha384ctx);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < ISC_SHA384_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_sha384_init(&ctx->sha384ctx);
+ isc_sha384_update(&ctx->sha384ctx, opad, sizeof(opad));
+ isc_sha384_update(&ctx->sha384ctx, newdigest, ISC_SHA384_DIGESTLENGTH);
+ isc_sha384_final(newdigest, &ctx->sha384ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+
+/*
+ * Start HMAC-SHA512 process. Initialize an sha512 context and digest the key.
+ */
+void
+isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[ISC_SHA512_BLOCK_LENGTH];
+ unsigned int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_sha512_t sha512ctx;
+ isc_sha512_init(&sha512ctx);
+ isc_sha512_update(&sha512ctx, key, len);
+ isc_sha512_final(ctx->key, &sha512ctx);
+ } else
+ memmove(ctx->key, key, len);
+
+ isc_sha512_init(&ctx->sha512ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < ISC_SHA512_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_sha512_update(&ctx->sha512ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) {
+ isc_safe_memwipe(ctx, sizeof(*ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_sha512_update(&ctx->sha512ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA512 operation and reapply SHA512.
+ */
+void
+isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char opad[ISC_SHA512_BLOCK_LENGTH];
+ unsigned char newdigest[ISC_SHA512_DIGESTLENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA512_DIGESTLENGTH);
+ isc_sha512_final(newdigest, &ctx->sha512ctx);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < ISC_SHA512_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_sha512_init(&ctx->sha512ctx);
+ isc_sha512_update(&ctx->sha512ctx, opad, sizeof(opad));
+ isc_sha512_update(&ctx->sha512ctx, newdigest, ISC_SHA512_DIGESTLENGTH);
+ isc_sha512_final(newdigest, &ctx->sha512ctx);
+ memmove(digest, newdigest, len);
+ isc_safe_memwipe(newdigest, sizeof(newdigest));
+}
+#endif /* !ISC_PLATFORM_OPENSSLHASH */
+
+/*
+ * Verify signature - finalize SHA1 operation and reapply SHA1, then
+ * compare to the supplied digest.
+ */
+bool
+isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA1_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA1_DIGESTLENGTH);
+ isc_hmacsha1_sign(ctx, newdigest, ISC_SHA1_DIGESTLENGTH);
+ return (isc_safe_memequal(digest, newdigest, len));
+}
+
+/*
+ * Verify signature - finalize SHA224 operation and reapply SHA224, then
+ * compare to the supplied digest.
+ */
+bool
+isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA224_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA224_DIGESTLENGTH);
+ isc_hmacsha224_sign(ctx, newdigest, ISC_SHA224_DIGESTLENGTH);
+ return (isc_safe_memequal(digest, newdigest, len));
+}
+
+/*
+ * Verify signature - finalize SHA256 operation and reapply SHA256, then
+ * compare to the supplied digest.
+ */
+bool
+isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA256_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA256_DIGESTLENGTH);
+ isc_hmacsha256_sign(ctx, newdigest, ISC_SHA256_DIGESTLENGTH);
+ return (isc_safe_memequal(digest, newdigest, len));
+}
+
+/*
+ * Verify signature - finalize SHA384 operation and reapply SHA384, then
+ * compare to the supplied digest.
+ */
+bool
+isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA384_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA384_DIGESTLENGTH);
+ isc_hmacsha384_sign(ctx, newdigest, ISC_SHA384_DIGESTLENGTH);
+ return (isc_safe_memequal(digest, newdigest, len));
+}
+
+/*
+ * Verify signature - finalize SHA512 operation and reapply SHA512, then
+ * compare to the supplied digest.
+ */
+bool
+isc_hmacsha512_verify(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA512_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA512_DIGESTLENGTH);
+ isc_hmacsha512_sign(ctx, newdigest, ISC_SHA512_DIGESTLENGTH);
+ return (isc_safe_memequal(digest, newdigest, len));
+}
+
+/*
+ * Check for SHA-1 support; if it does not work, raise a fatal error.
+ *
+ * Use the first test vector from RFC 2104, with a second round using
+ * a too-short key.
+ *
+ * Standard use is testing 0 and expecting result true.
+ * Testing use is testing 1..4 and expecting result false.
+ */
+bool
+isc_hmacsha1_check(int testing) {
+ isc_hmacsha1_t ctx;
+ unsigned char key[] = { /* 20*0x0b */
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+ };
+ unsigned char input[] = { /* "Hi There" */
+ 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65
+ };
+ unsigned char expected[] = {
+ 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64,
+ 0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e,
+ 0xf1, 0x46, 0xbe, 0x00
+ };
+ unsigned char expected2[] = {
+ 0xa0, 0x75, 0xe0, 0x5f, 0x7f, 0x17, 0x9d, 0x34,
+ 0xb2, 0xab, 0xc5, 0x19, 0x8f, 0x38, 0x62, 0x36,
+ 0x42, 0xbd, 0xec, 0xde
+ };
+ bool result;
+
+ /*
+ * Introduce a fault for testing.
+ */
+ switch (testing) {
+ case 0:
+ default:
+ break;
+ case 1:
+ key[0] ^= 0x01;
+ break;
+ case 2:
+ input[0] ^= 0x01;
+ break;
+ case 3:
+ expected[0] ^= 0x01;
+ break;
+ case 4:
+ expected2[0] ^= 0x01;
+ break;
+ }
+
+ /*
+ * These functions do not return anything; any failure will be fatal.
+ */
+ isc_hmacsha1_init(&ctx, key, 20U);
+ isc_hmacsha1_update(&ctx, input, 8U);
+ result = isc_hmacsha1_verify(&ctx, expected, sizeof(expected));
+ if (!result) {
+ return (result);
+ }
+
+ /* Second round using a byte key */
+ isc_hmacsha1_init(&ctx, key, 1U);
+ isc_hmacsha1_update(&ctx, input, 8U);
+ return (isc_hmacsha1_verify(&ctx, expected2, sizeof(expected2)));
+}
diff --git a/lib/isc/ht.c b/lib/isc/ht.c
new file mode 100644
index 0000000..b3c6825
--- /dev/null
+++ b/lib/isc/ht.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <isc/hash.h>
+#include <isc/ht.h>
+#include <isc/types.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+
+typedef struct isc_ht_node isc_ht_node_t;
+
+#define ISC_HT_MAGIC ISC_MAGIC('H', 'T', 'a', 'b')
+#define ISC_HT_VALID(ht) ISC_MAGIC_VALID(ht, ISC_HT_MAGIC)
+
+struct isc_ht_node {
+ void *value;
+ isc_ht_node_t *next;
+ size_t keysize;
+ unsigned char key[FLEXIBLE_ARRAY_MEMBER];
+};
+
+struct isc_ht {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ size_t size;
+ size_t mask;
+ unsigned int count;
+ isc_ht_node_t **table;
+};
+
+struct isc_ht_iter {
+ isc_ht_t *ht;
+ size_t i;
+ isc_ht_node_t *cur;
+};
+
+isc_result_t
+isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits) {
+ isc_ht_t *ht = NULL;
+ size_t i;
+
+ REQUIRE(htp != NULL && *htp == NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(bits >= 1 && bits <= (sizeof(size_t)*8 - 1));
+
+ ht = isc_mem_get(mctx, sizeof(struct isc_ht));
+ if (ht == NULL) {
+ return (ISC_R_NOMEMORY);
+ }
+
+ ht->mctx = NULL;
+ isc_mem_attach(mctx, &ht->mctx);
+
+ ht->size = ((size_t)1<<bits);
+ ht->mask = ((size_t)1<<bits)-1;
+ ht->count = 0;
+
+ ht->table = isc_mem_get(ht->mctx, ht->size * sizeof(isc_ht_node_t*));
+ if (ht->table == NULL) {
+ isc_mem_putanddetach(&ht->mctx, ht, sizeof(struct isc_ht));
+ return (ISC_R_NOMEMORY);
+ }
+
+ for (i = 0; i < ht->size; i++) {
+ ht->table[i] = NULL;
+ }
+
+ ht->magic = ISC_HT_MAGIC;
+
+ *htp = ht;
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_ht_destroy(isc_ht_t **htp) {
+ isc_ht_t *ht;
+ size_t i;
+
+ REQUIRE(htp != NULL);
+
+ ht = *htp;
+ REQUIRE(ISC_HT_VALID(ht));
+
+ ht->magic = 0;
+
+ for (i = 0; i < ht->size; i++) {
+ isc_ht_node_t *node = ht->table[i];
+ while (node != NULL) {
+ isc_ht_node_t *next = node->next;
+ ht->count--;
+ isc_mem_put(ht->mctx, node,
+ offsetof(isc_ht_node_t, key) +
+ node->keysize);
+ node = next;
+ }
+ }
+
+ INSIST(ht->count == 0);
+
+ isc_mem_put(ht->mctx, ht->table, ht->size * sizeof(isc_ht_node_t*));
+ isc_mem_putanddetach(&ht->mctx, ht, sizeof(struct isc_ht));
+
+ *htp = NULL;
+}
+
+isc_result_t
+isc_ht_add(isc_ht_t *ht, const unsigned char *key,
+ uint32_t keysize, void *value)
+{
+ isc_ht_node_t *node;
+ uint32_t hash;
+
+ REQUIRE(ISC_HT_VALID(ht));
+ REQUIRE(key != NULL && keysize > 0);
+
+ hash = isc_hash_function(key, keysize, true, NULL);
+ node = ht->table[hash & ht->mask];
+ while (node != NULL) {
+ if (keysize == node->keysize &&
+ memcmp(key, node->key, keysize) == 0) {
+ return (ISC_R_EXISTS);
+ }
+ node = node->next;
+ }
+
+ node = isc_mem_get(ht->mctx, offsetof(isc_ht_node_t, key) + keysize);
+ if (node == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memmove(node->key, key, keysize);
+ node->keysize = keysize;
+ node->next = ht->table[hash & ht->mask];
+ node->value = value;
+
+ ht->count++;
+ ht->table[hash & ht->mask] = node;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_ht_find(const isc_ht_t *ht, const unsigned char *key,
+ uint32_t keysize, void **valuep)
+{
+ isc_ht_node_t *node;
+ uint32_t hash;
+
+ REQUIRE(ISC_HT_VALID(ht));
+ REQUIRE(key != NULL && keysize > 0);
+ REQUIRE(valuep != NULL);
+
+ hash = isc_hash_function(key, keysize, true, NULL);
+ node = ht->table[hash & ht->mask];
+ while (node != NULL) {
+ if (keysize == node->keysize &&
+ memcmp(key, node->key, keysize) == 0) {
+ *valuep = node->value;
+ return (ISC_R_SUCCESS);
+ }
+ node = node->next;
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+isc_result_t
+isc_ht_delete(isc_ht_t *ht, const unsigned char *key, uint32_t keysize) {
+ isc_ht_node_t *node, *prev;
+ uint32_t hash;
+
+ REQUIRE(ISC_HT_VALID(ht));
+ REQUIRE(key != NULL && keysize > 0);
+
+ prev = NULL;
+ hash = isc_hash_function(key, keysize, true, NULL);
+ node = ht->table[hash & ht->mask];
+ while (node != NULL) {
+ if (keysize == node->keysize &&
+ memcmp(key, node->key, keysize) == 0) {
+ if (prev == NULL)
+ ht->table[hash & ht->mask] = node->next;
+ else
+ prev->next = node->next;
+ isc_mem_put(ht->mctx, node,
+ offsetof(isc_ht_node_t, key) +
+ node->keysize);
+ ht->count--;
+
+ return (ISC_R_SUCCESS);
+ }
+
+ prev = node;
+ node = node->next;
+ }
+ return (ISC_R_NOTFOUND);
+}
+
+isc_result_t
+isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) {
+ isc_ht_iter_t *it;
+
+ REQUIRE(ISC_HT_VALID(ht));
+ REQUIRE(itp != NULL && *itp == NULL);
+
+ it = isc_mem_get(ht->mctx, sizeof(isc_ht_iter_t));
+ if (it == NULL)
+ return (ISC_R_NOMEMORY);
+
+ it->ht = ht;
+ it->i = 0;
+ it->cur = NULL;
+
+ *itp = it;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_ht_iter_destroy(isc_ht_iter_t **itp) {
+ isc_ht_iter_t *it;
+ isc_ht_t *ht;
+
+ REQUIRE(itp != NULL && *itp != NULL);
+
+ it = *itp;
+ ht = it->ht;
+ isc_mem_put(ht->mctx, it, sizeof(isc_ht_iter_t));
+
+ *itp = NULL;
+}
+
+isc_result_t
+isc_ht_iter_first(isc_ht_iter_t *it) {
+ REQUIRE(it != NULL);
+
+ it->i = 0;
+ while (it->i < it->ht->size && it->ht->table[it->i] == NULL)
+ it->i++;
+
+ if (it->i == it->ht->size)
+ return (ISC_R_NOMORE);
+
+ it->cur = it->ht->table[it->i];
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_ht_iter_next(isc_ht_iter_t *it) {
+ REQUIRE(it != NULL);
+ REQUIRE(it->cur != NULL);
+
+ it->cur = it->cur->next;
+ if (it->cur == NULL) {
+ do {
+ it->i++;
+ } while (it->i < it->ht->size && it->ht->table[it->i] == NULL);
+ if (it->i >= it->ht->size)
+ return (ISC_R_NOMORE);
+ it->cur = it->ht->table[it->i];
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_ht_iter_delcurrent_next(isc_ht_iter_t *it) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_ht_node_t *to_delete = NULL;
+ isc_ht_node_t *prev = NULL;
+ isc_ht_node_t *node = NULL;
+ uint32_t hash;
+ isc_ht_t *ht;
+ REQUIRE(it != NULL);
+ REQUIRE(it->cur != NULL);
+ to_delete = it->cur;
+ ht = it->ht;
+
+ it->cur = it->cur->next;
+ if (it->cur == NULL) {
+ do {
+ it->i++;
+ } while (it->i < ht->size && ht->table[it->i] == NULL);
+ if (it->i >= ht->size)
+ result = ISC_R_NOMORE;
+ else
+ it->cur = ht->table[it->i];
+ }
+
+ hash = isc_hash_function(to_delete->key, to_delete->keysize, true,
+ NULL);
+ node = ht->table[hash & ht->mask];
+ while (node != to_delete) {
+ prev = node;
+ node = node->next;
+ INSIST(node != NULL);
+ }
+
+ if (prev == NULL)
+ ht->table[hash & ht->mask] = node->next;
+ else
+ prev->next = node->next;
+ isc_mem_put(ht->mctx, node,
+ offsetof(isc_ht_node_t, key) + node->keysize);
+ ht->count--;
+
+ return (result);
+}
+
+void
+isc_ht_iter_current(isc_ht_iter_t *it, void **valuep) {
+ REQUIRE(it != NULL);
+ REQUIRE(it->cur != NULL);
+ *valuep = it->cur->value;
+}
+
+void
+isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, size_t *keysize)
+{
+ REQUIRE(it != NULL);
+ REQUIRE(it->cur != NULL);
+ *key = it->cur->key;
+ *keysize = it->cur->keysize;
+}
+
+unsigned int
+isc_ht_count(isc_ht_t *ht) {
+ REQUIRE(ISC_HT_VALID(ht));
+
+ return(ht->count);
+}
diff --git a/lib/isc/httpd.c b/lib/isc/httpd.c
new file mode 100644
index 0000000..06e7a8b
--- /dev/null
+++ b/lib/isc/httpd.c
@@ -0,0 +1,1273 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <isc/buffer.h>
+#include <isc/httpd.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/socket.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+/*%
+ * TODO:
+ *
+ * o Put in better checks to make certain things are passed in correctly.
+ * This includes a magic number for externally-visible structures,
+ * checking for NULL-ness before dereferencing, etc.
+ * o Make the URL processing external functions which will fill-in a buffer
+ * structure we provide, or return an error and we will render a generic
+ * page and close the client.
+ */
+
+#define MSHUTTINGDOWN(cm) ((cm->flags & ISC_HTTPDMGR_FLAGSHUTTINGDOWN) != 0)
+#define MSETSHUTTINGDOWN(cm) (cm->flags |= ISC_HTTPDMGR_FLAGSHUTTINGDOWN)
+
+#ifdef DEBUG_HTTPD
+#define ENTER(x) do { fprintf(stderr, "ENTER %s\n", (x)); } while (0)
+#define EXIT(x) do { fprintf(stderr, "EXIT %s\n", (x)); } while (0)
+#define NOTICE(x) do { fprintf(stderr, "NOTICE %s\n", (x)); } while (0)
+#else
+#define ENTER(x) do { } while(0)
+#define EXIT(x) do { } while(0)
+#define NOTICE(x) do { } while(0)
+#endif
+
+#define HTTP_RECVLEN 1024
+#define HTTP_SENDGROW 1024
+#define HTTP_SEND_MAXLEN 10240
+
+#define HTTPD_CLOSE 0x0001 /* Got a Connection: close header */
+#define HTTPD_FOUNDHOST 0x0002 /* Got a Host: header */
+#define HTTPD_KEEPALIVE 0x0004 /* Got a Connection: Keep-Alive */
+#define HTTPD_ACCEPT_DEFLATE 0x0008
+
+/*% http client */
+struct isc_httpd {
+ isc_httpdmgr_t *mgr; /*%< our parent */
+ ISC_LINK(isc_httpd_t) link;
+ unsigned int state;
+ isc_socket_t *sock;
+
+ /*%
+ * Received data state.
+ */
+ char recvbuf[HTTP_RECVLEN]; /*%< receive buffer */
+ uint32_t recvlen; /*%< length recv'd */
+ char *headers; /*%< set in process_request() */
+ unsigned int method;
+ char *url;
+ char *querystring;
+ char *protocol;
+
+ /*
+ * Flags on the httpd client.
+ */
+ int flags;
+
+ /*%
+ * Transmit data state.
+ *
+ * This is the data buffer we will transmit.
+ *
+ * This free function pointer is filled in by the rendering function
+ * we call. The free function is called after the data is transmitted
+ * to the client.
+ *
+ * The bufflist is the list of buffers we are currently transmitting.
+ * The headerbuffer is where we render our headers to. If we run out of
+ * space when rendering a header, we will change the size of our
+ * buffer. We will not free it until we are finished, and will
+ * allocate an additional HTTP_SENDGROW bytes per header space grow.
+ *
+ * We currently use three buffers total, one for the headers (which
+ * we manage), another for the client to fill in (which it manages,
+ * it provides the space for it, etc) -- we will pass that buffer
+ * structure back to the caller, who is responsible for managing the
+ * space it may have allocated as backing store for it. This second
+ * buffer is bodybuffer, and we only allocate the buffer itself, not
+ * the backing store.
+ * The third buffer is compbuffer, managed by us, that contains the
+ * compressed HTTP data, if compression is used.
+ *
+ */
+ isc_bufferlist_t bufflist;
+ isc_buffer_t headerbuffer;
+ isc_buffer_t compbuffer;
+
+ const char *mimetype;
+ unsigned int retcode;
+ const char *retmsg;
+ isc_buffer_t bodybuffer;
+ isc_httpdfree_t *freecb;
+ void *freecb_arg;
+};
+
+/*% lightweight socket manager for httpd output */
+struct isc_httpdmgr {
+ isc_mem_t *mctx;
+ isc_socket_t *sock; /*%< listening socket */
+ isc_task_t *task; /*%< owning task */
+ isc_timermgr_t *timermgr;
+
+ isc_httpdclientok_t *client_ok; /*%< client validator */
+ isc_httpdondestroy_t *ondestroy; /*%< cleanup callback */
+ void *cb_arg; /*%< argument for the above */
+
+ unsigned int flags;
+ ISC_LIST(isc_httpd_t) running; /*%< running clients */
+
+ isc_mutex_t lock;
+
+ ISC_LIST(isc_httpdurl_t) urls; /*%< urls we manage */
+ isc_httpdaction_t *render_404;
+ isc_httpdaction_t *render_500;
+};
+
+/*%
+ * HTTP methods.
+ */
+#define ISC_HTTPD_METHODUNKNOWN 0
+#define ISC_HTTPD_METHODGET 1
+#define ISC_HTTPD_METHODPOST 2
+
+/*%
+ * Client states.
+ *
+ * _IDLE The client is not doing anything at all. This state should
+ * only occur just after creation, and just before being
+ * destroyed.
+ *
+ * _RECV The client is waiting for data after issuing a socket recv().
+ *
+ * _RECVDONE Data has been received, and is being processed.
+ *
+ * _SEND All data for a response has completed, and a reply was
+ * sent via a socket send() call.
+ *
+ * _SENDDONE Send is completed.
+ *
+ * Badly formatted state table:
+ *
+ * IDLE -> RECV when client has a recv() queued.
+ *
+ * RECV -> RECVDONE when recvdone event received.
+ *
+ * RECVDONE -> SEND if the data for a reply is at hand.
+ *
+ * SEND -> RECV when a senddone event was received.
+ *
+ * At any time -> RECV on error. If RECV fails, the client will
+ * self-destroy, closing the socket and freeing memory.
+ */
+#define ISC_HTTPD_STATEIDLE 0
+#define ISC_HTTPD_STATERECV 1
+#define ISC_HTTPD_STATERECVDONE 2
+#define ISC_HTTPD_STATESEND 3
+#define ISC_HTTPD_STATESENDDONE 4
+
+#define ISC_HTTPD_ISRECV(c) ((c)->state == ISC_HTTPD_STATERECV)
+#define ISC_HTTPD_ISRECVDONE(c) ((c)->state == ISC_HTTPD_STATERECVDONE)
+#define ISC_HTTPD_ISSEND(c) ((c)->state == ISC_HTTPD_STATESEND)
+#define ISC_HTTPD_ISSENDDONE(c) ((c)->state == ISC_HTTPD_STATESENDDONE)
+
+/*%
+ * Overall magic test that means we're not idle.
+ */
+#define ISC_HTTPD_SETRECV(c) ((c)->state = ISC_HTTPD_STATERECV)
+#define ISC_HTTPD_SETRECVDONE(c) ((c)->state = ISC_HTTPD_STATERECVDONE)
+#define ISC_HTTPD_SETSEND(c) ((c)->state = ISC_HTTPD_STATESEND)
+#define ISC_HTTPD_SETSENDDONE(c) ((c)->state = ISC_HTTPD_STATESENDDONE)
+
+static void isc_httpd_accept(isc_task_t *, isc_event_t *);
+static void isc_httpd_recvdone(isc_task_t *, isc_event_t *);
+static void isc_httpd_senddone(isc_task_t *, isc_event_t *);
+static void destroy_client(isc_httpd_t **);
+static isc_result_t process_request(isc_httpd_t *, int);
+static void httpdmgr_destroy(isc_httpdmgr_t *);
+static isc_result_t grow_headerspace(isc_httpd_t *);
+static void reset_client(isc_httpd_t *httpd);
+
+static isc_httpdaction_t render_404;
+static isc_httpdaction_t render_500;
+
+static void (*finishhook)(void) = NULL;
+
+static void
+destroy_client(isc_httpd_t **httpdp) {
+ isc_httpd_t *httpd = *httpdp;
+ isc_httpdmgr_t *httpdmgr = httpd->mgr;
+ isc_region_t r;
+
+ *httpdp = NULL;
+
+ LOCK(&httpdmgr->lock);
+
+ isc_socket_detach(&httpd->sock);
+ ISC_LIST_UNLINK(httpdmgr->running, httpd, link);
+
+ isc_buffer_region(&httpd->headerbuffer, &r);
+ if (r.length > 0) {
+ isc_mem_put(httpdmgr->mctx, r.base, r.length);
+ }
+
+ isc_buffer_region(&httpd->compbuffer, &r);
+ if (r.length > 0) {
+ isc_mem_put(httpdmgr->mctx, r.base, r.length);
+ }
+
+ isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t));
+
+ UNLOCK(&httpdmgr->lock);
+
+ if (finishhook != NULL)
+ finishhook();
+
+ httpdmgr_destroy(httpdmgr);
+}
+
+isc_result_t
+isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
+ isc_httpdclientok_t *client_ok,
+ isc_httpdondestroy_t *ondestroy, void *cb_arg,
+ isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdmgrp)
+{
+ isc_result_t result;
+ isc_httpdmgr_t *httpdmgr;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(sock != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(tmgr != NULL);
+ REQUIRE(httpdmgrp != NULL && *httpdmgrp == NULL);
+
+ httpdmgr = isc_mem_get(mctx, sizeof(isc_httpdmgr_t));
+ if (httpdmgr == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = isc_mutex_init(&httpdmgr->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, httpdmgr, sizeof(isc_httpdmgr_t));
+ return (result);
+ }
+ httpdmgr->mctx = NULL;
+ isc_mem_attach(mctx, &httpdmgr->mctx);
+ httpdmgr->sock = NULL;
+ isc_socket_attach(sock, &httpdmgr->sock);
+ httpdmgr->task = NULL;
+ isc_task_attach(task, &httpdmgr->task);
+ httpdmgr->timermgr = tmgr; /* XXXMLG no attach function? */
+ httpdmgr->client_ok = client_ok;
+ httpdmgr->ondestroy = ondestroy;
+ httpdmgr->cb_arg = cb_arg;
+ httpdmgr->flags = 0;
+
+ ISC_LIST_INIT(httpdmgr->running);
+ ISC_LIST_INIT(httpdmgr->urls);
+
+ /* XXXMLG ignore errors on isc_socket_listen() */
+ result = isc_socket_listen(sock, SOMAXCONN);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_socket_listen() failed: %s",
+ isc_result_totext(result));
+ goto cleanup;
+ }
+
+ (void)isc_socket_filter(sock, "httpready");
+
+ result = isc_socket_accept(sock, task, isc_httpd_accept, httpdmgr);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ httpdmgr->render_404 = render_404;
+ httpdmgr->render_500 = render_500;
+
+ *httpdmgrp = httpdmgr;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ isc_task_detach(&httpdmgr->task);
+ isc_socket_detach(&httpdmgr->sock);
+ isc_mem_detach(&httpdmgr->mctx);
+ (void)isc_mutex_destroy(&httpdmgr->lock);
+ isc_mem_put(mctx, httpdmgr, sizeof(isc_httpdmgr_t));
+ return (result);
+}
+
+static void
+httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) {
+ isc_mem_t *mctx;
+ isc_httpdurl_t *url;
+
+ ENTER("httpdmgr_destroy");
+
+ LOCK(&httpdmgr->lock);
+
+ if (!MSHUTTINGDOWN(httpdmgr)) {
+ NOTICE("httpdmgr_destroy not shutting down yet");
+ UNLOCK(&httpdmgr->lock);
+ return;
+ }
+
+ /*
+ * If all clients are not shut down, don't do anything yet.
+ */
+ if (!ISC_LIST_EMPTY(httpdmgr->running)) {
+ NOTICE("httpdmgr_destroy clients still active");
+ UNLOCK(&httpdmgr->lock);
+ return;
+ }
+
+ NOTICE("httpdmgr_destroy detaching socket, task, and timermgr");
+
+ isc_socket_detach(&httpdmgr->sock);
+ isc_task_detach(&httpdmgr->task);
+ httpdmgr->timermgr = NULL;
+
+ /*
+ * Clear out the list of all actions we know about. Just free the
+ * memory.
+ */
+ url = ISC_LIST_HEAD(httpdmgr->urls);
+ while (url != NULL) {
+ isc_mem_free(httpdmgr->mctx, url->url);
+ ISC_LIST_UNLINK(httpdmgr->urls, url, link);
+ isc_mem_put(httpdmgr->mctx, url, sizeof(isc_httpdurl_t));
+ url = ISC_LIST_HEAD(httpdmgr->urls);
+ }
+
+ UNLOCK(&httpdmgr->lock);
+ (void)isc_mutex_destroy(&httpdmgr->lock);
+
+ if (httpdmgr->ondestroy != NULL)
+ (httpdmgr->ondestroy)(httpdmgr->cb_arg);
+
+ mctx = httpdmgr->mctx;
+ isc_mem_putanddetach(&mctx, httpdmgr, sizeof(isc_httpdmgr_t));
+
+ EXIT("httpdmgr_destroy");
+}
+
+#define LENGTHOK(s) (httpd->recvbuf - (s) < (int)httpd->recvlen)
+#define BUFLENOK(s) (httpd->recvbuf - (s) < HTTP_RECVLEN)
+
+/*
+ * Look for the given header in headers.
+ * If value is specified look for it terminated with a character in eov.
+ */
+static bool
+have_header(isc_httpd_t *httpd, const char *header, const char *value,
+ const char *eov)
+{
+ char *cr, *nl, *h;
+ size_t hlen, vlen = 0;
+
+ h = httpd->headers;
+ hlen = strlen(header);
+ if (value != NULL) {
+ INSIST(eov != NULL);
+ vlen = strlen(value);
+ }
+
+ for (;;) {
+ if (strncasecmp(h, header, hlen) != 0) {
+ /*
+ * Skip to next line;
+ */
+ cr = strchr(h, '\r');
+ if (cr != NULL && cr[1] == '\n')
+ cr++;
+ nl = strchr(h, '\n');
+
+ /* last header? */
+ h = cr;
+ if (h == NULL || (nl != NULL && nl < h))
+ h = nl;
+ if (h == NULL)
+ return (false);
+ h++;
+ continue;
+ }
+
+ if (value == NULL)
+ return (true);
+
+ /*
+ * Skip optional leading white space.
+ */
+ h += hlen;
+ while (*h == ' ' || *h == '\t')
+ h++;
+ /*
+ * Terminate token search on NULL or EOL.
+ */
+ while (*h != 0 && *h != '\r' && *h != '\n') {
+ if (strncasecmp(h, value, vlen) == 0)
+ if (strchr(eov, h[vlen]) != NULL)
+ return (true);
+ /*
+ * Skip to next token.
+ */
+ h += strcspn(h, eov);
+ if (h[0] == '\r' && h[1] == '\n')
+ h++;
+ if (h[0] != 0)
+ h++;
+ }
+ return (false);
+ }
+}
+
+static isc_result_t
+process_request(isc_httpd_t *httpd, int length) {
+ char *s;
+ char *p;
+ int delim;
+
+ ENTER("request");
+
+ httpd->recvlen += length;
+
+ httpd->recvbuf[httpd->recvlen] = 0;
+ httpd->headers = NULL;
+
+ /*
+ * If we don't find a blank line in our buffer, return that we need
+ * more data.
+ */
+ s = strstr(httpd->recvbuf, "\r\n\r\n");
+ delim = 2;
+ if (s == NULL) {
+ s = strstr(httpd->recvbuf, "\n\n");
+ delim = 1;
+ }
+ if (s == NULL)
+ return (ISC_R_NOTFOUND);
+
+ /*
+ * NUL terminate request at the blank line.
+ */
+ s[delim] = 0;
+
+ /*
+ * Determine if this is a POST or GET method. Any other values will
+ * cause an error to be returned.
+ */
+ if (strncmp(httpd->recvbuf, "GET ", 4) == 0) {
+ httpd->method = ISC_HTTPD_METHODGET;
+ p = httpd->recvbuf + 4;
+ } else if (strncmp(httpd->recvbuf, "POST ", 5) == 0) {
+ httpd->method = ISC_HTTPD_METHODPOST;
+ p = httpd->recvbuf + 5;
+ } else {
+ return (ISC_R_RANGE);
+ }
+
+ /*
+ * From now on, p is the start of our buffer.
+ */
+
+ /*
+ * Extract the URL.
+ */
+ s = p;
+ while (LENGTHOK(s) && BUFLENOK(s) &&
+ (*s != '\n' && *s != '\r' && *s != '\0' && *s != ' '))
+ s++;
+ if (!LENGTHOK(s))
+ return (ISC_R_NOTFOUND);
+ if (!BUFLENOK(s))
+ return (ISC_R_NOMEMORY);
+ *s = 0;
+
+ /*
+ * Make the URL relative.
+ */
+ if ((strncmp(p, "http:/", 6) == 0)
+ || (strncmp(p, "https:/", 7) == 0)) {
+ /* Skip first / */
+ while (*p != '/' && *p != 0)
+ p++;
+ if (*p == 0)
+ return (ISC_R_RANGE);
+ p++;
+ /* Skip second / */
+ while (*p != '/' && *p != 0)
+ p++;
+ if (*p == 0)
+ return (ISC_R_RANGE);
+ p++;
+ /* Find third / */
+ while (*p != '/' && *p != 0)
+ p++;
+ if (*p == 0) {
+ p--;
+ *p = '/';
+ }
+ }
+
+ httpd->url = p;
+ p = s + 1;
+ s = p;
+
+ /*
+ * Now, see if there is a ? mark in the URL. If so, this is
+ * part of the query string, and we will split it from the URL.
+ */
+ httpd->querystring = strchr(httpd->url, '?');
+ if (httpd->querystring != NULL) {
+ *(httpd->querystring) = 0;
+ httpd->querystring++;
+ }
+
+ /*
+ * Extract the HTTP/1.X protocol. We will bounce on anything but
+ * HTTP/1.0 or HTTP/1.1 for now.
+ */
+ while (LENGTHOK(s) && BUFLENOK(s) &&
+ (*s != '\n' && *s != '\r' && *s != '\0'))
+ s++;
+ if (!LENGTHOK(s))
+ return (ISC_R_NOTFOUND);
+ if (!BUFLENOK(s))
+ return (ISC_R_NOMEMORY);
+ /*
+ * Check that we have the expected eol delimiter.
+ */
+ if (strncmp(s, delim == 1 ? "\n" : "\r\n", delim) != 0)
+ return (ISC_R_RANGE);
+ *s = 0;
+ if ((strncmp(p, "HTTP/1.0", 8) != 0)
+ && (strncmp(p, "HTTP/1.1", 8) != 0))
+ return (ISC_R_RANGE);
+ httpd->protocol = p;
+ p = s + delim; /* skip past eol */
+ s = p;
+
+ httpd->headers = s;
+
+ if (have_header(httpd, "Connection:", "close", ", \t\r\n"))
+ httpd->flags |= HTTPD_CLOSE;
+
+ if (have_header(httpd, "Host:", NULL, NULL))
+ httpd->flags |= HTTPD_FOUNDHOST;
+
+ if (strncmp(httpd->protocol, "HTTP/1.0", 8) == 0) {
+ if (have_header(httpd, "Connection:", "Keep-Alive",
+ ", \t\r\n"))
+ httpd->flags |= HTTPD_KEEPALIVE;
+ else
+ httpd->flags |= HTTPD_CLOSE;
+ }
+
+ /*
+ * Check for Accept-Encoding:
+ */
+#ifdef HAVE_ZLIB
+ if (have_header(httpd, "Accept-Encoding:", "deflate", ";, \t\r\n"))
+ httpd->flags |= HTTPD_ACCEPT_DEFLATE;
+#endif
+
+ /*
+ * Standards compliance hooks here.
+ */
+ if (strcmp(httpd->protocol, "HTTP/1.1") == 0
+ && ((httpd->flags & HTTPD_FOUNDHOST) == 0))
+ return (ISC_R_RANGE);
+
+ EXIT("request");
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+isc_httpd_accept(isc_task_t *task, isc_event_t *ev) {
+ isc_result_t result;
+ isc_httpdmgr_t *httpdmgr = ev->ev_arg;
+ isc_httpd_t *httpd;
+ isc_region_t r;
+ isc_socket_newconnev_t *nev = (isc_socket_newconnev_t *)ev;
+ isc_sockaddr_t peeraddr;
+ char *headerdata;
+
+ ENTER("accept");
+
+ LOCK(&httpdmgr->lock);
+ if (MSHUTTINGDOWN(httpdmgr)) {
+ NOTICE("accept shutting down, goto out");
+ goto out;
+ }
+
+ if (nev->result == ISC_R_CANCELED) {
+ NOTICE("accept canceled, goto out");
+ goto out;
+ }
+
+ if (nev->result != ISC_R_SUCCESS) {
+ /* XXXMLG log failure */
+ NOTICE("accept returned failure, goto requeue");
+ goto requeue;
+ }
+
+ (void)isc_socket_getpeername(nev->newsocket, &peeraddr);
+ if (httpdmgr->client_ok != NULL &&
+ !(httpdmgr->client_ok)(&peeraddr, httpdmgr->cb_arg)) {
+ isc_socket_detach(&nev->newsocket);
+ goto requeue;
+ }
+
+ httpd = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpd_t));
+ if (httpd == NULL) {
+ /* XXXMLG log failure */
+ NOTICE("accept failed to allocate memory, goto requeue");
+ isc_socket_detach(&nev->newsocket);
+ goto requeue;
+ }
+
+ httpd->mgr = httpdmgr;
+ ISC_LINK_INIT(httpd, link);
+ ISC_LIST_APPEND(httpdmgr->running, httpd, link);
+ ISC_HTTPD_SETRECV(httpd);
+ httpd->sock = nev->newsocket;
+ isc_socket_setname(httpd->sock, "httpd", NULL);
+ httpd->flags = 0;
+
+ /*
+ * Initialize the buffer for our headers.
+ */
+ headerdata = isc_mem_get(httpdmgr->mctx, HTTP_SENDGROW);
+ if (headerdata == NULL) {
+ isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t));
+ isc_socket_detach(&nev->newsocket);
+ goto requeue;
+ }
+ isc_buffer_init(&httpd->headerbuffer, headerdata, HTTP_SENDGROW);
+
+ ISC_LIST_INIT(httpd->bufflist);
+
+ isc_buffer_initnull(&httpd->compbuffer);
+ isc_buffer_initnull(&httpd->bodybuffer);
+ reset_client(httpd);
+
+ r.base = (unsigned char *)httpd->recvbuf;
+ r.length = HTTP_RECVLEN - 1;
+ result = isc_socket_recv(httpd->sock, &r, 1, task, isc_httpd_recvdone,
+ httpd);
+ /* FIXME!!! */
+ POST(result);
+ NOTICE("accept queued recv on socket");
+
+ requeue:
+ result = isc_socket_accept(httpdmgr->sock, task, isc_httpd_accept,
+ httpdmgr);
+ if (result != ISC_R_SUCCESS) {
+ /* XXXMLG what to do? Log failure... */
+ NOTICE("accept could not reaccept due to failure");
+ }
+
+ out:
+ UNLOCK(&httpdmgr->lock);
+
+ httpdmgr_destroy(httpdmgr);
+
+ isc_event_free(&ev);
+
+ EXIT("accept");
+}
+
+static isc_result_t
+render_404(const char *url, isc_httpdurl_t *urlinfo,
+ const char *querystring, const char *headers, void *arg,
+ unsigned int *retcode, const char **retmsg,
+ const char **mimetype, isc_buffer_t *b,
+ isc_httpdfree_t **freecb, void **freecb_args)
+{
+ static char msg[] = "No such URL.\r\n";
+
+ UNUSED(url);
+ UNUSED(urlinfo);
+ UNUSED(querystring);
+ UNUSED(headers);
+ UNUSED(arg);
+
+ *retcode = 404;
+ *retmsg = "No such URL";
+ *mimetype = "text/plain";
+ isc_buffer_reinit(b, msg, strlen(msg));
+ isc_buffer_add(b, strlen(msg));
+ *freecb = NULL;
+ *freecb_args = NULL;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+render_500(const char *url, isc_httpdurl_t *urlinfo,
+ const char *querystring, const char *headers, void *arg,
+ unsigned int *retcode, const char **retmsg,
+ const char **mimetype, isc_buffer_t *b,
+ isc_httpdfree_t **freecb, void **freecb_args)
+{
+ static char msg[] = "Internal server failure.\r\n";
+
+ UNUSED(url);
+ UNUSED(urlinfo);
+ UNUSED(querystring);
+ UNUSED(headers);
+ UNUSED(arg);
+
+ *retcode = 500;
+ *retmsg = "Internal server failure";
+ *mimetype = "text/plain";
+ isc_buffer_reinit(b, msg, strlen(msg));
+ isc_buffer_add(b, strlen(msg));
+ *freecb = NULL;
+ *freecb_args = NULL;
+
+ return (ISC_R_SUCCESS);
+}
+
+#ifdef HAVE_ZLIB
+/*%<
+ * Reallocates compbuffer to size, does nothing if compbuffer is already
+ * larger than size.
+ *
+ * Requires:
+ *\li httpd a valid isc_httpd_t object
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- all is well.
+ *\li #ISC_R_NOMEMORY -- not enough memory to extend buffer
+ */
+static isc_result_t
+alloc_compspace(isc_httpd_t *httpd, unsigned int size) {
+ char *newspace;
+ isc_region_t r;
+
+ isc_buffer_region(&httpd->compbuffer, &r);
+ if (size < r.length) {
+ return (ISC_R_SUCCESS);
+ }
+
+ newspace = isc_mem_get(httpd->mgr->mctx, size);
+ if (newspace == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_buffer_reinit(&httpd->compbuffer, newspace, size);
+
+ if (r.base != NULL) {
+ isc_mem_put(httpd->mgr->mctx, r.base, r.length);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*%<
+ * Tries to compress httpd->bodybuffer to httpd->compbuffer, extending it
+ * if necessary.
+ *
+ * Requires:
+ *\li httpd a valid isc_httpd_t object
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- all is well.
+ *\li #ISC_R_NOMEMORY -- not enough memory to compress data
+ *\li #ISC_R_FAILURE -- error during compression or compressed
+ * data would be larger than input data
+ */
+static isc_result_t
+isc_httpd_compress(isc_httpd_t *httpd) {
+ z_stream zstr;
+ isc_region_t r;
+ isc_result_t result;
+ int ret;
+ int inputlen;
+
+ inputlen = isc_buffer_usedlength(&httpd->bodybuffer);
+ result = alloc_compspace(httpd, inputlen);
+ if (result != ISC_R_SUCCESS) {
+ return result;
+ }
+ isc_buffer_region(&httpd->compbuffer, &r);
+
+ /*
+ * We're setting output buffer size to input size so it fails if the
+ * compressed data size would be bigger than the input size.
+ */
+ memset(&zstr, 0, sizeof(zstr));
+ zstr.total_in = zstr.avail_in =
+ zstr.total_out = zstr.avail_out = inputlen;
+
+ zstr.next_in = isc_buffer_base(&httpd->bodybuffer);
+ zstr.next_out = r.base;
+
+ ret = deflateInit(&zstr, Z_DEFAULT_COMPRESSION);
+ if (ret == Z_OK) {
+ ret = deflate(&zstr, Z_FINISH);
+ }
+ deflateEnd(&zstr);
+ if (ret == Z_STREAM_END) {
+ isc_buffer_add(&httpd->compbuffer, inputlen - zstr.avail_out);
+ return (ISC_R_SUCCESS);
+ } else {
+ return (ISC_R_FAILURE);
+ }
+}
+#endif
+
+static void
+isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
+ isc_region_t r;
+ isc_result_t result;
+ isc_httpd_t *httpd = ev->ev_arg;
+ isc_socketevent_t *sev = (isc_socketevent_t *)ev;
+ isc_httpdurl_t *url;
+ isc_time_t now;
+ bool is_compressed = false;
+ char datebuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
+
+ ENTER("recv");
+
+ INSIST(ISC_HTTPD_ISRECV(httpd));
+
+ if (sev->result != ISC_R_SUCCESS) {
+ NOTICE("recv destroying client");
+ destroy_client(&httpd);
+ goto out;
+ }
+
+ result = process_request(httpd, sev->n);
+ if (result == ISC_R_NOTFOUND) {
+ if (httpd->recvlen >= HTTP_RECVLEN - 1) {
+ destroy_client(&httpd);
+ goto out;
+ }
+ r.base = (unsigned char *)httpd->recvbuf + httpd->recvlen;
+ r.length = HTTP_RECVLEN - httpd->recvlen - 1;
+ /* check return code? */
+ (void)isc_socket_recv(httpd->sock, &r, 1, task,
+ isc_httpd_recvdone, httpd);
+ goto out;
+ } else if (result != ISC_R_SUCCESS) {
+ destroy_client(&httpd);
+ goto out;
+ }
+
+ ISC_HTTPD_SETSEND(httpd);
+
+ /*
+ * XXXMLG Call function here. Provide an add-header function
+ * which will append the common headers to a response we generate.
+ */
+ isc_buffer_initnull(&httpd->bodybuffer);
+ isc_time_now(&now);
+ isc_time_formathttptimestamp(&now, datebuf, sizeof(datebuf));
+ url = ISC_LIST_HEAD(httpd->mgr->urls);
+ while (url != NULL) {
+ if (strcmp(httpd->url, url->url) == 0)
+ break;
+ url = ISC_LIST_NEXT(url, link);
+ }
+ if (url == NULL)
+ result = httpd->mgr->render_404(httpd->url, NULL,
+ httpd->querystring,
+ NULL, NULL,
+ &httpd->retcode,
+ &httpd->retmsg,
+ &httpd->mimetype,
+ &httpd->bodybuffer,
+ &httpd->freecb,
+ &httpd->freecb_arg);
+ else
+ result = url->action(httpd->url, url,
+ httpd->querystring,
+ httpd->headers,
+ url->action_arg,
+ &httpd->retcode, &httpd->retmsg,
+ &httpd->mimetype, &httpd->bodybuffer,
+ &httpd->freecb, &httpd->freecb_arg);
+ if (result != ISC_R_SUCCESS) {
+ result = httpd->mgr->render_500(httpd->url, url,
+ httpd->querystring,
+ NULL, NULL,
+ &httpd->retcode,
+ &httpd->retmsg,
+ &httpd->mimetype,
+ &httpd->bodybuffer,
+ &httpd->freecb,
+ &httpd->freecb_arg);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ }
+
+#ifdef HAVE_ZLIB
+ if (httpd->flags & HTTPD_ACCEPT_DEFLATE) {
+ result = isc_httpd_compress(httpd);
+ if (result == ISC_R_SUCCESS) {
+ is_compressed = true;
+ }
+ }
+#endif
+
+ isc_httpd_response(httpd);
+ if ((httpd->flags & HTTPD_KEEPALIVE) != 0)
+ isc_httpd_addheader(httpd, "Connection", "Keep-Alive");
+ isc_httpd_addheader(httpd, "Content-Type", httpd->mimetype);
+ isc_httpd_addheader(httpd, "Date", datebuf);
+ isc_httpd_addheader(httpd, "Expires", datebuf);
+
+ if (url != NULL && url->isstatic) {
+ char loadbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
+ isc_time_formathttptimestamp(&url->loadtime,
+ loadbuf, sizeof(loadbuf));
+ isc_httpd_addheader(httpd, "Last-Modified", loadbuf);
+ isc_httpd_addheader(httpd, "Cache-Control: public", NULL);
+ } else {
+ isc_httpd_addheader(httpd, "Last-Modified", datebuf);
+ isc_httpd_addheader(httpd, "Pragma: no-cache", NULL);
+ isc_httpd_addheader(httpd, "Cache-Control: no-cache", NULL);
+ }
+
+ isc_httpd_addheader(httpd, "Server: libisc", NULL);
+
+ if (is_compressed == true) {
+ isc_httpd_addheader(httpd, "Content-Encoding", "deflate");
+ isc_httpd_addheaderuint(httpd, "Content-Length",
+ isc_buffer_usedlength(&httpd->compbuffer));
+ } else {
+ isc_httpd_addheaderuint(httpd, "Content-Length",
+ isc_buffer_usedlength(&httpd->bodybuffer));
+ }
+
+ isc_httpd_endheaders(httpd); /* done */
+
+ ISC_LIST_APPEND(httpd->bufflist, &httpd->headerbuffer, link);
+ /*
+ * Link the data buffer into our send queue, should we have any data
+ * rendered into it. If no data is present, we won't do anything
+ * with the buffer.
+ */
+ if (is_compressed == true) {
+ ISC_LIST_APPEND(httpd->bufflist, &httpd->compbuffer, link);
+ } else {
+ if (isc_buffer_length(&httpd->bodybuffer) > 0) {
+ ISC_LIST_APPEND(httpd->bufflist, &httpd->bodybuffer, link);
+ }
+ }
+
+ /* check return code? */
+ (void)isc_socket_sendv(httpd->sock, &httpd->bufflist, task,
+ isc_httpd_senddone, httpd);
+
+ out:
+ isc_event_free(&ev);
+ EXIT("recv");
+}
+
+void
+isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) {
+ isc_httpdmgr_t *httpdmgr;
+ isc_httpd_t *httpd;
+ httpdmgr = *httpdmgrp;
+ *httpdmgrp = NULL;
+
+ ENTER("isc_httpdmgr_shutdown");
+
+ LOCK(&httpdmgr->lock);
+
+ MSETSHUTTINGDOWN(httpdmgr);
+
+ isc_socket_cancel(httpdmgr->sock, httpdmgr->task, ISC_SOCKCANCEL_ALL);
+
+ httpd = ISC_LIST_HEAD(httpdmgr->running);
+ while (httpd != NULL) {
+ isc_socket_cancel(httpd->sock, httpdmgr->task,
+ ISC_SOCKCANCEL_ALL);
+ httpd = ISC_LIST_NEXT(httpd, link);
+ }
+
+ UNLOCK(&httpdmgr->lock);
+
+ EXIT("isc_httpdmgr_shutdown");
+}
+
+static isc_result_t
+grow_headerspace(isc_httpd_t *httpd) {
+ char *newspace;
+ unsigned int newlen;
+ isc_region_t r;
+
+ isc_buffer_region(&httpd->headerbuffer, &r);
+ newlen = r.length + HTTP_SENDGROW;
+ if (newlen > HTTP_SEND_MAXLEN)
+ return (ISC_R_NOSPACE);
+
+ newspace = isc_mem_get(httpd->mgr->mctx, newlen);
+ if (newspace == NULL)
+ return (ISC_R_NOMEMORY);
+
+ isc_buffer_reinit(&httpd->headerbuffer, newspace, newlen);
+
+ isc_mem_put(httpd->mgr->mctx, r.base, r.length);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_httpd_response(isc_httpd_t *httpd) {
+ isc_result_t result;
+ unsigned int needlen;
+
+ needlen = strlen(httpd->protocol) + 1; /* protocol + space */
+ needlen += 3 + 1; /* room for response code, always 3 bytes */
+ needlen += strlen(httpd->retmsg) + 2; /* return msg + CRLF */
+
+ while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
+ result = grow_headerspace(httpd);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ snprintf(isc_buffer_used(&httpd->headerbuffer),
+ (int)isc_buffer_availablelength(&httpd->headerbuffer),
+ "%s %03u %s\r\n", httpd->protocol, httpd->retcode,
+ httpd->retmsg);
+ isc_buffer_add(&httpd->headerbuffer, needlen);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_httpd_addheader(isc_httpd_t *httpd, const char *name,
+ const char *val)
+{
+ isc_result_t result;
+ unsigned int needlen;
+
+ needlen = strlen(name); /* name itself */
+ if (val != NULL)
+ needlen += 2 + strlen(val); /* :<space> and val */
+ needlen += 2; /* CRLF */
+
+ while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
+ result = grow_headerspace(httpd);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ if (val != NULL)
+ snprintf(isc_buffer_used(&httpd->headerbuffer),
+ isc_buffer_availablelength(&httpd->headerbuffer),
+ "%s: %s\r\n", name, val);
+ else
+ snprintf(isc_buffer_used(&httpd->headerbuffer),
+ isc_buffer_availablelength(&httpd->headerbuffer),
+ "%s\r\n", name);
+
+ isc_buffer_add(&httpd->headerbuffer, needlen);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_httpd_endheaders(isc_httpd_t *httpd) {
+ isc_result_t result;
+
+ while (isc_buffer_availablelength(&httpd->headerbuffer) < 2) {
+ result = grow_headerspace(httpd);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ snprintf(isc_buffer_used(&httpd->headerbuffer),
+ isc_buffer_availablelength(&httpd->headerbuffer), "\r\n");
+ isc_buffer_add(&httpd->headerbuffer, 2);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val) {
+ isc_result_t result;
+ unsigned int needlen;
+ char buf[sizeof "18446744073709551616"];
+
+ snprintf(buf, sizeof(buf), "%d", val);
+
+ needlen = strlen(name); /* name itself */
+ needlen += 2 + strlen(buf); /* :<space> and val */
+ needlen += 2; /* CRLF */
+
+ while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
+ result = grow_headerspace(httpd);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ snprintf(isc_buffer_used(&httpd->headerbuffer),
+ isc_buffer_availablelength(&httpd->headerbuffer),
+ "%s: %s\r\n", name, buf);
+
+ isc_buffer_add(&httpd->headerbuffer, needlen);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) {
+ isc_httpd_t *httpd = ev->ev_arg;
+ isc_region_t r;
+ isc_socketevent_t *sev = (isc_socketevent_t *)ev;
+
+ ENTER("senddone");
+ INSIST(ISC_HTTPD_ISSEND(httpd));
+
+ /*
+ * First, unlink our header buffer from the socket's bufflist. This
+ * is sort of an evil hack, since we know our buffer will be there,
+ * and we know it's address, so we can just remove it directly.
+ */
+ NOTICE("senddone unlinked header");
+ ISC_LIST_UNLINK(sev->bufferlist, &httpd->headerbuffer, link);
+
+ /*
+ * We will always want to clean up our receive buffer, even if we
+ * got an error on send or we are shutting down.
+ *
+ * We will pass in the buffer only if there is data in it. If
+ * there is no data, we will pass in a NULL.
+ */
+ if (httpd->freecb != NULL) {
+ isc_buffer_t *b = NULL;
+ if (isc_buffer_length(&httpd->bodybuffer) > 0) {
+ b = &httpd->bodybuffer;
+ httpd->freecb(b, httpd->freecb_arg);
+ }
+ NOTICE("senddone free callback performed");
+ }
+ if (ISC_LINK_LINKED(&httpd->bodybuffer, link)) {
+ ISC_LIST_UNLINK(sev->bufferlist, &httpd->bodybuffer, link);
+ NOTICE("senddone body buffer unlinked");
+ } else if (ISC_LINK_LINKED(&httpd->compbuffer, link)) {
+ ISC_LIST_UNLINK(sev->bufferlist, &httpd->compbuffer, link);
+ NOTICE("senddone compressed data unlinked and freed");
+ }
+
+ if (sev->result != ISC_R_SUCCESS) {
+ destroy_client(&httpd);
+ goto out;
+ }
+
+ if ((httpd->flags & HTTPD_CLOSE) != 0) {
+ destroy_client(&httpd);
+ goto out;
+ }
+
+ ISC_HTTPD_SETRECV(httpd);
+
+ NOTICE("senddone restarting recv on socket");
+
+ reset_client(httpd);
+
+ r.base = (unsigned char *)httpd->recvbuf;
+ r.length = HTTP_RECVLEN - 1;
+ /* check return code? */
+ (void)isc_socket_recv(httpd->sock, &r, 1, task,
+ isc_httpd_recvdone, httpd);
+
+out:
+ isc_event_free(&ev);
+ EXIT("senddone");
+}
+
+static void
+reset_client(isc_httpd_t *httpd) {
+ /*
+ * Catch errors here. We MUST be in RECV mode, and we MUST NOT have
+ * any outstanding buffers. If we have buffers, we have a leak.
+ */
+ INSIST(ISC_HTTPD_ISRECV(httpd));
+ INSIST(!ISC_LINK_LINKED(&httpd->headerbuffer, link));
+ INSIST(!ISC_LINK_LINKED(&httpd->bodybuffer, link));
+
+ httpd->recvbuf[0] = 0;
+ httpd->recvlen = 0;
+ httpd->headers = NULL;
+ httpd->method = ISC_HTTPD_METHODUNKNOWN;
+ httpd->url = NULL;
+ httpd->querystring = NULL;
+ httpd->protocol = NULL;
+ httpd->flags = 0;
+
+ isc_buffer_clear(&httpd->headerbuffer);
+ isc_buffer_clear(&httpd->compbuffer);
+ isc_buffer_invalidate(&httpd->bodybuffer);
+}
+
+isc_result_t
+isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url,
+ isc_httpdaction_t *func, void *arg)
+{
+ return (isc_httpdmgr_addurl2(httpdmgr, url, false, func, arg));
+}
+
+isc_result_t
+isc_httpdmgr_addurl2(isc_httpdmgr_t *httpdmgr, const char *url,
+ bool isstatic,
+ isc_httpdaction_t *func, void *arg)
+{
+ isc_httpdurl_t *item;
+
+ if (url == NULL) {
+ httpdmgr->render_404 = func;
+ return (ISC_R_SUCCESS);
+ }
+
+ item = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpdurl_t));
+ if (item == NULL)
+ return (ISC_R_NOMEMORY);
+
+ item->url = isc_mem_strdup(httpdmgr->mctx, url);
+ if (item->url == NULL) {
+ isc_mem_put(httpdmgr->mctx, item, sizeof(isc_httpdurl_t));
+ return (ISC_R_NOMEMORY);
+ }
+
+ item->action = func;
+ item->action_arg = arg;
+ item->isstatic = isstatic;
+ isc_time_now(&item->loadtime);
+
+ ISC_LINK_INIT(item, link);
+ ISC_LIST_APPEND(httpdmgr->urls, item, link);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_httpd_setfinishhook(void (*fn)(void))
+{
+ finishhook = fn;
+}
diff --git a/lib/isc/ia64/Makefile.in b/lib/isc/ia64/Makefile.in
new file mode 100644
index 0000000..419cf9f
--- /dev/null
+++ b/lib/isc/ia64/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/ia64/include/Makefile.in b/lib/isc/ia64/include/Makefile.in
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/lib/isc/ia64/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/ia64/include/isc/Makefile.in b/lib/isc/ia64/include/isc/Makefile.in
new file mode 100644
index 0000000..97b6b41
--- /dev/null
+++ b/lib/isc/ia64/include/isc/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
diff --git a/lib/isc/ia64/include/isc/atomic.h b/lib/isc/ia64/include/isc/atomic.h
new file mode 100644
index 0000000..e2f4331
--- /dev/null
+++ b/lib/isc/ia64/include/isc/atomic.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <inttypes.h>
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ *
+ * Open issue: can 'fetchadd' make the code faster for some particular values
+ * (e.g., 1 and -1)?
+ */
+static inline int32_t
+#ifdef __GNUC__
+__attribute__ ((unused))
+#endif
+isc_atomic_xadd(int32_t *p, int32_t val)
+{
+ int32_t prev, swapped;
+
+ for (prev = *(volatile int32_t *)p; ; prev = swapped) {
+ swapped = prev + val;
+ __asm__ volatile(
+ "mov ar.ccv=%2;;"
+ "cmpxchg4.acq %0=%4,%3,ar.ccv"
+ : "=r" (swapped), "=m" (*p)
+ : "r" (prev), "r" (swapped), "m" (*p)
+ : "memory");
+ if (swapped == prev)
+ break;
+ }
+
+ return (prev);
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+#ifdef __GNUC__
+__attribute__ ((unused))
+#endif
+isc_atomic_store(int32_t *p, int32_t val)
+{
+ __asm__ volatile(
+ "st4.rel %0=%1"
+ : "=m" (*p)
+ : "r" (val)
+ : "memory"
+ );
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+static inline int32_t
+#ifdef __GNUC__
+__attribute__ ((unused))
+#endif
+isc_atomic_cmpxchg(int32_t *p, int32_t cmpval, int32_t val)
+{
+ int32_t ret;
+
+ __asm__ volatile(
+ "mov ar.ccv=%2;;"
+ "cmpxchg4.acq %0=%4,%3,ar.ccv"
+ : "=r" (ret), "=m" (*p)
+ : "r" (cmpval), "r" (val), "m" (*p)
+ : "memory");
+
+ return (ret);
+}
+#else /* !ISC_PLATFORM_USEGCCASM */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/include/Makefile.in b/lib/isc/include/Makefile.in
new file mode 100644
index 0000000..3b21e6e
--- /dev/null
+++ b/lib/isc/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc pk11 pkcs11
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/include/isc/Makefile.in b/lib/isc/include/isc/Makefile.in
new file mode 100644
index 0000000..4698206
--- /dev/null
+++ b/lib/isc/include/isc/Makefile.in
@@ -0,0 +1,59 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+#
+# Only list headers that are to be installed and are not
+# machine generated. The latter are handled specially in the
+# install target below.
+#
+HEADERS = aes.h app.h assertions.h boolean.h backtrace.h base32.h base64.h \
+ bind9.h buffer.h bufferlist.h commandline.h \
+ counter.h crc64.h deprecated.h entropy.h errno.h \
+ error.h event.h eventclass.h file.h formatcheck.h \
+ fsaccess.h hash.h heap.h hex.h hmacmd5.h hmacsha.h \
+ ht.h httpd.h int.h interfaceiter.h @ISC_IPV6_H@ iterated_hash.h \
+ json.h lang.h lex.h lfsr.h lib.h likely.h list.h \
+ log.h magic.h md5.h mem.h meminfo.h msgcat.h msgs.h \
+ mutexblock.h netaddr.h netscope.h ondestroy.h os.h \
+ parseint.h pool.h portset.h print.h queue.h quota.h \
+ radix.h random.h ratelimiter.h refcount.h regex.h \
+ region.h resource.h result.h resultclass.h rwlock.h \
+ safe.h serial.h sha1.h sha2.h sockaddr.h socket.h \
+ stats.h stdio.h stdlib.h string.h symtab.h task.h \
+ taskpool.h timer.h tm.h types.h util.h version.h \
+ xml.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+ ${INSTALL_DATA} platform.h ${DESTDIR}${includedir}/isc
+
+uninstall::
+ rm -f ${DESTDIR}${includedir}/isc/platform.h
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
+
+distclean::
+ rm -f platform.h
diff --git a/lib/isc/include/isc/aes.h b/lib/isc/include/isc/aes.h
new file mode 100644
index 0000000..75f2a2b
--- /dev/null
+++ b/lib/isc/include/isc/aes.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file isc/aes.h */
+
+#ifndef ISC_AES_H
+#define ISC_AES_H 1
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#define ISC_AES128_KEYLENGTH 16U
+#define ISC_AES192_KEYLENGTH 24U
+#define ISC_AES256_KEYLENGTH 32U
+#define ISC_AES_BLOCK_LENGTH 16U
+
+#ifdef ISC_PLATFORM_WANTAES
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_aes128_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out);
+
+void
+isc_aes192_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out);
+
+void
+isc_aes256_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_PLATFORM_WANTAES */
+
+#endif /* ISC_AES_H */
diff --git a/lib/isc/include/isc/app.h b/lib/isc/include/isc/app.h
new file mode 100644
index 0000000..5ed2750
--- /dev/null
+++ b/lib/isc/include/isc/app.h
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_APP_H
+#define ISC_APP_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/app.h
+ * \brief ISC Application Support
+ *
+ * Dealing with program termination can be difficult, especially in a
+ * multithreaded program. The routines in this module help coordinate
+ * the shutdown process. They are used as follows by the initial (main)
+ * thread of the application:
+ *
+ *\li isc_app_start(); Call very early in main(), before
+ * any other threads have been created.
+ *
+ *\li isc_app_run(); This will post any on-run events,
+ * and then block until application
+ * shutdown is requested. A shutdown
+ * request is made by calling
+ * isc_app_shutdown(), or by sending
+ * SIGINT or SIGTERM to the process.
+ * After isc_app_run() returns, the
+ * application should shutdown itself.
+ *
+ *\li isc_app_finish(); Call very late in main().
+ *
+ * Applications that want to use SIGHUP/isc_app_reload() to trigger reloading
+ * should check the result of isc_app_run() and call the reload routine if
+ * the result is ISC_R_RELOAD. They should then call isc_app_run() again
+ * to resume waiting for reload or termination.
+ *
+ * Use of this module is not required. In particular, isc_app_start() is
+ * NOT an ISC library initialization routine.
+ *
+ * This module also supports per-thread 'application contexts'. With this
+ * mode, a thread-based application will have a separate context, in which
+ * it uses other ISC library services such as tasks or timers. Signals are
+ * not caught in this mode, so that the application can handle the signals
+ * in its preferred way.
+ *
+ * \li MP:
+ * Clients must ensure that isc_app_start(), isc_app_run(), and
+ * isc_app_finish() are called at most once. isc_app_shutdown()
+ * is safe to use by any thread (provided isc_app_start() has been
+ * called previously).
+ *
+ * The same note applies to isc_app_ctxXXX() functions, but in this case
+ * it's a per-thread restriction. For example, a thread with an
+ * application context must ensure that isc_app_ctxstart() with the
+ * context is called at most once.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * None.
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+#include <stdbool.h>
+
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/result.h>
+
+/***
+ *** Types
+ ***/
+
+typedef isc_event_t isc_appevent_t;
+
+#define ISC_APPEVENT_FIRSTEVENT (ISC_EVENTCLASS_APP + 0)
+#define ISC_APPEVENT_SHUTDOWN (ISC_EVENTCLASS_APP + 1)
+#define ISC_APPEVENT_LASTEVENT (ISC_EVENTCLASS_APP + 65535)
+
+/*%
+ * app module methods. Only app driver implementations use this structure.
+ * Other clients should use the top-level interfaces (i.e., isc_app_xxx
+ * functions). magic must be ISCAPI_APPMETHODS_MAGIC.
+ */
+typedef struct isc_appmethods {
+ void (*ctxdestroy)(isc_appctx_t **ctxp);
+ isc_result_t (*ctxstart)(isc_appctx_t *ctx);
+ isc_result_t (*ctxrun)(isc_appctx_t *ctx);
+ isc_result_t (*ctxsuspend)(isc_appctx_t *ctx);
+ isc_result_t (*ctxshutdown)(isc_appctx_t *ctx);
+ void (*ctxfinish)(isc_appctx_t *ctx);
+ void (*settaskmgr)(isc_appctx_t *ctx,
+ isc_taskmgr_t *timermgr);
+ void (*setsocketmgr)(isc_appctx_t *ctx,
+ isc_socketmgr_t *timermgr);
+ void (*settimermgr)(isc_appctx_t *ctx,
+ isc_timermgr_t *timermgr);
+ isc_result_t (*ctxonrun)(isc_appctx_t *ctx, isc_mem_t *mctx,
+ isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+} isc_appmethods_t;
+
+/*%
+ * This structure is actually just the common prefix of an application context
+ * implementation's version of an isc_appctx_t.
+ * \brief
+ * Direct use of this structure by clients is forbidden. app implementations
+ * may change the structure. 'magic' must be ISCAPI_APPCTX_MAGIC for any
+ * of the isc_app_ routines to work. app implementations must maintain
+ * all app context invariants.
+ */
+struct isc_appctx {
+ unsigned int impmagic;
+ unsigned int magic;
+ isc_appmethods_t *methods;
+};
+
+#define ISCAPI_APPCTX_MAGIC ISC_MAGIC('A','a','p','c')
+#define ISCAPI_APPCTX_VALID(c) ((c) != NULL && \
+ (c)->magic == ISCAPI_APPCTX_MAGIC)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_app_ctxstart(isc_appctx_t *ctx);
+
+isc_result_t
+isc_app_start(void);
+/*!<
+ * \brief Start an ISC library application.
+ *
+ * Notes:
+ * This call should be made before any other ISC library call, and as
+ * close to the beginning of the application as possible.
+ *
+ * Requires:
+ *\li 'ctx' is a valid application context (for app_ctxstart()).
+ */
+
+isc_result_t
+isc_app_ctxonrun(isc_appctx_t *ctx, isc_mem_t *mctx, isc_task_t *task,
+ isc_taskaction_t action, void *arg);
+isc_result_t
+isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+/*!<
+ * \brief Request delivery of an event when the application is run.
+ *
+ * Requires:
+ *\li isc_app_start() has been called.
+ *\li 'ctx' is a valid application context (for app_ctxonrun()).
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_NOMEMORY
+ */
+
+isc_result_t
+isc_app_ctxrun(isc_appctx_t *ctx);
+
+isc_result_t
+isc_app_run(void);
+/*!<
+ * \brief Run an ISC library application.
+ *
+ * Notes:
+ *\li The caller (typically the initial thread of an application) will
+ * block until shutdown is requested. When the call returns, the
+ * caller should start shutting down the application.
+ *
+ * Requires:
+ *\li isc_app_[ctx]start() has been called.
+ *
+ * Ensures:
+ *\li Any events requested via isc_app_onrun() will have been posted (in
+ * FIFO order) before isc_app_run() blocks.
+ *\li 'ctx' is a valid application context (for app_ctxrun()).
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS Shutdown has been requested.
+ *\li ISC_R_RELOAD Reload has been requested.
+ */
+
+bool
+isc_app_isrunning(void);
+/*!<
+ * \brief Return if the ISC library application is running.
+ *
+ * Returns:
+ *\li true App is running.
+ *\li false App is not running.
+ */
+
+isc_result_t
+isc_app_ctxshutdown(isc_appctx_t *ctx);
+
+isc_result_t
+isc_app_shutdown(void);
+/*!<
+ * \brief Request application shutdown.
+ *
+ * Notes:
+ *\li It is safe to call isc_app_shutdown() multiple times. Shutdown will
+ * only be triggered once.
+ *
+ * Requires:
+ *\li isc_app_[ctx]run() has been called.
+ *\li 'ctx' is a valid application context (for app_ctxshutdown()).
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_app_ctxsuspend(isc_appctx_t *ctx);
+/*!<
+ * \brief This has the same behavior as isc_app_ctxsuspend().
+ */
+
+isc_result_t
+isc_app_reload(void);
+/*!<
+ * \brief Request application reload.
+ *
+ * Requires:
+ *\li isc_app_run() has been called.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_UNEXPECTED
+ */
+
+void
+isc_app_ctxfinish(isc_appctx_t *ctx);
+
+void
+isc_app_finish(void);
+/*!<
+ * \brief Finish an ISC library application.
+ *
+ * Notes:
+ *\li This call should be made at or near the end of main().
+ *
+ * Requires:
+ *\li isc_app_start() has been called.
+ *\li 'ctx' is a valid application context (for app_ctxfinish()).
+ *
+ * Ensures:
+ *\li Any resources allocated by isc_app_start() have been released.
+ */
+
+void
+isc_app_block(void);
+/*!<
+ * \brief Indicate that a blocking operation will be performed.
+ *
+ * Notes:
+ *\li If a blocking operation is in process, a call to isc_app_shutdown()
+ * or an external signal will abort the program, rather than allowing
+ * clean shutdown. This is primarily useful for reading user input.
+ *
+ * Requires:
+ * \li isc_app_start() has been called.
+ * \li No other blocking operations are in progress.
+ */
+
+void
+isc_app_unblock(void);
+/*!<
+ * \brief Indicate that a blocking operation is complete.
+ *
+ * Notes:
+ * \li When a blocking operation has completed, return the program to a
+ * state where a call to isc_app_shutdown() or an external signal will
+ * shutdown normally.
+ *
+ * Requires:
+ * \li isc_app_start() has been called.
+ * \li isc_app_block() has been called by the same thread.
+ */
+
+isc_result_t
+isc_appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp);
+/*!<
+ * \brief Create an application context.
+ *
+ * Requires:
+ *\li 'mctx' is a valid memory context.
+ *\li 'ctxp' != NULL && *ctxp == NULL.
+ */
+
+void
+isc_appctx_destroy(isc_appctx_t **ctxp);
+/*!<
+ * \brief Destroy an application context.
+ *
+ * Requires:
+ *\li '*ctxp' is a valid application context.
+ *
+ * Ensures:
+ *\li *ctxp == NULL.
+ */
+
+void
+isc_appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr);
+/*!<
+ * \brief Associate a task manager with an application context.
+ *
+ * This must be done before running tasks within the application context.
+ *
+ * Requires:
+ *\li 'ctx' is a valid application context.
+ *\li 'taskmgr' is a valid task manager.
+ */
+
+void
+isc_appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr);
+/*!<
+ * \brief Associate a socket manager with an application context.
+ *
+ * This must be done before handling socket events within the application
+ * context.
+ *
+ * Requires:
+ *\li 'ctx' is a valid application context.
+ *\li 'socketmgr' is a valid socket manager.
+ */
+
+void
+isc_appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr);
+/*!<
+ * \brief Associate a socket timer with an application context.
+ *
+ * This must be done before handling timer events within the application
+ * context.
+ *
+ * Requires:
+ *\li 'ctx' is a valid application context.
+ *\li 'timermgr' is a valid timer manager.
+ */
+
+/*%<
+ * See isc_appctx_create() above.
+ */
+typedef isc_result_t
+(*isc_appctxcreatefunc_t)(isc_mem_t *mctx, isc_appctx_t **ctxp);
+
+isc_result_t
+isc_app_register(isc_appctxcreatefunc_t createfunc);
+/*%<
+ * Register a new application implementation and add it to the list of
+ * supported implementations. This function must be called when a different
+ * event library is used than the one contained in the ISC library.
+ */
+
+isc_result_t
+isc__app_register(void);
+/*%<
+ * A short cut function that specifies the application module in the ISC
+ * library for isc_app_register(). An application that uses the ISC library
+ * usually do not have to care about this function: it would call
+ * isc_lib_register(), which internally calls this function.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_APP_H */
diff --git a/lib/isc/include/isc/assertions.h b/lib/isc/include/isc/assertions.h
new file mode 100644
index 0000000..e5719d9
--- /dev/null
+++ b/lib/isc/include/isc/assertions.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file isc/assertions.h
+ */
+
+#ifndef ISC_ASSERTIONS_H
+#define ISC_ASSERTIONS_H 1
+
+#include <isc/lang.h>
+#include <isc/likely.h>
+#include <isc/platform.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% isc assertion type */
+typedef enum {
+ isc_assertiontype_require,
+ isc_assertiontype_ensure,
+ isc_assertiontype_insist,
+ isc_assertiontype_invariant
+} isc_assertiontype_t;
+
+typedef void (*isc_assertioncallback_t)(const char *, int, isc_assertiontype_t,
+ const char *);
+
+/* coverity[+kill] */
+ISC_PLATFORM_NORETURN_PRE
+void isc_assertion_failed(const char *, int, isc_assertiontype_t,
+ const char *) ISC_PLATFORM_NORETURN_POST;
+
+void
+isc_assertion_setcallback(isc_assertioncallback_t);
+
+const char *
+isc_assertion_typetotext(isc_assertiontype_t type);
+
+#if defined(ISC_CHECK_ALL) || defined(__COVERITY__)
+#define ISC_CHECK_REQUIRE 1
+#define ISC_CHECK_ENSURE 1
+#define ISC_CHECK_INSIST 1
+#define ISC_CHECK_INVARIANT 1
+#endif
+
+#if defined(ISC_CHECK_NONE) && !defined(__COVERITY__)
+#define ISC_CHECK_REQUIRE 0
+#define ISC_CHECK_ENSURE 0
+#define ISC_CHECK_INSIST 0
+#define ISC_CHECK_INVARIANT 0
+#endif
+
+#ifndef ISC_CHECK_REQUIRE
+#define ISC_CHECK_REQUIRE 1
+#endif
+
+#ifndef ISC_CHECK_ENSURE
+#define ISC_CHECK_ENSURE 1
+#endif
+
+#ifndef ISC_CHECK_INSIST
+#define ISC_CHECK_INSIST 1
+#endif
+
+#ifndef ISC_CHECK_INVARIANT
+#define ISC_CHECK_INVARIANT 1
+#endif
+
+#if ISC_CHECK_REQUIRE != 0
+#define ISC_REQUIRE(cond) \
+ ((void) (ISC_LIKELY(cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_require, \
+ #cond), 0)))
+#else
+#define ISC_REQUIRE(cond) ((void) 0)
+#endif /* ISC_CHECK_REQUIRE */
+
+#if ISC_CHECK_ENSURE != 0
+#define ISC_ENSURE(cond) \
+ ((void) (ISC_LIKELY(cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_ensure, \
+ #cond), 0)))
+#else
+#define ISC_ENSURE(cond) ((void) 0)
+#endif /* ISC_CHECK_ENSURE */
+
+#if ISC_CHECK_INSIST != 0
+#define ISC_INSIST(cond) \
+ ((void) (ISC_LIKELY(cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_insist, \
+ #cond), 0)))
+#else
+#define ISC_INSIST(cond) ((void) 0)
+#endif /* ISC_CHECK_INSIST */
+
+#if ISC_CHECK_INVARIANT != 0
+#define ISC_INVARIANT(cond) \
+ ((void) (ISC_LIKELY(cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_invariant, \
+ #cond), 0)))
+#else
+#define ISC_INVARIANT(cond) ((void) 0)
+#endif /* ISC_CHECK_INVARIANT */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ASSERTIONS_H */
diff --git a/lib/isc/include/isc/backtrace.h b/lib/isc/include/isc/backtrace.h
new file mode 100644
index 0000000..27ab9da
--- /dev/null
+++ b/lib/isc/include/isc/backtrace.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file isc/backtrace.h
+ * \brief provide a back trace of the running process to help debug problems.
+ *
+ * This module tries to get a back trace of the process using some platform
+ * dependent way when available. It also manages an internal symbol table
+ * that maps function addresses used in the process to their textual symbols.
+ * This module is expected to be used to help debug when some fatal error
+ * happens.
+ *
+ * IMPORTANT NOTE: since the (major) intended use case of this module is
+ * dumping a back trace on a fatal error, normally followed by self termination,
+ * functions defined in this module generally doesn't employ assertion checks
+ * (if it did, a program bug could cause infinite recursive calls to a
+ * backtrace function). These functions still perform minimal checks and return
+ * ISC_R_FAILURE if they detect an error, but the caller should therefore be
+ * very careful about the use of these functions, and generally discouraged to
+ * use them except in an exit path. The exception is
+ * isc_backtrace_getsymbolfromindex(), which is expected to be used in a
+ * non-error-handling context and validates arguments with assertion checks.
+ */
+
+#ifndef ISC_BACKTRACE_H
+#define ISC_BACKTRACE_H 1
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/types.h>
+
+/***
+ *** Types
+ ***/
+struct isc_backtrace_symmap {
+ void *addr;
+ const char *symbol;
+};
+
+LIBISC_EXTERNAL_DATA extern const int isc__backtrace_nsymbols;
+LIBISC_EXTERNAL_DATA extern const
+ isc_backtrace_symmap_t isc__backtrace_symtable[];
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+isc_result_t
+isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes);
+/*%<
+ * Get a back trace of the running process above this function itself. On
+ * success, addrs[i] will store the address of the call point of the i-th
+ * stack frame (addrs[0] is the caller of this function). *nframes will store
+ * the total number of frames.
+ *
+ * Requires (note that these are not ensured by assertion checks, see above):
+ *
+ *\li 'addrs' is a valid array containing at least 'maxaddrs' void * entries.
+ *
+ *\li 'nframes' must be non NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_FAILURE
+ *\li #ISC_R_NOTFOUND
+ *\li #ISC_R_NOTIMPLEMENTED
+ */
+
+isc_result_t
+isc_backtrace_getsymbolfromindex(int index, const void **addrp,
+ const char **symbolp);
+/*%<
+ * Returns the content of the internal symbol table of the given index.
+ * On success, *addrsp and *symbolp point to the address and the symbol of
+ * the 'index'th entry of the table, respectively. If 'index' is not in the
+ * range of the symbol table, ISC_R_RANGE will be returned.
+ *
+ * Requires
+ *
+ *\li 'addrp' must be non NULL && '*addrp' == NULL.
+ *
+ *\li 'symbolp' must be non NULL && '*symbolp' == NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_RANGE
+ */
+
+isc_result_t
+isc_backtrace_getsymbol(const void *addr, const char **symbolp,
+ unsigned long *offsetp);
+/*%<
+ * Searches the internal symbol table for the symbol that most matches the
+ * given 'addr'. On success, '*symbolp' will point to the name of function
+ * to which the address 'addr' belong, and '*offsetp' will store the offset
+ * from the function's entry address to 'addr'.
+ *
+ * Requires (note that these are not ensured by assertion checks, see above):
+ *
+ *\li 'symbolp' must be non NULL && '*symbolp' == NULL.
+ *
+ *\li 'offsetp' must be non NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_FAILURE
+ *\li #ISC_R_NOTFOUND
+ */
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BACKTRACE_H */
diff --git a/lib/isc/include/isc/base32.h b/lib/isc/include/isc/base32.h
new file mode 100644
index 0000000..96fe2ce
--- /dev/null
+++ b/lib/isc/include/isc/base32.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_BASE32_H
+#define ISC_BASE32_H 1
+
+/*! \file */
+
+/*
+ * Routines for manipulating base 32 and base 32 hex encoded data.
+ * Based on RFC 4648.
+ *
+ * Base 32 hex preserves the sort order of data when it is encoded /
+ * decoded.
+ *
+ * Base 32 hex "np" is base 32 hex but no padding is produced or accepted.
+ */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_base32_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+isc_result_t
+isc_base32hexnp_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+/*!<
+ * \brief Convert data into base32 encoded text.
+ *
+ * Notes:
+ *\li The base32 encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data
+ *\li 'target' is a text buffer containing available space
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters
+ *
+ * Ensures:
+ *\li target will contain the base32 encoded version of the data
+ * in source. The 'used' pointer in target will be advanced as
+ * necessary.
+ */
+
+isc_result_t
+isc_base32_decodestring(const char *cstr, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target);
+isc_result_t
+isc_base32hexnp_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated string in base32, base32hex, or
+ * base32hex non-padded.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE32 -- 'cstr' is not a valid base32 encoding.
+ *
+ * Other error returns are any possible error code from:
+ *\li isc_lex_create(),
+ *\li isc_lex_openbuffer(),
+ *\li isc_base32_tobuffer().
+ */
+
+isc_result_t
+isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+isc_result_t
+isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+isc_result_t
+isc_base32hexnp_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert text encoded in base32, base32hex, or base32hex
+ * non-padded from a lexer context into data.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer context
+ *\li 'target' is a buffer containing binary data
+ *\li 'length' is an integer
+ *
+ * Ensures:
+ *\li target will contain the data represented by the base32 encoded
+ * string parsed by the lexer. No more than length bytes will be read,
+ * if length is positive. The 'used' pointer in target will be
+ * advanced as necessary.
+ */
+
+isc_result_t
+isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target);
+isc_result_t
+isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target);
+/*!<
+ * \brief Decode a packed (no white space permitted) region in
+ * base32, base32hex or base32hex non-padded.
+ *
+ * Requires:
+ *\li 'source' is a valid region.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE32 -- 'source' is not a valid base32 encoding.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BASE32_H */
diff --git a/lib/isc/include/isc/base64.h b/lib/isc/include/isc/base64.h
new file mode 100644
index 0000000..1504d3d
--- /dev/null
+++ b/lib/isc/include/isc/base64.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_BASE64_H
+#define ISC_BASE64_H 1
+
+/*! \file isc/base64.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_base64_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+/*!<
+ * \brief Convert data into base64 encoded text.
+ *
+ * Notes:
+ *\li The base64 encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data
+ *\li 'target' is a text buffer containing available space
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters
+ *
+ * Ensures:
+ *\li target will contain the base64 encoded version of the data
+ * in source. The 'used' pointer in target will be advanced as
+ * necessary.
+ */
+
+isc_result_t
+isc_base64_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated base64 string.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE64 -- 'cstr' is not a valid base64 encoding.
+ *
+ * Other error returns are any possible error code from:
+ *\li isc_lex_create(),
+ *\li isc_lex_openbuffer(),
+ *\li isc_base64_tobuffer().
+ */
+
+isc_result_t
+isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert base64 encoded text from a lexer context into data.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer context
+ *\li 'target' is a buffer containing binary data
+ *\li 'length' is an integer
+ *
+ * Ensures:
+ *\li target will contain the data represented by the base64 encoded
+ * string parsed by the lexer. No more than length bytes will be read,
+ * if length is positive. The 'used' pointer in target will be
+ * advanced as necessary.
+ */
+
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BASE64_H */
diff --git a/lib/isc/include/isc/bind9.h b/lib/isc/include/isc/bind9.h
new file mode 100644
index 0000000..5a2837f
--- /dev/null
+++ b/lib/isc/include/isc/bind9.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_BIND9_H
+#define ISC_BIND9_H 1
+
+#include <stdbool.h>
+
+#include <isc/platform.h>
+
+/*
+ * This determines whether we are using the libisc/libdns libraries
+ * in BIND9 or in some other application. For BIND9 (named and related
+ * tools) it must be set to true at runtime. Export library clients
+ * will call isc_lib_register(), which will set it to false.
+ */
+LIBISC_EXTERNAL_DATA extern bool isc_bind9;
+
+#endif /* ISC_BIND9_H */
diff --git a/lib/isc/include/isc/boolean.h b/lib/isc/include/isc/boolean.h
new file mode 100644
index 0000000..2eebefa
--- /dev/null
+++ b/lib/isc/include/isc/boolean.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*! \file isc/boolean.h */
+
+#define isc_boolean_t bool
+#define isc_boolean_false false
+#define isc_boolean_true true
+
+#define ISC_FALSE false
+#define ISC_TRUE true
+#define ISC_TF(x) (!!(x))
diff --git a/lib/isc/include/isc/buffer.h b/lib/isc/include/isc/buffer.h
new file mode 100644
index 0000000..caaac57
--- /dev/null
+++ b/lib/isc/include/isc/buffer.h
@@ -0,0 +1,1047 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_BUFFER_H
+#define ISC_BUFFER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/buffer.h
+ *
+ * \brief A buffer is a region of memory, together with a set of related subregions.
+ * Buffers are used for parsing and I/O operations.
+ *
+ * The 'used region' and the 'available' region are disjoint, and their
+ * union is the buffer's region. The used region extends from the beginning
+ * of the buffer region to the last used byte. The available region
+ * extends from one byte greater than the last used byte to the end of the
+ * buffer's region. The size of the used region can be changed using various
+ * buffer commands. Initially, the used region is empty.
+ *
+ * The used region is further subdivided into two disjoint regions: the
+ * 'consumed region' and the 'remaining region'. The union of these two
+ * regions is the used region. The consumed region extends from the beginning
+ * of the used region to the byte before the 'current' offset (if any). The
+ * 'remaining' region the current pointer to the end of the used
+ * region. The size of the consumed region can be changed using various
+ * buffer commands. Initially, the consumed region is empty.
+ *
+ * The 'active region' is an (optional) subregion of the remaining region.
+ * It extends from the current offset to an offset in the remaining region
+ * that is selected with isc_buffer_setactive(). Initially, the active region
+ * is empty. If the current offset advances beyond the chosen offset, the
+ * active region will also be empty.
+ *
+ * \verbatim
+ * /------------entire length---------------\
+ * /----- used region -----\/-- available --\
+ * +----------------------------------------+
+ * | consumed | remaining | |
+ * +----------------------------------------+
+ * a b c d e
+ *
+ * a == base of buffer.
+ * b == current pointer. Can be anywhere between a and d.
+ * c == active pointer. Meaningful between b and d.
+ * d == used pointer.
+ * e == length of buffer.
+ *
+ * a-e == entire length of buffer.
+ * a-d == used region.
+ * a-b == consumed region.
+ * b-d == remaining region.
+ * b-c == optional active region.
+ *\endverbatim
+ *
+ * The following invariants are maintained by all routines:
+ *
+ *\code
+ * length > 0
+ *
+ * base is a valid pointer to length bytes of memory
+ *
+ * 0 <= used <= length
+ *
+ * 0 <= current <= used
+ *
+ * 0 <= active <= used
+ * (although active < current implies empty active region)
+ *\endcode
+ *
+ * \li MP:
+ * Buffers have no synchronization. Clients must ensure exclusive
+ * access.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * Memory: 1 pointer + 6 unsigned integers per buffer.
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/assertions.h>
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+#include <isc/likely.h>
+#include <isc/magic.h>
+#include <isc/types.h>
+
+/*!
+ * To make many functions be inline macros (via \#define) define this.
+ * If it is undefined, a function will be used.
+ */
+/* #define ISC_BUFFER_USEINLINE */
+
+
+ISC_LANG_BEGINDECLS
+
+/*@{*/
+/*!
+ *** Magic numbers
+ ***/
+#define ISC_BUFFER_MAGIC 0x42756621U /* Buf!. */
+#define ISC_BUFFER_VALID(b) ISC_MAGIC_VALID(b, ISC_BUFFER_MAGIC)
+/*@}*/
+
+/*!
+ * Size granularity for dynamically resizeable buffers; when reserving
+ * space in a buffer, we round the allocated buffer length up to the
+ * nearest * multiple of this value.
+ */
+#define ISC_BUFFER_INCR 2048
+
+/*
+ * The following macros MUST be used only on valid buffers. It is the
+ * caller's responsibility to ensure this by using the ISC_BUFFER_VALID
+ * check above, or by calling another isc_buffer_*() function (rather than
+ * another macro.)
+ */
+
+/*@{*/
+/*!
+ * Fundamental buffer elements. (A through E in the introductory comment.)
+ */
+#define isc_buffer_base(b) ((void *)(b)->base) /*a*/
+#define isc_buffer_current(b) \
+ ((void *)((unsigned char *)(b)->base + (b)->current)) /*b*/
+#define isc_buffer_active(b) \
+ ((void *)((unsigned char *)(b)->base + (b)->active)) /*c*/
+#define isc_buffer_used(b) \
+ ((void *)((unsigned char *)(b)->base + (b)->used)) /*d*/
+#define isc_buffer_length(b) ((b)->length) /*e*/
+/*@}*/
+
+/*@{*/
+/*!
+ * Derived lengths. (Described in the introductory comment.)
+ */
+#define isc_buffer_usedlength(b) ((b)->used) /* d-a */
+#define isc_buffer_consumedlength(b) ((b)->current) /* b-a */
+#define isc_buffer_remaininglength(b) ((b)->used - (b)->current) /* d-b */
+#define isc_buffer_activelength(b) ((b)->active - (b)->current) /* c-b */
+#define isc_buffer_availablelength(b) ((b)->length - (b)->used) /* e-d */
+/*@}*/
+
+/*!
+ * Note that the buffer structure is public. This is principally so buffer
+ * operations can be implemented using macros. Applications are strongly
+ * discouraged from directly manipulating the structure.
+ */
+
+struct isc_buffer {
+ unsigned int magic;
+ void *base;
+ /*@{*/
+ /*! The following integers are byte offsets from 'base'. */
+ unsigned int length;
+ unsigned int used;
+ unsigned int current;
+ unsigned int active;
+ /*@}*/
+ /*! linkable */
+ ISC_LINK(isc_buffer_t) link;
+ /*! private internal elements */
+ isc_mem_t *mctx;
+ /* automatically realloc buffer at put* */
+ bool autore;
+};
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
+ unsigned int length);
+/*!<
+ * \brief Allocate a dynamic linkable buffer which has "length" bytes in the
+ * data region.
+ *
+ * Requires:
+ *\li "mctx" is valid.
+ *
+ *\li "dynbuffer" is non-NULL, and "*dynbuffer" is NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS - success
+ *\li ISC_R_NOMEMORY - no memory available
+ *
+ * Note:
+ *\li Changing the buffer's length field is not permitted.
+ */
+
+isc_result_t
+isc_buffer_reallocate(isc_buffer_t **dynbuffer, unsigned int length);
+/*!<
+ * \brief Reallocate the buffer to be "length" bytes long. The buffer
+ * pointer may move when you call this function.
+ *
+ * Requires:
+ *\li "dynbuffer" is not NULL.
+ *
+ *\li "*dynbuffer" is a valid dynamic buffer.
+ *
+ *\li 'length' > current length of buffer.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS - success
+ *\li ISC_R_NOMEMORY - no memory available
+ *
+ * Ensures:
+ *\li "*dynbuffer" will be valid on return and will contain all the
+ * original data. However, the buffer pointer may be moved during
+ * reallocation.
+ */
+
+isc_result_t
+isc_buffer_reserve(isc_buffer_t **dynbuffer, unsigned int size);
+/*!<
+ * \brief Make "size" bytes of space available in the buffer. The buffer
+ * pointer may move when you call this function.
+ *
+ * Requires:
+ *\li "dynbuffer" is not NULL.
+ *
+ *\li "*dynbuffer" is a valid dynamic buffer.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS - success
+ *\li ISC_R_NOMEMORY - no memory available
+ *
+ * Ensures:
+ *\li "*dynbuffer" will be valid on return and will contain all the
+ * original data. However, the buffer pointer may be moved during
+ * reallocation.
+ */
+
+void
+isc_buffer_free(isc_buffer_t **dynbuffer);
+/*!<
+ * \brief Release resources allocated for a dynamic buffer.
+ *
+ * Requires:
+ *\li "dynbuffer" is not NULL.
+ *
+ *\li "*dynbuffer" is a valid dynamic buffer.
+ *
+ * Ensures:
+ *\li "*dynbuffer" will be NULL on return, and all memory associated with
+ * the dynamic buffer is returned to the memory context used in
+ * isc_buffer_allocate().
+ */
+
+void
+isc__buffer_init(isc_buffer_t *b, void *base, unsigned int length);
+/*!<
+ * \brief Make 'b' refer to the 'length'-byte region starting at base.
+ *
+ * Requires:
+ *
+ *\li 'length' > 0
+ *
+ *\li 'base' is a pointer to a sequence of 'length' bytes.
+ *
+ */
+
+void
+isc__buffer_initnull(isc_buffer_t *b);
+/*!<
+ *\brief Initialize a buffer 'b' with a null data and zero length/
+ */
+
+void
+isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length);
+/*!<
+ * \brief Make 'b' refer to the 'length'-byte region starting at base.
+ * Any existing data will be copied.
+ *
+ * Requires:
+ *
+ *\li 'length' > 0 AND length >= previous length
+ *
+ *\li 'base' is a pointer to a sequence of 'length' bytes.
+ *
+ */
+
+void
+isc__buffer_invalidate(isc_buffer_t *b);
+/*!<
+ * \brief Make 'b' an invalid buffer.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ * Ensures:
+ *\li If assertion checking is enabled, future attempts to use 'b' without
+ * calling isc_buffer_init() on it will cause an assertion failure.
+ */
+
+void
+isc_buffer_setautorealloc(isc_buffer_t *b, bool enable);
+/*!<
+ * \brief Enable or disable autoreallocation on 'b'.
+ *
+ * Requires:
+ *\li 'b' is a valid dynamic buffer (b->mctx != NULL).
+ *
+ */
+
+void
+isc__buffer_region(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_usedregion(const isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the used region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the available region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_add(isc_buffer_t *b, unsigned int n);
+/*!<
+ * \brief Increase the 'used' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li used + n <= length
+ *
+ */
+
+void
+isc__buffer_subtract(isc_buffer_t *b, unsigned int n);
+/*!<
+ * \brief Decrease the 'used' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li used >= n
+ *
+ */
+
+void
+isc__buffer_clear(isc_buffer_t *b);
+/*!<
+ * \brief Make the used region empty.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ *\li used = 0
+ *
+ */
+
+void
+isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the consumed region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the remaining region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the active region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_setactive(isc_buffer_t *b, unsigned int n);
+/*!<
+ * \brief Sets the end of the active region 'n' bytes after current.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li current + n <= used
+ */
+
+void
+isc__buffer_first(isc_buffer_t *b);
+/*!<
+ * \brief Make the consumed region empty.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ *\li current == 0
+ *
+ */
+
+void
+isc__buffer_forward(isc_buffer_t *b, unsigned int n);
+/*!<
+ * \brief Increase the 'consumed' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li current + n <= used
+ *
+ */
+
+void
+isc__buffer_back(isc_buffer_t *b, unsigned int n);
+/*!<
+ * \brief Decrease the 'consumed' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li n <= current
+ *
+ */
+
+void
+isc_buffer_compact(isc_buffer_t *b);
+/*!<
+ * \brief Compact the used region by moving the remaining region so it occurs
+ * at the start of the buffer. The used region is shrunk by the size of
+ * the consumed region, and the consumed region is then made empty.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ *\li current == 0
+ *
+ *\li The size of the used region is now equal to the size of the remaining
+ * region (as it was before the call). The contents of the used region
+ * are those of the remaining region (as it was before the call).
+ */
+
+uint8_t
+isc_buffer_getuint8(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 8-bit integer from 'b' and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 1.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 1.
+ *
+ * Returns:
+ *
+ *\li A 8-bit unsigned integer.
+ */
+
+void
+isc__buffer_putuint8(isc_buffer_t *b, uint8_t val);
+/*!<
+ * \brief Store an unsigned 8-bit integer from 'val' into 'b'.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the unused region of 'b' is at least 1
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 1.
+ */
+
+uint16_t
+isc_buffer_getuint16(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 16-bit integer in network byte order from 'b', convert
+ * it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 2
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 2.
+ *
+ * Returns:
+ *
+ *\li A 16-bit unsigned integer.
+ */
+
+void
+isc__buffer_putuint16(isc_buffer_t *b, uint16_t val);
+/*!<
+ * \brief Store an unsigned 16-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the unused region of 'b' is at least 2
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 2.
+ */
+
+uint32_t
+isc_buffer_getuint32(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 32-bit integer in network byte order from 'b', convert
+ * it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 4.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 4.
+ *
+ * Returns:
+ *
+ *\li A 32-bit unsigned integer.
+ */
+
+void
+isc__buffer_putuint32(isc_buffer_t *b, uint32_t val);
+/*!<
+ * \brief Store an unsigned 32-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the unused region of 'b' is at least 4
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 4.
+ */
+
+uint64_t
+isc_buffer_getuint48(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 48-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 6.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 6.
+ *
+ * Returns:
+ *
+ *\li A 48-bit unsigned integer (stored in a 64-bit integer).
+ */
+
+void
+isc__buffer_putuint48(isc_buffer_t *b, uint64_t val);
+/*!<
+ * \brief Store an unsigned 48-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the unused region of 'b' is at least 6
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 6.
+ */
+
+void
+isc__buffer_putuint24(isc_buffer_t *b, uint32_t val);
+/*!<
+ * Store an unsigned 24-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ * The length of the unused region of 'b' is at least 3
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 3.
+ */
+
+void
+isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
+ unsigned int length);
+/*!<
+ * \brief Copy 'length' bytes of memory at 'base' into 'b'.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer, and it has at least 'length'
+ * or the buffer has autoreallocation enabled.
+ *
+ *\li 'base' points to 'length' bytes of valid memory.
+ *
+ */
+
+void
+isc__buffer_putstr(isc_buffer_t *b, const char *source);
+/*!<
+ * \brief Copy 'source' into 'b', not including terminating NUL.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'source' to be a valid NULL terminated string.
+ *
+ *\li strlen(source) <= isc_buffer_available(b) || b->mctx != NULL
+ */
+
+void
+isc_buffer_putdecint(isc_buffer_t *b, int64_t v);
+/*!<
+ * \brief Put decimal representation of 'v' in b
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li strlen(dec(v)) <= isc_buffer_available(b) || b->mctx != NULL
+ */
+
+
+
+isc_result_t
+isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r);
+/*!<
+ * \brief Copy the contents of 'r' into 'b'.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' is a valid region.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOSPACE The available region of 'b' is not
+ * big enough.
+ */
+
+isc_result_t
+isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **dstp, const isc_buffer_t *src);
+/*!<
+ * \brief Allocate 'dst' and copy used contents of 'src' into it
+ *
+ * Requires:
+ *\li 'dstp' is not NULL and *dst is NULL
+ *\li 'src' is a valid buffer.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOSPACE The available region of 'b' is not
+ * big enough.
+ */
+
+ISC_LANG_ENDDECLS
+
+/*
+ * Inline macro versions of the functions. These should never be called
+ * directly by an application, but will be used by the functions within
+ * buffer.c. The callers should always use "isc_buffer_*()" names, never
+ * ones beginning with "isc__"
+ */
+
+/*! \note
+ * XXXDCL Something more could be done with initializing buffers that
+ * point to const data. For example, isc_buffer_constinit() could
+ * set a new boolean flag in the buffer structure indicating whether
+ * the buffer was initialized with that function. * Then if the
+ * boolean were true, the isc_buffer_put* functions could assert a
+ * contractual requirement for a non-const buffer.
+ *
+ * One drawback is that the isc_buffer_* functions (macros) that return
+ * pointers would still need to return non-const pointers to avoid compiler
+ * warnings, so it would be up to code that uses them to have to deal
+ * with the possibility that the buffer was initialized as const --
+ * a problem that they *already* have to deal with but have absolutely
+ * no ability to. With a new isc_buffer_isconst() function returning
+ * true/false, they could at least assert a contractual requirement for
+ * non-const buffers when needed.
+ */
+#define ISC__BUFFER_INIT(_b, _base, _length) \
+ do { \
+ (_b)->base = _base; \
+ (_b)->length = (_length); \
+ (_b)->used = 0; \
+ (_b)->current = 0; \
+ (_b)->active = 0; \
+ (_b)->mctx = NULL; \
+ ISC_LINK_INIT(_b, link); \
+ (_b)->magic = ISC_BUFFER_MAGIC; \
+ (_b)->autore = false; \
+ } while (0)
+
+#define ISC__BUFFER_INITNULL(_b) ISC__BUFFER_INIT(_b, NULL, 0)
+
+#define ISC__BUFFER_INVALIDATE(_b) \
+ do { \
+ (_b)->magic = 0; \
+ (_b)->base = NULL; \
+ (_b)->length = 0; \
+ (_b)->used = 0; \
+ (_b)->current = 0; \
+ (_b)->active = 0; \
+ } while (0)
+
+#define ISC__BUFFER_REGION(_b, _r) \
+ do { \
+ (_r)->base = (_b)->base; \
+ (_r)->length = (_b)->length; \
+ } while (0)
+
+#define ISC__BUFFER_USEDREGION(_b, _r) \
+ do { \
+ (_r)->base = (_b)->base; \
+ (_r)->length = (_b)->used; \
+ } while (0)
+
+#define ISC__BUFFER_AVAILABLEREGION(_b, _r) \
+ do { \
+ (_r)->base = isc_buffer_used(_b); \
+ (_r)->length = isc_buffer_availablelength(_b); \
+ } while (0)
+
+#define ISC__BUFFER_ADD(_b, _n) \
+ do { \
+ (_b)->used += (_n); \
+ } while (0)
+
+#define ISC__BUFFER_SUBTRACT(_b, _n) \
+ do { \
+ (_b)->used -= (_n); \
+ if ((_b)->current > (_b)->used) \
+ (_b)->current = (_b)->used; \
+ if ((_b)->active > (_b)->used) \
+ (_b)->active = (_b)->used; \
+ } while (0)
+
+#define ISC__BUFFER_CLEAR(_b) \
+ do { \
+ (_b)->used = 0; \
+ (_b)->current = 0; \
+ (_b)->active = 0; \
+ } while (0)
+
+#define ISC__BUFFER_CONSUMEDREGION(_b, _r) \
+ do { \
+ (_r)->base = (_b)->base; \
+ (_r)->length = (_b)->current; \
+ } while (0)
+
+#define ISC__BUFFER_REMAININGREGION(_b, _r) \
+ do { \
+ (_r)->base = isc_buffer_current(_b); \
+ (_r)->length = isc_buffer_remaininglength(_b); \
+ } while (0)
+
+#define ISC__BUFFER_ACTIVEREGION(_b, _r) \
+ do { \
+ if ((_b)->current < (_b)->active) { \
+ (_r)->base = isc_buffer_current(_b); \
+ (_r)->length = isc_buffer_activelength(_b); \
+ } else { \
+ (_r)->base = NULL; \
+ (_r)->length = 0; \
+ } \
+ } while (0)
+
+#define ISC__BUFFER_SETACTIVE(_b, _n) \
+ do { \
+ (_b)->active = (_b)->current + (_n); \
+ } while (0)
+
+#define ISC__BUFFER_FIRST(_b) \
+ do { \
+ (_b)->current = 0; \
+ } while (0)
+
+#define ISC__BUFFER_FORWARD(_b, _n) \
+ do { \
+ (_b)->current += (_n); \
+ } while (0)
+
+#define ISC__BUFFER_BACK(_b, _n) \
+ do { \
+ (_b)->current -= (_n); \
+ } while (0)
+
+#define ISC__BUFFER_PUTMEM(_b, _base, _length) \
+ do { \
+ if (ISC_UNLIKELY((_b)->autore)) { \
+ isc_buffer_t *_tmp = _b; \
+ ISC_REQUIRE(isc_buffer_reserve(&_tmp, _length) \
+ == ISC_R_SUCCESS); \
+ } \
+ ISC_REQUIRE(isc_buffer_availablelength(_b) >= (unsigned int) _length); \
+ if (_length > 0U) { \
+ memmove(isc_buffer_used(_b), (_base), (_length)); \
+ (_b)->used += (_length); \
+ } \
+ } while (0)
+
+#define ISC__BUFFER_PUTSTR(_b, _source) \
+ do { \
+ unsigned int _length; \
+ unsigned char *_cp; \
+ _length = (unsigned int)strlen(_source); \
+ if (ISC_UNLIKELY((_b)->autore)) { \
+ isc_buffer_t *_tmp = _b; \
+ ISC_REQUIRE(isc_buffer_reserve(&_tmp, _length) \
+ == ISC_R_SUCCESS); \
+ } \
+ ISC_REQUIRE(isc_buffer_availablelength(_b) >= _length); \
+ _cp = isc_buffer_used(_b); \
+ memmove(_cp, (_source), _length); \
+ (_b)->used += (_length); \
+ } while (0)
+
+#define ISC__BUFFER_PUTUINT8(_b, _val) \
+ do { \
+ unsigned char *_cp; \
+ /* evaluate (_val) only once */ \
+ uint8_t _val2 = (_val); \
+ if (ISC_UNLIKELY((_b)->autore)) { \
+ isc_buffer_t *_tmp = _b; \
+ ISC_REQUIRE(isc_buffer_reserve(&_tmp, 1) \
+ == ISC_R_SUCCESS); \
+ } \
+ ISC_REQUIRE(isc_buffer_availablelength(_b) >= 1U); \
+ _cp = isc_buffer_used(_b); \
+ (_b)->used++; \
+ _cp[0] = _val2; \
+ } while (0)
+
+#define ISC__BUFFER_PUTUINT16(_b, _val) \
+ do { \
+ unsigned char *_cp; \
+ /* evaluate (_val) only once */ \
+ uint16_t _val2 = (_val); \
+ if (ISC_UNLIKELY((_b)->autore)) { \
+ isc_buffer_t *_tmp = _b; \
+ ISC_REQUIRE(isc_buffer_reserve(&_tmp, 2) \
+ == ISC_R_SUCCESS); \
+ } \
+ ISC_REQUIRE(isc_buffer_availablelength(_b) >= 2U); \
+ _cp = isc_buffer_used(_b); \
+ (_b)->used += 2; \
+ _cp[0] = _val2 >> 8; \
+ _cp[1] = _val2; \
+ } while (0)
+
+#define ISC__BUFFER_PUTUINT24(_b, _val) \
+ do { \
+ unsigned char *_cp; \
+ /* evaluate (_val) only once */ \
+ uint32_t _val2 = (_val); \
+ if (ISC_UNLIKELY((_b)->autore)) { \
+ isc_buffer_t *_tmp = _b; \
+ ISC_REQUIRE(isc_buffer_reserve(&_tmp, 3) \
+ == ISC_R_SUCCESS); \
+ } \
+ ISC_REQUIRE(isc_buffer_availablelength(_b) >= 3U); \
+ _cp = isc_buffer_used(_b); \
+ (_b)->used += 3; \
+ _cp[0] = _val2 >> 16; \
+ _cp[1] = _val2 >> 8; \
+ _cp[2] = _val2; \
+ } while (0)
+
+#define ISC__BUFFER_PUTUINT32(_b, _val) \
+ do { \
+ unsigned char *_cp; \
+ /* evaluate (_val) only once */ \
+ uint32_t _val2 = (_val); \
+ if (ISC_UNLIKELY((_b)->autore)) { \
+ isc_buffer_t *_tmp = _b; \
+ ISC_REQUIRE(isc_buffer_reserve(&_tmp, 4) \
+ == ISC_R_SUCCESS); \
+ } \
+ ISC_REQUIRE(isc_buffer_availablelength(_b) >= 4U); \
+ _cp = isc_buffer_used(_b); \
+ (_b)->used += 4; \
+ _cp[0] = _val2 >> 24; \
+ _cp[1] = _val2 >> 16; \
+ _cp[2] = _val2 >> 8; \
+ _cp[3] = _val2; \
+ } while (0)
+
+#if defined(ISC_BUFFER_USEINLINE)
+#define isc_buffer_init ISC__BUFFER_INIT
+#define isc_buffer_initnull ISC__BUFFER_INITNULL
+#define isc_buffer_invalidate ISC__BUFFER_INVALIDATE
+#define isc_buffer_region ISC__BUFFER_REGION
+#define isc_buffer_usedregion ISC__BUFFER_USEDREGION
+#define isc_buffer_availableregion ISC__BUFFER_AVAILABLEREGION
+#define isc_buffer_add ISC__BUFFER_ADD
+#define isc_buffer_subtract ISC__BUFFER_SUBTRACT
+#define isc_buffer_clear ISC__BUFFER_CLEAR
+#define isc_buffer_consumedregion ISC__BUFFER_CONSUMEDREGION
+#define isc_buffer_remainingregion ISC__BUFFER_REMAININGREGION
+#define isc_buffer_activeregion ISC__BUFFER_ACTIVEREGION
+#define isc_buffer_setactive ISC__BUFFER_SETACTIVE
+#define isc_buffer_first ISC__BUFFER_FIRST
+#define isc_buffer_forward ISC__BUFFER_FORWARD
+#define isc_buffer_back ISC__BUFFER_BACK
+#define isc_buffer_putmem ISC__BUFFER_PUTMEM
+#define isc_buffer_putstr ISC__BUFFER_PUTSTR
+#define isc_buffer_putuint8 ISC__BUFFER_PUTUINT8
+#define isc_buffer_putuint16 ISC__BUFFER_PUTUINT16
+#define isc_buffer_putuint24 ISC__BUFFER_PUTUINT24
+#define isc_buffer_putuint32 ISC__BUFFER_PUTUINT32
+#else
+#define isc_buffer_init isc__buffer_init
+#define isc_buffer_initnull isc__buffer_initnull
+#define isc_buffer_invalidate isc__buffer_invalidate
+#define isc_buffer_region isc__buffer_region
+#define isc_buffer_usedregion isc__buffer_usedregion
+#define isc_buffer_availableregion isc__buffer_availableregion
+#define isc_buffer_add isc__buffer_add
+#define isc_buffer_subtract isc__buffer_subtract
+#define isc_buffer_clear isc__buffer_clear
+#define isc_buffer_consumedregion isc__buffer_consumedregion
+#define isc_buffer_remainingregion isc__buffer_remainingregion
+#define isc_buffer_activeregion isc__buffer_activeregion
+#define isc_buffer_setactive isc__buffer_setactive
+#define isc_buffer_first isc__buffer_first
+#define isc_buffer_forward isc__buffer_forward
+#define isc_buffer_back isc__buffer_back
+#define isc_buffer_putmem isc__buffer_putmem
+#define isc_buffer_putstr isc__buffer_putstr
+#define isc_buffer_putuint8 isc__buffer_putuint8
+#define isc_buffer_putuint16 isc__buffer_putuint16
+#define isc_buffer_putuint24 isc__buffer_putuint24
+#define isc_buffer_putuint32 isc__buffer_putuint32
+#endif
+
+#define isc_buffer_constinit(_b, _d, _l) \
+ do { \
+ union { void *_var; const void *_const; } _deconst; \
+ _deconst._const = (_d); \
+ isc_buffer_init((_b), _deconst._var, (_l)); \
+ } while (0)
+
+/*
+ * No inline method for this one (yet).
+ */
+#define isc_buffer_putuint48 isc__buffer_putuint48
+
+#endif /* ISC_BUFFER_H */
diff --git a/lib/isc/include/isc/bufferlist.h b/lib/isc/include/isc/bufferlist.h
new file mode 100644
index 0000000..ffb4986
--- /dev/null
+++ b/lib/isc/include/isc/bufferlist.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_BUFFERLIST_H
+#define ISC_BUFFERLIST_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/bufferlist.h
+ *
+ *
+ *\brief Buffer lists have no synchronization. Clients must ensure exclusive
+ * access.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+unsigned int
+isc_bufferlist_usedcount(isc_bufferlist_t *bl);
+/*!<
+ * \brief Return the length of the sum of all used regions of all buffers in
+ * the buffer list 'bl'
+ *
+ * Requires:
+ *
+ *\li 'bl' is not NULL.
+ *
+ * Returns:
+ *\li sum of all used regions' lengths.
+ */
+
+unsigned int
+isc_bufferlist_availablecount(isc_bufferlist_t *bl);
+/*!<
+ * \brief Return the length of the sum of all available regions of all buffers in
+ * the buffer list 'bl'
+ *
+ * Requires:
+ *
+ *\li 'bl' is not NULL.
+ *
+ * Returns:
+ *\li sum of all available regions' lengths.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BUFFERLIST_H */
diff --git a/lib/isc/include/isc/commandline.h b/lib/isc/include/isc/commandline.h
new file mode 100644
index 0000000..a1a256e
--- /dev/null
+++ b/lib/isc/include/isc/commandline.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_COMMANDLINE_H
+#define ISC_COMMANDLINE_H 1
+
+/*! \file isc/commandline.h */
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/result.h>
+
+/*% Index into parent argv vector. */
+LIBISC_EXTERNAL_DATA extern int isc_commandline_index;
+/*% Character checked for validity. */
+LIBISC_EXTERNAL_DATA extern int isc_commandline_option;
+/*% Argument associated with option. */
+LIBISC_EXTERNAL_DATA extern char *isc_commandline_argument;
+/*% For printing error messages. */
+LIBISC_EXTERNAL_DATA extern char *isc_commandline_progname;
+/*% Print error message. */
+LIBISC_EXTERNAL_DATA extern bool isc_commandline_errprint;
+/*% Reset getopt. */
+LIBISC_EXTERNAL_DATA extern bool isc_commandline_reset;
+
+ISC_LANG_BEGINDECLS
+
+int
+isc_commandline_parse(int argc, char * const *argv, const char *options);
+/*%<
+ * Parse a command line (similar to getopt())
+ */
+
+isc_result_t
+isc_commandline_strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp,
+ char ***argvp, unsigned int n);
+/*%<
+ * Tokenize the string "s" into whitespace-separated words,
+ * returning the number of words in '*argcp' and an array
+ * of pointers to the words in '*argvp'. The caller
+ * must free the array using isc_mem_free(). The string
+ * is modified in-place.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_COMMANDLINE_H */
diff --git a/lib/isc/include/isc/counter.h b/lib/isc/include/isc/counter.h
new file mode 100644
index 0000000..28d9c79
--- /dev/null
+++ b/lib/isc/include/isc/counter.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_COUNTER_H
+#define ISC_COUNTER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/counter.h
+ *
+ * \brief The isc_counter_t object is a simplified version of the
+ * isc_quota_t object; it tracks the consumption of limited
+ * resources, returning an error condition when the quota is
+ * exceeded. However, unlike isc_quota_t, attaching and detaching
+ * from a counter object does not increment or decrement the counter.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+/*****
+ ***** Types.
+ *****/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp);
+/*%<
+ * Allocate and initialize a counter object.
+ */
+
+isc_result_t
+isc_counter_increment(isc_counter_t *counter);
+/*%<
+ * Increment the counter.
+ *
+ * If the counter limit is nonzero and has been reached, then
+ * return ISC_R_QUOTA, otherwise ISC_R_SUCCESS. (The counter is
+ * incremented regardless of return value.)
+ */
+
+unsigned int
+isc_counter_used(isc_counter_t *counter);
+/*%<
+ * Return the current counter value.
+ */
+
+void
+isc_counter_setlimit(isc_counter_t *counter, int limit);
+/*%<
+ * Set the counter limit.
+ */
+
+void
+isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp);
+/*%<
+ * Attach to a counter object, increasing its reference counter.
+ */
+
+void
+isc_counter_detach(isc_counter_t **counterp);
+/*%<
+ * Detach (and destroy if reference counter has dropped to zero)
+ * a counter object.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_COUNTER_H */
diff --git a/lib/isc/include/isc/crc64.h b/lib/isc/include/isc/crc64.h
new file mode 100644
index 0000000..ed5860b
--- /dev/null
+++ b/lib/isc/include/isc/crc64.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_CRC64_H
+#define ISC_CRC64_H 1
+
+/*! \file isc/crc64.h
+ * \brief CRC64 in C
+ */
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_crc64_init(uint64_t *crc);
+/*%
+ * Initialize a new CRC.
+ *
+ * Requires:
+ * * 'crc' is not NULL.
+ */
+
+void
+isc_crc64_update(uint64_t *crc, const void *data, size_t len);
+/*%
+ * Add data to the CRC.
+ *
+ * Requires:
+ * * 'crc' is not NULL.
+ * * 'data' is not NULL.
+ */
+
+void
+isc_crc64_final(uint64_t *crc);
+/*%
+ * Finalize the CRC.
+ *
+ * Requires:
+ * * 'crc' is not NULL.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_CRC64_H */
diff --git a/lib/isc/include/isc/deprecated.h b/lib/isc/include/isc/deprecated.h
new file mode 100644
index 0000000..d485e20
--- /dev/null
+++ b/lib/isc/include/isc/deprecated.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_DEPRECATED_H
+#define ISC_DEPRECATED_H
+
+#if (__GNUC__ + 0) > 3
+#define ISC_DEPRECATED __attribute__((deprecated))
+#else
+#define ISC_DEPRECATED /* none */
+#endif /* __GNUC__ > 3*/
+
+#endif
diff --git a/lib/isc/include/isc/entropy.h b/lib/isc/include/isc/entropy.h
new file mode 100644
index 0000000..4bba8e1
--- /dev/null
+++ b/lib/isc/include/isc/entropy.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id: entropy.h,v 1.35 2009/10/19 02:37:08 marka Exp $ */
+
+#ifndef ISC_ENTROPY_H
+#define ISC_ENTROPY_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/entropy.h
+ * \brief The entropy API
+ *
+ * \li MP:
+ * The entropy object is locked internally. All callbacks into
+ * application-provided functions (for setup, gathering, and
+ * shutdown of sources) are guaranteed to be called with the
+ * entropy API lock held. This means these functions are
+ * not permitted to call back into the entropy API.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * A buffer, used as an entropy pool.
+ *
+ * \li Security:
+ * While this code is believed to implement good entropy gathering
+ * and distribution, it has not been reviewed by a cryptographic
+ * expert.
+ * Since the added entropy is only as good as the sources used,
+ * this module could hand out bad data and never know it.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*@{*/
+/*% Entropy callback function. */
+typedef isc_result_t (*isc_entropystart_t)(isc_entropysource_t *source,
+ void *arg, bool blocking);
+typedef isc_result_t (*isc_entropyget_t)(isc_entropysource_t *source,
+ void *arg, bool blocking);
+typedef void (*isc_entropystop_t)(isc_entropysource_t *source, void *arg);
+/*@}*/
+
+/***
+ *** Flags.
+ ***/
+
+/*!
+ * \brief
+ * Extract only "good" data; return failure if there is not enough
+ * data available and there are no sources which we can poll to get
+ * data, or those sources are empty.
+ *
+ *
+ */
+#define ISC_ENTROPY_GOODONLY 0x00000001U
+/*!
+ * \brief
+ * Extract as much good data as possible, but if there isn't enough
+ * at hand, return what is available. This flag only makes sense
+ * when used with _GOODONLY.
+ */
+#define ISC_ENTROPY_PARTIAL 0x00000002U
+/*!
+ * \brief
+ * Block the task until data is available. This is contrary to the
+ * ISC task system, where tasks should never block. However, if
+ * this is a special purpose application where blocking a task is
+ * acceptable (say, an offline zone signer) this flag may be set.
+ * This flag only makes sense when used with _GOODONLY, and will
+ * block regardless of the setting for _PARTIAL.
+ */
+#define ISC_ENTROPY_BLOCKING 0x00000004U
+
+/*!
+ * \brief
+ * Estimate the amount of entropy contained in the sample pool.
+ * If this is not set, the source will be gathered and periodically
+ * mixed into the entropy pool, but no increment in contained entropy
+ * will be assumed. This flag only makes sense on sample sources.
+ */
+#define ISC_ENTROPYSOURCE_ESTIMATE 0x00000001U
+
+/*
+ * For use with isc_entropy_usebestsource().
+ */
+/*!
+ * \brief
+ * Use the keyboard as the only entropy source.
+ */
+#define ISC_ENTROPY_KEYBOARDYES 1
+/*!
+ * \brief
+ * Never use the keyboard as an entropy source.
+ */
+#define ISC_ENTROPY_KEYBOARDNO 2
+/*!
+ * \brief
+ * Use the keyboard as an entropy source only if opening the
+ * random device fails.
+ */
+#define ISC_ENTROPY_KEYBOARDMAYBE 3
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp);
+/*!<
+ * \brief Create a new entropy object.
+ */
+
+void
+isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp);
+/*!<
+ * Attaches to an entropy object.
+ */
+
+void
+isc_entropy_detach(isc_entropy_t **entp);
+/*!<
+ * \brief Detaches from an entropy object.
+ */
+
+isc_result_t
+isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname);
+/*!<
+ * \brief Create a new entropy source from a file.
+ *
+ * The file is assumed to contain good randomness, and will be mixed directly
+ * into the pool with every byte adding 8 bits of entropy.
+ *
+ * The file will be put into non-blocking mode, so it may be a device file,
+ * such as /dev/random. /dev/urandom should not be used here if it can
+ * be avoided, since it will always provide data even if it isn't good.
+ * We will make as much pseudorandom data as we need internally if our
+ * caller asks for it.
+ *
+ * If we hit end-of-file, we will stop reading from this source. Callers
+ * who require strong random data will get failure when our pool drains.
+ * The file will never be opened/read again once EOF is reached.
+ */
+
+void
+isc_entropy_destroysource(isc_entropysource_t **sourcep);
+/*!<
+ * \brief Removes an entropy source from the entropy system.
+ */
+
+isc_result_t
+isc_entropy_createsamplesource(isc_entropy_t *ent,
+ isc_entropysource_t **sourcep);
+/*!<
+ * \brief Create an entropy source that consists of samples. Each sample is
+ * added to the source via isc_entropy_addsamples(), below.
+ */
+
+isc_result_t
+isc_entropy_createcallbacksource(isc_entropy_t *ent,
+ isc_entropystart_t start,
+ isc_entropyget_t get,
+ isc_entropystop_t stop,
+ void *arg,
+ isc_entropysource_t **sourcep);
+/*!<
+ * \brief Create an entropy source that is polled via a callback.
+ *
+ * This would
+ * be used when keyboard input is used, or a GUI input method. It can
+ * also be used to hook in any external entropy source.
+ *
+ * Samples are added via isc_entropy_addcallbacksample(), below.
+ * _addcallbacksample() is the only function which may be called from
+ * within an entropy API callback function.
+ */
+
+void
+isc_entropy_stopcallbacksources(isc_entropy_t *ent);
+/*!<
+ * \brief Call the stop functions for callback sources that have had their
+ * start functions called.
+ */
+
+/*@{*/
+isc_result_t
+isc_entropy_addcallbacksample(isc_entropysource_t *source, uint32_t sample,
+ uint32_t extra);
+isc_result_t
+isc_entropy_addsample(isc_entropysource_t *source, uint32_t sample,
+ uint32_t extra);
+/*!<
+ * \brief Add a sample to the sample source.
+ *
+ * The sample MUST be a timestamp
+ * that increases over time, with the exception of wrap-around for
+ * extremely high resolution timers which will quickly wrap-around
+ * a 32-bit integer.
+ *
+ * The "extra" parameter is used only to add a bit more unpredictable
+ * data. It is not used other than included in the hash of samples.
+ *
+ * When in an entropy API callback function, _addcallbacksource() must be
+ * used. At all other times, _addsample() must be used.
+ */
+/*@}*/
+
+isc_result_t
+isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
+ unsigned int *returned, unsigned int flags);
+/*!<
+ * \brief Extract data from the entropy pool. This may load the pool from various
+ * sources.
+ *
+ * Do this by stiring the pool and returning a part of hash as randomness.
+ * Note that no secrets are given away here since parts of the hash are
+ * xored together before returned.
+ *
+ * Honor the request from the caller to only return good data, any data,
+ * etc.
+ */
+
+void
+isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
+ uint32_t entropy);
+/*!<
+ * \brief Add "length" bytes in "data" to the entropy pool, incrementing the
+ * pool's entropy count by "entropy."
+ *
+ * These bytes will prime the pseudorandom portion even if no entropy is
+ * actually added.
+ */
+
+void
+isc_entropy_stats(isc_entropy_t *ent, FILE *out);
+/*!<
+ * \brief Dump some (trivial) stats to the stdio stream "out".
+ */
+
+unsigned int
+isc_entropy_status(isc_entropy_t *end);
+/*
+ * Returns the number of bits the pool currently contains. This is just
+ * an estimate.
+ */
+
+isc_result_t
+isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
+ const char *randomfile, int use_keyboard);
+/*!<
+ * \brief Use whatever source of entropy is best.
+ *
+ * Notes:
+ *\li If "randomfile" is not NULL, open it with
+ * isc_entropy_createfilesource().
+ *
+ *\li If "randomfile" is NULL and the system's random device was detected
+ * when the program was configured and built, open that device with
+ * isc_entropy_createfilesource().
+ *
+ *\li If "use_keyboard" is #ISC_ENTROPY_KEYBOARDYES, then always open
+ * the keyboard as an entropy source (possibly in addition to
+ * "randomfile" or the random device).
+ *
+ *\li If "use_keyboard" is #ISC_ENTROPY_KEYBOARDMAYBE, open the keyboard only
+ * if opening the random file/device fails. A message will be
+ * printed describing the need for keyboard input.
+ *
+ *\li If "use_keyboard" is #ISC_ENTROPY_KEYBOARDNO, the keyboard will
+ * never be opened.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS if at least one source of entropy could be started.
+ *
+ *\li #ISC_R_NOENTROPY if use_keyboard is #ISC_ENTROPY_KEYBOARDNO and
+ * there is no random device pathname compiled into the program.
+ *
+ *\li A return code from isc_entropy_createfilesource() or
+ * isc_entropy_createcallbacksource().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ENTROPY_H */
diff --git a/lib/isc/include/isc/errno.h b/lib/isc/include/isc/errno.h
new file mode 100644
index 0000000..7777b8d
--- /dev/null
+++ b/lib/isc/include/isc/errno.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_ERRNO_H
+#define ISC_ERRNO_H 1
+
+/*! \file isc/file.h */
+
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_errno_toresult(int err);
+/*!<
+ * \brief Convert a POSIX errno value to an ISC result code.
+ */
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ERRNO_H */
diff --git a/lib/isc/include/isc/error.h b/lib/isc/include/isc/error.h
new file mode 100644
index 0000000..87bb6ba
--- /dev/null
+++ b/lib/isc/include/isc/error.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ERROR_H
+#define ISC_ERROR_H 1
+
+/*! \file isc/error.h */
+
+#include <stdarg.h>
+
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+#include <isc/likely.h>
+#include <isc/platform.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef void (*isc_errorcallback_t)(const char *, int, const char *, va_list);
+
+/*% set unexpected error */
+void
+isc_error_setunexpected(isc_errorcallback_t);
+
+/*% set fatal error */
+void
+isc_error_setfatal(isc_errorcallback_t);
+
+/*% unexpected error */
+void
+isc_error_unexpected(const char *, int, const char *, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+/*% fatal error */
+ISC_PLATFORM_NORETURN_PRE void
+isc_error_fatal(const char *, int, const char *, ...)
+ISC_FORMAT_PRINTF(3, 4) ISC_PLATFORM_NORETURN_POST;
+
+/*% runtimecheck error */
+ISC_PLATFORM_NORETURN_PRE void
+isc_error_runtimecheck(const char *, int, const char *) ISC_PLATFORM_NORETURN_POST;
+
+#define ISC_ERROR_RUNTIMECHECK(cond) \
+ ((void) (ISC_LIKELY(cond) || \
+ ((isc_error_runtimecheck)(__FILE__, __LINE__, #cond), 0)))
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ERROR_H */
diff --git a/lib/isc/include/isc/event.h b/lib/isc/include/isc/event.h
new file mode 100644
index 0000000..22f735d
--- /dev/null
+++ b/lib/isc/include/isc/event.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_EVENT_H
+#define ISC_EVENT_H 1
+
+/*! \file isc/event.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*****
+ ***** Events.
+ *****/
+
+typedef void (*isc_eventdestructor_t)(isc_event_t *);
+
+#define ISC_EVENT_COMMON(ltype) \
+ size_t ev_size; \
+ unsigned int ev_attributes; \
+ void * ev_tag; \
+ isc_eventtype_t ev_type; \
+ isc_taskaction_t ev_action; \
+ void * ev_arg; \
+ void * ev_sender; \
+ isc_eventdestructor_t ev_destroy; \
+ void * ev_destroy_arg; \
+ ISC_LINK(ltype) ev_link; \
+ ISC_LINK(ltype) ev_ratelink
+
+/*%
+ * Attributes matching a mask of 0x000000ff are reserved for the task library's
+ * definition. Attributes of 0xffffff00 may be used by the application
+ * or non-ISC libraries.
+ */
+#define ISC_EVENTATTR_NOPURGE 0x00000001
+
+/*%
+ * The ISC_EVENTATTR_CANCELED attribute is intended to indicate
+ * that an event is delivered as a result of a canceled operation
+ * rather than successful completion, by mutual agreement
+ * between the sender and receiver. It is not set or used by
+ * the task system.
+ */
+#define ISC_EVENTATTR_CANCELED 0x00000002
+
+#define ISC_EVENT_INIT(event, sz, at, ta, ty, ac, ar, sn, df, da) \
+do { \
+ (event)->ev_size = (sz); \
+ (event)->ev_attributes = (at); \
+ (event)->ev_tag = (ta); \
+ (event)->ev_type = (ty); \
+ (event)->ev_action = (ac); \
+ (event)->ev_arg = (ar); \
+ (event)->ev_sender = (sn); \
+ (event)->ev_destroy = (df); \
+ (event)->ev_destroy_arg = (da); \
+ ISC_LINK_INIT((event), ev_link); \
+ ISC_LINK_INIT((event), ev_ratelink); \
+} while (0)
+
+/*%
+ * This structure is public because "subclassing" it may be useful when
+ * defining new event types.
+ */
+struct isc_event {
+ ISC_EVENT_COMMON(struct isc_event);
+};
+
+#define ISC_EVENTTYPE_FIRSTEVENT 0x00000000
+#define ISC_EVENTTYPE_LASTEVENT 0xffffffff
+
+#define ISC_EVENT_PTR(p) ((isc_event_t **)(void *)(p))
+
+ISC_LANG_BEGINDECLS
+
+isc_event_t *
+isc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
+ isc_taskaction_t action, void *arg, size_t size);
+isc_event_t *
+isc_event_constallocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
+ isc_taskaction_t action, const void *arg, size_t size);
+/*%<
+ * Allocate an event structure.
+ *
+ * Allocate and initialize in a structure with initial elements
+ * defined by:
+ *
+ * \code
+ * struct {
+ * ISC_EVENT_COMMON(struct isc_event);
+ * ...
+ * };
+ * \endcode
+ *
+ * Requires:
+ *\li 'size' >= sizeof(struct isc_event)
+ *\li 'action' to be non NULL
+ *
+ * Returns:
+ *\li a pointer to a initialized structure of the requested size.
+ *\li NULL if unable to allocate memory.
+ */
+
+void
+isc_event_free(isc_event_t **);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_EVENT_H */
diff --git a/lib/isc/include/isc/eventclass.h b/lib/isc/include/isc/eventclass.h
new file mode 100644
index 0000000..15ad345
--- /dev/null
+++ b/lib/isc/include/isc/eventclass.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_EVENTCLASS_H
+#define ISC_EVENTCLASS_H 1
+
+/*! \file isc/eventclass.h
+ ***** Registry of Predefined Event Type Classes
+ *****/
+
+/*%
+ * An event class is an unsigned 16 bit number. Each class may contain up
+ * to 65536 events. An event type is formed by adding the event number
+ * within the class to the class number.
+ *
+ */
+
+#define ISC_EVENTCLASS(eclass) ((eclass) << 16)
+
+/*@{*/
+/*!
+ * Classes < 1024 are reserved for ISC use.
+ * Event classes >= 1024 and <= 65535 are reserved for application use.
+ */
+
+#define ISC_EVENTCLASS_TASK ISC_EVENTCLASS(0)
+#define ISC_EVENTCLASS_TIMER ISC_EVENTCLASS(1)
+#define ISC_EVENTCLASS_SOCKET ISC_EVENTCLASS(2)
+#define ISC_EVENTCLASS_FILE ISC_EVENTCLASS(3)
+#define ISC_EVENTCLASS_DNS ISC_EVENTCLASS(4)
+#define ISC_EVENTCLASS_APP ISC_EVENTCLASS(5)
+#define ISC_EVENTCLASS_OMAPI ISC_EVENTCLASS(6)
+#define ISC_EVENTCLASS_RATELIMITER ISC_EVENTCLASS(7)
+#define ISC_EVENTCLASS_ISCCC ISC_EVENTCLASS(8)
+/*@}*/
+
+#endif /* ISC_EVENTCLASS_H */
diff --git a/lib/isc/include/isc/file.h b/lib/isc/include/isc/file.h
new file mode 100644
index 0000000..0797f02
--- /dev/null
+++ b/lib/isc/include/isc/file.h
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_FILE_H
+#define ISC_FILE_H 1
+
+/*! \file isc/file.h */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/stat.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_file_settime(const char *file, isc_time_t *time);
+
+isc_result_t
+isc_file_mode(const char *file, mode_t *modep);
+
+isc_result_t
+isc_file_getmodtime(const char *file, isc_time_t *time);
+/*!<
+ * \brief Get the time of last modification of a file.
+ *
+ * Notes:
+ *\li The time that is set is relative to the (OS-specific) epoch, as are
+ * all isc_time_t structures.
+ *
+ * Requires:
+ *\li file != NULL.
+ *\li time != NULL.
+ *
+ * Ensures:
+ *\li If the file could not be accessed, 'time' is unchanged.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * Success.
+ *\li #ISC_R_NOTFOUND
+ * No such file exists.
+ *\li #ISC_R_INVALIDFILE
+ * The path specified was not usable by the operating system.
+ *\li #ISC_R_NOPERM
+ * The file's metainformation could not be retrieved because
+ * permission was denied to some part of the file's path.
+ *\li #ISC_R_IOERROR
+ * Hardware error interacting with the filesystem.
+ *\li #ISC_R_UNEXPECTED
+ * Something totally unexpected happened.
+ *
+ */
+
+isc_result_t
+isc_file_mktemplate(const char *path, char *buf, size_t buflen);
+/*!<
+ * \brief Generate a template string suitable for use with isc_file_openunique().
+ *
+ * Notes:
+ *\li This function is intended to make creating temporary files
+ * portable between different operating systems.
+ *
+ *\li The path is prepended to an implementation-defined string and
+ * placed into buf. The string has no path characters in it,
+ * and its maximum length is 14 characters plus a NUL. Thus
+ * buflen should be at least strlen(path) + 15 characters or
+ * an error will be returned.
+ *
+ * Requires:
+ *\li buf != NULL.
+ *
+ * Ensures:
+ *\li If result == #ISC_R_SUCCESS:
+ * buf contains a string suitable for use as the template argument
+ * to isc_file_openunique().
+ *
+ *\li If result != #ISC_R_SUCCESS:
+ * buf is unchanged.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOSPACE buflen indicates buf is too small for the catenation
+ * of the path with the internal template string.
+ */
+
+isc_result_t
+isc_file_openunique(char *templet, FILE **fp);
+isc_result_t
+isc_file_openuniqueprivate(char *templet, FILE **fp);
+isc_result_t
+isc_file_openuniquemode(char *templet, int mode, FILE **fp);
+isc_result_t
+isc_file_bopenunique(char *templet, FILE **fp);
+isc_result_t
+isc_file_bopenuniqueprivate(char *templet, FILE **fp);
+isc_result_t
+isc_file_bopenuniquemode(char *templet, int mode, FILE **fp);
+/*!<
+ * \brief Create and open a file with a unique name based on 'templet'.
+ * isc_file_bopen*() open the file in binary mode in Windows.
+ * isc_file_open*() open the file in text mode in Windows.
+ *
+ * Notes:
+ *\li 'template' is a reserved work in C++. If you want to complain
+ * about the spelling of 'templet', first look it up in the
+ * Merriam-Webster English dictionary. (http://www.m-w.com/)
+ *
+ *\li This function works by using the template to generate file names.
+ * The template must be a writable string, as it is modified in place.
+ * Trailing X characters in the file name (full file name on Unix,
+ * basename on Win32 -- eg, tmp-XXXXXX vs XXXXXX.tmp, respectively)
+ * are replaced with ASCII characters until a non-existent filename
+ * is found. If the template does not include pathname information,
+ * the files in the working directory of the program are searched.
+ *
+ *\li isc_file_mktemplate is a good, portable way to get a template.
+ *
+ * Requires:
+ *\li 'fp' is non-NULL and '*fp' is NULL.
+ *
+ *\li 'template' is non-NULL, and of a form suitable for use by
+ * the system as described above.
+ *
+ * Ensures:
+ *\li If result is #ISC_R_SUCCESS:
+ * *fp points to an stream opening in stdio's "w+" mode.
+ *
+ *\li If result is not #ISC_R_SUCCESS:
+ * *fp is NULL.
+ *
+ * No file is open. Even if one was created (but unable
+ * to be reopened as a stdio FILE pointer) then it has been
+ * removed.
+ *
+ *\li This function does *not* ensure that the template string has not been
+ * modified, even if the operation was unsuccessful.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * Success.
+ *\li #ISC_R_EXISTS
+ * No file with a unique name could be created based on the
+ * template.
+ *\li #ISC_R_INVALIDFILE
+ * The path specified was not usable by the operating system.
+ *\li #ISC_R_NOPERM
+ * The file could not be created because permission was denied
+ * to some part of the file's path.
+ *\li #ISC_R_IOERROR
+ * Hardware error interacting with the filesystem.
+ *\li #ISC_R_UNEXPECTED
+ * Something totally unexpected happened.
+ */
+
+isc_result_t
+isc_file_remove(const char *filename);
+/*!<
+ * \brief Remove the file named by 'filename'.
+ */
+
+isc_result_t
+isc_file_rename(const char *oldname, const char *newname);
+/*!<
+ * \brief Rename the file 'oldname' to 'newname'.
+ */
+
+bool
+isc_file_exists(const char *pathname);
+/*!<
+ * \brief Return #true if the calling process can tell that the given file exists.
+ * Will not return true if the calling process has insufficient privileges
+ * to search the entire path.
+ */
+
+bool
+isc_file_isabsolute(const char *filename);
+/*!<
+ * \brief Return #true if the given file name is absolute.
+ */
+
+isc_result_t
+isc_file_isplainfile(const char *name);
+
+isc_result_t
+isc_file_isplainfilefd(int fd);
+/*!<
+ * \brief Check that the file is a plain file
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * Success. The file is a plain file.
+ *\li #ISC_R_INVALIDFILE
+ * The path specified was not usable by the operating system.
+ *\li #ISC_R_FILENOTFOUND
+ * The file does not exist. This return code comes from
+ * errno=ENOENT when stat returns -1. This code is mentioned
+ * here, because in logconf.c, it is the one rcode that is
+ * permitted in addition to ISC_R_SUCCESS. This is done since
+ * the next call in logconf.c is to isc_stdio_open(), which
+ * will create the file if it can.
+ *\li other ISC_R_* errors translated from errno
+ * These occur when stat returns -1 and an errno.
+ */
+
+isc_result_t
+isc_file_isdirectory(const char *name);
+/*!<
+ * \brief Check that 'name' exists and is a directory.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * Success, file is a directory.
+ *\li #ISC_R_INVALIDFILE
+ * File is not a directory.
+ *\li #ISC_R_FILENOTFOUND
+ * File does not exist.
+ *\li other ISC_R_* errors translated from errno
+ * These occur when stat returns -1 and an errno.
+ */
+
+bool
+isc_file_iscurrentdir(const char *filename);
+/*!<
+ * \brief Return #true if the given file name is the current directory (".").
+ */
+
+bool
+isc_file_ischdiridempotent(const char *filename);
+/*%<
+ * Return #true if calling chdir(filename) multiple times will give
+ * the same result as calling it once.
+ */
+
+const char *
+isc_file_basename(const char *filename);
+/*%<
+ * Return the final component of the path in the file name.
+ */
+
+isc_result_t
+isc_file_progname(const char *filename, char *buf, size_t buflen);
+/*!<
+ * \brief Given an operating system specific file name "filename"
+ * referring to a program, return the canonical program name.
+ *
+ * Any directory prefix or executable file name extension (if
+ * used on the OS in case) is stripped. On systems where program
+ * names are case insensitive, the name is canonicalized to all
+ * lower case. The name is written to 'buf', an array of 'buflen'
+ * chars, and null terminated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE The name did not fit in 'buf'.
+ */
+
+isc_result_t
+isc_file_template(const char *path, const char *templet, char *buf,
+ size_t buflen);
+/*%<
+ * Create an OS specific template using 'path' to define the directory
+ * 'templet' to describe the filename and store the result in 'buf'
+ * such that path can be renamed to buf atomically.
+ */
+
+isc_result_t
+isc_file_renameunique(const char *file, char *templet);
+/*%<
+ * Rename 'file' using 'templet' as a template for the new file name.
+ */
+
+isc_result_t
+isc_file_absolutepath(const char *filename, char *path, size_t pathlen);
+/*%<
+ * Given a file name, return the fully qualified path to the file.
+ */
+
+/*
+ * XXX We should also have a isc_file_writeeopen() function
+ * for safely open a file in a publicly writable directory
+ * (see write_open() in BIND 8's ns_config.c).
+ */
+
+isc_result_t
+isc_file_truncate(const char *filename, isc_offset_t size);
+/*%<
+ * Truncate/extend the file specified to 'size' bytes.
+ */
+
+isc_result_t
+isc_file_safecreate(const char *filename, FILE **fp);
+/*%<
+ * Open 'filename' for writing, truncating if necessary. Ensure that
+ * if it existed it was a normal file. If creating the file, ensure
+ * that only the owner can read/write it.
+ */
+
+isc_result_t
+isc_file_splitpath(isc_mem_t *mctx, const char *path,
+ char **dirname, char const **basename);
+/*%<
+ * Split a path into dirname and basename. If 'path' contains no slash
+ * (or, on windows, backslash), then '*dirname' is set to ".".
+ *
+ * Allocates memory for '*dirname', which can be freed with isc_mem_free().
+ *
+ * Returns:
+ * - ISC_R_SUCCESS on success
+ * - ISC_R_INVALIDFILE if 'path' is empty or ends with '/'
+ * - ISC_R_NOMEMORY if unable to allocate memory
+ */
+
+isc_result_t
+isc_file_getsize(const char *file, off_t *size);
+/*%<
+ * Return the size of the file (stored in the parameter pointed
+ * to by 'size') in bytes.
+ *
+ * Returns:
+ * - ISC_R_SUCCESS on success
+ */
+
+isc_result_t
+isc_file_getsizefd(int fd, off_t *size);
+/*%<
+ * Return the size of the file (stored in the parameter pointed
+ * to by 'size') in bytes.
+ *
+ * Returns:
+ * - ISC_R_SUCCESS on success
+ */
+
+void *
+isc_file_mmap(void *addr, size_t len, int prot,
+ int flags, int fd, off_t offset);
+/*%<
+ * Portable front-end to mmap(). If mmap() is not defined on this
+ * platform, then we simulate it by calling malloc() and read().
+ * (In this event, the addr, prot, and flags parameters are ignored).
+ */
+
+int
+isc_file_munmap(void *addr, size_t len);
+/*%<
+ * Portable front-end to munmap(). If munmap() is not defined on
+ * this platform, then we simply free the memory.
+ */
+
+isc_result_t
+isc_file_sanitize(const char *dir, const char *base, const char *ext,
+ char *path, size_t length);
+/*%<
+ * Generate a sanitized filename, such as for MKEYS or NZF files.
+ *
+ * Historically, MKEYS and NZF files used SHA256 hashes of the view
+ * name for the filename; this was to deal with the possibility of
+ * forbidden characters such as "/" being in a view name, and to
+ * avoid problems with case-insensitive file systems.
+ *
+ * Given a basename 'base' and an extension 'ext', this function checks
+ * for the existence of file using the old-style name format in directory
+ * 'dir'. If found, it returns the path to that file. If there is no
+ * file already in place, a new pathname is generated; if the basename
+ * contains any excluded characters, then a truncated SHA256 hash is
+ * used, otherwise the basename is used. The path name is copied
+ * into 'path', which must point to a buffer of at least 'length'
+ * bytes.
+ *
+ * Requires:
+ * - base != NULL
+ * - path != NULL
+ *
+ * Returns:
+ * - ISC_R_SUCCESS on success
+ * - ISC_R_NOSPACE if the resulting path would be longer than 'length'
+ */
+
+bool
+isc_file_isdirwritable(const char *path);
+/*%<
+ * Return true if the path is a directory and is writable
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_FILE_H */
diff --git a/lib/isc/include/isc/formatcheck.h b/lib/isc/include/isc/formatcheck.h
new file mode 100644
index 0000000..162c16e
--- /dev/null
+++ b/lib/isc/include/isc/formatcheck.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_FORMATCHECK_H
+#define ISC_FORMATCHECK_H 1
+
+/*! \file isc/formatcheck.h */
+
+/*%
+ * ISC_FORMAT_PRINTF().
+ *
+ * \li fmt is the location of the format string parameter.
+ * \li args is the location of the first argument (or 0 for no argument checking).
+ *
+ * Note:
+ * \li The first parameter is 1, not 0.
+ */
+#ifdef __GNUC__
+#define ISC_FORMAT_PRINTF(fmt, args) __attribute__((__format__(__printf__, fmt, args)))
+#else
+#define ISC_FORMAT_PRINTF(fmt, args)
+#endif
+
+#endif /* ISC_FORMATCHECK_H */
diff --git a/lib/isc/include/isc/fsaccess.h b/lib/isc/include/isc/fsaccess.h
new file mode 100644
index 0000000..d842aaf
--- /dev/null
+++ b/lib/isc/include/isc/fsaccess.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_FSACCESS_H
+#define ISC_FSACCESS_H 1
+
+/*! \file isc/fsaccess.h
+ * \brief The ISC filesystem access module encapsulates the setting of file
+ * and directory access permissions into one API that is meant to be
+ * portable to multiple operating systems.
+ *
+ * The two primary operating system flavors that are initially accommodated
+ * are POSIX and Windows NT 4.0 and later. The Windows NT access model is
+ * considerable more flexible than POSIX's model (as much as I am loathe to
+ * admit it), and so the ISC API has a higher degree of complexity than would
+ * be needed to simply address POSIX's needs.
+ *
+ * The full breadth of NT's flexibility is not available either, for the
+ * present time. Much of it is to provide compatibility with what Unix
+ * programmers are expecting. This is also due to not yet really needing all
+ * of the functionality of an NT system (or, for that matter, a POSIX system)
+ * in BIND9, and so resolving how to handle the various incompatibilities has
+ * been a purely theoretical exercise with no operational experience to
+ * indicate how flawed the thinking may be.
+ *
+ * Some of the more notable dumbing down of NT for this API includes:
+ *
+ *\li Each of FILE_READ_DATA and FILE_READ_EA are set with #ISC_FSACCESS_READ.
+ *
+ * \li All of FILE_WRITE_DATA, FILE_WRITE_EA and FILE_APPEND_DATA are
+ * set with #ISC_FSACCESS_WRITE. FILE_WRITE_ATTRIBUTES is not set
+ * so as to be consistent with Unix, where only the owner of the file
+ * or the superuser can change the attributes/mode of a file.
+ *
+ * \li Both of FILE_ADD_FILE and FILE_ADD_SUBDIRECTORY are set with
+ * #ISC_FSACCESS_CREATECHILD. This is similar to setting the WRITE
+ * permission on a Unix directory.
+ *
+ * \li SYNCHRONIZE is always set for files and directories, unless someone
+ * can give me a reason why this is a bad idea.
+ *
+ * \li READ_CONTROL and FILE_READ_ATTRIBUTES are always set; this is
+ * consistent with Unix, where any file or directory can be stat()'d
+ * unless the directory path disallows complete access somewhere along
+ * the way.
+ *
+ * \li WRITE_DAC is only set for the owner. This too is consistent with
+ * Unix, and is tighter security than allowing anyone else to be
+ * able to set permissions.
+ *
+ * \li DELETE is only set for the owner. On Unix the ability to delete
+ * a file is controlled by the directory permissions, but it isn't
+ * currently clear to me what happens on NT if the directory has
+ * FILE_DELETE_CHILD set but a file within it does not have DELETE
+ * set. Always setting DELETE on the file/directory for the owner
+ * gives maximum flexibility to the owner without exposing the
+ * file to deletion by others.
+ *
+ * \li WRITE_OWNER is never set. This too is consistent with Unix,
+ * and is also tighter security than allowing anyone to change the
+ * ownership of the file apart from the superu..ahem, Administrator.
+ *
+ * \li Inheritance is set to NO_INHERITANCE.
+ *
+ * Unix's dumbing down includes:
+ *
+ * \li The sticky bit cannot be set.
+ *
+ * \li setuid and setgid cannot be set.
+ *
+ * \li Only regular files and directories can be set.
+ *
+ * The rest of this comment discusses a few of the incompatibilities
+ * between the two systems that need more thought if this API is to
+ * be extended to accommodate them.
+ *
+ * The Windows standard access right "DELETE" doesn't have a direct
+ * equivalent in the Unix world, so it isn't clear what should be done
+ * with it.
+ *
+ * The Unix sticky bit is not supported. While NT does have a concept
+ * of allowing users to create files in a directory but not delete or
+ * rename them, it does not have a concept of allowing them to be deleted
+ * if they are owned by the user trying to delete/rename. While it is
+ * probable that something could be cobbled together in NT 5 with inheritance,
+ * it can't really be done in NT 4 as a single property that you could
+ * set on a directory. You'd need to coordinate something with file creation
+ * so that every file created had DELETE set for the owner but noone else.
+ *
+ * On Unix systems, setting #ISC_FSACCESS_LISTDIRECTORY sets READ.
+ * ... setting either #ISC_FSACCESS_CREATECHILD or #ISC_FSACCESS_DELETECHILD
+ * sets WRITE.
+ * ... setting #ISC_FSACCESS_ACCESSCHILD sets EXECUTE.
+ *
+ * On NT systems, setting #ISC_FSACCESS_LISTDIRECTORY sets FILE_LIST_DIRECTORY.
+ * ... setting #ISC_FSACCESS_CREATECHILD sets FILE_CREATE_CHILD independently.
+ * ... setting #ISC_FSACCESS_DELETECHILD sets FILE_DELETE_CHILD independently.
+ * ... setting #ISC_FSACCESS_ACCESSCHILD sets FILE_TRAVERSE.
+ *
+ * Unresolved: XXXDCL
+ * \li What NT access right controls the ability to rename a file?
+ * \li How does DELETE work? If a directory has FILE_DELETE_CHILD but a
+ * file or directory within it does not have DELETE, is that file
+ * or directory deletable?
+ * \li To implement isc_fsaccess_get(), mapping an existing Unix permission
+ * mode_t back to an isc_fsaccess_t is pretty trivial; however, mapping
+ * an NT DACL could be impossible to do in a responsible way.
+ * \li Similarly, trying to implement the functionality of being able to
+ * say "add group writability to whatever permissions already exist"
+ * could be tricky on NT because of the order-of-entry issue combined
+ * with possibly having one or more matching ACEs already explicitly
+ * granting or denying access. Because this functionality is
+ * not yet needed by the ISC, no code has been written to try to
+ * solve this problem.
+ */
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*
+ * Trustees.
+ */
+#define ISC_FSACCESS_OWNER 0x1 /*%< User account. */
+#define ISC_FSACCESS_GROUP 0x2 /*%< Primary group owner. */
+#define ISC_FSACCESS_OTHER 0x4 /*%< Not the owner or the group owner. */
+#define ISC_FSACCESS_WORLD 0x7 /*%< User, Group, Other. */
+
+/*
+ * Types of permission.
+ */
+#define ISC_FSACCESS_READ 0x00000001 /*%< File only. */
+#define ISC_FSACCESS_WRITE 0x00000002 /*%< File only. */
+#define ISC_FSACCESS_EXECUTE 0x00000004 /*%< File only. */
+#define ISC_FSACCESS_CREATECHILD 0x00000008 /*%< Dir only. */
+#define ISC_FSACCESS_DELETECHILD 0x00000010 /*%< Dir only. */
+#define ISC_FSACCESS_LISTDIRECTORY 0x00000020 /*%< Dir only. */
+#define ISC_FSACCESS_ACCESSCHILD 0x00000040 /*%< Dir only. */
+
+/*%
+ * Adding any permission bits beyond 0x200 would mean typedef'ing
+ * isc_fsaccess_t as uint64_t, and redefining this value to
+ * reflect the new range of permission types, Probably to 21 for
+ * maximum flexibility. The number of bits has to accommodate all of
+ * the permission types, and three full sets of them have to fit
+ * within an isc_fsaccess_t.
+ */
+#define ISC__FSACCESS_PERMISSIONBITS 10
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_fsaccess_add(int trustee, int permission, isc_fsaccess_t *access);
+
+void
+isc_fsaccess_remove(int trustee, int permission, isc_fsaccess_t *access);
+
+isc_result_t
+isc_fsaccess_set(const char *path, isc_fsaccess_t access);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_FSACCESS_H */
diff --git a/lib/isc/include/isc/hash.h b/lib/isc/include/isc/hash.h
new file mode 100644
index 0000000..fd558f7
--- /dev/null
+++ b/lib/isc/include/isc/hash.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_HASH_H
+#define ISC_HASH_H 1
+
+#include <stdbool.h>
+
+#include <isc/deprecated.h>
+#include <isc/types.h>
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/hash.h
+ *
+ * \brief The hash API
+ * provides an unpredictable hash value for variable length data.
+ * A hash object contains a random vector (which is hidden from clients
+ * of this API) to make the actual hash value unpredictable.
+ *
+ * The algorithm used in the API guarantees the probability of hash
+ * collision; in the current implementation, as long as the values stored
+ * in the random vector are unpredictable, the probability of hash
+ * collision between arbitrary two different values is at most 1/2^16.
+ *
+ * Although the API is generic about the hash keys, it mainly expects
+ * DNS names (and sometimes IPv4/v6 addresses) as inputs. It has an
+ * upper limit of the input length, and may run slow to calculate the
+ * hash values for large inputs.
+ *
+ * This API is designed to be general so that it can provide multiple
+ * different hash contexts that have different random vectors. However,
+ * it should be typical to have a single context for an entire system.
+ * To support such cases, the API also provides a single-context mode.
+ *
+ * \li MP:
+ * The hash object is almost read-only. Once the internal random vector
+ * is initialized, no write operation will occur, and there will be no
+ * need to lock the object to calculate actual hash values.
+ *
+ * \li Reliability:
+ * In some cases this module uses low-level data copy to initialize the
+ * random vector. Errors in this part are likely to crash the server or
+ * corrupt memory.
+ *
+ * \li Resources:
+ * A buffer, used as a random vector for calculating hash values.
+ *
+ * \li Security:
+ * This module intends to provide unpredictable hash values in
+ * adversarial environments in order to avoid denial of service attacks
+ * to hash buckets.
+ * Its unpredictability relies on the quality of entropy to build the
+ * random vector.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/types.h>
+
+/***
+ *** Functions
+ ***/
+ISC_LANG_BEGINDECLS
+
+LIBISC_EXTERNAL_DATA extern isc_hash_t *isc_hashctx;
+
+isc_result_t
+isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit,
+ isc_hash_t **hctx);
+isc_result_t
+isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit);
+/*!<
+ * \brief Create a new hash object.
+ *
+ * isc_hash_ctxcreate() creates a different object.
+ *
+ * isc_hash_create() creates a module-internal object to support the
+ * single-context mode. It should be called only once.
+ *
+ * 'entropy' must be NULL or a valid entropy object. If 'entropy' is NULL,
+ * pseudo random values will be used to build the random vector, which may
+ * weaken security.
+ *
+ * 'limit' specifies the maximum number of hash keys. If it is too large,
+ * these functions may fail.
+ */
+
+void
+isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp)
+ ISC_DEPRECATED;
+/*!<
+ * \brief Attach to a hash object.
+ *
+ * This function is only necessary for the multiple-context mode.
+ */
+
+void
+isc_hash_ctxdetach(isc_hash_t **hctxp)
+ ISC_DEPRECATED;
+/*!<
+ * \brief Detach from a hash object.
+ *
+ * This function is for the multiple-context mode, and takes a valid
+ * hash object as an argument.
+ */
+
+void
+isc_hash_destroy(void);
+/*!<
+ * \brief This function is for the single-context mode, and is expected to be used
+ * as a counterpart of isc_hash_create().
+ *
+ * A valid module-internal hash object must have been created, and this
+ * function should be called only once.
+ */
+
+/*@{*/
+void
+isc_hash_ctxinit(isc_hash_t *hctx);
+void
+isc_hash_init(void);
+/*!<
+ * \brief Initialize a hash object.
+ *
+ * It fills in the random vector with a proper
+ * source of entropy, which is typically from the entropy object specified
+ * at the creation. Thus, it is desirable to call these functions after
+ * initializing the entropy object with some good entropy sources.
+ *
+ * These functions should be called before the first hash calculation.
+ *
+ * isc_hash_ctxinit() is for the multiple-context mode, and takes a valid hash
+ * object as an argument.
+ *
+ * isc_hash_init() is for the single-context mode. A valid module-internal
+ * hash object must have been created, and this function should be called only
+ * once.
+ */
+/*@}*/
+
+/*@{*/
+unsigned int
+isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
+ unsigned int keylen, bool case_sensitive)
+ ISC_DEPRECATED;
+unsigned int
+isc_hash_calc(const unsigned char *key, unsigned int keylen,
+ bool case_sensitive)
+ ISC_DEPRECATED;
+/*!<
+ * \brief Calculate a hash value.
+ *
+ * isc_hash_ctxinit() is for the multiple-context mode, and takes a valid hash
+ * object as an argument.
+ *
+ * isc_hash_init() is for the single-context mode. A valid module-internal
+ * hash object must have been created.
+ *
+ * 'key' is the hash key, which is a variable length buffer.
+ *
+ * 'keylen' specifies the key length, which must not be larger than the limit
+ * specified for the corresponding hash object.
+ *
+ * 'case_sensitive' specifies whether the hash key should be treated as
+ * case_sensitive values. It should typically be false if the hash key
+ * is a DNS name.
+ */
+/*@}*/
+
+void
+isc__hash_setvec(const uint16_t *vec)
+ ISC_DEPRECATED;
+
+/*!<
+ * \brief Set the contents of the random vector used in hashing.
+ *
+ * WARNING: This function is meant to be used only in testing code. It
+ * must not be used anywhere in normally running code.
+ *
+ * The hash context must have been created beforehand, otherwise this
+ * function is a nop.
+ *
+ * 'vec' is not documented here on purpose. You should know what you are
+ * doing before using this function.
+ */
+
+const void *
+isc_hash_get_initializer(void);
+
+void
+isc_hash_set_initializer(const void *initializer);
+
+uint32_t
+isc_hash_function(const void *data, size_t length,
+ bool case_sensitive,
+ const uint32_t *previous_hashp);
+uint32_t
+isc_hash_function_reverse(const void *data, size_t length,
+ bool case_sensitive,
+ const uint32_t *previous_hashp);
+/*!<
+ * \brief Calculate a hash over data.
+ *
+ * This hash function is useful for hashtables. The hash function is
+ * opaque and not important to the caller. The returned hash values are
+ * non-deterministic and will have different mapping every time a
+ * process using this library is run, but will have uniform
+ * distribution.
+ *
+ * isc_hash_function() calculates the hash from start to end over the
+ * input data. isc_hash_function_reverse() calculates the hash from the
+ * end to the start over the input data. The difference in order is
+ * useful in incremental hashing; for example, a previously hashed
+ * value for 'com' can be used as input when hashing 'example.com'.
+ *
+ * This is a new variant of isc_hash_calc() and will supercede
+ * isc_hash_calc() eventually.
+ *
+ * 'data' is the data to be hashed.
+ *
+ * 'length' is the size of the data to be hashed.
+ *
+ * 'case_sensitive' specifies whether the hash key should be treated as
+ * case_sensitive values. It should typically be false if the hash key
+ * is a DNS name.
+ *
+ * 'previous_hashp' is a pointer to a previous hash value returned by
+ * this function. It can be used to perform incremental hashing. NULL
+ * must be passed during first calls.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HASH_H */
diff --git a/lib/isc/include/isc/heap.h b/lib/isc/include/isc/heap.h
new file mode 100644
index 0000000..747287b
--- /dev/null
+++ b/lib/isc/include/isc/heap.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_HEAP_H
+#define ISC_HEAP_H 1
+
+/*! \file isc/heap.h */
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * The comparison function returns true if the first argument has
+ * higher priority than the second argument, and false otherwise.
+ */
+typedef bool (*isc_heapcompare_t)(void *, void *);
+
+/*%
+ * The index function allows the client of the heap to receive a callback
+ * when an item's index number changes. This allows it to maintain
+ * sync with its external state, but still delete itself, since deletions
+ * from the heap require the index be provided.
+ */
+typedef void (*isc_heapindex_t)(void *, unsigned int);
+
+/*%
+ * The heapaction function is used when iterating over the heap.
+ *
+ * NOTE: The heap structure CANNOT BE MODIFIED during the call to
+ * isc_heap_foreach().
+ */
+typedef void (*isc_heapaction_t)(void *, void *);
+
+typedef struct isc_heap isc_heap_t;
+
+isc_result_t
+isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare,
+ isc_heapindex_t index, unsigned int size_increment,
+ isc_heap_t **heapp);
+/*!<
+ * \brief Create a new heap. The heap is implemented using a space-efficient
+ * storage method. When the heap elements are deleted space is not freed
+ * but will be reused when new elements are inserted.
+ *
+ * Heap elements are indexed from 1.
+ *
+ * Requires:
+ *\li "mctx" is valid.
+ *\li "compare" is a function which takes two void * arguments and
+ * returns true if the first argument has a higher priority than
+ * the second, and false otherwise.
+ *\li "index" is a function which takes a void *, and an unsigned int
+ * argument. This function will be called whenever an element's
+ * index value changes, so it may continue to delete itself from the
+ * heap. This option may be NULL if this functionality is unneeded.
+ *\li "size_increment" is a hint about how large the heap should grow
+ * when resizing is needed. If this is 0, a default size will be
+ * used, which is currently 1024, allowing space for an additional 1024
+ * heap elements to be inserted before adding more space.
+ *\li "heapp" is not NULL, and "*heap" is NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS - success
+ *\li ISC_R_NOMEMORY - insufficient memory
+ */
+
+void
+isc_heap_destroy(isc_heap_t **heapp);
+/*!<
+ * \brief Destroys a heap.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ */
+
+isc_result_t
+isc_heap_insert(isc_heap_t *heap, void *elt);
+/*!<
+ * \brief Inserts a new element into a heap.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ */
+
+void
+isc_heap_delete(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Deletes an element from a heap, by element index.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ */
+
+void
+isc_heap_increased(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Indicates to the heap that an element's priority has increased.
+ * This function MUST be called whenever an element has increased in priority.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ */
+
+void
+isc_heap_decreased(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Indicates to the heap that an element's priority has decreased.
+ * This function MUST be called whenever an element has decreased in priority.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ */
+
+void *
+isc_heap_element(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Returns the element for a specific element index.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ *
+ * Returns:
+ *\li A pointer to the element for the element index.
+ */
+
+void
+isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap);
+/*!<
+ * \brief Iterate over the heap, calling an action for each element. The
+ * order of iteration is not sorted.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "action" is not NULL, and is a function which takes two arguments.
+ * The first is a void *, representing the element, and the second is
+ * "uap" as provided to isc_heap_foreach.
+ *\li "uap" is a caller-provided argument, and may be NULL.
+ *
+ * Note:
+ *\li The heap structure CANNOT be modified during this iteration. The only
+ * safe function to call while iterating the heap is isc_heap_element().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HEAP_H */
diff --git a/lib/isc/include/isc/hex.h b/lib/isc/include/isc/hex.h
new file mode 100644
index 0000000..3e09e59
--- /dev/null
+++ b/lib/isc/include/isc/hex.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_HEX_H
+#define ISC_HEX_H 1
+
+/*! \file isc/hex.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_hex_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+/*!<
+ * \brief Convert data into hex encoded text.
+ *
+ * Notes:
+ *\li The hex encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data
+ *\li 'target' is a text buffer containing available space
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters
+ *
+ * Ensures:
+ *\li target will contain the hex encoded version of the data
+ * in source. The 'used' pointer in target will be advanced as
+ * necessary.
+ */
+
+isc_result_t
+isc_hex_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated hex string.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADHEX -- 'cstr' is not a valid hex encoding.
+ *
+ * Other error returns are any possible error code from:
+ * isc_lex_create(),
+ * isc_lex_openbuffer(),
+ * isc_hex_tobuffer().
+ */
+
+isc_result_t
+isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert hex encoded text from a lexer context into data.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer context
+ *\li 'target' is a buffer containing binary data
+ *\li 'length' is an integer
+ *
+ * Ensures:
+ *\li target will contain the data represented by the hex encoded
+ * string parsed by the lexer. No more than length bytes will be read,
+ * if length is positive. The 'used' pointer in target will be
+ * advanced as necessary.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HEX_H */
diff --git a/lib/isc/include/isc/hmacmd5.h b/lib/isc/include/isc/hmacmd5.h
new file mode 100644
index 0000000..ca2ec56
--- /dev/null
+++ b/lib/isc/include/isc/hmacmd5.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file isc/hmacmd5.h
+ * \brief This is the header file for the HMAC-MD5 keyed hash algorithm
+ * described in RFC2104.
+ */
+
+#ifndef ISC_HMACMD5_H
+#define ISC_HMACMD5_H 1
+
+#include <pk11/site.h>
+
+#ifndef PK11_MD5_DISABLE
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/md5.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#define ISC_HMACMD5_KEYLENGTH 64
+
+#ifdef ISC_PLATFORM_OPENSSLHASH
+#include <openssl/opensslv.h>
+#include <openssl/hmac.h>
+
+typedef struct {
+ HMAC_CTX *ctx;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ HMAC_CTX _ctx;
+#endif
+} isc_hmacmd5_t;
+
+#elif PKCS11CRYPTO
+#include <pk11/pk11.h>
+
+typedef pk11_context_t isc_hmacmd5_t;
+
+#else
+
+typedef struct {
+ isc_md5_t md5ctx;
+ unsigned char key[ISC_HMACMD5_KEYLENGTH];
+} isc_hmacmd5_t;
+#endif
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx);
+
+void
+isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest);
+
+bool
+isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest);
+
+bool
+isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len);
+
+bool
+isc_hmacmd5_check(int testing);
+
+ISC_LANG_ENDDECLS
+
+#endif /* !PK11_MD5_DISABLE */
+
+#endif /* ISC_HMACMD5_H */
diff --git a/lib/isc/include/isc/hmacsha.h b/lib/isc/include/isc/hmacsha.h
new file mode 100644
index 0000000..3c80fba
--- /dev/null
+++ b/lib/isc/include/isc/hmacsha.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file isc/hmacsha.h
+ * This is the header file for the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256,
+ * HMAC-SHA334 and HMAC-SHA512 hash algorithm described in RFC 2104.
+ */
+
+#ifndef ISC_HMACSHA_H
+#define ISC_HMACSHA_H 1
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/sha1.h>
+#include <isc/sha2.h>
+#include <isc/types.h>
+
+#define ISC_HMACSHA1_KEYLENGTH ISC_SHA1_BLOCK_LENGTH
+#define ISC_HMACSHA224_KEYLENGTH ISC_SHA224_BLOCK_LENGTH
+#define ISC_HMACSHA256_KEYLENGTH ISC_SHA256_BLOCK_LENGTH
+#define ISC_HMACSHA384_KEYLENGTH ISC_SHA384_BLOCK_LENGTH
+#define ISC_HMACSHA512_KEYLENGTH ISC_SHA512_BLOCK_LENGTH
+
+#ifdef ISC_PLATFORM_OPENSSLHASH
+#include <openssl/opensslv.h>
+#include <openssl/hmac.h>
+
+typedef struct {
+ HMAC_CTX *ctx;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ HMAC_CTX _ctx;
+#endif
+} isc_hmacsha_t;
+
+typedef isc_hmacsha_t isc_hmacsha1_t;
+typedef isc_hmacsha_t isc_hmacsha224_t;
+typedef isc_hmacsha_t isc_hmacsha256_t;
+typedef isc_hmacsha_t isc_hmacsha384_t;
+typedef isc_hmacsha_t isc_hmacsha512_t;
+
+#elif PKCS11CRYPTO
+#include <pk11/pk11.h>
+
+typedef pk11_context_t isc_hmacsha1_t;
+typedef pk11_context_t isc_hmacsha224_t;
+typedef pk11_context_t isc_hmacsha256_t;
+typedef pk11_context_t isc_hmacsha384_t;
+typedef pk11_context_t isc_hmacsha512_t;
+
+#else
+
+typedef struct {
+ isc_sha1_t sha1ctx;
+ unsigned char key[ISC_HMACSHA1_KEYLENGTH];
+} isc_hmacsha1_t;
+
+typedef struct {
+ isc_sha224_t sha224ctx;
+ unsigned char key[ISC_HMACSHA224_KEYLENGTH];
+} isc_hmacsha224_t;
+
+typedef struct {
+ isc_sha256_t sha256ctx;
+ unsigned char key[ISC_HMACSHA256_KEYLENGTH];
+} isc_hmacsha256_t;
+
+typedef struct {
+ isc_sha384_t sha384ctx;
+ unsigned char key[ISC_HMACSHA384_KEYLENGTH];
+} isc_hmacsha384_t;
+
+typedef struct {
+ isc_sha512_t sha512ctx;
+ unsigned char key[ISC_HMACSHA512_KEYLENGTH];
+} isc_hmacsha512_t;
+#endif
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx);
+
+void
+isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len);
+
+bool
+isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len);
+
+bool
+isc_hmacsha1_check(int testing);
+
+
+void
+isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx);
+
+void
+isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len);
+
+bool
+isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx);
+
+void
+isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len);
+
+bool
+isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx);
+
+void
+isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len);
+
+bool
+isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx);
+
+void
+isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len);
+
+bool
+isc_hmacsha512_verify(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HMACSHA_H */
diff --git a/lib/isc/include/isc/ht.h b/lib/isc/include/isc/ht.h
new file mode 100644
index 0000000..b36d77f
--- /dev/null
+++ b/lib/isc/include/isc/ht.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* ! \file */
+
+#ifndef ISC_HT_H
+#define ISC_HT_H 1
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <isc/types.h>
+#include <isc/result.h>
+
+typedef struct isc_ht isc_ht_t;
+typedef struct isc_ht_iter isc_ht_iter_t;
+
+/*%
+ * Initialize hashtable at *htp, using memory context and size of (1<<bits)
+ *
+ * Requires:
+ *\li htp is not NULL
+ *\li *htp is NULL
+ *\li mctx is a valid memory context
+ *\li bits >=1 && bits <=32
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY -- not enough memory to create pool
+ *\li #ISC_R_SUCCESS -- all is well.
+ */
+isc_result_t
+isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits);
+
+/*%
+ * Destroy hashtable, freeing everything
+ *
+ * Requires:
+ * \li *htp is valid hashtable
+ */
+void
+isc_ht_destroy(isc_ht_t **htp);
+
+/*%
+ * Add a node to hashtable, pointed by binary key 'key' of size 'keysize';
+ * set its value to 'value'
+ *
+ * Requires:
+ *\li ht is a valid hashtable
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY -- not enough memory to create pool
+ *\li #ISC_R_EXISTS -- node of the same key already exists
+ *\li #ISC_R_SUCCESS -- all is well.
+ */
+isc_result_t
+isc_ht_add(isc_ht_t *ht, const unsigned char *key, uint32_t keysize,
+ void *value);
+
+/*%
+ * Find a node matching 'key'/'keysize' in hashtable 'ht';
+ * if found, set 'value' to its value
+ *
+ * Requires:
+ * \li 'ht' is a valid hashtable
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS -- success
+ * \li #ISC_R_NOTFOUND -- key not found
+ */
+isc_result_t
+isc_ht_find(const isc_ht_t *ht, const unsigned char *key,
+ uint32_t keysize, void **valuep);
+
+/*%
+ * Delete node from hashtable
+ * Requires:
+ *\li ht is a valid hashtable
+ *
+ * Returns:
+ *\li #ISC_R_NOTFOUND -- key not found
+ *\li #ISC_R_SUCCESS -- all is well
+ */
+isc_result_t
+isc_ht_delete(isc_ht_t *ht, const unsigned char *key, uint32_t keysize);
+
+/*%
+ * Create an iterator for the hashtable; point '*itp' to it.
+ */
+isc_result_t
+isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp);
+
+/*%
+ * Destroy the iterator '*itp', set it to NULL
+ */
+void
+isc_ht_iter_destroy(isc_ht_iter_t **itp);
+
+/*%
+ * Set an iterator to the first entry.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS -- success
+ * \li #ISC_R_NOMORE -- no data in the hashtable
+ */
+isc_result_t
+isc_ht_iter_first(isc_ht_iter_t *it);
+
+/*%
+ * Set an iterator to the next entry.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS -- success
+ * \li #ISC_R_NOMORE -- end of hashtable reached
+ */
+isc_result_t
+isc_ht_iter_next(isc_ht_iter_t *it);
+
+/*%
+ * Delete current entry and set an iterator to the next entry.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS -- success
+ * \li #ISC_R_NOMORE -- end of hashtable reached
+ */
+isc_result_t
+isc_ht_iter_delcurrent_next(isc_ht_iter_t *it);
+
+
+/*%
+ * Set 'value' to the current value under the iterator
+ */
+void
+isc_ht_iter_current(isc_ht_iter_t *it, void **valuep);
+
+/*%
+ * Set 'key' and 'keysize to the current key and keysize for the value
+ * under the iterator
+ */
+void
+isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, size_t *keysize);
+
+/*%
+ * Returns the number of items in the hashtable.
+ *
+ * Requires:
+ *\li 'ht' is a valid hashtable
+ */
+unsigned int
+isc_ht_count(isc_ht_t *ht);
+#endif
diff --git a/lib/isc/include/isc/httpd.h b/lib/isc/include/isc/httpd.h
new file mode 100644
index 0000000..b02b33e
--- /dev/null
+++ b/lib/isc/include/isc/httpd.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_HTTPD_H
+#define ISC_HTTPD_H 1
+
+/*! \file */
+
+#include <stdbool.h>
+
+#include <isc/event.h>
+#include <isc/eventclass.h>
+#include <isc/types.h>
+#include <isc/mutex.h>
+#include <isc/task.h>
+#include <isc/time.h>
+
+/*%
+ * HTTP urls. These are the URLs we manage, and the function to call to
+ * provide the data for it. We pass in the base url (so the same function
+ * can handle multiple requests), and a structure to fill in to return a
+ * result to the client. We also pass in a pointer to be filled in for
+ * the data cleanup function.
+ */
+struct isc_httpdurl {
+ char *url;
+ isc_httpdaction_t *action;
+ void *action_arg;
+ bool isstatic;
+ isc_time_t loadtime;
+ ISC_LINK(isc_httpdurl_t) link;
+};
+
+#define HTTPD_EVENTCLASS ISC_EVENTCLASS(4300)
+#define HTTPD_SHUTDOWN (HTTPD_EVENTCLASS + 0x0001)
+
+#define ISC_HTTPDMGR_FLAGSHUTTINGDOWN 0x00000001
+
+/*
+ * Create a new http daemon which will send, once every time period,
+ * a http-like header followed by HTTP data.
+ */
+isc_result_t
+isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
+ isc_httpdclientok_t *client_ok,
+ isc_httpdondestroy_t *ondestory, void *cb_arg,
+ isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdp);
+
+void
+isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdp);
+
+isc_result_t
+isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url,
+ isc_httpdaction_t *func, void *arg);
+
+isc_result_t
+isc_httpdmgr_addurl2(isc_httpdmgr_t *httpdmgr, const char *url,
+ bool isstatic,
+ isc_httpdaction_t *func, void *arg);
+
+isc_result_t
+isc_httpd_response(isc_httpd_t *httpd);
+
+isc_result_t
+isc_httpd_addheader(isc_httpd_t *httpd, const char *name,
+ const char *val);
+
+isc_result_t
+isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val);
+
+isc_result_t isc_httpd_endheaders(isc_httpd_t *httpd);
+
+void
+isc_httpd_setfinishhook(void (*fn)(void));
+
+#endif /* ISC_HTTPD_H */
diff --git a/lib/isc/include/isc/int.h b/lib/isc/include/isc/int.h
new file mode 100644
index 0000000..9bf3066
--- /dev/null
+++ b/lib/isc/include/isc/int.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <inttypes.h>
+
+typedef int8_t isc_int8_t;
+typedef uint8_t isc_uint8_t;
+typedef int16_t isc_int16_t;
+typedef uint16_t isc_uint16_t;
+typedef int32_t isc_int32_t;
+typedef uint32_t isc_uint32_t;
+typedef int64_t isc_int64_t;
+typedef uint64_t isc_uint64_t;
+
+#define ISC_INT8_MIN INT8_MIN
+#define ISC_INT8_MAX INT8_MAX
+#define ISC_UINT8_MAX UINT8_MAX
+
+#define ISC_INT16_MIN INT16_MIN
+#define ISC_INT16_MAX INT16_MAX
+#define ISC_UINT16_MAX UINT16_MAX
+
+#define ISC_INT32_MIN INT32_MIN
+#define ISC_INT32_MAX INT32_MAX
+#define ISC_UINT32_MAX UINT32_MAX
+
+#define ISC_INT64_MIN INT64_MIN
+#define ISC_INT64_MAX INT64_MAX
+#define ISC_UINT64_MAX UINT64_MAX
diff --git a/lib/isc/include/isc/interfaceiter.h b/lib/isc/include/isc/interfaceiter.h
new file mode 100644
index 0000000..2ef82a3
--- /dev/null
+++ b/lib/isc/include/isc/interfaceiter.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_INTERFACEITER_H
+#define ISC_INTERFACEITER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/interfaceiter.h
+ * \brief Iterates over the list of network interfaces.
+ *
+ * Interfaces whose address family is not supported are ignored and never
+ * returned by the iterator. Interfaces whose netmask, interface flags,
+ * or similar cannot be obtained are also ignored, and the failure is logged.
+ *
+ * Standards:
+ * The API for scanning varies greatly among operating systems.
+ * This module attempts to hide the differences.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/netaddr.h>
+#include <isc/types.h>
+
+/*!
+ * \brief Public structure describing a network interface.
+ */
+
+struct isc_interface {
+ char name[32]; /*%< Interface name, null-terminated. */
+ unsigned int af; /*%< Address family. */
+ isc_netaddr_t address; /*%< Local address. */
+ isc_netaddr_t netmask; /*%< Network mask. */
+ isc_netaddr_t dstaddress; /*%< Destination address (point-to-point only). */
+ uint32_t flags; /*%< Flags; see INTERFACE flags. */
+};
+
+/*@{*/
+/*! Interface flags. */
+
+#define INTERFACE_F_UP 0x00000001U
+#define INTERFACE_F_POINTTOPOINT 0x00000002U
+#define INTERFACE_F_LOOPBACK 0x00000004U
+/*@}*/
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp);
+/*!<
+ * \brief Create an iterator for traversing the operating system's list
+ * of network interfaces.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ *\li Various network-related errors
+ */
+
+isc_result_t
+isc_interfaceiter_first(isc_interfaceiter_t *iter);
+/*!<
+ * \brief Position the iterator on the first interface.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOMORE There are no interfaces.
+ */
+
+isc_result_t
+isc_interfaceiter_current(isc_interfaceiter_t *iter,
+ isc_interface_t *ifdata);
+/*!<
+ * \brief Get information about the interface the iterator is currently
+ * positioned at and store it at *ifdata.
+ *
+ * Requires:
+ *\li The iterator has been successfully positioned using
+ * isc_interface_iter_first() / isc_interface_iter_next().
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ */
+
+isc_result_t
+isc_interfaceiter_next(isc_interfaceiter_t *iter);
+/*!<
+ * \brief Position the iterator on the next interface.
+ *
+ * Requires:
+ * \li The iterator has been successfully positioned using
+ * isc_interface_iter_first() / isc_interface_iter_next().
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOMORE There are no more interfaces.
+ */
+
+void
+isc_interfaceiter_destroy(isc_interfaceiter_t **iterp);
+/*!<
+ * \brief Destroy the iterator.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_INTERFACEITER_H */
diff --git a/lib/isc/include/isc/ipv6.h b/lib/isc/include/isc/ipv6.h
new file mode 100644
index 0000000..93852d0
--- /dev/null
+++ b/lib/isc/include/isc/ipv6.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id: ipv6.h,v 1.24 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_IPV6_H
+#define ISC_IPV6_H 1
+
+/*!
+ * Also define LWRES_IPV6_H to keep it from being included if liblwres is
+ * being used, or redefinition errors will occur.
+ */
+#define LWRES_IPV6_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/ipv6.h
+ * \brief IPv6 definitions for systems which do not support IPv6.
+ *
+ * \li MP:
+ * No impact.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * N/A.
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * RFC2553.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <inttypes.h>
+#include <isc/platform.h>
+
+/***
+ *** Types.
+ ***/
+
+struct in6_addr {
+ union {
+ uint8_t _S6_u8[16];
+ uint16_t _S6_u16[8];
+ uint32_t _S6_u32[4];
+ } _S6_un;
+};
+#define s6_addr _S6_un._S6_u8
+#define s6_addr8 _S6_un._S6_u8
+#define s6_addr16 _S6_un._S6_u16
+#define s6_addr32 _S6_un._S6_u32
+
+#define IN6ADDR_ANY_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}}
+#define IN6ADDR_LOOPBACK_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}}
+
+LIBISC_EXTERNAL_DATA extern const struct in6_addr in6addr_any;
+LIBISC_EXTERNAL_DATA extern const struct in6_addr in6addr_loopback;
+
+struct sockaddr_in6 {
+#ifdef ISC_PLATFORM_HAVESALEN
+ uint8_t sin6_len;
+ uint8_t sin6_family;
+#else
+ uint16_t sin6_family;
+#endif
+ uint16_t sin6_port;
+ uint32_t sin6_flowinfo;
+ struct in6_addr sin6_addr;
+ uint32_t sin6_scope_id;
+};
+
+#ifdef ISC_PLATFORM_HAVESALEN
+#define SIN6_LEN 1
+#endif
+
+/*%
+ * Unspecified
+ */
+#define IN6_IS_ADDR_UNSPECIFIED(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] == 0))
+
+/*%
+ * Loopback
+ */
+#define IN6_IS_ADDR_LOOPBACK(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] == htonl(1)))
+
+/*%
+ * IPv4 compatible
+ */
+#define IN6_IS_ADDR_V4COMPAT(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] != 0) && \
+ ((a)->s6_addr32[3] != htonl(1)))
+
+/*%
+ * Mapped
+ */
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == htonl(0x0000ffff)))
+
+/*%
+ * Multicast
+ */
+#define IN6_IS_ADDR_MULTICAST(a) \
+ ((a)->s6_addr8[0] == 0xffU)
+
+/*%
+ * Unicast link / site local.
+ */
+#define IN6_IS_ADDR_LINKLOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
+#define IN6_IS_ADDR_SITELOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
+
+#endif /* ISC_IPV6_H */
diff --git a/lib/isc/include/isc/iterated_hash.h b/lib/isc/include/isc/iterated_hash.h
new file mode 100644
index 0000000..a43ae69
--- /dev/null
+++ b/lib/isc/include/isc/iterated_hash.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ITERATED_HASH_H
+#define ISC_ITERATED_HASH_H 1
+
+#include <isc/lang.h>
+#include <isc/sha1.h>
+
+/*
+ * The maximal hash length that can be encoded in a name
+ * using base32hex. floor(255/8)*5
+ */
+#define NSEC3_MAX_HASH_LENGTH 155
+
+/*
+ * The maximum has that can be encoded in a single label using
+ * base32hex. floor(63/8)*5
+ */
+#define NSEC3_MAX_LABEL_HASH 35
+
+ISC_LANG_BEGINDECLS
+
+int isc_iterated_hash(unsigned char out[NSEC3_MAX_HASH_LENGTH],
+ unsigned int hashalg, int iterations,
+ const unsigned char *salt, int saltlength,
+ const unsigned char *in, int inlength);
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ITERATED_HASH_H */
diff --git a/lib/isc/include/isc/json.h b/lib/isc/include/isc/json.h
new file mode 100644
index 0000000..52295e6
--- /dev/null
+++ b/lib/isc/include/isc/json.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_JSON_H
+#define ISC_JSON_H 1
+
+#ifdef HAVE_JSON
+/*
+ * This file is here mostly to make it easy to add additional libjson header
+ * files as needed across all the users of this file. Rather than place
+ * these libjson includes in each file, one include makes it easy to handle
+ * the ifdef as well as adding the ability to add additional functions
+ * which may be useful.
+ */
+#ifdef HAVE_JSON_C
+/*
+ * We don't include <json-c/json.h> as the subsequent includes do not
+ * prefix the header file names with "json-c/" and using
+ * -I <prefix>/include/json-c results in too many filename collisions.
+ */
+#include <json-c/linkhash.h>
+#include <json-c/json_util.h>
+#include <json-c/json_object.h>
+#include <json-c/json_tokener.h>
+#include <json-c/json_object_iterator.h>
+#include <json-c/json_c_version.h>
+#else
+#include <json/json.h>
+#endif
+#endif
+
+#define ISC_JSON_RENDERCONFIG 0x00000001 /* render config data */
+#define ISC_JSON_RENDERSTATS 0x00000002 /* render stats */
+#define ISC_JSON_RENDERALL 0x000000ff /* render everything */
+
+#endif /* ISC_JSON_H */
diff --git a/lib/isc/include/isc/lang.h b/lib/isc/include/isc/lang.h
new file mode 100644
index 0000000..bffcbac
--- /dev/null
+++ b/lib/isc/include/isc/lang.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_LANG_H
+#define ISC_LANG_H 1
+
+/*! \file isc/lang.h */
+
+#ifdef __cplusplus
+#define ISC_LANG_BEGINDECLS extern "C" {
+#define ISC_LANG_ENDDECLS }
+#else
+#define ISC_LANG_BEGINDECLS
+#define ISC_LANG_ENDDECLS
+#endif
+
+#endif /* ISC_LANG_H */
diff --git a/lib/isc/include/isc/lex.h b/lib/isc/include/isc/lex.h
new file mode 100644
index 0000000..d63ecf9
--- /dev/null
+++ b/lib/isc/include/isc/lex.h
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_LEX_H
+#define ISC_LEX_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/lex.h
+ * \brief The "lex" module provides a lightweight tokenizer. It can operate
+ * on files or buffers, and can handle "include". It is designed for
+ * parsing of DNS master files and the BIND configuration file, but
+ * should be general enough to tokenize other things, e.g. HTTP.
+ *
+ * \li MP:
+ * No synchronization is provided. Clients must ensure exclusive
+ * access.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/region.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Options
+ ***/
+
+/*@{*/
+/*!
+ * Various options for isc_lex_gettoken().
+ */
+
+#define ISC_LEXOPT_EOL 0x01 /*%< Want end-of-line token. */
+#define ISC_LEXOPT_EOF 0x02 /*%< Want end-of-file token. */
+#define ISC_LEXOPT_INITIALWS 0x04 /*%< Want initial whitespace. */
+#define ISC_LEXOPT_NUMBER 0x08 /*%< Recognize numbers. */
+#define ISC_LEXOPT_QSTRING 0x10 /*%< Recognize qstrings. */
+/*@}*/
+
+/*@{*/
+/*!
+ * The ISC_LEXOPT_DNSMULTILINE option handles the processing of '(' and ')' in
+ * the DNS master file format. If this option is set, then the
+ * ISC_LEXOPT_INITIALWS and ISC_LEXOPT_EOL options will be ignored when
+ * the paren count is > 0. To use this option, '(' and ')' must be special
+ * characters.
+ */
+#define ISC_LEXOPT_DNSMULTILINE 0x20 /*%< Handle '(' and ')'. */
+#define ISC_LEXOPT_NOMORE 0x40 /*%< Want "no more" token. */
+
+#define ISC_LEXOPT_CNUMBER 0x80 /*%< Recognize octal and hex. */
+#define ISC_LEXOPT_ESCAPE 0x100 /*%< Recognize escapes. */
+#define ISC_LEXOPT_QSTRINGMULTILINE 0x200 /*%< Allow multiline "" strings */
+#define ISC_LEXOPT_OCTAL 0x400 /*%< Expect a octal number. */
+#define ISC_LEXOPT_BTEXT 0x800 /*%< Bracketed text. */
+/*@}*/
+/*@{*/
+/*!
+ * Various commenting styles, which may be changed at any time with
+ * isc_lex_setcomments().
+ */
+
+#define ISC_LEXCOMMENT_C 0x01
+#define ISC_LEXCOMMENT_CPLUSPLUS 0x02
+#define ISC_LEXCOMMENT_SHELL 0x04
+#define ISC_LEXCOMMENT_DNSMASTERFILE 0x08
+/*@}*/
+
+/***
+ *** Types
+ ***/
+
+/*! Lex */
+
+typedef char isc_lexspecials_t[256];
+
+/* Tokens */
+
+typedef enum {
+ isc_tokentype_unknown = 0,
+ isc_tokentype_string = 1,
+ isc_tokentype_number = 2,
+ isc_tokentype_qstring = 3,
+ isc_tokentype_eol = 4,
+ isc_tokentype_eof = 5,
+ isc_tokentype_initialws = 6,
+ isc_tokentype_special = 7,
+ isc_tokentype_nomore = 8,
+ isc_tokentype_btext = 8
+} isc_tokentype_t;
+
+typedef union {
+ char as_char;
+ unsigned long as_ulong;
+ isc_region_t as_region;
+ isc_textregion_t as_textregion;
+ void * as_pointer;
+} isc_tokenvalue_t;
+
+typedef struct isc_token {
+ isc_tokentype_t type;
+ isc_tokenvalue_t value;
+} isc_token_t;
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp);
+/*%<
+ * Create a lexer.
+ *
+ * 'max_token' is a hint of the number of bytes in the largest token.
+ *
+ * Requires:
+ *\li '*lexp' is a valid lexer.
+ *
+ * Ensures:
+ *\li On success, *lexp is attached to the newly created lexer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+void
+isc_lex_destroy(isc_lex_t **lexp);
+/*%<
+ * Destroy the lexer.
+ *
+ * Requires:
+ *\li '*lexp' is a valid lexer.
+ *
+ * Ensures:
+ *\li *lexp == NULL
+ */
+
+unsigned int
+isc_lex_getcomments(isc_lex_t *lex);
+/*%<
+ * Return the current lexer commenting styles.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ *\li The commenting sytles which are currently allowed.
+ */
+
+void
+isc_lex_setcomments(isc_lex_t *lex, unsigned int comments);
+/*%<
+ * Set allowed lexer commenting styles.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'comments' has meaningful values.
+ */
+
+void
+isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials);
+/*%<
+ * Put the current list of specials into 'specials'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ */
+
+void
+isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials);
+/*!<
+ * The characters in 'specials' are returned as tokens. Along with
+ * whitespace, they delimit strings and numbers.
+ *
+ * Note:
+ *\li Comment processing takes precedence over special character
+ * recognition.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ */
+
+isc_result_t
+isc_lex_openfile(isc_lex_t *lex, const char *filename);
+/*%<
+ * Open 'filename' and make it the current input source for 'lex'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li filename is a valid C string.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY Out of memory
+ *\li #ISC_R_NOTFOUND File not found
+ *\li #ISC_R_NOPERM No permission to open file
+ *\li #ISC_R_FAILURE Couldn't open file, not sure why
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_lex_openstream(isc_lex_t *lex, FILE *stream);
+/*%<
+ * Make 'stream' the current input source for 'lex'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'stream' is a valid C stream.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY Out of memory
+ */
+
+isc_result_t
+isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer);
+/*%<
+ * Make 'buffer' the current input source for 'lex'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'buffer' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY Out of memory
+ */
+
+isc_result_t
+isc_lex_close(isc_lex_t *lex);
+/*%<
+ * Close the most recently opened object (i.e. file or buffer).
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE No more input sources
+ */
+
+isc_result_t
+isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp);
+/*%<
+ * Get the next token.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'lex' has an input source.
+ *
+ *\li 'options' contains valid options.
+ *
+ *\li '*tokenp' is a valid pointer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_UNEXPECTEDEND
+ *\li #ISC_R_NOMEMORY
+ *
+ * These two results are returned only if their corresponding lexer
+ * options are not set.
+ *
+ *\li #ISC_R_EOF End of input source
+ *\li #ISC_R_NOMORE No more input sources
+ */
+
+isc_result_t
+isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
+ isc_tokentype_t expect, bool eol);
+/*%<
+ * Get the next token from a DNS master file type stream. This is a
+ * convenience function that sets appropriate options and handles quoted
+ * strings and end of line correctly for master files. It also ungets
+ * unexpected tokens.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'token' is a valid pointer
+ *
+ * Returns:
+ *
+ * \li any return code from isc_lex_gettoken().
+ */
+
+isc_result_t
+isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, bool eol);
+/*%<
+ * Get the next token from a DNS master file type stream. This is a
+ * convenience function that sets appropriate options and handles end
+ * of line correctly for master files. It also ungets unexpected tokens.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'token' is a valid pointer
+ *
+ * Returns:
+ *
+ * \li any return code from isc_lex_gettoken().
+ */
+
+void
+isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp);
+/*%<
+ * Unget the current token.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'lex' has an input source.
+ *
+ *\li 'tokenp' points to a valid token.
+ *
+ *\li There is no ungotten token already.
+ */
+
+void
+isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r);
+/*%<
+ * Returns a region containing the text of the last token returned.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'lex' has an input source.
+ *
+ *\li 'tokenp' points to a valid token.
+ *
+ *\li A token has been gotten and not ungotten.
+ */
+
+char *
+isc_lex_getsourcename(isc_lex_t *lex);
+/*%<
+ * Return the input source name.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li source name or NULL if no current source.
+ *\li result valid while current input source exists.
+ */
+
+
+unsigned long
+isc_lex_getsourceline(isc_lex_t *lex);
+/*%<
+ * Return the input source line number.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ *\li Current line number or 0 if no current source.
+ */
+
+isc_result_t
+isc_lex_setsourcename(isc_lex_t *lex, const char *name);
+/*%<
+ * Assigns a new name to the input source.
+ *
+ * Requires:
+ *
+ * \li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ * \li #ISC_R_NOTFOUND - there are no sources.
+ */
+
+isc_result_t
+isc_lex_setsourceline(isc_lex_t *lex, unsigned long line);
+/*%<
+ * Assigns a new line number to the input source. This can be used
+ * when parsing a buffer that's been excerpted from the middle a file,
+ * allowing logged messages to display the correct line number,
+ * rather than the line number within the buffer.
+ *
+ * Requires:
+ *
+ * \li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND - there are no sources.
+ */
+
+bool
+isc_lex_isfile(isc_lex_t *lex);
+/*%<
+ * Return whether the current input source is a file.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li #true if the current input is a file,
+ *\li #false otherwise.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_LEX_H */
diff --git a/lib/isc/include/isc/lfsr.h b/lib/isc/include/isc/lfsr.h
new file mode 100644
index 0000000..3f2cfb4
--- /dev/null
+++ b/lib/isc/include/isc/lfsr.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_LFSR_H
+#define ISC_LFSR_H 1
+
+/*! \file isc/lfsr.h */
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+typedef struct isc_lfsr isc_lfsr_t;
+
+/*%
+ * This function is called when reseeding is needed. It is allowed to
+ * modify any state in the LFSR in any way it sees fit OTHER THAN "bits".
+ *
+ * It MUST set "count" to a new value or the lfsr will never reseed again.
+ *
+ * Also, a reseed will never occur in the middle of an extraction. This
+ * is purely an optimization, and is probably what one would want.
+ */
+typedef void (*isc_lfsrreseed_t)(isc_lfsr_t *, void *);
+
+/*%
+ * The members of this structure can be used by the application, but care
+ * needs to be taken to not change state once the lfsr is in operation.
+ */
+struct isc_lfsr {
+ uint32_t state; /*%< previous state */
+ unsigned int bits; /*%< length */
+ uint32_t tap; /*%< bit taps */
+ unsigned int count; /*%< reseed count (in BITS!) */
+ isc_lfsrreseed_t reseed; /*%< reseed function */
+ void *arg; /*%< reseed function argument */
+};
+
+ISC_LANG_BEGINDECLS
+
+
+void
+isc_lfsr_init(isc_lfsr_t *lfsr, uint32_t state, unsigned int bits,
+ uint32_t tap, unsigned int count,
+ isc_lfsrreseed_t reseed, void *arg);
+/*%<
+ * Initialize an LFSR.
+ *
+ * Note:
+ *
+ *\li Putting untrusted values into this function will cause the LFSR to
+ * generate (perhaps) non-maximal length sequences.
+ *
+ * Requires:
+ *
+ *\li lfsr != NULL
+ *
+ *\li 8 <= bits <= 32
+ *
+ *\li tap != 0
+ */
+
+void
+isc_lfsr_generate(isc_lfsr_t *lfsr, void *data, unsigned int count);
+/*%<
+ * Returns "count" bytes of data from the LFSR.
+ *
+ * Requires:
+ *
+ *\li lfsr be valid.
+ *
+ *\li data != NULL.
+ *
+ *\li count > 0.
+ */
+
+void
+isc_lfsr_skip(isc_lfsr_t *lfsr, unsigned int skip);
+/*%<
+ * Skip "skip" states.
+ *
+ * Requires:
+ *
+ *\li lfsr be valid.
+ */
+
+uint32_t
+isc_lfsr_generate32(isc_lfsr_t *lfsr1, isc_lfsr_t *lfsr2);
+/*%<
+ * Given two LFSRs, use the current state from each to skip entries in the
+ * other. The next states are then xor'd together and returned.
+ *
+ * WARNING:
+ *
+ *\li This function is used only for very, very low security data, such
+ * as DNS message IDs where it is desired to have an unpredictable
+ * stream of bytes that are harder to predict than a simple flooding
+ * attack.
+ *
+ * Notes:
+ *
+ *\li Since the current state from each of the LFSRs is used to skip
+ * state in the other, it is important that no state be leaked
+ * from either LFSR.
+ *
+ * Requires:
+ *
+ *\li lfsr1 and lfsr2 be valid.
+ *
+ *\li 1 <= skipbits <= 31
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_LFSR_H */
diff --git a/lib/isc/include/isc/lib.h b/lib/isc/include/isc/lib.h
new file mode 100644
index 0000000..55ef20a
--- /dev/null
+++ b/lib/isc/include/isc/lib.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_LIB_H
+#define ISC_LIB_H 1
+
+/*! \file isc/lib.h */
+
+#include <isc/types.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+LIBISC_EXTERNAL_DATA extern isc_msgcat_t *isc_msgcat;
+
+void
+isc_lib_initmsgcat(void);
+/*!<
+ * \brief Initialize the ISC library's message catalog, isc_msgcat, if it
+ * has not already been initialized.
+ */
+
+void
+isc_lib_register(void);
+/*!<
+ * \brief Register the ISC library implementations for some base services
+ * such as memory or event management and handling socket or timer events.
+ * An external application that wants to use the ISC library must call this
+ * function very early in main().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_LIB_H */
diff --git a/lib/isc/include/isc/likely.h b/lib/isc/include/isc/likely.h
new file mode 100644
index 0000000..6c77957
--- /dev/null
+++ b/lib/isc/include/isc/likely.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_LIKELY_H
+#define ISC_LIKELY_H 1
+
+/*%
+ * Performance
+ */
+#ifdef HAVE_BUILTIN_EXPECT
+#define ISC_LIKELY(x) __builtin_expect((x), 1)
+#define ISC_UNLIKELY(x) __builtin_expect((x), 0)
+#else
+#define ISC_LIKELY(x) (x)
+#define ISC_UNLIKELY(x) (x)
+#endif
+
+#endif /* ISC_LIKELY_H */
diff --git a/lib/isc/include/isc/list.h b/lib/isc/include/isc/list.h
new file mode 100644
index 0000000..ab476ca
--- /dev/null
+++ b/lib/isc/include/isc/list.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_LIST_H
+#define ISC_LIST_H 1
+#include <isc/assertions.h>
+
+#ifdef ISC_LIST_CHECKINIT
+#define ISC_LINK_INSIST(x) ISC_INSIST(x)
+#else
+#define ISC_LINK_INSIST(x)
+#endif
+
+#define ISC_LIST(type) struct { type *head, *tail; }
+#define ISC_LIST_INIT(list) \
+ do { (list).head = NULL; (list).tail = NULL; } while (0)
+
+#define ISC_LINK(type) struct { type *prev, *next; }
+#define ISC_LINK_INIT_TYPE(elt, link, type) \
+ do { \
+ (elt)->link.prev = (type *)(-1); \
+ (elt)->link.next = (type *)(-1); \
+ } while (0)
+#define ISC_LINK_INIT(elt, link) \
+ ISC_LINK_INIT_TYPE(elt, link, void)
+#define ISC_LINK_LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1))
+
+#define ISC_LIST_HEAD(list) ((list).head)
+#define ISC_LIST_TAIL(list) ((list).tail)
+#define ISC_LIST_EMPTY(list) ((list).head == NULL)
+
+#define __ISC_LIST_PREPENDUNSAFE(list, elt, link) \
+ do { \
+ if ((list).head != NULL) \
+ (list).head->link.prev = (elt); \
+ else \
+ (list).tail = (elt); \
+ (elt)->link.prev = NULL; \
+ (elt)->link.next = (list).head; \
+ (list).head = (elt); \
+ } while (0)
+
+#define ISC_LIST_PREPEND(list, elt, link) \
+ do { \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_PREPENDUNSAFE(list, elt, link); \
+ } while (0)
+
+#define ISC_LIST_INITANDPREPEND(list, elt, link) \
+ __ISC_LIST_PREPENDUNSAFE(list, elt, link)
+
+#define __ISC_LIST_APPENDUNSAFE(list, elt, link) \
+ do { \
+ if ((list).tail != NULL) \
+ (list).tail->link.next = (elt); \
+ else \
+ (list).head = (elt); \
+ (elt)->link.prev = (list).tail; \
+ (elt)->link.next = NULL; \
+ (list).tail = (elt); \
+ } while (0)
+
+#define ISC_LIST_APPEND(list, elt, link) \
+ do { \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_APPENDUNSAFE(list, elt, link); \
+ } while (0)
+
+#define ISC_LIST_INITANDAPPEND(list, elt, link) \
+ __ISC_LIST_APPENDUNSAFE(list, elt, link)
+
+#define __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type) \
+ do { \
+ if ((elt)->link.next != NULL) \
+ (elt)->link.next->link.prev = (elt)->link.prev; \
+ else { \
+ ISC_INSIST((list).tail == (elt)); \
+ (list).tail = (elt)->link.prev; \
+ } \
+ if ((elt)->link.prev != NULL) \
+ (elt)->link.prev->link.next = (elt)->link.next; \
+ else { \
+ ISC_INSIST((list).head == (elt)); \
+ (list).head = (elt)->link.next; \
+ } \
+ (elt)->link.prev = (type *)(-1); \
+ (elt)->link.next = (type *)(-1); \
+ ISC_INSIST((list).head != (elt)); \
+ ISC_INSIST((list).tail != (elt)); \
+ } while (0)
+
+#define __ISC_LIST_UNLINKUNSAFE(list, elt, link) \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, void)
+
+#define ISC_LIST_UNLINK_TYPE(list, elt, link, type) \
+ do { \
+ ISC_LINK_INSIST(ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type); \
+ } while (0)
+#define ISC_LIST_UNLINK(list, elt, link) \
+ ISC_LIST_UNLINK_TYPE(list, elt, link, void)
+
+#define ISC_LIST_PREV(elt, link) ((elt)->link.prev)
+#define ISC_LIST_NEXT(elt, link) ((elt)->link.next)
+
+#define __ISC_LIST_INSERTBEFOREUNSAFE(list, before, elt, link) \
+ do { \
+ if ((before)->link.prev == NULL) \
+ ISC_LIST_PREPEND(list, elt, link); \
+ else { \
+ (elt)->link.prev = (before)->link.prev; \
+ (before)->link.prev = (elt); \
+ (elt)->link.prev->link.next = (elt); \
+ (elt)->link.next = (before); \
+ } \
+ } while (0)
+
+#define ISC_LIST_INSERTBEFORE(list, before, elt, link) \
+ do { \
+ ISC_LINK_INSIST(ISC_LINK_LINKED(before, link)); \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_INSERTBEFOREUNSAFE(list, before, elt, link); \
+ } while (0)
+
+#define __ISC_LIST_INSERTAFTERUNSAFE(list, after, elt, link) \
+ do { \
+ if ((after)->link.next == NULL) \
+ ISC_LIST_APPEND(list, elt, link); \
+ else { \
+ (elt)->link.next = (after)->link.next; \
+ (after)->link.next = (elt); \
+ (elt)->link.next->link.prev = (elt); \
+ (elt)->link.prev = (after); \
+ } \
+ } while (0)
+
+#define ISC_LIST_INSERTAFTER(list, after, elt, link) \
+ do { \
+ ISC_LINK_INSIST(ISC_LINK_LINKED(after, link)); \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_INSERTAFTERUNSAFE(list, after, elt, link); \
+ } while (0)
+
+#define ISC_LIST_APPENDLIST(list1, list2, link) \
+ do { \
+ if (ISC_LIST_EMPTY(list1)) \
+ (list1) = (list2); \
+ else if (!ISC_LIST_EMPTY(list2)) { \
+ (list1).tail->link.next = (list2).head; \
+ (list2).head->link.prev = (list1).tail; \
+ (list1).tail = (list2).tail; \
+ } \
+ (list2).head = NULL; \
+ (list2).tail = NULL; \
+ } while (0)
+
+#define ISC_LIST_PREPENDLIST(list1, list2, link) \
+ do { \
+ if (ISC_LIST_EMPTY(list1)) \
+ (list1) = (list2); \
+ else if (!ISC_LIST_EMPTY(list2)) { \
+ (list2).tail->link.next = (list1).head; \
+ (list1).head->link.prev = (list2).tail; \
+ (list1).head = (list2).head; \
+ } \
+ (list2).head = NULL; \
+ (list2).tail = NULL; \
+ } while (0)
+
+#define ISC_LIST_ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link)
+#define __ISC_LIST_ENQUEUEUNSAFE(list, elt, link) \
+ __ISC_LIST_APPENDUNSAFE(list, elt, link)
+#define ISC_LIST_DEQUEUE(list, elt, link) \
+ ISC_LIST_UNLINK_TYPE(list, elt, link, void)
+#define ISC_LIST_DEQUEUE_TYPE(list, elt, link, type) \
+ ISC_LIST_UNLINK_TYPE(list, elt, link, type)
+#define __ISC_LIST_DEQUEUEUNSAFE(list, elt, link) \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, void)
+#define __ISC_LIST_DEQUEUEUNSAFE_TYPE(list, elt, link, type) \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type)
+
+#endif /* ISC_LIST_H */
diff --git a/lib/isc/include/isc/log.h b/lib/isc/include/isc/log.h
new file mode 100644
index 0000000..fd0443f
--- /dev/null
+++ b/lib/isc/include/isc/log.h
@@ -0,0 +1,920 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_LOG_H
+#define ISC_LOG_H 1
+
+/*! \file isc/log.h */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h> /* XXXDCL NT */
+
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+/*@{*/
+/*!
+ * \brief Severity levels, patterned after Unix's syslog levels.
+ *
+ */
+#define ISC_LOG_DEBUG(level) (level)
+/*!
+ * #ISC_LOG_DYNAMIC can only be used for defining channels with
+ * isc_log_createchannel(), not to specify a level in isc_log_write().
+ */
+#define ISC_LOG_DYNAMIC 0
+#define ISC_LOG_INFO (-1)
+#define ISC_LOG_NOTICE (-2)
+#define ISC_LOG_WARNING (-3)
+#define ISC_LOG_ERROR (-4)
+#define ISC_LOG_CRITICAL (-5)
+/*@}*/
+
+/*@{*/
+/*!
+ * \brief Destinations.
+ */
+#define ISC_LOG_TONULL 1
+#define ISC_LOG_TOSYSLOG 2
+#define ISC_LOG_TOFILE 3
+#define ISC_LOG_TOFILEDESC 4
+/*@}*/
+
+/*@{*/
+/*%
+ * Channel flags.
+ */
+#define ISC_LOG_PRINTTIME 0x0001
+#define ISC_LOG_PRINTLEVEL 0x0002
+#define ISC_LOG_PRINTCATEGORY 0x0004
+#define ISC_LOG_PRINTMODULE 0x0008
+#define ISC_LOG_PRINTTAG 0x0010 /* tag and ":" */
+#define ISC_LOG_PRINTPREFIX 0x0020 /* tag only, no colon */
+#define ISC_LOG_PRINTALL 0x003F
+#define ISC_LOG_BUFFERED 0x0040
+#define ISC_LOG_DEBUGONLY 0x1000
+#define ISC_LOG_OPENERR 0x8000 /* internal */
+/*@}*/
+
+/*@{*/
+/*!
+ * \brief Other options.
+ *
+ * XXXDCL INFINITE doesn't yet work. Arguably it isn't needed, but
+ * since I am intend to make large number of versions work efficiently,
+ * INFINITE is going to be trivial to add to that.
+ */
+#define ISC_LOG_ROLLINFINITE (-1)
+#define ISC_LOG_ROLLNEVER (-2)
+/*@}*/
+
+/*!
+ * \brief Used to name the categories used by a library.
+ *
+ * An array of isc_logcategory
+ * structures names each category, and the id value is initialized by calling
+ * isc_log_registercategories.
+ */
+struct isc_logcategory {
+ const char *name;
+ unsigned int id;
+};
+
+/*%
+ * Similar to isc_logcategory, but for all the modules a library defines.
+ */
+struct isc_logmodule {
+ const char *name;
+ unsigned int id;
+};
+
+/*%
+ * The isc_logfile structure is initialized as part of an isc_logdestination
+ * before calling isc_log_createchannel().
+ *
+ * When defining an #ISC_LOG_TOFILE
+ * channel the name, versions and maximum_size should be set before calling
+ * isc_log_createchannel(). To define an #ISC_LOG_TOFILEDESC channel set only
+ * the stream before the call.
+ *
+ * Setting maximum_size to zero implies no maximum.
+ */
+typedef struct isc_logfile {
+ FILE *stream; /*%< Initialized to NULL for #ISC_LOG_TOFILE. */
+ const char *name; /*%< NULL for #ISC_LOG_TOFILEDESC. */
+ int versions; /* >= 0, #ISC_LOG_ROLLNEVER, #ISC_LOG_ROLLINFINITE. */
+ /*%
+ * stdio's ftell is standardized to return a long, which may well not
+ * be big enough for the largest file supportable by the operating
+ * system (though it is _probably_ big enough for the largest log
+ * anyone would want). st_size returned by fstat should be typedef'd
+ * to a size large enough for the largest possible file on a system.
+ */
+ isc_offset_t maximum_size;
+ bool maximum_reached; /*%< Private. */
+} isc_logfile_t;
+
+/*%
+ * Passed to isc_log_createchannel to define the attributes of either
+ * a stdio or a syslog log.
+ */
+typedef union isc_logdestination {
+ isc_logfile_t file;
+ int facility; /* XXXDCL NT */
+} isc_logdestination_t;
+
+/*@{*/
+/*%
+ * The built-in categories of libisc.
+ *
+ * Each library registering categories should provide library_LOGCATEGORY_name
+ * definitions with indexes into its isc_logcategory structure corresponding to
+ * the order of the names.
+ */
+LIBISC_EXTERNAL_DATA extern isc_logcategory_t isc_categories[];
+LIBISC_EXTERNAL_DATA extern isc_log_t *isc_lctx;
+LIBISC_EXTERNAL_DATA extern isc_logmodule_t isc_modules[];
+/*@}*/
+
+/*@{*/
+/*%
+ * Do not log directly to DEFAULT. Use another category. When in doubt,
+ * use GENERAL.
+ */
+#define ISC_LOGCATEGORY_DEFAULT (&isc_categories[0])
+#define ISC_LOGCATEGORY_GENERAL (&isc_categories[1])
+/*@}*/
+
+#define ISC_LOGMODULE_SOCKET (&isc_modules[0])
+#define ISC_LOGMODULE_TIME (&isc_modules[1])
+#define ISC_LOGMODULE_INTERFACE (&isc_modules[2])
+#define ISC_LOGMODULE_TIMER (&isc_modules[3])
+#define ISC_LOGMODULE_FILE (&isc_modules[4])
+#define ISC_LOGMODULE_OTHER (&isc_modules[5])
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp);
+/*%<
+ * Establish a new logging context, with default channels.
+ *
+ * Notes:
+ *\li isc_log_create() calls isc_logconfig_create(), so see its comment
+ * below for more information.
+ *
+ * Requires:
+ *\li mctx is a valid memory context.
+ *\li lctxp is not null and *lctxp is null.
+ *\li lcfgp is null or lcfgp is not null and *lcfgp is null.
+ *
+ * Ensures:
+ *\li *lctxp will point to a valid logging context if all of the necessary
+ * memory was allocated, or NULL otherwise.
+ *\li *lcfgp will point to a valid logging configuration if all of the
+ * necessary memory was allocated, or NULL otherwise.
+ *\li On failure, no additional memory is allocated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ */
+
+isc_result_t
+isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp);
+/*%<
+ * Create the data structure that holds all of the configurable information
+ * about where messages are actually supposed to be sent -- the information
+ * that could changed based on some configuration file, as opposed to the
+ * the category/module specification of isc_log_[v]write[1] that is compiled
+ * into a program, or the debug_level which is dynamic state information.
+ *
+ * Notes:
+ *\li It is necessary to specify the logging context the configuration
+ * will be used with because the number of categories and modules
+ * needs to be known in order to set the configuration. However,
+ * the configuration is not used by the logging context until the
+ * isc_logconfig_use function is called.
+ *
+ *\li The memory context used for operations that allocate memory for
+ * the configuration is that of the logging context, as specified
+ * in the isc_log_create call.
+ *
+ *\li Four default channels are established:
+ *\verbatim
+ * default_syslog
+ * - log to syslog's daemon facility #ISC_LOG_INFO or higher
+ * default_stderr
+ * - log to stderr #ISC_LOG_INFO or higher
+ * default_debug
+ * - log to stderr #ISC_LOG_DEBUG dynamically
+ * null
+ * - log nothing
+ *\endverbatim
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li lcftp is not null and *lcfgp is null.
+ *
+ * Ensures:
+ *\li *lcfgp will point to a valid logging context if all of the necessary
+ * memory was allocated, or NULL otherwise.
+ *\li On failure, no additional memory is allocated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ */
+
+isc_logconfig_t *
+isc_logconfig_get(isc_log_t *lctx);
+/*%<
+ * Returns a pointer to the configuration currently in use by the log context.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *
+ * Ensures:
+ *\li The configuration pointer is non-null.
+ *
+ * Returns:
+ *\li The configuration pointer.
+ */
+
+isc_result_t
+isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg);
+/*%<
+ * Associate a new configuration with a logging context.
+ *
+ * Notes:
+ *\li This is thread safe. The logging context will lock a mutex
+ * before attempting to swap in the new configuration, and isc_log_doit
+ * (the internal function used by all of isc_log_[v]write[1]) locks
+ * the same lock for the duration of its use of the configuration.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li lcfg is a valid logging configuration.
+ *\li lctx is the same configuration given to isc_logconfig_create
+ * when the configuration was created.
+ *
+ * Ensures:
+ *\li Future calls to isc_log_write will use the new configuration.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ */
+
+void
+isc_log_destroy(isc_log_t **lctxp);
+/*%<
+ * Deallocate the memory associated with a logging context.
+ *
+ * Requires:
+ *\li *lctx is a valid logging context.
+ *
+ * Ensures:
+ *\li All of the memory associated with the logging context is returned
+ * to the free memory pool.
+ *
+ *\li Any open files are closed.
+ *
+ *\li The logging context is marked as invalid.
+ */
+
+void
+isc_logconfig_destroy(isc_logconfig_t **lcfgp);
+/*%<
+ * Destroy a logging configuration.
+ *
+ * Notes:
+ *\li This function cannot be used directly with the return value of
+ * isc_logconfig_get, because a logging context must always have
+ * a valid configuration associated with it.
+ *
+ * Requires:
+ *\li lcfgp is not null and *lcfgp is a valid logging configuration.
+ *\li The logging configuration is not in use by an existing logging context.
+ *
+ * Ensures:
+ *\li All memory allocated for the configuration is freed.
+ *
+ *\li The configuration is marked as invalid.
+ */
+
+void
+isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]);
+/*%<
+ * Identify logging categories a library will use.
+ *
+ * Notes:
+ *\li A category should only be registered once, but no mechanism enforces
+ * this rule.
+ *
+ *\li The end of the categories array is identified by a NULL name.
+ *
+ *\li Because the name is used by #ISC_LOG_PRINTCATEGORY, it should not
+ * be altered or destroyed after isc_log_registercategories().
+ *
+ *\li Because each element of the categories array is used by
+ * isc_log_categorybyname, it should not be altered or destroyed
+ * after registration.
+ *
+ *\li The value of the id integer in each structure is overwritten
+ * by this function, and so id need not be initialized to any particular
+ * value prior to the function call.
+ *
+ *\li A subsequent call to isc_log_registercategories with the same
+ * logging context (but new categories) will cause the last
+ * element of the categories array from the prior call to have
+ * its "name" member changed from NULL to point to the new
+ * categories array, and its "id" member set to UINT_MAX.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li categories != NULL.
+ *\li categories[0].name != NULL.
+ *
+ * Ensures:
+ * \li There are references to each category in the logging context,
+ * so they can be used with isc_log_usechannel() and isc_log_write().
+ */
+
+void
+isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]);
+/*%<
+ * Identify logging categories a library will use.
+ *
+ * Notes:
+ *\li A module should only be registered once, but no mechanism enforces
+ * this rule.
+ *
+ *\li The end of the modules array is identified by a NULL name.
+ *
+ *\li Because the name is used by #ISC_LOG_PRINTMODULE, it should not
+ * be altered or destroyed after isc_log_registermodules().
+ *
+ *\li Because each element of the modules array is used by
+ * isc_log_modulebyname, it should not be altered or destroyed
+ * after registration.
+ *
+ *\li The value of the id integer in each structure is overwritten
+ * by this function, and so id need not be initialized to any particular
+ * value prior to the function call.
+ *
+ *\li A subsequent call to isc_log_registermodules with the same
+ * logging context (but new modules) will cause the last
+ * element of the modules array from the prior call to have
+ * its "name" member changed from NULL to point to the new
+ * modules array, and its "id" member set to UINT_MAX.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li modules != NULL.
+ *\li modules[0].name != NULL;
+ *
+ * Ensures:
+ *\li Each module has a reference in the logging context, so they can be
+ * used with isc_log_usechannel() and isc_log_write().
+ */
+
+isc_result_t
+isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
+ unsigned int type, int level,
+ const isc_logdestination_t *destination,
+ unsigned int flags);
+/*%<
+ * Specify the parameters of a logging channel.
+ *
+ * Notes:
+ *\li The name argument is copied to memory in the logging context, so
+ * it can be altered or destroyed after isc_log_createchannel().
+ *
+ *\li Defining a very large number of channels will have a performance
+ * impact on isc_log_usechannel(), since the names are searched
+ * linearly until a match is made. This same issue does not affect
+ * isc_log_write, however.
+ *
+ *\li Channel names can be redefined; this is primarily useful for programs
+ * that want their own definition of default_syslog, default_debug
+ * and default_stderr.
+ *
+ *\li Any channel that is redefined will not affect logging that was
+ * already directed to its original definition, _except_ for the
+ * default_stderr channel. This case is handled specially so that
+ * the default logging category can be changed by redefining
+ * default_stderr. (XXXDCL Though now that I think of it, the default
+ * logging category can be changed with only one additional function
+ * call by defining a new channel and then calling isc_log_usechannel()
+ * for #ISC_LOGCATEGORY_DEFAULT.)
+ *
+ *\li Specifying #ISC_LOG_PRINTTIME or #ISC_LOG_PRINTTAG for syslog is
+ * allowed, but probably not what you wanted to do.
+ *
+ * #ISC_LOG_DEBUGONLY will mark the channel as usable only when the
+ * debug level of the logging context (see isc_log_setdebuglevel)
+ * is non-zero.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ *\li name is not NULL.
+ *
+ *\li type is #ISC_LOG_TOSYSLOG, #ISC_LOG_TOFILE, #ISC_LOG_TOFILEDESC or
+ * #ISC_LOG_TONULL.
+ *
+ *\li destination is not NULL unless type is #ISC_LOG_TONULL.
+ *
+ *\li level is >= #ISC_LOG_CRITICAL (the most negative logging level).
+ *
+ *\li flags does not include any bits aside from the ISC_LOG_PRINT* bits,
+ * #ISC_LOG_DEBUGONLY or #ISC_LOG_BUFFERED.
+ *
+ * Ensures:
+ *\li #ISC_R_SUCCESS
+ * A channel with the given name is usable with
+ * isc_log_usechannel().
+ *
+ *\li #ISC_R_NOMEMORY or #ISC_R_UNEXPECTED
+ * No additional memory is being used by the logging context.
+ * Any channel that previously existed with the given name
+ * is not redefined.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ *\li #ISC_R_UNEXPECTED type was out of range and REQUIRE()
+ * was disabled.
+ */
+
+isc_result_t
+isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
+ const isc_logcategory_t *category,
+ const isc_logmodule_t *module);
+/*%<
+ * Associate a named logging channel with a category and module that
+ * will use it.
+ *
+ * Notes:
+ *\li The name is searched for linearly in the set of known channel names
+ * until a match is found. (Note the performance impact of a very large
+ * number of named channels.) When multiple channels of the same
+ * name are defined, the most recent definition is found.
+ *
+ *\li Specifying a very large number of channels for a category will have
+ * a moderate impact on performance in isc_log_write(), as each
+ * call looks up the category for the start of a linked list, which
+ * it follows all the way to the end to find matching modules. The
+ * test for matching modules is integral, though.
+ *
+ *\li If category is NULL, then the channel is associated with the indicated
+ * module for all known categories (including the "default" category).
+ *
+ *\li If module is NULL, then the channel is associated with every module
+ * that uses that category.
+ *
+ *\li Passing both category and module as NULL would make every log message
+ * use the indicated channel.
+ *
+ * \li Specifying a channel that is #ISC_LOG_TONULL for a category/module pair
+ * has no effect on any other channels associated with that pair,
+ * regardless of ordering. Thus you cannot use it to "mask out" one
+ * category/module pair when you have specified some other channel that
+ * is also used by that category/module pair.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ *\li category is NULL or has an id that is in the range of known ids.
+ *
+ * module is NULL or has an id that is in the range of known ids.
+ *
+ * Ensures:
+ *\li #ISC_R_SUCCESS
+ * The channel will be used by the indicated category/module
+ * arguments.
+ *
+ *\li #ISC_R_NOMEMORY
+ * If assignment for a specific category has been requested,
+ * the channel has not been associated with the indicated
+ * category/module arguments and no additional memory is
+ * used by the logging context.
+ * If assignment for all categories has been requested
+ * then _some_ may have succeeded (starting with category
+ * "default" and progressing through the order of categories
+ * passed to isc_log_registercategories()) and additional memory
+ * is being used by whatever assignments succeeded.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ */
+
+/* Attention: next four comments PRECEED code */
+/*!
+ * \brief
+ * Write a message to the log channels.
+ *
+ * Notes:
+ *\li Log messages containing natural language text should be logged with
+ * isc_log_iwrite() to allow for localization.
+ *
+ *\li lctx can be NULL; this is allowed so that programs which use
+ * libraries that use the ISC logging system are not required to
+ * also use it.
+ *
+ *\li The format argument is a printf(3) string, with additional arguments
+ * as necessary.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ *\li The category and module arguments must have ids that are in the
+ * range of known ids, as established by isc_log_registercategories()
+ * and isc_log_registermodules().
+ *
+ *\li level != #ISC_LOG_DYNAMIC. ISC_LOG_DYNAMIC is used only to define
+ * channels, and explicit debugging level must be identified for
+ * isc_log_write() via ISC_LOG_DEBUG(level).
+ *
+ *\li format != NULL.
+ *
+ * Ensures:
+ *\li The log message is written to every channel associated with the
+ * indicated category/module pair.
+ *
+ * Returns:
+ *\li Nothing. Failure to log a message is not construed as a
+ * meaningful error.
+ */
+void
+isc_log_write(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ const char *format, ...)
+
+ISC_FORMAT_PRINTF(5, 6);
+
+/*%
+ * Write a message to the log channels.
+ *
+ * Notes:
+ *\li lctx can be NULL; this is allowed so that programs which use
+ * libraries that use the ISC logging system are not required to
+ * also use it.
+ *
+ *\li The format argument is a printf(3) string, with additional arguments
+ * as necessary.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ *\li The category and module arguments must have ids that are in the
+ * range of known ids, as established by isc_log_registercategories()
+ * and isc_log_registermodules().
+ *
+ *\li level != #ISC_LOG_DYNAMIC. ISC_LOG_DYNAMIC is used only to define
+ * channels, and explicit debugging level must be identified for
+ * isc_log_write() via ISC_LOG_DEBUG(level).
+ *
+ *\li format != NULL.
+ *
+ * Ensures:
+ *\li The log message is written to every channel associated with the
+ * indicated category/module pair.
+ *
+ * Returns:
+ *\li Nothing. Failure to log a message is not construed as a
+ * meaningful error.
+ */
+void
+isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ const char *format, va_list args)
+
+ISC_FORMAT_PRINTF(5, 0);
+
+/*%
+ * Write a message to the log channels, pruning duplicates that occur within
+ * a configurable amount of seconds (see isc_log_[sg]etduplicateinterval).
+ * This function is otherwise identical to isc_log_write().
+ */
+void
+isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format, ...)
+
+ISC_FORMAT_PRINTF(5, 6);
+
+/*%
+ * Write a message to the log channels, pruning duplicates that occur within
+ * a configurable amount of seconds (see isc_log_[sg]etduplicateinterval).
+ * This function is otherwise identical to isc_log_vwrite().
+ */
+void
+isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format,
+ va_list args)
+
+ISC_FORMAT_PRINTF(5, 0);
+
+/*%
+ * These are four internationalized versions of the isc_log_[v]write[1]
+ * functions.
+ *
+ * The only difference is that they take arguments for a message
+ * catalog, message set, and message number, all immediately preceding the
+ * format argument. The format argument becomes the default text, a la
+ * isc_msgcat_get. If the message catalog is NULL, no lookup is attempted
+ * for a message -- which makes the message set and message number irrelevant,
+ * and the non-internationalized call should have probably been used instead.
+ *
+ * Yes, that means there are now *eight* interfaces to logging a message.
+ * Sheesh. Make the madness stop!
+ */
+/*@{*/
+void
+isc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *format, ...)
+ISC_FORMAT_PRINTF(8, 9);
+
+void
+isc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *format, va_list args)
+ISC_FORMAT_PRINTF(8, 0);
+
+void
+isc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *format, ...)
+ISC_FORMAT_PRINTF(8, 9);
+
+void
+isc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *format, va_list args)
+ISC_FORMAT_PRINTF(8, 0);
+/*@}*/
+
+void
+isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level);
+/*%<
+ * Set the debugging level used for logging.
+ *
+ * Notes:
+ *\li Setting the debugging level to 0 disables debugging log messages.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ * Ensures:
+ *\li The debugging level is set to the requested value.
+ */
+
+unsigned int
+isc_log_getdebuglevel(isc_log_t *lctx);
+/*%<
+ * Get the current debugging level.
+ *
+ * Notes:
+ *\li This is provided so that a program can have a notion of
+ * "increment debugging level" or "decrement debugging level"
+ * without needing to keep track of what the current level is.
+ *
+ *\li A return value of 0 indicates that debugging messages are disabled.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ * Ensures:
+ *\li The current logging debugging level is returned.
+ */
+
+bool
+isc_log_wouldlog(isc_log_t *lctx, int level);
+/*%<
+ * Determine whether logging something to 'lctx' at 'level' would
+ * actually cause something to be logged somewhere.
+ *
+ * If #false is returned, it is guaranteed that nothing would
+ * be logged, allowing the caller to omit unnecessary
+ * isc_log_write() calls and possible message preformatting.
+ */
+
+void
+isc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval);
+/*%<
+ * Set the interval over which duplicate log messages will be ignored
+ * by isc_log_[v]write1(), in seconds.
+ *
+ * Notes:
+ *\li Increasing the duplicate interval from X to Y will not necessarily
+ * filter out duplicates of messages logged in Y - X seconds since the
+ * increase. (Example: Message1 is logged at midnight. Message2
+ * is logged at 00:01:00, when the interval is only 30 seconds, causing
+ * Message1 to be expired from the log message history. Then the interval
+ * is increased to 3000 (five minutes) and at 00:04:00 Message1 is logged
+ * again. It will appear the second time even though less than five
+ * passed since the first occurrence.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ */
+
+unsigned int
+isc_log_getduplicateinterval(isc_logconfig_t *lcfg);
+/*%<
+ * Get the current duplicate filtering interval.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ * Returns:
+ *\li The current duplicate filtering interval.
+ */
+
+isc_result_t
+isc_log_settag(isc_logconfig_t *lcfg, const char *tag);
+/*%<
+ * Set the program name or other identifier for #ISC_LOG_PRINTTAG.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ * Notes:
+ *\li If this function has not set the tag to a non-NULL, non-empty value,
+ * then the #ISC_LOG_PRINTTAG channel flag will not print anything.
+ * Unlike some implementations of syslog on Unix systems, you *must* set
+ * the tag in order to get it logged. It is not implicitly derived from
+ * the program name (which is pretty impossible to infer portably).
+ *
+ *\li Setting the tag to NULL or the empty string will also cause the
+ * #ISC_LOG_PRINTTAG channel flag to not print anything. If tag equals the
+ * empty string, calls to isc_log_gettag will return NULL.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource Limit: Out of memory
+ *
+ * XXXDCL when creating a new isc_logconfig_t, it might be nice if the tag
+ * of the currently active isc_logconfig_t was inherited. this does not
+ * currently happen.
+ */
+
+char *
+isc_log_gettag(isc_logconfig_t *lcfg);
+/*%<
+ * Get the current identifier printed with #ISC_LOG_PRINTTAG.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ * Notes:
+ *\li Since isc_log_settag() will not associate a zero-length string
+ * with the logging configuration, attempts to do so will cause
+ * this function to return NULL. However, a determined programmer
+ * will observe that (currently) a tag of length greater than zero
+ * could be set, and then modified to be zero length.
+ *
+ * Returns:
+ *\li A pointer to the current identifier, or NULL if none has been set.
+ */
+
+void
+isc_log_opensyslog(const char *tag, int options, int facility);
+/*%<
+ * Initialize syslog logging.
+ *
+ * Notes:
+ *\li XXXDCL NT
+ * This is currently equivalent to openlog(), but is not going to remain
+ * that way. In the meantime, the arguments are all identical to
+ * those used by openlog(3), as follows:
+ *
+ * \code
+ * tag: The string to use in the position of the program
+ * name in syslog messages. Most (all?) syslogs
+ * will use basename(argv[0]) if tag is NULL.
+ *
+ * options: LOG_CONS, LOG_PID, LOG_NDELAY ... whatever your
+ * syslog supports.
+ *
+ * facility: The default syslog facility. This is irrelevant
+ * since isc_log_write will ALWAYS use the channel's
+ * declared facility.
+ * \endcode
+ *
+ *\li Zero effort has been made (yet) to accommodate systems with openlog()
+ * that only takes two arguments, or to identify valid syslog
+ * facilities or options for any given architecture.
+ *
+ *\li It is necessary to call isc_log_opensyslog() to initialize
+ * syslogging on machines which do not support network connections to
+ * syslogd because they require a Unix domain socket to be used. Since
+ * this is a chore to determine at run-time, it is suggested that it
+ * always be called by programs using the ISC logging system.
+ *
+ * Requires:
+ *\li Nothing.
+ *
+ * Ensures:
+ *\li openlog() is called to initialize the syslog system.
+ */
+
+void
+isc_log_closefilelogs(isc_log_t *lctx);
+/*%<
+ * Close all open files used by #ISC_LOG_TOFILE channels.
+ *
+ * Notes:
+ *\li This function is provided for programs that want to use their own
+ * log rolling mechanism rather than the one provided internally.
+ * For example, a program that wanted to keep daily logs would define
+ * a channel which used #ISC_LOG_ROLLNEVER, then once a day would
+ * rename the log file and call isc_log_closefilelogs().
+ *
+ *\li #ISC_LOG_TOFILEDESC channels are unaffected.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *
+ * Ensures:
+ *\li The open files are closed and will be reopened when they are
+ * next needed.
+ */
+
+isc_logcategory_t *
+isc_log_categorybyname(isc_log_t *lctx, const char *name);
+/*%<
+ * Find a category by its name.
+ *
+ * Notes:
+ *\li The string name of a category is not required to be unique.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *\li name is not NULL.
+ *
+ * Returns:
+ *\li A pointer to the _first_ isc_logcategory_t structure used by "name".
+ *
+ *\li NULL if no category exists by that name.
+ */
+
+isc_logmodule_t *
+isc_log_modulebyname(isc_log_t *lctx, const char *name);
+/*%<
+ * Find a module by its name.
+ *
+ * Notes:
+ *\li The string name of a module is not required to be unique.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *\li name is not NULL.
+ *
+ * Returns:
+ *\li A pointer to the _first_ isc_logmodule_t structure used by "name".
+ *
+ *\li NULL if no module exists by that name.
+ */
+
+void
+isc_log_setcontext(isc_log_t *lctx);
+/*%<
+ * Sets the context used by the libisc for logging.
+ *
+ * Requires:
+ *\li lctx be a valid context.
+ */
+
+isc_result_t
+isc_logfile_roll(isc_logfile_t *file);
+/*%<
+ * Roll a logfile.
+ *
+ * Requires:
+ *\li file is not NULL.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_LOG_H */
diff --git a/lib/isc/include/isc/magic.h b/lib/isc/include/isc/magic.h
new file mode 100644
index 0000000..c342d0c
--- /dev/null
+++ b/lib/isc/include/isc/magic.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_MAGIC_H
+#define ISC_MAGIC_H 1
+
+#include <isc/likely.h>
+
+/*! \file isc/magic.h */
+
+typedef struct {
+ unsigned int magic;
+} isc__magic_t;
+
+
+/*%
+ * To use this macro the magic number MUST be the first thing in the
+ * structure, and MUST be of type "unsigned int".
+ * The intent of this is to allow magic numbers to be checked even though
+ * the object is otherwise opaque.
+ */
+#define ISC_MAGIC_VALID(a,b) (ISC_LIKELY((a) != NULL) && \
+ ISC_LIKELY(((const isc__magic_t *)(a))->magic == (b)))
+
+#define ISC_MAGIC(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
+
+#endif /* ISC_MAGIC_H */
diff --git a/lib/isc/include/isc/md5.h b/lib/isc/include/isc/md5.h
new file mode 100644
index 0000000..4d29398
--- /dev/null
+++ b/lib/isc/include/isc/md5.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file isc/md5.h
+ * \brief This is the header file for the MD5 message-digest algorithm.
+ *
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ * - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ */
+
+#ifndef ISC_MD5_H
+#define ISC_MD5_H 1
+
+#include <pk11/site.h>
+
+#ifndef PK11_MD5_DISABLE
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#define ISC_MD5_DIGESTLENGTH 16U
+#define ISC_MD5_BLOCK_LENGTH 64U
+
+#ifdef ISC_PLATFORM_OPENSSLHASH
+#include <openssl/opensslv.h>
+#include <openssl/evp.h>
+
+typedef struct {
+ EVP_MD_CTX *ctx;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ EVP_MD_CTX _ctx;
+#endif
+} isc_md5_t;
+
+#elif PKCS11CRYPTO
+#include <pk11/pk11.h>
+
+typedef pk11_context_t isc_md5_t;
+
+#else
+
+typedef struct {
+ uint32_t buf[4];
+ uint32_t bytes[2];
+ uint32_t in[16];
+} isc_md5_t;
+#endif
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_md5_init(isc_md5_t *ctx);
+
+void
+isc_md5_invalidate(isc_md5_t *ctx);
+
+void
+isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len);
+
+void
+isc_md5_final(isc_md5_t *ctx, unsigned char *digest);
+
+bool
+isc_md5_check(bool testing);
+
+ISC_LANG_ENDDECLS
+
+#endif /* !PK11_MD5_DISABLE */
+
+#endif /* ISC_MD5_H */
diff --git a/lib/isc/include/isc/mem.h b/lib/isc/include/isc/mem.h
new file mode 100644
index 0000000..8f01856
--- /dev/null
+++ b/lib/isc/include/isc/mem.h
@@ -0,0 +1,755 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_MEM_H
+#define ISC_MEM_H 1
+
+/*! \file isc/mem.h */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/json.h>
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+#include <isc/xml.h>
+
+ISC_LANG_BEGINDECLS
+
+#define ISC_MEM_LOWATER 0
+#define ISC_MEM_HIWATER 1
+typedef void (*isc_mem_water_t)(void *, int);
+
+typedef void * (*isc_memalloc_t)(void *, size_t);
+typedef void (*isc_memfree_t)(void *, void *);
+
+/*%
+ * Define ISC_MEM_TRACKLINES=1 to turn on detailed tracing of memory
+ * allocation and freeing by file and line number.
+ */
+#ifndef ISC_MEM_TRACKLINES
+#define ISC_MEM_TRACKLINES 1
+#endif
+
+/*%
+ * Define ISC_MEM_CHECKOVERRUN=1 to turn on checks for using memory outside
+ * the requested space. This will increase the size of each allocation.
+ *
+ * If we are performing a Coverity static analysis then ISC_MEM_CHECKOVERRUN
+ * can hide bugs that would otherwise discovered so force to zero.
+ */
+#ifdef __COVERITY__
+#undef ISC_MEM_CHECKOVERRUN
+#define ISC_MEM_CHECKOVERRUN 0
+#endif
+#ifndef ISC_MEM_CHECKOVERRUN
+#define ISC_MEM_CHECKOVERRUN 1
+#endif
+
+/*%
+ * Define ISC_MEM_FILL=1 to fill each block of memory returned to the system
+ * with the byte string '0xbe'. This helps track down uninitialized pointers
+ * and the like. On freeing memory, the space is filled with '0xde' for
+ * the same reasons.
+ *
+ * If we are performing a Coverity static analysis then ISC_MEM_FILL
+ * can hide bugs that would otherwise discovered so force to zero.
+ */
+#ifdef __COVERITY__
+#undef ISC_MEM_FILL
+#define ISC_MEM_FILL 0
+#endif
+#ifndef ISC_MEM_FILL
+#define ISC_MEM_FILL 1
+#endif
+
+/*%
+ * Define ISC_MEMPOOL_NAMES=1 to make memory pools store a symbolic
+ * name so that the leaking pool can be more readily identified in
+ * case of a memory leak.
+ */
+#ifndef ISC_MEMPOOL_NAMES
+#define ISC_MEMPOOL_NAMES 1
+#endif
+
+LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_debugging;
+LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_defaultflags;
+
+/*@{*/
+#define ISC_MEM_DEBUGTRACE 0x00000001U
+#define ISC_MEM_DEBUGRECORD 0x00000002U
+#define ISC_MEM_DEBUGUSAGE 0x00000004U
+#define ISC_MEM_DEBUGSIZE 0x00000008U
+#define ISC_MEM_DEBUGCTX 0x00000010U
+#define ISC_MEM_DEBUGALL 0x0000001FU
+/*!<
+ * The variable isc_mem_debugging holds a set of flags for
+ * turning certain memory debugging options on or off at
+ * runtime. It is initialized to the value ISC_MEM_DEGBUGGING,
+ * which is 0 by default but may be overridden at compile time.
+ * The following flags can be specified:
+ *
+ * \li #ISC_MEM_DEBUGTRACE
+ * Log each allocation and free to isc_lctx.
+ *
+ * \li #ISC_MEM_DEBUGRECORD
+ * Remember each allocation, and match them up on free.
+ * Crash if a free doesn't match an allocation.
+ *
+ * \li #ISC_MEM_DEBUGUSAGE
+ * If a hi_water mark is set, print the maximum inuse memory
+ * every time it is raised once it exceeds the hi_water mark.
+ *
+ * \li #ISC_MEM_DEBUGSIZE
+ * Check the size argument being passed to isc_mem_put() matches
+ * that passed to isc_mem_get().
+ *
+ * \li #ISC_MEM_DEBUGCTX
+ * Check the mctx argument being passed to isc_mem_put() matches
+ * that passed to isc_mem_get().
+ */
+/*@}*/
+
+#if ISC_MEM_TRACKLINES
+#define _ISC_MEM_FILELINE , __FILE__, __LINE__
+#define _ISC_MEM_FLARG , const char *, unsigned int
+#else
+#define _ISC_MEM_FILELINE
+#define _ISC_MEM_FLARG
+#endif
+
+/*!
+ * Define ISC_MEM_USE_INTERNAL_MALLOC=1 to use the internal malloc()
+ * implementation in preference to the system one. The internal malloc()
+ * is very space-efficient, and quite fast on uniprocessor systems. It
+ * performs poorly on multiprocessor machines.
+ * JT: we can overcome the performance issue on multiprocessor machines
+ * by carefully separating memory contexts.
+ */
+
+#ifndef ISC_MEM_USE_INTERNAL_MALLOC
+#define ISC_MEM_USE_INTERNAL_MALLOC 1
+#endif
+
+/*
+ * Flags for isc_mem_create2()calls.
+ */
+#define ISC_MEMFLAG_NOLOCK 0x00000001 /* no lock is necessary */
+#define ISC_MEMFLAG_INTERNAL 0x00000002 /* use internal malloc */
+#if ISC_MEM_USE_INTERNAL_MALLOC
+#define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_INTERNAL
+#else
+#define ISC_MEMFLAG_DEFAULT 0
+#endif
+
+
+/*%<
+ * We use either isc___mem (three underscores) or isc__mem (two) depending on
+ * whether it's for BIND9's internal purpose (with -DBIND9) or generic export
+ * library.
+ */
+#define ISCMEMFUNC(sfx) isc__mem_ ## sfx
+#define ISCMEMPOOLFUNC(sfx) isc__mempool_ ## sfx
+
+#define isc_mem_get(c, s) ISCMEMFUNC(get)((c), (s) _ISC_MEM_FILELINE)
+#define isc_mem_allocate(c, s) ISCMEMFUNC(allocate)((c), (s) _ISC_MEM_FILELINE)
+#define isc_mem_reallocate(c, p, s) ISCMEMFUNC(reallocate)((c), (p), (s) _ISC_MEM_FILELINE)
+#define isc_mem_strdup(c, p) ISCMEMFUNC(strdup)((c), (p) _ISC_MEM_FILELINE)
+#define isc_mempool_get(c) ISCMEMPOOLFUNC(get)((c) _ISC_MEM_FILELINE)
+
+/*%
+ * isc_mem_putanddetach() is a convenience function for use where you
+ * have a structure with an attached memory context.
+ *
+ * Given:
+ *
+ * \code
+ * struct {
+ * ...
+ * isc_mem_t *mctx;
+ * ...
+ * } *ptr;
+ *
+ * isc_mem_t *mctx;
+ *
+ * isc_mem_putanddetach(&ptr->mctx, ptr, sizeof(*ptr));
+ * \endcode
+ *
+ * is the equivalent of:
+ *
+ * \code
+ * mctx = NULL;
+ * isc_mem_attach(ptr->mctx, &mctx);
+ * isc_mem_detach(&ptr->mctx);
+ * isc_mem_put(mctx, ptr, sizeof(*ptr));
+ * isc_mem_detach(&mctx);
+ * \endcode
+ */
+
+/*% memory and memory pool methods */
+typedef struct isc_memmethods {
+ void (*attach)(isc_mem_t *source, isc_mem_t **targetp);
+ void (*detach)(isc_mem_t **mctxp);
+ void (*destroy)(isc_mem_t **mctxp);
+ void *(*memget)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG);
+ void (*memput)(isc_mem_t *mctx, void *ptr, size_t size _ISC_MEM_FLARG);
+ void (*memputanddetach)(isc_mem_t **mctxp, void *ptr,
+ size_t size _ISC_MEM_FLARG);
+ void *(*memallocate)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG);
+ void *(*memreallocate)(isc_mem_t *mctx, void *ptr,
+ size_t size _ISC_MEM_FLARG);
+ char *(*memstrdup)(isc_mem_t *mctx, const char *s _ISC_MEM_FLARG);
+ void (*memfree)(isc_mem_t *mctx, void *ptr _ISC_MEM_FLARG);
+ void (*setdestroycheck)(isc_mem_t *mctx, bool flag);
+ void (*setwater)(isc_mem_t *ctx, isc_mem_water_t water,
+ void *water_arg, size_t hiwater, size_t lowater);
+ void (*waterack)(isc_mem_t *ctx, int flag);
+ size_t (*inuse)(isc_mem_t *mctx);
+ size_t (*maxinuse)(isc_mem_t *mctx);
+ size_t (*total)(isc_mem_t *mctx);
+ bool (*isovermem)(isc_mem_t *mctx);
+ isc_result_t (*mpcreate)(isc_mem_t *mctx, size_t size,
+ isc_mempool_t **mpctxp);
+} isc_memmethods_t;
+
+typedef struct isc_mempoolmethods {
+ void (*destroy)(isc_mempool_t **mpctxp);
+ void *(*get)(isc_mempool_t *mpctx _ISC_MEM_FLARG);
+ void (*put)(isc_mempool_t *mpctx, void *mem _ISC_MEM_FLARG);
+ unsigned int (*getallocated)(isc_mempool_t *mpctx);
+ void (*setmaxalloc)(isc_mempool_t *mpctx, unsigned int limit);
+ void (*setfreemax)(isc_mempool_t *mpctx, unsigned int limit);
+ void (*setname)(isc_mempool_t *mpctx, const char *name);
+ void (*associatelock)(isc_mempool_t *mpctx, isc_mutex_t *lock);
+ void (*setfillcount)(isc_mempool_t *mpctx, unsigned int limit);
+} isc_mempoolmethods_t;
+
+/*%
+ * This structure is actually just the common prefix of a memory context
+ * implementation's version of an isc_mem_t.
+ * \brief
+ * Direct use of this structure by clients is forbidden. mctx implementations
+ * may change the structure. 'magic' must be ISCAPI_MCTX_MAGIC for any of the
+ * isc_mem_ routines to work. mctx implementations must maintain all mctx
+ * invariants.
+ */
+struct isc_mem {
+ unsigned int impmagic;
+ unsigned int magic;
+ isc_memmethods_t *methods;
+};
+
+#define ISCAPI_MCTX_MAGIC ISC_MAGIC('A','m','c','x')
+#define ISCAPI_MCTX_VALID(m) ((m) != NULL && \
+ (m)->magic == ISCAPI_MCTX_MAGIC)
+
+/*%
+ * This is the common prefix of a memory pool context. The same note as
+ * that for the mem structure applies.
+ */
+struct isc_mempool {
+ unsigned int impmagic;
+ unsigned int magic;
+ isc_mempoolmethods_t *methods;
+};
+
+#define ISCAPI_MPOOL_MAGIC ISC_MAGIC('A','m','p','l')
+#define ISCAPI_MPOOL_VALID(mp) ((mp) != NULL && \
+ (mp)->magic == ISCAPI_MPOOL_MAGIC)
+
+#define isc_mem_put(c, p, s) \
+ do { \
+ ISCMEMFUNC(put)((c), (p), (s) _ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mem_putanddetach(c, p, s) \
+ do { \
+ ISCMEMFUNC(putanddetach)((c), (p), (s) _ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mem_free(c, p) \
+ do { \
+ ISCMEMFUNC(free)((c), (p) _ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mempool_put(c, p) \
+ do { \
+ ISCMEMPOOLFUNC(put)((c), (p) _ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+
+/*@{*/
+isc_result_t
+isc_mem_create(size_t max_size, size_t target_size,
+ isc_mem_t **mctxp);
+
+isc_result_t
+isc_mem_create2(size_t max_size, size_t target_size,
+ isc_mem_t **mctxp, unsigned int flags);
+
+isc_result_t
+isc_mem_createx(size_t max_size, size_t target_size,
+ isc_memalloc_t memalloc, isc_memfree_t memfree,
+ void *arg, isc_mem_t **mctxp);
+
+isc_result_t
+isc_mem_createx2(size_t max_size, size_t target_size,
+ isc_memalloc_t memalloc, isc_memfree_t memfree,
+ void *arg, isc_mem_t **mctxp, unsigned int flags);
+
+/*!<
+ * \brief Create a memory context.
+ *
+ * 'max_size' and 'target_size' are tuning parameters. When
+ * ISC_MEMFLAG_INTERNAL is set, allocations smaller than 'max_size'
+ * will be satisfied by getting blocks of size 'target_size' from the
+ * system allocator and breaking them up into pieces; larger allocations
+ * will use the system allocator directly. If 'max_size' and/or
+ * 'target_size' are zero, default values will be * used. When
+ * ISC_MEMFLAG_INTERNAL is not set, 'target_size' is ignored.
+ *
+ * 'max_size' is also used to size the statistics arrays and the array
+ * used to record active memory when ISC_MEM_DEBUGRECORD is set. Setting
+ * 'max_size' too low can have detrimental effects on performance.
+ *
+ * A memory context created using isc_mem_createx() will obtain
+ * memory from the system by calling 'memalloc' and 'memfree',
+ * passing them the argument 'arg'. A memory context created
+ * using isc_mem_create() will use the standard library malloc()
+ * and free().
+ *
+ * If ISC_MEMFLAG_NOLOCK is set in 'flags', the corresponding memory context
+ * will be accessed without locking. The user who creates the context must
+ * ensure there be no race. Since this can be a source of bug, it is generally
+ * inadvisable to use this flag unless the user is very sure about the race
+ * condition and the access to the object is highly performance sensitive.
+ *
+ * Requires:
+ * mctxp != NULL && *mctxp == NULL */
+/*@}*/
+
+/*@{*/
+void
+isc_mem_attach(isc_mem_t *, isc_mem_t **);
+void
+isc_mem_detach(isc_mem_t **);
+/*!<
+ * \brief Attach to / detach from a memory context.
+ *
+ * This is intended for applications that use multiple memory contexts
+ * in such a way that it is not obvious when the last allocations from
+ * a given context has been freed and destroying the context is safe.
+ *
+ * Most applications do not need to call these functions as they can
+ * simply create a single memory context at the beginning of main()
+ * and destroy it at the end of main(), thereby guaranteeing that it
+ * is not destroyed while there are outstanding allocations.
+ */
+/*@}*/
+
+void
+isc_mem_destroy(isc_mem_t **);
+/*%<
+ * Destroy a memory context.
+ */
+
+isc_result_t
+isc_mem_ondestroy(isc_mem_t *ctx,
+ isc_task_t *task,
+ isc_event_t **event);
+/*%<
+ * Request to be notified with an event when a memory context has
+ * been successfully destroyed.
+ */
+
+void
+isc_mem_stats(isc_mem_t *mctx, FILE *out);
+/*%<
+ * Print memory usage statistics for 'mctx' on the stream 'out'.
+ */
+
+void
+isc_mem_setdestroycheck(isc_mem_t *mctx,
+ bool on);
+/*%<
+ * If 'on' is true, 'mctx' will check for memory leaks when
+ * destroyed and abort the program if any are present.
+ */
+
+/*@{*/
+void
+isc_mem_setquota(isc_mem_t *, size_t);
+size_t
+isc_mem_getquota(isc_mem_t *);
+/*%<
+ * Set/get the memory quota of 'mctx'. This is a hard limit
+ * on the amount of memory that may be allocated from mctx;
+ * if it is exceeded, allocations will fail.
+ */
+/*@}*/
+
+size_t
+isc_mem_inuse(isc_mem_t *mctx);
+/*%<
+ * Get an estimate of the amount of memory in use in 'mctx', in bytes.
+ * This includes quantization overhead, but does not include memory
+ * allocated from the system but not yet used.
+ */
+
+size_t
+isc_mem_maxinuse(isc_mem_t *mctx);
+/*%<
+ * Get an estimate of the largest amount of memory that has been in
+ * use in 'mctx' at any time.
+ */
+
+size_t
+isc_mem_total(isc_mem_t *mctx);
+/*%<
+ * Get the total amount of memory in 'mctx', in bytes, including memory
+ * not yet used.
+ */
+
+bool
+isc_mem_isovermem(isc_mem_t *mctx);
+/*%<
+ * Return true iff the memory context is in "over memory" state, i.e.,
+ * a hiwater mark has been set and the used amount of memory has exceeds
+ * the mark.
+ */
+
+void
+isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg,
+ size_t hiwater, size_t lowater);
+/*%<
+ * Set high and low water marks for this memory context.
+ *
+ * When the memory usage of 'mctx' exceeds 'hiwater',
+ * '(water)(water_arg, #ISC_MEM_HIWATER)' will be called. 'water' needs to
+ * call isc_mem_waterack() with #ISC_MEM_HIWATER to acknowledge the state
+ * change. 'water' may be called multiple times.
+ *
+ * When the usage drops below 'lowater', 'water' will again be called, this
+ * time with #ISC_MEM_LOWATER. 'water' need to calls isc_mem_waterack() with
+ * #ISC_MEM_LOWATER to acknowledge the change.
+ *
+ * static void
+ * water(void *arg, int mark) {
+ * struct foo *foo = arg;
+ *
+ * LOCK(&foo->marklock);
+ * if (foo->mark != mark) {
+ * foo->mark = mark;
+ * ....
+ * isc_mem_waterack(foo->mctx, mark);
+ * }
+ * UNLOCK(&foo->marklock);
+ * }
+ *
+ * If 'water' is NULL then 'water_arg', 'hi_water' and 'lo_water' are
+ * ignored and the state is reset.
+ *
+ * Requires:
+ *
+ * 'water' is not NULL.
+ * hi_water >= lo_water
+ */
+
+void
+isc_mem_waterack(isc_mem_t *ctx, int mark);
+/*%<
+ * Called to acknowledge changes in signaled by calls to 'water'.
+ */
+
+void
+isc_mem_printactive(isc_mem_t *mctx, FILE *file);
+/*%<
+ * Print to 'file' all active memory in 'mctx'.
+ *
+ * Requires ISC_MEM_DEBUGRECORD to have been set.
+ */
+
+void
+isc_mem_printallactive(FILE *file);
+/*%<
+ * Print to 'file' all active memory in all contexts.
+ *
+ * Requires ISC_MEM_DEBUGRECORD to have been set.
+ */
+
+void
+isc_mem_checkdestroyed(FILE *file);
+/*%<
+ * Check that all memory contexts have been destroyed.
+ * Prints out those that have not been.
+ * Fatally fails if there are still active contexts.
+ */
+
+unsigned int
+isc_mem_references(isc_mem_t *ctx);
+/*%<
+ * Return the current reference count.
+ */
+
+void
+isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag);
+/*%<
+ * Name 'ctx'.
+ *
+ * Notes:
+ *
+ *\li Only the first 15 characters of 'name' will be copied.
+ *
+ *\li 'tag' is for debugging purposes only.
+ *
+ * Requires:
+ *
+ *\li 'ctx' is a valid ctx.
+ */
+
+const char *
+isc_mem_getname(isc_mem_t *ctx);
+/*%<
+ * Get the name of 'ctx', as previously set using isc_mem_setname().
+ *
+ * Requires:
+ *\li 'ctx' is a valid ctx.
+ *
+ * Returns:
+ *\li A non-NULL pointer to a null-terminated string.
+ * If the ctx has not been named, the string is
+ * empty.
+ */
+
+void *
+isc_mem_gettag(isc_mem_t *ctx);
+/*%<
+ * Get the tag value for 'task', as previously set using isc_mem_setname().
+ *
+ * Requires:
+ *\li 'ctx' is a valid ctx.
+ *
+ * Notes:
+ *\li This function is for debugging purposes only.
+ *
+ * Requires:
+ *\li 'ctx' is a valid task.
+ */
+
+#ifdef HAVE_LIBXML2
+int
+isc_mem_renderxml(xmlTextWriterPtr writer);
+/*%<
+ * Render all contexts' statistics and status in XML for writer.
+ */
+#endif /* HAVE_LIBXML2 */
+
+#ifdef HAVE_JSON
+isc_result_t
+isc_mem_renderjson(json_object *memobj);
+/*%<
+ * Render all contexts' statistics and status in JSON.
+ */
+#endif /* HAVE_JSON */
+
+
+/*
+ * Memory pools
+ */
+
+isc_result_t
+isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
+/*%<
+ * Create a memory pool.
+ *
+ * Requires:
+ *\li mctx is a valid memory context.
+ *\li size > 0
+ *\li mpctxp != NULL and *mpctxp == NULL
+ *
+ * Defaults:
+ *\li maxalloc = UINT_MAX
+ *\li freemax = 1
+ *\li fillcount = 1
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY -- not enough memory to create pool
+ *\li #ISC_R_SUCCESS -- all is well.
+ */
+
+void
+isc_mempool_destroy(isc_mempool_t **mpctxp);
+/*%<
+ * Destroy a memory pool.
+ *
+ * Requires:
+ *\li mpctxp != NULL && *mpctxp is a valid pool.
+ *\li The pool has no un"put" allocations outstanding
+ */
+
+void
+isc_mempool_setname(isc_mempool_t *mpctx, const char *name);
+/*%<
+ * Associate a name with a memory pool. At most 15 characters may be used.
+ *
+ * Requires:
+ *\li mpctx is a valid pool.
+ *\li name != NULL;
+ */
+
+void
+isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
+/*%<
+ * Associate a lock with this memory pool.
+ *
+ * This lock is used when getting or putting items using this memory pool,
+ * and it is also used to set or get internal state via the isc_mempool_get*()
+ * and isc_mempool_set*() set of functions.
+ *
+ * Multiple pools can each share a single lock. For instance, if "manager"
+ * type object contained pools for various sizes of events, and each of
+ * these pools used a common lock. Note that this lock must NEVER be used
+ * by other than mempool routines once it is given to a pool, since that can
+ * easily cause double locking.
+ *
+ * Requires:
+ *
+ *\li mpctpx is a valid pool.
+ *
+ *\li lock != NULL.
+ *
+ *\li No previous lock is assigned to this pool.
+ *
+ *\li The lock is initialized before calling this function via the normal
+ * means of doing that.
+ */
+
+/*
+ * The following functions get/set various parameters. Note that due to
+ * the unlocked nature of pools these are potentially random values unless
+ * the imposed externally provided locking protocols are followed.
+ *
+ * Also note that the quota limits will not always take immediate effect.
+ * For instance, setting "maxalloc" to a number smaller than the currently
+ * allocated count is permitted. New allocations will be refused until
+ * the count drops below this threshold.
+ *
+ * All functions require (in addition to other requirements):
+ * mpctx is a valid memory pool
+ */
+
+unsigned int
+isc_mempool_getfreemax(isc_mempool_t *mpctx);
+/*%<
+ * Returns the maximum allowed size of the free list.
+ */
+
+void
+isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
+/*%<
+ * Sets the maximum allowed size of the free list.
+ */
+
+unsigned int
+isc_mempool_getfreecount(isc_mempool_t *mpctx);
+/*%<
+ * Returns current size of the free list.
+ */
+
+unsigned int
+isc_mempool_getmaxalloc(isc_mempool_t *mpctx);
+/*!<
+ * Returns the maximum allowed number of allocations.
+ */
+
+void
+isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
+/*%<
+ * Sets the maximum allowed number of allocations.
+ *
+ * Additional requirements:
+ *\li limit > 0
+ */
+
+unsigned int
+isc_mempool_getallocated(isc_mempool_t *mpctx);
+/*%<
+ * Returns the number of items allocated from this pool.
+ */
+
+unsigned int
+isc_mempool_getfillcount(isc_mempool_t *mpctx);
+/*%<
+ * Returns the number of items allocated as a block from the parent memory
+ * context when the free list is empty.
+ */
+
+void
+isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
+/*%<
+ * Sets the fillcount.
+ *
+ * Additional requirements:
+ *\li limit > 0
+ */
+
+
+/*
+ * Pseudo-private functions for use via macros. Do not call directly.
+ */
+void *
+ISCMEMFUNC(get)(isc_mem_t *, size_t _ISC_MEM_FLARG);
+void
+ISCMEMFUNC(putanddetach)(isc_mem_t **, void *, size_t _ISC_MEM_FLARG);
+void
+ISCMEMFUNC(put)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
+void *
+ISCMEMFUNC(allocate)(isc_mem_t *, size_t _ISC_MEM_FLARG);
+void *
+ISCMEMFUNC(reallocate)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
+void
+ISCMEMFUNC(free)(isc_mem_t *, void * _ISC_MEM_FLARG);
+char *
+ISCMEMFUNC(strdup)(isc_mem_t *, const char *_ISC_MEM_FLARG);
+void *
+ISCMEMPOOLFUNC(get)(isc_mempool_t * _ISC_MEM_FLARG);
+void
+ISCMEMPOOLFUNC(put)(isc_mempool_t *, void * _ISC_MEM_FLARG);
+
+/*%<
+ * See isc_mem_create2() above.
+ */
+typedef isc_result_t
+(*isc_memcreatefunc_t)(size_t init_max_size, size_t target_size,
+ isc_mem_t **ctxp, unsigned int flags);
+
+isc_result_t
+isc_mem_register(isc_memcreatefunc_t createfunc);
+/*%<
+ * Register a new memory management implementation and add it to the list of
+ * supported implementations. This function must be called when a different
+ * memory management library is used than the one contained in the ISC library.
+ */
+
+isc_result_t
+isc__mem_register(void);
+/*%<
+ * A short cut function that specifies the memory management module in the ISC
+ * library for isc_mem_register(). An application that uses the ISC library
+ * usually do not have to care about this function: it would call
+ * isc_lib_register(), which internally calls this function.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_MEM_H */
diff --git a/lib/isc/include/isc/meminfo.h b/lib/isc/include/isc/meminfo.h
new file mode 100644
index 0000000..c2c7e57
--- /dev/null
+++ b/lib/isc/include/isc/meminfo.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_MEMINFO_H
+#define ISC_MEMINFO_H 1
+
+#include <inttypes.h>
+
+#include <isc/types.h>
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+uint64_t
+isc_meminfo_totalphys(void);
+/*%<
+ * Return total available physical memory in bytes, or 0 if this cannot
+ * be determined
+*/
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_MEMINFO_H */
diff --git a/lib/isc/include/isc/msgcat.h b/lib/isc/include/isc/msgcat.h
new file mode 100644
index 0000000..3b533d6
--- /dev/null
+++ b/lib/isc/include/isc/msgcat.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_MSGCAT_H
+#define ISC_MSGCAT_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/msgcat.h
+ * \brief The ISC Message Catalog
+ * aids internationalization of applications by allowing
+ * messages to be retrieved from locale-specific files instead of
+ * hardwiring them into the application. This allows translations of
+ * messages appropriate to the locale to be supplied without recompiling
+ * the application.
+ *
+ * Notes:
+ *\li It's very important that message catalogs work, even if only the
+ * default_text can be used.
+ *
+ * MP:
+ *\li The caller must ensure appropriate synchronization of
+ * isc_msgcat_open() and isc_msgcat_close(). isc_msgcat_get()
+ * ensures appropriate synchronization.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/*****
+ ***** Imports
+ *****/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Methods
+ *****/
+
+void
+isc_msgcat_open(const char *name, isc_msgcat_t **msgcatp);
+/*%<
+ * Open a message catalog.
+ *
+ * Notes:
+ *
+ *\li If memory cannot be allocated or other failures occur, *msgcatp
+ * will be set to NULL. If a NULL msgcat is given to isc_msgcat_get(),
+ * the default_text will be returned, ensuring that some message text
+ * will be available, no matter what's going wrong.
+ *
+ * Requires:
+ *
+ *\li 'name' is a valid string.
+ *
+ *\li msgcatp != NULL && *msgcatp == NULL
+ */
+
+void
+isc_msgcat_close(isc_msgcat_t **msgcatp);
+/*%<
+ * Close a message catalog.
+ *
+ * Notes:
+ *
+ *\li Any string pointers returned by prior calls to isc_msgcat_get() are
+ * invalid after isc_msgcat_close() has been called and must not be
+ * used.
+ *
+ * Requires:
+ *
+ *\li *msgcatp is a valid message catalog or is NULL.
+ *
+ * Ensures:
+ *
+ *\li All resources associated with the message catalog are released.
+ *
+ *\li *msgcatp == NULL
+ */
+
+const char *
+isc_msgcat_get(isc_msgcat_t *msgcat, int set, int message,
+ const char *default_text);
+/*%<
+ * Get message 'message' from message set 'set' in 'msgcat'. If it
+ * is not available, use 'default_text'.
+ *
+ * Requires:
+ *
+ *\li 'msgcat' is a valid message catalog or is NULL.
+ *
+ *\li set > 0
+ *
+ *\li message > 0
+ *
+ *\li 'default_text' is a valid string.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_MSGCAT_H */
diff --git a/lib/isc/include/isc/msgs.h b/lib/isc/include/isc/msgs.h
new file mode 100644
index 0000000..01e3b48
--- /dev/null
+++ b/lib/isc/include/isc/msgs.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_MSGS_H
+#define ISC_MSGS_H 1
+
+/*! \file isc/msgs.h */
+
+#include <isc/lib.h> /* Provide isc_msgcat global variable. */
+#include <isc/msgcat.h> /* Provide isc_msgcat_*() functions. */
+
+/*@{*/
+/*!
+ * \brief Message sets, named per source file, excepting "GENERAL".
+ *
+ * IMPORTANT: The original list is alphabetical, but any new sets must
+ * be added to the end.
+ */
+#define ISC_MSGSET_GENERAL 1
+/* ISC_RESULT_RESULTSET 2 */ /* XXX */
+/* ISC_RESULT_UNAVAILABLESET 3 */ /* XXX */
+#define ISC_MSGSET_APP 4
+#define ISC_MSGSET_COMMANDLINE 5
+#define ISC_MSGSET_ENTROPY 6
+#define ISC_MSGSET_IFITERIOCTL 7
+#define ISC_MSGSET_IFITERSYSCTL 8
+#define ISC_MSGSET_LEX 9
+#define ISC_MSGSET_LOG 10
+#define ISC_MSGSET_MEM 11
+#define ISC_MSGSET_NETADDR 12
+#define ISC_MSGSET_PRINT 13
+#define ISC_MSGSET_RESULT 14
+#define ISC_MSGSET_RWLOCK 15
+#define ISC_MSGSET_SOCKADDR 16
+#define ISC_MSGSET_SOCKET 17
+#define ISC_MSGSET_TASK 18
+#define ISC_MSGSET_TIMER 19
+#define ISC_MSGSET_UTIL 20
+#define ISC_MSGSET_IFITERGETIFADDRS 21
+/*@}*/
+
+/*@{*/
+/*!
+ * Message numbers
+ * are only required to be unique per message set,
+ * but are unique throughout the entire catalog to not be as confusing when
+ * debugging.
+ *
+ * The initial numbering was done by multiply by 100 the set number the
+ * message appears in then adding the incremental message number.
+ */
+#define ISC_MSG_FAILED 101 /*%< "failed" */
+#define ISC_MSG_SUCCEEDED 102 /*%< Compatible with "failed" */
+#define ISC_MSG_SUCCESS 103 /*%< More usual way to say "success" */
+#define ISC_MSG_STARTING 104 /*%< As in "daemon: starting" */
+#define ISC_MSG_STOPING 105 /*%< As in "daemon: stopping" */
+#define ISC_MSG_ENTERING 106 /*%< As in "some_subr: entering" */
+#define ISC_MSG_EXITING 107 /*%< As in "some_subr: exiting" */
+#define ISC_MSG_CALLING 108 /*%< As in "calling some_subr()" */
+#define ISC_MSG_RETURNED 109 /*%< As in "some_subr: returned <foo>" */
+#define ISC_MSG_FATALERROR 110 /*%< "fatal error" */
+#define ISC_MSG_SHUTTINGDOWN 111 /*%< "shutting down" */
+#define ISC_MSG_RUNNING 112 /*%< "running" */
+#define ISC_MSG_WAIT 113 /*%< "wait" */
+#define ISC_MSG_WAITUNTIL 114 /*%< "waituntil" */
+
+#define ISC_MSG_SIGNALSETUP 201 /*%< "handle_signal() %d setup: %s" */
+
+#define ISC_MSG_ILLEGALOPT 301 /*%< "illegal option" */
+#define ISC_MSG_OPTNEEDARG 302 /*%< "option requires an argument" */
+
+#define ISC_MSG_ENTROPYSTATS 401 /*%< "Entropy pool %p: refcnt %u ..." */
+
+#define ISC_MSG_MAKESCANSOCKET 501 /*%< "making interface scan socket: %s" */
+#define ISC_MSG_GETIFCONFIG 502 /*%< "get interface configuration: %s" */
+#define ISC_MSG_BUFFERMAX 503 /*%< "... maximum buffer size exceeded" */
+#define ISC_MSG_GETDESTADDR 504 /*%< "%s: getting destination address: %s" */
+#define ISC_MSG_GETNETMASK 505 /*%< "%s: getting netmask: %s" */
+
+#define ISC_MSG_GETIFLISTSIZE 601 /*%< "getting interface list size: ..." */
+#define ISC_MSG_GETIFLIST 602 /*%< "getting interface list: ..." */
+#define ISC_MSG_UNEXPECTEDTYPE 603 /*%< "... unexpected ... message type" */
+
+#define ISC_MSG_UNEXPECTEDSTATE 701 /*%< "Unexpected state %d" */
+
+#define ISC_MSG_BADTIME 801 /*%< "Bad 00 99:99:99.999 " */
+#define ISC_MSG_LEVEL 802 /*%< "level %d: " */
+
+#define ISC_MSG_ADDTRACE 901 /*%< "add %p size %u " */
+#define ISC_MSG_DELTRACE 902 /*%< "del %p size %u " */
+#define ISC_MSG_POOLSTATS 903 /*%< "[Pool statistics]\n" */
+#define ISC_MSG_POOLNAME 904 /*%< "name" */
+#define ISC_MSG_POOLSIZE 905 /*%< "size" */
+#define ISC_MSG_POOLMAXALLOC 906 /*%< "maxalloc" */
+#define ISC_MSG_POOLALLOCATED 907 /*%< "allocated" */
+#define ISC_MSG_POOLFREECOUNT 908 /*%< "freecount" */
+#define ISC_MSG_POOLFREEMAX 909 /*%< "freemax" */
+#define ISC_MSG_POOLFILLCOUNT 910 /*%< "fillcount" */
+#define ISC_MSG_POOLGETS 911 /*%< "gets" */
+#define ISC_MSG_DUMPALLOC 912 /*%< "DUMP OF ALL OUTSTANDING MEMORY ..." */
+#define ISC_MSG_NONE 913 /*%< "\tNone.\n" */
+#define ISC_MSG_PTRFILELINE 914 /*%< "\tptr %p file %s line %u\n" */
+
+#define ISC_MSG_UNKNOWNADDR 1001 /*%< "<unknown address, family %u>" */
+
+#define ISC_MSG_NOLONGDBL 1104 /*%< "long doubles are not supported" */
+
+#define ISC_MSG_PRINTLOCK 1201 /*%< "rwlock %p thread %lu ..." */
+#define ISC_MSG_READ 1202 /*%< "read" */
+#define ISC_MSG_WRITE 1203 /*%< "write" */
+#define ISC_MSG_READING 1204 /*%< "reading" */
+#define ISC_MSG_WRITING 1205 /*%< "writing" */
+#define ISC_MSG_PRELOCK 1206 /*%< "prelock" */
+#define ISC_MSG_POSTLOCK 1207 /*%< "postlock" */
+#define ISC_MSG_PREUNLOCK 1208 /*%< "preunlock" */
+#define ISC_MSG_POSTUNLOCK 1209 /*%< "postunlock" */
+#define ISC_MSG_PRINTLOCK2 1210 /*%< "rwlock %p thread %lu ..." w/ atomic */
+
+#define ISC_MSG_UNKNOWNFAMILY 1301 /*%< "unknown address family: %d" */
+
+#define ISC_MSG_WRITEFAILED 1401 /*%< "write() failed during watcher ..." */
+#define ISC_MSG_READFAILED 1402 /*%< "read() failed during watcher ... " */
+#define ISC_MSG_PROCESSCMSG 1403 /*%< "processing cmsg %p" */
+#define ISC_MSG_IFRECEIVED 1404 /*%< "interface received on ifindex %u" */
+#define ISC_MSG_SENDTODATA 1405 /*%< "sendto pktinfo data, ifindex %u" */
+#define ISC_MSG_DOIORECV 1406 /*%< "doio_recv: recvmsg(%d) %d bytes ..." */
+#define ISC_MSG_PKTRECV 1407 /*%< "packet received correctly" */
+#define ISC_MSG_DESTROYING 1408 /*%< "destroying" */
+#define ISC_MSG_CREATED 1409 /*%< "created" */
+#define ISC_MSG_ACCEPTLOCK 1410 /*%< "internal_accept called, locked ..." */
+#define ISC_MSG_ACCEPTEDCXN 1411 /*%< "accepted connection, new socket %p" */
+#define ISC_MSG_INTERNALRECV 1412 /*%< "internal_recv: task %p got event %p" */
+#define ISC_MSG_INTERNALSEND 1413 /*%< "internal_send: task %p got event %p" */
+#define ISC_MSG_WATCHERMSG 1414 /*%< "watcher got message %d" */
+#define ISC_MSG_SOCKETSREMAIN 1415 /*%< "sockets exist" */
+#define ISC_MSG_PKTINFOPROVIDED 1416 /*%< "pktinfo structure provided, ..." */
+#define ISC_MSG_BOUND 1417 /*%< "bound" */
+#define ISC_MSG_ACCEPTRETURNED 1418 /*%< accept() returned %d/%s */
+#define ISC_MSG_TOOMANYFDS 1419 /*%< %s: too many open file descriptors */
+#define ISC_MSG_ZEROPORT 1420 /*%< dropping source port zero packet */
+#define ISC_MSG_FILTER 1421 /*%< setsockopt(SO_ACCEPTFILTER): %s */
+
+#define ISC_MSG_TOOMANYHANDLES 1422 /*%< %s: too many open WSA event handles: %s */
+#define ISC_MSG_POKED 1423 /*%< "poked flags: %d" */
+
+#define ISC_MSG_AWAKE 1502 /*%< "awake" */
+#define ISC_MSG_WORKING 1503 /*%< "working" */
+#define ISC_MSG_EXECUTE 1504 /*%< "execute action" */
+#define ISC_MSG_EMPTY 1505 /*%< "empty" */
+#define ISC_MSG_DONE 1506 /*%< "done" */
+#define ISC_MSG_QUANTUM 1507 /*%< "quantum" */
+
+#define ISC_MSG_SCHEDULE 1601 /*%< "schedule" */
+#define ISC_MSG_SIGNALSCHED 1602 /*%< "signal (schedule)" */
+#define ISC_MSG_SIGNALDESCHED 1603 /*%< "signal (deschedule)" */
+#define ISC_MSG_SIGNALDESTROY 1604 /*%< "signal (destroy)" */
+#define ISC_MSG_IDLERESCHED 1605 /*%< "idle reschedule" */
+#define ISC_MSG_EVENTNOTALLOC 1606 /*%< "couldn't allocate event" */
+#define ISC_MSG_SCHEDFAIL 1607 /*%< "couldn't schedule timer: %u" */
+#define ISC_MSG_POSTING 1608 /*%< "posting" */
+#define ISC_MSG_WAKEUP 1609 /*%< "wakeup" */
+
+#define ISC_MSG_LOCK 1701 /*%< "LOCK" */
+#define ISC_MSG_LOCKING 1702 /*%< "LOCKING" */
+#define ISC_MSG_LOCKED 1703 /*%< "LOCKED" */
+#define ISC_MSG_UNLOCKED 1704 /*%< "UNLOCKED" */
+#define ISC_MSG_RWLOCK 1705 /*%< "RWLOCK" */
+#define ISC_MSG_RWLOCKED 1706 /*%< "RWLOCKED" */
+#define ISC_MSG_RWUNLOCK 1707 /*%< "RWUNLOCK" */
+#define ISC_MSG_BROADCAST 1708 /*%< "BROADCAST" */
+#define ISC_MSG_SIGNAL 1709 /*%< "SIGNAL" */
+#define ISC_MSG_UTILWAIT 1710 /*%< "WAIT" */
+#define ISC_MSG_WAITED 1711 /*%< "WAITED" */
+
+#define ISC_MSG_GETIFADDRS 1801 /*%< "getting interface addresses: ..." */
+
+/*@}*/
+
+#endif /* ISC_MSGS_H */
diff --git a/lib/isc/include/isc/mutexblock.h b/lib/isc/include/isc/mutexblock.h
new file mode 100644
index 0000000..f00088d
--- /dev/null
+++ b/lib/isc/include/isc/mutexblock.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_MUTEXBLOCK_H
+#define ISC_MUTEXBLOCK_H 1
+
+/*! \file isc/mutexblock.h */
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_mutexblock_init(isc_mutex_t *block, unsigned int count);
+/*%<
+ * Initialize a block of locks. If an error occurs all initialized locks
+ * will be destroyed, if possible.
+ *
+ * Requires:
+ *
+ *\li block != NULL
+ *
+ *\li count > 0
+ *
+ * Returns:
+ *
+ *\li Any code isc_mutex_init() can return is a valid return for this
+ * function.
+ */
+
+isc_result_t
+isc_mutexblock_destroy(isc_mutex_t *block, unsigned int count);
+/*%<
+ * Destroy a block of locks.
+ *
+ * Requires:
+ *
+ *\li block != NULL
+ *
+ *\li count > 0
+ *
+ *\li Each lock in the block be initialized via isc_mutex_init() or
+ * the whole block was initialized via isc_mutex_initblock().
+ *
+ * Returns:
+ *
+ *\li Any code isc_mutex_init() can return is a valid return for this
+ * function.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_MUTEXBLOCK_H */
diff --git a/lib/isc/include/isc/netaddr.h b/lib/isc/include/isc/netaddr.h
new file mode 100644
index 0000000..2d6b12b
--- /dev/null
+++ b/lib/isc/include/isc/netaddr.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_NETADDR_H
+#define ISC_NETADDR_H 1
+
+/*! \file isc/netaddr.h */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/net.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_HAVESYSUNH
+#include <sys/types.h>
+#include <sys/un.h>
+#endif
+
+ISC_LANG_BEGINDECLS
+
+struct isc_netaddr {
+ unsigned int family;
+ union {
+ struct in_addr in;
+ struct in6_addr in6;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ char un[sizeof(((struct sockaddr_un *)0)->sun_path)];
+#endif
+ } type;
+ uint32_t zone;
+};
+
+bool
+isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b);
+
+/*%<
+ * Compare network addresses 'a' and 'b'. Return #true if
+ * they are equal, #false if not.
+ */
+
+bool
+isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
+ unsigned int prefixlen);
+/*%<
+ * Compare the 'prefixlen' most significant bits of the network
+ * addresses 'a' and 'b'. If 'b''s scope is zero then 'a''s scope is
+ * ignored. Return #true if they are equal, #false if not.
+ */
+
+isc_result_t
+isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp);
+/*%<
+ * Convert a netmask in 's' into a prefix length in '*lenp'.
+ * The mask should consist of zero or more '1' bits in the
+ * most significant part of the address, followed by '0' bits.
+ * If this is not the case, #ISC_R_MASKNONCONTIG is returned.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_MASKNONCONTIG
+ */
+
+isc_result_t
+isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target);
+/*%<
+ * Append a text representation of 'sockaddr' to the buffer 'target'.
+ * The text is NOT null terminated. Handles IPv4 and IPv6 addresses.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE The text or the null termination did not fit.
+ *\li #ISC_R_FAILURE Unspecified failure
+ */
+
+void
+isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size);
+/*%<
+ * Format a human-readable representation of the network address '*na'
+ * into the character array 'array', which is of size 'size'.
+ * The resulting string is guaranteed to be null-terminated.
+ */
+
+#define ISC_NETADDR_FORMATSIZE \
+ sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS")
+/*%<
+ * Minimum size of array to pass to isc_netaddr_format().
+ */
+
+void
+isc_netaddr_fromsockaddr(isc_netaddr_t *netaddr, const isc_sockaddr_t *source);
+
+void
+isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina);
+
+void
+isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6);
+
+isc_result_t
+isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path);
+
+void
+isc_netaddr_setzone(isc_netaddr_t *netaddr, uint32_t zone);
+
+uint32_t
+isc_netaddr_getzone(const isc_netaddr_t *netaddr);
+
+void
+isc_netaddr_any(isc_netaddr_t *netaddr);
+/*%<
+ * Return the IPv4 wildcard address.
+ */
+
+void
+isc_netaddr_any6(isc_netaddr_t *netaddr);
+/*%<
+ * Return the IPv6 wildcard address.
+ */
+
+bool
+isc_netaddr_ismulticast(isc_netaddr_t *na);
+/*%<
+ * Returns true if the address is a multicast address.
+ */
+
+bool
+isc_netaddr_isexperimental(isc_netaddr_t *na);
+/*%<
+ * Returns true if the address is a experimental (CLASS E) address.
+ */
+
+bool
+isc_netaddr_islinklocal(isc_netaddr_t *na);
+/*%<
+ * Returns #true if the address is a link local address.
+ */
+
+bool
+isc_netaddr_issitelocal(isc_netaddr_t *na);
+/*%<
+ * Returns #true if the address is a site local address.
+ */
+
+bool
+isc_netaddr_isnetzero(isc_netaddr_t *na);
+/*%<
+ * Returns #true if the address is in net zero.
+ */
+
+void
+isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s);
+/*%<
+ * Convert an IPv6 v4mapped address into an IPv4 address.
+ */
+
+isc_result_t
+isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen);
+/*
+ * Test whether the netaddr 'na' and 'prefixlen' are consistant.
+ * e.g. prefixlen within range.
+ * na does not have bits set which are not covered by the prefixlen.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_RANGE prefixlen out of range
+ * ISC_R_NOTIMPLEMENTED unsupported family
+ * ISC_R_FAILURE extra bits.
+ */
+
+bool
+isc_netaddr_isloopback(const isc_netaddr_t *na);
+/*
+ * Test whether the netaddr 'na' is a loopback IPv4 or IPv6 address (in
+ * 127.0.0.0/8 or ::1).
+ */
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NETADDR_H */
diff --git a/lib/isc/include/isc/netscope.h b/lib/isc/include/isc/netscope.h
new file mode 100644
index 0000000..22224a1
--- /dev/null
+++ b/lib/isc/include/isc/netscope.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_NETSCOPE_H
+#define ISC_NETSCOPE_H 1
+
+/*! \file isc/netscope.h */
+
+#include <inttypes.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * Convert a string of an IPv6 scope zone to zone index. If the conversion
+ * succeeds, 'zoneid' will store the index value.
+ *
+ * XXXJT: when a standard interface for this purpose is defined,
+ * we should use it.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS: conversion succeeds
+ * \li ISC_R_FAILURE: conversion fails
+ */
+isc_result_t
+isc_netscope_pton(int af, char *scopename, void *addr, uint32_t *zoneid);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NETSCOPE_H */
diff --git a/lib/isc/include/isc/ondestroy.h b/lib/isc/include/isc/ondestroy.h
new file mode 100644
index 0000000..ad1aa61
--- /dev/null
+++ b/lib/isc/include/isc/ondestroy.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id: ondestroy.h,v 1.14 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_ONDESTROY_H
+#define ISC_ONDESTROY_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*! \file isc/ondestroy.h
+ * ondestroy handling.
+ *
+ * Any class ``X'' of objects that wants to send out notifications
+ * on its destruction should declare a field of type isc_ondestroy_t
+ * (call it 'ondest').
+ *
+ * \code
+ * typedef struct {
+ * ...
+ * isc_ondestroy_t ondest;
+ * ...
+ * } X;
+ * \endcode
+ *
+ * When an object ``A'' of type X is created
+ * it must initialize the field ondest with a call to
+ *
+ * \code
+ * isc_ondestroy_init(&A->ondest).
+ * \endcode
+ *
+ * X should also provide a registration function for third-party
+ * objects to call to register their interest in being told about
+ * the destruction of a particular instance of X.
+ *
+ * \code
+ * isc_result_t
+ * X_ondestroy(X *instance, isc_task_t *task,
+ * isc_event_t **eventp) {
+ * return(isc_ondestroy_register(&instance->ondest, task,eventp));
+ * }
+ * \endcode
+ *
+ * Note: locking of the ondestory structure embedded inside of X, is
+ * X's responsibility.
+ *
+ * When an instance of X is destroyed, a call to isc_ondestroy_notify()
+ * sends the notifications:
+ *
+ * \code
+ * X *instance;
+ * isc_ondestroy_t ondest = instance->ondest;
+ *
+ * ... completely cleanup 'instance' here...
+ *
+ * isc_ondestroy_notify(&ondest, instance);
+ * \endcode
+ *
+ *
+ * see lib/dns/zone.c for an ifdef'd-out example.
+ */
+
+struct isc_ondestroy {
+ unsigned int magic;
+ isc_eventlist_t events;
+};
+
+void
+isc_ondestroy_init(isc_ondestroy_t *ondest);
+/*%<
+ * Initialize the on ondest structure. *must* be called before first call
+ * to isc_ondestroy_register().
+ */
+
+isc_result_t
+isc_ondestroy_register(isc_ondestroy_t *ondest, isc_task_t *task,
+ isc_event_t **eventp);
+
+/*%<
+ * Stores task and *eventp away inside *ondest. Ownership of **event is
+ * taken from the caller (and *eventp is set to NULL). The task is attached
+ * to.
+ */
+
+void
+isc_ondestroy_notify(isc_ondestroy_t *ondest, void *sender);
+/*%<
+ * Dispatches the event(s) to the task(s) that were given in
+ * isc_ondestroy_register call(s) (done via calls to
+ * isc_task_sendanddetach()). Before dispatch, the sender value of each
+ * event structure is set to the value of the sender paramater. The
+ * internal structures of the ondest parameter are cleaned out, so no other
+ * cleanup is needed.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ONDESTROY_H */
diff --git a/lib/isc/include/isc/os.h b/lib/isc/include/isc/os.h
new file mode 100644
index 0000000..eb8223e
--- /dev/null
+++ b/lib/isc/include/isc/os.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_OS_H
+#define ISC_OS_H 1
+
+/*! \file isc/os.h */
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+unsigned int
+isc_os_ncpus(void);
+/*%<
+ * Return the number of CPUs available on the system, or 1 if this cannot
+ * be determined.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_OS_H */
diff --git a/lib/isc/include/isc/parseint.h b/lib/isc/include/isc/parseint.h
new file mode 100644
index 0000000..41e8a6c
--- /dev/null
+++ b/lib/isc/include/isc/parseint.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_PARSEINT_H
+#define ISC_PARSEINT_H 1
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file isc/parseint.h
+ * \brief Parse integers, in a saner way than atoi() or strtoul() do.
+ */
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_parse_uint32(uint32_t *uip, const char *string, int base);
+
+isc_result_t
+isc_parse_uint16(uint16_t *uip, const char *string, int base);
+
+isc_result_t
+isc_parse_uint8(uint8_t *uip, const char *string, int base);
+/*%<
+ * Parse the null-terminated string 'string' containing a base 'base'
+ * integer, storing the result in '*uip'.
+ * The base is interpreted
+ * as in strtoul(). Unlike strtoul(), leading whitespace, minus or
+ * plus signs are not accepted, and all errors (including overflow)
+ * are reported uniformly through the return value.
+ *
+ * Requires:
+ *\li 'string' points to a null-terminated string
+ *\li 0 <= 'base' <= 36
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_BADNUMBER The string is not numeric (in the given base)
+ *\li #ISC_R_RANGE The number is not representable as the requested type.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_PARSEINT_H */
diff --git a/lib/isc/include/isc/platform.h.in b/lib/isc/include/isc/platform.h.in
new file mode 100644
index 0000000..c902d46
--- /dev/null
+++ b/lib/isc/include/isc/platform.h.in
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_PLATFORM_H
+#define ISC_PLATFORM_H 1
+
+/*! \file */
+
+/*****
+ ***** Platform-dependent defines.
+ *****/
+
+/***
+ *** Network.
+ ***/
+
+/*! \brief
+ * Define if this system needs the <netinet/in6.h> header file included
+ * for full IPv6 support (pretty much only UnixWare).
+ */
+@ISC_PLATFORM_NEEDNETINETIN6H@
+
+/*! \brief
+ * Define if this system needs the <netinet6/in6.h> header file included
+ * to support in6_pkinfo (pretty much only BSD/OS).
+ */
+@ISC_PLATFORM_NEEDNETINET6IN6H@
+
+/*! \brief
+ * If sockaddrs on this system have an sa_len field, ISC_PLATFORM_HAVESALEN
+ * will be defined.
+ */
+@ISC_PLATFORM_HAVESALEN@
+
+/*! \brief
+ * If this system has the IPv6 structure definitions, ISC_PLATFORM_HAVEIPV6
+ * will be defined.
+ */
+@ISC_PLATFORM_HAVEIPV6@
+
+/*! \brief
+ * If this system is missing in6addr_any, ISC_PLATFORM_NEEDIN6ADDRANY will
+ * be defined.
+ */
+@ISC_PLATFORM_NEEDIN6ADDRANY@
+
+/*! \brief
+ * If this system is missing in6addr_loopback, ISC_PLATFORM_NEEDIN6ADDRLOOPBACK
+ * will be defined.
+ */
+@ISC_PLATFORM_NEEDIN6ADDRLOOPBACK@
+
+/*! \brief
+ * If this system has in6_pktinfo, ISC_PLATFORM_HAVEIN6PKTINFO will be
+ * defined.
+ */
+@ISC_PLATFORM_HAVEIN6PKTINFO@
+
+/*! \brief
+ * If this system has in_addr6, rather than in6_addr, ISC_PLATFORM_HAVEINADDR6
+ * will be defined.
+ */
+@ISC_PLATFORM_HAVEINADDR6@
+
+/*! \brief
+ * If this system has sin6_scope_id, ISC_PLATFORM_HAVESCOPEID will be defined.
+ */
+@ISC_PLATFORM_HAVESCOPEID@
+
+/*! \brief
+ * If this system needs inet_ntop(), ISC_PLATFORM_NEEDNTOP will be defined.
+ */
+@ISC_PLATFORM_NEEDNTOP@
+
+/*! \brief
+ * If this system needs inet_pton(), ISC_PLATFORM_NEEDPTON will be defined.
+ */
+@ISC_PLATFORM_NEEDPTON@
+
+/*! \brief
+ * If this system needs in_port_t, ISC_PLATFORM_NEEDPORTT will be defined.
+ */
+@ISC_PLATFORM_NEEDPORTT@
+
+/*! \brief
+ * Define if the system has struct lifconf which is a extended struct ifconf
+ * for IPv6.
+ */
+@ISC_PLATFORM_HAVELIFCONF@
+
+/*! \brief
+ * Define if the system has struct if_laddrconf which is a extended struct
+ * ifconf for IPv6.
+ */
+@ISC_PLATFORM_HAVEIF_LADDRCONF@
+
+/*! \brief
+ * Define if the system has struct if_laddrreq.
+ */
+@ISC_PLATFORM_HAVEIF_LADDRREQ@
+
+/*! \brief
+ * Define either ISC_PLATFORM_BSD44MSGHDR or ISC_PLATFORM_BSD43MSGHDR.
+ */
+@ISC_PLATFORM_MSGHDRFLAVOR@
+
+/*! \brief
+ * Define if the system supports if_nametoindex.
+ */
+@ISC_PLATFORM_HAVEIFNAMETOINDEX@
+
+/*! \brief
+ * Define on some UnixWare systems to fix erroneous definitions of various
+ * IN6_IS_ADDR_* macros.
+ */
+@ISC_PLATFORM_FIXIN6ISADDR@
+
+/*! \brief
+ * Define if the system has struct sockaddr_storage.
+ */
+@ISC_PLATFORM_HAVESOCKADDRSTORAGE@
+
+/*! \brief
+ * Define if the system has TCP_FASTOPEN socket option.
+ */
+@ISC_PLATFORM_HAVETFO@
+
+/*! \brief
+ * Define if the system supports kqueue multiplexing
+ */
+@ISC_PLATFORM_HAVEKQUEUE@
+
+/*! \brief
+ * Define if the system supports epoll multiplexing
+ */
+@ISC_PLATFORM_HAVEEPOLL@
+
+/*! \brief
+ * Define if the system supports /dev/poll multiplexing
+ */
+@ISC_PLATFORM_HAVEDEVPOLL@
+
+/*! \brief
+ * Define if we want to log backtrace
+ */
+@ISC_PLATFORM_USEBACKTRACE@
+
+/*
+ *** Printing.
+ ***/
+
+/*! \brief
+ * If this system needs vsnprintf() and snprintf(), ISC_PLATFORM_NEEDVSNPRINTF
+ * will be defined.
+ */
+@ISC_PLATFORM_NEEDVSNPRINTF@
+
+/*! \brief
+ * If this system need a modern sprintf() that returns (int) not (char*).
+ */
+@ISC_PLATFORM_NEEDSPRINTF@
+
+/*! \brief
+ * If this system need a modern printf() that format size %z (size_t).
+ */
+@ISC_PLATFORM_NEEDPRINTF@
+
+/*! \brief
+ * If this system need a modern fprintf() that format size %z (size_t).
+ */
+@ISC_PLATFORM_NEEDFPRINTF@
+
+/***
+ *** String functions.
+ ***/
+/*
+ * If the system needs strsep(), ISC_PLATFORM_NEEDSTRSEP will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRSEP@
+
+/*
+ * If the system needs strlcpy(), ISC_PLATFORM_NEEDSTRLCPY will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRLCPY@
+
+/*
+ * If the system needs strlcat(), ISC_PLATFORM_NEEDSTRLCAT will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRLCAT@
+
+/*
+ * Define if this system needs strtoul.
+ */
+@ISC_PLATFORM_NEEDSTRTOUL@
+
+/*
+ * Define if this system needs memmove.
+ */
+@ISC_PLATFORM_NEEDMEMMOVE@
+
+/*
+ * Define if this system needs strcasestr.
+ */
+@ISC_PLATFORM_NEEDSTRCASESTR@
+
+/***
+ *** Miscellaneous.
+ ***/
+
+/*
+ * Defined if we are using threads.
+ */
+@ISC_PLATFORM_USETHREADS@
+
+/*
+ * Defined if unistd.h does not cause fd_set to be delared.
+ */
+@ISC_PLATFORM_NEEDSYSSELECTH@
+
+/*
+ * Defined to <gssapi.h> or <gssapi/gssapi.h> for how to include
+ * the GSSAPI header.
+ */
+@ISC_PLATFORM_GSSAPIHEADER@
+
+/*
+ * Defined to <gssapi_krb5.h> or <gssapi/gssapi_krb5.h> for how to
+ * include the GSSAPI KRB5 header.
+ */
+@ISC_PLATFORM_GSSAPI_KRB5_HEADER@
+
+/*
+ * Defined to <krb5.h> or <krb5/krb5.h> for how to include
+ * the KRB5 header.
+ */
+@ISC_PLATFORM_KRB5HEADER@
+
+/*
+ * Define if the system has nanosecond-level accuracy in file stats.
+ */
+@ISC_PLATFORM_HAVESTATNSEC@
+
+/*
+ * Type used for resource limits.
+ */
+@ISC_PLATFORM_RLIMITTYPE@
+
+/*
+ * Define if your compiler supports "long long int".
+ */
+@ISC_PLATFORM_HAVELONGLONG@
+
+/*
+ * Define if PTHREAD_ONCE_INIT should be surrounded by braces to
+ * prevent compiler warnings (such as with gcc on Solaris 2.8).
+ */
+@ISC_PLATFORM_BRACEPTHREADONCEINIT@
+
+/*
+ * Used to control how extern data is linked; needed for Win32 platforms.
+ */
+@ISC_PLATFORM_USEDECLSPEC@
+
+/*
+ * Define if the platform has <sys/un.h>.
+ */
+@ISC_PLATFORM_HAVESYSUNH@
+
+/*
+ * If the "xadd" operation is available on this architecture,
+ * ISC_PLATFORM_HAVEXADD will be defined.
+ */
+@ISC_PLATFORM_HAVEXADD@
+
+/*
+ * If the "xaddq" operation (64bit xadd) is available on this architecture,
+ * ISC_PLATFORM_HAVEXADDQ will be defined.
+ */
+@ISC_PLATFORM_HAVEXADDQ@
+
+/*
+ * If the 32-bit "atomic swap" operation is available on this
+ * architecture, ISC_PLATFORM_HAVEATOMICSTORE" will be defined.
+ */
+@ISC_PLATFORM_HAVEATOMICSTORE@
+
+/*
+ * If the 64-bit "atomic swap" operation is available on this
+ * architecture, ISC_PLATFORM_HAVEATOMICSTORE" will be defined.
+ */
+@ISC_PLATFORM_HAVEATOMICSTOREQ@
+
+/*
+ * If the "compare-and-exchange" operation is available on this architecture,
+ * ISC_PLATFORM_HAVECMPXCHG will be defined.
+ */
+@ISC_PLATFORM_HAVECMPXCHG@
+
+/*
+ * If <stdatomic.h> is available on this architecture,
+ * ISC_PLATFORM_HAVESTDATOMIC will be defined.
+ */
+@ISC_PLATFORM_HAVESTDATOMIC@
+
+/*
+ * Define if gcc ASM extension is available
+ */
+@ISC_PLATFORM_USEGCCASM@
+
+/*
+ * Define if Tru64 style ASM syntax must be used.
+ */
+@ISC_PLATFORM_USEOSFASM@
+
+/*
+ * Define if the standard __asm function must be used.
+ */
+@ISC_PLATFORM_USESTDASM@
+
+/*
+ * Define with the busy wait nop asm or function call.
+ */
+@ISC_PLATFORM_BUSYWAITNOP@
+
+/*
+ * Define if the platform has <strings.h>.
+ */
+@ISC_PLATFORM_HAVESTRINGSH@
+
+/*
+ * Define if the hash functions must be provided by OpenSSL.
+ */
+@ISC_PLATFORM_OPENSSLHASH@
+
+/*
+ * Define if AES support is wanted
+ */
+@ISC_PLATFORM_WANTAES@
+
+/*
+ * Defines for the noreturn attribute.
+ */
+@ISC_PLATFORM_NORETURN_PRE@
+@ISC_PLATFORM_NORETURN_POST@
+
+/***
+ *** Windows dll support.
+ ***/
+
+/*
+ * Define if MacOS style of PPC assembly must be used.
+ * e.g. "r6", not "6", for register six.
+ */
+@ISC_PLATFORM_USEMACASM@
+
+#ifndef ISC_PLATFORM_USEDECLSPEC
+#define LIBISC_EXTERNAL_DATA
+#define LIBDNS_EXTERNAL_DATA
+#define LIBISCCC_EXTERNAL_DATA
+#define LIBISCCFG_EXTERNAL_DATA
+#define LIBBIND9_EXTERNAL_DATA
+#define LIBTESTS_EXTERNAL_DATA
+#else /*! \brief ISC_PLATFORM_USEDECLSPEC */
+#ifdef LIBISC_EXPORTS
+#define LIBISC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBDNS_EXPORTS
+#define LIBDNS_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBDNS_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBISCCC_EXPORTS
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBISCCFG_EXPORTS
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBBIND9_EXPORTS
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBTESTS_EXPORTS
+#define LIBTESTS_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBTESTS_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#endif /*! \brief ISC_PLATFORM_USEDECLSPEC */
+
+/*
+ * Tell emacs to use C mode for this file.
+ *
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
+#endif /* ISC_PLATFORM_H */
diff --git a/lib/isc/include/isc/pool.h b/lib/isc/include/isc/pool.h
new file mode 100644
index 0000000..a648312
--- /dev/null
+++ b/lib/isc/include/isc/pool.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_OBJPOOL_H
+#define ISC_OBJPOOL_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/pool.h
+ * \brief An object pool is a mechanism for sharing a small pool of
+ * fungible objects among a large number of objects that depend on them.
+ *
+ * This is useful, for example, when it causes performance problems for
+ * large number of zones to share a single memory context or task object,
+ * but it would create a different set of problems for them each to have an
+ * independent task or memory context.
+ */
+
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/mem.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Types.
+ *****/
+
+typedef void
+(*isc_pooldeallocator_t)(void **object);
+
+typedef isc_result_t
+(*isc_poolinitializer_t)(void **target, void *arg);
+
+typedef struct isc_pool isc_pool_t;
+
+/*****
+ ***** Functions.
+ *****/
+
+isc_result_t
+isc_pool_create(isc_mem_t *mctx, unsigned int count,
+ isc_pooldeallocator_t free,
+ isc_poolinitializer_t init, void *initarg,
+ isc_pool_t **poolp);
+/*%<
+ * Create a pool of "count" object pointers. If 'free' is not NULL,
+ * it points to a function that will detach the objects. 'init'
+ * points to a function that will initialize the arguments, and
+ * 'arg' to an argument to be passed into that function (for example,
+ * a relevant manager or context object).
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li init != NULL
+ *
+ *\li poolp != NULL && *poolp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, '*poolp' points to the new object pool.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ */
+
+void *
+isc_pool_get(isc_pool_t *pool);
+/*%<
+ * Returns a pointer to an object from the pool. Currently the object
+ * is chosen from the pool at random. (This may be changed in the future
+ * to something that guaratees balance.)
+ */
+
+int
+isc_pool_count(isc_pool_t *pool);
+/*%<
+ * Returns the number of objcts in the pool 'pool'.
+ */
+
+isc_result_t
+isc_pool_expand(isc_pool_t **sourcep, unsigned int count, isc_pool_t **targetp);
+
+/*%<
+ * If 'size' is larger than the number of objects in the pool pointed to by
+ * 'sourcep', then a new pool of size 'count' is allocated, the existing
+ * objects are copied into it, additional ones created to bring the
+ * total number up to 'count', and the resulting pool is attached to
+ * 'targetp'.
+ *
+ * If 'count' is less than or equal to the number of objects in 'source', then
+ * 'sourcep' is attached to 'targetp' without any other action being taken.
+ *
+ * In either case, 'sourcep' is detached.
+ *
+ * Requires:
+ *
+ * \li 'sourcep' is not NULL and '*source' is not NULL
+ * \li 'targetp' is not NULL and '*source' is NULL
+ *
+ * Ensures:
+ *
+ * \li On success, '*targetp' points to a valid task pool.
+ * \li On success, '*sourcep' points to NULL.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ */
+
+void
+isc_pool_destroy(isc_pool_t **poolp);
+/*%<
+ * Destroy a task pool. The tasks in the pool are detached but not
+ * shut down.
+ *
+ * Requires:
+ * \li '*poolp' is a valid task pool.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_OBJPOOL_H */
diff --git a/lib/isc/include/isc/portset.h b/lib/isc/include/isc/portset.h
new file mode 100644
index 0000000..1f0d928
--- /dev/null
+++ b/lib/isc/include/isc/portset.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file isc/portset.h
+ * \brief Transport Protocol Port Manipulation Module
+ *
+ * This module provides simple utilities to handle a set of transport protocol
+ * (UDP or TCP) port numbers, e.g., for creating an ACL list. An isc_portset_t
+ * object is an opaque instance of a port set, for which the user can add or
+ * remove a specific port or a range of consecutive ports. This object is
+ * expected to be used as a temporary work space only, and does not protect
+ * simultaneous access from multiple threads. Therefore it must not be stored
+ * in a place that can be accessed from multiple threads.
+ */
+
+#ifndef ISC_PORTSET_H
+#define ISC_PORTSET_H 1
+
+/***
+ *** Imports
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/net.h>
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp);
+/*%<
+ * Create a port set and initialize it as an empty set.
+ *
+ * Requires:
+ *\li 'mctx' to be valid.
+ *\li 'portsetp' to be non NULL and '*portsetp' to be NULL;
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+void
+isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp);
+/*%<
+ * Destroy a port set.
+ *
+ * Requires:
+ *\li 'mctx' to be valid and must be the same context given when the port set
+ * was created.
+ *\li '*portsetp' to be a valid set.
+ */
+
+bool
+isc_portset_isset(isc_portset_t *portset, in_port_t port);
+/*%<
+ * Test whether the given port is stored in the portset.
+ *
+ * Requires:
+ *\li 'portset' to be a valid set.
+ *
+ * Returns
+ * \li #true if the port is found, false otherwise.
+ */
+
+unsigned int
+isc_portset_nports(isc_portset_t *portset);
+/*%<
+ * Provides the number of ports stored in the given portset.
+ *
+ * Requires:
+ *\li 'portset' to be a valid set.
+ *
+ * Returns
+ * \li the number of ports stored in portset.
+ */
+
+void
+isc_portset_add(isc_portset_t *portset, in_port_t port);
+/*%<
+ * Add the given port to the portset. The port may or may not be stored in
+ * the portset.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ */
+
+void
+isc_portset_remove(isc_portset_t *portset, in_port_t port);
+/*%<
+ * Remove the given port to the portset. The port may or may not be stored in
+ * the portset.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ */
+
+void
+isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo,
+ in_port_t port_hi);
+/*%<
+ * Add a subset of [port_lo, port_hi] (inclusive) to the portset. Ports in the
+ * subset may or may not be stored in portset.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ *\li port_lo <= port_hi
+ */
+
+void
+isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo,
+ in_port_t port_hi);
+/*%<
+ * Subtract a subset of [port_lo, port_hi] (inclusive) from the portset. Ports
+ * in the subset may or may not be stored in portset.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ *\li port_lo <= port_hi
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_PORTSET_H */
diff --git a/lib/isc/include/isc/print.h b/lib/isc/include/isc/print.h
new file mode 100644
index 0000000..e4fa76c
--- /dev/null
+++ b/lib/isc/include/isc/print.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_PRINT_H
+#define ISC_PRINT_H 1
+
+/*! \file isc/print.h */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/formatcheck.h> /* Required for ISC_FORMAT_PRINTF() macro. */
+#include <isc/lang.h>
+#include <isc/platform.h>
+
+/*!
+ * This block allows lib/isc/print.c to be cleanly compiled even if
+ * the platform does not need it. The standard Makefile will still
+ * not compile print.c or archive print.o, so this is just to make test
+ * compilation ("make print.o") easier.
+ */
+#if !defined(ISC_PLATFORM_NEEDVSNPRINTF) && defined(ISC__PRINT_SOURCE)
+#define ISC_PLATFORM_NEEDVSNPRINTF
+#undef snprintf
+#undef vsnprintf
+#endif
+
+#if !defined(ISC_PLATFORM_NEEDSPRINTF) && defined(ISC__PRINT_SOURCE)
+#define ISC_PLATFORM_NEEDSPRINTF
+#undef sprintf
+#endif
+
+#if !defined(ISC_PLATFORM_NEEDFPRINTF) && defined(ISC__PRINT_SOURCE)
+#define ISC_PLATFORM_NEEDFPRINTF
+#undef fprintf
+#endif
+
+#if !defined(ISC_PLATFORM_NEEDPRINTF) && defined(ISC__PRINT_SOURCE)
+#define ISC_PLATFORM_NEEDPRINTF
+#undef printf
+#endif
+
+/***
+ *** Functions
+ ***/
+
+#ifdef ISC_PLATFORM_NEEDVSNPRINTF
+#include <stdarg.h>
+#include <stddef.h>
+#endif
+
+#include <stdio.h>
+
+ISC_LANG_BEGINDECLS
+
+#ifdef ISC_PLATFORM_NEEDVSNPRINTF
+int
+isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+ ISC_FORMAT_PRINTF(3, 0);
+#undef vsnprintf
+#define vsnprintf isc_print_vsnprintf
+
+int
+isc_print_snprintf(char *str, size_t size, const char *format, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+#undef snprintf
+#define snprintf isc_print_snprintf
+#endif /* ISC_PLATFORM_NEEDVSNPRINTF */
+
+#ifdef ISC_PLATFORM_NEEDSPRINTF
+int
+isc_print_sprintf(char *str, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
+#undef sprintf
+#define sprintf isc_print_sprintf
+#endif
+
+#ifdef ISC_PLATFORM_NEEDPRINTF
+int
+isc_print_printf(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
+#undef printf
+#define printf isc_print_printf
+#endif
+
+#ifdef ISC_PLATFORM_NEEDFPRINTF
+int
+isc_print_fprintf(FILE * fp, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
+#undef fprintf
+#define fprintf isc_print_fprintf
+#endif
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_PRINT_H */
diff --git a/lib/isc/include/isc/queue.h b/lib/isc/include/isc/queue.h
new file mode 100644
index 0000000..210f302
--- /dev/null
+++ b/lib/isc/include/isc/queue.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * This is a generic implementation of a two-lock concurrent queue.
+ * There are built-in mutex locks for the head and tail of the queue,
+ * allowing elements to be safely added and removed at the same time.
+ *
+ * NULL is "end of list"
+ * -1 is "not linked"
+ */
+
+#ifndef ISC_QUEUE_H
+#define ISC_QUEUE_H 1
+
+#include <stdbool.h>
+
+#include <isc/assertions.h>
+#include <isc/mutex.h>
+
+#ifdef ISC_QUEUE_CHECKINIT
+#define ISC_QLINK_INSIST(x) ISC_INSIST(x)
+#else
+#define ISC_QLINK_INSIST(x) (void)0
+#endif
+
+#define ISC_QLINK(type) struct { type *prev, *next; }
+
+#define ISC_QLINK_INIT(elt, link) \
+ do { \
+ (elt)->link.next = (elt)->link.prev = (void *)(-1); \
+ } while(0)
+
+#define ISC_QLINK_LINKED(elt, link) ((void*)(elt)->link.next != (void*)(-1))
+
+#define ISC_QUEUE(type) struct { \
+ type *head, *tail; \
+ isc_mutex_t headlock, taillock; \
+}
+
+#define ISC_QUEUE_INIT(queue, link) \
+ do { \
+ (void) isc_mutex_init(&(queue).taillock); \
+ (void) isc_mutex_init(&(queue).headlock); \
+ (queue).tail = (queue).head = NULL; \
+ } while (0)
+
+#define ISC_QUEUE_EMPTY(queue) ((queue).head == NULL)
+
+#define ISC_QUEUE_DESTROY(queue) \
+ do { \
+ ISC_QLINK_INSIST(ISC_QUEUE_EMPTY(queue)); \
+ (void) isc_mutex_destroy(&(queue).taillock); \
+ (void) isc_mutex_destroy(&(queue).headlock); \
+ } while (0)
+
+/*
+ * queues are meant to separate the locks at either end. For best effect, that
+ * means keeping the ends separate - i.e. non-empty queues work best.
+ *
+ * a push to an empty queue has to take the pop lock to update
+ * the pop side of the queue.
+ * Popping the last entry has to take the push lock to update
+ * the push side of the queue.
+ *
+ * The order is (pop, push), because a pop is presumably in the
+ * latency path and a push is when we're done.
+ *
+ * We do an MT hot test in push to see if we need both locks, so we can
+ * acquire them in order. Hopefully that makes the case where we get
+ * the push lock and find we need the pop lock (and have to release it) rare.
+ *
+ * > 1 entry - no collision, push works on one end, pop on the other
+ * 0 entry - headlock race
+ * pop wins - return(NULL), push adds new as both head/tail
+ * push wins - updates head/tail, becomes 1 entry case.
+ * 1 entry - taillock race
+ * pop wins - return(pop) sets head/tail NULL, becomes 0 entry case
+ * push wins - updates {head,tail}->link.next, pop updates head
+ * with new ->link.next and doesn't update tail
+ *
+ */
+#define ISC_QUEUE_PUSH(queue, elt, link) \
+ do { \
+ bool headlocked = false; \
+ ISC_QLINK_INSIST(!ISC_QLINK_LINKED(elt, link)); \
+ if ((queue).head == NULL) { \
+ LOCK(&(queue).headlock); \
+ headlocked = true; \
+ } \
+ LOCK(&(queue).taillock); \
+ if ((queue).tail == NULL && !headlocked) { \
+ UNLOCK(&(queue).taillock); \
+ LOCK(&(queue).headlock); \
+ LOCK(&(queue).taillock); \
+ headlocked = true; \
+ } \
+ (elt)->link.prev = (queue).tail; \
+ (elt)->link.next = NULL; \
+ if ((queue).tail != NULL) \
+ (queue).tail->link.next = (elt); \
+ (queue).tail = (elt); \
+ UNLOCK(&(queue).taillock); \
+ if (headlocked) { \
+ if ((queue).head == NULL) \
+ (queue).head = (elt); \
+ UNLOCK(&(queue).headlock); \
+ } \
+ } while (0)
+
+#define ISC_QUEUE_POP(queue, link, ret) \
+ do { \
+ LOCK(&(queue).headlock); \
+ ret = (queue).head; \
+ while (ret != NULL) { \
+ if (ret->link.next == NULL) { \
+ LOCK(&(queue).taillock); \
+ if (ret->link.next == NULL) { \
+ (queue).head = (queue).tail = NULL; \
+ UNLOCK(&(queue).taillock); \
+ break; \
+ }\
+ UNLOCK(&(queue).taillock); \
+ } \
+ (queue).head = ret->link.next; \
+ (queue).head->link.prev = NULL; \
+ break; \
+ } \
+ UNLOCK(&(queue).headlock); \
+ if (ret != NULL) \
+ (ret)->link.next = (ret)->link.prev = (void *)(-1); \
+ } while(0)
+
+#define ISC_QUEUE_UNLINK(queue, elt, link) \
+ do { \
+ ISC_QLINK_INSIST(ISC_QLINK_LINKED(elt, link)); \
+ LOCK(&(queue).headlock); \
+ LOCK(&(queue).taillock); \
+ if ((elt)->link.prev == NULL) \
+ (queue).head = (elt)->link.next; \
+ else \
+ (elt)->link.prev->link.next = (elt)->link.next; \
+ if ((elt)->link.next == NULL) \
+ (queue).tail = (elt)->link.prev; \
+ else \
+ (elt)->link.next->link.prev = (elt)->link.prev; \
+ UNLOCK(&(queue).taillock); \
+ UNLOCK(&(queue).headlock); \
+ (elt)->link.next = (elt)->link.prev = (void *)(-1); \
+ } while(0)
+
+#endif /* ISC_QUEUE_H */
diff --git a/lib/isc/include/isc/quota.h b/lib/isc/include/isc/quota.h
new file mode 100644
index 0000000..b9bf598
--- /dev/null
+++ b/lib/isc/include/isc/quota.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_QUOTA_H
+#define ISC_QUOTA_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/quota.h
+ *
+ * \brief The isc_quota_t object is a simple helper object for implementing
+ * quotas on things like the number of simultaneous connections to
+ * a server. It keeps track of the amount of quota in use, and
+ * encapsulates the locking necessary to allow multiple tasks to
+ * share a quota.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+/*****
+ ***** Types.
+ *****/
+
+ISC_LANG_BEGINDECLS
+
+/*% isc_quota structure */
+struct isc_quota {
+ isc_mutex_t lock; /*%< Locked by lock. */
+ int max;
+ int used;
+ int soft;
+};
+
+isc_result_t
+isc_quota_init(isc_quota_t *quota, int max);
+/*%<
+ * Initialize a quota object.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * Other error Lock creation failed.
+ */
+
+void
+isc_quota_destroy(isc_quota_t *quota);
+/*%<
+ * Destroy a quota object.
+ */
+
+void
+isc_quota_soft(isc_quota_t *quota, int soft);
+/*%<
+ * Set a soft quota.
+ */
+
+void
+isc_quota_max(isc_quota_t *quota, int max);
+/*%<
+ * Re-set a maximum quota.
+ */
+
+isc_result_t
+isc_quota_reserve(isc_quota_t *quota);
+/*%<
+ * Attempt to reserve one unit of 'quota'.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS Success
+ * \li #ISC_R_SOFTQUOTA Success soft quota reached
+ * \li #ISC_R_QUOTA Quota is full
+ */
+
+void
+isc_quota_release(isc_quota_t *quota);
+/*%<
+ * Release one unit of quota.
+ */
+
+isc_result_t
+isc_quota_attach(isc_quota_t *quota, isc_quota_t **p);
+/*%<
+ * Like isc_quota_reserve, and also attaches '*p' to the
+ * quota if successful (ISC_R_SUCCESS or ISC_R_SOFTQUOTA).
+ */
+
+void
+isc_quota_detach(isc_quota_t **p);
+/*%<
+ * Like isc_quota_release, and also detaches '*p' from the
+ * quota.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_QUOTA_H */
diff --git a/lib/isc/include/isc/radix.h b/lib/isc/include/isc/radix.h
new file mode 100644
index 0000000..135552a
--- /dev/null
+++ b/lib/isc/include/isc/radix.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+
+#include <isc/magic.h>
+#include <isc/types.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/refcount.h>
+
+#include <string.h>
+
+#ifndef _RADIX_H
+#define _RADIX_H
+
+#define NETADDR_TO_PREFIX_T(na,pt,bits,is_ecs) \
+ do { \
+ const void *p = na; \
+ memset(&(pt), 0, sizeof(pt)); \
+ if (p != NULL) { \
+ (pt).family = (na)->family; \
+ (pt).bitlen = (bits); \
+ if ((pt).family == AF_INET6) { \
+ memmove(&(pt).add.sin6, &(na)->type.in6, \
+ ((bits)+7)/8); \
+ } else \
+ memmove(&(pt).add.sin, &(na)->type.in, \
+ ((bits)+7)/8); \
+ } else { \
+ (pt).family = AF_UNSPEC; \
+ (pt).bitlen = 0; \
+ } \
+ (pt).ecs = is_ecs; \
+ isc_refcount_init(&(pt).refcount, 0); \
+ } while(0)
+
+typedef struct isc_prefix {
+ isc_mem_t *mctx;
+ unsigned int family; /* AF_INET | AF_INET6, or AF_UNSPEC for "any" */
+ unsigned int bitlen; /* 0 for "any" */
+ bool ecs; /* true for an EDNS client subnet address */
+ isc_refcount_t refcount;
+ union {
+ struct in_addr sin;
+ struct in6_addr sin6;
+ } add;
+} isc_prefix_t;
+
+typedef void (*isc_radix_destroyfunc_t)(void *);
+typedef void (*isc_radix_processfunc_t)(isc_prefix_t *, void **);
+
+#define isc_prefix_tochar(prefix) ((char *)&(prefix)->add.sin)
+#define isc_prefix_touchar(prefix) ((u_char *)&(prefix)->add.sin)
+
+#define BIT_TEST(f, b) ((f) & (b))
+
+/*
+ * We need "first match" when we search the radix tree to preserve
+ * compatibility with the existing ACL implementation. Radix trees
+ * naturally lend themselves to "best match". In order to get "first match"
+ * behavior, we keep track of the order in which entries are added to the
+ * tree--and when a search is made, we find all matching entries, and
+ * return the one that was added first.
+ *
+ * An IPv4 prefix and an IPv6 prefix may share a radix tree node if they
+ * have the same length and bit pattern (e.g., 127/8 and 7f::/8). Also,
+ * a node that matches a client address may also match an EDNS client
+ * subnet address. To disambiguate between these, node_num and data
+ * are four-element arrays;
+ *
+ * - node_num[0] and data[0] are used for IPv4 client addresses
+ * - node_num[1] and data[1] for IPv4 client subnet addresses
+ * - node_num[2] and data[2] are used for IPv6 client addresses
+ * - node_num[3] and data[3] for IPv6 client subnet addresses
+ *
+ * A prefix of 0/0 (aka "any" or "none"), is always stored as IPv4,
+ * but matches IPv6 addresses too, as well as all client subnet
+ * addresses.
+ */
+
+#define RADIX_NOECS 0
+#define RADIX_ECS 2
+#define RADIX_V4 0
+#define RADIX_V6 1
+#define RADIX_V4_ECS 2
+#define RADIX_V6_ECS 3
+#define RADIX_FAMILIES 4
+
+#define ISC_RADIX_FAMILY(p) \
+ ((((p)->family == AF_INET6) ? RADIX_V6 : RADIX_V4) + \
+ ((p)->ecs ? RADIX_ECS : RADIX_NOECS))
+
+typedef struct isc_radix_node {
+ isc_mem_t *mctx;
+ uint32_t bit; /* bit length of the prefix */
+ isc_prefix_t *prefix; /* who we are in radix tree */
+ struct isc_radix_node *l, *r; /* left and right children */
+ struct isc_radix_node *parent; /* may be used */
+ void *data[RADIX_FAMILIES]; /* pointers to IPv4 and IPV6 data */
+ int node_num[RADIX_FAMILIES]; /* which node this was in the tree,
+ or -1 for glue nodes */
+} isc_radix_node_t;
+
+#define RADIX_TREE_MAGIC ISC_MAGIC('R','d','x','T');
+#define RADIX_TREE_VALID(a) ISC_MAGIC_VALID(a, RADIX_TREE_MAGIC);
+
+typedef struct isc_radix_tree {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_radix_node_t *head;
+ uint32_t maxbits; /* for IP, 32 bit addresses */
+ int num_active_node; /* for debugging purposes */
+ int num_added_node; /* total number of nodes */
+} isc_radix_tree_t;
+
+isc_result_t
+isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target,
+ isc_prefix_t *prefix);
+/*%<
+ * Search 'radix' for the best match to 'prefix'.
+ * Return the node found in '*target'.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'target' is not NULL and "*target" is NULL.
+ * \li 'prefix' to be valid.
+ *
+ * Returns:
+ * \li ISC_R_NOTFOUND
+ * \li ISC_R_SUCCESS
+ */
+
+isc_result_t
+isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
+ isc_radix_node_t *source, isc_prefix_t *prefix);
+/*%<
+ * Insert 'source' or 'prefix' into the radix tree 'radix'.
+ * Return the node added in 'target'.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'target' is not NULL and "*target" is NULL.
+ * \li 'prefix' to be valid or 'source' to be non NULL and contain
+ * a valid prefix.
+ *
+ * Returns:
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_SUCCESS
+ */
+
+void
+isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node);
+/*%<
+ * Remove the node 'node' from the radix tree 'radix'.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'node' to be valid.
+ */
+
+isc_result_t
+isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, int maxbits);
+/*%<
+ * Create a radix tree with a maximum depth of 'maxbits';
+ *
+ * Requires:
+ * \li 'mctx' to be valid.
+ * \li 'target' to be non NULL and '*target' to be NULL.
+ * \li 'maxbits' to be less than or equal to RADIX_MAXBITS.
+ *
+ * Returns:
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_SUCCESS
+ */
+
+void
+isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func);
+/*%<
+ * Destroy a radix tree optionally calling 'func' to clean up node data.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ */
+
+void
+isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func);
+/*%<
+ * Walk a radix tree calling 'func' to process node data.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'func' to point to a function.
+ */
+
+#define RADIX_MAXBITS 128
+#define RADIX_NBIT(x) (0x80 >> ((x) & 0x7f))
+#define RADIX_NBYTE(x) ((x) >> 3)
+
+#define RADIX_WALK(Xhead, Xnode) \
+ do { \
+ isc_radix_node_t *Xstack[RADIX_MAXBITS+1]; \
+ isc_radix_node_t **Xsp = Xstack; \
+ isc_radix_node_t *Xrn = (Xhead); \
+ while ((Xnode = Xrn)) { \
+ if (Xnode->prefix)
+
+#define RADIX_WALK_END \
+ if (Xrn->l) { \
+ if (Xrn->r) { \
+ *Xsp++ = Xrn->r; \
+ } \
+ Xrn = Xrn->l; \
+ } else if (Xrn->r) { \
+ Xrn = Xrn->r; \
+ } else if (Xsp != Xstack) { \
+ Xrn = *(--Xsp); \
+ } else { \
+ Xrn = (isc_radix_node_t *) 0; \
+ } \
+ } \
+ } while (0)
+
+#endif /* _RADIX_H */
diff --git a/lib/isc/include/isc/random.h b/lib/isc/include/isc/random.h
new file mode 100644
index 0000000..f8aed34
--- /dev/null
+++ b/lib/isc/include/isc/random.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id: random.h,v 1.20 2009/01/17 23:47:43 tbox Exp $ */
+
+#ifndef ISC_RANDOM_H
+#define ISC_RANDOM_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+#include <isc/entropy.h>
+#include <isc/mem.h>
+#include <isc/mutex.h>
+
+/*! \file isc/random.h
+ * \brief Implements a random state pool which will let the caller return a
+ * series of possibly non-reproducible random values.
+ *
+ * Note that the
+ * strength of these numbers is not all that high, and should not be
+ * used in cryptography functions. It is useful for jittering values
+ * a bit here and there, such as timeouts, etc.
+ */
+
+ISC_LANG_BEGINDECLS
+
+typedef struct isc_rng isc_rng_t;
+/*%<
+ * Opaque type
+ */
+
+void
+isc_random_seed(uint32_t seed);
+/*%<
+ * Set the initial seed of the random state.
+ */
+
+void
+isc_random_get(uint32_t *val);
+/*%<
+ * Get a random value.
+ *
+ * Requires:
+ * val != NULL.
+ */
+
+uint32_t
+isc_random_jitter(uint32_t max, uint32_t jitter);
+/*%<
+ * Get a random value between (max - jitter) and (max).
+ * This is useful for jittering timer values.
+ */
+
+isc_result_t
+isc_rng_create(isc_mem_t *mctx, isc_entropy_t *entropy, isc_rng_t **rngp);
+/*%<
+ * Creates and initializes a pseudo random number generator. The
+ * returned RNG can be used to generate pseudo random numbers.
+ *
+ * The reference count of the returned RNG is set to 1.
+ *
+ * Requires:
+ * \li mctx is a pointer to a valid memory context.
+ * \li entropy is an optional entopy source (can be NULL)
+ * \li rngp != NULL && *rngp == NULL is where a pointer to the RNG is
+ * returned.
+ *
+ * Ensures:
+ *\li If result is ISC_R_SUCCESS:
+ * *rngp points to a valid RNG.
+ *
+ *\li If result is failure:
+ * *rngp does not point to a valid RNG.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of Memory
+ */
+
+void
+isc_rng_attach(isc_rng_t *source, isc_rng_t **targetp);
+/*%<
+ * Increments a reference count on the passed RNG.
+ *
+ * Requires:
+ * \li source the RNG struct to attach to (is refcount is incremented)
+ * \li targetp != NULL && *targetp == NULL where a pointer to the
+ * reference incremented RNG is returned.
+ */
+
+void
+isc_rng_detach(isc_rng_t **rngp);
+/*%<
+ * Decrements a reference count on the passed RNG. If the reference
+ * count reaches 0, the RNG is destroyed.
+ *
+ * Requires:
+ * \li rngp != NULL the RNG struct to decrement reference for
+ */
+
+uint16_t
+isc_rng_random(isc_rng_t *rngctx);
+/*%<
+ * Returns a pseudo random 16-bit unsigned integer.
+ */
+
+uint16_t
+isc_rng_uniformrandom(isc_rng_t *rngctx, uint16_t upper_bound);
+/*%<
+ * Returns a uniformly distributed pseudo random 16-bit unsigned
+ * integer.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RANDOM_H */
diff --git a/lib/isc/include/isc/ratelimiter.h b/lib/isc/include/isc/ratelimiter.h
new file mode 100644
index 0000000..f6320b2
--- /dev/null
+++ b/lib/isc/include/isc/ratelimiter.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_RATELIMITER_H
+#define ISC_RATELIMITER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/ratelimiter.h
+ * \brief A rate limiter is a mechanism for dispatching events at a limited
+ * rate. This is intended to be used when sending zone maintenance
+ * SOA queries, NOTIFY messages, etc.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Functions.
+ *****/
+
+isc_result_t
+isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
+ isc_task_t *task, isc_ratelimiter_t **ratelimiterp);
+/*%<
+ * Create a rate limiter. The execution interval is initially undefined.
+ */
+
+isc_result_t
+isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval);
+/*!<
+ * Set the minimum interval between event executions.
+ * The interval value is copied, so the caller need not preserve it.
+ *
+ * Requires:
+ * '*interval' is a nonzero interval.
+ */
+
+void
+isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, uint32_t perint);
+/*%<
+ * Set the number of events processed per interval timer tick.
+ * If 'perint' is zero it is treated as 1.
+ */
+
+void
+isc_ratelimiter_setpushpop(isc_ratelimiter_t *rl, bool pushpop);
+/*%<
+ * Set / clear the ratelimiter to from push pop mode rather
+ * first in - first out mode (default).
+ */
+
+isc_result_t
+isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
+ isc_event_t **eventp);
+/*%<
+ * Queue an event for rate-limited execution.
+ *
+ * This is similar
+ * to doing an isc_task_send() to the 'task', except that the
+ * execution may be delayed to achieve the desired rate of
+ * execution.
+ *
+ * '(*eventp)->ev_sender' is used to hold the task. The caller
+ * must ensure that the task exists until the event is delivered.
+ *
+ * Requires:
+ *\li An interval has been set by calling
+ * isc_ratelimiter_setinterval().
+ *
+ *\li 'task' to be non NULL.
+ *\li '(*eventp)->ev_sender' to be NULL.
+ */
+
+isc_result_t
+isc_ratelimiter_dequeue(isc_ratelimiter_t *rl, isc_event_t *event);
+/*
+ * Dequeue a event off the ratelimiter queue.
+ *
+ * Returns:
+ * \li ISC_R_NOTFOUND if the event is no longer linked to the rate limiter.
+ * \li ISC_R_SUCCESS
+ */
+
+void
+isc_ratelimiter_shutdown(isc_ratelimiter_t *ratelimiter);
+/*%<
+ * Shut down a rate limiter.
+ *
+ * Ensures:
+ *\li All events that have not yet been
+ * dispatched to the task are dispatched immediately with
+ * the #ISC_EVENTATTR_CANCELED bit set in ev_attributes.
+ *
+ *\li Further attempts to enqueue events will fail with
+ * #ISC_R_SHUTTINGDOWN.
+ *
+ *\li The rate limiter is no longer attached to its task.
+ */
+
+void
+isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target);
+/*%<
+ * Attach to a rate limiter.
+ */
+
+void
+isc_ratelimiter_detach(isc_ratelimiter_t **ratelimiterp);
+/*%<
+ * Detach from a rate limiter.
+ */
+
+isc_result_t
+isc_ratelimiter_stall(isc_ratelimiter_t *rl);
+/*%<
+ * Stall event processing.
+ */
+
+isc_result_t
+isc_ratelimiter_release(isc_ratelimiter_t *rl);
+/*%<
+ * Release a stalled rate limiter.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RATELIMITER_H */
diff --git a/lib/isc/include/isc/refcount.h b/lib/isc/include/isc/refcount.h
new file mode 100644
index 0000000..c911e5b
--- /dev/null
+++ b/lib/isc/include/isc/refcount.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_REFCOUNT_H
+#define ISC_REFCOUNT_H 1
+
+#include <inttypes.h>
+
+#include <isc/assertions.h>
+#include <isc/atomic.h>
+#include <isc/error.h>
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#if defined(ISC_PLATFORM_HAVESTDATOMIC)
+#if defined (__cplusplus)
+#include <isc/stdatomic.h>
+#else
+#include <stdatomic.h>
+#endif
+#endif
+
+/*! \file isc/refcount.h
+ * \brief Implements a locked reference counter.
+ *
+ * These functions may actually be
+ * implemented using macros, and implementations of these macros are below.
+ * The isc_refcount_t type should not be accessed directly, as its contents
+ * depend on the implementation.
+ */
+
+ISC_LANG_BEGINDECLS
+
+/*
+ * Function prototypes
+ */
+
+/*
+ * isc_result_t
+ * isc_refcount_init(isc_refcount_t *ref, unsigned int n);
+ *
+ * Initialize the reference counter. There will be 'n' initial references.
+ *
+ * Requires:
+ * ref != NULL
+ */
+
+/*
+ * void
+ * isc_refcount_destroy(isc_refcount_t *ref);
+ *
+ * Destroys a reference counter.
+ *
+ * Requires:
+ * ref != NULL
+ * The number of references is 0.
+ */
+
+/*
+ * void
+ * isc_refcount_increment(isc_refcount_t *ref, unsigned int *targetp);
+ * isc_refcount_increment0(isc_refcount_t *ref, unsigned int *targetp);
+ *
+ * Increments the reference count, returning the new value in targetp if it's
+ * not NULL. The reference counter typically begins with the initial counter
+ * of 1, and will be destroyed once the counter reaches 0. Thus,
+ * isc_refcount_increment() additionally requires the previous counter be
+ * larger than 0 so that an error which violates the usage can be easily
+ * caught. isc_refcount_increment0() does not have this restriction.
+ *
+ * Requires:
+ * ref != NULL.
+ */
+
+/*
+ * void
+ * isc_refcount_decrement(isc_refcount_t *ref, unsigned int *targetp);
+ *
+ * Decrements the reference count, returning the new value in targetp if it's
+ * not NULL.
+ *
+ * Requires:
+ * ref != NULL.
+ */
+
+
+/*
+ * Sample implementations
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE)) || defined(ISC_PLATFORM_HAVEXADD)
+#define ISC_REFCOUNT_HAVEATOMIC 1
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE))
+#define ISC_REFCOUNT_HAVESTDATOMIC 1
+#endif
+
+typedef struct isc_refcount {
+#if defined(ISC_REFCOUNT_HAVESTDATOMIC)
+ atomic_int_fast32_t refs;
+#else
+ int32_t refs;
+#endif
+} isc_refcount_t;
+
+#if defined(ISC_REFCOUNT_HAVESTDATOMIC)
+
+#define isc_refcount_current(rp) \
+ ((unsigned int)(atomic_load_explicit(&(rp)->refs, \
+ memory_order_relaxed)))
+#define isc_refcount_destroy(rp) ISC_REQUIRE(isc_refcount_current(rp) == 0)
+
+#define isc_refcount_increment0(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int32_t prev; \
+ prev = atomic_fetch_add_explicit \
+ (&(rp)->refs, 1, memory_order_relaxed); \
+ if (_tmp != NULL) \
+ *_tmp = prev + 1; \
+ } while (0)
+
+#define isc_refcount_increment(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int32_t prev; \
+ prev = atomic_fetch_add_explicit \
+ (&(rp)->refs, 1, memory_order_relaxed); \
+ ISC_REQUIRE(prev > 0); \
+ if (_tmp != NULL) \
+ *_tmp = prev + 1; \
+ } while (0)
+
+#define isc_refcount_decrement(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int32_t prev; \
+ prev = atomic_fetch_sub_explicit \
+ (&(rp)->refs, 1, memory_order_relaxed); \
+ ISC_REQUIRE(prev > 0); \
+ if (_tmp != NULL) \
+ *_tmp = prev - 1; \
+ } while (0)
+
+#else /* ISC_REFCOUNT_HAVESTDATOMIC */
+
+#define isc_refcount_current(rp) \
+ ((unsigned int)(isc_atomic_xadd(&(rp)->refs, 0)))
+#define isc_refcount_destroy(rp) ISC_REQUIRE(isc_refcount_current(rp) == 0)
+
+#define isc_refcount_increment0(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int32_t prev; \
+ prev = isc_atomic_xadd(&(rp)->refs, 1); \
+ if (_tmp != NULL) \
+ *_tmp = prev + 1; \
+ } while (0)
+
+#define isc_refcount_increment(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int32_t prev; \
+ prev = isc_atomic_xadd(&(rp)->refs, 1); \
+ ISC_REQUIRE(prev > 0); \
+ if (_tmp != NULL) \
+ *_tmp = prev + 1; \
+ } while (0)
+
+#define isc_refcount_decrement(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int32_t prev; \
+ prev = isc_atomic_xadd(&(rp)->refs, -1); \
+ ISC_REQUIRE(prev > 0); \
+ if (_tmp != NULL) \
+ *_tmp = prev - 1; \
+ } while (0)
+
+#endif /* ISC_REFCOUNT_HAVESTDATOMIC */
+
+#else /* ISC_PLATFORM_HAVEXADD */
+
+typedef struct isc_refcount {
+ int refs;
+ isc_mutex_t lock;
+} isc_refcount_t;
+
+/*% Destroys a reference counter. */
+#define isc_refcount_destroy(rp) \
+ do { \
+ isc_result_t _result; \
+ ISC_REQUIRE((rp)->refs == 0); \
+ _result = isc_mutex_destroy(&(rp)->lock); \
+ ISC_ERROR_RUNTIMECHECK(_result == ISC_R_SUCCESS); \
+ } while (0)
+
+#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
+
+/*%
+ * Increments the reference count, returning the new value in
+ * 'tp' if it's not NULL.
+ */
+#define isc_refcount_increment0(rp, tp) \
+ do { \
+ isc_result_t _result; \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ _result = isc_mutex_lock(&(rp)->lock); \
+ ISC_ERROR_RUNTIMECHECK(_result == ISC_R_SUCCESS); \
+ ++((rp)->refs); \
+ if (_tmp != NULL) \
+ *_tmp = ((rp)->refs); \
+ _result = isc_mutex_unlock(&(rp)->lock); \
+ ISC_ERROR_RUNTIMECHECK(_result == ISC_R_SUCCESS); \
+ } while (0)
+
+#define isc_refcount_increment(rp, tp) \
+ do { \
+ isc_result_t _result; \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ _result = isc_mutex_lock(&(rp)->lock); \
+ ISC_ERROR_RUNTIMECHECK(_result == ISC_R_SUCCESS); \
+ ISC_REQUIRE((rp)->refs > 0); \
+ ++((rp)->refs); \
+ if (_tmp != NULL) \
+ *_tmp = ((rp)->refs); \
+ _result = isc_mutex_unlock(&(rp)->lock); \
+ ISC_ERROR_RUNTIMECHECK(_result == ISC_R_SUCCESS); \
+ } while (0)
+
+/*%
+ * Decrements the reference count, returning the new value in 'tp'
+ * if it's not NULL.
+ */
+#define isc_refcount_decrement(rp, tp) \
+ do { \
+ isc_result_t _result; \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ _result = isc_mutex_lock(&(rp)->lock); \
+ ISC_ERROR_RUNTIMECHECK(_result == ISC_R_SUCCESS); \
+ ISC_REQUIRE((rp)->refs > 0); \
+ --((rp)->refs); \
+ if (_tmp != NULL) \
+ *_tmp = ((rp)->refs); \
+ _result = isc_mutex_unlock(&(rp)->lock); \
+ ISC_ERROR_RUNTIMECHECK(_result == ISC_R_SUCCESS); \
+ } while (0)
+
+#endif /* (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE)) || defined(ISC_PLATFORM_HAVEXADD) */
+#else /* ISC_PLATFORM_USETHREADS */
+
+typedef struct isc_refcount {
+ int refs;
+} isc_refcount_t;
+
+#define isc_refcount_destroy(rp) ISC_REQUIRE((rp)->refs == 0)
+#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
+
+#define isc_refcount_increment0(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int _n = ++(rp)->refs; \
+ if (_tmp != NULL) \
+ *_tmp = _n; \
+ } while (0)
+
+#define isc_refcount_increment(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int _n; \
+ ISC_REQUIRE((rp)->refs > 0); \
+ _n = ++(rp)->refs; \
+ if (_tmp != NULL) \
+ *_tmp = _n; \
+ } while (0)
+
+#define isc_refcount_decrement(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int _n; \
+ ISC_REQUIRE((rp)->refs > 0); \
+ _n = --(rp)->refs; \
+ if (_tmp != NULL) \
+ *_tmp = _n; \
+ } while (0)
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc_refcount_init(isc_refcount_t *ref, unsigned int n);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_REFCOUNT_H */
diff --git a/lib/isc/include/isc/regex.h b/lib/isc/include/isc/regex.h
new file mode 100644
index 0000000..cab10c1
--- /dev/null
+++ b/lib/isc/include/isc/regex.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_REGEX_H
+#define ISC_REGEX_H 1
+
+/*! \file isc/regex.h */
+
+#include <isc/types.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+int
+isc_regex_validate(const char *expression);
+/*%<
+ * Check a regular expression for syntactic correctness.
+ *
+ * Returns:
+ *\li -1 on error.
+ *\li the number of groups in the expression.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_REGEX_H */
diff --git a/lib/isc/include/isc/region.h b/lib/isc/include/isc/region.h
new file mode 100644
index 0000000..ee01354
--- /dev/null
+++ b/lib/isc/include/isc/region.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_REGION_H
+#define ISC_REGION_H 1
+
+/*! \file isc/region.h */
+
+#include <isc/types.h>
+#include <isc/lang.h>
+
+struct isc_region {
+ unsigned char * base;
+ unsigned int length;
+};
+
+struct isc_textregion {
+ char * base;
+ unsigned int length;
+};
+
+/* XXXDCL questionable ... bears discussion. we have been putting off
+ * discussing the region api.
+ */
+struct isc_constregion {
+ const void * base;
+ unsigned int length;
+};
+
+struct isc_consttextregion {
+ const char * base;
+ unsigned int length;
+};
+
+/*@{*/
+/*!
+ * The region structure is not opaque, and is usually directly manipulated.
+ * Some macros are defined below for convenience.
+ */
+
+#define isc_region_consume(r,l) \
+ do { \
+ isc_region_t *_r = (r); \
+ unsigned int _l = (l); \
+ INSIST(_r->length >= _l); \
+ _r->base += _l; \
+ _r->length -= _l; \
+ } while (0)
+
+#define isc_textregion_consume(r,l) \
+ do { \
+ isc_textregion_t *_r = (r); \
+ unsigned int _l = (l); \
+ INSIST(_r->length >= _l); \
+ _r->base += _l; \
+ _r->length -= _l; \
+ } while (0)
+
+#define isc_constregion_consume(r,l) \
+ do { \
+ isc_constregion_t *_r = (r); \
+ unsigned int _l = (l); \
+ INSIST(_r->length >= _l); \
+ _r->base += _l; \
+ _r->length -= _l; \
+ } while (0)
+/*@}*/
+
+ISC_LANG_BEGINDECLS
+
+int
+isc_region_compare(isc_region_t *r1, isc_region_t *r2);
+/*%<
+ * Compares the contents of two regions
+ *
+ * Requires:
+ *\li 'r1' is a valid region
+ *\li 'r2' is a valid region
+ *
+ * Returns:
+ *\li < 0 if r1 is lexicographically less than r2
+ *\li = 0 if r1 is lexicographically identical to r2
+ *\li > 0 if r1 is lexicographically greater than r2
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_REGION_H */
diff --git a/lib/isc/include/isc/resource.h b/lib/isc/include/isc/resource.h
new file mode 100644
index 0000000..0179234
--- /dev/null
+++ b/lib/isc/include/isc/resource.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_RESOURCE_H
+#define ISC_RESOURCE_H 1
+
+/*! \file isc/resource.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_RESOURCE_UNLIMITED ((isc_resourcevalue_t)UINT64_MAX)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value);
+/*%<
+ * Set the maximum limit for a system resource.
+ *
+ * Notes:
+ *\li If 'value' exceeds the maximum possible on the operating system,
+ * it is silently limited to that maximum -- or to "infinity", if
+ * the operating system has that concept. #ISC_RESOURCE_UNLIMITED
+ * can be used to explicitly ask for the maximum.
+ *
+ * Requires:
+ *\li 'resource' is a valid member of the isc_resource_t enumeration.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS.
+ *\li #ISC_R_NOPERM The calling process did not have adequate permission
+ * to change the resource limit.
+ */
+
+isc_result_t
+isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value);
+/*%<
+ * Get the maximum limit for a system resource.
+ *
+ * Notes:
+ *\li 'value' is set to the maximum limit.
+ *
+ *\li #ISC_RESOURCE_UNLIMITED is the maximum value of isc_resourcevalue_t.
+ *
+ *\li On many (all?) Unix systems, RLIM_INFINITY is a valid value that is
+ * significantly less than #ISC_RESOURCE_UNLIMITED, but which in practice
+ * behaves the same.
+ *
+ *\li The current ISC libdns configuration file parser assigns a value
+ * of UINT32_MAX for a size_spec of "unlimited" and ISC_UNIT32_MAX - 1
+ * for "default", the latter of which is supposed to represent "the
+ * limit that was in force when the server started". Since these are
+ * valid values in the middle of the range of isc_resourcevalue_t,
+ * there is the possibility for confusion over what exactly those
+ * particular values are supposed to represent in a particular context --
+ * discrete integral values or generalized concepts.
+ *
+ * Requires:
+ *\li 'resource' is a valid member of the isc_resource_t enumeration.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS.
+ */
+
+isc_result_t
+isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value);
+/*%<
+ * Same as isc_resource_getlimit(), but returns the current (soft) limit.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RESOURCE_H */
+
diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h
new file mode 100644
index 0000000..246aefb
--- /dev/null
+++ b/lib/isc/include/isc/result.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_RESULT_H
+#define ISC_RESULT_H 1
+
+/*! \file isc/result.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_R_SUCCESS 0 /*%< success */
+#define ISC_R_NOMEMORY 1 /*%< out of memory */
+#define ISC_R_TIMEDOUT 2 /*%< timed out */
+#define ISC_R_NOTHREADS 3 /*%< no available threads */
+#define ISC_R_ADDRNOTAVAIL 4 /*%< address not available */
+#define ISC_R_ADDRINUSE 5 /*%< address in use */
+#define ISC_R_NOPERM 6 /*%< permission denied */
+#define ISC_R_NOCONN 7 /*%< no pending connections */
+#define ISC_R_NETUNREACH 8 /*%< network unreachable */
+#define ISC_R_HOSTUNREACH 9 /*%< host unreachable */
+#define ISC_R_NETDOWN 10 /*%< network down */
+#define ISC_R_HOSTDOWN 11 /*%< host down */
+#define ISC_R_CONNREFUSED 12 /*%< connection refused */
+#define ISC_R_NORESOURCES 13 /*%< not enough free resources */
+#define ISC_R_EOF 14 /*%< end of file */
+#define ISC_R_BOUND 15 /*%< socket already bound */
+#define ISC_R_RELOAD 16 /*%< reload */
+#define ISC_R_SUSPEND ISC_R_RELOAD /*%< alias of 'reload' */
+#define ISC_R_LOCKBUSY 17 /*%< lock busy */
+#define ISC_R_EXISTS 18 /*%< already exists */
+#define ISC_R_NOSPACE 19 /*%< ran out of space */
+#define ISC_R_CANCELED 20 /*%< operation canceled */
+#define ISC_R_NOTBOUND 21 /*%< socket is not bound */
+#define ISC_R_SHUTTINGDOWN 22 /*%< shutting down */
+#define ISC_R_NOTFOUND 23 /*%< not found */
+#define ISC_R_UNEXPECTEDEND 24 /*%< unexpected end of input */
+#define ISC_R_FAILURE 25 /*%< generic failure */
+#define ISC_R_IOERROR 26 /*%< I/O error */
+#define ISC_R_NOTIMPLEMENTED 27 /*%< not implemented */
+#define ISC_R_UNBALANCED 28 /*%< unbalanced parentheses */
+#define ISC_R_NOMORE 29 /*%< no more */
+#define ISC_R_INVALIDFILE 30 /*%< invalid file */
+#define ISC_R_BADBASE64 31 /*%< bad base64 encoding */
+#define ISC_R_UNEXPECTEDTOKEN 32 /*%< unexpected token */
+#define ISC_R_QUOTA 33 /*%< quota reached */
+#define ISC_R_UNEXPECTED 34 /*%< unexpected error */
+#define ISC_R_ALREADYRUNNING 35 /*%< already running */
+#define ISC_R_IGNORE 36 /*%< ignore */
+#define ISC_R_MASKNONCONTIG 37 /*%< addr mask not contiguous */
+#define ISC_R_FILENOTFOUND 38 /*%< file not found */
+#define ISC_R_FILEEXISTS 39 /*%< file already exists */
+#define ISC_R_NOTCONNECTED 40 /*%< socket is not connected */
+#define ISC_R_RANGE 41 /*%< out of range */
+#define ISC_R_NOENTROPY 42 /*%< out of entropy */
+#define ISC_R_MULTICAST 43 /*%< invalid use of multicast */
+#define ISC_R_NOTFILE 44 /*%< not a file */
+#define ISC_R_NOTDIRECTORY 45 /*%< not a directory */
+#define ISC_R_QUEUEFULL 46 /*%< queue is full */
+#define ISC_R_FAMILYMISMATCH 47 /*%< address family mismatch */
+#define ISC_R_FAMILYNOSUPPORT 48 /*%< AF not supported */
+#define ISC_R_BADHEX 49 /*%< bad hex encoding */
+#define ISC_R_TOOMANYOPENFILES 50 /*%< too many open files */
+#define ISC_R_NOTBLOCKING 51 /*%< not blocking */
+#define ISC_R_UNBALANCEDQUOTES 52 /*%< unbalanced quotes */
+#define ISC_R_INPROGRESS 53 /*%< operation in progress */
+#define ISC_R_CONNECTIONRESET 54 /*%< connection reset */
+#define ISC_R_SOFTQUOTA 55 /*%< soft quota reached */
+#define ISC_R_BADNUMBER 56 /*%< not a valid number */
+#define ISC_R_DISABLED 57 /*%< disabled */
+#define ISC_R_MAXSIZE 58 /*%< max size */
+#define ISC_R_BADADDRESSFORM 59 /*%< invalid address format */
+#define ISC_R_BADBASE32 60 /*%< bad base32 encoding */
+#define ISC_R_UNSET 61 /*%< unset */
+#define ISC_R_MULTIPLE 62 /*%< multiple */
+#define ISC_R_WOULDBLOCK 63 /*%< would block */
+
+/*% Not a result code: the number of results. */
+#define ISC_R_NRESULTS 64
+
+ISC_LANG_BEGINDECLS
+
+const char *
+isc_result_totext(isc_result_t);
+/*%<
+ * Convert an isc_result_t into a string message describing the result.
+ */
+
+const char *
+isc_result_toid(isc_result_t);
+/*%<
+ * Convert an isc_result_t into a string identifier such as
+ * "ISC_R_SUCCESS".
+ */
+
+isc_result_t
+isc_result_register(unsigned int base, unsigned int nresults,
+ const char **text, isc_msgcat_t *msgcat, int set);
+
+isc_result_t
+isc_result_registerids(unsigned int base, unsigned int nresults,
+ const char **ids, isc_msgcat_t *msgcat, int set);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RESULT_H */
diff --git a/lib/isc/include/isc/resultclass.h b/lib/isc/include/isc/resultclass.h
new file mode 100644
index 0000000..08135f4
--- /dev/null
+++ b/lib/isc/include/isc/resultclass.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_RESULTCLASS_H
+#define ISC_RESULTCLASS_H 1
+
+
+/*! \file isc/resultclass.h
+ * \brief Registry of Predefined Result Type Classes
+ *
+ * A result class number is an unsigned 16 bit number. Each class may
+ * contain up to 65536 results. A result code is formed by adding the
+ * result number within the class to the class number multiplied by 65536.
+ *
+ * Classes < 1024 are reserved for ISC use.
+ * Result classes >= 1024 and <= 65535 are reserved for application use.
+ */
+
+#define ISC_RESULTCLASS_FROMNUM(num) ((num) << 16)
+#define ISC_RESULTCLASS_TONUM(rclass) ((rclass) >> 16)
+#define ISC_RESULTCLASS_SIZE 65536
+#define ISC_RESULTCLASS_INCLASS(rclass, result) \
+ ((rclass) == ((result) & 0xFFFF0000))
+
+
+#define ISC_RESULTCLASS_ISC ISC_RESULTCLASS_FROMNUM(0)
+#define ISC_RESULTCLASS_DNS ISC_RESULTCLASS_FROMNUM(1)
+#define ISC_RESULTCLASS_DST ISC_RESULTCLASS_FROMNUM(2)
+#define ISC_RESULTCLASS_DNSRCODE ISC_RESULTCLASS_FROMNUM(3)
+#define ISC_RESULTCLASS_OMAPI ISC_RESULTCLASS_FROMNUM(4)
+#define ISC_RESULTCLASS_ISCCC ISC_RESULTCLASS_FROMNUM(5)
+#define ISC_RESULTCLASS_DHCP ISC_RESULTCLASS_FROMNUM(6)
+#define ISC_RESULTCLASS_PK11 ISC_RESULTCLASS_FROMNUM(7)
+
+#endif /* ISC_RESULTCLASS_H */
diff --git a/lib/isc/include/isc/rwlock.h b/lib/isc/include/isc/rwlock.h
new file mode 100644
index 0000000..b957509
--- /dev/null
+++ b/lib/isc/include/isc/rwlock.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_RWLOCK_H
+#define ISC_RWLOCK_H 1
+
+#include <inttypes.h>
+
+/*! \file isc/rwlock.h */
+
+#include <isc/condition.h>
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#if defined(ISC_PLATFORM_HAVESTDATOMIC)
+#if defined(__cplusplus)
+#include <isc/stdatomic.h>
+#else
+#include <stdatomic.h>
+#endif
+#endif
+
+ISC_LANG_BEGINDECLS
+
+typedef enum {
+ isc_rwlocktype_none = 0,
+ isc_rwlocktype_read,
+ isc_rwlocktype_write
+} isc_rwlocktype_t;
+
+#ifdef ISC_PLATFORM_USETHREADS
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE)) || (defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG))
+#define ISC_RWLOCK_USEATOMIC 1
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE))
+#define ISC_RWLOCK_USESTDATOMIC 1
+#endif
+#endif
+
+struct isc_rwlock {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mutex_t lock;
+ int32_t spins;
+
+#if defined(ISC_RWLOCK_USEATOMIC)
+ /*
+ * When some atomic instructions with hardware assistance are
+ * available, rwlock will use those so that concurrent readers do not
+ * interfere with each other through mutex as long as no writers
+ * appear, massively reducing the lock overhead in the typical case.
+ *
+ * The basic algorithm of this approach is the "simple
+ * writer-preference lock" shown in the following URL:
+ * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
+ * but our implementation does not rely on the spin lock unlike the
+ * original algorithm to be more portable as a user space application.
+ */
+
+ /* Read or modified atomically. */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ atomic_int_fast32_t write_requests;
+ atomic_int_fast32_t write_completions;
+ atomic_int_fast32_t cnt_and_flag;
+#else
+ int32_t write_requests;
+ int32_t write_completions;
+ int32_t cnt_and_flag;
+#endif
+
+ /* Locked by lock. */
+ isc_condition_t readable;
+ isc_condition_t writeable;
+ unsigned int readers_waiting;
+
+ /* Locked by rwlock itself. */
+ unsigned int write_granted;
+
+ /* Unlocked. */
+ unsigned int write_quota;
+
+#else /* ISC_RWLOCK_USEATOMIC */
+
+ /*%< Locked by lock. */
+ isc_condition_t readable;
+ isc_condition_t writeable;
+ isc_rwlocktype_t type;
+
+ /*% The number of threads that have the lock. */
+ unsigned int active;
+
+ /*%
+ * The number of lock grants made since the lock was last switched
+ * from reading to writing or vice versa; used in determining
+ * when the quota is reached and it is time to switch.
+ */
+ unsigned int granted;
+
+ unsigned int readers_waiting;
+ unsigned int writers_waiting;
+ unsigned int read_quota;
+ unsigned int write_quota;
+ isc_rwlocktype_t original;
+#endif /* ISC_RWLOCK_USEATOMIC */
+};
+#else /* ISC_PLATFORM_USETHREADS */
+struct isc_rwlock {
+ unsigned int magic;
+ isc_rwlocktype_t type;
+ unsigned int active;
+};
+#endif /* ISC_PLATFORM_USETHREADS */
+
+
+isc_result_t
+isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
+ unsigned int write_quota);
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl);
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl);
+
+void
+isc_rwlock_destroy(isc_rwlock_t *rwl);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RWLOCK_H */
diff --git a/lib/isc/include/isc/safe.h b/lib/isc/include/isc/safe.h
new file mode 100644
index 0000000..66ed08b
--- /dev/null
+++ b/lib/isc/include/isc/safe.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_SAFE_H
+#define ISC_SAFE_H 1
+
+/*! \file isc/safe.h */
+
+#include <stdbool.h>
+
+#include <isc/types.h>
+#include <stdlib.h>
+
+ISC_LANG_BEGINDECLS
+
+bool
+isc_safe_memequal(const void *s1, const void *s2, size_t n);
+/*%<
+ * Returns true iff. two blocks of memory are equal, otherwise
+ * false.
+ *
+ */
+
+int
+isc_safe_memcompare(const void *b1, const void *b2, size_t len);
+/*%<
+ * Clone of libc memcmp() which is safe to differential timing attacks.
+ */
+
+void
+isc_safe_memwipe(void *ptr, size_t len);
+/*%<
+ * Clear the memory of length `len` pointed to by `ptr`.
+ *
+ * Some crypto code calls memset() on stack allocated buffers just
+ * before return so that they are wiped. Such memset() calls can be
+ * optimized away by the compiler. We provide this external non-inline C
+ * function to perform the memset operation so that the compiler cannot
+ * infer about what the function does and optimize the call away.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SAFE_H */
diff --git a/lib/isc/include/isc/serial.h b/lib/isc/include/isc/serial.h
new file mode 100644
index 0000000..2c6923f
--- /dev/null
+++ b/lib/isc/include/isc/serial.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_SERIAL_H
+#define ISC_SERIAL_H 1
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file isc/serial.h
+ * \brief Implement 32 bit serial space arithmetic comparison functions.
+ * Note: Undefined results are returned as false.
+ */
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+bool
+isc_serial_lt(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' < 'b' otherwise false.
+ */
+
+bool
+isc_serial_gt(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' > 'b' otherwise false.
+ */
+
+bool
+isc_serial_le(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' <= 'b' otherwise false.
+ */
+
+bool
+isc_serial_ge(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' >= 'b' otherwise false.
+ */
+
+bool
+isc_serial_eq(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' == 'b' otherwise false.
+ */
+
+bool
+isc_serial_ne(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' != 'b' otherwise false.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SERIAL_H */
diff --git a/lib/isc/include/isc/sha1.h b/lib/isc/include/isc/sha1.h
new file mode 100644
index 0000000..02bca12
--- /dev/null
+++ b/lib/isc/include/isc/sha1.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_SHA1_H
+#define ISC_SHA1_H 1
+
+/* $NetBSD: sha1.h,v 1.2 1998/05/29 22:55:44 thorpej Exp $ */
+
+/*! \file isc/sha1.h
+ * \brief SHA-1 in C
+ * \author By Steve Reid <steve@edmweb.com>
+ * \note 100% Public Domain
+ */
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#define ISC_SHA1_DIGESTLENGTH 20U
+#define ISC_SHA1_BLOCK_LENGTH 64U
+
+#ifdef ISC_PLATFORM_OPENSSLHASH
+#include <openssl/opensslv.h>
+#include <openssl/evp.h>
+
+typedef struct {
+ EVP_MD_CTX *ctx;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ EVP_MD_CTX _ctx;
+#endif
+} isc_sha1_t;
+
+#elif PKCS11CRYPTO
+#include <pk11/pk11.h>
+
+typedef pk11_context_t isc_sha1_t;
+
+#else
+
+typedef struct {
+ uint32_t state[5];
+ uint32_t count[2];
+ unsigned char buffer[ISC_SHA1_BLOCK_LENGTH];
+} isc_sha1_t;
+#endif
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_sha1_init(isc_sha1_t *ctx);
+
+void
+isc_sha1_invalidate(isc_sha1_t *ctx);
+
+void
+isc_sha1_update(isc_sha1_t *ctx, const unsigned char *data, unsigned int len);
+
+void
+isc_sha1_final(isc_sha1_t *ctx, unsigned char *digest);
+
+bool
+isc_sha1_check(bool testing);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SHA1_H */
diff --git a/lib/isc/include/isc/sha2.h b/lib/isc/include/isc/sha2.h
new file mode 100644
index 0000000..f9e1be3
--- /dev/null
+++ b/lib/isc/include/isc/sha2.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/* $FreeBSD: src/sys/crypto/sha2/sha2.h,v 1.1.2.1 2001/07/03 11:01:36 ume Exp $ */
+/* $KAME: sha2.h,v 1.3 2001/03/12 08:27:48 itojun Exp $ */
+
+/*
+ * sha2.h
+ *
+ * Version 1.0.0beta1
+ *
+ * Written by Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright 2000 Aaron D. Gifford. 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. Neither the name of the copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``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(S) OR CONTRIBUTOR(S) 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 ISC_SHA2_H
+#define ISC_SHA2_H
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+/*** SHA-224/256/384/512 Various Length Definitions ***********************/
+
+#define ISC_SHA224_BLOCK_LENGTH 64U
+#define ISC_SHA224_DIGESTLENGTH 28U
+#define ISC_SHA224_DIGESTSTRINGLENGTH (ISC_SHA224_DIGESTLENGTH * 2 + 1)
+#define ISC_SHA256_BLOCK_LENGTH 64U
+#define ISC_SHA256_DIGESTLENGTH 32U
+#define ISC_SHA256_DIGESTSTRINGLENGTH (ISC_SHA256_DIGESTLENGTH * 2 + 1)
+#define ISC_SHA384_BLOCK_LENGTH 128
+#define ISC_SHA384_DIGESTLENGTH 48U
+#define ISC_SHA384_DIGESTSTRINGLENGTH (ISC_SHA384_DIGESTLENGTH * 2 + 1)
+#define ISC_SHA512_BLOCK_LENGTH 128U
+#define ISC_SHA512_DIGESTLENGTH 64U
+#define ISC_SHA512_DIGESTSTRINGLENGTH (ISC_SHA512_DIGESTLENGTH * 2 + 1)
+
+/*** SHA-256/384/512 Context Structures *******************************/
+
+#if defined(ISC_PLATFORM_OPENSSLHASH)
+#include <openssl/opensslv.h>
+#include <openssl/evp.h>
+#endif
+
+#if defined(ISC_PLATFORM_OPENSSLHASH) && !defined(LIBRESSL_VERSION_NUMBER)
+
+
+typedef struct {
+ EVP_MD_CTX *ctx;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ EVP_MD_CTX _ctx;
+#endif
+} isc_sha2_t;
+
+typedef isc_sha2_t isc_sha256_t;
+typedef isc_sha2_t isc_sha512_t;
+
+#elif PKCS11CRYPTO
+#include <pk11/pk11.h>
+
+typedef pk11_context_t isc_sha256_t;
+typedef pk11_context_t isc_sha512_t;
+
+#else
+
+/*
+ * Keep buffer immediately after bitcount to preserve alignment.
+ */
+typedef struct {
+ uint32_t state[8];
+ uint64_t bitcount;
+ uint8_t buffer[ISC_SHA256_BLOCK_LENGTH];
+} isc_sha256_t;
+
+/*
+ * Keep buffer immediately after bitcount to preserve alignment.
+ */
+typedef struct {
+ uint64_t state[8];
+ uint64_t bitcount[2];
+ uint8_t buffer[ISC_SHA512_BLOCK_LENGTH];
+} isc_sha512_t;
+#endif
+
+typedef isc_sha256_t isc_sha224_t;
+typedef isc_sha512_t isc_sha384_t;
+
+ISC_LANG_BEGINDECLS
+
+/*** SHA-224/256/384/512 Function Prototypes ******************************/
+
+void isc_sha224_init (isc_sha224_t *);
+void isc_sha224_invalidate (isc_sha224_t *);
+void isc_sha224_update (isc_sha224_t *, const uint8_t *, size_t);
+void isc_sha224_final (uint8_t[ISC_SHA224_DIGESTLENGTH], isc_sha224_t *);
+char *isc_sha224_end (isc_sha224_t *, char[ISC_SHA224_DIGESTSTRINGLENGTH]);
+char *isc_sha224_data (const uint8_t *, size_t, char[ISC_SHA224_DIGESTSTRINGLENGTH]);
+
+void isc_sha256_init (isc_sha256_t *);
+void isc_sha256_invalidate (isc_sha256_t *);
+void isc_sha256_update (isc_sha256_t *, const uint8_t *, size_t);
+void isc_sha256_final (uint8_t[ISC_SHA256_DIGESTLENGTH], isc_sha256_t *);
+char *isc_sha256_end (isc_sha256_t *, char[ISC_SHA256_DIGESTSTRINGLENGTH]);
+char *isc_sha256_data (const uint8_t *, size_t, char[ISC_SHA256_DIGESTSTRINGLENGTH]);
+
+void isc_sha384_init (isc_sha384_t *);
+void isc_sha384_invalidate (isc_sha384_t *);
+void isc_sha384_update (isc_sha384_t *, const uint8_t *, size_t);
+void isc_sha384_final (uint8_t[ISC_SHA384_DIGESTLENGTH], isc_sha384_t *);
+char *isc_sha384_end (isc_sha384_t *, char[ISC_SHA384_DIGESTSTRINGLENGTH]);
+char *isc_sha384_data (const uint8_t *, size_t, char[ISC_SHA384_DIGESTSTRINGLENGTH]);
+
+void isc_sha512_init (isc_sha512_t *);
+void isc_sha512_invalidate (isc_sha512_t *);
+void isc_sha512_update (isc_sha512_t *, const uint8_t *, size_t);
+void isc_sha512_final (uint8_t[ISC_SHA512_DIGESTLENGTH], isc_sha512_t *);
+char *isc_sha512_end (isc_sha512_t *, char[ISC_SHA512_DIGESTSTRINGLENGTH]);
+char *isc_sha512_data (const uint8_t *, size_t, char[ISC_SHA512_DIGESTSTRINGLENGTH]);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SHA2_H */
diff --git a/lib/isc/include/isc/sockaddr.h b/lib/isc/include/isc/sockaddr.h
new file mode 100644
index 0000000..478e77c
--- /dev/null
+++ b/lib/isc/include/isc/sockaddr.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_SOCKADDR_H
+#define ISC_SOCKADDR_H 1
+
+/*! \file isc/sockaddr.h */
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/net.h>
+#include <isc/types.h>
+#ifdef ISC_PLATFORM_HAVESYSUNH
+#include <sys/un.h>
+#endif
+
+struct isc_sockaddr {
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr_storage ss;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ struct sockaddr_un sunix;
+#endif
+ } type;
+ unsigned int length; /* XXXRTH beginning? */
+ ISC_LINK(struct isc_sockaddr) link;
+};
+
+#define ISC_SOCKADDR_CMPADDR 0x0001 /*%< compare the address
+ * sin_addr/sin6_addr */
+#define ISC_SOCKADDR_CMPPORT 0x0002 /*%< compare the port
+ * sin_port/sin6_port */
+#define ISC_SOCKADDR_CMPSCOPE 0x0004 /*%< compare the scope
+ * sin6_scope */
+#define ISC_SOCKADDR_CMPSCOPEZERO 0x0008 /*%< when comparing scopes
+ * zero scopes always match */
+
+ISC_LANG_BEGINDECLS
+
+bool
+isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+ unsigned int flags);
+/*%<
+ * Compare the elements of the two address ('a' and 'b') as specified
+ * by 'flags' and report if they are equal or not.
+ *
+ * 'flags' is set from ISC_SOCKADDR_CMP*.
+ */
+
+bool
+isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b);
+/*%<
+ * Return true iff the socket addresses 'a' and 'b' are equal.
+ */
+
+bool
+isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b);
+/*%<
+ * Return true iff the address parts of the socket addresses
+ * 'a' and 'b' are equal, ignoring the ports.
+ */
+
+bool
+isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+ unsigned int prefixlen);
+/*%<
+ * Return true iff the most significant 'prefixlen' bits of the
+ * socket addresses 'a' and 'b' are equal, ignoring the ports.
+ * If 'b''s scope is zero then 'a''s scope will be ignored.
+ */
+
+unsigned int
+isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, bool address_only);
+/*%<
+ * Return a hash value for the socket address 'sockaddr'. If 'address_only'
+ * is true, the hash value will not depend on the port.
+ *
+ * IPv6 addresses containing mapped IPv4 addresses generate the same hash
+ * value as the equivalent IPv4 address.
+ */
+
+void
+isc_sockaddr_any(isc_sockaddr_t *sockaddr);
+/*%<
+ * Return the IPv4 wildcard address.
+ */
+
+void
+isc_sockaddr_any6(isc_sockaddr_t *sockaddr);
+/*%<
+ * Return the IPv6 wildcard address.
+ */
+
+void
+isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int family);
+/*%<
+ * Set '*sockaddr' to the wildcard address of protocol family
+ * 'family'.
+ *
+ * Requires:
+ * \li 'family' is AF_INET or AF_INET6.
+ */
+
+void
+isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
+ in_port_t port);
+/*%<
+ * Construct an isc_sockaddr_t from an IPv4 address and port.
+ */
+
+void
+isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
+ in_port_t port);
+/*%<
+ * Construct an isc_sockaddr_t from an IPv6 address and port.
+ */
+
+void
+isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
+ in_port_t port);
+/*%<
+ * Construct an IPv6 isc_sockaddr_t representing a mapped IPv4 address.
+ */
+
+void
+isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
+ in_port_t port);
+/*%<
+ * Construct an isc_sockaddr_t from an isc_netaddr_t and port.
+ */
+
+int
+isc_sockaddr_pf(const isc_sockaddr_t *sockaddr);
+/*%<
+ * Get the protocol family of 'sockaddr'.
+ *
+ * Requires:
+ *
+ *\li 'sockaddr' is a valid sockaddr with an address family of AF_INET
+ * or AF_INET6.
+ *
+ * Returns:
+ *
+ *\li The protocol family of 'sockaddr', e.g. PF_INET or PF_INET6.
+ */
+
+void
+isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port);
+/*%<
+ * Set the port of 'sockaddr' to 'port'.
+ */
+
+in_port_t
+isc_sockaddr_getport(const isc_sockaddr_t *sockaddr);
+/*%<
+ * Get the port stored in 'sockaddr'.
+ */
+
+isc_result_t
+isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target);
+/*%<
+ * Append a text representation of 'sockaddr' to the buffer 'target'.
+ * The text will include both the IP address (v4 or v6) and the port.
+ * The text is null terminated, but the terminating null is not
+ * part of the buffer's used region.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOSPACE The text or the null termination did not fit.
+ */
+
+void
+isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size);
+/*%<
+ * Format a human-readable representation of the socket address '*sa'
+ * into the character array 'array', which is of size 'size'.
+ * The resulting string is guaranteed to be null-terminated.
+ */
+
+bool
+isc_sockaddr_ismulticast(const isc_sockaddr_t *sa);
+/*%<
+ * Returns #true if the address is a multicast address.
+ */
+
+bool
+isc_sockaddr_isexperimental(const isc_sockaddr_t *sa);
+/*
+ * Returns true if the address is a experimental (CLASS E) address.
+ */
+
+bool
+isc_sockaddr_islinklocal(const isc_sockaddr_t *sa);
+/*%<
+ * Returns true if the address is a link local address.
+ */
+
+bool
+isc_sockaddr_issitelocal(const isc_sockaddr_t *sa);
+/*%<
+ * Returns true if the address is a sitelocal address.
+ */
+
+bool
+isc_sockaddr_isnetzero(const isc_sockaddr_t *sa);
+/*%<
+ * Returns true if the address is in net zero.
+ */
+
+isc_result_t
+isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path);
+/*
+ * Create a UNIX domain sockaddr that refers to path.
+ *
+ * Returns:
+ * \li ISC_R_NOSPACE
+ * \li ISC_R_NOTIMPLEMENTED
+ * \li ISC_R_SUCCESS
+ */
+
+#define ISC_SOCKADDR_FORMATSIZE \
+ sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS#YYYYY")
+/*%<
+ * Minimum size of array to pass to isc_sockaddr_format().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SOCKADDR_H */
diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h
new file mode 100644
index 0000000..574de2a
--- /dev/null
+++ b/lib/isc/include/isc/socket.h
@@ -0,0 +1,1272 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_SOCKET_H
+#define ISC_SOCKET_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/socket.h
+ * \brief Provides TCP and UDP sockets for network I/O. The sockets are event
+ * sources in the task system.
+ *
+ * When I/O completes, a completion event for the socket is posted to the
+ * event queue of the task which requested the I/O.
+ *
+ * \li MP:
+ * The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ * Clients of this module must not be holding a socket's task's lock when
+ * making a call that affects that socket. Failure to follow this rule
+ * can result in deadlock.
+ * The caller must ensure that isc_socketmgr_destroy() is called only
+ * once for a given manager.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/event.h>
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+#include <isc/json.h>
+#include <isc/region.h>
+#include <isc/sockaddr.h>
+#include <isc/time.h>
+#include <isc/types.h>
+#include <isc/xml.h>
+
+#ifdef WIN32
+
+/* from the old namespace.h */
+
+#define isc_socket_create isc__socket_create
+#define isc_socket_dup isc__socket_dup
+#define isc_socket_attach isc__socket_attach
+#define isc_socket_detach isc__socket_detach
+#define isc_socketmgr_create isc__socketmgr_create
+#define isc_socketmgr_create2 isc__socketmgr_create2
+#define isc_socketmgr_destroy isc__socketmgr_destroy
+#define isc_socket_open isc__socket_open
+#define isc_socket_close isc__socket_close
+#define isc_socket_recvv isc__socket_recvv
+#define isc_socket_recv isc__socket_recv
+#define isc_socket_recv2 isc__socket_recv2
+#define isc_socket_send isc__socket_send
+#define isc_socket_sendto isc__socket_sendto
+#define isc_socket_sendv isc__socket_sendv
+#define isc_socket_sendtov isc__socket_sendtov
+#define isc_socket_sendtov2 isc__socket_sendtov2
+#define isc_socket_sendto2 isc__socket_sendto2
+#define isc_socket_cleanunix isc__socket_cleanunix
+#define isc_socket_permunix isc__socket_permunix
+#define isc_socket_bind isc__socket_bind
+#define isc_socket_filter isc__socket_filter
+#define isc_socket_listen isc__socket_listen
+#define isc_socket_accept isc__socket_accept
+#define isc_socket_connect isc__socket_connect
+#define isc_socket_getfd isc__socket_getfd
+#define isc_socket_getname isc__socket_getname
+#define isc_socket_gettag isc__socket_gettag
+#define isc_socket_getpeername isc__socket_getpeername
+#define isc_socket_getsockname isc__socket_getsockname
+#define isc_socket_cancel isc__socket_cancel
+#define isc_socket_gettype isc__socket_gettype
+#define isc_socket_isbound isc__socket_isbound
+#define isc_socket_ipv6only isc__socket_ipv6only
+#define isc_socket_setname isc__socket_setname
+#define isc_socketmgr_getmaxsockets isc__socketmgr_getmaxsockets
+#define isc_socketmgr_setstats isc__socketmgr_setstats
+#define isc_socketmgr_setreserved isc__socketmgr_setreserved
+#define isc__socketmgr_maxudp isc___socketmgr_maxudp
+#define isc_socket_fdwatchcreate isc__socket_fdwatchcreate
+#define isc_socket_fdwatchpoke isc__socket_fdwatchpoke
+#define isc_socket_dscp isc__socket_dscp
+
+#endif
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Constants
+ ***/
+
+/*%
+ * Maximum number of buffers in a scatter/gather read/write. The operating
+ * system in use must support at least this number (plus one on some.)
+ */
+#define ISC_SOCKET_MAXSCATTERGATHER 8
+
+/*%
+ * In isc_socket_bind() set socket option SO_REUSEADDR prior to calling
+ * bind() if a non zero port is specified (AF_INET and AF_INET6).
+ */
+#define ISC_SOCKET_REUSEADDRESS 0x01U
+
+/*%
+ * Statistics counters. Used as isc_statscounter_t values.
+ */
+enum {
+ isc_sockstatscounter_udp4open = 0,
+ isc_sockstatscounter_udp6open = 1,
+ isc_sockstatscounter_tcp4open = 2,
+ isc_sockstatscounter_tcp6open = 3,
+ isc_sockstatscounter_unixopen = 4,
+
+ isc_sockstatscounter_udp4openfail = 5,
+ isc_sockstatscounter_udp6openfail = 6,
+ isc_sockstatscounter_tcp4openfail = 7,
+ isc_sockstatscounter_tcp6openfail = 8,
+ isc_sockstatscounter_unixopenfail = 9,
+
+ isc_sockstatscounter_udp4close = 10,
+ isc_sockstatscounter_udp6close = 11,
+ isc_sockstatscounter_tcp4close = 12,
+ isc_sockstatscounter_tcp6close = 13,
+ isc_sockstatscounter_unixclose = 14,
+ isc_sockstatscounter_fdwatchclose = 15,
+
+ isc_sockstatscounter_udp4bindfail = 16,
+ isc_sockstatscounter_udp6bindfail = 17,
+ isc_sockstatscounter_tcp4bindfail = 18,
+ isc_sockstatscounter_tcp6bindfail = 19,
+ isc_sockstatscounter_unixbindfail = 20,
+ isc_sockstatscounter_fdwatchbindfail = 21,
+
+ isc_sockstatscounter_udp4connect = 22,
+ isc_sockstatscounter_udp6connect = 23,
+ isc_sockstatscounter_tcp4connect = 24,
+ isc_sockstatscounter_tcp6connect = 25,
+ isc_sockstatscounter_unixconnect = 26,
+ isc_sockstatscounter_fdwatchconnect = 27,
+
+ isc_sockstatscounter_udp4connectfail = 28,
+ isc_sockstatscounter_udp6connectfail = 29,
+ isc_sockstatscounter_tcp4connectfail = 30,
+ isc_sockstatscounter_tcp6connectfail = 31,
+ isc_sockstatscounter_unixconnectfail = 32,
+ isc_sockstatscounter_fdwatchconnectfail = 33,
+
+ isc_sockstatscounter_tcp4accept = 34,
+ isc_sockstatscounter_tcp6accept = 35,
+ isc_sockstatscounter_unixaccept = 36,
+
+ isc_sockstatscounter_tcp4acceptfail = 37,
+ isc_sockstatscounter_tcp6acceptfail = 38,
+ isc_sockstatscounter_unixacceptfail = 39,
+
+ isc_sockstatscounter_udp4sendfail = 40,
+ isc_sockstatscounter_udp6sendfail = 41,
+ isc_sockstatscounter_tcp4sendfail = 42,
+ isc_sockstatscounter_tcp6sendfail = 43,
+ isc_sockstatscounter_unixsendfail = 44,
+ isc_sockstatscounter_fdwatchsendfail = 45,
+
+ isc_sockstatscounter_udp4recvfail = 46,
+ isc_sockstatscounter_udp6recvfail = 47,
+ isc_sockstatscounter_tcp4recvfail = 48,
+ isc_sockstatscounter_tcp6recvfail = 49,
+ isc_sockstatscounter_unixrecvfail = 50,
+ isc_sockstatscounter_fdwatchrecvfail = 51,
+
+ isc_sockstatscounter_udp4active = 52,
+ isc_sockstatscounter_udp6active = 53,
+ isc_sockstatscounter_tcp4active = 54,
+ isc_sockstatscounter_tcp6active = 55,
+ isc_sockstatscounter_unixactive = 56,
+
+ isc_sockstatscounter_rawopen = 57,
+ isc_sockstatscounter_rawopenfail = 58,
+ isc_sockstatscounter_rawclose = 59,
+ isc_sockstatscounter_rawrecvfail = 60,
+ isc_sockstatscounter_rawactive = 61,
+
+ isc_sockstatscounter_max = 62
+};
+
+/***
+ *** Types
+ ***/
+
+struct isc_socketevent {
+ ISC_EVENT_COMMON(isc_socketevent_t);
+ isc_result_t result; /*%< OK, EOF, whatever else */
+ unsigned int minimum; /*%< minimum i/o for event */
+ unsigned int n; /*%< bytes read or written */
+ unsigned int offset; /*%< offset into buffer list */
+ isc_region_t region; /*%< for single-buffer i/o */
+ isc_bufferlist_t bufferlist; /*%< list of buffers */
+ isc_sockaddr_t address; /*%< source address */
+ isc_time_t timestamp; /*%< timestamp of packet recv */
+ struct in6_pktinfo pktinfo; /*%< ipv6 pktinfo */
+ uint32_t attributes; /*%< see below */
+ isc_eventdestructor_t destroy; /*%< original destructor */
+ unsigned int dscp; /*%< UDP dscp value */
+};
+
+typedef struct isc_socket_newconnev isc_socket_newconnev_t;
+struct isc_socket_newconnev {
+ ISC_EVENT_COMMON(isc_socket_newconnev_t);
+ isc_socket_t * newsocket;
+ isc_result_t result; /*%< OK, EOF, whatever else */
+ isc_sockaddr_t address; /*%< source address */
+};
+
+typedef struct isc_socket_connev isc_socket_connev_t;
+struct isc_socket_connev {
+ ISC_EVENT_COMMON(isc_socket_connev_t);
+ isc_result_t result; /*%< OK, EOF, whatever else */
+};
+
+/*@{*/
+/*!
+ * _ATTACHED: Internal use only.
+ * _TRUNC: Packet was truncated on receive.
+ * _CTRUNC: Packet control information was truncated. This can
+ * indicate that the packet is not complete, even though
+ * all the data is valid.
+ * _TIMESTAMP: The timestamp member is valid.
+ * _PKTINFO: The pktinfo member is valid.
+ * _MULTICAST: The UDP packet was received via a multicast transmission.
+ * _DSCP: The UDP DSCP value is valid.
+ * _USEMINMTU: Set the per packet IPV6_USE_MIN_MTU flag.
+ */
+#define ISC_SOCKEVENTATTR_ATTACHED 0x10000000U /* internal */
+#define ISC_SOCKEVENTATTR_TRUNC 0x00800000U /* public */
+#define ISC_SOCKEVENTATTR_CTRUNC 0x00400000U /* public */
+#define ISC_SOCKEVENTATTR_TIMESTAMP 0x00200000U /* public */
+#define ISC_SOCKEVENTATTR_PKTINFO 0x00100000U /* public */
+#define ISC_SOCKEVENTATTR_MULTICAST 0x00080000U /* public */
+#define ISC_SOCKEVENTATTR_DSCP 0x00040000U /* public */
+#define ISC_SOCKEVENTATTR_USEMINMTU 0x00020000U /* public */
+/*@}*/
+
+#define ISC_SOCKEVENT_ANYEVENT (0)
+#define ISC_SOCKEVENT_RECVDONE (ISC_EVENTCLASS_SOCKET + 1)
+#define ISC_SOCKEVENT_SENDDONE (ISC_EVENTCLASS_SOCKET + 2)
+#define ISC_SOCKEVENT_NEWCONN (ISC_EVENTCLASS_SOCKET + 3)
+#define ISC_SOCKEVENT_CONNECT (ISC_EVENTCLASS_SOCKET + 4)
+
+/*
+ * Internal events.
+ */
+#define ISC_SOCKEVENT_INTR (ISC_EVENTCLASS_SOCKET + 256)
+#define ISC_SOCKEVENT_INTW (ISC_EVENTCLASS_SOCKET + 257)
+
+typedef enum {
+ isc_sockettype_udp = 1,
+ isc_sockettype_tcp = 2,
+ isc_sockettype_unix = 3,
+ isc_sockettype_fdwatch = 4,
+ isc_sockettype_raw = 5
+} isc_sockettype_t;
+
+/*@{*/
+/*!
+ * How a socket should be shutdown in isc_socket_shutdown() calls.
+ */
+#define ISC_SOCKSHUT_RECV 0x00000001 /*%< close read side */
+#define ISC_SOCKSHUT_SEND 0x00000002 /*%< close write side */
+#define ISC_SOCKSHUT_ALL 0x00000003 /*%< close them all */
+/*@}*/
+
+/*@{*/
+/*!
+ * What I/O events to cancel in isc_socket_cancel() calls.
+ */
+#define ISC_SOCKCANCEL_RECV 0x00000001 /*%< cancel recv */
+#define ISC_SOCKCANCEL_SEND 0x00000002 /*%< cancel send */
+#define ISC_SOCKCANCEL_ACCEPT 0x00000004 /*%< cancel accept */
+#define ISC_SOCKCANCEL_CONNECT 0x00000008 /*%< cancel connect */
+#define ISC_SOCKCANCEL_ALL 0x0000000f /*%< cancel everything */
+/*@}*/
+
+/*@{*/
+/*!
+ * Flags for isc_socket_send() and isc_socket_recv() calls.
+ */
+#define ISC_SOCKFLAG_IMMEDIATE 0x00000001 /*%< send event only if needed */
+#define ISC_SOCKFLAG_NORETRY 0x00000002 /*%< drop failed UDP sends */
+/*@}*/
+
+/*@{*/
+/*!
+ * Flags for fdwatchcreate.
+ */
+#define ISC_SOCKFDWATCH_READ 0x00000001 /*%< watch for readable */
+#define ISC_SOCKFDWATCH_WRITE 0x00000002 /*%< watch for writable */
+/*@}*/
+
+/*% Socket and socket manager methods */
+typedef struct isc_socketmgrmethods {
+ void (*destroy)(isc_socketmgr_t **managerp);
+ isc_result_t (*socketcreate)(isc_socketmgr_t *manager, int pf,
+ isc_sockettype_t type,
+ isc_socket_t **socketp);
+ isc_result_t (*fdwatchcreate)(isc_socketmgr_t *manager, int fd,
+ int flags,
+ isc_sockfdwatch_t callback,
+ void *cbarg, isc_task_t *task,
+ isc_socket_t **socketp);
+} isc_socketmgrmethods_t;
+
+typedef struct isc_socketmethods {
+ void (*attach)(isc_socket_t *socket,
+ isc_socket_t **socketp);
+ void (*detach)(isc_socket_t **socketp);
+ isc_result_t (*bind)(isc_socket_t *sock, isc_sockaddr_t *sockaddr,
+ unsigned int options);
+ isc_result_t (*sendto)(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action,
+ void *arg, isc_sockaddr_t *address,
+ struct in6_pktinfo *pktinfo);
+ isc_result_t (*sendto2)(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_sockaddr_t *address,
+ struct in6_pktinfo *pktinfo,
+ isc_socketevent_t *event,
+ unsigned int flags);
+ isc_result_t (*connect)(isc_socket_t *sock, isc_sockaddr_t *addr,
+ isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+ isc_result_t (*recv)(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_taskaction_t action, void *arg);
+ isc_result_t (*recv2)(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_socketevent_t *event, unsigned int flags);
+ void (*cancel)(isc_socket_t *sock, isc_task_t *task,
+ unsigned int how);
+ isc_result_t (*getsockname)(isc_socket_t *sock,
+ isc_sockaddr_t *addressp);
+ isc_sockettype_t (*gettype)(isc_socket_t *sock);
+ void (*ipv6only)(isc_socket_t *sock, bool yes);
+ isc_result_t (*fdwatchpoke)(isc_socket_t *sock, int flags);
+ isc_result_t (*dup)(isc_socket_t *socket,
+ isc_socket_t **socketp);
+ int (*getfd)(isc_socket_t *socket);
+ void (*dscp)(isc_socket_t *socket, isc_dscp_t dscp);
+} isc_socketmethods_t;
+
+/*%
+ * This structure is actually just the common prefix of a socket manager
+ * object implementation's version of an isc_socketmgr_t.
+ * \brief
+ * Direct use of this structure by clients is forbidden. socket implementations
+ * may change the structure. 'magic' must be ISCAPI_SOCKETMGR_MAGIC for any
+ * of the isc_socket_ routines to work. socket implementations must maintain
+ * all socket invariants.
+ * In effect, this definition is used only for non-BIND9 version ("export")
+ * of the library, and the export version does not work for win32. So, to avoid
+ * the definition conflict with win32/socket.c, we enable this definition only
+ * for non-Win32 (i.e. Unix) platforms.
+ */
+#ifndef WIN32
+struct isc_socketmgr {
+ unsigned int impmagic;
+ unsigned int magic;
+ isc_socketmgrmethods_t *methods;
+};
+#endif
+
+#define ISCAPI_SOCKETMGR_MAGIC ISC_MAGIC('A','s','m','g')
+#define ISCAPI_SOCKETMGR_VALID(m) ((m) != NULL && \
+ (m)->magic == ISCAPI_SOCKETMGR_MAGIC)
+
+/*%
+ * This is the common prefix of a socket object. The same note as
+ * that for the socketmgr structure applies.
+ */
+#ifndef WIN32
+struct isc_socket {
+ unsigned int impmagic;
+ unsigned int magic;
+ isc_socketmethods_t *methods;
+};
+#endif
+
+#define ISCAPI_SOCKET_MAGIC ISC_MAGIC('A','s','c','t')
+#define ISCAPI_SOCKET_VALID(s) ((s) != NULL && \
+ (s)->magic == ISCAPI_SOCKET_MAGIC)
+
+/***
+ *** Socket and Socket Manager Functions
+ ***
+ *** Note: all Ensures conditions apply only if the result is success for
+ *** those functions which return an isc_result.
+ ***/
+
+isc_result_t
+isc_socket_fdwatchcreate(isc_socketmgr_t *manager,
+ int fd,
+ int flags,
+ isc_sockfdwatch_t callback,
+ void *cbarg,
+ isc_task_t *task,
+ isc_socket_t **socketp);
+/*%<
+ * Create a new file descriptor watch socket managed by 'manager'.
+ *
+ * Note:
+ *
+ *\li 'fd' is the already-opened file descriptor (must be less
+ * than maxsockets).
+ *\li This function is not available on Windows.
+ *\li The callback function is called "in-line" - this means the function
+ * needs to return as fast as possible, as all other I/O will be suspended
+ * until the callback completes.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid manager
+ *
+ *\li 'socketp' is a valid pointer, and *socketp == NULL
+ *
+ *\li 'fd' be opened.
+ *
+ * Ensures:
+ *
+ * '*socketp' is attached to the newly created fdwatch socket
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_NORESOURCES
+ *\li #ISC_R_UNEXPECTED
+ *\li #ISC_R_RANGE
+ */
+
+isc_result_t
+isc_socket_fdwatchpoke(isc_socket_t *sock,
+ int flags);
+/*%<
+ * Poke a file descriptor watch socket informing the manager that it
+ * should restart watching the socket
+ *
+ * Note:
+ *
+ *\li 'sock' is the socket returned by isc_socket_fdwatchcreate
+ *
+ *\li 'flags' indicates what the manager should watch for on the socket
+ * in addition to what it may already be watching. It can be one or
+ * both of ISC_SOCKFDWATCH_READ and ISC_SOCKFDWATCH_WRITE. To
+ * temporarily disable watching on a socket the value indicating
+ * no more data should be returned from the call back routine.
+ *
+ *\li This function is not available on Windows.
+ *
+ * Requires:
+ *
+ *\li 'sock' is a valid isc socket
+ *
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ */
+
+isc_result_t
+isc_socket_create(isc_socketmgr_t *manager,
+ int pf,
+ isc_sockettype_t type,
+ isc_socket_t **socketp);
+/*%<
+ * Create a new 'type' socket managed by 'manager'.
+ *
+ * For isc_sockettype_fdwatch sockets you should use isc_socket_fdwatchcreate()
+ * rather than isc_socket_create().
+ *
+ * Note:
+ *
+ *\li 'pf' is the desired protocol family, e.g. PF_INET or PF_INET6.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid manager
+ *
+ *\li 'socketp' is a valid pointer, and *socketp == NULL
+ *
+ *\li 'type' is not isc_sockettype_fdwatch
+ *
+ * Ensures:
+ *
+ * '*socketp' is attached to the newly created socket
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_NORESOURCES
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_dup(isc_socket_t *sock0, isc_socket_t **socketp);
+/*%<
+ * Duplicate an existing socket, reusing its file descriptor.
+ */
+
+void
+isc_socket_cancel(isc_socket_t *sock, isc_task_t *task,
+ unsigned int how);
+/*%<
+ * Cancel pending I/O of the type specified by "how".
+ *
+ * Note: if "task" is NULL, then the cancel applies to all tasks using the
+ * socket.
+ *
+ * Requires:
+ *
+ * \li "socket" is a valid socket
+ *
+ * \li "task" is NULL or a valid task
+ *
+ * "how" is a bitmask describing the type of cancelation to perform.
+ * The type ISC_SOCKCANCEL_ALL will cancel all pending I/O on this
+ * socket.
+ *
+ * \li ISC_SOCKCANCEL_RECV:
+ * Cancel pending isc_socket_recv() calls.
+ *
+ * \li ISC_SOCKCANCEL_SEND:
+ * Cancel pending isc_socket_send() and isc_socket_sendto() calls.
+ *
+ * \li ISC_SOCKCANCEL_ACCEPT:
+ * Cancel pending isc_socket_accept() calls.
+ *
+ * \li ISC_SOCKCANCEL_CONNECT:
+ * Cancel pending isc_socket_connect() call.
+ */
+
+void
+isc_socket_shutdown(isc_socket_t *sock, unsigned int how);
+/*%<
+ * Shutdown 'socket' according to 'how'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket.
+ *
+ * \li 'task' is NULL or is a valid task.
+ *
+ * \li If 'how' is 'ISC_SOCKSHUT_RECV' or 'ISC_SOCKSHUT_ALL' then
+ *
+ * The read queue must be empty.
+ *
+ * No further read requests may be made.
+ *
+ * \li If 'how' is 'ISC_SOCKSHUT_SEND' or 'ISC_SOCKSHUT_ALL' then
+ *
+ * The write queue must be empty.
+ *
+ * No further write requests may be made.
+ */
+
+void
+isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp);
+/*%<
+ * Attach *socketp to socket.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket.
+ *
+ * \li 'socketp' points to a NULL socket.
+ *
+ * Ensures:
+ *
+ * \li *socketp is attached to socket.
+ */
+
+void
+isc_socket_detach(isc_socket_t **socketp);
+/*%<
+ * Detach *socketp from its socket.
+ *
+ * Requires:
+ *
+ * \li 'socketp' points to a valid socket.
+ *
+ * \li If '*socketp' is the last reference to the socket,
+ * then:
+ *
+ * There must be no pending I/O requests.
+ *
+ * Ensures:
+ *
+ * \li *socketp is NULL.
+ *
+ * \li If '*socketp' is the last reference to the socket,
+ * then:
+ *
+ * The socket will be shutdown (both reading and writing)
+ * for all tasks.
+ *
+ * All resources used by the socket have been freed
+ */
+
+isc_result_t
+isc_socket_open(isc_socket_t *sock);
+/*%<
+ * Open a new socket file descriptor of the given socket structure. It simply
+ * opens a new descriptor; all of the other parameters including the socket
+ * type are inherited from the existing socket. This function is provided to
+ * avoid overhead of destroying and creating sockets when many short-lived
+ * sockets are frequently opened and closed. When the efficiency is not an
+ * issue, it should be safer to detach the unused socket and re-create a new
+ * one. This optimization may not be available for some systems, in which
+ * case this function will return ISC_R_NOTIMPLEMENTED and must not be used.
+ *
+ * isc_socket_open() should not be called on sockets created by
+ * isc_socket_fdwatchcreate().
+ *
+ * Requires:
+ *
+ * \li there must be no other reference to this socket.
+ *
+ * \li 'socket' is a valid and previously closed by isc_socket_close()
+ *
+ * \li 'sock->type' is not isc_sockettype_fdwatch
+ *
+ * Returns:
+ * Same as isc_socket_create().
+ * \li ISC_R_NOTIMPLEMENTED
+ */
+
+isc_result_t
+isc_socket_close(isc_socket_t *sock);
+/*%<
+ * Close a socket file descriptor of the given socket structure. This function
+ * is provided as an alternative to destroying an unused socket when overhead
+ * destroying/re-creating sockets can be significant, and is expected to be
+ * used with isc_socket_open(). This optimization may not be available for some
+ * systems, in which case this function will return ISC_R_NOTIMPLEMENTED and
+ * must not be used.
+ *
+ * isc_socket_close() should not be called on sockets created by
+ * isc_socket_fdwatchcreate().
+ *
+ * Requires:
+ *
+ * \li The socket must have a valid descriptor.
+ *
+ * \li There must be no other reference to this socket.
+ *
+ * \li There must be no pending I/O requests.
+ *
+ * \li 'sock->type' is not isc_sockettype_fdwatch
+ *
+ * Returns:
+ * \li #ISC_R_NOTIMPLEMENTED
+ */
+
+isc_result_t
+isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *addressp,
+ unsigned int options);
+/*%<
+ * Bind 'socket' to '*addressp'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket
+ *
+ * \li 'addressp' points to a valid isc_sockaddr.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOPERM
+ * \li ISC_R_ADDRNOTAVAIL
+ * \li ISC_R_ADDRINUSE
+ * \li ISC_R_BOUND
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_filter(isc_socket_t *sock, const char *filter);
+/*%<
+ * Inform the kernel that it should perform accept filtering.
+ * If filter is NULL the current filter will be removed.:w
+ */
+
+isc_result_t
+isc_socket_listen(isc_socket_t *sock, unsigned int backlog);
+/*%<
+ * Set listen mode on the socket. After this call, the only function that
+ * can be used (other than attach and detach) is isc_socket_accept().
+ *
+ * Notes:
+ *
+ * \li 'backlog' is as in the UNIX system call listen() and may be
+ * ignored by non-UNIX implementations.
+ *
+ * \li If 'backlog' is zero, a reasonable system default is used, usually
+ * SOMAXCONN.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid, bound TCP socket or a valid, bound UNIX socket.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_accept(isc_socket_t *sock,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+/*%<
+ * Queue accept event. When a new connection is received, the task will
+ * get an ISC_SOCKEVENT_NEWCONN event with the sender set to the listen
+ * socket. The new socket structure is sent inside the isc_socket_newconnev_t
+ * event type, and is attached to the task 'task'.
+ *
+ * REQUIRES:
+ * \li 'socket' is a valid TCP socket that isc_socket_listen() was called
+ * on.
+ *
+ * \li 'task' is a valid task
+ *
+ * \li 'action' is a valid action
+ *
+ * RETURNS:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addressp,
+ isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+/*%<
+ * Connect 'socket' to peer with address *saddr. When the connection
+ * succeeds, or when an error occurs, a CONNECT event with action 'action'
+ * and arg 'arg' will be posted to the event queue for 'task'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid TCP socket
+ *
+ * \li 'addressp' points to a valid isc_sockaddr
+ *
+ * \li 'task' is a valid task
+ *
+ * \li 'action' is a valid action
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_UNEXPECTED
+ *
+ * Posted event's result code:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_TIMEDOUT
+ * \li ISC_R_CONNREFUSED
+ * \li ISC_R_NETUNREACH
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp);
+/*%<
+ * Get the name of the peer connected to 'socket'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid TCP socket.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_TOOSMALL
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp);
+/*%<
+ * Get the name of 'socket'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_TOOSMALL
+ * \li ISC_R_UNEXPECTED
+ */
+
+/*@{*/
+isc_result_t
+isc_socket_recv(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+isc_result_t
+isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ unsigned int minimum,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+
+isc_result_t
+isc_socket_recv2(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_socketevent_t *event, unsigned int flags);
+
+/*!
+ * Receive from 'socket', storing the results in region.
+ *
+ * Notes:
+ *
+ *\li Let 'length' refer to the length of 'region' or to the sum of all
+ * available regions in the list of buffers '*buflist'.
+ *
+ *\li If 'minimum' is non-zero and at least that many bytes are read,
+ * the completion event will be posted to the task 'task.' If minimum
+ * is zero, the exact number of bytes requested in the region must
+ * be read for an event to be posted. This only makes sense for TCP
+ * connections, and is always set to 1 byte for UDP.
+ *
+ *\li The read will complete when the desired number of bytes have been
+ * read, if end-of-input occurs, or if an error occurs. A read done
+ * event with the given 'action' and 'arg' will be posted to the
+ * event queue of 'task'.
+ *
+ *\li The caller may not modify 'region', the buffers which are passed
+ * into this function, or any data they refer to until the completion
+ * event is received.
+ *
+ *\li For isc_socket_recvv():
+ * On successful completion, '*buflist' will be empty, and the list of
+ * all buffers will be returned in the done event's 'bufferlist'
+ * member. On error return, '*buflist' will be unchanged.
+ *
+ *\li For isc_socket_recv2():
+ * 'event' is not NULL, and the non-socket specific fields are
+ * expected to be initialized.
+ *
+ *\li For isc_socket_recv2():
+ * The only defined value for 'flags' is ISC_SOCKFLAG_IMMEDIATE. If
+ * set and the operation completes, the return value will be
+ * ISC_R_SUCCESS and the event will be filled in and not sent. If the
+ * operation does not complete, the return value will be
+ * ISC_R_INPROGRESS and the event will be sent when the operation
+ * completes.
+ *
+ * Requires:
+ *
+ *\li 'socket' is a valid, bound socket.
+ *
+ *\li For isc_socket_recv():
+ * 'region' is a valid region
+ *
+ *\li For isc_socket_recvv():
+ * 'buflist' is non-NULL, and '*buflist' contain at least one buffer.
+ *
+ *\li 'task' is a valid task
+ *
+ *\li For isc_socket_recv() and isc_socket_recvv():
+ * action != NULL and is a valid action
+ *
+ *\li For isc_socket_recv2():
+ * event != NULL
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_INPROGRESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ *
+ * Event results:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_UNEXPECTED
+ *\li XXX needs other net-type errors
+ */
+/*@}*/
+
+/*@{*/
+isc_result_t
+isc_socket_send(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+isc_result_t
+isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo);
+isc_result_t
+isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+isc_result_t
+isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo);
+isc_result_t
+isc_socket_sendtov2(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ unsigned int flags);
+isc_result_t
+isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ isc_socketevent_t *event, unsigned int flags);
+
+/*!
+ * Send the contents of 'region' to the socket's peer.
+ *
+ * Notes:
+ *
+ *\li Shutting down the requestor's task *may* result in any
+ * still pending writes being dropped or completed, depending on the
+ * underlying OS implementation.
+ *
+ *\li If 'action' is NULL, then no completion event will be posted.
+ *
+ *\li The caller may not modify 'region', the buffers which are passed
+ * into this function, or any data they refer to until the completion
+ * event is received.
+ *
+ *\li For isc_socket_sendv() and isc_socket_sendtov():
+ * On successful completion, '*buflist' will be empty, and the list of
+ * all buffers will be returned in the done event's 'bufferlist'
+ * member. On error return, '*buflist' will be unchanged.
+ *
+ *\li For isc_socket_sendto2():
+ * 'event' is not NULL, and the non-socket specific fields are
+ * expected to be initialized.
+ *
+ *\li For isc_socket_sendto2():
+ * The only defined values for 'flags' are ISC_SOCKFLAG_IMMEDIATE
+ * and ISC_SOCKFLAG_NORETRY.
+ *
+ *\li If ISC_SOCKFLAG_IMMEDIATE is set and the operation completes, the
+ * return value will be ISC_R_SUCCESS and the event will be filled
+ * in and not sent. If the operation does not complete, the return
+ * value will be ISC_R_INPROGRESS and the event will be sent when
+ * the operation completes.
+ *
+ *\li ISC_SOCKFLAG_NORETRY can only be set for UDP sockets. If set
+ * and the send operation fails due to a transient error, the send
+ * will not be retried and the error will be indicated in the event.
+ * Using this option along with ISC_SOCKFLAG_IMMEDIATE allows the caller
+ * to specify a region that is allocated on the stack.
+ *
+ * Requires:
+ *
+ *\li 'socket' is a valid, bound socket.
+ *
+ *\li For isc_socket_send():
+ * 'region' is a valid region
+ *
+ *\li For isc_socket_sendv() and isc_socket_sendtov():
+ * 'buflist' is non-NULL, and '*buflist' contain at least one buffer.
+ *
+ *\li 'task' is a valid task
+ *
+ *\li For isc_socket_sendv(), isc_socket_sendtov(), isc_socket_send(), and
+ * isc_socket_sendto():
+ * action == NULL or is a valid action
+ *
+ *\li For isc_socket_sendto2():
+ * event != NULL
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_INPROGRESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ *
+ * Event results:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_UNEXPECTED
+ *\li XXX needs other net-type errors
+ */
+/*@}*/
+
+isc_result_t
+isc_socketmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
+ isc_socketmgr_t **managerp);
+
+isc_result_t
+isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp);
+
+isc_result_t
+isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
+ unsigned int maxsocks);
+/*%<
+ * Create a socket manager. If "maxsocks" is non-zero, it specifies the
+ * maximum number of sockets that the created manager should handle.
+ * isc_socketmgr_create() is equivalent of isc_socketmgr_create2() with
+ * "maxsocks" being zero.
+ * isc_socketmgr_createinctx() also associates the new manager with the
+ * specified application context.
+ *
+ * Notes:
+ *
+ *\li All memory will be allocated in memory context 'mctx'.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li 'managerp' points to a NULL isc_socketmgr_t.
+ *
+ *\li 'actx' is a valid application context (for createinctx()).
+ *
+ * Ensures:
+ *
+ *\li '*managerp' is a valid isc_socketmgr_t.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ *\li #ISC_R_NOTIMPLEMENTED
+ */
+
+isc_result_t
+isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp);
+/*%<
+ * Returns in "*nsockp" the maximum number of sockets this manager may open.
+ *
+ * Requires:
+ *
+ *\li '*manager' is a valid isc_socketmgr_t.
+ *\li 'nsockp' is not NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOTIMPLEMENTED
+ */
+
+void
+isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats);
+/*%<
+ * Set a general socket statistics counter set 'stats' for 'manager'.
+ *
+ * Requires:
+ * \li 'manager' is valid, hasn't opened any socket, and doesn't have
+ * stats already set.
+ *
+ *\li stats is a valid statistics supporting socket statistics counters
+ * (see above).
+ */
+
+void
+isc_socketmgr_destroy(isc_socketmgr_t **managerp);
+/*%<
+ * Destroy a socket manager.
+ *
+ * Notes:
+ *
+ *\li This routine blocks until there are no sockets left in the manager,
+ * so if the caller holds any socket references using the manager, it
+ * must detach them before calling isc_socketmgr_destroy() or it will
+ * block forever.
+ *
+ * Requires:
+ *
+ *\li '*managerp' is a valid isc_socketmgr_t.
+ *
+ *\li All sockets managed by this manager are fully detached.
+ *
+ * Ensures:
+ *
+ *\li *managerp == NULL
+ *
+ *\li All resources used by the manager have been freed.
+ */
+
+isc_sockettype_t
+isc_socket_gettype(isc_socket_t *sock);
+/*%<
+ * Returns the socket type for "sock."
+ *
+ * Requires:
+ *
+ *\li "sock" is a valid socket.
+ */
+
+/*@{*/
+bool
+isc__socket_isbound(isc_socket_t *sock);
+/*%
+ * Intended for internal use in BIND9 only
+ */
+
+void
+isc_socket_ipv6only(isc_socket_t *sock, bool yes);
+/*%<
+ * If the socket is an IPv6 socket set/clear the IPV6_IPV6ONLY socket
+ * option if the host OS supports this option.
+ *
+ * Requires:
+ *\li 'sock' is a valid socket.
+ */
+/*@}*/
+
+void
+isc_socket_dscp(isc_socket_t *sock, isc_dscp_t dscp);
+/*%<
+ * Sets the Differentiated Services Code Point (DSCP) field for packets
+ * transmitted on this socket. If 'dscp' is -1, return immediately.
+ *
+ * Requires:
+ *\li 'sock' is a valid socket.
+ */
+
+isc_socketevent_t *
+isc_socket_socketevent(isc_mem_t *mctx, void *sender,
+ isc_eventtype_t eventtype, isc_taskaction_t action,
+ void *arg);
+/*%<
+ * Get a isc_socketevent_t to be used with isc_socket_sendto2(), etc.
+ */
+
+void
+isc_socket_cleanunix(isc_sockaddr_t *addr, bool active);
+
+/*%<
+ * Cleanup UNIX domain sockets in the file-system. If 'active' is true
+ * then just unlink the socket. If 'active' is false try to determine
+ * if there is a listener of the socket or not. If no listener is found
+ * then unlink socket.
+ *
+ * Prior to unlinking the path is tested to see if it a socket.
+ *
+ * Note: there are a number of race conditions which cannot be avoided
+ * both in the filesystem and any application using UNIX domain
+ * sockets (e.g. socket is tested between bind() and listen(),
+ * the socket is deleted and replaced in the file-system between
+ * stat() and unlink()).
+ */
+
+isc_result_t
+isc_socket_permunix(isc_sockaddr_t *sockaddr, uint32_t perm,
+ uint32_t owner, uint32_t group);
+/*%<
+ * Set ownership and file permissions on the UNIX domain socket.
+ *
+ * Note: On Solaris and SunOS this secures the directory containing
+ * the socket as Solaris and SunOS do not honour the filesystem
+ * permissions on the socket.
+ *
+ * Requires:
+ * \li 'sockaddr' to be a valid UNIX domain sockaddr.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_FAILURE
+ */
+
+void isc_socket_setname(isc_socket_t *socket, const char *name, void *tag);
+/*%<
+ * Set the name and optional tag for a socket. This allows tracking of the
+ * owner or purpose for this socket, and is useful for tracing and statistics
+ * reporting.
+ */
+
+const char *isc_socket_getname(isc_socket_t *socket);
+/*%<
+ * Get the name associated with a socket, if any.
+ */
+
+void *isc_socket_gettag(isc_socket_t *socket);
+/*%<
+ * Get the tag associated with a socket, if any.
+ */
+
+int isc_socket_getfd(isc_socket_t *socket);
+/*%<
+ * Get the file descriptor associated with a socket
+ */
+
+void
+isc__socketmgr_setreserved(isc_socketmgr_t *mgr, uint32_t);
+/*%<
+ * Temporary. For use by named only.
+ */
+
+void
+isc__socketmgr_maxudp(isc_socketmgr_t *mgr, int maxudp);
+/*%<
+ * Test interface. Drop UDP packet > 'maxudp'.
+ */
+
+#ifdef HAVE_LIBXML2
+int
+isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer);
+/*%<
+ * Render internal statistics and other state into the XML document.
+ */
+#endif /* HAVE_LIBXML2 */
+
+#ifdef HAVE_JSON
+isc_result_t
+isc_socketmgr_renderjson(isc_socketmgr_t *mgr, json_object *stats);
+/*%<
+ * Render internal statistics and other state into JSON format.
+ */
+#endif /* HAVE_JSON */
+
+/*%<
+ * See isc_socketmgr_create() above.
+ */
+typedef isc_result_t
+(*isc_socketmgrcreatefunc_t)(isc_mem_t *mctx, isc_socketmgr_t **managerp);
+
+isc_result_t
+isc_socket_register(isc_socketmgrcreatefunc_t createfunc);
+/*%<
+ * Register a new socket I/O implementation and add it to the list of
+ * supported implementations. This function must be called when a different
+ * event library is used than the one contained in the ISC library.
+ */
+
+isc_result_t
+isc__socket_register(void);
+/*%<
+ * A short cut function that specifies the socket I/O module in the ISC
+ * library for isc_socket_register(). An application that uses the ISC library
+ * usually do not have to care about this function: it would call
+ * isc_lib_register(), which internally calls this function.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SOCKET_H */
diff --git a/lib/isc/include/isc/stats.h b/lib/isc/include/isc/stats.h
new file mode 100644
index 0000000..8f41bb9
--- /dev/null
+++ b/lib/isc/include/isc/stats.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_STATS_H
+#define ISC_STATS_H 1
+
+/*! \file isc/stats.h */
+
+#include <inttypes.h>
+
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%<
+ * Flag(s) for isc_stats_dump().
+ */
+#define ISC_STATSDUMP_VERBOSE 0x00000001 /*%< dump 0-value counters */
+
+/*%<
+ * Dump callback type.
+ */
+typedef void (*isc_stats_dumper_t)(isc_statscounter_t, uint64_t, void *);
+
+isc_result_t
+isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters);
+/*%<
+ * Create a statistics counter structure of general type. It counts a general
+ * set of counters indexed by an ID between 0 and ncounters -1.
+ *
+ * Requires:
+ *\li 'mctx' must be a valid memory context.
+ *
+ *\li 'statsp' != NULL && '*statsp' == NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS -- all ok
+ *
+ *\li anything else -- failure
+ */
+
+void
+isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp);
+/*%<
+ * Attach to a statistics set.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ *
+ *\li 'statsp' != NULL && '*statsp' == NULL
+ */
+
+void
+isc_stats_detach(isc_stats_t **statsp);
+/*%<
+ * Detaches from the statistics set.
+ *
+ * Requires:
+ *\li 'statsp' != NULL and '*statsp' is a valid isc_stats_t.
+ */
+
+int
+isc_stats_ncounters(isc_stats_t *stats);
+/*%<
+ * Returns the number of counters contained in stats.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ *
+ */
+
+void
+isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter);
+/*%<
+ * Increment the counter-th counter of stats.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ *
+ *\li counter is less than the maximum available ID for the stats specified
+ * on creation.
+ */
+
+void
+isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter);
+/*%<
+ * Decrement the counter-th counter of stats.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ */
+
+void
+isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn, void *arg,
+ unsigned int options);
+/*%<
+ * Dump the current statistics counters in a specified way. For each counter
+ * in stats, dump_fn is called with its current value and the given argument
+ * arg. By default counters that have a value of 0 is skipped; if options has
+ * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ */
+
+void
+isc_stats_set(isc_stats_t *stats, uint64_t val,
+ isc_statscounter_t counter);
+/*%<
+ * Set the given counter to the specfied value.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ */
+
+void
+isc_stats_set(isc_stats_t *stats, uint64_t val,
+ isc_statscounter_t counter);
+/*%<
+ * Set the given counter to the specfied value.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STATS_H */
diff --git a/lib/isc/include/isc/stdatomic.h b/lib/isc/include/isc/stdatomic.h
new file mode 100644
index 0000000..723ed1e
--- /dev/null
+++ b/lib/isc/include/isc/stdatomic.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+#if !defined(__has_feature)
+#define __has_feature(x) 0
+#endif
+
+#if !defined(__has_extension)
+#define __has_extension(x) __has_feature(x)
+#endif
+
+#if !defined(__GNUC_PREREQ__)
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define __GNUC_PREREQ__(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+#define __GNUC_PREREQ__(maj, min) 0
+#endif
+#endif
+
+#if !defined(__CLANG_ATOMICS) && !defined(__GNUC_ATOMICS)
+#if __has_extension(c_atomic) || __has_extension(cxx_atomic)
+#define __CLANG_ATOMICS
+#elif __GNUC_PREREQ__(4, 7)
+#define __GNUC_ATOMICS
+#elif !defined(__GNUC__)
+#error "isc/stdatomic.h does not support your compiler"
+#endif
+#endif
+
+#ifndef __ATOMIC_RELAXED
+#define __ATOMIC_RELAXED 0
+#endif
+#ifndef __ATOMIC_CONSUME
+#define __ATOMIC_CONSUME 1
+#endif
+#ifndef __ATOMIC_ACQUIRE
+#define __ATOMIC_ACQUIRE 2
+#endif
+#ifndef __ATOMIC_RELEASE
+#define __ATOMIC_RELEASE 3
+#endif
+#ifndef __ATOMIC_ACQ_REL
+#define __ATOMIC_ACQ_REL 4
+#endif
+#ifndef __ATOMIC_SEQ_CST
+#define __ATOMIC_SEQ_CST 5
+#endif
+
+
+enum memory_order {
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_consume = __ATOMIC_CONSUME,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
+};
+
+typedef enum memory_order memory_order;
+
+typedef int_fast32_t atomic_int_fast32_t;
+typedef uint_fast32_t atomic_uint_fast32_t;
+typedef int_fast64_t atomic_int_fast64_t;
+typedef uint_fast64_t atomic_uint_fast64_t;
+
+#if defined(__CLANG_ATOMICS) /* __c11_atomic builtins */
+#define atomic_init(obj, desired) \
+ __c11_atomic_init(obj, desired)
+#define atomic_load_explicit(obj, order) \
+ __c11_atomic_load(obj, order)
+#define atomic_store_explicit(obj, desired, order) \
+ __c11_atomic_store(obj, desired, order)
+#define atomic_fetch_add_explicit(obj, arg, order) \
+ __c11_atomic_fetch_add(obj, arg, order)
+#define atomic_fetch_sub_explicit(obj, arg, order) \
+ __c11_atomic_fetch_sub(obj, arg, order)
+#define atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, fail) \
+ __c11_atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, fail)
+#define atomic_compare_exchange_weak_explicit(obj, expected, desired, succ, fail) \
+ __c11_atomic_compare_exchange_weak_explicit(obj, expected, desired, succ, fail)
+#elif defined(__GNUC_ATOMICS) /* __atomic builtins */
+#define atomic_init(obj, desired) \
+ (*obj = desired)
+#define atomic_load_explicit(obj, order) \
+ __atomic_load_n(obj, order)
+#define atomic_store_explicit(obj, desired, order) \
+ __atomic_store_n(obj, desired, order)
+#define atomic_fetch_add_explicit(obj, arg, order) \
+ __atomic_fetch_add(obj, arg, order)
+#define atomic_fetch_sub_explicit(obj, arg, order) \
+ __atomic_fetch_sub(obj, arg, order)
+#define atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, fail) \
+ __atomic_compare_exchange_n(obj, expected, desired, 0, succ, fail)
+#define atomic_compare_exchange_weak_explicit(obj, expected, desired, succ, fail) \
+ __atomic_compare_exchange_n(obj, expected, desired, 1, succ, fail)
+#else /* __sync builtins */
+#define atomic_init(obj, desired) \
+ (*obj = desired)
+#define atomic_load_explicit(obj, order) \
+ __sync_fetch_and_add(obj, 0)
+#define atomic_store_explicit(obj, desired, order) \
+ do { \
+ __sync_synchronize(); \
+ *obj = desired; \
+ __sync_synchronize(); \
+ } while (0);
+#define atomic_fetch_add_explicit(obj, arg, order) \
+ __sync_fetch_and_add(obj, arg)
+#define atomic_fetch_sub_explicit(obj, arg, order) \
+ __sync_fetch_and_sub(obj, arg, order)
+#define atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, fail) \
+ ({ \
+ __typeof__(obj) __v; \
+ _Bool __r; \
+ __v = __sync_val_compare_and_swap(obj, *(expected), desired); \
+ __r = *(expected) == __v; \
+ *(expected) = __v; \
+ __r; \
+ })
+#define atomic_compare_exchange_weak_explicit(obj, expected, desired, succ, fail) \
+ atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, fail)
+#endif
+
+#define atomic_load(obj) \
+ atomic_load_explicit(obj, memory_order_seq_cst)
+#define atomic_store(obj) \
+ atomic_store_explicit(obj, memory_order_seq_cst)
+#define atomic_fetch_add(obj) \
+ atomic_fetch_add_explicit(obj, arg, memory_order_seq_cst)
+#define atomic_fetch_sub(obj) \
+ atomic_fetch_sub_explicit(obj, arg, memory_order_seq_cst)
+#define atomic_compare_exchange_strong(obj, expected, desired) \
+ atomic_compare_exchange_strong_explicit(obj, expected, desired, memory_order_seq_cst, memory_order_seq_cst)
+#define atomic_compare_exchange_weak(obj, expected, desired) \
+ atomic_compare_exchange_weak_explicit(obj, expected, desired, memory_order_seq_cst, memory_order_seq_cst)
diff --git a/lib/isc/include/isc/stdio.h b/lib/isc/include/isc/stdio.h
new file mode 100644
index 0000000..1f44b5a
--- /dev/null
+++ b/lib/isc/include/isc/stdio.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_STDIO_H
+#define ISC_STDIO_H 1
+
+/*! \file isc/stdio.h */
+
+/*%
+ * These functions are wrappers around the corresponding stdio functions.
+ *
+ * They return a detailed error code in the form of an an isc_result_t. ANSI C
+ * does not guarantee that stdio functions set errno, hence these functions
+ * must use platform dependent methods (e.g., the POSIX errno) to construct the
+ * error code.
+ */
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% Open */
+isc_result_t
+isc_stdio_open(const char *filename, const char *mode, FILE **fp);
+
+/*% Close */
+isc_result_t
+isc_stdio_close(FILE *f);
+
+/*% Seek */
+isc_result_t
+isc_stdio_seek(FILE *f, off_t offset, int whence);
+
+/*% Tell */
+isc_result_t
+isc_stdio_tell(FILE *f, off_t *offsetp);
+
+/*% Read */
+isc_result_t
+isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f,
+ size_t *nret);
+
+/*% Write */
+isc_result_t
+isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f,
+ size_t *nret);
+
+/*% Flush */
+isc_result_t
+isc_stdio_flush(FILE *f);
+
+isc_result_t
+isc_stdio_sync(FILE *f);
+/*%<
+ * Invoke fsync() on the file descriptor underlying an stdio stream, or an
+ * equivalent system-dependent operation. Note that this function has no
+ * direct counterpart in the stdio library.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STDIO_H */
diff --git a/lib/isc/include/isc/stdlib.h b/lib/isc/include/isc/stdlib.h
new file mode 100644
index 0000000..c44b0ea
--- /dev/null
+++ b/lib/isc/include/isc/stdlib.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_STDLIB_H
+#define ISC_STDLIB_H 1
+
+/*! \file isc/stdlib.h */
+
+#include <stdlib.h>
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+
+#ifdef ISC_PLATFORM_NEEDSTRTOUL
+#define strtoul isc_strtoul
+#endif
+
+ISC_LANG_BEGINDECLS
+
+unsigned long isc_strtoul(const char *, char **, int);
+
+ISC_LANG_ENDDECLS
+
+#endif
diff --git a/lib/isc/include/isc/string.h b/lib/isc/include/isc/string.h
new file mode 100644
index 0000000..5323aa7
--- /dev/null
+++ b/lib/isc/include/isc/string.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id: string.h,v 1.23 2007/09/13 04:48:16 each Exp $ */
+
+#ifndef ISC_STRING_H
+#define ISC_STRING_H 1
+
+/*! \file isc/string.h */
+
+#include <inttypes.h>
+
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#include <string.h>
+
+#ifdef ISC_PLATFORM_HAVESTRINGSH
+#include <strings.h>
+#endif
+
+#define ISC_STRING_MAGIC 0x5e
+
+ISC_LANG_BEGINDECLS
+
+uint64_t
+isc_string_touint64(char *source, char **endp, int base);
+/*%<
+ * Convert the string pointed to by 'source' to uint64_t.
+ *
+ * On successful conversion 'endp' points to the first character
+ * after conversion is complete.
+ *
+ * 'base': 0 or 2..36
+ *
+ * If base is 0 the base is computed from the string type.
+ *
+ * On error 'endp' points to 'source'.
+ */
+
+isc_result_t
+isc_string_copy(char *target, size_t size, const char *source);
+/*
+ * Copy the string pointed to by 'source' to 'target' which is a
+ * pointer to a string of at least 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a char[] of at least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * If result == ISC_R_SUCCESS
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ *
+ * If result == ISC_R_NOSPACE
+ * 'target' is undefined.
+ *
+ * Returns:
+ * ISC_R_SUCCESS -- 'source' was successfully copied to 'target'.
+ * ISC_R_NOSPACE -- 'source' could not be copied since 'target'
+ * is too small.
+ */
+
+void
+isc_string_copy_truncate(char *target, size_t size, const char *source);
+/*
+ * Copy the string pointed to by 'source' to 'target' which is a
+ * pointer to a string of at least 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a char[] of at least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ */
+
+isc_result_t
+isc_string_append(char *target, size_t size, const char *source);
+/*
+ * Append the string pointed to by 'source' to 'target' which is a
+ * pointer to a NUL terminated string of at least 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a NUL terminated char[] of at
+ * least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * If result == ISC_R_SUCCESS
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ *
+ * If result == ISC_R_NOSPACE
+ * 'target' is undefined.
+ *
+ * Returns:
+ * ISC_R_SUCCESS -- 'source' was successfully appended to 'target'.
+ * ISC_R_NOSPACE -- 'source' could not be appended since 'target'
+ * is too small.
+ */
+
+void
+isc_string_append_truncate(char *target, size_t size, const char *source);
+/*
+ * Append the string pointed to by 'source' to 'target' which is a
+ * pointer to a NUL terminated string of at least 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a NUL terminated char[] of at
+ * least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ */
+
+isc_result_t
+isc_string_printf(char *target, size_t size, const char *format, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+/*
+ * Print 'format' to 'target' which is a pointer to a string of at least
+ * 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a char[] of at least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'format' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * If result == ISC_R_SUCCESS
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ *
+ * If result == ISC_R_NOSPACE
+ * 'target' is undefined.
+ *
+ * Returns:
+ * ISC_R_SUCCESS -- 'format' was successfully printed to 'target'.
+ * ISC_R_NOSPACE -- 'format' could not be printed to 'target' since it
+ * is too small.
+ */
+
+void
+isc_string_printf_truncate(char *target, size_t size, const char *format, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+/*
+ * Print 'format' to 'target' which is a pointer to a string of at least
+ * 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a char[] of at least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'format' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ */
+
+
+char *
+isc_string_regiondup(isc_mem_t *mctx, const isc_region_t *source);
+/*
+ * Copy the region pointed to by r to a NUL terminated string
+ * allocated from the memory context pointed to by mctx.
+ *
+ * The result should be deallocated using isc_mem_free()
+ *
+ * Requires:
+ * 'mctx' is a point to a valid memory context.
+ * 'source' is a pointer to a valid region.
+ *
+ * Returns:
+ * a pointer to a NUL terminated string or
+ * NULL if memory for the copy could not be allocated
+ *
+ */
+
+char *
+isc_string_separate(char **stringp, const char *delim);
+
+#ifdef ISC_PLATFORM_NEEDSTRSEP
+#define strsep isc_string_separate
+#endif
+
+#ifdef ISC_PLATFORM_NEEDMEMMOVE
+#define memmove(a,b,c) bcopy(b,a,c)
+#endif
+
+size_t
+isc_string_strlcpy(char *dst, const char *src, size_t size);
+
+
+#ifdef ISC_PLATFORM_NEEDSTRLCPY
+#define strlcpy isc_string_strlcpy
+#endif
+
+
+size_t
+isc_string_strlcat(char *dst, const char *src, size_t size);
+
+#ifdef ISC_PLATFORM_NEEDSTRLCAT
+#define strlcat isc_string_strlcat
+#endif
+
+char *
+isc_string_strcasestr(const char *big, const char *little);
+
+#ifdef ISC_PLATFORM_NEEDSTRCASESTR
+#define strcasestr isc_string_strcasestr
+#endif
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STRING_H */
diff --git a/lib/isc/include/isc/symtab.h b/lib/isc/include/isc/symtab.h
new file mode 100644
index 0000000..0f53b5e
--- /dev/null
+++ b/lib/isc/include/isc/symtab.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_SYMTAB_H
+#define ISC_SYMTAB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/symtab.h
+ * \brief Provides a simple memory-based symbol table.
+ *
+ * Keys are C strings, and key comparisons are case-insensitive. A type may
+ * be specified when looking up, defining, or undefining. A type value of
+ * 0 means "match any type"; any other value will only match the given
+ * type.
+ *
+ * It's possible that a client will attempt to define a <key, type, value>
+ * tuple when a tuple with the given key and type already exists in the table.
+ * What to do in this case is specified by the client. Possible policies are:
+ *
+ *\li #isc_symexists_reject Disallow the define, returning #ISC_R_EXISTS
+ *\li #isc_symexists_replace Replace the old value with the new. The
+ * undefine action (if provided) will be called
+ * with the old <key, type, value> tuple.
+ *\li #isc_symexists_add Add the new tuple, leaving the old tuple in
+ * the table. Subsequent lookups will retrieve
+ * the most-recently-defined tuple.
+ *
+ * A lookup of a key using type 0 will return the most-recently defined
+ * symbol with that key. An undefine of a key using type 0 will undefine the
+ * most-recently defined symbol with that key. Trying to define a key with
+ * type 0 is illegal.
+ *
+ * The symbol table library does not make a copy the key field, so the
+ * caller must ensure that any key it passes to isc_symtab_define() will not
+ * change until it calls isc_symtab_undefine() or isc_symtab_destroy().
+ *
+ * A user-specified action will be called (if provided) when a symbol is
+ * undefined. It can be used to free memory associated with keys and/or
+ * values.
+ *
+ * A symbol table is implemented as a hash table of lists; the size of the
+ * hash table is set by the 'size' parameter to isc_symtbl_create(). When
+ * the number of entries in the symbol table reaches three quarters of this
+ * value, the hash table is reallocated with size doubled, in order to
+ * optimize lookup performance. This has a negative effect on insertion
+ * performance, which can be mitigated by sizing the table appropriately
+ * when creating it.
+ *
+ * \li MP:
+ * The callers of this module must ensure any required synchronization.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*
+ *** Symbol Tables.
+ ***/
+/*% Symbol table value. */
+typedef union isc_symvalue {
+ void * as_pointer;
+ const void * as_cpointer;
+ int as_integer;
+ unsigned int as_uinteger;
+} isc_symvalue_t;
+
+typedef void (*isc_symtabaction_t)(char *key, unsigned int type,
+ isc_symvalue_t value, void *userarg);
+/*% Symbol table exists. */
+typedef enum {
+ isc_symexists_reject = 0, /*%< Disallow the define */
+ isc_symexists_replace = 1, /*%< Replace the old value with the new */
+ isc_symexists_add = 2 /*%< Add the new tuple */
+} isc_symexists_t;
+
+ISC_LANG_BEGINDECLS
+
+/*% Create a symbol table. */
+isc_result_t
+isc_symtab_create(isc_mem_t *mctx, unsigned int size,
+ isc_symtabaction_t undefine_action, void *undefine_arg,
+ bool case_sensitive, isc_symtab_t **symtabp);
+
+/*% Destroy a symbol table. */
+void
+isc_symtab_destroy(isc_symtab_t **symtabp);
+
+/*% Lookup a symbol table. */
+isc_result_t
+isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type,
+ isc_symvalue_t *value);
+
+/*% Define a symbol table. */
+isc_result_t
+isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
+ isc_symvalue_t value, isc_symexists_t exists_policy);
+
+/*% Undefine a symbol table. */
+isc_result_t
+isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type);
+
+/*% Return the number of items in a symbol table. */
+unsigned int
+isc_symtab_count(isc_symtab_t *symtab);
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SYMTAB_H */
diff --git a/lib/isc/include/isc/task.h b/lib/isc/include/isc/task.h
new file mode 100644
index 0000000..6920395
--- /dev/null
+++ b/lib/isc/include/isc/task.h
@@ -0,0 +1,827 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_TASK_H
+#define ISC_TASK_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/task.h
+ * \brief The task system provides a lightweight execution context, which is
+ * basically an event queue.
+
+ * When a task's event queue is non-empty, the
+ * task is runnable. A small work crew of threads, typically one per CPU,
+ * execute runnable tasks by dispatching the events on the tasks' event
+ * queues. Context switching between tasks is fast.
+ *
+ * \li MP:
+ * The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ * The caller must ensure that isc_taskmgr_destroy() is called only
+ * once for a given manager.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ *
+ * \section purge Purging and Unsending
+ *
+ * Events which have been queued for a task but not delivered may be removed
+ * from the task's event queue by purging or unsending.
+ *
+ * With both types, the caller specifies a matching pattern that selects
+ * events based upon their sender, type, and tag.
+ *
+ * Purging calls isc_event_free() on the matching events.
+ *
+ * Unsending returns a list of events that matched the pattern.
+ * The caller is then responsible for them.
+ *
+ * Consumers of events should purge, not unsend.
+ *
+ * Producers of events often want to remove events when the caller indicates
+ * it is no longer interested in the object, e.g. by canceling a timer.
+ * Sometimes this can be done by purging, but for some event types, the
+ * calls to isc_event_free() cause deadlock because the event free routine
+ * wants to acquire a lock the caller is already holding. Unsending instead
+ * of purging solves this problem. As a general rule, producers should only
+ * unsend events which they have sent.
+ */
+
+
+/***
+ *** Imports.
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/eventclass.h>
+#include <isc/json.h>
+#include <isc/lang.h>
+#include <isc/stdtime.h>
+#include <isc/types.h>
+#include <isc/xml.h>
+
+#define ISC_TASKEVENT_FIRSTEVENT (ISC_EVENTCLASS_TASK + 0)
+#define ISC_TASKEVENT_SHUTDOWN (ISC_EVENTCLASS_TASK + 1)
+#define ISC_TASKEVENT_TEST (ISC_EVENTCLASS_TASK + 1)
+#define ISC_TASKEVENT_LASTEVENT (ISC_EVENTCLASS_TASK + 65535)
+
+/*****
+ ***** Tasks.
+ *****/
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+typedef enum {
+ isc_taskmgrmode_normal = 0,
+ isc_taskmgrmode_privileged
+} isc_taskmgrmode_t;
+
+/*% Task and task manager methods */
+typedef struct isc_taskmgrmethods {
+ void (*destroy)(isc_taskmgr_t **managerp);
+ void (*setmode)(isc_taskmgr_t *manager,
+ isc_taskmgrmode_t mode);
+ isc_taskmgrmode_t (*mode)(isc_taskmgr_t *manager);
+ isc_result_t (*taskcreate)(isc_taskmgr_t *manager,
+ unsigned int quantum,
+ isc_task_t **taskp);
+ void (*setexcltask)(isc_taskmgr_t *mgr, isc_task_t *task);
+ isc_result_t (*excltask)(isc_taskmgr_t *mgr, isc_task_t **taskp);
+} isc_taskmgrmethods_t;
+
+typedef struct isc_taskmethods {
+ void (*attach)(isc_task_t *source, isc_task_t **targetp);
+ void (*detach)(isc_task_t **taskp);
+ void (*destroy)(isc_task_t **taskp);
+ void (*send)(isc_task_t *task, isc_event_t **eventp);
+ void (*sendanddetach)(isc_task_t **taskp, isc_event_t **eventp);
+ unsigned int (*unsend)(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag, isc_eventlist_t *events);
+ isc_result_t (*onshutdown)(isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+ void (*shutdown)(isc_task_t *task);
+ void (*setname)(isc_task_t *task, const char *name, void *tag);
+ unsigned int (*purgeevents)(isc_task_t *task, void *sender,
+ isc_eventtype_t type, void *tag);
+ unsigned int (*purgerange)(isc_task_t *task, void *sender,
+ isc_eventtype_t first, isc_eventtype_t last,
+ void *tag);
+ isc_result_t (*beginexclusive)(isc_task_t *task);
+ void (*endexclusive)(isc_task_t *task);
+ void (*setprivilege)(isc_task_t *task, bool priv);
+ bool (*privilege)(isc_task_t *task);
+} isc_taskmethods_t;
+
+/*%
+ * This structure is actually just the common prefix of a task manager
+ * object implementation's version of an isc_taskmgr_t.
+ * \brief
+ * Direct use of this structure by clients is forbidden. task implementations
+ * may change the structure. 'magic' must be ISCAPI_TASKMGR_MAGIC for any
+ * of the isc_task_ routines to work. task implementations must maintain
+ * all task invariants.
+ */
+struct isc_taskmgr {
+ unsigned int impmagic;
+ unsigned int magic;
+ isc_taskmgrmethods_t *methods;
+};
+
+#define ISCAPI_TASKMGR_MAGIC ISC_MAGIC('A','t','m','g')
+#define ISCAPI_TASKMGR_VALID(m) ((m) != NULL && \
+ (m)->magic == ISCAPI_TASKMGR_MAGIC)
+
+/*%
+ * This is the common prefix of a task object. The same note as
+ * that for the taskmgr structure applies.
+ */
+struct isc_task {
+ unsigned int impmagic;
+ unsigned int magic;
+ isc_taskmethods_t *methods;
+};
+
+#define ISCAPI_TASK_MAGIC ISC_MAGIC('A','t','s','t')
+#define ISCAPI_TASK_VALID(s) ((s) != NULL && \
+ (s)->magic == ISCAPI_TASK_MAGIC)
+
+isc_result_t
+isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
+ isc_task_t **taskp);
+/*%<
+ * Create a task.
+ *
+ * Notes:
+ *
+ *\li If 'quantum' is non-zero, then only that many events can be dispatched
+ * before the task must yield to other tasks waiting to execute. If
+ * quantum is zero, then the default quantum of the task manager will
+ * be used.
+ *
+ *\li The 'quantum' option may be removed from isc_task_create() in the
+ * future. If this happens, isc_task_getquantum() and
+ * isc_task_setquantum() will be provided.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid task manager.
+ *
+ *\li taskp != NULL && *taskp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, '*taskp' is bound to the new task.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ *\li #ISC_R_SHUTTINGDOWN
+ */
+
+void
+isc_task_attach(isc_task_t *source, isc_task_t **targetp);
+/*%<
+ * Attach *targetp to source.
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid task.
+ *
+ *\li 'targetp' points to a NULL isc_task_t *.
+ *
+ * Ensures:
+ *
+ *\li *targetp is attached to source.
+ */
+
+void
+isc_task_detach(isc_task_t **taskp);
+/*%<
+ * Detach *taskp from its task.
+ *
+ * Requires:
+ *
+ *\li '*taskp' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li *taskp is NULL.
+ *
+ *\li If '*taskp' is the last reference to the task, the task is idle (has
+ * an empty event queue), and has not been shutdown, the task will be
+ * shutdown.
+ *
+ *\li If '*taskp' is the last reference to the task and
+ * the task has been shutdown,
+ * all resources used by the task will be freed.
+ */
+
+void
+isc_task_send(isc_task_t *task, isc_event_t **eventp);
+/*%<
+ * Send '*event' to 'task'.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *\li eventp != NULL && *eventp != NULL.
+ *
+ * Ensures:
+ *
+ *\li *eventp == NULL.
+ */
+
+void
+isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp);
+/*%<
+ * Send '*event' to '*taskp' and then detach '*taskp' from its
+ * task.
+ *
+ * Requires:
+ *
+ *\li '*taskp' is a valid task.
+ *\li eventp != NULL && *eventp != NULL.
+ *
+ * Ensures:
+ *
+ *\li *eventp == NULL.
+ *
+ *\li *taskp == NULL.
+ *
+ *\li If '*taskp' is the last reference to the task, the task is
+ * idle (has an empty event queue), and has not been shutdown,
+ * the task will be shutdown.
+ *
+ *\li If '*taskp' is the last reference to the task and
+ * the task has been shutdown,
+ * all resources used by the task will be freed.
+ */
+
+
+unsigned int
+isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag);
+/*%<
+ * Purge events from a task's event queue.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li last >= first
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is >= first and <= last, and whose tag is 'tag' will be purged,
+ * unless they are marked as unpurgable.
+ *
+ *\li A sender of NULL will match any sender. A NULL tag matches any
+ * tag.
+ *
+ * Returns:
+ *
+ *\li The number of events purged.
+ */
+
+unsigned int
+isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag);
+/*%<
+ * Purge events from a task's event queue.
+ *
+ * Notes:
+ *
+ *\li This function is equivalent to
+ *
+ *\code
+ * isc_task_purgerange(task, sender, type, type, tag);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is 'type', and whose tag is 'tag' will be purged, unless they
+ * are marked as unpurgable.
+ *
+ *\li A sender of NULL will match any sender. A NULL tag matches any
+ * tag.
+ *
+ * Returns:
+ *
+ *\li The number of events purged.
+ */
+
+bool
+isc_task_purgeevent(isc_task_t *task, isc_event_t *event);
+/*%<
+ * Purge 'event' from a task's event queue.
+ *
+ * XXXRTH: WARNING: This method may be removed before beta.
+ *
+ * Notes:
+ *
+ *\li If 'event' is on the task's event queue, it will be purged,
+ * unless it is marked as unpurgeable. 'event' does not have to be
+ * on the task's event queue; in fact, it can even be an invalid
+ * pointer. Purging only occurs if the event is actually on the task's
+ * event queue.
+ *
+ * \li Purging never changes the state of the task.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li 'event' is not in the event queue for 'task'.
+ *
+ * Returns:
+ *
+ *\li #true The event was purged.
+ *\li #false The event was not in the event queue,
+ * or was marked unpurgeable.
+ */
+
+unsigned int
+isc_task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag, isc_eventlist_t *events);
+/*%<
+ * Remove events from a task's event queue.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li last >= first.
+ *
+ *\li *events is a valid list.
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is >= first and <= last, and whose tag is 'tag' will be dequeued
+ * and appended to *events.
+ *
+ *\li A sender of NULL will match any sender. A NULL tag matches any
+ * tag.
+ *
+ * Returns:
+ *
+ *\li The number of events unsent.
+ */
+
+unsigned int
+isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag, isc_eventlist_t *events);
+/*%<
+ * Remove events from a task's event queue.
+ *
+ * Notes:
+ *
+ *\li This function is equivalent to
+ *
+ *\code
+ * isc_task_unsendrange(task, sender, type, type, tag, events);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li *events is a valid list.
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is 'type', and whose tag is 'tag' will be dequeued and appended
+ * to *events.
+ *
+ * Returns:
+ *
+ *\li The number of events unsent.
+ */
+
+isc_result_t
+isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+/*%<
+ * Send a shutdown event with action 'action' and argument 'arg' when
+ * 'task' is shutdown.
+ *
+ * Notes:
+ *
+ *\li Shutdown events are posted in LIFO order.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li 'action' is a valid task action.
+ *
+ * Ensures:
+ *
+ *\li When the task is shutdown, shutdown events requested with
+ * isc_task_onshutdown() will be appended to the task's event queue.
+ *
+
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_SHUTTINGDOWN Task is shutting down.
+ */
+
+void
+isc_task_shutdown(isc_task_t *task);
+/*%<
+ * Shutdown 'task'.
+ *
+ * Notes:
+ *
+ *\li Shutting down a task causes any shutdown events requested with
+ * isc_task_onshutdown() to be posted (in LIFO order). The task
+ * moves into a "shutting down" mode which prevents further calls
+ * to isc_task_onshutdown().
+ *
+ *\li Trying to shutdown a task that has already been shutdown has no
+ * effect.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li Any shutdown events requested with isc_task_onshutdown() have been
+ * posted (in LIFO order).
+ */
+
+void
+isc_task_destroy(isc_task_t **taskp);
+/*%<
+ * Destroy '*taskp'.
+ *
+ * Notes:
+ *
+ *\li This call is equivalent to:
+ *
+ *\code
+ * isc_task_shutdown(*taskp);
+ * isc_task_detach(taskp);
+ *\endcode
+ *
+ * Requires:
+ *
+ * '*taskp' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li Any shutdown events requested with isc_task_onshutdown() have been
+ * posted (in LIFO order).
+ *
+ *\li *taskp == NULL
+ *
+ *\li If '*taskp' is the last reference to the task,
+ * all resources used by the task will be freed.
+ */
+
+void
+isc_task_setname(isc_task_t *task, const char *name, void *tag);
+/*%<
+ * Name 'task'.
+ *
+ * Notes:
+ *
+ *\li Only the first 15 characters of 'name' will be copied.
+ *
+ *\li Naming a task is currently only useful for debugging purposes.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ */
+
+const char *
+isc_task_getname(isc_task_t *task);
+/*%<
+ * Get the name of 'task', as previously set using isc_task_setname().
+ *
+ * Notes:
+ *\li This function is for debugging purposes only.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ *
+ * Returns:
+ *\li A non-NULL pointer to a null-terminated string.
+ * If the task has not been named, the string is
+ * empty.
+ *
+ */
+
+void *
+isc_task_gettag(isc_task_t *task);
+/*%<
+ * Get the tag value for 'task', as previously set using isc_task_settag().
+ *
+ * Notes:
+ *\li This function is for debugging purposes only.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+isc_result_t
+isc_task_beginexclusive(isc_task_t *task);
+/*%<
+ * Request exclusive access for 'task', which must be the calling
+ * task. Waits for any other concurrently executing tasks to finish their
+ * current event, and prevents any new events from executing in any of the
+ * tasks sharing a task manager with 'task'.
+ *
+ * The exclusive access must be relinquished by calling
+ * isc_task_endexclusive() before returning from the current event handler.
+ *
+ * Requires:
+ *\li 'task' is the calling task.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS The current task now has exclusive access.
+ *\li #ISC_R_LOCKBUSY Another task has already requested exclusive
+ * access.
+ */
+
+void
+isc_task_endexclusive(isc_task_t *task);
+/*%<
+ * Relinquish the exclusive access obtained by isc_task_beginexclusive(),
+ * allowing other tasks to execute.
+ *
+ * Requires:
+ *\li 'task' is the calling task, and has obtained
+ * exclusive access by calling isc_task_spl().
+ */
+
+void
+isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t);
+void
+isc_task_getcurrenttimex(isc_task_t *task, isc_time_t *t);
+/*%<
+ * Provide the most recent timestamp on the task. The timestamp is considered
+ * as the "current time".
+ *
+ * isc_task_getcurrentime() returns the time in one-second granularity;
+ * isc_task_getcurrentimex() returns it in nanosecond granularity.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ *\li 't' is a valid non NULL pointer.
+ *
+ * Ensures:
+ *\li '*t' has the "current time".
+ */
+
+bool
+isc_task_exiting(isc_task_t *t);
+/*%<
+ * Returns true if the task is in the process of shutting down,
+ * false otherwise.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+void
+isc_task_setprivilege(isc_task_t *task, bool priv);
+/*%<
+ * Set or unset the task's "privileged" flag depending on the value of
+ * 'priv'.
+ *
+ * Under normal circumstances this flag has no effect on the task behavior,
+ * but when the task manager has been set to privileged execution mode via
+ * isc_taskmgr_setmode(), only tasks with the flag set will be executed,
+ * and all other tasks will wait until they're done. Once all privileged
+ * tasks have finished executing, the task manager will automatically
+ * return to normal execution mode and nonprivileged task can resume.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+bool
+isc_task_privilege(isc_task_t *task);
+/*%<
+ * Returns the current value of the task's privilege flag.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+/*****
+ ***** Task Manager.
+ *****/
+
+isc_result_t
+isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
+ unsigned int workers, unsigned int default_quantum,
+ isc_taskmgr_t **managerp);
+isc_result_t
+isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
+ unsigned int default_quantum, isc_taskmgr_t **managerp);
+/*%<
+ * Create a new task manager. isc_taskmgr_createinctx() also associates
+ * the new manager with the specified application context.
+ *
+ * Notes:
+ *
+ *\li 'workers' in the number of worker threads to create. In general,
+ * the value should be close to the number of processors in the system.
+ * The 'workers' value is advisory only. An attempt will be made to
+ * create 'workers' threads, but if at least one thread creation
+ * succeeds, isc_taskmgr_create() may return ISC_R_SUCCESS.
+ *
+ *\li If 'default_quantum' is non-zero, then it will be used as the default
+ * quantum value when tasks are created. If zero, then an implementation
+ * defined default quantum will be used.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li workers > 0
+ *
+ *\li managerp != NULL && *managerp == NULL
+ *
+ *\li 'actx' is a valid application context (for createinctx()).
+ *
+ * Ensures:
+ *
+ *\li On success, '*managerp' will be attached to the newly created task
+ * manager.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_NOTHREADS No threads could be created.
+ *\li #ISC_R_UNEXPECTED An unexpected error occurred.
+ *\li #ISC_R_SHUTTINGDOWN The non-threaded, shared, task
+ * manager shutting down.
+ */
+
+void
+isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode);
+
+isc_taskmgrmode_t
+isc_taskmgr_mode(isc_taskmgr_t *manager);
+/*%<
+ * Set/get the current operating mode of the task manager. Valid modes are:
+ *
+ *\li isc_taskmgrmode_normal
+ *\li isc_taskmgrmode_privileged
+ *
+ * In privileged execution mode, only tasks that have had the "privilege"
+ * flag set via isc_task_setprivilege() can be executed. When all such
+ * tasks are complete, the manager automatically returns to normal mode
+ * and proceeds with running non-privileged ready tasks. This means it is
+ * necessary to have at least one privileged task waiting on the ready
+ * queue *before* setting the manager into privileged execution mode,
+ * which in turn means the task which calls this function should be in
+ * task-exclusive mode when it does so.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid task manager.
+ */
+
+void
+isc_taskmgr_destroy(isc_taskmgr_t **managerp);
+/*%<
+ * Destroy '*managerp'.
+ *
+ * Notes:
+ *
+ *\li Calling isc_taskmgr_destroy() will shutdown all tasks managed by
+ * *managerp that haven't already been shutdown. The call will block
+ * until all tasks have entered the done state.
+ *
+ *\li isc_taskmgr_destroy() must not be called by a task event action,
+ * because it would block forever waiting for the event action to
+ * complete. An event action that wants to cause task manager shutdown
+ * should request some non-event action thread of execution to do the
+ * shutdown, e.g. by signaling a condition variable or using
+ * isc_app_shutdown().
+ *
+ *\li Task manager references are not reference counted, so the caller
+ * must ensure that no attempt will be made to use the manager after
+ * isc_taskmgr_destroy() returns.
+ *
+ * Requires:
+ *
+ *\li '*managerp' is a valid task manager.
+ *
+ *\li isc_taskmgr_destroy() has not be called previously on '*managerp'.
+ *
+ * Ensures:
+ *
+ *\li All resources used by the task manager, and any tasks it managed,
+ * have been freed.
+ */
+
+void
+isc_taskmgr_setexcltask(isc_taskmgr_t *mgr, isc_task_t *task);
+/*%<
+ * Set a task which will be used for all task-exclusive operations.
+ *
+ * Requires:
+ *\li 'manager' is a valid task manager.
+ *
+ *\li 'task' is a valid task.
+ */
+
+isc_result_t
+isc_taskmgr_excltask(isc_taskmgr_t *mgr, isc_task_t **taskp);
+/*%<
+ * Attach '*taskp' to the task set by isc_taskmgr_getexcltask().
+ * This task should be used whenever running in task-exclusive mode,
+ * so as to prevent deadlock between two exclusive tasks.
+ *
+ * Requires:
+ *\li 'manager' is a valid task manager.
+
+ *\li taskp != NULL && *taskp == NULL
+ */
+
+
+#ifdef HAVE_LIBXML2
+int
+isc_taskmgr_renderxml(isc_taskmgr_t *mgr, xmlTextWriterPtr writer);
+#endif
+
+#ifdef HAVE_JSON
+isc_result_t
+isc_taskmgr_renderjson(isc_taskmgr_t *mgr, json_object *tasksobj);
+#endif
+
+/*%<
+ * See isc_taskmgr_create() above.
+ */
+typedef isc_result_t
+(*isc_taskmgrcreatefunc_t)(isc_mem_t *mctx, unsigned int workers,
+ unsigned int default_quantum,
+ isc_taskmgr_t **managerp);
+
+isc_result_t
+isc_task_register(isc_taskmgrcreatefunc_t createfunc);
+/*%<
+ * Register a new task management implementation and add it to the list of
+ * supported implementations. This function must be called when a different
+ * event library is used than the one contained in the ISC library.
+ */
+
+isc_result_t
+isc__task_register(void);
+/*%<
+ * A short cut function that specifies the task management module in the ISC
+ * library for isc_task_register(). An application that uses the ISC library
+ * usually do not have to care about this function: it would call
+ * isc_lib_register(), which internally calls this function.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TASK_H */
diff --git a/lib/isc/include/isc/taskpool.h b/lib/isc/include/isc/taskpool.h
new file mode 100644
index 0000000..32ca594
--- /dev/null
+++ b/lib/isc/include/isc/taskpool.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_TASKPOOL_H
+#define ISC_TASKPOOL_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/taskpool.h
+ * \brief A task pool is a mechanism for sharing a small number of tasks
+ * among a large number of objects such that each object is
+ * assigned a unique task, but each task may be shared by several
+ * objects.
+ *
+ * Task pools are used to let objects that can exist in large
+ * numbers (e.g., zones) use tasks for synchronization without
+ * the memory overhead and unfair scheduling competition that
+ * could result from creating a separate task for each object.
+ */
+
+
+/***
+ *** Imports.
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/task.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Types.
+ *****/
+
+typedef struct isc_taskpool isc_taskpool_t;
+
+/*****
+ ***** Functions.
+ *****/
+
+isc_result_t
+isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx,
+ unsigned int ntasks, unsigned int quantum,
+ isc_taskpool_t **poolp);
+/*%<
+ * Create a task pool of "ntasks" tasks, each with quantum
+ * "quantum".
+ *
+ * Requires:
+ *
+ *\li 'tmgr' is a valid task manager.
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li poolp != NULL && *poolp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, '*taskp' points to the new task pool.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ */
+
+void
+isc_taskpool_gettask(isc_taskpool_t *pool, isc_task_t **targetp);
+/*%<
+ * Attach to a task from the pool. Currently the next task is chosen
+ * from the pool at random. (This may be changed in the future to
+ * something that guaratees balance.)
+ */
+
+int
+isc_taskpool_size(isc_taskpool_t *pool);
+/*%<
+ * Returns the number of tasks in the task pool 'pool'.
+ */
+
+isc_result_t
+isc_taskpool_expand(isc_taskpool_t **sourcep, unsigned int size,
+ isc_taskpool_t **targetp);
+
+/*%<
+ * If 'size' is larger than the number of tasks in the pool pointed to by
+ * 'sourcep', then a new taskpool of size 'size' is allocated, the existing
+ * tasks from are moved into it, additional tasks are created to bring the
+ * total number up to 'size', and the resulting pool is attached to
+ * 'targetp'.
+ *
+ * If 'size' is less than or equal to the tasks in pool 'source', then
+ * 'sourcep' is attached to 'targetp' without any other action being taken.
+ *
+ * In either case, 'sourcep' is detached.
+ *
+ * Requires:
+ *
+ * \li 'sourcep' is not NULL and '*source' is not NULL
+ * \li 'targetp' is not NULL and '*source' is NULL
+ *
+ * Ensures:
+ *
+ * \li On success, '*targetp' points to a valid task pool.
+ * \li On success, '*sourcep' points to NULL.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ */
+
+void
+isc_taskpool_destroy(isc_taskpool_t **poolp);
+/*%<
+ * Destroy a task pool. The tasks in the pool are detached but not
+ * shut down.
+ *
+ * Requires:
+ * \li '*poolp' is a valid task pool.
+ */
+
+void
+isc_taskpool_setprivilege(isc_taskpool_t *pool, bool priv);
+/*%<
+ * Set the privilege flag on all tasks in 'pool' to 'priv'. If 'priv' is
+ * true, then when the task manager is set into privileged mode, only
+ * tasks wihin this pool will be able to execute. (Note: It is important
+ * to turn the pool tasks' privilege back off before the last task finishes
+ * executing.)
+ *
+ * Requires:
+ * \li 'pool' is a valid task pool.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TASKPOOL_H */
diff --git a/lib/isc/include/isc/timer.h b/lib/isc/include/isc/timer.h
new file mode 100644
index 0000000..40aa5a6
--- /dev/null
+++ b/lib/isc/include/isc/timer.h
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_TIMER_H
+#define ISC_TIMER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/timer.h
+ * \brief Provides timers which are event sources in the task system.
+ *
+ * Three types of timers are supported:
+ *
+ *\li 'ticker' timers generate a periodic tick event.
+ *
+ *\li 'once' timers generate an idle timeout event if they are idle for too
+ * long, and generate a life timeout event if their lifetime expires.
+ * They are used to implement both (possibly expiring) idle timers and
+ * 'one-shot' timers.
+ *
+ *\li 'limited' timers generate a periodic tick event until they reach
+ * their lifetime when they generate a life timeout event.
+ *
+ *\li 'inactive' timers generate no events.
+ *
+ * Timers can change type. It is typical to create a timer as
+ * an 'inactive' timer and then change it into a 'ticker' or
+ * 'once' timer.
+ *
+ *\li MP:
+ * The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ * Clients of this module must not be holding a timer's task's lock when
+ * making a call that affects that timer. Failure to follow this rule
+ * can result in deadlock.
+ * The caller must ensure that isc_timermgr_destroy() is called only
+ * once for a given manager.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+
+/***
+ *** Imports
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/types.h>
+#include <isc/event.h>
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+#include <isc/time.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+/*% Timer Type */
+typedef enum {
+ isc_timertype_undefined = -1, /*%< Undefined */
+ isc_timertype_ticker = 0, /*%< Ticker */
+ isc_timertype_once = 1, /*%< Once */
+ isc_timertype_limited = 2, /*%< Limited */
+ isc_timertype_inactive = 3 /*%< Inactive */
+} isc_timertype_t;
+
+typedef struct isc_timerevent {
+ struct isc_event common;
+ isc_time_t due;
+} isc_timerevent_t;
+
+#define ISC_TIMEREVENT_FIRSTEVENT (ISC_EVENTCLASS_TIMER + 0)
+#define ISC_TIMEREVENT_TICK (ISC_EVENTCLASS_TIMER + 1)
+#define ISC_TIMEREVENT_IDLE (ISC_EVENTCLASS_TIMER + 2)
+#define ISC_TIMEREVENT_LIFE (ISC_EVENTCLASS_TIMER + 3)
+#define ISC_TIMEREVENT_LASTEVENT (ISC_EVENTCLASS_TIMER + 65535)
+
+/*% Timer and timer manager methods */
+typedef struct {
+ void (*destroy)(isc_timermgr_t **managerp);
+ isc_result_t (*timercreate)(isc_timermgr_t *manager,
+ isc_timertype_t type,
+ const isc_time_t *expires,
+ const isc_interval_t *interval,
+ isc_task_t *task,
+ isc_taskaction_t action,
+ void *arg,
+ isc_timer_t **timerp);
+} isc_timermgrmethods_t;
+
+typedef struct {
+ void (*attach)(isc_timer_t *timer, isc_timer_t **timerp);
+ void (*detach)(isc_timer_t **timerp);
+ isc_result_t (*reset)(isc_timer_t *timer, isc_timertype_t type,
+ const isc_time_t *expires,
+ const isc_interval_t *interval,
+ bool purge);
+ isc_result_t (*touch)(isc_timer_t *timer);
+} isc_timermethods_t;
+
+/*%
+ * This structure is actually just the common prefix of a timer manager
+ * object implementation's version of an isc_timermgr_t.
+ * \brief
+ * Direct use of this structure by clients is forbidden. timer implementations
+ * may change the structure. 'magic' must be ISCAPI_TIMERMGR_MAGIC for any
+ * of the isc_timer_ routines to work. timer implementations must maintain
+ * all timer invariants.
+ */
+struct isc_timermgr {
+ unsigned int impmagic;
+ unsigned int magic;
+ isc_timermgrmethods_t *methods;
+};
+
+#define ISCAPI_TIMERMGR_MAGIC ISC_MAGIC('A','t','m','g')
+#define ISCAPI_TIMERMGR_VALID(m) ((m) != NULL && \
+ (m)->magic == ISCAPI_TIMERMGR_MAGIC)
+
+/*%
+ * This is the common prefix of a timer object. The same note as
+ * that for the timermgr structure applies.
+ */
+struct isc_timer {
+ unsigned int impmagic;
+ unsigned int magic;
+ isc_timermethods_t *methods;
+};
+
+#define ISCAPI_TIMER_MAGIC ISC_MAGIC('A','t','m','r')
+#define ISCAPI_TIMER_VALID(s) ((s) != NULL && \
+ (s)->magic == ISCAPI_TIMER_MAGIC)
+
+/***
+ *** Timer and Timer Manager Functions
+ ***
+ *** Note: all Ensures conditions apply only if the result is success for
+ *** those functions which return an isc_result_t.
+ ***/
+
+isc_result_t
+isc_timer_create(isc_timermgr_t *manager,
+ isc_timertype_t type,
+ const isc_time_t *expires,
+ const isc_interval_t *interval,
+ isc_task_t *task,
+ isc_taskaction_t action,
+ void *arg,
+ isc_timer_t **timerp);
+/*%<
+ * Create a new 'type' timer managed by 'manager'. The timers parameters
+ * are specified by 'expires' and 'interval'. Events will be posted to
+ * 'task' and when dispatched 'action' will be called with 'arg' as the
+ * arg value. The new timer is returned in 'timerp'.
+ *
+ * Notes:
+ *
+ *\li For ticker timers, the timer will generate a 'tick' event every
+ * 'interval' seconds. The value of 'expires' is ignored.
+ *
+ *\li For once timers, 'expires' specifies the time when a life timeout
+ * event should be generated. If 'expires' is 0 (the epoch), then no life
+ * timeout will be generated. 'interval' specifies how long the timer
+ * can be idle before it generates an idle timeout. If 0, then no
+ * idle timeout will be generated.
+ *
+ *\li If 'expires' is NULL, the epoch will be used.
+ *
+ * If 'interval' is NULL, the zero interval will be used.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid manager
+ *
+ *\li 'task' is a valid task
+ *
+ *\li 'action' is a valid action
+ *
+ *\li 'expires' points to a valid time, or is NULL.
+ *
+ *\li 'interval' points to a valid interval, or is NULL.
+ *
+ *\li type == isc_timertype_inactive ||
+ * ('expires' and 'interval' are not both 0)
+ *
+ *\li 'timerp' is a valid pointer, and *timerp == NULL
+ *
+ * Ensures:
+ *
+ *\li '*timerp' is attached to the newly created timer
+ *
+ *\li The timer is attached to the task
+ *
+ *\li An idle timeout will not be generated until at least Now + the
+ * timer's interval if 'timer' is a once timer with a non-zero
+ * interval.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li No memory
+ *\li Unexpected error
+ */
+
+isc_result_t
+isc_timer_reset(isc_timer_t *timer,
+ isc_timertype_t type,
+ const isc_time_t *expires,
+ const isc_interval_t *interval,
+ bool purge);
+/*%<
+ * Change the timer's type, expires, and interval values to the given
+ * values. If 'purge' is TRUE, any pending events from this timer
+ * are purged from its task's event queue.
+ *
+ * Notes:
+ *
+ *\li If 'expires' is NULL, the epoch will be used.
+ *
+ *\li If 'interval' is NULL, the zero interval will be used.
+ *
+ * Requires:
+ *
+ *\li 'timer' is a valid timer
+ *
+ *\li The same requirements that isc_timer_create() imposes on 'type',
+ * 'expires' and 'interval' apply.
+ *
+ * Ensures:
+ *
+ *\li An idle timeout will not be generated until at least Now + the
+ * timer's interval if 'timer' is a once timer with a non-zero
+ * interval.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li No memory
+ *\li Unexpected error
+ */
+
+isc_result_t
+isc_timer_touch(isc_timer_t *timer);
+/*%<
+ * Set the last-touched time of 'timer' to the current time.
+ *
+ * Requires:
+ *
+ *\li 'timer' is a valid once timer.
+ *
+ * Ensures:
+ *
+ *\li An idle timeout will not be generated until at least Now + the
+ * timer's interval if 'timer' is a once timer with a non-zero
+ * interval.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ */
+
+void
+isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp);
+/*%<
+ * Attach *timerp to timer.
+ *
+ * Requires:
+ *
+ *\li 'timer' is a valid timer.
+ *
+ *\li 'timerp' points to a NULL timer.
+ *
+ * Ensures:
+ *
+ *\li *timerp is attached to timer.
+ */
+
+void
+isc_timer_detach(isc_timer_t **timerp);
+/*%<
+ * Detach *timerp from its timer.
+ *
+ * Requires:
+ *
+ *\li 'timerp' points to a valid timer.
+ *
+ * Ensures:
+ *
+ *\li *timerp is NULL.
+ *
+ *\li If '*timerp' is the last reference to the timer,
+ * then:
+ *
+ *\code
+ * The timer will be shutdown
+ *
+ * The timer will detach from its task
+ *
+ * All resources used by the timer have been freed
+ *
+ * Any events already posted by the timer will be purged.
+ * Therefore, if isc_timer_detach() is called in the context
+ * of the timer's task, it is guaranteed that no more
+ * timer event callbacks will run after the call.
+ *\endcode
+ */
+
+isc_timertype_t
+isc_timer_gettype(isc_timer_t *timer);
+/*%<
+ * Return the timer type.
+ *
+ * Requires:
+ *
+ *\li 'timer' to be a valid timer.
+ */
+
+isc_result_t
+isc_timermgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
+ isc_timermgr_t **managerp);
+
+isc_result_t
+isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp);
+/*%<
+ * Create a timer manager. isc_timermgr_createinctx() also associates
+ * the new manager with the specified application context.
+ *
+ * Notes:
+ *
+ *\li All memory will be allocated in memory context 'mctx'.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li 'managerp' points to a NULL isc_timermgr_t.
+ *
+ *\li 'actx' is a valid application context (for createinctx()).
+ *
+ * Ensures:
+ *
+ *\li '*managerp' is a valid isc_timermgr_t.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li No memory
+ *\li Unexpected error
+ */
+
+void
+isc_timermgr_destroy(isc_timermgr_t **managerp);
+/*%<
+ * Destroy a timer manager.
+ *
+ * Notes:
+ *
+ *\li This routine blocks until there are no timers left in the manager,
+ * so if the caller holds any timer references using the manager, it
+ * must detach them before calling isc_timermgr_destroy() or it will
+ * block forever.
+ *
+ * Requires:
+ *
+ *\li '*managerp' is a valid isc_timermgr_t.
+ *
+ * Ensures:
+ *
+ *\li *managerp == NULL
+ *
+ *\li All resources used by the manager have been freed.
+ */
+
+void isc_timermgr_poke(isc_timermgr_t *m);
+
+/*%<
+ * See isc_timermgr_create() above.
+ */
+typedef isc_result_t
+(*isc_timermgrcreatefunc_t)(isc_mem_t *mctx, isc_timermgr_t **managerp);
+
+isc_result_t
+isc__timer_register(void);
+/*%<
+ * Register a new timer management implementation and add it to the list of
+ * supported implementations. This function must be called when a different
+ * event library is used than the one contained in the ISC library.
+ */
+
+isc_result_t
+isc_timer_register(isc_timermgrcreatefunc_t createfunc);
+/*%<
+ * A short cut function that specifies the timer management module in the ISC
+ * library for isc_timer_register(). An application that uses the ISC library
+ * usually do not have to care about this function: it would call
+ * isc_lib_register(), which internally calls this function.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TIMER_H */
diff --git a/lib/isc/include/isc/tm.h b/lib/isc/include/isc/tm.h
new file mode 100644
index 0000000..b6f520c
--- /dev/null
+++ b/lib/isc/include/isc/tm.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_TM_H
+#define ISC_TM_H 1
+
+/*! \file isc/tm.h
+ * Provides portable conversion routines for struct tm.
+ */
+#include <time.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+
+ISC_LANG_BEGINDECLS
+
+time_t
+isc_tm_timegm(struct tm *tm);
+/*
+ * Convert a tm structure to time_t, using UTC rather than the local
+ * time zone.
+ */
+
+char *
+isc_tm_strptime(const char *buf, const char *fmt, struct tm *tm);
+/*
+ * Parse a formatted date string into struct tm.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TIMER_H */
diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h
new file mode 100644
index 0000000..42ff7e0
--- /dev/null
+++ b/lib/isc/include/isc/types.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id$ */
+
+#ifndef ISC_TYPES_H
+#define ISC_TYPES_H 1
+
+#include <stdbool.h>
+
+#include <isc/bind9.h>
+
+/*! \file isc/types.h
+ * \brief
+ * OS-specific types, from the OS-specific include directories.
+ */
+#include <inttypes.h>
+#include <isc/offset.h>
+
+/*
+ * XXXDCL should bool be moved here, requiring an explicit include
+ */
+/*
+ * XXXDCL This is just for ISC_LIST and ISC_LINK, but gets all of the other
+ * list macros too.
+ */
+#include <isc/list.h>
+
+/* Core Types. Alphabetized by defined type. */
+
+typedef struct isc_appctx isc_appctx_t; /*%< Application context */
+typedef struct isc_backtrace_symmap isc_backtrace_symmap_t; /*%< Symbol Table Entry */
+typedef struct isc_buffer isc_buffer_t; /*%< Buffer */
+typedef ISC_LIST(isc_buffer_t) isc_bufferlist_t; /*%< Buffer List */
+typedef struct isc_constregion isc_constregion_t; /*%< Const region */
+typedef struct isc_consttextregion isc_consttextregion_t; /*%< Const Text Region */
+typedef struct isc_counter isc_counter_t; /*%< Counter */
+typedef int16_t isc_dscp_t; /*%< Diffserv code point */
+typedef struct isc_entropy isc_entropy_t; /*%< Entropy */
+typedef struct isc_entropysource isc_entropysource_t; /*%< Entropy Source */
+typedef struct isc_event isc_event_t; /*%< Event */
+typedef ISC_LIST(isc_event_t) isc_eventlist_t; /*%< Event List */
+typedef unsigned int isc_eventtype_t; /*%< Event Type */
+typedef uint32_t isc_fsaccess_t; /*%< FS Access */
+typedef struct isc_hash isc_hash_t; /*%< Hash */
+typedef struct isc_httpd isc_httpd_t; /*%< HTTP client */
+typedef void (isc_httpdfree_t)(isc_buffer_t *, void *); /*%< HTTP free function */
+typedef struct isc_httpdmgr isc_httpdmgr_t; /*%< HTTP manager */
+typedef struct isc_httpdurl isc_httpdurl_t; /*%< HTTP URL */
+typedef void (isc_httpdondestroy_t)(void *); /*%< Callback on destroying httpd */
+typedef struct isc_interface isc_interface_t; /*%< Interface */
+typedef struct isc_interfaceiter isc_interfaceiter_t; /*%< Interface Iterator */
+typedef struct isc_interval isc_interval_t; /*%< Interval */
+typedef struct isc_lex isc_lex_t; /*%< Lex */
+typedef struct isc_log isc_log_t; /*%< Log */
+typedef struct isc_logcategory isc_logcategory_t; /*%< Log Category */
+typedef struct isc_logconfig isc_logconfig_t; /*%< Log Configuration */
+typedef struct isc_logmodule isc_logmodule_t; /*%< Log Module */
+typedef struct isc_mem isc_mem_t; /*%< Memory */
+typedef struct isc_mempool isc_mempool_t; /*%< Memory Pool */
+typedef struct isc_msgcat isc_msgcat_t; /*%< Message Catalog */
+typedef struct isc_ondestroy isc_ondestroy_t; /*%< On Destroy */
+typedef struct isc_netaddr isc_netaddr_t; /*%< Net Address */
+typedef struct isc_portset isc_portset_t; /*%< Port Set */
+typedef struct isc_quota isc_quota_t; /*%< Quota */
+typedef struct isc_random isc_random_t; /*%< Random */
+typedef struct isc_ratelimiter isc_ratelimiter_t; /*%< Rate Limiter */
+typedef struct isc_region isc_region_t; /*%< Region */
+typedef uint64_t isc_resourcevalue_t; /*%< Resource Value */
+typedef unsigned int isc_result_t; /*%< Result */
+typedef struct isc_rwlock isc_rwlock_t; /*%< Read Write Lock */
+typedef struct isc_sockaddr isc_sockaddr_t; /*%< Socket Address */
+typedef ISC_LIST(isc_sockaddr_t) isc_sockaddrlist_t; /*%< Socket Address List */
+typedef struct isc_socket isc_socket_t; /*%< Socket */
+typedef struct isc_socketevent isc_socketevent_t; /*%< Socket Event */
+typedef struct isc_socketmgr isc_socketmgr_t; /*%< Socket Manager */
+typedef struct isc_stats isc_stats_t; /*%< Statistics */
+typedef int isc_statscounter_t; /*%< Statistics Counter */
+typedef struct isc_symtab isc_symtab_t; /*%< Symbol Table */
+typedef struct isc_task isc_task_t; /*%< Task */
+typedef ISC_LIST(isc_task_t) isc_tasklist_t; /*%< Task List */
+typedef struct isc_taskmgr isc_taskmgr_t; /*%< Task Manager */
+typedef struct isc_textregion isc_textregion_t; /*%< Text Region */
+typedef struct isc_time isc_time_t; /*%< Time */
+typedef struct isc_timer isc_timer_t; /*%< Timer */
+typedef struct isc_timermgr isc_timermgr_t; /*%< Timer Manager */
+
+typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *);
+typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *, int);
+
+/* The following cannot be listed alphabetically due to forward reference */
+typedef isc_result_t (isc_httpdaction_t)(const char *url,
+ isc_httpdurl_t *urlinfo,
+ const char *querystring,
+ const char *headers,
+ void *arg,
+ unsigned int *retcode,
+ const char **retmsg,
+ const char **mimetype,
+ isc_buffer_t *body,
+ isc_httpdfree_t **freecb,
+ void **freecb_args);
+typedef bool (isc_httpdclientok_t)(const isc_sockaddr_t *, void *);
+
+/*% Resource */
+typedef enum {
+ isc_resource_coresize = 1,
+ isc_resource_cputime,
+ isc_resource_datasize,
+ isc_resource_filesize,
+ isc_resource_lockedmemory,
+ isc_resource_openfiles,
+ isc_resource_processes,
+ isc_resource_residentsize,
+ isc_resource_stacksize
+} isc_resource_t;
+
+/*% Statistics formats (text file or XML) */
+typedef enum {
+ isc_statsformat_file,
+ isc_statsformat_xml,
+ isc_statsformat_json
+} isc_statsformat_t;
+
+#endif /* ISC_TYPES_H */
diff --git a/lib/isc/include/isc/util.h b/lib/isc/include/isc/util.h
new file mode 100644
index 0000000..75a63c1
--- /dev/null
+++ b/lib/isc/include/isc/util.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_UTIL_H
+#define ISC_UTIL_H 1
+
+/*! \file isc/util.h
+ * NOTE:
+ *
+ * This file is not to be included from any <isc/???.h> (or other) library
+ * files.
+ *
+ * \brief
+ * Including this file puts several macros in your name space that are
+ * not protected (as all the other ISC functions/macros do) by prepending
+ * ISC_ or isc_ to the name.
+ */
+
+/***
+ *** General Macros.
+ ***/
+
+/*%
+ * Use this to hide unused function arguments.
+ * \code
+ * int
+ * foo(char *bar)
+ * {
+ * UNUSED(bar);
+ * }
+ * \endcode
+ */
+#define UNUSED(x) (void)(x)
+
+/*%
+ * The opposite: silent warnings about stored values which are never read.
+ */
+#define POST(x) (void)(x)
+
+#define ISC_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define ISC_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#define ISC_CLAMP(v, x, y) ((v) < (x) ? (x) : ((v) > (y) ? (y) : (v)))
+
+/*%
+ * Use this to remove the const qualifier of a variable to assign it to
+ * a non-const variable or pass it as a non-const function argument ...
+ * but only when you are sure it won't then be changed!
+ * This is necessary to sometimes shut up some compilers
+ * (as with gcc -Wcast-qual) when there is just no other good way to avoid the
+ * situation.
+ */
+#define DE_CONST(konst, var) \
+ do { \
+ union { const void *k; void *v; } _u; \
+ _u.k = konst; \
+ var = _u.v; \
+ } while (0)
+
+/*%
+ * Use this in translation units that would otherwise be empty, to
+ * suppress compiler warnings.
+ */
+#define EMPTY_TRANSLATION_UNIT static void isc__empty(void) { isc__empty(); }
+
+/*%
+ * We use macros instead of calling the routines directly because
+ * the capital letters make the locking stand out.
+ * We RUNTIME_CHECK for success since in general there's no way
+ * for us to continue if they fail.
+ */
+
+#ifdef ISC_UTIL_TRACEON
+#define ISC_UTIL_TRACE(a) a
+#include <stdio.h> /* Required for fprintf/stderr when tracing. */
+#include <isc/msgs.h> /* Required for isc_msgcat when tracing. */
+#else
+#define ISC_UTIL_TRACE(a)
+#endif
+
+#include <isc/result.h> /* Contractual promise. */
+
+#define LOCK(lp) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_LOCKING, "LOCKING"), \
+ (lp), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_mutex_lock((lp)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_LOCKED, "LOCKED"), \
+ (lp), __FILE__, __LINE__)); \
+ } while (0)
+#define UNLOCK(lp) do { \
+ RUNTIME_CHECK(isc_mutex_unlock((lp)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_UNLOCKED, "UNLOCKED"), \
+ (lp), __FILE__, __LINE__)); \
+ } while (0)
+#define ISLOCKED(lp) (1)
+#define DESTROYLOCK(lp) \
+ RUNTIME_CHECK(isc_mutex_destroy((lp)) == ISC_R_SUCCESS)
+
+
+#define BROADCAST(cvp) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_BROADCAST, "BROADCAST"),\
+ (cvp), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_condition_broadcast((cvp)) == ISC_R_SUCCESS); \
+ } while (0)
+#define SIGNAL(cvp) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_SIGNAL, "SIGNAL"), \
+ (cvp), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_condition_signal((cvp)) == ISC_R_SUCCESS); \
+ } while (0)
+#define WAIT(cvp, lp) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_UTILWAIT, "WAIT"), \
+ (cvp), \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_LOCK, "LOCK"), \
+ (lp), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_condition_wait((cvp), (lp)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_WAITED, "WAITED"), \
+ (cvp), \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_LOCKED, "LOCKED"), \
+ (lp), __FILE__, __LINE__)); \
+ } while (0)
+
+/*
+ * isc_condition_waituntil can return ISC_R_TIMEDOUT, so we
+ * don't RUNTIME_CHECK the result.
+ *
+ * XXX Also, can't really debug this then...
+ */
+
+#define WAITUNTIL(cvp, lp, tp) \
+ isc_condition_waituntil((cvp), (lp), (tp))
+
+#define RWLOCK(lp, t) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p, %d %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_RWLOCK, "RWLOCK"), \
+ (lp), (t), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_rwlock_lock((lp), (t)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p, %d %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_RWLOCKED, "RWLOCKED"), \
+ (lp), (t), __FILE__, __LINE__)); \
+ } while (0)
+#define RWUNLOCK(lp, t) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p, %d %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_RWUNLOCK, "RWUNLOCK"), \
+ (lp), (t), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_rwlock_unlock((lp), (t)) == ISC_R_SUCCESS); \
+ } while (0)
+
+#define DESTROYMUTEXBLOCK(bp, n) \
+ RUNTIME_CHECK(isc_mutexblock_destroy((bp), (n)) == ISC_R_SUCCESS)
+
+/*
+ * List Macros.
+ */
+#include <isc/list.h> /* Contractual promise. */
+
+#define LIST(type) ISC_LIST(type)
+#define INIT_LIST(type) ISC_LIST_INIT(type)
+#define LINK(type) ISC_LINK(type)
+#define INIT_LINK(elt, link) ISC_LINK_INIT(elt, link)
+#define HEAD(list) ISC_LIST_HEAD(list)
+#define TAIL(list) ISC_LIST_TAIL(list)
+#define EMPTY(list) ISC_LIST_EMPTY(list)
+#define PREV(elt, link) ISC_LIST_PREV(elt, link)
+#define NEXT(elt, link) ISC_LIST_NEXT(elt, link)
+#define APPEND(list, elt, link) ISC_LIST_APPEND(list, elt, link)
+#define PREPEND(list, elt, link) ISC_LIST_PREPEND(list, elt, link)
+#define UNLINK(list, elt, link) ISC_LIST_UNLINK(list, elt, link)
+#define ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link)
+#define DEQUEUE(list, elt, link) ISC_LIST_UNLINK(list, elt, link)
+#define INSERTBEFORE(li, b, e, ln) ISC_LIST_INSERTBEFORE(li, b, e, ln)
+#define INSERTAFTER(li, a, e, ln) ISC_LIST_INSERTAFTER(li, a, e, ln)
+#define APPENDLIST(list1, list2, link) ISC_LIST_APPENDLIST(list1, list2, link)
+
+/*%
+ * Performance
+ */
+#include <isc/likely.h>
+
+/*
+ * Assertions
+ */
+#include <isc/assertions.h> /* Contractual promise. */
+
+/*% Require Assertion */
+#define REQUIRE(e) ISC_REQUIRE(e)
+/*% Ensure Assertion */
+#define ENSURE(e) ISC_ENSURE(e)
+/*% Insist Assertion */
+#define INSIST(e) ISC_INSIST(e)
+/*% Invariant Assertion */
+#define INVARIANT(e) ISC_INVARIANT(e)
+
+/*
+ * Errors
+ */
+#include <isc/error.h> /* Contractual promise. */
+
+/*% Unexpected Error */
+#define UNEXPECTED_ERROR isc_error_unexpected
+/*% Fatal Error */
+#define FATAL_ERROR isc_error_fatal
+/*% Runtime Check */
+#define RUNTIME_CHECK(cond) ISC_ERROR_RUNTIMECHECK(cond)
+
+/*%
+ * Time
+ */
+#define TIME_NOW(tp) RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS)
+
+/*%
+ * Alignment
+ */
+#define ISC_ALIGN(x, a) (((x) + (a) - 1) & ~((typeof(x))(a)-1))
+
+/*%
+ * Misc
+ */
+#include <isc/deprecated.h>
+
+#endif /* ISC_UTIL_H */
diff --git a/lib/isc/include/isc/version.h b/lib/isc/include/isc/version.h
new file mode 100644
index 0000000..d371e0d
--- /dev/null
+++ b/lib/isc/include/isc/version.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file isc/version.h */
+
+#include <isc/platform.h>
+
+LIBISC_EXTERNAL_DATA extern const char isc_version[];
+
+LIBISC_EXTERNAL_DATA extern const unsigned int isc_libinterface;
+LIBISC_EXTERNAL_DATA extern const unsigned int isc_librevision;
+LIBISC_EXTERNAL_DATA extern const unsigned int isc_libage;
diff --git a/lib/isc/include/isc/xml.h b/lib/isc/include/isc/xml.h
new file mode 100644
index 0000000..a091d30
--- /dev/null
+++ b/lib/isc/include/isc/xml.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_XML_H
+#define ISC_XML_H 1
+
+/*
+ * This file is here mostly to make it easy to add additional libxml header
+ * files as needed across all the users of this file. Rather than place
+ * these libxml includes in each file, one include makes it easy to handle
+ * the ifdef as well as adding the ability to add additional functions
+ * which may be useful.
+ */
+
+#ifdef HAVE_LIBXML2
+#include <libxml/encoding.h>
+#include <libxml/xmlwriter.h>
+#endif
+
+#define ISC_XMLCHAR (const xmlChar *)
+
+#define ISC_XML_RENDERCONFIG 0x00000001 /* render config data */
+#define ISC_XML_RENDERSTATS 0x00000002 /* render stats */
+#define ISC_XML_RENDERALL 0x000000ff /* render everything */
+
+#endif /* ISC_XML_H */
diff --git a/lib/isc/include/pk11/Makefile.in b/lib/isc/include/pk11/Makefile.in
new file mode 100644
index 0000000..395c924
--- /dev/null
+++ b/lib/isc/include/pk11/Makefile.in
@@ -0,0 +1,38 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+#
+# Only list headers that are to be installed and are not
+# machine generated. The latter are handled specially in the
+# install target below.
+#
+HEADERS = constants.h internal.h pk11.h result.h site.h
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/pk11
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/pk11 || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/pk11/$$i || exit 1; \
+ done
diff --git a/lib/isc/include/pk11/README.site b/lib/isc/include/pk11/README.site
new file mode 100644
index 0000000..6c49891
--- /dev/null
+++ b/lib/isc/include/pk11/README.site
@@ -0,0 +1,72 @@
+Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+
+See COPYRIGHT in the source root or http://isc.org/copyright.html for terms.
+
+How to use site.h for the PKCS#11 provider of your HSM
+------------------------------------------------------
+
+First run "pkcs11-tokens" (in bin/pkcs11). This tool is built when BIND9
+is configured with the --with-pcks11 flag. It prints the addresses of
+selected tokens per algorithm:
+
+ - random number generation
+ - RSA (sign/verify)
+ - DSA (sign/verify)
+ - DH (secret derivation)
+ - digest (hash)
+ - EC (ECDSA, sign/verify)
+ - GOST (Russian hash and sign/verify)
+ - AES (encrypt/decrypt)
+
+...and a summary of PKCS#11 tokens that have been found.
+
+Current well-known HSMs are predefined in site.h according to HSM "flavors":
+
+ - Thales nCipher (default)
+ - OpenDNSSEC SoftHSMv2
+
+...and with experimental status:
+
+ - OpenDNSSEC SoftHSMv1 with SHA224 support added
+ - Cryptech
+ - AEP Keyper
+
+If BIND9 is configured with native PKCS#11 support (--enable-native-pkcs11),
+then pkcs11-tokens will raise an error when a mandatory algorithm is not
+supported. (The usual error is 0x70, or CKR_MECHANISM_INVALID; 0x0
+indicates that a required flag is not available.) The following steps
+may be taken, depending on which algorithms indicate failures:
+
+ - rand or RSA: nothing can be done; native PKCS#11 is not supported
+ in BIND9 with this HSM.
+
+ - DSA or DH: run pkcs11-tokens with the -v (verbose) flag. If the
+ parameter generation mechanism is not supported you can make the token
+ selection to ignore the error. Note DSA and DH are not critical
+ algorithms; you can use BIND9 in production without them.
+
+ - digest: run pkcs11-tokens with the -v (verbose) flag. If the problem is
+ with HMAC mechanisms, use the corresponding REPLACE flags in site.h.
+ If the problem is with MD5, use the corresponding DISABLE flag in
+ site.h. If the problem is with SHA224, contact the implementor of the
+ PKCS#11 provider and ask to have this hash algorithm implemented. For
+ any other problem, nothing can be done; native PKCS#11 is not supported
+ with this HSM.
+
+ - EC: you may wish to configure BIND9 without ECDSA support by adding
+ --without-ecdsa to the "configure" arguments.
+
+ - GOST: you SHOULD configure BIND9 without GOST support by adding
+ --without-gost to the "configure" arguments.
+
+ - AES: you MUST reconfigure bind9 without AES support by adding
+ --without-aes to configure arguments.
+
+You can disable some algorithms (e.g. DSA, DH and MD5) using the
+"disable-algorithms" option in named.conf, and some other algorithms can be
+disabled at compile time (ECDSA, GOST, AES). Note, however, that disabling
+algorithms can have unwanted side effects; for instance, disabling DH breaks
+TKEY support.
+
+A final note: the DISABLE flags in site.h work for OpenSSL code too, but
+this feature is not officially supported yet and should not be relied on.
diff --git a/lib/isc/include/pk11/constants.h b/lib/isc/include/pk11/constants.h
new file mode 100644
index 0000000..0abbf7e
--- /dev/null
+++ b/lib/isc/include/pk11/constants.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef PK11_CONSTANTS_H
+#define PK11_CONSTANTS_H 1
+
+/*! \file pk11/constants.h */
+
+/*%
+ * Static arrays of data used for key template initalization
+ */
+#ifdef WANT_ECC_CURVES
+static CK_BYTE pk11_ecc_prime256v1[] = {
+ 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
+};
+static CK_BYTE pk11_ecc_secp384r1[] = {
+ 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22
+};
+static CK_BYTE pk11_ecc_ed25519[] = {
+ 0x06, 0x03, 0x2b, 0x65, 0x70
+};
+static CK_BYTE pk11_ecc_ed448[] = {
+ 0x06, 0x03, 0x2b, 0x65, 0x71
+};
+#endif
+
+#ifdef WANT_DH_PRIMES
+static CK_BYTE pk11_dh_bn2[] = { 2 };
+static CK_BYTE pk11_dh_bn768[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
+ 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1,
+ 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
+ 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22,
+ 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
+ 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b,
+ 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
+ 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
+ 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
+ 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+static CK_BYTE pk11_dh_bn1024[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
+ 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1,
+ 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
+ 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22,
+ 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
+ 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b,
+ 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
+ 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
+ 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
+ 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b,
+ 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
+ 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5,
+ 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
+ 0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+static CK_BYTE pk11_dh_bn1536[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
+ 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1,
+ 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
+ 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22,
+ 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
+ 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b,
+ 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
+ 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
+ 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
+ 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b,
+ 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
+ 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5,
+ 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
+ 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d,
+ 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05,
+ 0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a,
+ 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
+ 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96,
+ 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb,
+ 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d,
+ 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04,
+ 0xf1, 0x74, 0x6c, 0x08, 0xca, 0x23, 0x73, 0x27,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+#endif
+
+#ifdef WANT_GOST_PARAMS
+static CK_BYTE pk11_gost_a_paramset[] = {
+ 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01
+};
+static CK_BYTE pk11_gost_paramset[] = {
+ 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01
+};
+#endif
+
+#endif /* PK11_CONSTANTS_H */
diff --git a/lib/isc/include/pk11/internal.h b/lib/isc/include/pk11/internal.h
new file mode 100644
index 0000000..aa8907a
--- /dev/null
+++ b/lib/isc/include/pk11/internal.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef PK11_INTERNAL_H
+#define PK11_INTERNAL_H 1
+
+/*! \file pk11/internal.h */
+
+ISC_LANG_BEGINDECLS
+
+const char *pk11_get_lib_name(void);
+
+void *pk11_mem_get(size_t size);
+
+void pk11_mem_put(void *ptr, size_t size);
+
+CK_SLOT_ID pk11_get_best_token(pk11_optype_t optype);
+
+unsigned int pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt);
+
+CK_ATTRIBUTE *pk11_attribute_first(const pk11_object_t *obj);
+
+CK_ATTRIBUTE *pk11_attribute_next(const pk11_object_t *obj,
+ CK_ATTRIBUTE *attr);
+
+CK_ATTRIBUTE *pk11_attribute_bytype(const pk11_object_t *obj,
+ CK_ATTRIBUTE_TYPE type);
+
+ISC_LANG_ENDDECLS
+
+#endif /* PK11_INTERNAL_H */
diff --git a/lib/isc/include/pk11/pk11.h b/lib/isc/include/pk11/pk11.h
new file mode 100644
index 0000000..2ff21fb
--- /dev/null
+++ b/lib/isc/include/pk11/pk11.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef PK11_PK11_H
+#define PK11_PK11_H 1
+
+/*! \file pk11/pk11.h */
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/types.h>
+
+#define PK11_FATALCHECK(func, args) \
+ ((void) (((rv = (func) args) == CKR_OK) || \
+ ((pk11_error_fatalcheck)(__FILE__, __LINE__, #func, rv), 0)))
+
+#include <pkcs11/cryptoki.h>
+#include <pk11/site.h>
+
+ISC_LANG_BEGINDECLS
+
+#define SES_MAGIC ISC_MAGIC('P','K','S','S')
+#define TOK_MAGIC ISC_MAGIC('P','K','T','K')
+
+#define VALID_SES(x) ISC_MAGIC_VALID(x, SES_MAGIC)
+#define VALID_TOK(x) ISC_MAGIC_VALID(x, TOK_MAGIC)
+
+typedef struct pk11_context pk11_context_t;
+
+struct pk11_object {
+ CK_OBJECT_HANDLE object;
+ CK_SLOT_ID slot;
+ CK_BBOOL ontoken;
+ CK_BBOOL reqlogon;
+ CK_BYTE attrcnt;
+ CK_ATTRIBUTE *repr;
+};
+
+struct pk11_context {
+ void *handle;
+ CK_SESSION_HANDLE session;
+ CK_BBOOL ontoken;
+ CK_OBJECT_HANDLE object;
+#if defined(PK11_MD5_HMAC_REPLACE) || defined(PK11_SHA_1_HMAC_REPLACE) || \
+ defined(PK11_SHA224_HMAC_REPLACE) || defined(PK11_SHA256_HMAC_REPLACE) || \
+ defined(PK11_SHA384_HMAC_REPLACE) || defined(PK11_SHA512_HMAC_REPLACE)
+ unsigned char *key;
+#endif
+};
+
+typedef struct pk11_object pk11_object_t;
+
+typedef enum {
+ OP_ANY = 0,
+ OP_RAND = 1,
+ OP_RSA = 2,
+ OP_DSA = 3,
+ OP_DH = 4,
+ OP_DIGEST = 5,
+ OP_EC = 6,
+ OP_GOST = 7,
+ OP_AES = 8,
+ OP_MAX = 9
+} pk11_optype_t;
+
+/*%
+ * Global flag to make choose_slots() verbose
+ */
+LIBISC_EXTERNAL_DATA extern bool pk11_verbose_init;
+
+/*%
+ * Function prototypes
+ */
+
+void pk11_set_lib_name(const char *lib_name);
+/*%<
+ * Set the PKCS#11 provider (aka library) path/name.
+ */
+
+isc_result_t pk11_initialize(isc_mem_t *mctx, const char *engine);
+/*%<
+ * Initialize PKCS#11 device
+ *
+ * mctx: memory context to attach to pk11_mctx.
+ * engine: PKCS#11 provider (aka library) path/name.
+ *
+ * returns:
+ * ISC_R_SUCCESS
+ * PK11_R_NOPROVIDER: can't load the provider
+ * PK11_R_INITFAILED: C_Initialize() failed
+ * PK11_R_NORANDOMSERVICE: can't find required random service
+ * PK11_R_NODIGESTSERVICE: can't find required digest service
+ * PK11_R_NOAESSERVICE: can't find required AES service
+ */
+
+isc_result_t pk11_get_session(pk11_context_t *ctx,
+ pk11_optype_t optype,
+ bool need_services,
+ bool rw,
+ bool logon,
+ const char *pin,
+ CK_SLOT_ID slot);
+/*%<
+ * Initialize PKCS#11 device and acquire a session.
+ *
+ * need_services:
+ * if true, this session requires full PKCS#11 API
+ * support including random and digest services, and
+ * the lack of these services will cause the session not
+ * to be initialized. If false, the function will return
+ * an error code indicating the missing service, but the
+ * session will be usable for other purposes.
+ * rw: if true, session will be read/write (useful for
+ * generating or destroying keys); otherwise read-only.
+ * login: indicates whether to log in to the device
+ * pin: optional PIN, overriding any PIN currently associated
+ * with the
+ * slot: device slot ID
+ */
+
+void pk11_return_session(pk11_context_t *ctx);
+/*%<
+ * Release an active PKCS#11 session for reuse.
+ */
+
+isc_result_t pk11_finalize(void);
+/*%<
+ * Shut down PKCS#11 device and free all sessions.
+ */
+
+isc_result_t pk11_rand_bytes(unsigned char *buf, int num);
+
+void pk11_rand_seed_fromfile(const char *randomfile);
+
+isc_result_t pk11_parse_uri(pk11_object_t *obj, const char *label,
+ isc_mem_t *mctx, pk11_optype_t optype);
+
+ISC_PLATFORM_NORETURN_PRE void
+pk11_error_fatalcheck(const char *file, int line,
+ const char *funcname, CK_RV rv)
+ISC_PLATFORM_NORETURN_POST;
+
+void pk11_dump_tokens(void);
+
+CK_RV
+pkcs_C_Initialize(CK_VOID_PTR pReserved);
+
+char *pk11_get_load_error_message(void);
+
+CK_RV
+pkcs_C_Finalize(CK_VOID_PTR pReserved);
+
+CK_RV
+pkcs_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
+ CK_ULONG_PTR pulCount);
+
+CK_RV
+pkcs_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo);
+
+CK_RV
+pkcs_C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
+ CK_MECHANISM_INFO_PTR pInfo);
+
+CK_RV
+pkcs_C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
+ CK_VOID_PTR pApplication,
+ CK_RV (*Notify) (CK_SESSION_HANDLE hSession,
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication),
+ CK_SESSION_HANDLE_PTR phSession);
+
+CK_RV
+pkcs_C_CloseSession(CK_SESSION_HANDLE hSession);
+
+CK_RV
+pkcs_C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
+ CK_CHAR_PTR pPin, CK_ULONG usPinLen);
+
+CK_RV
+pkcs_C_Logout(CK_SESSION_HANDLE hSession);
+
+CK_RV
+pkcs_C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG usCount, CK_OBJECT_HANDLE_PTR phObject);
+
+CK_RV
+pkcs_C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject);
+
+CK_RV
+pkcs_C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount);
+
+CK_RV
+pkcs_C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount);
+
+CK_RV
+pkcs_C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG usCount);
+
+CK_RV
+pkcs_C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject,
+ CK_ULONG usMaxObjectCount, CK_ULONG_PTR pusObjectCount);
+
+CK_RV
+pkcs_C_FindObjectsFinal(CK_SESSION_HANDLE hSession);
+
+CK_RV
+pkcs_C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey);
+
+CK_RV
+pkcs_C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
+ CK_ULONG_PTR pulEncryptedDataLen);
+
+CK_RV
+pkcs_C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism);
+
+CK_RV
+pkcs_C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen);
+
+CK_RV
+pkcs_C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
+ CK_ULONG_PTR pulDigestLen);
+
+CK_RV
+pkcs_C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey);
+
+CK_RV
+pkcs_C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
+ CK_ULONG_PTR pulSignatureLen);
+
+CK_RV
+pkcs_C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen);
+
+CK_RV
+pkcs_C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
+ CK_ULONG_PTR pulSignatureLen);
+
+CK_RV
+pkcs_C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey);
+
+CK_RV
+pkcs_C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
+ CK_ULONG ulSignatureLen);
+
+CK_RV
+pkcs_C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen);
+
+CK_RV
+pkcs_C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
+ CK_ULONG ulSignatureLen);
+
+CK_RV
+pkcs_C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+ CK_OBJECT_HANDLE_PTR phKey);
+
+CK_RV
+pkcs_C_GenerateKeyPair(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+ CK_ULONG usPublicKeyAttributeCount,
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+ CK_ULONG usPrivateKeyAttributeCount,
+ CK_OBJECT_HANDLE_PTR phPrivateKey,
+ CK_OBJECT_HANDLE_PTR phPublicKey);
+
+CK_RV
+pkcs_C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey);
+
+CK_RV
+pkcs_C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
+ CK_ULONG ulSeedLen);
+
+CK_RV
+pkcs_C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData,
+ CK_ULONG ulRandomLen);
+
+ISC_LANG_ENDDECLS
+
+#endif /* PK11_PK11_H */
diff --git a/lib/isc/include/pk11/result.h b/lib/isc/include/pk11/result.h
new file mode 100644
index 0000000..cce9150
--- /dev/null
+++ b/lib/isc/include/pk11/result.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef PK11_RESULT_H
+#define PK11_RESULT_H 1
+
+/*! \file pk11/result.h */
+
+#include <isc/lang.h>
+#include <isc/resultclass.h>
+
+/*
+ * Nothing in this file truly depends on <isc/result.h>, but the
+ * PK11 result codes are considered to be publicly derived from
+ * the ISC result codes, so including this file buys you the ISC_R_
+ * namespace too.
+ */
+#include <isc/result.h> /* Contractual promise. */
+
+#define PK11_R_INITFAILED (ISC_RESULTCLASS_PK11 + 0)
+#define PK11_R_NOPROVIDER (ISC_RESULTCLASS_PK11 + 1)
+#define PK11_R_NORANDOMSERVICE (ISC_RESULTCLASS_PK11 + 2)
+#define PK11_R_NODIGESTSERVICE (ISC_RESULTCLASS_PK11 + 3)
+#define PK11_R_NOAESSERVICE (ISC_RESULTCLASS_PK11 + 4)
+
+#define PK11_R_NRESULTS 5 /* Number of results */
+
+ISC_LANG_BEGINDECLS
+
+LIBISC_EXTERNAL_DATA extern isc_msgcat_t *pk11_msgcat;
+
+void
+pk11_initmsgcat(void);
+
+const char *
+pk11_result_totext(isc_result_t);
+
+void
+pk11_result_register(void);
+
+ISC_LANG_ENDDECLS
+
+#endif /* PK11_RESULT_H */
diff --git a/lib/isc/include/pk11/site.h b/lib/isc/include/pk11/site.h
new file mode 100644
index 0000000..1d97dbb
--- /dev/null
+++ b/lib/isc/include/pk11/site.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* The documentation about this file is in README.site */
+
+#ifndef PK11_SITE_H
+#define PK11_SITE_H 1
+
+/*! \file pk11/site.h */
+
+/*\brief Put here specific PKCS#11 tweaks
+ *
+ *\li PK11_<mechanism>_SKIP:
+ * Don't consider the lack of this mechanism as a fatal error.
+ *
+ *\li PK11_<mechanism>_REPLACE:
+ * Same as SKIP, and implement the mechanism using lower-level steps.
+ *
+ *\li PK11_<algorithm>_DISABLE:
+ * Same as SKIP, and disable support for the algorithm.
+ *
+ *\li PK11_PAD_HMAC_KEYS:
+ * Extend HMAC keys shorter than digest length.
+ */
+
+/* current implemented flags are:
+PK11_DH_PKCS_PARAMETER_GEN_SKIP
+PK11_DSA_PARAMETER_GEN_SKIP
+PK11_RSA_PKCS_REPLACE
+PK11_MD5_HMAC_REPLACE
+PK11_SHA_1_HMAC_REPLACE
+PK11_SHA224_HMAC_REPLACE
+PK11_SHA256_HMAC_REPLACE
+PK11_SHA384_HMAC_REPLACE
+PK11_SHA512_HMAC_REPLACE
+PK11_MD5_DISABLE
+PK11_DSA_DISABLE
+PK11_DH_DISABLE
+PK11_PAD_HMAC_KEYS
+*/
+
+/*
+ * Predefined flavors
+ */
+/* Thales nCipher */
+#define PK11_THALES_FLAVOR 0
+/* SoftHSMv1 with SHA224 */
+#define PK11_SOFTHSMV1_FLAVOR 1
+/* SoftHSMv2 */
+#define PK11_SOFTHSMV2_FLAVOR 2
+/* Cryptech */
+#define PK11_CRYPTECH_FLAVOR 3
+/* AEP Keyper */
+#define PK11_AEP_FLAVOR 4
+
+/* Default is for Thales nCipher */
+#ifndef PK11_FLAVOR
+#define PK11_FLAVOR PK11_THALES_FLAVOR
+#endif
+
+#if PK11_FLAVOR == PK11_THALES_FLAVOR
+#define PK11_DH_PKCS_PARAMETER_GEN_SKIP
+/* doesn't work but supported #define PK11_DSA_PARAMETER_GEN_SKIP */
+#define PK11_MD5_HMAC_REPLACE
+#endif
+
+#if PK11_FLAVOR == PK11_SOFTHSMV1_FLAVOR
+#define PK11_PAD_HMAC_KEYS
+#endif
+
+#if PK11_FLAVOR == PK11_SOFTHSMV2_FLAVOR
+/* SoftHSMv2 was updated to enforce minimal key sizes... argh! */
+#define PK11_MD5_HMAC_REPLACE
+#define PK11_SHA_1_HMAC_REPLACE
+#define PK11_SHA224_HMAC_REPLACE
+#define PK11_SHA256_HMAC_REPLACE
+#define PK11_SHA384_HMAC_REPLACE
+#define PK11_SHA512_HMAC_REPLACE
+#endif
+
+#if PK11_FLAVOR == PK11_CRYPTECH_FLAVOR
+#define PK11_DH_DISABLE
+#define PK11_DSA_DISABLE
+#define PK11_MD5_DISABLE
+#define PK11_SHA_1_HMAC_REPLACE
+#define PK11_SHA224_HMAC_REPLACE
+#define PK11_SHA256_HMAC_REPLACE
+#define PK11_SHA384_HMAC_REPLACE
+#define PK11_SHA512_HMAC_REPLACE
+#endif
+
+#if PK11_FLAVOR == PK11_AEP_FLAVOR
+#define PK11_DH_DISABLE
+#define PK11_DSA_DISABLE
+#define PK11_RSA_PKCS_REPLACE
+#define PK11_MD5_HMAC_REPLACE
+#define PK11_SHA_1_HMAC_REPLACE
+#define PK11_SHA224_HMAC_REPLACE
+#define PK11_SHA256_HMAC_REPLACE
+#define PK11_SHA384_HMAC_REPLACE
+#define PK11_SHA512_HMAC_REPLACE
+#endif
+
+#endif /* PK11_SITE_H */
diff --git a/lib/isc/include/pkcs11/Makefile.in b/lib/isc/include/pkcs11/Makefile.in
new file mode 100644
index 0000000..8b442b4
--- /dev/null
+++ b/lib/isc/include/pkcs11/Makefile.in
@@ -0,0 +1,38 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+#
+# Only list headers that are to be installed and are not
+# machine generated. The latter are handled specially in the
+# install target below.
+#
+HEADERS = pkcs11f.h pkcs11.h pkcs11t.h eddsa.h
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/pkcs11
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/pkcs11 || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/pkcs11/$$i || exit 1; \
+ done
diff --git a/lib/isc/include/pkcs11/eddsa.h b/lib/isc/include/pkcs11/eddsa.h
new file mode 100644
index 0000000..c0b2e9c
--- /dev/null
+++ b/lib/isc/include/pkcs11/eddsa.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef _EDDSA_H_
+#define _EDDSA_H_ 1
+
+#ifndef CKK_EDDSA
+#ifdef PK11_SOFTHSMV2_FLAVOR
+#define CKK_EDDSA 0x00008003UL
+#endif
+#endif
+
+#ifndef CKM_EDDSA_KEY_PAIR_GEN
+#ifdef PK11_SOFTHSMV2_FLAVOR
+#define CKM_EDDSA_KEY_PAIR_GEN 0x00009040UL
+#endif
+#endif
+
+#ifndef CKM_EDDSA
+#ifdef PK11_SOFTHSMV2_FLAVOR
+#define CKM_EDDSA 0x00009041UL
+#endif
+#endif
+
+#endif /* _EDDSA_H_ */
diff --git a/lib/isc/include/pkcs11/pkcs11.h b/lib/isc/include/pkcs11/pkcs11.h
new file mode 100644
index 0000000..c66b0bc
--- /dev/null
+++ b/lib/isc/include/pkcs11/pkcs11.h
@@ -0,0 +1,264 @@
+/*
+ * PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01
+ * Committee Specification Draft 01 / Public Review Draft 01
+ * 09 December 2015
+ * Copyright (c) OASIS Open 2015. All Rights Reserved.
+ * Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/
+ * Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
+ * https://www.oasis-open.org/policies-guidelines/ipr
+ */
+
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 5 platform-specific macros must be defined. These
+ * macros are described below, and typical definitions for them
+ * are also given. Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a Cryptoki library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 5 macros, the packing convention
+ * for Cryptoki structures should be set. The Cryptoki
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, this might be done by using the following
+ * preprocessor directive before including pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, this might be done by using
+ * the following preprocessor directive before including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(1)
+ *
+ * In a UNIX environment, you're on your own for this. You might
+ * not need to do (or be able to do!) anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object. It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, it might be defined by:
+ *
+ * #define CK_PTR far *
+ *
+ * In a typical UNIX environment, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable Cryptoki library function declaration out of a
+ * return type and a function name. It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * );
+ *
+ * If you're using Microsoft Developer Studio 5.0 to declare a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllimport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to declare a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a Cryptoki API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name. It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a Cryptoki API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // Cryptoki API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to access
+ * functions in a Win32 Cryptoki .dll, in might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __declspec(dllimport) (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to access functions in a Win16 Cryptoki .dll, it might
+ * be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __export _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 4. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV. It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to do Win32
+ * Cryptoki development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to do Win16 development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 5. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should best be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+
+/* All the various Cryptoki types and #define'd values are in the
+ * file pkcs11t.h.
+ */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y) x##y
+
+
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ extern CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes.
+ */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points. That is, for
+ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes.
+ */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points. A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's Cryptoki version
+ * and then a whole slew of function pointers to the routines in
+ * the library. This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ __PASTE(CK_,name) name;
+
+struct CK_FUNCTION_LIST {
+
+ CK_VERSION version; /* Cryptoki version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes.
+ */
+#include "pkcs11f.h"
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKCS11_H_ */
+
diff --git a/lib/isc/include/pkcs11/pkcs11f.h b/lib/isc/include/pkcs11/pkcs11f.h
new file mode 100644
index 0000000..48ba572
--- /dev/null
+++ b/lib/isc/include/pkcs11/pkcs11f.h
@@ -0,0 +1,938 @@
+/*
+ * PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01
+ * Committee Specification Draft 01 / Public Review Draft 01
+ * 09 December 2015
+ * Copyright (c) OASIS Open 2015. All Rights Reserved.
+ * Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/
+ * Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
+ * https://www.oasis-open.org/policies-guidelines/ipr
+ */
+
+/* This header file contains pretty much everything about all the
+ * Cryptoki function prototypes. Because this information is
+ * used for more than just declaring function prototypes, the
+ * order of the functions appearing herein is important, and
+ * should not be altered.
+ */
+
+/* General-purpose */
+
+/* C_Initialize initializes the Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
+ * cast to CK_C_INITIALIZE_ARGS_PTR
+ * and dereferenced
+ */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * Cryptoki library.
+ */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about Cryptoki. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_INFO_PTR pInfo /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
+ * function list
+ */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_BBOOL tokenPresent, /* only slots with tokens */
+ CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
+ CK_ULONG_PTR pulCount /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the ID of the slot */
+ CK_SLOT_INFO_PTR pInfo /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_TOKEN_INFO_PTR pInfo /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of token's slot */
+ CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
+ CK_ULONG_PTR pulCount /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_MECHANISM_TYPE type, /* type of mechanism */
+ CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */
+ CK_ULONG ulPinLen, /* length in bytes of the PIN */
+ CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */
+ CK_ULONG ulPinLen /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pOldPin, /* the old PIN */
+ CK_ULONG ulOldLen, /* length of the old PIN */
+ CK_UTF8CHAR_PTR pNewPin, /* the new PIN */
+ CK_ULONG ulNewLen /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the slot's ID */
+ CK_FLAGS flags, /* from CK_SESSION_INFO */
+ CK_VOID_PTR pApplication, /* passed to callback */
+ CK_NOTIFY Notify, /* callback function */
+ CK_SESSION_HANDLE_PTR phSession /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_SESSION_INFO_PTR pInfo /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* gets state */
+ CK_ULONG_PTR pulOperationStateLen /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* holds state */
+ CK_ULONG ulOperationStateLen, /* holds state length */
+ CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
+ CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_USER_TYPE userType, /* the user type */
+ CK_UTF8CHAR_PTR pPin, /* the user's PIN */
+ CK_ULONG ulPinLen /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy.
+ */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ULONG_PTR pulSize /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template.
+ */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
+ CK_ULONG ulCount /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles.
+ */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
+ CK_ULONG ulMaxObjectCount, /* max handles to get */
+ CK_ULONG_PTR pulObjectCount /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects.
+ */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pData, /* the plaintext data */
+ CK_ULONG ulDataLen, /* bytes of plaintext */
+ CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext data len */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session handle */
+ CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
+ CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedData, /* ciphertext */
+ CK_ULONG ulEncryptedDataLen, /* ciphertext length */
+ CK_BYTE_PTR pData, /* gets plaintext */
+ CK_ULONG_PTR pulDataLen /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* encrypted data */
+ CK_ULONG ulEncryptedPartLen, /* input length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pLastPart, /* gets plaintext */
+ CK_ULONG_PTR pulLastPartLen /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* data to be digested */
+ CK_ULONG ulDataLen, /* bytes of data to digest */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* data to be digested */
+ CK_ULONG ulPartLen /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hKey /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ * signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data,
+ * and plaintext cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* the data to sign */
+ CK_ULONG ulPartLen /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation,
+ * returning the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ * cannot be recovered from the signature (e.g. DSA).
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation,
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* signed data */
+ CK_ULONG ulDataLen, /* length of signed data */
+ CK_BYTE_PTR pSignature, /* signature */
+ CK_ULONG ulSignatureLen /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data,
+ * and plaintext cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* signed data */
+ CK_ULONG ulPartLen /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen, /* signature length */
+ CK_BYTE_PTR pData, /* gets signed data */
+ CK_ULONG_PTR pulDataLen /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key generation mech. */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
+ CK_ULONG ulCount, /* # of attrs in template */
+ CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair,
+ * creating new key objects.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session handle */
+ CK_MECHANISM_PTR pMechanism, /* key-gen mech. */
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template for pub. key */
+ CK_ULONG ulPublicKeyAttributeCount, /* # pub. attrs. */
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template for priv. key */
+ CK_ULONG ulPrivateKeyAttributeCount, /* # priv. attrs. */
+ CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub. key handle */
+ CK_OBJECT_HANDLE_PTR phPrivateKey /* gets priv. key handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
+ CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
+ CK_OBJECT_HANDLE hKey, /* key to be wrapped */
+ CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
+ CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object.
+ */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
+ CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
+ CK_BYTE_PTR pWrappedKey, /* the wrapped key */
+ CK_ULONG ulWrappedKeyLen, /* wrapped key len */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
+ CK_OBJECT_HANDLE hBaseKey, /* base key */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSeed, /* the seed material */
+ CK_ULONG ulSeedLen /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR RandomData, /* receives the random data */
+ CK_ULONG ulRandomLen /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel.
+ */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur.
+ */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FLAGS flags, /* blocking/nonblocking flag */
+ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
+ CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
+);
+#endif
+
diff --git a/lib/isc/include/pkcs11/pkcs11t.h b/lib/isc/include/pkcs11/pkcs11t.h
new file mode 100644
index 0000000..ed83ed3
--- /dev/null
+++ b/lib/isc/include/pkcs11/pkcs11t.h
@@ -0,0 +1,2006 @@
+/*
+ * PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01
+ * Committee Specification Draft 01 / Public Review Draft 01
+ * 09 December 2015
+ * Copyright (c) OASIS Open 2015. All Rights Reserved.
+ * Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/
+ * Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
+ * https://www.oasis-open.org/policies-guidelines/ipr
+ */
+
+/* See top of pkcs11.h for information about the macros that
+ * must be defined and the structure-packing conventions that
+ * must be set before including this file.
+ */
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#define CRYPTOKI_VERSION_MAJOR 2
+#define CRYPTOKI_VERSION_MINOR 40
+#define CRYPTOKI_VERSION_AMENDMENT 0
+
+#define CK_TRUE 1
+#define CK_FALSE 0
+
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE CK_FALSE
+#endif
+#ifndef TRUE
+#define TRUE CK_TRUE
+#endif
+#endif
+
+/* an unsigned 8-bit value */
+typedef unsigned char CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+typedef long int CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION (~0UL)
+#define CK_EFFECTIVELY_INFINITE 0UL
+
+
+typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+typedef CK_CHAR CK_PTR CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR;
+typedef CK_ULONG CK_PTR CK_ULONG_PTR;
+typedef void CK_PTR CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session
+ * handle or object handle
+ */
+#define CK_INVALID_HANDLE 0UL
+
+
+typedef struct CK_VERSION {
+ CK_BYTE major; /* integer portion of version number */
+ CK_BYTE minor; /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+ CK_VERSION cryptokiVersion; /* Cryptoki interface ver */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags; /* must be zero */
+ CK_UTF8CHAR libraryDescription[32]; /* blank padded */
+ CK_VERSION libraryVersion; /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * Cryptoki provides to an application
+ */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER 0UL
+#define CKN_OTP_CHANGED 1UL
+
+typedef CK_ULONG CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+ CK_UTF8CHAR slotDescription[64]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags;
+
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_TOKEN_PRESENT 0x00000001UL /* a token is there */
+#define CKF_REMOVABLE_DEVICE 0x00000002UL /* removable devices*/
+#define CKF_HW_SLOT 0x00000004UL /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+ CK_UTF8CHAR label[32]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_UTF8CHAR model[16]; /* blank padded */
+ CK_CHAR serialNumber[16]; /* blank padded */
+ CK_FLAGS flags; /* see below */
+
+ CK_ULONG ulMaxSessionCount; /* max open sessions */
+ CK_ULONG ulSessionCount; /* sess. now open */
+ CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */
+ CK_ULONG ulRwSessionCount; /* R/W sess. now open */
+ CK_ULONG ulMaxPinLen; /* in bytes */
+ CK_ULONG ulMinPinLen; /* in bytes */
+ CK_ULONG ulTotalPublicMemory; /* in bytes */
+ CK_ULONG ulFreePublicMemory; /* in bytes */
+ CK_ULONG ulTotalPrivateMemory; /* in bytes */
+ CK_ULONG ulFreePrivateMemory; /* in bytes */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+ CK_CHAR utcTime[16]; /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RNG 0x00000001UL /* has random # generator */
+#define CKF_WRITE_PROTECTED 0x00000002UL /* token is write-protected */
+#define CKF_LOGIN_REQUIRED 0x00000004UL /* user must login */
+#define CKF_USER_PIN_INITIALIZED 0x00000008UL /* normal user's PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED. If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state
+ */
+#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020UL
+
+/* CKF_CLOCK_ON_TOKEN. If it is set, that means
+ * that the token has some sort of clock. The time on that
+ * clock is returned in the token info structure
+ */
+#define CKF_CLOCK_ON_TOKEN 0x00000040UL
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH. If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the Cryptoki library itself
+ */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100UL
+
+/* CKF_DUAL_CRYPTO_OPERATIONS. If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign)
+ */
+#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200UL
+
+/* CKF_TOKEN_INITIALIZED. If it is true, the
+ * token has been initialized using C_InitializeToken or an
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause
+ * the token to be reinitialized.
+ */
+#define CKF_TOKEN_INITIALIZED 0x00000400UL
+
+/* CKF_SECONDARY_AUTHENTICATION. If it is
+ * true, the token supports secondary authentication for
+ * private key objects.
+ */
+#define CKF_SECONDARY_AUTHENTICATION 0x00000800UL
+
+/* CKF_USER_PIN_COUNT_LOW. If it is true, an
+ * incorrect user login PIN has been entered at least once
+ * since the last successful authentication.
+ */
+#define CKF_USER_PIN_COUNT_LOW 0x00010000UL
+
+/* CKF_USER_PIN_FINAL_TRY. If it is true,
+ * supplying an incorrect user PIN will it to become locked.
+ */
+#define CKF_USER_PIN_FINAL_TRY 0x00020000UL
+
+/* CKF_USER_PIN_LOCKED. If it is true, the
+ * user PIN has been locked. User login to the token is not
+ * possible.
+ */
+#define CKF_USER_PIN_LOCKED 0x00040000UL
+
+/* CKF_USER_PIN_TO_BE_CHANGED. If it is true,
+ * the user PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card.
+ */
+#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000UL
+
+/* CKF_SO_PIN_COUNT_LOW. If it is true, an
+ * incorrect SO login PIN has been entered at least once since
+ * the last successful authentication.
+ */
+#define CKF_SO_PIN_COUNT_LOW 0x00100000UL
+
+/* CKF_SO_PIN_FINAL_TRY. If it is true,
+ * supplying an incorrect SO PIN will it to become locked.
+ */
+#define CKF_SO_PIN_FINAL_TRY 0x00200000UL
+
+/* CKF_SO_PIN_LOCKED. If it is true, the SO
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED 0x00400000UL
+
+/* CKF_SO_PIN_TO_BE_CHANGED. If it is true,
+ * the SO PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card.
+ */
+#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000UL
+
+#define CKF_ERROR_STATE 0x01000000UL
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
+ * identifies a session
+ */
+typedef CK_ULONG CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
+
+
+/* CK_USER_TYPE enumerates the types of Cryptoki users */
+typedef CK_ULONG CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO 0UL
+/* Normal user */
+#define CKU_USER 1UL
+/* Context specific */
+#define CKU_CONTEXT_SPECIFIC 2UL
+
+/* CK_STATE enumerates the session states */
+typedef CK_ULONG CK_STATE;
+#define CKS_RO_PUBLIC_SESSION 0UL
+#define CKS_RO_USER_FUNCTIONS 1UL
+#define CKS_RW_PUBLIC_SESSION 2UL
+#define CKS_RW_USER_FUNCTIONS 3UL
+#define CKS_RW_SO_FUNCTIONS 4UL
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+ CK_SLOT_ID slotID;
+ CK_STATE state;
+ CK_FLAGS flags; /* see below */
+ CK_ULONG ulDeviceError; /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RW_SESSION 0x00000002UL /* session is r/w */
+#define CKF_SERIAL_SESSION 0x00000004UL /* no parallel */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object
+ */
+typedef CK_ULONG CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that Cryptoki recognizes. It is defined
+ * as follows:
+ */
+typedef CK_ULONG CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+#define CKO_DATA 0x00000000UL
+#define CKO_CERTIFICATE 0x00000001UL
+#define CKO_PUBLIC_KEY 0x00000002UL
+#define CKO_PRIVATE_KEY 0x00000003UL
+#define CKO_SECRET_KEY 0x00000004UL
+#define CKO_HW_FEATURE 0x00000005UL
+#define CKO_DOMAIN_PARAMETERS 0x00000006UL
+#define CKO_MECHANISM 0x00000007UL
+#define CKO_OTP_KEY 0x00000008UL
+
+#define CKO_VENDOR_DEFINED 0x80000000UL
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is a value that identifies the hardware feature type
+ * of an object with CK_OBJECT_CLASS equal to CKO_HW_FEATURE.
+ */
+typedef CK_ULONG CK_HW_FEATURE_TYPE;
+
+/* The following hardware feature types are defined */
+#define CKH_MONOTONIC_COUNTER 0x00000001UL
+#define CKH_CLOCK 0x00000002UL
+#define CKH_USER_INTERFACE 0x00000003UL
+#define CKH_VENDOR_DEFINED 0x80000000UL
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+typedef CK_ULONG CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA 0x00000000UL
+#define CKK_DSA 0x00000001UL
+#define CKK_DH 0x00000002UL
+#define CKK_ECDSA 0x00000003UL /* Deprecated */
+#define CKK_EC 0x00000003UL
+#define CKK_X9_42_DH 0x00000004UL
+#define CKK_KEA 0x00000005UL
+#define CKK_GENERIC_SECRET 0x00000010UL
+#define CKK_RC2 0x00000011UL
+#define CKK_RC4 0x00000012UL
+#define CKK_DES 0x00000013UL
+#define CKK_DES2 0x00000014UL
+#define CKK_DES3 0x00000015UL
+#define CKK_CAST 0x00000016UL
+#define CKK_CAST3 0x00000017UL
+#define CKK_CAST5 0x00000018UL /* Deprecated */
+#define CKK_CAST128 0x00000018UL
+#define CKK_RC5 0x00000019UL
+#define CKK_IDEA 0x0000001AUL
+#define CKK_SKIPJACK 0x0000001BUL
+#define CKK_BATON 0x0000001CUL
+#define CKK_JUNIPER 0x0000001DUL
+#define CKK_CDMF 0x0000001EUL
+#define CKK_AES 0x0000001FUL
+#define CKK_BLOWFISH 0x00000020UL
+#define CKK_TWOFISH 0x00000021UL
+#define CKK_SECURID 0x00000022UL
+#define CKK_HOTP 0x00000023UL
+#define CKK_ACTI 0x00000024UL
+#define CKK_CAMELLIA 0x00000025UL
+#define CKK_ARIA 0x00000026UL
+
+#define CKK_MD5_HMAC 0x00000027UL
+#define CKK_SHA_1_HMAC 0x00000028UL
+#define CKK_RIPEMD128_HMAC 0x00000029UL
+#define CKK_RIPEMD160_HMAC 0x0000002AUL
+#define CKK_SHA256_HMAC 0x0000002BUL
+#define CKK_SHA384_HMAC 0x0000002CUL
+#define CKK_SHA512_HMAC 0x0000002DUL
+#define CKK_SHA224_HMAC 0x0000002EUL
+
+#define CKK_SEED 0x0000002FUL
+#define CKK_GOSTR3410 0x00000030UL
+#define CKK_GOSTR3411 0x00000031UL
+#define CKK_GOST28147 0x00000032UL
+
+
+
+#define CKK_VENDOR_DEFINED 0x80000000UL
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type
+ */
+typedef CK_ULONG CK_CERTIFICATE_TYPE;
+
+#define CK_CERTIFICATE_CATEGORY_UNSPECIFIED 0UL
+#define CK_CERTIFICATE_CATEGORY_TOKEN_USER 1UL
+#define CK_CERTIFICATE_CATEGORY_AUTHORITY 2UL
+#define CK_CERTIFICATE_CATEGORY_OTHER_ENTITY 3UL
+
+#define CK_SECURITY_DOMAIN_UNSPECIFIED 0UL
+#define CK_SECURITY_DOMAIN_MANUFACTURER 1UL
+#define CK_SECURITY_DOMAIN_OPERATOR 2UL
+#define CK_SECURITY_DOMAIN_THIRD_PARTY 3UL
+
+
+/* The following certificate types are defined: */
+#define CKC_X_509 0x00000000UL
+#define CKC_X_509_ATTR_CERT 0x00000001UL
+#define CKC_WTLS 0x00000002UL
+#define CKC_VENDOR_DEFINED 0x80000000UL
+
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type
+ */
+typedef CK_ULONG CK_ATTRIBUTE_TYPE;
+
+/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
+ * consists of an array of values.
+ */
+#define CKF_ARRAY_ATTRIBUTE 0x40000000UL
+
+/* The following OTP-related defines relate to the CKA_OTP_FORMAT attribute */
+#define CK_OTP_FORMAT_DECIMAL 0UL
+#define CK_OTP_FORMAT_HEXADECIMAL 1UL
+#define CK_OTP_FORMAT_ALPHANUMERIC 2UL
+#define CK_OTP_FORMAT_BINARY 3UL
+
+/* The following OTP-related defines relate to the CKA_OTP_..._REQUIREMENT
+ * attributes
+ */
+#define CK_OTP_PARAM_IGNORED 0UL
+#define CK_OTP_PARAM_OPTIONAL 1UL
+#define CK_OTP_PARAM_MANDATORY 2UL
+
+/* The following attribute types are defined: */
+#define CKA_CLASS 0x00000000UL
+#define CKA_TOKEN 0x00000001UL
+#define CKA_PRIVATE 0x00000002UL
+#define CKA_LABEL 0x00000003UL
+#define CKA_APPLICATION 0x00000010UL
+#define CKA_VALUE 0x00000011UL
+#define CKA_OBJECT_ID 0x00000012UL
+#define CKA_CERTIFICATE_TYPE 0x00000080UL
+#define CKA_ISSUER 0x00000081UL
+#define CKA_SERIAL_NUMBER 0x00000082UL
+#define CKA_AC_ISSUER 0x00000083UL
+#define CKA_OWNER 0x00000084UL
+#define CKA_ATTR_TYPES 0x00000085UL
+#define CKA_TRUSTED 0x00000086UL
+#define CKA_CERTIFICATE_CATEGORY 0x00000087UL
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088UL
+#define CKA_URL 0x00000089UL
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008AUL
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008BUL
+#define CKA_NAME_HASH_ALGORITHM 0x0000008CUL
+#define CKA_CHECK_VALUE 0x00000090UL
+
+#define CKA_KEY_TYPE 0x00000100UL
+#define CKA_SUBJECT 0x00000101UL
+#define CKA_ID 0x00000102UL
+#define CKA_SENSITIVE 0x00000103UL
+#define CKA_ENCRYPT 0x00000104UL
+#define CKA_DECRYPT 0x00000105UL
+#define CKA_WRAP 0x00000106UL
+#define CKA_UNWRAP 0x00000107UL
+#define CKA_SIGN 0x00000108UL
+#define CKA_SIGN_RECOVER 0x00000109UL
+#define CKA_VERIFY 0x0000010AUL
+#define CKA_VERIFY_RECOVER 0x0000010BUL
+#define CKA_DERIVE 0x0000010CUL
+#define CKA_START_DATE 0x00000110UL
+#define CKA_END_DATE 0x00000111UL
+#define CKA_MODULUS 0x00000120UL
+#define CKA_MODULUS_BITS 0x00000121UL
+#define CKA_PUBLIC_EXPONENT 0x00000122UL
+#define CKA_PRIVATE_EXPONENT 0x00000123UL
+#define CKA_PRIME_1 0x00000124UL
+#define CKA_PRIME_2 0x00000125UL
+#define CKA_EXPONENT_1 0x00000126UL
+#define CKA_EXPONENT_2 0x00000127UL
+#define CKA_COEFFICIENT 0x00000128UL
+#define CKA_PUBLIC_KEY_INFO 0x00000129UL
+#define CKA_PRIME 0x00000130UL
+#define CKA_SUBPRIME 0x00000131UL
+#define CKA_BASE 0x00000132UL
+
+#define CKA_PRIME_BITS 0x00000133UL
+#define CKA_SUBPRIME_BITS 0x00000134UL
+#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS
+
+#define CKA_VALUE_BITS 0x00000160UL
+#define CKA_VALUE_LEN 0x00000161UL
+#define CKA_EXTRACTABLE 0x00000162UL
+#define CKA_LOCAL 0x00000163UL
+#define CKA_NEVER_EXTRACTABLE 0x00000164UL
+#define CKA_ALWAYS_SENSITIVE 0x00000165UL
+#define CKA_KEY_GEN_MECHANISM 0x00000166UL
+
+#define CKA_MODIFIABLE 0x00000170UL
+#define CKA_COPYABLE 0x00000171UL
+
+#define CKA_DESTROYABLE 0x00000172UL
+
+#define CKA_ECDSA_PARAMS 0x00000180UL /* Deprecated */
+#define CKA_EC_PARAMS 0x00000180UL
+
+#define CKA_EC_POINT 0x00000181UL
+
+#define CKA_SECONDARY_AUTH 0x00000200UL /* Deprecated */
+#define CKA_AUTH_PIN_FLAGS 0x00000201UL /* Deprecated */
+
+#define CKA_ALWAYS_AUTHENTICATE 0x00000202UL
+
+#define CKA_WRAP_WITH_TRUSTED 0x00000210UL
+#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211UL)
+#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212UL)
+#define CKA_DERIVE_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000213UL)
+
+#define CKA_OTP_FORMAT 0x00000220UL
+#define CKA_OTP_LENGTH 0x00000221UL
+#define CKA_OTP_TIME_INTERVAL 0x00000222UL
+#define CKA_OTP_USER_FRIENDLY_MODE 0x00000223UL
+#define CKA_OTP_CHALLENGE_REQUIREMENT 0x00000224UL
+#define CKA_OTP_TIME_REQUIREMENT 0x00000225UL
+#define CKA_OTP_COUNTER_REQUIREMENT 0x00000226UL
+#define CKA_OTP_PIN_REQUIREMENT 0x00000227UL
+#define CKA_OTP_COUNTER 0x0000022EUL
+#define CKA_OTP_TIME 0x0000022FUL
+#define CKA_OTP_USER_IDENTIFIER 0x0000022AUL
+#define CKA_OTP_SERVICE_IDENTIFIER 0x0000022BUL
+#define CKA_OTP_SERVICE_LOGO 0x0000022CUL
+#define CKA_OTP_SERVICE_LOGO_TYPE 0x0000022DUL
+
+#define CKA_GOSTR3410_PARAMS 0x00000250UL
+#define CKA_GOSTR3411_PARAMS 0x00000251UL
+#define CKA_GOST28147_PARAMS 0x00000252UL
+
+#define CKA_HW_FEATURE_TYPE 0x00000300UL
+#define CKA_RESET_ON_INIT 0x00000301UL
+#define CKA_HAS_RESET 0x00000302UL
+
+#define CKA_PIXEL_X 0x00000400UL
+#define CKA_PIXEL_Y 0x00000401UL
+#define CKA_RESOLUTION 0x00000402UL
+#define CKA_CHAR_ROWS 0x00000403UL
+#define CKA_CHAR_COLUMNS 0x00000404UL
+#define CKA_COLOR 0x00000405UL
+#define CKA_BITS_PER_PIXEL 0x00000406UL
+#define CKA_CHAR_SETS 0x00000480UL
+#define CKA_ENCODING_METHODS 0x00000481UL
+#define CKA_MIME_TYPES 0x00000482UL
+#define CKA_MECHANISM_TYPE 0x00000500UL
+#define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501UL
+#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502UL
+#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503UL
+#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600UL)
+
+#define CKA_VENDOR_DEFINED 0x80000000UL
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute
+ */
+typedef struct CK_ATTRIBUTE {
+ CK_ATTRIBUTE_TYPE type;
+ CK_VOID_PTR pValue;
+ CK_ULONG ulValueLen; /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+ CK_CHAR year[4]; /* the year ("1900" - "9999") */
+ CK_CHAR month[2]; /* the month ("01" - "12") */
+ CK_CHAR day[2]; /* the day ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type
+ */
+typedef CK_ULONG CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000UL
+#define CKM_RSA_PKCS 0x00000001UL
+#define CKM_RSA_9796 0x00000002UL
+#define CKM_RSA_X_509 0x00000003UL
+
+#define CKM_MD2_RSA_PKCS 0x00000004UL
+#define CKM_MD5_RSA_PKCS 0x00000005UL
+#define CKM_SHA1_RSA_PKCS 0x00000006UL
+
+#define CKM_RIPEMD128_RSA_PKCS 0x00000007UL
+#define CKM_RIPEMD160_RSA_PKCS 0x00000008UL
+#define CKM_RSA_PKCS_OAEP 0x00000009UL
+
+#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000AUL
+#define CKM_RSA_X9_31 0x0000000BUL
+#define CKM_SHA1_RSA_X9_31 0x0000000CUL
+#define CKM_RSA_PKCS_PSS 0x0000000DUL
+#define CKM_SHA1_RSA_PKCS_PSS 0x0000000EUL
+
+#define CKM_DSA_KEY_PAIR_GEN 0x00000010UL
+#define CKM_DSA 0x00000011UL
+#define CKM_DSA_SHA1 0x00000012UL
+#define CKM_DSA_SHA224 0x00000013UL
+#define CKM_DSA_SHA256 0x00000014UL
+#define CKM_DSA_SHA384 0x00000015UL
+#define CKM_DSA_SHA512 0x00000016UL
+
+#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020UL
+#define CKM_DH_PKCS_DERIVE 0x00000021UL
+
+#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030UL
+#define CKM_X9_42_DH_DERIVE 0x00000031UL
+#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032UL
+#define CKM_X9_42_MQV_DERIVE 0x00000033UL
+
+#define CKM_SHA256_RSA_PKCS 0x00000040UL
+#define CKM_SHA384_RSA_PKCS 0x00000041UL
+#define CKM_SHA512_RSA_PKCS 0x00000042UL
+#define CKM_SHA256_RSA_PKCS_PSS 0x00000043UL
+#define CKM_SHA384_RSA_PKCS_PSS 0x00000044UL
+#define CKM_SHA512_RSA_PKCS_PSS 0x00000045UL
+
+#define CKM_SHA224_RSA_PKCS 0x00000046UL
+#define CKM_SHA224_RSA_PKCS_PSS 0x00000047UL
+
+#define CKM_SHA512_224 0x00000048UL
+#define CKM_SHA512_224_HMAC 0x00000049UL
+#define CKM_SHA512_224_HMAC_GENERAL 0x0000004AUL
+#define CKM_SHA512_224_KEY_DERIVATION 0x0000004BUL
+#define CKM_SHA512_256 0x0000004CUL
+#define CKM_SHA512_256_HMAC 0x0000004DUL
+#define CKM_SHA512_256_HMAC_GENERAL 0x0000004EUL
+#define CKM_SHA512_256_KEY_DERIVATION 0x0000004FUL
+
+#define CKM_SHA512_T 0x00000050UL
+#define CKM_SHA512_T_HMAC 0x00000051UL
+#define CKM_SHA512_T_HMAC_GENERAL 0x00000052UL
+#define CKM_SHA512_T_KEY_DERIVATION 0x00000053UL
+
+#define CKM_RC2_KEY_GEN 0x00000100UL
+#define CKM_RC2_ECB 0x00000101UL
+#define CKM_RC2_CBC 0x00000102UL
+#define CKM_RC2_MAC 0x00000103UL
+
+#define CKM_RC2_MAC_GENERAL 0x00000104UL
+#define CKM_RC2_CBC_PAD 0x00000105UL
+
+#define CKM_RC4_KEY_GEN 0x00000110UL
+#define CKM_RC4 0x00000111UL
+#define CKM_DES_KEY_GEN 0x00000120UL
+#define CKM_DES_ECB 0x00000121UL
+#define CKM_DES_CBC 0x00000122UL
+#define CKM_DES_MAC 0x00000123UL
+
+#define CKM_DES_MAC_GENERAL 0x00000124UL
+#define CKM_DES_CBC_PAD 0x00000125UL
+
+#define CKM_DES2_KEY_GEN 0x00000130UL
+#define CKM_DES3_KEY_GEN 0x00000131UL
+#define CKM_DES3_ECB 0x00000132UL
+#define CKM_DES3_CBC 0x00000133UL
+#define CKM_DES3_MAC 0x00000134UL
+
+#define CKM_DES3_MAC_GENERAL 0x00000135UL
+#define CKM_DES3_CBC_PAD 0x00000136UL
+#define CKM_DES3_CMAC_GENERAL 0x00000137UL
+#define CKM_DES3_CMAC 0x00000138UL
+#define CKM_CDMF_KEY_GEN 0x00000140UL
+#define CKM_CDMF_ECB 0x00000141UL
+#define CKM_CDMF_CBC 0x00000142UL
+#define CKM_CDMF_MAC 0x00000143UL
+#define CKM_CDMF_MAC_GENERAL 0x00000144UL
+#define CKM_CDMF_CBC_PAD 0x00000145UL
+
+#define CKM_DES_OFB64 0x00000150UL
+#define CKM_DES_OFB8 0x00000151UL
+#define CKM_DES_CFB64 0x00000152UL
+#define CKM_DES_CFB8 0x00000153UL
+
+#define CKM_MD2 0x00000200UL
+
+#define CKM_MD2_HMAC 0x00000201UL
+#define CKM_MD2_HMAC_GENERAL 0x00000202UL
+
+#define CKM_MD5 0x00000210UL
+
+#define CKM_MD5_HMAC 0x00000211UL
+#define CKM_MD5_HMAC_GENERAL 0x00000212UL
+
+#define CKM_SHA_1 0x00000220UL
+
+#define CKM_SHA_1_HMAC 0x00000221UL
+#define CKM_SHA_1_HMAC_GENERAL 0x00000222UL
+
+#define CKM_RIPEMD128 0x00000230UL
+#define CKM_RIPEMD128_HMAC 0x00000231UL
+#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232UL
+#define CKM_RIPEMD160 0x00000240UL
+#define CKM_RIPEMD160_HMAC 0x00000241UL
+#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242UL
+
+#define CKM_SHA256 0x00000250UL
+#define CKM_SHA256_HMAC 0x00000251UL
+#define CKM_SHA256_HMAC_GENERAL 0x00000252UL
+#define CKM_SHA224 0x00000255UL
+#define CKM_SHA224_HMAC 0x00000256UL
+#define CKM_SHA224_HMAC_GENERAL 0x00000257UL
+#define CKM_SHA384 0x00000260UL
+#define CKM_SHA384_HMAC 0x00000261UL
+#define CKM_SHA384_HMAC_GENERAL 0x00000262UL
+#define CKM_SHA512 0x00000270UL
+#define CKM_SHA512_HMAC 0x00000271UL
+#define CKM_SHA512_HMAC_GENERAL 0x00000272UL
+#define CKM_SECURID_KEY_GEN 0x00000280UL
+#define CKM_SECURID 0x00000282UL
+#define CKM_HOTP_KEY_GEN 0x00000290UL
+#define CKM_HOTP 0x00000291UL
+#define CKM_ACTI 0x000002A0UL
+#define CKM_ACTI_KEY_GEN 0x000002A1UL
+
+#define CKM_CAST_KEY_GEN 0x00000300UL
+#define CKM_CAST_ECB 0x00000301UL
+#define CKM_CAST_CBC 0x00000302UL
+#define CKM_CAST_MAC 0x00000303UL
+#define CKM_CAST_MAC_GENERAL 0x00000304UL
+#define CKM_CAST_CBC_PAD 0x00000305UL
+#define CKM_CAST3_KEY_GEN 0x00000310UL
+#define CKM_CAST3_ECB 0x00000311UL
+#define CKM_CAST3_CBC 0x00000312UL
+#define CKM_CAST3_MAC 0x00000313UL
+#define CKM_CAST3_MAC_GENERAL 0x00000314UL
+#define CKM_CAST3_CBC_PAD 0x00000315UL
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST5_KEY_GEN 0x00000320UL
+#define CKM_CAST128_KEY_GEN 0x00000320UL
+#define CKM_CAST5_ECB 0x00000321UL
+#define CKM_CAST128_ECB 0x00000321UL
+#define CKM_CAST5_CBC 0x00000322UL /* Deprecated */
+#define CKM_CAST128_CBC 0x00000322UL
+#define CKM_CAST5_MAC 0x00000323UL /* Deprecated */
+#define CKM_CAST128_MAC 0x00000323UL
+#define CKM_CAST5_MAC_GENERAL 0x00000324UL /* Deprecated */
+#define CKM_CAST128_MAC_GENERAL 0x00000324UL
+#define CKM_CAST5_CBC_PAD 0x00000325UL /* Deprecated */
+#define CKM_CAST128_CBC_PAD 0x00000325UL
+#define CKM_RC5_KEY_GEN 0x00000330UL
+#define CKM_RC5_ECB 0x00000331UL
+#define CKM_RC5_CBC 0x00000332UL
+#define CKM_RC5_MAC 0x00000333UL
+#define CKM_RC5_MAC_GENERAL 0x00000334UL
+#define CKM_RC5_CBC_PAD 0x00000335UL
+#define CKM_IDEA_KEY_GEN 0x00000340UL
+#define CKM_IDEA_ECB 0x00000341UL
+#define CKM_IDEA_CBC 0x00000342UL
+#define CKM_IDEA_MAC 0x00000343UL
+#define CKM_IDEA_MAC_GENERAL 0x00000344UL
+#define CKM_IDEA_CBC_PAD 0x00000345UL
+#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350UL
+#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360UL
+#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362UL
+#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363UL
+#define CKM_XOR_BASE_AND_DATA 0x00000364UL
+#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365UL
+#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370UL
+#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371UL
+#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372UL
+
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373UL
+#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374UL
+#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375UL
+#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376UL
+#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377UL
+
+#define CKM_TLS_PRF 0x00000378UL
+
+#define CKM_SSL3_MD5_MAC 0x00000380UL
+#define CKM_SSL3_SHA1_MAC 0x00000381UL
+#define CKM_MD5_KEY_DERIVATION 0x00000390UL
+#define CKM_MD2_KEY_DERIVATION 0x00000391UL
+#define CKM_SHA1_KEY_DERIVATION 0x00000392UL
+
+#define CKM_SHA256_KEY_DERIVATION 0x00000393UL
+#define CKM_SHA384_KEY_DERIVATION 0x00000394UL
+#define CKM_SHA512_KEY_DERIVATION 0x00000395UL
+#define CKM_SHA224_KEY_DERIVATION 0x00000396UL
+
+#define CKM_PBE_MD2_DES_CBC 0x000003A0UL
+#define CKM_PBE_MD5_DES_CBC 0x000003A1UL
+#define CKM_PBE_MD5_CAST_CBC 0x000003A2UL
+#define CKM_PBE_MD5_CAST3_CBC 0x000003A3UL
+#define CKM_PBE_MD5_CAST5_CBC 0x000003A4UL /* Deprecated */
+#define CKM_PBE_MD5_CAST128_CBC 0x000003A4UL
+#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5UL /* Deprecated */
+#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5UL
+#define CKM_PBE_SHA1_RC4_128 0x000003A6UL
+#define CKM_PBE_SHA1_RC4_40 0x000003A7UL
+#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8UL
+#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9UL
+#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AAUL
+#define CKM_PBE_SHA1_RC2_40_CBC 0x000003ABUL
+
+#define CKM_PKCS5_PBKD2 0x000003B0UL
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0UL
+
+#define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0UL
+#define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1UL
+#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2UL
+#define CKM_WTLS_PRF 0x000003D3UL
+#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4UL
+#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5UL
+
+#define CKM_TLS10_MAC_SERVER 0x000003D6UL
+#define CKM_TLS10_MAC_CLIENT 0x000003D7UL
+#define CKM_TLS12_MAC 0x000003D8UL
+#define CKM_TLS12_KDF 0x000003D9UL
+#define CKM_TLS12_MASTER_KEY_DERIVE 0x000003E0UL
+#define CKM_TLS12_KEY_AND_MAC_DERIVE 0x000003E1UL
+#define CKM_TLS12_MASTER_KEY_DERIVE_DH 0x000003E2UL
+#define CKM_TLS12_KEY_SAFE_DERIVE 0x000003E3UL
+#define CKM_TLS_MAC 0x000003E4UL
+#define CKM_TLS_KDF 0x000003E5UL
+
+#define CKM_KEY_WRAP_LYNKS 0x00000400UL
+#define CKM_KEY_WRAP_SET_OAEP 0x00000401UL
+
+#define CKM_CMS_SIG 0x00000500UL
+#define CKM_KIP_DERIVE 0x00000510UL
+#define CKM_KIP_WRAP 0x00000511UL
+#define CKM_KIP_MAC 0x00000512UL
+
+#define CKM_CAMELLIA_KEY_GEN 0x00000550UL
+#define CKM_CAMELLIA_ECB 0x00000551UL
+#define CKM_CAMELLIA_CBC 0x00000552UL
+#define CKM_CAMELLIA_MAC 0x00000553UL
+#define CKM_CAMELLIA_MAC_GENERAL 0x00000554UL
+#define CKM_CAMELLIA_CBC_PAD 0x00000555UL
+#define CKM_CAMELLIA_ECB_ENCRYPT_DATA 0x00000556UL
+#define CKM_CAMELLIA_CBC_ENCRYPT_DATA 0x00000557UL
+#define CKM_CAMELLIA_CTR 0x00000558UL
+
+#define CKM_ARIA_KEY_GEN 0x00000560UL
+#define CKM_ARIA_ECB 0x00000561UL
+#define CKM_ARIA_CBC 0x00000562UL
+#define CKM_ARIA_MAC 0x00000563UL
+#define CKM_ARIA_MAC_GENERAL 0x00000564UL
+#define CKM_ARIA_CBC_PAD 0x00000565UL
+#define CKM_ARIA_ECB_ENCRYPT_DATA 0x00000566UL
+#define CKM_ARIA_CBC_ENCRYPT_DATA 0x00000567UL
+
+#define CKM_SEED_KEY_GEN 0x00000650UL
+#define CKM_SEED_ECB 0x00000651UL
+#define CKM_SEED_CBC 0x00000652UL
+#define CKM_SEED_MAC 0x00000653UL
+#define CKM_SEED_MAC_GENERAL 0x00000654UL
+#define CKM_SEED_CBC_PAD 0x00000655UL
+#define CKM_SEED_ECB_ENCRYPT_DATA 0x00000656UL
+#define CKM_SEED_CBC_ENCRYPT_DATA 0x00000657UL
+
+#define CKM_SKIPJACK_KEY_GEN 0x00001000UL
+#define CKM_SKIPJACK_ECB64 0x00001001UL
+#define CKM_SKIPJACK_CBC64 0x00001002UL
+#define CKM_SKIPJACK_OFB64 0x00001003UL
+#define CKM_SKIPJACK_CFB64 0x00001004UL
+#define CKM_SKIPJACK_CFB32 0x00001005UL
+#define CKM_SKIPJACK_CFB16 0x00001006UL
+#define CKM_SKIPJACK_CFB8 0x00001007UL
+#define CKM_SKIPJACK_WRAP 0x00001008UL
+#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009UL
+#define CKM_SKIPJACK_RELAYX 0x0000100aUL
+#define CKM_KEA_KEY_PAIR_GEN 0x00001010UL
+#define CKM_KEA_KEY_DERIVE 0x00001011UL
+#define CKM_KEA_DERIVE 0x00001012UL
+#define CKM_FORTEZZA_TIMESTAMP 0x00001020UL
+#define CKM_BATON_KEY_GEN 0x00001030UL
+#define CKM_BATON_ECB128 0x00001031UL
+#define CKM_BATON_ECB96 0x00001032UL
+#define CKM_BATON_CBC128 0x00001033UL
+#define CKM_BATON_COUNTER 0x00001034UL
+#define CKM_BATON_SHUFFLE 0x00001035UL
+#define CKM_BATON_WRAP 0x00001036UL
+
+#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040UL /* Deprecated */
+#define CKM_EC_KEY_PAIR_GEN 0x00001040UL
+
+#define CKM_ECDSA 0x00001041UL
+#define CKM_ECDSA_SHA1 0x00001042UL
+#define CKM_ECDSA_SHA224 0x00001043UL
+#define CKM_ECDSA_SHA256 0x00001044UL
+#define CKM_ECDSA_SHA384 0x00001045UL
+#define CKM_ECDSA_SHA512 0x00001046UL
+
+#define CKM_ECDH1_DERIVE 0x00001050UL
+#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051UL
+#define CKM_ECMQV_DERIVE 0x00001052UL
+
+#define CKM_ECDH_AES_KEY_WRAP 0x00001053UL
+#define CKM_RSA_AES_KEY_WRAP 0x00001054UL
+
+#define CKM_JUNIPER_KEY_GEN 0x00001060UL
+#define CKM_JUNIPER_ECB128 0x00001061UL
+#define CKM_JUNIPER_CBC128 0x00001062UL
+#define CKM_JUNIPER_COUNTER 0x00001063UL
+#define CKM_JUNIPER_SHUFFLE 0x00001064UL
+#define CKM_JUNIPER_WRAP 0x00001065UL
+#define CKM_FASTHASH 0x00001070UL
+
+#define CKM_AES_KEY_GEN 0x00001080UL
+#define CKM_AES_ECB 0x00001081UL
+#define CKM_AES_CBC 0x00001082UL
+#define CKM_AES_MAC 0x00001083UL
+#define CKM_AES_MAC_GENERAL 0x00001084UL
+#define CKM_AES_CBC_PAD 0x00001085UL
+#define CKM_AES_CTR 0x00001086UL
+#define CKM_AES_GCM 0x00001087UL
+#define CKM_AES_CCM 0x00001088UL
+#define CKM_AES_CTS 0x00001089UL
+#define CKM_AES_CMAC 0x0000108AUL
+#define CKM_AES_CMAC_GENERAL 0x0000108BUL
+
+#define CKM_AES_XCBC_MAC 0x0000108CUL
+#define CKM_AES_XCBC_MAC_96 0x0000108DUL
+#define CKM_AES_GMAC 0x0000108EUL
+
+#define CKM_BLOWFISH_KEY_GEN 0x00001090UL
+#define CKM_BLOWFISH_CBC 0x00001091UL
+#define CKM_TWOFISH_KEY_GEN 0x00001092UL
+#define CKM_TWOFISH_CBC 0x00001093UL
+#define CKM_BLOWFISH_CBC_PAD 0x00001094UL
+#define CKM_TWOFISH_CBC_PAD 0x00001095UL
+
+#define CKM_DES_ECB_ENCRYPT_DATA 0x00001100UL
+#define CKM_DES_CBC_ENCRYPT_DATA 0x00001101UL
+#define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102UL
+#define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103UL
+#define CKM_AES_ECB_ENCRYPT_DATA 0x00001104UL
+#define CKM_AES_CBC_ENCRYPT_DATA 0x00001105UL
+
+#define CKM_GOSTR3410_KEY_PAIR_GEN 0x00001200UL
+#define CKM_GOSTR3410 0x00001201UL
+#define CKM_GOSTR3410_WITH_GOSTR3411 0x00001202UL
+#define CKM_GOSTR3410_KEY_WRAP 0x00001203UL
+#define CKM_GOSTR3410_DERIVE 0x00001204UL
+#define CKM_GOSTR3411 0x00001210UL
+#define CKM_GOSTR3411_HMAC 0x00001211UL
+#define CKM_GOST28147_KEY_GEN 0x00001220UL
+#define CKM_GOST28147_ECB 0x00001221UL
+#define CKM_GOST28147 0x00001222UL
+#define CKM_GOST28147_MAC 0x00001223UL
+#define CKM_GOST28147_KEY_WRAP 0x00001224UL
+
+#define CKM_DSA_PARAMETER_GEN 0x00002000UL
+#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001UL
+#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002UL
+#define CKM_DSA_PROBABLISTIC_PARAMETER_GEN 0x00002003UL
+#define CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN 0x00002004UL
+
+#define CKM_AES_OFB 0x00002104UL
+#define CKM_AES_CFB64 0x00002105UL
+#define CKM_AES_CFB8 0x00002106UL
+#define CKM_AES_CFB128 0x00002107UL
+
+#define CKM_AES_CFB1 0x00002108UL
+#define CKM_AES_KEY_WRAP 0x00002109UL /* WAS: 0x00001090 */
+#define CKM_AES_KEY_WRAP_PAD 0x0000210AUL /* WAS: 0x00001091 */
+
+#define CKM_RSA_PKCS_TPM_1_1 0x00004001UL
+#define CKM_RSA_PKCS_OAEP_TPM_1_1 0x00004002UL
+
+#define CKM_VENDOR_DEFINED 0x80000000UL
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism
+ */
+typedef struct CK_MECHANISM {
+ CK_MECHANISM_TYPE mechanism;
+ CK_VOID_PTR pParameter;
+ CK_ULONG ulParameterLen; /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism
+ */
+typedef struct CK_MECHANISM_INFO {
+ CK_ULONG ulMinKeySize;
+ CK_ULONG ulMaxKeySize;
+ CK_FLAGS flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ * Bit Flag Mask Meaning */
+#define CKF_HW 0x00000001UL /* performed by HW */
+
+/* Specify whether or not a mechanism can be used for a particular task */
+#define CKF_ENCRYPT 0x00000100UL
+#define CKF_DECRYPT 0x00000200UL
+#define CKF_DIGEST 0x00000400UL
+#define CKF_SIGN 0x00000800UL
+#define CKF_SIGN_RECOVER 0x00001000UL
+#define CKF_VERIFY 0x00002000UL
+#define CKF_VERIFY_RECOVER 0x00004000UL
+#define CKF_GENERATE 0x00008000UL
+#define CKF_GENERATE_KEY_PAIR 0x00010000UL
+#define CKF_WRAP 0x00020000UL
+#define CKF_UNWRAP 0x00040000UL
+#define CKF_DERIVE 0x00080000UL
+
+/* Describe a token's EC capabilities not available in mechanism
+ * information.
+ */
+#define CKF_EC_F_P 0x00100000UL
+#define CKF_EC_F_2M 0x00200000UL
+#define CKF_EC_ECPARAMETERS 0x00400000UL
+#define CKF_EC_NAMEDCURVE 0x00800000UL
+#define CKF_EC_UNCOMPRESS 0x01000000UL
+#define CKF_EC_COMPRESS 0x02000000UL
+
+#define CKF_EXTENSION 0x80000000UL
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+/* CK_RV is a value that identifies the return value of a
+ * Cryptoki function
+ */
+typedef CK_ULONG CK_RV;
+
+#define CKR_OK 0x00000000UL
+#define CKR_CANCEL 0x00000001UL
+#define CKR_HOST_MEMORY 0x00000002UL
+#define CKR_SLOT_ID_INVALID 0x00000003UL
+
+#define CKR_GENERAL_ERROR 0x00000005UL
+#define CKR_FUNCTION_FAILED 0x00000006UL
+
+#define CKR_ARGUMENTS_BAD 0x00000007UL
+#define CKR_NO_EVENT 0x00000008UL
+#define CKR_NEED_TO_CREATE_THREADS 0x00000009UL
+#define CKR_CANT_LOCK 0x0000000AUL
+
+#define CKR_ATTRIBUTE_READ_ONLY 0x00000010UL
+#define CKR_ATTRIBUTE_SENSITIVE 0x00000011UL
+#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012UL
+#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013UL
+
+#define CKR_ACTION_PROHIBITED 0x0000001BUL
+
+#define CKR_DATA_INVALID 0x00000020UL
+#define CKR_DATA_LEN_RANGE 0x00000021UL
+#define CKR_DEVICE_ERROR 0x00000030UL
+#define CKR_DEVICE_MEMORY 0x00000031UL
+#define CKR_DEVICE_REMOVED 0x00000032UL
+#define CKR_ENCRYPTED_DATA_INVALID 0x00000040UL
+#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041UL
+#define CKR_FUNCTION_CANCELED 0x00000050UL
+#define CKR_FUNCTION_NOT_PARALLEL 0x00000051UL
+
+#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054UL
+
+#define CKR_KEY_HANDLE_INVALID 0x00000060UL
+
+#define CKR_KEY_SIZE_RANGE 0x00000062UL
+#define CKR_KEY_TYPE_INCONSISTENT 0x00000063UL
+
+#define CKR_KEY_NOT_NEEDED 0x00000064UL
+#define CKR_KEY_CHANGED 0x00000065UL
+#define CKR_KEY_NEEDED 0x00000066UL
+#define CKR_KEY_INDIGESTIBLE 0x00000067UL
+#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068UL
+#define CKR_KEY_NOT_WRAPPABLE 0x00000069UL
+#define CKR_KEY_UNEXTRACTABLE 0x0000006AUL
+
+#define CKR_MECHANISM_INVALID 0x00000070UL
+#define CKR_MECHANISM_PARAM_INVALID 0x00000071UL
+
+#define CKR_OBJECT_HANDLE_INVALID 0x00000082UL
+#define CKR_OPERATION_ACTIVE 0x00000090UL
+#define CKR_OPERATION_NOT_INITIALIZED 0x00000091UL
+#define CKR_PIN_INCORRECT 0x000000A0UL
+#define CKR_PIN_INVALID 0x000000A1UL
+#define CKR_PIN_LEN_RANGE 0x000000A2UL
+
+#define CKR_PIN_EXPIRED 0x000000A3UL
+#define CKR_PIN_LOCKED 0x000000A4UL
+
+#define CKR_SESSION_CLOSED 0x000000B0UL
+#define CKR_SESSION_COUNT 0x000000B1UL
+#define CKR_SESSION_HANDLE_INVALID 0x000000B3UL
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4UL
+#define CKR_SESSION_READ_ONLY 0x000000B5UL
+#define CKR_SESSION_EXISTS 0x000000B6UL
+
+#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7UL
+#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8UL
+
+#define CKR_SIGNATURE_INVALID 0x000000C0UL
+#define CKR_SIGNATURE_LEN_RANGE 0x000000C1UL
+#define CKR_TEMPLATE_INCOMPLETE 0x000000D0UL
+#define CKR_TEMPLATE_INCONSISTENT 0x000000D1UL
+#define CKR_TOKEN_NOT_PRESENT 0x000000E0UL
+#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1UL
+#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2UL
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0UL
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1UL
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2UL
+#define CKR_USER_ALREADY_LOGGED_IN 0x00000100UL
+#define CKR_USER_NOT_LOGGED_IN 0x00000101UL
+#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102UL
+#define CKR_USER_TYPE_INVALID 0x00000103UL
+
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104UL
+#define CKR_USER_TOO_MANY_TYPES 0x00000105UL
+
+#define CKR_WRAPPED_KEY_INVALID 0x00000110UL
+#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112UL
+#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113UL
+#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114UL
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115UL
+#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120UL
+
+#define CKR_RANDOM_NO_RNG 0x00000121UL
+
+#define CKR_DOMAIN_PARAMS_INVALID 0x00000130UL
+
+#define CKR_CURVE_NOT_SUPPORTED 0x00000140UL
+
+#define CKR_BUFFER_TOO_SMALL 0x00000150UL
+#define CKR_SAVED_STATE_INVALID 0x00000160UL
+#define CKR_INFORMATION_SENSITIVE 0x00000170UL
+#define CKR_STATE_UNSAVEABLE 0x00000180UL
+
+#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190UL
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191UL
+#define CKR_MUTEX_BAD 0x000001A0UL
+#define CKR_MUTEX_NOT_LOCKED 0x000001A1UL
+
+#define CKR_NEW_PIN_MODE 0x000001B0UL
+#define CKR_NEXT_OTP 0x000001B1UL
+
+#define CKR_EXCEEDED_MAX_ITERATIONS 0x000001B5UL
+#define CKR_FIPS_SELF_TEST_FAILED 0x000001B6UL
+#define CKR_LIBRARY_LOAD_FAILED 0x000001B7UL
+#define CKR_PIN_TOO_WEAK 0x000001B8UL
+#define CKR_PUBLIC_KEY_INVALID 0x000001B9UL
+
+#define CKR_FUNCTION_REJECTED 0x00000200UL
+
+#define CKR_VENDOR_DEFINED 0x80000000UL
+
+/* private extra values */
+#define CKR_LIBRARY_ALREADY_INITIALIZED 0x000000FDUL
+#define CKR_LIBRARY_FAILED_TO_LOAD 0x000000FEUL
+#define CKR_SYMBOL_RESOLUTION_FAILED 0x000000FFUL
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
+ * version and pointers of appropriate types to all the
+ * Cryptoki functions
+ */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object
+ */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+ CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object
+ */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex
+ */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize
+ */
+typedef struct CK_C_INITIALIZE_ARGS {
+ CK_CREATEMUTEX CreateMutex;
+ CK_DESTROYMUTEX DestroyMutex;
+ CK_LOCKMUTEX LockMutex;
+ CK_UNLOCKMUTEX UnlockMutex;
+ CK_FLAGS flags;
+ CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001UL
+#define CKF_OS_LOCKING_OK 0x00000002UL
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK 1
+
+/* CK_RSA_PKCS_MGF_TYPE is used to indicate the Message
+ * Generation Function (MGF) applied to a message block when
+ * formatting a message block for the PKCS #1 OAEP encryption
+ * scheme.
+ */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+#define CKG_MGF1_SHA1 0x00000001UL
+#define CKG_MGF1_SHA256 0x00000002UL
+#define CKG_MGF1_SHA384 0x00000003UL
+#define CKG_MGF1_SHA512 0x00000004UL
+#define CKG_MGF1_SHA224 0x00000005UL
+
+/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source
+ * of the encoding parameter when formatting a message block
+ * for the PKCS #1 OAEP encryption scheme.
+ */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED 0x00000001UL
+
+/* CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_OAEP mechanism.
+ */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+ CK_VOID_PTR pSourceData;
+ CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/* CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s).
+ */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_ULONG sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+typedef CK_ULONG CK_EC_KDF_TYPE;
+
+/* The following EC Key Derivation Functions are defined */
+#define CKD_NULL 0x00000001UL
+#define CKD_SHA1_KDF 0x00000002UL
+
+/* The following X9.42 DH key derivation functions are defined */
+#define CKD_SHA1_KDF_ASN1 0x00000003UL
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004UL
+#define CKD_SHA224_KDF 0x00000005UL
+#define CKD_SHA256_KDF 0x00000006UL
+#define CKD_SHA384_KDF 0x00000007UL
+#define CKD_SHA512_KDF 0x00000008UL
+#define CKD_CPDIVERSIFY_KDF 0x00000009UL
+
+
+/* CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
+ * where each party contributes one key pair.
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
+
+/*
+ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs.
+ */
+typedef struct CK_ECDH2_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_ECDH2_DERIVE_PARAMS;
+
+typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_ECMQV_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_ECMQV_DERIVE_PARAMS;
+
+typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
+
+/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
+ * CKM_X9_42_DH_PARAMETER_GEN mechanisms
+ */
+typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
+typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
+
+/* CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
+ * contributes one key pair
+ */
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_X9_42_DH1_DERIVE_PARAMS;
+
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
+
+/* CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
+ * mechanisms, where each party contributes two key pairs
+ */
+typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_X9_42_DH2_DERIVE_PARAMS;
+
+typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_X9_42_MQV_DERIVE_PARAMS;
+
+typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism
+ */
+typedef struct CK_KEA_DERIVE_PARAMS {
+ CK_BBOOL isSender;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pRandomB;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just
+ * holds the effective keysize
+ */
+typedef CK_ULONG CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism
+ */
+typedef struct CK_RC2_CBC_PARAMS {
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+ CK_BYTE iv[8]; /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism
+ */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms
+ */
+typedef struct CK_RC5_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism
+ */
+typedef struct CK_RC5_CBC_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_BYTE_PTR pIv; /* pointer to IV */
+ CK_ULONG ulIvLen; /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism
+ */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms. Its value is the length of
+ * the MAC
+ */
+typedef CK_ULONG CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[8];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism
+ */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pPassword;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPAndGLen;
+ CK_ULONG ulQLen;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pPrimeP;
+ CK_BYTE_PTR pBaseG;
+ CK_BYTE_PTR pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+ CK_SKIPJACK_PRIVATE_WRAP_PARAMS_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism
+ */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+ CK_ULONG ulOldWrappedXLen;
+ CK_BYTE_PTR pOldWrappedX;
+ CK_ULONG ulOldPasswordLen;
+ CK_BYTE_PTR pOldPassword;
+ CK_ULONG ulOldPublicDataLen;
+ CK_BYTE_PTR pOldPublicData;
+ CK_ULONG ulOldRandomLen;
+ CK_BYTE_PTR pOldRandomA;
+ CK_ULONG ulNewPasswordLen;
+ CK_BYTE_PTR pNewPassword;
+ CK_ULONG ulNewPublicDataLen;
+ CK_BYTE_PTR pNewPublicData;
+ CK_ULONG ulNewRandomLen;
+ CK_BYTE_PTR pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+ CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+ CK_BYTE_PTR pInitVector;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pSalt;
+ CK_ULONG ulSaltLen;
+ CK_ULONG ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism
+ */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+ CK_BYTE bBC; /* block contents byte */
+ CK_BYTE_PTR pX; /* extra data */
+ CK_ULONG ulXLen; /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+typedef struct CK_SSL3_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hClientMacSecret;
+ CK_OBJECT_HANDLE hServerMacSecret;
+ CK_OBJECT_HANDLE hClientKey;
+ CK_OBJECT_HANDLE hServerKey;
+ CK_BYTE_PTR pIVClient;
+ CK_BYTE_PTR pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_BBOOL bIsExport;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_TLS_PRF_PARAMS {
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_TLS_PRF_PARAMS;
+
+typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_WTLS_RANDOM_DATA;
+
+typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
+
+typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_BYTE_PTR pVersion;
+} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_WTLS_PRF_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_WTLS_PRF_PARAMS;
+
+typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hMacSecret;
+ CK_OBJECT_HANDLE hKey;
+ CK_BYTE_PTR pIV;
+} CK_WTLS_KEY_MAT_OUT;
+
+typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_ULONG ulSequenceNumber;
+ CK_BBOOL bIsExport;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_WTLS_KEY_MAT_PARAMS;
+
+typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_CMS_SIG_PARAMS {
+ CK_OBJECT_HANDLE certificateHandle;
+ CK_MECHANISM_PTR pSigningMechanism;
+ CK_MECHANISM_PTR pDigestMechanism;
+ CK_UTF8CHAR_PTR pContentType;
+ CK_BYTE_PTR pRequestedAttributes;
+ CK_ULONG ulRequestedAttributesLen;
+ CK_BYTE_PTR pRequiredAttributes;
+ CK_ULONG ulRequiredAttributesLen;
+} CK_CMS_SIG_PARAMS;
+
+typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR;
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+ CK_BYTE_PTR pData;
+ CK_ULONG ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+ CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key
+ */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
+ * indicate the Pseudo-Random Function (PRF) used to generate
+ * key bits using PKCS #5 PBKDF2.
+ */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR \
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001UL
+#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411 0x00000002UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA224 0x00000003UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA256 0x00000004UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA384 0x00000005UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA512 0x00000006UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA512_224 0x00000007UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA512_256 0x00000008UL
+
+/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
+ * source of the salt value when deriving a key using PKCS #5
+ * PBKDF2.
+ */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR \
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED 0x00000001UL
+
+/* CK_PKCS5_PBKD2_PARAMS is a structure that provides the
+ * parameters to the CKM_PKCS5_PBKD2 mechanism.
+ */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+ CK_VOID_PTR pSaltSourceData;
+ CK_ULONG ulSaltSourceDataLen;
+ CK_ULONG iterations;
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+ CK_VOID_PTR pPrfData;
+ CK_ULONG ulPrfDataLen;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG_PTR ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PARAMS2 is a corrected version of the CK_PKCS5_PBKD2_PARAMS
+ * structure that provides the parameters to the CKM_PKCS5_PBKD2 mechanism
+ * noting that the ulPasswordLen field is a CK_ULONG and not a CK_ULONG_PTR.
+ */
+typedef struct CK_PKCS5_PBKD2_PARAMS2 {
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+ CK_VOID_PTR pSaltSourceData;
+ CK_ULONG ulSaltSourceDataLen;
+ CK_ULONG iterations;
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+ CK_VOID_PTR pPrfData;
+ CK_ULONG ulPrfDataLen;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS2;
+
+typedef CK_PKCS5_PBKD2_PARAMS2 CK_PTR CK_PKCS5_PBKD2_PARAMS2_PTR;
+
+typedef CK_ULONG CK_OTP_PARAM_TYPE;
+typedef CK_OTP_PARAM_TYPE CK_PARAM_TYPE; /* backward compatibility */
+
+typedef struct CK_OTP_PARAM {
+ CK_OTP_PARAM_TYPE type;
+ CK_VOID_PTR pValue;
+ CK_ULONG ulValueLen;
+} CK_OTP_PARAM;
+
+typedef CK_OTP_PARAM CK_PTR CK_OTP_PARAM_PTR;
+
+typedef struct CK_OTP_PARAMS {
+ CK_OTP_PARAM_PTR pParams;
+ CK_ULONG ulCount;
+} CK_OTP_PARAMS;
+
+typedef CK_OTP_PARAMS CK_PTR CK_OTP_PARAMS_PTR;
+
+typedef struct CK_OTP_SIGNATURE_INFO {
+ CK_OTP_PARAM_PTR pParams;
+ CK_ULONG ulCount;
+} CK_OTP_SIGNATURE_INFO;
+
+typedef CK_OTP_SIGNATURE_INFO CK_PTR CK_OTP_SIGNATURE_INFO_PTR;
+
+#define CK_OTP_VALUE 0UL
+#define CK_OTP_PIN 1UL
+#define CK_OTP_CHALLENGE 2UL
+#define CK_OTP_TIME 3UL
+#define CK_OTP_COUNTER 4UL
+#define CK_OTP_FLAGS 5UL
+#define CK_OTP_OUTPUT_LENGTH 6UL
+#define CK_OTP_OUTPUT_FORMAT 7UL
+
+#define CKF_NEXT_OTP 0x00000001UL
+#define CKF_EXCLUDE_TIME 0x00000002UL
+#define CKF_EXCLUDE_COUNTER 0x00000004UL
+#define CKF_EXCLUDE_CHALLENGE 0x00000008UL
+#define CKF_EXCLUDE_PIN 0x00000010UL
+#define CKF_USER_FRIENDLY_OTP 0x00000020UL
+
+typedef struct CK_KIP_PARAMS {
+ CK_MECHANISM_PTR pMechanism;
+ CK_OBJECT_HANDLE hKey;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+} CK_KIP_PARAMS;
+
+typedef CK_KIP_PARAMS CK_PTR CK_KIP_PARAMS_PTR;
+
+typedef struct CK_AES_CTR_PARAMS {
+ CK_ULONG ulCounterBits;
+ CK_BYTE cb[16];
+} CK_AES_CTR_PARAMS;
+
+typedef CK_AES_CTR_PARAMS CK_PTR CK_AES_CTR_PARAMS_PTR;
+
+typedef struct CK_GCM_PARAMS {
+ CK_BYTE_PTR pIv;
+ CK_ULONG ulIvLen;
+ CK_ULONG ulIvBits;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulTagBits;
+} CK_GCM_PARAMS;
+
+typedef CK_GCM_PARAMS CK_PTR CK_GCM_PARAMS_PTR;
+
+typedef struct CK_CCM_PARAMS {
+ CK_ULONG ulDataLen;
+ CK_BYTE_PTR pNonce;
+ CK_ULONG ulNonceLen;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulMACLen;
+} CK_CCM_PARAMS;
+
+typedef CK_CCM_PARAMS CK_PTR CK_CCM_PARAMS_PTR;
+
+/* Deprecated. Use CK_GCM_PARAMS */
+typedef struct CK_AES_GCM_PARAMS {
+ CK_BYTE_PTR pIv;
+ CK_ULONG ulIvLen;
+ CK_ULONG ulIvBits;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulTagBits;
+} CK_AES_GCM_PARAMS;
+
+typedef CK_AES_GCM_PARAMS CK_PTR CK_AES_GCM_PARAMS_PTR;
+
+/* Deprecated. Use CK_CCM_PARAMS */
+typedef struct CK_AES_CCM_PARAMS {
+ CK_ULONG ulDataLen;
+ CK_BYTE_PTR pNonce;
+ CK_ULONG ulNonceLen;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulMACLen;
+} CK_AES_CCM_PARAMS;
+
+typedef CK_AES_CCM_PARAMS CK_PTR CK_AES_CCM_PARAMS_PTR;
+
+typedef struct CK_CAMELLIA_CTR_PARAMS {
+ CK_ULONG ulCounterBits;
+ CK_BYTE cb[16];
+} CK_CAMELLIA_CTR_PARAMS;
+
+typedef CK_CAMELLIA_CTR_PARAMS CK_PTR CK_CAMELLIA_CTR_PARAMS_PTR;
+
+typedef struct CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
+ CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_ARIA_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_ARIA_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_ARIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
+ CK_ARIA_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_DSA_PARAMETER_GEN_PARAM {
+ CK_MECHANISM_TYPE hash;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_ULONG ulIndex;
+} CK_DSA_PARAMETER_GEN_PARAM;
+
+typedef CK_DSA_PARAMETER_GEN_PARAM CK_PTR CK_DSA_PARAMETER_GEN_PARAM_PTR;
+
+typedef struct CK_ECDH_AES_KEY_WRAP_PARAMS {
+ CK_ULONG ulAESKeyBits;
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+} CK_ECDH_AES_KEY_WRAP_PARAMS;
+
+typedef CK_ECDH_AES_KEY_WRAP_PARAMS CK_PTR CK_ECDH_AES_KEY_WRAP_PARAMS_PTR;
+
+typedef CK_ULONG CK_JAVA_MIDP_SECURITY_DOMAIN;
+
+typedef CK_ULONG CK_CERTIFICATE_CATEGORY;
+
+typedef struct CK_RSA_AES_KEY_WRAP_PARAMS {
+ CK_ULONG ulAESKeyBits;
+ CK_RSA_PKCS_OAEP_PARAMS_PTR pOAEPParams;
+} CK_RSA_AES_KEY_WRAP_PARAMS;
+
+typedef CK_RSA_AES_KEY_WRAP_PARAMS CK_PTR CK_RSA_AES_KEY_WRAP_PARAMS_PTR;
+
+typedef struct CK_TLS12_MASTER_KEY_DERIVE_PARAMS {
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_VERSION_PTR pVersion;
+ CK_MECHANISM_TYPE prfHashMechanism;
+} CK_TLS12_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_TLS12_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_TLS12_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_TLS12_KEY_MAT_PARAMS {
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_BBOOL bIsExport;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+ CK_MECHANISM_TYPE prfHashMechanism;
+} CK_TLS12_KEY_MAT_PARAMS;
+
+typedef CK_TLS12_KEY_MAT_PARAMS CK_PTR CK_TLS12_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_TLS_KDF_PARAMS {
+ CK_MECHANISM_TYPE prfMechanism;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLength;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_BYTE_PTR pContextData;
+ CK_ULONG ulContextDataLength;
+} CK_TLS_KDF_PARAMS;
+
+typedef CK_TLS_KDF_PARAMS CK_PTR CK_TLS_KDF_PARAMS_PTR;
+
+typedef struct CK_TLS_MAC_PARAMS {
+ CK_MECHANISM_TYPE prfHashMechanism;
+ CK_ULONG ulMacLength;
+ CK_ULONG ulServerOrClient;
+} CK_TLS_MAC_PARAMS;
+
+typedef CK_TLS_MAC_PARAMS CK_PTR CK_TLS_MAC_PARAMS_PTR;
+
+typedef struct CK_GOSTR3410_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pUKM;
+ CK_ULONG ulUKMLen;
+} CK_GOSTR3410_DERIVE_PARAMS;
+
+typedef CK_GOSTR3410_DERIVE_PARAMS CK_PTR CK_GOSTR3410_DERIVE_PARAMS_PTR;
+
+typedef struct CK_GOSTR3410_KEY_WRAP_PARAMS {
+ CK_BYTE_PTR pWrapOID;
+ CK_ULONG ulWrapOIDLen;
+ CK_BYTE_PTR pUKM;
+ CK_ULONG ulUKMLen;
+ CK_OBJECT_HANDLE hKey;
+} CK_GOSTR3410_KEY_WRAP_PARAMS;
+
+typedef CK_GOSTR3410_KEY_WRAP_PARAMS CK_PTR CK_GOSTR3410_KEY_WRAP_PARAMS_PTR;
+
+typedef struct CK_SEED_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_SEED_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_SEED_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
+ CK_SEED_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+#endif /* _PKCS11T_H_ */
+
diff --git a/lib/isc/inet_aton.c b/lib/isc/inet_aton.c
new file mode 100644
index 0000000..aa54667
--- /dev/null
+++ b/lib/isc/inet_aton.c
@@ -0,0 +1,187 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * Copyright (c) 1983, 1990, 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. 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.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/*! \file */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
+static char rcsid[] = "$Id: inet_aton.c,v 1.23 2008/12/01 23:47:45 tbox Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stddef.h> /* Required for NULL. */
+
+#include <isc/types.h>
+#include <isc/net.h>
+
+/*%
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+isc_net_aton(const char *cp, struct in_addr *addr) {
+ uint32_t val;
+ int base;
+ ptrdiff_t n;
+ unsigned char c;
+ uint32_t parts[4];
+ uint32_t *pp = parts;
+ int digit;
+
+ c = *cp;
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, isdigit=decimal.
+ */
+ if (!isdigit(c & 0xff))
+ return (0);
+ val = 0; base = 10; digit = 0;
+ if (c == '0') {
+ c = *++cp;
+ if (c == 'x' || c == 'X')
+ base = 16, c = *++cp;
+ else {
+ base = 8;
+ digit = 1;
+ }
+ }
+ for (;;) {
+ /*
+ * isascii() is valid for all integer values, and
+ * when it is true, c is known to be in scope
+ * for isdigit(). No cast necessary. Similar
+ * comment applies for later ctype uses.
+ */
+ if (isascii(c) && isdigit(c)) {
+ if (base == 8 && (c == '8' || c == '9'))
+ return (0);
+ val = (val * base) + (c - '0');
+ c = *++cp;
+ digit = 1;
+ } else if (base == 16 && isascii(c) && isxdigit(c)) {
+ val = (val << 4) |
+ (c + 10 - (islower(c) ? 'a' : 'A'));
+ c = *++cp;
+ digit = 1;
+ } else
+ break;
+ }
+ if (c == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16 bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xffU)
+ return (0);
+ *pp++ = val;
+ c = *++cp;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (c != '\0' && (!isascii(c) || !isspace(c)))
+ return (0);
+ /*
+ * Did we get a valid digit?
+ */
+ if (!digit)
+ return (0);
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffffU)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffffU)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xffU)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr != NULL)
+ addr->s_addr = htonl(val);
+
+ return (1);
+}
diff --git a/lib/isc/inet_ntop.c b/lib/isc/inet_ntop.c
new file mode 100644
index 0000000..fb06f85
--- /dev/null
+++ b/lib/isc/inet_ntop.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include <isc/net.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define NS_INT16SZ 2
+#define NS_IN6ADDRSZ 16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4(const unsigned char *src, char *dst,
+ size_t size);
+
+#ifdef AF_INET6
+static const char *inet_ntop6(const unsigned char *src, char *dst,
+ size_t size);
+#endif
+
+/*! char *
+ * isc_net_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * \return
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * \author
+ * Paul Vixie, 1996.
+ */
+const char *
+isc_net_ntop(int af, const void *src, char *dst, size_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+#ifdef AF_INET6
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+/*! const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address
+ * \return
+ * `dst' (as a const)
+ * \note
+ * (1) uses no statics
+ * \note
+ * (2) takes a unsigned char* not an in_addr as input
+ * \author
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, size_t size)
+{
+ static const char *fmt = "%u.%u.%u.%u";
+ char tmp[sizeof("255.255.255.255")];
+ int n;
+
+
+ n = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+ if (n < 0 || (size_t)n >= size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strlcpy(dst, tmp, size);
+
+ return (dst);
+}
+
+/*! const char *
+ * isc_inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * \author
+ * Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static const char *
+inet_ntop6(const unsigned char *src, char *dst, size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")], *tp;
+ struct { int base, len; } best, cur;
+ unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof(words));
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0; /* silence compiler */
+ cur.base = -1;
+ cur.len = 0; /* silence compiler */
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 && (best.len == 6 ||
+ (best.len == 7 && words[7] != 0x0001) ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src+12, tp,
+ sizeof(tmp) - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
+ }
+ INSIST((size_t)(tp - tmp) < sizeof(tmp));
+ tp += snprintf(tp, sizeof(tmp) - (tp - tmp), "%x", words[i]);
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strlcpy(dst, tmp, size);
+ return (dst);
+}
+#endif /* AF_INET6 */
diff --git a/lib/isc/inet_pton.c b/lib/isc/inet_pton.c
new file mode 100644
index 0000000..bde88e3
--- /dev/null
+++ b/lib/isc/inet_pton.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <isc/net.h>
+
+/*% INT16 Size */
+#define NS_INT16SZ 2
+/*% IPv4 Address Size */
+#define NS_INADDRSZ 4
+/*% IPv6 Address Size */
+#define NS_IN6ADDRSZ 16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+static int inet_pton6(const char *src, unsigned char *dst);
+
+/*%
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * \return
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * \author
+ * Paul Vixie, 1996.
+ */
+int
+isc_net_pton(int af, const char *src, void *dst) {
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/*!\fn static int inet_pton4(const char *src, unsigned char *dst)
+ * \brief
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * \return
+ * 1 if `src' is a valid dotted quad, else 0.
+ * \note
+ * does not touch `dst' unless it's returning 1.
+ * \author
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst) {
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ unsigned int byte = *tp * 10;
+
+ byte += (int)(pch - digits);
+ if (saw_digit && *tp == 0)
+ return (0);
+ if (byte > 255)
+ return (0);
+ *tp = byte;
+ if (!saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memmove(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+/*%
+ * convert presentation level address to network order binary form.
+ * \return
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * \note
+ * (1) does not touch `dst' unless it's returning 1.
+ * \note
+ * (2) :: in a full address is silently ignored.
+ * \author
+ * inspired by Mark Andrews.
+ * \author
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, seen_xdigits;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ seen_xdigits = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++seen_xdigits > 4)
+ return (0);
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!seen_xdigits) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ seen_xdigits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ seen_xdigits = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (seen_xdigits) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = (int)(tp - colonp);
+ int i;
+
+ if (tp == endp)
+ return (0);
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memmove(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
diff --git a/lib/isc/iterated_hash.c b/lib/isc/iterated_hash.c
new file mode 100644
index 0000000..cf4e67f
--- /dev/null
+++ b/lib/isc/iterated_hash.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <isc/sha1.h>
+#include <isc/iterated_hash.h>
+
+int
+isc_iterated_hash(unsigned char out[ISC_SHA1_DIGESTLENGTH],
+ unsigned int hashalg, int iterations,
+ const unsigned char *salt, int saltlength,
+ const unsigned char *in, int inlength)
+{
+ isc_sha1_t ctx;
+ int n = 0;
+
+ if (hashalg != 1)
+ return (0);
+
+ do {
+ isc_sha1_init(&ctx);
+ isc_sha1_update(&ctx, in, inlength);
+ isc_sha1_update(&ctx, salt, saltlength);
+ isc_sha1_final(&ctx, out);
+ in = out;
+ inlength = ISC_SHA1_DIGESTLENGTH;
+ } while (n++ < iterations);
+
+ return (ISC_SHA1_DIGESTLENGTH);
+}
diff --git a/lib/isc/lex.c b/lib/isc/lex.c
new file mode 100644
index 0000000..a8955bc
--- /dev/null
+++ b/lib/isc/lex.c
@@ -0,0 +1,1051 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/file.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/parseint.h>
+#include <isc/print.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+typedef struct inputsource {
+ isc_result_t result;
+ bool is_file;
+ bool need_close;
+ bool at_eof;
+ bool last_was_eol;
+ isc_buffer_t * pushback;
+ unsigned int ignored;
+ void * input;
+ char * name;
+ unsigned long line;
+ unsigned long saved_line;
+ ISC_LINK(struct inputsource) link;
+} inputsource;
+
+#define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!')
+#define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC)
+
+struct isc_lex {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ size_t max_token;
+ char * data;
+ unsigned int comments;
+ bool comment_ok;
+ bool last_was_eol;
+ unsigned int brace_count;
+ unsigned int paren_count;
+ unsigned int saved_paren_count;
+ isc_lexspecials_t specials;
+ LIST(struct inputsource) sources;
+};
+
+static inline isc_result_t
+grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
+ char *tmp;
+
+ tmp = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
+ if (tmp == NULL)
+ return (ISC_R_NOMEMORY);
+ memmove(tmp, lex->data, lex->max_token + 1);
+ *currp = tmp + (*currp - lex->data);
+ if (*prevp != NULL)
+ *prevp = tmp + (*prevp - lex->data);
+ isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
+ lex->data = tmp;
+ *remainingp += lex->max_token;
+ lex->max_token *= 2;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
+ isc_lex_t *lex;
+
+ /*
+ * Create a lexer.
+ */
+ REQUIRE(lexp != NULL && *lexp == NULL);
+
+ if (max_token == 0U)
+ max_token = 1;
+
+ lex = isc_mem_get(mctx, sizeof(*lex));
+ if (lex == NULL)
+ return (ISC_R_NOMEMORY);
+ lex->data = isc_mem_get(mctx, max_token + 1);
+ if (lex->data == NULL) {
+ isc_mem_put(mctx, lex, sizeof(*lex));
+ return (ISC_R_NOMEMORY);
+ }
+ lex->mctx = mctx;
+ lex->max_token = max_token;
+ lex->comments = 0;
+ lex->comment_ok = true;
+ lex->last_was_eol = true;
+ lex->brace_count = 0;
+ lex->paren_count = 0;
+ lex->saved_paren_count = 0;
+ memset(lex->specials, 0, 256);
+ INIT_LIST(lex->sources);
+ lex->magic = LEX_MAGIC;
+
+ *lexp = lex;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_lex_destroy(isc_lex_t **lexp) {
+ isc_lex_t *lex;
+
+ /*
+ * Destroy the lexer.
+ */
+
+ REQUIRE(lexp != NULL);
+ lex = *lexp;
+ REQUIRE(VALID_LEX(lex));
+
+ while (!EMPTY(lex->sources))
+ RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
+ if (lex->data != NULL)
+ isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
+ lex->magic = 0;
+ isc_mem_put(lex->mctx, lex, sizeof(*lex));
+
+ *lexp = NULL;
+}
+
+unsigned int
+isc_lex_getcomments(isc_lex_t *lex) {
+ /*
+ * Return the current lexer commenting styles.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ return (lex->comments);
+}
+
+void
+isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
+ /*
+ * Set allowed lexer commenting styles.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ lex->comments = comments;
+}
+
+void
+isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
+ /*
+ * Put the current list of specials into 'specials'.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ memmove(specials, lex->specials, 256);
+}
+
+void
+isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
+ /*
+ * The characters in 'specials' are returned as tokens. Along with
+ * whitespace, they delimit strings and numbers.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ memmove(lex->specials, specials, 256);
+}
+
+static inline isc_result_t
+new_source(isc_lex_t *lex, bool is_file, bool need_close,
+ void *input, const char *name)
+{
+ inputsource *source;
+ isc_result_t result;
+
+ source = isc_mem_get(lex->mctx, sizeof(*source));
+ if (source == NULL)
+ return (ISC_R_NOMEMORY);
+ source->result = ISC_R_SUCCESS;
+ source->is_file = is_file;
+ source->need_close = need_close;
+ source->at_eof = false;
+ source->last_was_eol = lex->last_was_eol;
+ source->input = input;
+ source->name = isc_mem_strdup(lex->mctx, name);
+ if (source->name == NULL) {
+ isc_mem_put(lex->mctx, source, sizeof(*source));
+ return (ISC_R_NOMEMORY);
+ }
+ source->pushback = NULL;
+ result = isc_buffer_allocate(lex->mctx, &source->pushback,
+ (unsigned int)lex->max_token);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_free(lex->mctx, source->name);
+ isc_mem_put(lex->mctx, source, sizeof(*source));
+ return (result);
+ }
+ source->ignored = 0;
+ source->line = 1;
+ ISC_LIST_INITANDPREPEND(lex->sources, source, link);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_openfile(isc_lex_t *lex, const char *filename) {
+ isc_result_t result;
+ FILE *stream = NULL;
+
+ /*
+ * Open 'filename' and make it the current input source for 'lex'.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ result = isc_stdio_open(filename, "r", &stream);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = new_source(lex, true, true, stream, filename);
+ if (result != ISC_R_SUCCESS)
+ (void)fclose(stream);
+ return (result);
+}
+
+isc_result_t
+isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
+ char name[128];
+
+ /*
+ * Make 'stream' the current input source for 'lex'.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ snprintf(name, sizeof(name), "stream-%p", stream);
+
+ return (new_source(lex, true, false, stream, name));
+}
+
+isc_result_t
+isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
+ char name[128];
+
+ /*
+ * Make 'buffer' the current input source for 'lex'.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ snprintf(name, sizeof(name), "buffer-%p", buffer);
+
+ return (new_source(lex, false, false, buffer, name));
+}
+
+isc_result_t
+isc_lex_close(isc_lex_t *lex) {
+ inputsource *source;
+
+ /*
+ * Close the most recently opened object (i.e. file or buffer).
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ source = HEAD(lex->sources);
+ if (source == NULL)
+ return (ISC_R_NOMORE);
+
+ ISC_LIST_UNLINK(lex->sources, source, link);
+ lex->last_was_eol = source->last_was_eol;
+ if (source->is_file) {
+ if (source->need_close)
+ (void)fclose((FILE *)(source->input));
+ }
+ isc_mem_free(lex->mctx, source->name);
+ isc_buffer_free(&source->pushback);
+ isc_mem_put(lex->mctx, source, sizeof(*source));
+
+ return (ISC_R_SUCCESS);
+}
+
+typedef enum {
+ lexstate_start,
+ lexstate_crlf,
+ lexstate_string,
+ lexstate_number,
+ lexstate_maybecomment,
+ lexstate_ccomment,
+ lexstate_ccommentend,
+ lexstate_eatline,
+ lexstate_qstring,
+ lexstate_btext
+} lexstate;
+
+#define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
+
+static void
+pushback(inputsource *source, int c) {
+ REQUIRE(source->pushback->current > 0);
+ if (c == EOF) {
+ source->at_eof = false;
+ return;
+ }
+ source->pushback->current--;
+ if (c == '\n')
+ source->line--;
+}
+
+static isc_result_t
+pushandgrow(isc_lex_t *lex, inputsource *source, int c) {
+ if (isc_buffer_availablelength(source->pushback) == 0) {
+ isc_buffer_t *tbuf = NULL;
+ unsigned int oldlen;
+ isc_region_t used;
+ isc_result_t result;
+
+ oldlen = isc_buffer_length(source->pushback);
+ result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_usedregion(source->pushback, &used);
+ result = isc_buffer_copyregion(tbuf, &used);
+ INSIST(result == ISC_R_SUCCESS);
+ tbuf->current = source->pushback->current;
+ isc_buffer_free(&source->pushback);
+ source->pushback = tbuf;
+ }
+ isc_buffer_putuint8(source->pushback, (uint8_t)c);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
+ inputsource *source;
+ int c;
+ bool done = false;
+ bool no_comments = false;
+ bool escaped = false;
+ lexstate state = lexstate_start;
+ lexstate saved_state = lexstate_start;
+ isc_buffer_t *buffer;
+ FILE *stream;
+ char *curr, *prev;
+ size_t remaining;
+ uint32_t as_ulong;
+ unsigned int saved_options;
+ isc_result_t result;
+
+ /*
+ * Get the next token.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+ REQUIRE(tokenp != NULL);
+
+ if (source == NULL) {
+ if ((options & ISC_LEXOPT_NOMORE) != 0) {
+ tokenp->type = isc_tokentype_nomore;
+ return (ISC_R_SUCCESS);
+ }
+ return (ISC_R_NOMORE);
+ }
+
+ if (source->result != ISC_R_SUCCESS)
+ return (source->result);
+
+ lex->saved_paren_count = lex->paren_count;
+ source->saved_line = source->line;
+
+ if (isc_buffer_remaininglength(source->pushback) == 0 &&
+ source->at_eof)
+ {
+ if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
+ lex->paren_count != 0)
+ {
+ lex->paren_count = 0;
+ return (ISC_R_UNBALANCED);
+ }
+ if ((options & ISC_LEXOPT_BTEXT) != 0 &&
+ lex->brace_count != 0)
+ {
+ lex->brace_count = 0;
+ return (ISC_R_UNBALANCED);
+ }
+ if ((options & ISC_LEXOPT_EOF) != 0) {
+ tokenp->type = isc_tokentype_eof;
+ return (ISC_R_SUCCESS);
+ }
+ return (ISC_R_EOF);
+ }
+
+ isc_buffer_compact(source->pushback);
+
+ saved_options = options;
+ if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
+ options &= ~IWSEOL;
+
+ curr = lex->data;
+ *curr = '\0';
+
+ prev = NULL;
+ remaining = lex->max_token;
+
+#ifdef HAVE_FLOCKFILE
+ if (source->is_file)
+ flockfile(source->input);
+#endif
+
+ do {
+ if (isc_buffer_remaininglength(source->pushback) == 0) {
+ if (source->is_file) {
+ stream = source->input;
+
+#if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED)
+ c = getc_unlocked(stream);
+#else
+ c = getc(stream);
+#endif
+ if (c == EOF) {
+ if (ferror(stream)) {
+ source->result = ISC_R_IOERROR;
+ result = source->result;
+ goto done;
+ }
+ source->at_eof = true;
+ }
+ } else {
+ buffer = source->input;
+
+ if (buffer->current == buffer->used) {
+ c = EOF;
+ source->at_eof = true;
+ } else {
+ c = *((unsigned char *)buffer->base +
+ buffer->current);
+ buffer->current++;
+ }
+ }
+ if (c != EOF) {
+ source->result = pushandgrow(lex, source, c);
+ if (source->result != ISC_R_SUCCESS) {
+ result = source->result;
+ goto done;
+ }
+ }
+ }
+
+ if (!source->at_eof) {
+ if (state == lexstate_start)
+ /* Token has not started yet. */
+ source->ignored =
+ isc_buffer_consumedlength(source->pushback);
+ c = isc_buffer_getuint8(source->pushback);
+ } else {
+ c = EOF;
+ }
+
+ if (c == '\n')
+ source->line++;
+
+ if (lex->comment_ok && !no_comments) {
+ if (!escaped && c == ';' &&
+ ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE)
+ != 0)) {
+ saved_state = state;
+ state = lexstate_eatline;
+ no_comments = true;
+ continue;
+ } else if (c == '/' &&
+ (lex->comments &
+ (ISC_LEXCOMMENT_C|
+ ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
+ saved_state = state;
+ state = lexstate_maybecomment;
+ no_comments = true;
+ continue;
+ } else if (c == '#' &&
+ ((lex->comments & ISC_LEXCOMMENT_SHELL)
+ != 0)) {
+ saved_state = state;
+ state = lexstate_eatline;
+ no_comments = true;
+ continue;
+ }
+ }
+
+ no_read:
+ /* INSIST(c == EOF || (c >= 0 && c <= 255)); */
+ switch (state) {
+ case lexstate_start:
+ if (c == EOF) {
+ lex->last_was_eol = false;
+ if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
+ lex->paren_count != 0) {
+ lex->paren_count = 0;
+ result = ISC_R_UNBALANCED;
+ goto done;
+ }
+ if ((options & ISC_LEXOPT_BTEXT) != 0 &&
+ lex->brace_count != 0) {
+ lex->brace_count = 0;
+ result = ISC_R_UNBALANCED;
+ goto done;
+ }
+ if ((options & ISC_LEXOPT_EOF) == 0) {
+ result = ISC_R_EOF;
+ goto done;
+ }
+ tokenp->type = isc_tokentype_eof;
+ done = true;
+ } else if (c == ' ' || c == '\t') {
+ if (lex->last_was_eol &&
+ (options & ISC_LEXOPT_INITIALWS)
+ != 0) {
+ lex->last_was_eol = false;
+ tokenp->type = isc_tokentype_initialws;
+ tokenp->value.as_char = c;
+ done = true;
+ }
+ } else if (c == '\n') {
+ if ((options & ISC_LEXOPT_EOL) != 0) {
+ tokenp->type = isc_tokentype_eol;
+ done = true;
+ }
+ lex->last_was_eol = true;
+ } else if (c == '\r') {
+ if ((options & ISC_LEXOPT_EOL) != 0)
+ state = lexstate_crlf;
+ } else if (c == '"' &&
+ (options & ISC_LEXOPT_QSTRING) != 0) {
+ lex->last_was_eol = false;
+ no_comments = true;
+ state = lexstate_qstring;
+ } else if (lex->specials[c]) {
+ lex->last_was_eol = false;
+ if ((c == '(' || c == ')') &&
+ (options & ISC_LEXOPT_DNSMULTILINE) != 0)
+ {
+ if (c == '(') {
+ if (lex->paren_count == 0)
+ options &= ~IWSEOL;
+ lex->paren_count++;
+ } else {
+ if (lex->paren_count == 0) {
+ result =
+ ISC_R_UNBALANCED;
+ goto done;
+ }
+ lex->paren_count--;
+ if (lex->paren_count == 0)
+ options = saved_options;
+ }
+ continue;
+ } else if (c == '{' &&
+ (options & ISC_LEXOPT_BTEXT) != 0)
+ {
+ if (lex->brace_count != 0) {
+ result = ISC_R_UNBALANCED;
+ goto done;
+ }
+ lex->brace_count++;
+ options &= ~IWSEOL;
+ state = lexstate_btext;
+ no_comments = true;
+ continue;
+ }
+ tokenp->type = isc_tokentype_special;
+ tokenp->value.as_char = c;
+ done = true;
+ } else if (isdigit((unsigned char)c) &&
+ (options & ISC_LEXOPT_NUMBER) != 0) {
+ lex->last_was_eol = false;
+ if ((options & ISC_LEXOPT_OCTAL) != 0 &&
+ (c == '8' || c == '9'))
+ state = lexstate_string;
+ else
+ state = lexstate_number;
+ goto no_read;
+ } else {
+ lex->last_was_eol = false;
+ state = lexstate_string;
+ goto no_read;
+ }
+ break;
+ case lexstate_crlf:
+ if (c != '\n')
+ pushback(source, c);
+ tokenp->type = isc_tokentype_eol;
+ done = true;
+ lex->last_was_eol = true;
+ break;
+ case lexstate_number:
+ if (c == EOF || !isdigit((unsigned char)c)) {
+ if (c == ' ' || c == '\t' || c == '\r' ||
+ c == '\n' || c == EOF ||
+ lex->specials[c]) {
+ int base;
+ if ((options & ISC_LEXOPT_OCTAL) != 0)
+ base = 8;
+ else if ((options & ISC_LEXOPT_CNUMBER) != 0)
+ base = 0;
+ else
+ base = 10;
+ pushback(source, c);
+
+ result = isc_parse_uint32(&as_ulong,
+ lex->data,
+ base);
+ if (result == ISC_R_SUCCESS) {
+ tokenp->type =
+ isc_tokentype_number;
+ tokenp->value.as_ulong =
+ as_ulong;
+ } else if (result == ISC_R_BADNUMBER) {
+ isc_tokenvalue_t *v;
+
+ tokenp->type =
+ isc_tokentype_string;
+ v = &(tokenp->value);
+ v->as_textregion.base =
+ lex->data;
+ v->as_textregion.length =
+ (unsigned int)
+ (lex->max_token -
+ remaining);
+ } else
+ goto done;
+ done = true;
+ continue;
+ } else if (!(options & ISC_LEXOPT_CNUMBER) ||
+ ((c != 'x' && c != 'X') ||
+ (curr != &lex->data[1]) ||
+ (lex->data[0] != '0'))) {
+ /* Above test supports hex numbers */
+ state = lexstate_string;
+ }
+ } else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
+ (c == '8' || c == '9')) {
+ state = lexstate_string;
+ }
+ if (remaining == 0U) {
+ result = grow_data(lex, &remaining,
+ &curr, &prev);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ }
+ INSIST(remaining > 0U);
+ *curr++ = c;
+ *curr = '\0';
+ remaining--;
+ break;
+ case lexstate_string:
+ /*
+ * EOF needs to be checked before lex->specials[c]
+ * as lex->specials[EOF] is not a good idea.
+ */
+ if (c == '\r' || c == '\n' || c == EOF ||
+ (!escaped &&
+ (c == ' ' || c == '\t' || lex->specials[c]))) {
+ pushback(source, c);
+ if (source->result != ISC_R_SUCCESS) {
+ result = source->result;
+ goto done;
+ }
+ tokenp->type = isc_tokentype_string;
+ tokenp->value.as_textregion.base = lex->data;
+ tokenp->value.as_textregion.length =
+ (unsigned int)
+ (lex->max_token - remaining);
+ done = true;
+ continue;
+ }
+ if ((options & ISC_LEXOPT_ESCAPE) != 0)
+ escaped = (!escaped && c == '\\') ?
+ true : false;
+ if (remaining == 0U) {
+ result = grow_data(lex, &remaining,
+ &curr, &prev);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ }
+ INSIST(remaining > 0U);
+ *curr++ = c;
+ *curr = '\0';
+ remaining--;
+ break;
+ case lexstate_maybecomment:
+ if (c == '*' &&
+ (lex->comments & ISC_LEXCOMMENT_C) != 0) {
+ state = lexstate_ccomment;
+ continue;
+ } else if (c == '/' &&
+ (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
+ state = lexstate_eatline;
+ continue;
+ }
+ pushback(source, c);
+ c = '/';
+ no_comments = false;
+ state = saved_state;
+ goto no_read;
+ case lexstate_ccomment:
+ if (c == EOF) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto done;
+ }
+ if (c == '*')
+ state = lexstate_ccommentend;
+ break;
+ case lexstate_ccommentend:
+ if (c == EOF) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto done;
+ }
+ if (c == '/') {
+ /*
+ * C-style comments become a single space.
+ * We do this to ensure that a comment will
+ * act as a delimiter for strings and
+ * numbers.
+ */
+ c = ' ';
+ no_comments = false;
+ state = saved_state;
+ goto no_read;
+ } else if (c != '*')
+ state = lexstate_ccomment;
+ break;
+ case lexstate_eatline:
+ if ((c == '\n') || (c == EOF)) {
+ no_comments = false;
+ state = saved_state;
+ goto no_read;
+ }
+ break;
+ case lexstate_qstring:
+ if (c == EOF) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto done;
+ }
+ if (c == '"') {
+ if (escaped) {
+ escaped = false;
+ /*
+ * Overwrite the preceding backslash.
+ */
+ INSIST(prev != NULL);
+ *prev = '"';
+ } else {
+ tokenp->type = isc_tokentype_qstring;
+ tokenp->value.as_textregion.base =
+ lex->data;
+ tokenp->value.as_textregion.length =
+ (unsigned int)
+ (lex->max_token - remaining);
+ no_comments = false;
+ done = true;
+ }
+ } else {
+ if (c == '\n' && !escaped &&
+ (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
+ pushback(source, c);
+ result = ISC_R_UNBALANCEDQUOTES;
+ goto done;
+ }
+ if (c == '\\' && !escaped)
+ escaped = true;
+ else
+ escaped = false;
+ if (remaining == 0U) {
+ result = grow_data(lex, &remaining,
+ &curr, &prev);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ }
+ INSIST(remaining > 0U);
+ prev = curr;
+ *curr++ = c;
+ *curr = '\0';
+ remaining--;
+ }
+ break;
+ case lexstate_btext:
+ if (c == EOF) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto done;
+ }
+ if (c == '{') {
+ if (escaped) {
+ escaped = false;
+ } else {
+ lex->brace_count++;
+ }
+ } else if (c == '}') {
+ if (escaped) {
+ escaped = false;
+ } else {
+ INSIST(lex->brace_count > 0);
+ lex->brace_count--;
+ }
+
+ if (lex->brace_count == 0) {
+ tokenp->type = isc_tokentype_btext;
+ tokenp->value.as_textregion.base =
+ lex->data;
+ tokenp->value.as_textregion.length =
+ (unsigned int) (lex->max_token -
+ remaining);
+ no_comments = false;
+ done = true;
+ break;
+ }
+ }
+
+ if (c == '\\' && !escaped)
+ escaped = true;
+ else
+ escaped = false;
+
+ if (remaining == 0U) {
+ result = grow_data(lex, &remaining,
+ &curr, &prev);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ }
+ INSIST(remaining > 0U);
+ prev = curr;
+ *curr++ = c;
+ *curr = '\0';
+ remaining--;
+ break;
+ default:
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX,
+ ISC_MSG_UNEXPECTEDSTATE,
+ "Unexpected state %d"),
+ state);
+ /* Does not return. */
+ }
+
+ } while (!done);
+
+ result = ISC_R_SUCCESS;
+ done:
+#ifdef HAVE_FLOCKFILE
+ if (source->is_file)
+ funlockfile(source->input);
+#endif
+ return (result);
+}
+
+isc_result_t
+isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
+ isc_tokentype_t expect, bool eol)
+{
+ unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
+ ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
+ isc_result_t result;
+
+ if (expect == isc_tokentype_qstring)
+ options |= ISC_LEXOPT_QSTRING;
+ else if (expect == isc_tokentype_number)
+ options |= ISC_LEXOPT_NUMBER;
+ result = isc_lex_gettoken(lex, options, token);
+ if (result == ISC_R_RANGE)
+ isc_lex_ungettoken(lex, token);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (eol && ((token->type == isc_tokentype_eol) ||
+ (token->type == isc_tokentype_eof)))
+ return (ISC_R_SUCCESS);
+ if (token->type == isc_tokentype_string &&
+ expect == isc_tokentype_qstring)
+ return (ISC_R_SUCCESS);
+ if (token->type != expect) {
+ isc_lex_ungettoken(lex, token);
+ if (token->type == isc_tokentype_eol ||
+ token->type == isc_tokentype_eof)
+ return (ISC_R_UNEXPECTEDEND);
+ if (expect == isc_tokentype_number)
+ return (ISC_R_BADNUMBER);
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, bool eol)
+{
+ unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
+ ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE|
+ ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL;
+ isc_result_t result;
+
+ result = isc_lex_gettoken(lex, options, token);
+ if (result == ISC_R_RANGE)
+ isc_lex_ungettoken(lex, token);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (eol && ((token->type == isc_tokentype_eol) ||
+ (token->type == isc_tokentype_eof)))
+ return (ISC_R_SUCCESS);
+ if (token->type != isc_tokentype_number) {
+ isc_lex_ungettoken(lex, token);
+ if (token->type == isc_tokentype_eol ||
+ token->type == isc_tokentype_eof)
+ return (ISC_R_UNEXPECTEDEND);
+ return (ISC_R_BADNUMBER);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
+ inputsource *source;
+ /*
+ * Unget the current token.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+ REQUIRE(source != NULL);
+ REQUIRE(tokenp != NULL);
+ REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
+ tokenp->type == isc_tokentype_eof);
+
+ UNUSED(tokenp);
+
+ isc_buffer_first(source->pushback);
+ lex->paren_count = lex->saved_paren_count;
+ source->line = source->saved_line;
+ source->at_eof = false;
+}
+
+void
+isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
+{
+ inputsource *source;
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+ REQUIRE(source != NULL);
+ REQUIRE(tokenp != NULL);
+ REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
+ tokenp->type == isc_tokentype_eof);
+
+ UNUSED(tokenp);
+
+ INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
+ r->base = (unsigned char *)isc_buffer_base(source->pushback) +
+ source->ignored;
+ r->length = isc_buffer_consumedlength(source->pushback) -
+ source->ignored;
+}
+
+char *
+isc_lex_getsourcename(isc_lex_t *lex) {
+ inputsource *source;
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+
+ if (source == NULL)
+ return (NULL);
+
+ return (source->name);
+}
+
+unsigned long
+isc_lex_getsourceline(isc_lex_t *lex) {
+ inputsource *source;
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+
+ if (source == NULL)
+ return (0);
+
+ return (source->line);
+}
+
+isc_result_t
+isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
+ inputsource *source;
+ char *newname;
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+
+ if (source == NULL)
+ return (ISC_R_NOTFOUND);
+ newname = isc_mem_strdup(lex->mctx, name);
+ if (newname == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_mem_free(lex->mctx, source->name);
+ source->name = newname;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_setsourceline(isc_lex_t *lex, unsigned long line) {
+ inputsource *source;
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+
+ if (source == NULL)
+ return (ISC_R_NOTFOUND);
+
+ source->line = line;
+ return (ISC_R_SUCCESS);
+}
+
+bool
+isc_lex_isfile(isc_lex_t *lex) {
+ inputsource *source;
+
+ REQUIRE(VALID_LEX(lex));
+
+ source = HEAD(lex->sources);
+
+ if (source == NULL)
+ return (false);
+
+ return (source->is_file);
+}
diff --git a/lib/isc/lfsr.c b/lib/isc/lfsr.c
new file mode 100644
index 0000000..3b0b47f
--- /dev/null
+++ b/lib/isc/lfsr.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <isc/assertions.h>
+#include <isc/lfsr.h>
+#include <isc/util.h>
+
+#define VALID_LFSR(x) (x != NULL)
+
+void
+isc_lfsr_init(isc_lfsr_t *lfsr, uint32_t state, unsigned int bits,
+ uint32_t tap, unsigned int count,
+ isc_lfsrreseed_t reseed, void *arg)
+{
+ REQUIRE(VALID_LFSR(lfsr));
+ REQUIRE(8 <= bits && bits <= 32);
+ REQUIRE(tap != 0);
+
+ lfsr->state = state;
+ lfsr->bits = bits;
+ lfsr->tap = tap;
+ lfsr->count = count;
+ lfsr->reseed = reseed;
+ lfsr->arg = arg;
+
+ if (count == 0 && reseed != NULL)
+ reseed(lfsr, arg);
+ if (lfsr->state == 0)
+ lfsr->state = 0xffffffffU >> (32 - lfsr->bits);
+}
+
+/*!
+ * Return the next state of the lfsr.
+ */
+static inline uint32_t
+lfsr_generate(isc_lfsr_t *lfsr)
+{
+
+ /*
+ * If the previous state is zero, we must fill it with something
+ * here, or we will begin to generate an extremely predictable output.
+ *
+ * First, give the reseed function a crack at it. If the state is
+ * still 0, set it to all ones.
+ */
+ if (lfsr->state == 0) {
+ if (lfsr->reseed != NULL)
+ lfsr->reseed(lfsr, lfsr->arg);
+ if (lfsr->state == 0)
+ lfsr->state = 0xffffffffU >> (32 - lfsr->bits);
+ }
+
+ if (lfsr->state & 0x01) {
+ lfsr->state = (lfsr->state >> 1) ^ lfsr->tap;
+ return (1);
+ } else {
+ lfsr->state >>= 1;
+ return (0);
+ }
+}
+
+void
+isc_lfsr_generate(isc_lfsr_t *lfsr, void *data, unsigned int count)
+{
+ unsigned char *p;
+ unsigned int bit;
+ unsigned int byte;
+
+ REQUIRE(VALID_LFSR(lfsr));
+ REQUIRE(data != NULL);
+ REQUIRE(count > 0);
+
+ p = data;
+ byte = count;
+
+ while (byte--) {
+ *p = 0;
+ for (bit = 0; bit < 7; bit++) {
+ *p |= lfsr_generate(lfsr);
+ *p <<= 1;
+ }
+ *p |= lfsr_generate(lfsr);
+ p++;
+ }
+
+ if (lfsr->count != 0 && lfsr->reseed != NULL) {
+ if (lfsr->count <= count * 8)
+ lfsr->reseed(lfsr, lfsr->arg);
+ else
+ lfsr->count -= (count * 8);
+ }
+}
+
+static inline uint32_t
+lfsr_skipgenerate(isc_lfsr_t *lfsr, unsigned int skip)
+{
+ while (skip--)
+ (void)lfsr_generate(lfsr);
+
+ (void)lfsr_generate(lfsr);
+
+ return (lfsr->state);
+}
+
+/*
+ * Skip "skip" states in "lfsr".
+ */
+void
+isc_lfsr_skip(isc_lfsr_t *lfsr, unsigned int skip)
+{
+ REQUIRE(VALID_LFSR(lfsr));
+
+ while (skip--)
+ (void)lfsr_generate(lfsr);
+}
+
+/*
+ * Skip states in lfsr1 and lfsr2 using the other's current state.
+ * Return the final state of lfsr1 ^ lfsr2.
+ */
+uint32_t
+isc_lfsr_generate32(isc_lfsr_t *lfsr1, isc_lfsr_t *lfsr2)
+{
+ uint32_t state1, state2;
+ uint32_t skip1, skip2;
+
+ REQUIRE(VALID_LFSR(lfsr1));
+ REQUIRE(VALID_LFSR(lfsr2));
+
+ skip1 = lfsr1->state & 0x01;
+ skip2 = lfsr2->state & 0x01;
+
+ /* cross-skip. */
+ state1 = lfsr_skipgenerate(lfsr1, skip2);
+ state2 = lfsr_skipgenerate(lfsr2, skip1);
+
+ return (state1 ^ state2);
+}
diff --git a/lib/isc/lib.c b/lib/isc/lib.c
new file mode 100644
index 0000000..018cc3e
--- /dev/null
+++ b/lib/isc/lib.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isc/app.h>
+#include <isc/lib.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/socket.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+/***
+ *** Globals
+ ***/
+
+LIBISC_EXTERNAL_DATA isc_msgcat_t * isc_msgcat = NULL;
+
+
+/***
+ *** Private
+ ***/
+
+static isc_once_t msgcat_once = ISC_ONCE_INIT;
+
+/***
+ *** Functions
+ ***/
+
+static void
+open_msgcat(void) {
+ isc_msgcat_open("libisc.cat", &isc_msgcat);
+}
+
+void
+isc_lib_initmsgcat(void) {
+ isc_result_t result;
+
+ /*!
+ * Initialize the ISC library's message catalog, isc_msgcat, if it
+ * has not already been initialized.
+ */
+
+ result = isc_once_do(&msgcat_once, open_msgcat);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * Normally we'd use RUNTIME_CHECK() or FATAL_ERROR(), but
+ * we can't do that here, since they might call us!
+ * (Note that the catalog might be open anyway, so we might
+ * as well try to provide an internationalized message.)
+ */
+ fprintf(stderr, "%s:%d: %s: isc_once_do() %s.\n",
+ __FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FATALERROR, "fatal error"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ abort();
+ }
+}
+
+static isc_once_t register_once = ISC_ONCE_INIT;
+
+static void
+do_register(void) {
+ isc_bind9 = false;
+
+ RUNTIME_CHECK(isc__mem_register() == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc__app_register() == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc__task_register() == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc__socket_register() == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc__timer_register() == ISC_R_SUCCESS);
+}
+
+void
+isc_lib_register(void) {
+ RUNTIME_CHECK(isc_once_do(&register_once, do_register)
+ == ISC_R_SUCCESS);
+}
diff --git a/lib/isc/log.c b/lib/isc/log.c
new file mode 100644
index 0000000..3387533
--- /dev/null
+++ b/lib/isc/log.c
@@ -0,0 +1,1761 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <time.h>
+
+#include <sys/types.h> /* dev_t FreeBSD 2.1 */
+
+#include <isc/dir.h>
+#include <isc/file.h>
+#include <isc/log.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/print.h>
+#include <isc/stat.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#define LCTX_MAGIC ISC_MAGIC('L', 'c', 't', 'x')
+#define VALID_CONTEXT(lctx) ISC_MAGIC_VALID(lctx, LCTX_MAGIC)
+
+#define LCFG_MAGIC ISC_MAGIC('L', 'c', 'f', 'g')
+#define VALID_CONFIG(lcfg) ISC_MAGIC_VALID(lcfg, LCFG_MAGIC)
+
+/*
+ * XXXDCL make dynamic?
+ */
+#define LOG_BUFFER_SIZE (8 * 1024)
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024 /* AIX and others don't define this. */
+#endif
+
+/*!
+ * This is the structure that holds each named channel. A simple linked
+ * list chains all of the channels together, so an individual channel is
+ * found by doing strcmp()s with the names down the list. Their should
+ * be no performance penalty from this as it is expected that the number
+ * of named channels will be no more than a dozen or so, and name lookups
+ * from the head of the list are only done when isc_log_usechannel() is
+ * called, which should also be very infrequent.
+ */
+typedef struct isc_logchannel isc_logchannel_t;
+
+struct isc_logchannel {
+ char * name;
+ unsigned int type;
+ int level;
+ unsigned int flags;
+ isc_logdestination_t destination;
+ ISC_LINK(isc_logchannel_t) link;
+};
+
+/*!
+ * The logchannellist structure associates categories and modules with
+ * channels. First the appropriate channellist is found based on the
+ * category, and then each structure in the linked list is checked for
+ * a matching module. It is expected that the number of channels
+ * associated with any given category will be very short, no more than
+ * three or four in the more unusual cases.
+ */
+typedef struct isc_logchannellist isc_logchannellist_t;
+
+struct isc_logchannellist {
+ const isc_logmodule_t * module;
+ isc_logchannel_t * channel;
+ ISC_LINK(isc_logchannellist_t) link;
+};
+
+/*!
+ * This structure is used to remember messages for pruning via
+ * isc_log_[v]write1().
+ */
+typedef struct isc_logmessage isc_logmessage_t;
+
+struct isc_logmessage {
+ char * text;
+ isc_time_t time;
+ ISC_LINK(isc_logmessage_t) link;
+};
+
+/*!
+ * The isc_logconfig structure is used to store the configurable information
+ * about where messages are actually supposed to be sent -- the information
+ * that could changed based on some configuration file, as opposed to the
+ * the category/module specification of isc_log_[v]write[1] that is compiled
+ * into a program, or the debug_level which is dynamic state information.
+ */
+struct isc_logconfig {
+ unsigned int magic;
+ isc_log_t * lctx;
+ ISC_LIST(isc_logchannel_t) channels;
+ ISC_LIST(isc_logchannellist_t) *channellists;
+ unsigned int channellist_count;
+ unsigned int duplicate_interval;
+ int highest_level;
+ char * tag;
+ bool dynamic;
+};
+
+/*!
+ * This isc_log structure provides the context for the isc_log functions.
+ * The log context locks itself in isc_log_doit, the internal backend to
+ * isc_log_write. The locking is necessary both to provide exclusive access
+ * to the buffer into which the message is formatted and to guard against
+ * competing threads trying to write to the same syslog resource. (On
+ * some systems, such as BSD/OS, stdio is thread safe but syslog is not.)
+ * Unfortunately, the lock cannot guard against a _different_ logging
+ * context in the same program competing for syslog's attention. Thus
+ * There Can Be Only One, but this is not enforced.
+ * XXXDCL enforce it?
+ *
+ * Note that the category and module information is not locked.
+ * This is because in the usual case, only one isc_log_t is ever created
+ * in a program, and the category/module registration happens only once.
+ * XXXDCL it might be wise to add more locking overall.
+ */
+struct isc_log {
+ /* Not locked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ isc_logcategory_t * categories;
+ unsigned int category_count;
+ isc_logmodule_t * modules;
+ unsigned int module_count;
+ int debug_level;
+ isc_mutex_t lock;
+ /* Locked by isc_log lock. */
+ isc_logconfig_t * logconfig;
+ char buffer[LOG_BUFFER_SIZE];
+ ISC_LIST(isc_logmessage_t) messages;
+};
+
+/*!
+ * Used when ISC_LOG_PRINTLEVEL is enabled for a channel.
+ */
+static const char *log_level_strings[] = {
+ "debug",
+ "info",
+ "notice",
+ "warning",
+ "error",
+ "critical"
+};
+
+/*!
+ * Used to convert ISC_LOG_* priorities into syslog priorities.
+ * XXXDCL This will need modification for NT.
+ */
+static const int syslog_map[] = {
+ LOG_DEBUG,
+ LOG_INFO,
+ LOG_NOTICE,
+ LOG_WARNING,
+ LOG_ERR,
+ LOG_CRIT
+};
+
+/*!
+ * When adding new categories, a corresponding ISC_LOGCATEGORY_foo
+ * definition needs to be added to <isc/log.h>.
+ *
+ * The default category is provided so that the internal default can
+ * be overridden. Since the default is always looked up as the first
+ * channellist in the log context, it must come first in isc_categories[].
+ */
+LIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = {
+ { "default", 0 }, /* "default" must come first. */
+ { "general", 0 },
+ { NULL, 0 }
+};
+
+/*!
+ * See above comment for categories on LIBISC_EXTERNAL_DATA, and apply it to modules.
+ */
+LIBISC_EXTERNAL_DATA isc_logmodule_t isc_modules[] = {
+ { "socket", 0 },
+ { "time", 0 },
+ { "interface", 0 },
+ { "timer", 0 },
+ { "file", 0 },
+ { "other", 0 },
+ { NULL, 0 }
+};
+
+/*!
+ * This essentially constant structure must be filled in at run time,
+ * because its channel member is pointed to a channel that is created
+ * dynamically with isc_log_createchannel.
+ */
+static isc_logchannellist_t default_channel;
+
+/*!
+ * libisc logs to this context.
+ */
+LIBISC_EXTERNAL_DATA isc_log_t *isc_lctx = NULL;
+
+/*!
+ * Forward declarations.
+ */
+static isc_result_t
+assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
+ const isc_logmodule_t *module, isc_logchannel_t *channel);
+
+static isc_result_t
+sync_channellist(isc_logconfig_t *lcfg);
+
+static isc_result_t
+greatest_version(isc_logfile_t *file, int versions, int *greatest);
+
+static void
+isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, bool write_once,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, va_list args)
+ ISC_FORMAT_PRINTF(9, 0);
+
+/*@{*/
+/*!
+ * Convenience macros.
+ */
+
+#define FACILITY(channel) (channel->destination.facility)
+#define FILE_NAME(channel) (channel->destination.file.name)
+#define FILE_STREAM(channel) (channel->destination.file.stream)
+#define FILE_VERSIONS(channel) (channel->destination.file.versions)
+#define FILE_MAXSIZE(channel) (channel->destination.file.maximum_size)
+#define FILE_MAXREACHED(channel) (channel->destination.file.maximum_reached)
+
+/*@}*/
+/****
+ **** Public interfaces.
+ ****/
+
+/*
+ * Establish a new logging context, with default channels.
+ */
+isc_result_t
+isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
+ isc_log_t *lctx;
+ isc_logconfig_t *lcfg = NULL;
+ isc_result_t result;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(lctxp != NULL && *lctxp == NULL);
+ REQUIRE(lcfgp == NULL || *lcfgp == NULL);
+
+ lctx = isc_mem_get(mctx, sizeof(*lctx));
+ if (lctx != NULL) {
+ lctx->mctx = NULL;
+ isc_mem_attach(mctx, &lctx->mctx);
+ lctx->categories = NULL;
+ lctx->category_count = 0;
+ lctx->modules = NULL;
+ lctx->module_count = 0;
+ lctx->debug_level = 0;
+
+ ISC_LIST_INIT(lctx->messages);
+
+ result = isc_mutex_init(&lctx->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_putanddetach(&mctx, lctx, sizeof(*lctx));
+ return (result);
+ }
+
+ /*
+ * Normally setting the magic number is the last step done
+ * in a creation function, but a valid log context is needed
+ * by isc_log_registercategories and isc_logconfig_create.
+ * If either fails, the lctx is destroyed and not returned
+ * to the caller.
+ */
+ lctx->magic = LCTX_MAGIC;
+
+ isc_log_registercategories(lctx, isc_categories);
+ isc_log_registermodules(lctx, isc_modules);
+ result = isc_logconfig_create(lctx, &lcfg);
+
+ } else
+ result = ISC_R_NOMEMORY;
+
+ if (result == ISC_R_SUCCESS)
+ result = sync_channellist(lcfg);
+
+ if (result == ISC_R_SUCCESS) {
+ lctx->logconfig = lcfg;
+
+ *lctxp = lctx;
+ if (lcfgp != NULL)
+ *lcfgp = lcfg;
+
+ } else {
+ if (lcfg != NULL)
+ isc_logconfig_destroy(&lcfg);
+ if (lctx != NULL)
+ isc_log_destroy(&lctx);
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) {
+ isc_logconfig_t *lcfg;
+ isc_logdestination_t destination;
+ isc_result_t result = ISC_R_SUCCESS;
+ int level = ISC_LOG_INFO;
+
+ REQUIRE(lcfgp != NULL && *lcfgp == NULL);
+ REQUIRE(VALID_CONTEXT(lctx));
+
+ lcfg = isc_mem_get(lctx->mctx, sizeof(*lcfg));
+
+ if (lcfg != NULL) {
+ lcfg->lctx = lctx;
+ lcfg->channellists = NULL;
+ lcfg->channellist_count = 0;
+ lcfg->duplicate_interval = 0;
+ lcfg->highest_level = level;
+ lcfg->tag = NULL;
+ lcfg->dynamic = false;
+
+ ISC_LIST_INIT(lcfg->channels);
+
+ /*
+ * Normally the magic number is the last thing set in the
+ * structure, but isc_log_createchannel() needs a valid
+ * config. If the channel creation fails, the lcfg is not
+ * returned to the caller.
+ */
+ lcfg->magic = LCFG_MAGIC;
+
+ } else
+ result = ISC_R_NOMEMORY;
+
+ /*
+ * Create the default channels:
+ * default_syslog, default_stderr, default_debug and null.
+ */
+ if (result == ISC_R_SUCCESS) {
+ destination.facility = LOG_DAEMON;
+ result = isc_log_createchannel(lcfg, "default_syslog",
+ ISC_LOG_TOSYSLOG, level,
+ &destination, 0);
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ destination.file.stream = stderr;
+ destination.file.name = NULL;
+ destination.file.versions = ISC_LOG_ROLLNEVER;
+ destination.file.maximum_size = 0;
+ result = isc_log_createchannel(lcfg, "default_stderr",
+ ISC_LOG_TOFILEDESC,
+ level,
+ &destination,
+ ISC_LOG_PRINTTIME);
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * Set the default category's channel to default_stderr,
+ * which is at the head of the channels list because it was
+ * just created.
+ */
+ default_channel.channel = ISC_LIST_HEAD(lcfg->channels);
+
+ destination.file.stream = stderr;
+ destination.file.name = NULL;
+ destination.file.versions = ISC_LOG_ROLLNEVER;
+ destination.file.maximum_size = 0;
+ result = isc_log_createchannel(lcfg, "default_debug",
+ ISC_LOG_TOFILEDESC,
+ ISC_LOG_DYNAMIC,
+ &destination,
+ ISC_LOG_PRINTTIME);
+ }
+
+ if (result == ISC_R_SUCCESS)
+ result = isc_log_createchannel(lcfg, "null",
+ ISC_LOG_TONULL,
+ ISC_LOG_DYNAMIC,
+ NULL, 0);
+
+ if (result == ISC_R_SUCCESS)
+ *lcfgp = lcfg;
+
+ else
+ if (lcfg != NULL)
+ isc_logconfig_destroy(&lcfg);
+
+ return (result);
+}
+
+isc_logconfig_t *
+isc_logconfig_get(isc_log_t *lctx) {
+ REQUIRE(VALID_CONTEXT(lctx));
+
+ ENSURE(lctx->logconfig != NULL);
+
+ return (lctx->logconfig);
+}
+
+isc_result_t
+isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) {
+ isc_logconfig_t *old_cfg;
+ isc_result_t result;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+ REQUIRE(VALID_CONFIG(lcfg));
+ REQUIRE(lcfg->lctx == lctx);
+
+ /*
+ * Ensure that lcfg->channellist_count == lctx->category_count.
+ * They won't be equal if isc_log_usechannel has not been called
+ * since any call to isc_log_registercategories.
+ */
+ result = sync_channellist(lcfg);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ LOCK(&lctx->lock);
+
+ old_cfg = lctx->logconfig;
+ lctx->logconfig = lcfg;
+
+ UNLOCK(&lctx->lock);
+
+ isc_logconfig_destroy(&old_cfg);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_log_destroy(isc_log_t **lctxp) {
+ isc_log_t *lctx;
+ isc_logconfig_t *lcfg;
+ isc_mem_t *mctx;
+ isc_logmessage_t *message;
+
+ REQUIRE(lctxp != NULL && VALID_CONTEXT(*lctxp));
+
+ lctx = *lctxp;
+ mctx = lctx->mctx;
+
+ if (lctx->logconfig != NULL) {
+ lcfg = lctx->logconfig;
+ lctx->logconfig = NULL;
+ isc_logconfig_destroy(&lcfg);
+ }
+
+ DESTROYLOCK(&lctx->lock);
+
+ while ((message = ISC_LIST_HEAD(lctx->messages)) != NULL) {
+ ISC_LIST_UNLINK(lctx->messages, message, link);
+
+ isc_mem_put(mctx, message,
+ sizeof(*message) + strlen(message->text) + 1);
+ }
+
+ lctx->buffer[0] = '\0';
+ lctx->debug_level = 0;
+ lctx->categories = NULL;
+ lctx->category_count = 0;
+ lctx->modules = NULL;
+ lctx->module_count = 0;
+ lctx->mctx = NULL;
+ lctx->magic = 0;
+
+ isc_mem_putanddetach(&mctx, lctx, sizeof(*lctx));
+
+ *lctxp = NULL;
+}
+
+void
+isc_logconfig_destroy(isc_logconfig_t **lcfgp) {
+ isc_logconfig_t *lcfg;
+ isc_mem_t *mctx;
+ isc_logchannel_t *channel;
+ isc_logchannellist_t *item;
+ char *filename;
+ unsigned int i;
+
+ REQUIRE(lcfgp != NULL && VALID_CONFIG(*lcfgp));
+
+ lcfg = *lcfgp;
+
+ /*
+ * This function cannot be called with a logconfig that is in
+ * use by a log context.
+ */
+ REQUIRE(lcfg->lctx != NULL && lcfg->lctx->logconfig != lcfg);
+
+ mctx = lcfg->lctx->mctx;
+
+ while ((channel = ISC_LIST_HEAD(lcfg->channels)) != NULL) {
+ ISC_LIST_UNLINK(lcfg->channels, channel, link);
+
+ if (channel->type == ISC_LOG_TOFILE) {
+ /*
+ * The filename for the channel may have ultimately
+ * started its life in user-land as a const string,
+ * but in isc_log_createchannel it gets copied
+ * into writable memory and is not longer truly const.
+ */
+ DE_CONST(FILE_NAME(channel), filename);
+ isc_mem_free(mctx, filename);
+
+ if (FILE_STREAM(channel) != NULL)
+ (void)fclose(FILE_STREAM(channel));
+ }
+
+ isc_mem_free(mctx, channel->name);
+ isc_mem_put(mctx, channel, sizeof(*channel));
+ }
+
+ for (i = 0; i < lcfg->channellist_count; i++)
+ while ((item = ISC_LIST_HEAD(lcfg->channellists[i])) != NULL) {
+ ISC_LIST_UNLINK(lcfg->channellists[i], item, link);
+ isc_mem_put(mctx, item, sizeof(*item));
+ }
+
+ if (lcfg->channellist_count > 0)
+ isc_mem_put(mctx, lcfg->channellists,
+ lcfg->channellist_count *
+ sizeof(ISC_LIST(isc_logchannellist_t)));
+
+ lcfg->dynamic = false;
+ if (lcfg->tag != NULL)
+ isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
+ lcfg->tag = NULL;
+ lcfg->highest_level = 0;
+ lcfg->duplicate_interval = 0;
+ lcfg->magic = 0;
+
+ isc_mem_put(mctx, lcfg, sizeof(*lcfg));
+
+ *lcfgp = NULL;
+}
+
+void
+isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]) {
+ isc_logcategory_t *catp;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+ REQUIRE(categories != NULL && categories[0].name != NULL);
+
+ /*
+ * XXXDCL This somewhat sleazy situation of using the last pointer
+ * in one category array to point to the next array exists because
+ * this registration function returns void and I didn't want to have
+ * change everything that used it by making it return an isc_result_t.
+ * It would need to do that if it had to allocate memory to store
+ * pointers to each array passed in.
+ */
+ if (lctx->categories == NULL)
+ lctx->categories = categories;
+
+ else {
+ /*
+ * Adjust the last (NULL) pointer of the already registered
+ * categories to point to the incoming array.
+ */
+ for (catp = lctx->categories; catp->name != NULL; )
+ if (catp->id == UINT_MAX)
+ /*
+ * The name pointer points to the next array.
+ * Ick.
+ */
+ DE_CONST(catp->name, catp);
+ else
+ catp++;
+
+ catp->name = (void *)categories;
+ catp->id = UINT_MAX;
+ }
+
+ /*
+ * Update the id number of the category with its new global id.
+ */
+ for (catp = categories; catp->name != NULL; catp++)
+ catp->id = lctx->category_count++;
+}
+
+isc_logcategory_t *
+isc_log_categorybyname(isc_log_t *lctx, const char *name) {
+ isc_logcategory_t *catp;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+ REQUIRE(name != NULL);
+
+ for (catp = lctx->categories; catp->name != NULL; )
+ if (catp->id == UINT_MAX)
+ /*
+ * catp is neither modified nor returned to the
+ * caller, so removing its const qualifier is ok.
+ */
+ DE_CONST(catp->name, catp);
+ else {
+ if (strcmp(catp->name, name) == 0)
+ return (catp);
+ catp++;
+ }
+
+ return (NULL);
+}
+
+void
+isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]) {
+ isc_logmodule_t *modp;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+ REQUIRE(modules != NULL && modules[0].name != NULL);
+
+ /*
+ * XXXDCL This somewhat sleazy situation of using the last pointer
+ * in one category array to point to the next array exists because
+ * this registration function returns void and I didn't want to have
+ * change everything that used it by making it return an isc_result_t.
+ * It would need to do that if it had to allocate memory to store
+ * pointers to each array passed in.
+ */
+ if (lctx->modules == NULL)
+ lctx->modules = modules;
+
+ else {
+ /*
+ * Adjust the last (NULL) pointer of the already registered
+ * modules to point to the incoming array.
+ */
+ for (modp = lctx->modules; modp->name != NULL; )
+ if (modp->id == UINT_MAX)
+ /*
+ * The name pointer points to the next array.
+ * Ick.
+ */
+ DE_CONST(modp->name, modp);
+ else
+ modp++;
+
+ modp->name = (void *)modules;
+ modp->id = UINT_MAX;
+ }
+
+ /*
+ * Update the id number of the module with its new global id.
+ */
+ for (modp = modules; modp->name != NULL; modp++)
+ modp->id = lctx->module_count++;
+}
+
+isc_logmodule_t *
+isc_log_modulebyname(isc_log_t *lctx, const char *name) {
+ isc_logmodule_t *modp;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+ REQUIRE(name != NULL);
+
+ for (modp = lctx->modules; modp->name != NULL; )
+ if (modp->id == UINT_MAX)
+ /*
+ * modp is neither modified nor returned to the
+ * caller, so removing its const qualifier is ok.
+ */
+ DE_CONST(modp->name, modp);
+ else {
+ if (strcmp(modp->name, name) == 0)
+ return (modp);
+ modp++;
+ }
+
+ return (NULL);
+}
+
+isc_result_t
+isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
+ unsigned int type, int level,
+ const isc_logdestination_t *destination,
+ unsigned int flags)
+{
+ isc_logchannel_t *channel;
+ isc_mem_t *mctx;
+ unsigned int permitted = ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY |
+ ISC_LOG_BUFFERED;
+
+ REQUIRE(VALID_CONFIG(lcfg));
+ REQUIRE(name != NULL);
+ REQUIRE(type == ISC_LOG_TOSYSLOG || type == ISC_LOG_TOFILE ||
+ type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL);
+ REQUIRE(destination != NULL || type == ISC_LOG_TONULL);
+ REQUIRE(level >= ISC_LOG_CRITICAL);
+ REQUIRE((flags & ~permitted) == 0);
+
+ /* XXXDCL find duplicate names? */
+
+ mctx = lcfg->lctx->mctx;
+
+ channel = isc_mem_get(mctx, sizeof(*channel));
+ if (channel == NULL)
+ return (ISC_R_NOMEMORY);
+
+ channel->name = isc_mem_strdup(mctx, name);
+ if (channel->name == NULL) {
+ isc_mem_put(mctx, channel, sizeof(*channel));
+ return (ISC_R_NOMEMORY);
+ }
+
+ channel->type = type;
+ channel->level = level;
+ channel->flags = flags;
+ ISC_LINK_INIT(channel, link);
+
+ switch (type) {
+ case ISC_LOG_TOSYSLOG:
+ FACILITY(channel) = destination->facility;
+ break;
+
+ case ISC_LOG_TOFILE:
+ /*
+ * The file name is copied because greatest_version wants
+ * to scribble on it, so it needs to be definitely in
+ * writable memory.
+ */
+ FILE_NAME(channel) =
+ isc_mem_strdup(mctx, destination->file.name);
+ FILE_STREAM(channel) = NULL;
+ FILE_VERSIONS(channel) = destination->file.versions;
+ FILE_MAXSIZE(channel) = destination->file.maximum_size;
+ FILE_MAXREACHED(channel) = false;
+ break;
+
+ case ISC_LOG_TOFILEDESC:
+ FILE_NAME(channel) = NULL;
+ FILE_STREAM(channel) = destination->file.stream;
+ FILE_MAXSIZE(channel) = 0;
+ FILE_VERSIONS(channel) = ISC_LOG_ROLLNEVER;
+ break;
+
+ case ISC_LOG_TONULL:
+ /* Nothing. */
+ break;
+
+ default:
+ isc_mem_free(mctx, channel->name);
+ isc_mem_put(mctx, channel, sizeof(*channel));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ ISC_LIST_PREPEND(lcfg->channels, channel, link);
+
+ /*
+ * If default_stderr was redefined, make the default category
+ * point to the new default_stderr.
+ */
+ if (strcmp(name, "default_stderr") == 0)
+ default_channel.channel = channel;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
+ const isc_logcategory_t *category,
+ const isc_logmodule_t *module)
+{
+ isc_log_t *lctx;
+ isc_logchannel_t *channel;
+ isc_result_t result = ISC_R_SUCCESS;
+ unsigned int i;
+
+ REQUIRE(VALID_CONFIG(lcfg));
+ REQUIRE(name != NULL);
+
+ lctx = lcfg->lctx;
+
+ REQUIRE(category == NULL || category->id < lctx->category_count);
+ REQUIRE(module == NULL || module->id < lctx->module_count);
+
+ for (channel = ISC_LIST_HEAD(lcfg->channels); channel != NULL;
+ channel = ISC_LIST_NEXT(channel, link))
+ if (strcmp(name, channel->name) == 0)
+ break;
+
+ if (channel == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (category != NULL)
+ result = assignchannel(lcfg, category->id, module, channel);
+
+ else
+ /*
+ * Assign to all categories. Note that this includes
+ * the default channel.
+ */
+ for (i = 0; i < lctx->category_count; i++) {
+ result = assignchannel(lcfg, i, module, channel);
+ if (result != ISC_R_SUCCESS)
+ break;
+ }
+
+ return (result);
+}
+
+void
+isc_log_write(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format, ...)
+{
+ va_list args;
+
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+
+ va_start(args, format);
+ isc_log_doit(lctx, category, module, level, false,
+ NULL, 0, 0, format, args);
+ va_end(args);
+}
+
+void
+isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ const char *format, va_list args)
+{
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+ isc_log_doit(lctx, category, module, level, false,
+ NULL, 0, 0, format, args);
+}
+
+void
+isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format, ...)
+{
+ va_list args;
+
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+
+ va_start(args, format);
+ isc_log_doit(lctx, category, module, level, true,
+ NULL, 0, 0, format, args);
+ va_end(args);
+}
+
+void
+isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ const char *format, va_list args)
+{
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+ isc_log_doit(lctx, category, module, level, true,
+ NULL, 0, 0, format, args);
+}
+
+void
+isc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, ...)
+{
+ va_list args;
+
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+
+ va_start(args, format);
+ isc_log_doit(lctx, category, module, level, false,
+ msgcat, msgset, msg, format, args);
+ va_end(args);
+}
+
+void
+isc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, va_list args)
+{
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+ isc_log_doit(lctx, category, module, level, false,
+ msgcat, msgset, msg, format, args);
+}
+
+void
+isc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, ...)
+{
+ va_list args;
+
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+
+ va_start(args, format);
+ isc_log_doit(lctx, category, module, level, true,
+ msgcat, msgset, msg, format, args);
+ va_end(args);
+}
+
+void
+isc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, va_list args)
+{
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+ isc_log_doit(lctx, category, module, level, true,
+ msgcat, msgset, msg, format, args);
+}
+
+void
+isc_log_setcontext(isc_log_t *lctx) {
+ isc_lctx = lctx;
+}
+
+void
+isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) {
+ isc_logchannel_t *channel;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+
+ LOCK(&lctx->lock);
+
+ lctx->debug_level = level;
+ /*
+ * Close ISC_LOG_DEBUGONLY channels if level is zero.
+ */
+ if (lctx->debug_level == 0)
+ for (channel = ISC_LIST_HEAD(lctx->logconfig->channels);
+ channel != NULL;
+ channel = ISC_LIST_NEXT(channel, link))
+ if (channel->type == ISC_LOG_TOFILE &&
+ (channel->flags & ISC_LOG_DEBUGONLY) != 0 &&
+ FILE_STREAM(channel) != NULL) {
+ (void)fclose(FILE_STREAM(channel));
+ FILE_STREAM(channel) = NULL;
+ }
+ UNLOCK(&lctx->lock);
+}
+
+unsigned int
+isc_log_getdebuglevel(isc_log_t *lctx) {
+ REQUIRE(VALID_CONTEXT(lctx));
+
+ return (lctx->debug_level);
+}
+
+void
+isc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval) {
+ REQUIRE(VALID_CONFIG(lcfg));
+
+ lcfg->duplicate_interval = interval;
+}
+
+unsigned int
+isc_log_getduplicateinterval(isc_logconfig_t *lcfg) {
+ REQUIRE(VALID_CONTEXT(lcfg));
+
+ return (lcfg->duplicate_interval);
+}
+
+isc_result_t
+isc_log_settag(isc_logconfig_t *lcfg, const char *tag) {
+ REQUIRE(VALID_CONFIG(lcfg));
+
+ if (tag != NULL && *tag != '\0') {
+ if (lcfg->tag != NULL)
+ isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
+ lcfg->tag = isc_mem_strdup(lcfg->lctx->mctx, tag);
+ if (lcfg->tag == NULL)
+ return (ISC_R_NOMEMORY);
+
+ } else {
+ if (lcfg->tag != NULL)
+ isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
+ lcfg->tag = NULL;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+char *
+isc_log_gettag(isc_logconfig_t *lcfg) {
+ REQUIRE(VALID_CONFIG(lcfg));
+
+ return (lcfg->tag);
+}
+
+/* XXXDCL NT -- This interface will assuredly be changing. */
+void
+isc_log_opensyslog(const char *tag, int options, int facility) {
+ (void)openlog(tag, options, facility);
+}
+
+void
+isc_log_closefilelogs(isc_log_t *lctx) {
+ isc_logchannel_t *channel;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+
+ LOCK(&lctx->lock);
+ for (channel = ISC_LIST_HEAD(lctx->logconfig->channels);
+ channel != NULL;
+ channel = ISC_LIST_NEXT(channel, link))
+
+ if (channel->type == ISC_LOG_TOFILE &&
+ FILE_STREAM(channel) != NULL) {
+ (void)fclose(FILE_STREAM(channel));
+ FILE_STREAM(channel) = NULL;
+ }
+ UNLOCK(&lctx->lock);
+}
+
+/****
+ **** Internal functions
+ ****/
+
+static isc_result_t
+assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
+ const isc_logmodule_t *module, isc_logchannel_t *channel)
+{
+ isc_logchannellist_t *new_item;
+ isc_log_t *lctx;
+ isc_result_t result;
+
+ REQUIRE(VALID_CONFIG(lcfg));
+
+ lctx = lcfg->lctx;
+
+ REQUIRE(category_id < lctx->category_count);
+ REQUIRE(module == NULL || module->id < lctx->module_count);
+ REQUIRE(channel != NULL);
+
+ /*
+ * Ensure lcfg->channellist_count == lctx->category_count.
+ */
+ result = sync_channellist(lcfg);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ new_item = isc_mem_get(lctx->mctx, sizeof(*new_item));
+ if (new_item == NULL)
+ return (ISC_R_NOMEMORY);
+
+ new_item->channel = channel;
+ new_item->module = module;
+ ISC_LIST_INITANDPREPEND(lcfg->channellists[category_id],
+ new_item, link);
+
+ /*
+ * Remember the highest logging level set by any channel in the
+ * logging config, so isc_log_doit() can quickly return if the
+ * message is too high to be logged by any channel.
+ */
+ if (channel->type != ISC_LOG_TONULL) {
+ if (lcfg->highest_level < channel->level)
+ lcfg->highest_level = channel->level;
+ if (channel->level == ISC_LOG_DYNAMIC)
+ lcfg->dynamic = true;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This would ideally be part of isc_log_registercategories(), except then
+ * that function would have to return isc_result_t instead of void.
+ */
+static isc_result_t
+sync_channellist(isc_logconfig_t *lcfg) {
+ unsigned int bytes;
+ isc_log_t *lctx;
+ void *lists;
+
+ REQUIRE(VALID_CONFIG(lcfg));
+
+ lctx = lcfg->lctx;
+
+ REQUIRE(lctx->category_count != 0);
+
+ if (lctx->category_count == lcfg->channellist_count)
+ return (ISC_R_SUCCESS);
+
+ bytes = lctx->category_count * sizeof(ISC_LIST(isc_logchannellist_t));
+
+ lists = isc_mem_get(lctx->mctx, bytes);
+
+ if (lists == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(lists, 0, bytes);
+
+ if (lcfg->channellist_count != 0) {
+ bytes = lcfg->channellist_count *
+ sizeof(ISC_LIST(isc_logchannellist_t));
+ memmove(lists, lcfg->channellists, bytes);
+ isc_mem_put(lctx->mctx, lcfg->channellists, bytes);
+ }
+
+ lcfg->channellists = lists;
+ lcfg->channellist_count = lctx->category_count;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+greatest_version(isc_logfile_t *file, int versions, int *greatestp) {
+ char *bname, *digit_end;
+ const char *dirname;
+ int version, greatest = -1;
+ size_t bnamelen;
+ isc_dir_t dir;
+ isc_result_t result;
+ char sep = '/';
+#ifdef _WIN32
+ char *bname2;
+#endif
+
+ /*
+ * It is safe to DE_CONST the file.name because it was copied
+ * with isc_mem_strdup().
+ */
+ bname = strrchr(file->name, sep);
+#ifdef _WIN32
+ bname2 = strrchr(file->name, '\\');
+ if ((bname != NULL && bname2 != NULL && bname2 > bname) ||
+ (bname == NULL && bname2 != NULL)) {
+ bname = bname2;
+ sep = '\\';
+ }
+#endif
+ if (bname != NULL) {
+ *bname++ = '\0';
+ dirname = file->name;
+ } else {
+ DE_CONST(file->name, bname);
+ dirname = ".";
+ }
+ bnamelen = strlen(bname);
+
+ isc_dir_init(&dir);
+ result = isc_dir_open(&dir, dirname);
+
+ /*
+ * Replace the file separator if it was taken out.
+ */
+ if (bname != file->name)
+ *(bname - 1) = sep;
+
+ /*
+ * Return if the directory open failed.
+ */
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
+ if (dir.entry.length > bnamelen &&
+ strncmp(dir.entry.name, bname, bnamelen) == 0 &&
+ dir.entry.name[bnamelen] == '.')
+ {
+ version = strtol(&dir.entry.name[bnamelen + 1],
+ &digit_end, 10);
+ /*
+ * Remove any backup files that exceed versions.
+ */
+ if (*digit_end == '\0' && version >= versions) {
+ result = isc_file_remove(dir.entry.name);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_FILENOTFOUND)
+ syslog(LOG_ERR, "unable to remove "
+ "log file '%s': %s",
+ dir.entry.name,
+ isc_result_totext(result));
+ } else if (*digit_end == '\0' && version > greatest)
+ greatest = version;
+ }
+ }
+ isc_dir_close(&dir);
+
+ *greatestp = greatest;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_logfile_roll(isc_logfile_t *file) {
+ int i, n, greatest;
+ char current[PATH_MAX + 1];
+ char newpath[PATH_MAX + 1];
+ const char *path;
+ isc_result_t result;
+
+ REQUIRE(file != NULL);
+
+ /*
+ * Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER
+ * is specified. Apparently complete external control over the log
+ * files is desired.
+ */
+ if (file->versions == ISC_LOG_ROLLNEVER)
+ return (ISC_R_SUCCESS);
+
+ path = file->name;
+
+ if (file->versions == ISC_LOG_ROLLINFINITE) {
+ /*
+ * Find the first missing entry in the log file sequence.
+ */
+ for (greatest = 0; greatest < INT_MAX; greatest++) {
+ n = snprintf(current, sizeof(current),
+ "%s.%u", path, (unsigned)greatest) ;
+ if (n >= (int)sizeof(current) || n < 0 ||
+ !isc_file_exists(current))
+ break;
+ }
+ } else {
+ /*
+ * Get the largest existing version and remove any
+ * version greater than the permitted version.
+ */
+ result = greatest_version(file, file->versions, &greatest);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Increment if greatest is not the actual maximum value.
+ */
+ if (greatest < file->versions - 1)
+ greatest++;
+ }
+
+ for (i = greatest; i > 0; i--) {
+ result = ISC_R_SUCCESS;
+ n = snprintf(current, sizeof(current), "%s.%u", path,
+ (unsigned)(i - 1));
+ if (n >= (int)sizeof(current) || n < 0) {
+ result = ISC_R_NOSPACE;
+ }
+ if (result == ISC_R_SUCCESS) {
+ n = snprintf(newpath, sizeof(newpath), "%s.%u",
+ path, (unsigned)i);
+ if (n >= (int)sizeof(newpath) || n < 0) {
+ result = ISC_R_NOSPACE;
+ }
+ }
+ if (result == ISC_R_SUCCESS)
+ result = isc_file_rename(current, newpath);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_FILENOTFOUND)
+ syslog(LOG_ERR,
+ "unable to rename log file '%s.%u' to "
+ "'%s.%u': %s", path, i - 1, path, i,
+ isc_result_totext(result));
+ }
+
+ if (file->versions != 0) {
+ n = snprintf(newpath, sizeof(newpath), "%s.0", path);
+ if (n >= (int)sizeof(newpath) || n < 0)
+ result = ISC_R_NOSPACE;
+ else
+ result = isc_file_rename(path, newpath);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_FILENOTFOUND)
+ syslog(LOG_ERR,
+ "unable to rename log file '%s' to '%s.0': %s",
+ path, path, isc_result_totext(result));
+ } else {
+ result = isc_file_remove(path);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_FILENOTFOUND)
+ syslog(LOG_ERR, "unable to remove log file '%s': %s",
+ path, isc_result_totext(result));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+isc_log_open(isc_logchannel_t *channel) {
+ struct stat statbuf;
+ bool regular_file;
+ bool roll = false;
+ isc_result_t result = ISC_R_SUCCESS;
+ const char *path;
+
+ REQUIRE(channel->type == ISC_LOG_TOFILE);
+ REQUIRE(FILE_STREAM(channel) == NULL);
+
+ path = FILE_NAME(channel);
+
+ REQUIRE(path != NULL && *path != '\0');
+
+ /*
+ * Determine type of file; only regular files will be
+ * version renamed, and only if the base file exists
+ * and either has no size limit or has reached its size limit.
+ */
+ if (stat(path, &statbuf) == 0) {
+ regular_file = S_ISREG(statbuf.st_mode) ? true : false;
+ /* XXXDCL if not regular_file complain? */
+ if ((FILE_MAXSIZE(channel) == 0 &&
+ FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER) ||
+ (FILE_MAXSIZE(channel) > 0 &&
+ statbuf.st_size >= FILE_MAXSIZE(channel)))
+ roll = regular_file;
+ } else if (errno == ENOENT) {
+ regular_file = true;
+ POST(regular_file);
+ } else
+ result = ISC_R_INVALIDFILE;
+
+ /*
+ * Version control.
+ */
+ if (result == ISC_R_SUCCESS && roll) {
+ if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
+ return (ISC_R_MAXSIZE);
+ result = isc_logfile_roll(&channel->destination.file);
+ if (result != ISC_R_SUCCESS) {
+ if ((channel->flags & ISC_LOG_OPENERR) == 0) {
+ syslog(LOG_ERR,
+ "isc_log_open: isc_logfile_roll '%s' "
+ "failed: %s",
+ FILE_NAME(channel),
+ isc_result_totext(result));
+ channel->flags |= ISC_LOG_OPENERR;
+ }
+ return (result);
+ }
+ }
+
+ result = isc_stdio_open(path, "a", &FILE_STREAM(channel));
+
+ return (result);
+}
+
+bool
+isc_log_wouldlog(isc_log_t *lctx, int level) {
+ /*
+ * Try to avoid locking the mutex for messages which can't
+ * possibly be logged to any channels -- primarily debugging
+ * messages that the debug level is not high enough to print.
+ *
+ * If the level is (mathematically) less than or equal to the
+ * highest_level, or if there is a dynamic channel and the level is
+ * less than or equal to the debug level, the main loop must be
+ * entered to see if the message should really be output.
+ *
+ * NOTE: this is UNLOCKED access to the logconfig. However,
+ * the worst thing that can happen is that a bad decision is made
+ * about returning without logging, and that's not a big concern,
+ * because that's a risk anyway if the logconfig is being
+ * dynamically changed.
+ */
+
+ if (lctx == NULL || lctx->logconfig == NULL)
+ return (false);
+
+ return (level <= lctx->logconfig->highest_level ||
+ (lctx->logconfig->dynamic &&
+ level <= lctx->debug_level));
+}
+
+static void
+isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, bool write_once,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, va_list args)
+{
+ int syslog_level;
+ char time_string[64];
+ char level_string[24];
+ const char *iformat;
+ struct stat statbuf;
+ bool matched = false;
+ bool printtime, printtag, printcolon;
+ bool printcategory, printmodule, printlevel, buffered;
+ isc_logconfig_t *lcfg;
+ isc_logchannel_t *channel;
+ isc_logchannellist_t *category_channels;
+ isc_result_t result;
+
+ REQUIRE(lctx == NULL || VALID_CONTEXT(lctx));
+ REQUIRE(category != NULL);
+ REQUIRE(module != NULL);
+ REQUIRE(level != ISC_LOG_DYNAMIC);
+ REQUIRE(format != NULL);
+
+ /*
+ * Programs can use libraries that use this logging code without
+ * wanting to do any logging, thus the log context is allowed to
+ * be non-existent.
+ */
+ if (lctx == NULL)
+ return;
+
+ REQUIRE(category->id < lctx->category_count);
+ REQUIRE(module->id < lctx->module_count);
+
+ if (! isc_log_wouldlog(lctx, level))
+ return;
+
+ if (msgcat != NULL)
+ iformat = isc_msgcat_get(msgcat, msgset, msg, format);
+ else
+ iformat = format;
+
+ time_string[0] = '\0';
+ level_string[0] = '\0';
+
+ LOCK(&lctx->lock);
+
+ lctx->buffer[0] = '\0';
+
+ lcfg = lctx->logconfig;
+
+ category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]);
+
+ /*
+ * XXXDCL add duplicate filtering? (To not write multiple times to
+ * the same source via various channels).
+ */
+ do {
+ /*
+ * If the channel list end was reached and a match was made,
+ * everything is finished.
+ */
+ if (category_channels == NULL && matched)
+ break;
+
+ if (category_channels == NULL && ! matched &&
+ category_channels != ISC_LIST_HEAD(lcfg->channellists[0]))
+ /*
+ * No category/module pair was explicitly configured.
+ * Try the category named "default".
+ */
+ category_channels =
+ ISC_LIST_HEAD(lcfg->channellists[0]);
+
+ if (category_channels == NULL && ! matched)
+ /*
+ * No matching module was explicitly configured
+ * for the category named "default". Use the internal
+ * default channel.
+ */
+ category_channels = &default_channel;
+
+ if (category_channels->module != NULL &&
+ category_channels->module != module) {
+ category_channels = ISC_LIST_NEXT(category_channels,
+ link);
+ continue;
+ }
+
+ matched = true;
+
+ channel = category_channels->channel;
+ category_channels = ISC_LIST_NEXT(category_channels, link);
+
+ if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) &&
+ lctx->debug_level == 0)
+ continue;
+
+ if (channel->level == ISC_LOG_DYNAMIC) {
+ if (lctx->debug_level < level)
+ continue;
+ } else if (channel->level < level)
+ continue;
+
+ if ((channel->flags & ISC_LOG_PRINTTIME) != 0 &&
+ time_string[0] == '\0') {
+ isc_time_t isctime;
+
+ TIME_NOW(&isctime);
+ isc_time_formattimestamp(&isctime, time_string,
+ sizeof(time_string));
+ }
+
+ if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 &&
+ level_string[0] == '\0') {
+ if (level < ISC_LOG_CRITICAL)
+ snprintf(level_string, sizeof(level_string),
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_LOG,
+ ISC_MSG_LEVEL,
+ "level %d: "),
+ level);
+ else if (level > ISC_LOG_DYNAMIC)
+ snprintf(level_string, sizeof(level_string),
+ "%s %d: ", log_level_strings[0],
+ level);
+ else
+ snprintf(level_string, sizeof(level_string),
+ "%s: ", log_level_strings[-level]);
+ }
+
+ /*
+ * Only format the message once.
+ */
+ if (lctx->buffer[0] == '\0') {
+ (void)vsnprintf(lctx->buffer, sizeof(lctx->buffer),
+ iformat, args);
+
+ /*
+ * Check for duplicates.
+ */
+ if (write_once) {
+ isc_logmessage_t *message, *next;
+ isc_time_t oldest;
+ isc_interval_t interval;
+ size_t size;
+
+ isc_interval_set(&interval,
+ lcfg->duplicate_interval, 0);
+
+ /*
+ * 'oldest' is the age of the oldest messages
+ * which fall within the duplicate_interval
+ * range.
+ */
+ TIME_NOW(&oldest);
+ if (isc_time_subtract(&oldest, &interval,
+ &oldest)
+ != ISC_R_SUCCESS)
+ /*
+ * Can't effectively do the checking
+ * without having a valid time.
+ */
+ message = NULL;
+ else
+ message = ISC_LIST_HEAD(lctx->messages);
+
+ while (message != NULL) {
+ if (isc_time_compare(&message->time,
+ &oldest) < 0) {
+ /*
+ * This message is older
+ * than the duplicate_interval,
+ * so it should be dropped from
+ * the history.
+ *
+ * Setting the interval to be
+ * to be longer will obviously
+ * not cause the expired
+ * message to spring back into
+ * existence.
+ */
+ next = ISC_LIST_NEXT(message,
+ link);
+
+ ISC_LIST_UNLINK(lctx->messages,
+ message, link);
+
+ isc_mem_put(lctx->mctx,
+ message,
+ sizeof(*message) + 1 +
+ strlen(message->text));
+
+ message = next;
+ continue;
+ }
+
+ /*
+ * This message is in the duplicate
+ * filtering interval ...
+ */
+ if (strcmp(lctx->buffer, message->text)
+ == 0) {
+ /*
+ * ... and it is a duplicate.
+ * Unlock the mutex and
+ * get the hell out of Dodge.
+ */
+ UNLOCK(&lctx->lock);
+ return;
+ }
+
+ message = ISC_LIST_NEXT(message, link);
+ }
+
+ /*
+ * It wasn't in the duplicate interval,
+ * so add it to the message list.
+ */
+ size = sizeof(isc_logmessage_t) +
+ strlen(lctx->buffer) + 1;
+ message = isc_mem_get(lctx->mctx, size);
+ if (message != NULL) {
+ /*
+ * Put the text immediately after
+ * the struct. The strcpy is safe.
+ */
+ message->text = (char *)(message + 1);
+ size -= sizeof(isc_logmessage_t);
+ strlcpy(message->text, lctx->buffer,
+ size);
+
+ TIME_NOW(&message->time);
+
+ ISC_LINK_INIT(message, link);
+ ISC_LIST_APPEND(lctx->messages,
+ message, link);
+ }
+ }
+ }
+
+ printtime = (channel->flags & ISC_LOG_PRINTTIME);
+ printtag = ((channel->flags &
+ (ISC_LOG_PRINTTAG|ISC_LOG_PRINTPREFIX))
+ && lcfg->tag != NULL);
+ printcolon = ((channel->flags & ISC_LOG_PRINTTAG)
+ && lcfg->tag != NULL);
+ printcategory = (channel->flags & ISC_LOG_PRINTCATEGORY);
+ printmodule = (channel->flags & ISC_LOG_PRINTMODULE);
+ printlevel = (channel->flags & ISC_LOG_PRINTLEVEL);
+ buffered = (channel->flags & ISC_LOG_BUFFERED);
+
+ switch (channel->type) {
+ case ISC_LOG_TOFILE:
+ if (FILE_MAXREACHED(channel)) {
+ /*
+ * If the file can be rolled, OR
+ * If the file no longer exists, OR
+ * If the file is less than the maximum size,
+ * (such as if it had been renamed and
+ * a new one touched, or it was truncated
+ * in place)
+ * ... then close it to trigger reopening.
+ */
+ if (FILE_VERSIONS(channel) !=
+ ISC_LOG_ROLLNEVER ||
+ (stat(FILE_NAME(channel), &statbuf) != 0 &&
+ errno == ENOENT) ||
+ statbuf.st_size < FILE_MAXSIZE(channel)) {
+ (void)fclose(FILE_STREAM(channel));
+ FILE_STREAM(channel) = NULL;
+ FILE_MAXREACHED(channel) = false;
+ } else
+ /*
+ * Eh, skip it.
+ */
+ break;
+ }
+
+ if (FILE_STREAM(channel) == NULL) {
+ result = isc_log_open(channel);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_MAXSIZE &&
+ (channel->flags & ISC_LOG_OPENERR) == 0) {
+ syslog(LOG_ERR,
+ "isc_log_open '%s' failed: %s",
+ FILE_NAME(channel),
+ isc_result_totext(result));
+ channel->flags |= ISC_LOG_OPENERR;
+ }
+ if (result != ISC_R_SUCCESS)
+ break;
+ channel->flags &= ~ISC_LOG_OPENERR;
+ }
+ /* FALLTHROUGH */
+
+ case ISC_LOG_TOFILEDESC:
+ fprintf(FILE_STREAM(channel),
+ "%s%s%s%s%s%s%s%s%s%s\n",
+ printtime ? time_string : "",
+ printtime ? " " : "",
+ printtag ? lcfg->tag : "",
+ printcolon ? ": " : "",
+ printcategory ? category->name : "",
+ printcategory ? ": " : "",
+ printmodule ? (module != NULL ? module->name
+ : "no_module")
+ : "",
+ printmodule ? ": " : "",
+ printlevel ? level_string : "",
+ lctx->buffer);
+
+ if (!buffered)
+ fflush(FILE_STREAM(channel));
+
+ /*
+ * If the file now exceeds its maximum size
+ * threshold, note it so that it will not be logged
+ * to any more.
+ */
+ if (FILE_MAXSIZE(channel) > 0) {
+ INSIST(channel->type == ISC_LOG_TOFILE);
+
+ /* XXXDCL NT fstat/fileno */
+ /* XXXDCL complain if fstat fails? */
+ if (fstat(fileno(FILE_STREAM(channel)),
+ &statbuf) >= 0 &&
+ statbuf.st_size > FILE_MAXSIZE(channel))
+ FILE_MAXREACHED(channel) = true;
+ }
+
+ break;
+
+ case ISC_LOG_TOSYSLOG:
+ if (level > 0)
+ syslog_level = LOG_DEBUG;
+ else if (level < ISC_LOG_CRITICAL)
+ syslog_level = LOG_CRIT;
+ else
+ syslog_level = syslog_map[-level];
+
+ (void)syslog(FACILITY(channel) | syslog_level,
+ "%s%s%s%s%s%s%s%s%s%s",
+ printtime ? time_string : "",
+ printtime ? " " : "",
+ printtag ? lcfg->tag : "",
+ printcolon ? ": " : "",
+ printcategory ? category->name : "",
+ printcategory ? ": " : "",
+ printmodule ? (module != NULL
+ ? module->name
+ : "no_module")
+ : "",
+ printmodule ? ": " : "",
+ printlevel ? level_string : "",
+ lctx->buffer);
+ break;
+
+ case ISC_LOG_TONULL:
+ break;
+
+ }
+
+ } while (1);
+
+ UNLOCK(&lctx->lock);
+}
diff --git a/lib/isc/md5.c b/lib/isc/md5.c
new file mode 100644
index 0000000..25c71a2
--- /dev/null
+++ b/lib/isc/md5.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include "config.h"
+
+#include <pk11/site.h>
+
+#ifndef PK11_MD5_DISABLE
+
+#include <stdbool.h>
+
+#include <isc/assertions.h>
+#include <isc/md5.h>
+#include <isc/platform.h>
+#include <isc/safe.h>
+#include <isc/string.h>
+#include <isc/types.h>
+
+#if PKCS11CRYPTO
+#include <pk11/internal.h>
+#include <pk11/pk11.h>
+#endif
+
+#include <isc/util.h>
+
+#ifdef ISC_PLATFORM_OPENSSLHASH
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#define EVP_MD_CTX_new() &(ctx->_ctx)
+#define EVP_MD_CTX_free(ptr) EVP_MD_CTX_cleanup(ptr)
+#endif
+
+void
+isc_md5_init(isc_md5_t *ctx) {
+ ctx->ctx = EVP_MD_CTX_new();
+ RUNTIME_CHECK(ctx->ctx != NULL);
+ if (EVP_DigestInit(ctx->ctx, EVP_md5()) != 1) {
+ FATAL_ERROR(__FILE__, __LINE__, "Cannot initialize MD5.");
+ }
+}
+
+void
+isc_md5_invalidate(isc_md5_t *ctx) {
+ EVP_MD_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+}
+
+void
+isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) {
+ if (len == 0U)
+ return;
+ RUNTIME_CHECK(EVP_DigestUpdate(ctx->ctx,
+ (const void *) buf,
+ (size_t) len) == 1);
+}
+
+void
+isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
+ RUNTIME_CHECK(EVP_DigestFinal(ctx->ctx, digest, NULL) == 1);
+ EVP_MD_CTX_free(ctx->ctx);
+ ctx->ctx = NULL;
+}
+
+#elif PKCS11CRYPTO
+
+void
+isc_md5_init(isc_md5_t *ctx) {
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
+
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+}
+
+void
+isc_md5_invalidate(isc_md5_t *ctx) {
+ CK_BYTE garbage[ISC_MD5_DIGESTLENGTH];
+ CK_ULONG len = ISC_MD5_DIGESTLENGTH;
+
+ if (ctx->handle == NULL)
+ return;
+ (void) pkcs_C_DigestFinal(ctx->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ pk11_return_session(ctx);
+}
+
+void
+isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) {
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
+ CK_RV rv;
+ CK_ULONG len = ISC_MD5_DIGESTLENGTH;
+
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (ctx->session, (CK_BYTE_PTR) digest, &len));
+ pk11_return_session(ctx);
+}
+
+#else
+
+static void
+byteSwap(uint32_t *buf, unsigned words)
+{
+ unsigned char *p = (unsigned char *)buf;
+
+ do {
+ *buf++ = (uint32_t)((unsigned)p[3] << 8 | p[2]) << 16 |
+ ((unsigned)p[1] << 8 | p[0]);
+ p += 4;
+ } while (--words);
+}
+
+/*!
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+isc_md5_init(isc_md5_t *ctx) {
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bytes[0] = 0;
+ ctx->bytes[1] = 0;
+}
+
+void
+isc_md5_invalidate(isc_md5_t *ctx) {
+ isc_safe_memwipe(ctx, sizeof(*ctx));
+}
+
+/*@{*/
+/*! The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+/*@}*/
+
+/*! This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+ (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*!
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+transform(uint32_t buf[4], uint32_t const in[16]) {
+ register uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*!
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) {
+ uint32_t t;
+
+ /* Update byte count */
+
+ t = ctx->bytes[0];
+ if ((ctx->bytes[0] = t + len) < t)
+ ctx->bytes[1]++; /* Carry from low to high */
+
+ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
+ if (t > len) {
+ memmove((unsigned char *)ctx->in + 64 - t, buf, len);
+ return;
+ }
+ /* First chunk is an odd size */
+ memmove((unsigned char *)ctx->in + 64 - t, buf, t);
+ byteSwap(ctx->in, 16);
+ transform(ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+
+ /* Process data in 64-byte chunks */
+ while (len >= 64) {
+ memmove(ctx->in, buf, 64);
+ byteSwap(ctx->in, 16);
+ transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memmove(ctx->in, buf, len);
+}
+
+/*!
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
+ int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
+ unsigned char *p = (unsigned char *)ctx->in + count;
+
+ /* Set the first char of padding to 0x80. There is always room. */
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 56 bytes (-8..55) */
+ count = 56 - 1 - count;
+
+ if (count < 0) { /* Padding forces an extra block */
+ memset(p, 0, count + 8);
+ byteSwap(ctx->in, 16);
+ transform(ctx->buf, ctx->in);
+ p = (unsigned char *)ctx->in;
+ count = 56;
+ }
+ memset(p, 0, count);
+ byteSwap(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ctx->in[14] = ctx->bytes[0] << 3;
+ ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+ transform(ctx->buf, ctx->in);
+
+ byteSwap(ctx->buf, 4);
+ memmove(digest, ctx->buf, 16);
+ isc_safe_memwipe(ctx, sizeof(*ctx)); /* In case it's sensitive */
+}
+#endif
+
+/*
+ * Check for MD5 support; if it does not work, raise a fatal error.
+ *
+ * Use "a" as the test vector.
+ *
+ * Standard use is testing false and result true.
+ * Testing use is testing true and result false;
+ */
+bool
+isc_md5_check(bool testing) {
+ isc_md5_t ctx;
+ unsigned char input = 'a';
+ unsigned char digest[ISC_MD5_DIGESTLENGTH];
+ unsigned char expected[] = {
+ 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
+ 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61
+ };
+
+ INSIST(sizeof(expected) == ISC_MD5_DIGESTLENGTH);
+
+ /*
+ * Introduce a fault for testing.
+ */
+ if (testing) {
+ input ^= 0x01;
+ }
+
+ /*
+ * These functions do not return anything; any failure will be fatal.
+ */
+ isc_md5_init(&ctx);
+ isc_md5_update(&ctx, &input, 1U);
+ isc_md5_final(&ctx, digest);
+
+ /*
+ * Must return true in standard case, should return false for testing.
+ */
+ return (memcmp(digest, expected, ISC_MD5_DIGESTLENGTH) == 0);
+}
+
+#else /* !PK11_MD5_DISABLE */
+#ifdef WIN32
+/* Make the Visual Studio linker happy */
+#include <isc/util.h>
+
+void isc_md5_final() { INSIST(0); }
+void isc_md5_init() { INSIST(0); }
+void isc_md5_invalidate() { INSIST(0); }
+void isc_md5_update() { INSIST(0); }
+void isc_md5_check() { INSIST(0); }
+#endif
+#endif /* PK11_MD5_DISABLE */
diff --git a/lib/isc/mem.c b/lib/isc/mem.c
new file mode 100644
index 0000000..3fec795
--- /dev/null
+++ b/lib/isc/mem.c
@@ -0,0 +1,3015 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <limits.h>
+
+#include <isc/bind9.h>
+#include <isc/json.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/once.h>
+#include <isc/ondestroy.h>
+#include <isc/string.h>
+#include <isc/mutex.h>
+#include <isc/print.h>
+#include <isc/util.h>
+#include <isc/xml.h>
+
+#define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
+#define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
+
+#ifndef ISC_MEM_DEBUGGING
+#define ISC_MEM_DEBUGGING 0
+#endif
+LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
+LIBISC_EXTERNAL_DATA unsigned int isc_mem_defaultflags = ISC_MEMFLAG_DEFAULT;
+
+/*
+ * Constants.
+ */
+
+#define DEF_MAX_SIZE 1100
+#define DEF_MEM_TARGET 4096
+#define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */
+#define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */
+#define TABLE_INCREMENT 1024
+#define DEBUGLIST_COUNT 1024
+
+/*
+ * Types.
+ */
+typedef struct isc__mem isc__mem_t;
+typedef struct isc__mempool isc__mempool_t;
+
+#if ISC_MEM_TRACKLINES
+typedef struct debuglink debuglink_t;
+struct debuglink {
+ ISC_LINK(debuglink_t) link;
+ const void *ptr[DEBUGLIST_COUNT];
+ size_t size[DEBUGLIST_COUNT];
+ const char *file[DEBUGLIST_COUNT];
+ unsigned int line[DEBUGLIST_COUNT];
+ unsigned int count;
+};
+
+#define FLARG_PASS , file, line
+#define FLARG , const char *file, unsigned int line
+#else
+#define FLARG_PASS
+#define FLARG
+#endif
+
+typedef struct element element;
+struct element {
+ element * next;
+};
+
+typedef struct {
+ /*!
+ * This structure must be ALIGNMENT_SIZE bytes.
+ */
+ union {
+ size_t size;
+ isc__mem_t *ctx;
+ char bytes[ALIGNMENT_SIZE];
+ } u;
+} size_info;
+
+struct stats {
+ unsigned long gets;
+ unsigned long totalgets;
+ unsigned long blocks;
+ unsigned long freefrags;
+};
+
+#define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
+#define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
+
+#if ISC_MEM_TRACKLINES
+typedef ISC_LIST(debuglink_t) debuglist_t;
+#endif
+
+/* List of all active memory contexts. */
+
+static ISC_LIST(isc__mem_t) contexts;
+
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_mutex_t contextslock;
+static isc_mutex_t createlock;
+
+/*%
+ * Total size of lost memory due to a bug of external library.
+ * Locked by the global lock.
+ */
+static uint64_t totallost;
+
+struct isc__mem {
+ isc_mem_t common;
+ isc_ondestroy_t ondestroy;
+ unsigned int flags;
+ isc_mutex_t lock;
+ isc_memalloc_t memalloc;
+ isc_memfree_t memfree;
+ void * arg;
+ size_t max_size;
+ bool checkfree;
+ struct stats * stats;
+ unsigned int references;
+ char name[16];
+ void * tag;
+ size_t quota;
+ size_t total;
+ size_t inuse;
+ size_t maxinuse;
+ size_t hi_water;
+ size_t lo_water;
+ bool hi_called;
+ bool is_overmem;
+ isc_mem_water_t water;
+ void * water_arg;
+ ISC_LIST(isc__mempool_t) pools;
+ unsigned int poolcnt;
+
+ /* ISC_MEMFLAG_INTERNAL */
+ size_t mem_target;
+ element ** freelists;
+ element * basic_blocks;
+ unsigned char ** basic_table;
+ unsigned int basic_table_count;
+ unsigned int basic_table_size;
+ unsigned char * lowest;
+ unsigned char * highest;
+
+#if ISC_MEM_TRACKLINES
+ debuglist_t * debuglist;
+ unsigned int debuglistcnt;
+#endif
+
+ unsigned int memalloc_failures;
+ ISC_LINK(isc__mem_t) link;
+};
+
+#define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
+#define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
+
+struct isc__mempool {
+ /* always unlocked */
+ isc_mempool_t common; /*%< common header of mempool's */
+ isc_mutex_t *lock; /*%< optional lock */
+ isc__mem_t *mctx; /*%< our memory context */
+ /*%< locked via the memory context's lock */
+ ISC_LINK(isc__mempool_t) link; /*%< next pool in this mem context */
+ /*%< optionally locked from here down */
+ element *items; /*%< low water item list */
+ size_t size; /*%< size of each item on this pool */
+ unsigned int maxalloc; /*%< max number of items allowed */
+ unsigned int allocated; /*%< # of items currently given out */
+ unsigned int freecount; /*%< # of items on reserved list */
+ unsigned int freemax; /*%< # of items allowed on free list */
+ unsigned int fillcount; /*%< # of items to fetch on each fill */
+ /*%< Stats only. */
+ unsigned int gets; /*%< # of requests to this pool */
+ /*%< Debugging only. */
+#if ISC_MEMPOOL_NAMES
+ char name[16]; /*%< printed name in stats reports */
+#endif
+};
+
+/*
+ * Private Inline-able.
+ */
+
+#if ! ISC_MEM_TRACKLINES
+#define ADD_TRACE(a, b, c, d, e)
+#define DELETE_TRACE(a, b, c, d, e)
+#define ISC_MEMFUNC_SCOPE
+#else
+#define TRACE_OR_RECORD (ISC_MEM_DEBUGTRACE|ISC_MEM_DEBUGRECORD)
+#define ADD_TRACE(a, b, c, d, e) \
+ do { \
+ if ((isc_mem_debugging & TRACE_OR_RECORD) != 0 && \
+ b != NULL) \
+ add_trace_entry(a, b, c, d, e); \
+ } while (0)
+#define DELETE_TRACE(a, b, c, d, e) \
+ do { \
+ if ((isc_mem_debugging & TRACE_OR_RECORD) != 0 && \
+ b != NULL) \
+ delete_trace_entry(a, b, c, d, e); \
+ } while(0)
+
+static void
+print_active(isc__mem_t *ctx, FILE *out);
+
+#endif /* ISC_MEM_TRACKLINES */
+
+/*%
+ * The following are intended for internal use (indicated by "isc__"
+ * prefix) but are not declared as static, allowing direct access
+ * from unit tests, etc.
+ */
+
+isc_result_t
+isc__mem_create2(size_t init_max_size, size_t target_size,
+ isc_mem_t **ctxp, unsigned int flags);
+void
+isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp);
+void
+isc__mem_detach(isc_mem_t **ctxp);
+void
+isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
+void
+isc__mem_destroy(isc_mem_t **ctxp);
+isc_result_t
+isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event);
+void *
+isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
+void
+isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
+void
+isc__mem_stats(isc_mem_t *ctx, FILE *out);
+void *
+isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
+void *
+isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
+void
+isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
+char *
+isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
+void
+isc__mem_setdestroycheck(isc_mem_t *ctx, bool flag);
+void
+isc__mem_setquota(isc_mem_t *ctx, size_t quota);
+size_t
+isc__mem_getquota(isc_mem_t *ctx);
+size_t
+isc__mem_inuse(isc_mem_t *ctx);
+size_t
+isc__mem_maxinuse(isc_mem_t *ctx);
+size_t
+isc__mem_total(isc_mem_t *ctx);
+bool
+isc__mem_isovermem(isc_mem_t *ctx);
+void
+isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
+ size_t hiwater, size_t lowater);
+void
+isc__mem_waterack(isc_mem_t *ctx0, int flag);
+void
+isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag);
+const char *
+isc__mem_getname(isc_mem_t *ctx);
+void *
+isc__mem_gettag(isc_mem_t *ctx);
+isc_result_t
+isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
+void
+isc__mempool_setname(isc_mempool_t *mpctx, const char *name);
+void
+isc__mempool_destroy(isc_mempool_t **mpctxp);
+void
+isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
+void *
+isc___mempool_get(isc_mempool_t *mpctx FLARG);
+void
+isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG);
+void
+isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
+unsigned int
+isc__mempool_getfreemax(isc_mempool_t *mpctx);
+unsigned int
+isc__mempool_getfreecount(isc_mempool_t *mpctx);
+void
+isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
+unsigned int
+isc__mempool_getmaxalloc(isc_mempool_t *mpctx);
+unsigned int
+isc__mempool_getallocated(isc_mempool_t *mpctx);
+void
+isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
+unsigned int
+isc__mempool_getfillcount(isc_mempool_t *mpctx);
+void
+isc__mem_printactive(isc_mem_t *ctx0, FILE *file);
+void
+isc__mem_printallactive(FILE *file);
+unsigned int
+isc__mem_references(isc_mem_t *ctx0);
+
+static struct isc__memmethods {
+ isc_memmethods_t methods;
+
+ /*%
+ * The following are defined just for avoiding unused static functions.
+ */
+ void *createx, *create, *create2, *ondestroy, *stats,
+ *setquota, *getquota, *setname, *getname, *gettag;
+} memmethods = {
+ {
+ isc__mem_attach,
+ isc__mem_detach,
+ isc__mem_destroy,
+ isc___mem_get,
+ isc___mem_put,
+ isc___mem_putanddetach,
+ isc___mem_allocate,
+ isc___mem_reallocate,
+ isc___mem_strdup,
+ isc___mem_free,
+ isc__mem_setdestroycheck,
+ isc__mem_setwater,
+ isc__mem_waterack,
+ isc__mem_inuse,
+ isc__mem_maxinuse,
+ isc__mem_total,
+ isc__mem_isovermem,
+ isc__mempool_create
+ },
+ (void *)isc_mem_createx,
+ (void *)isc_mem_create,
+ (void *)isc_mem_create2,
+ (void *)isc_mem_ondestroy,
+ (void *)isc_mem_stats,
+ (void *)isc_mem_setquota,
+ (void *)isc_mem_getquota,
+ (void *)isc_mem_setname,
+ (void *)isc_mem_getname,
+ (void *)isc_mem_gettag
+};
+
+static struct isc__mempoolmethods {
+ isc_mempoolmethods_t methods;
+
+ /*%
+ * The following are defined just for avoiding unused static functions.
+ */
+ void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount;
+} mempoolmethods = {
+ {
+ isc__mempool_destroy,
+ isc___mempool_get,
+ isc___mempool_put,
+ isc__mempool_getallocated,
+ isc__mempool_setmaxalloc,
+ isc__mempool_setfreemax,
+ isc__mempool_setname,
+ isc__mempool_associatelock,
+ isc__mempool_setfillcount
+ },
+ (void *)isc_mempool_getfreemax,
+ (void *)isc_mempool_getfreecount,
+ (void *)isc_mempool_getmaxalloc,
+ (void *)isc_mempool_getfillcount
+};
+
+#if ISC_MEM_TRACKLINES
+/*!
+ * mctx must be locked.
+ */
+static inline void
+add_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size FLARG) {
+ debuglink_t *dl;
+ unsigned int i;
+ size_t mysize = size;
+
+ if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
+ fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_ADDTRACE,
+ "add %p size %u "
+ "file %s line %u mctx %p\n"),
+ ptr, size, file, line, mctx);
+
+ if (mctx->debuglist == NULL)
+ return;
+
+ if (mysize > mctx->max_size)
+ mysize = mctx->max_size;
+
+ dl = ISC_LIST_HEAD(mctx->debuglist[mysize]);
+ while (dl != NULL) {
+ if (dl->count == DEBUGLIST_COUNT)
+ goto next;
+ for (i = 0; i < DEBUGLIST_COUNT; i++) {
+ if (dl->ptr[i] == NULL) {
+ dl->ptr[i] = ptr;
+ dl->size[i] = size;
+ dl->file[i] = file;
+ dl->line[i] = line;
+ dl->count++;
+ return;
+ }
+ }
+ next:
+ dl = ISC_LIST_NEXT(dl, link);
+ }
+
+ dl = malloc(sizeof(debuglink_t));
+ INSIST(dl != NULL);
+
+ ISC_LINK_INIT(dl, link);
+ for (i = 1; i < DEBUGLIST_COUNT; i++) {
+ dl->ptr[i] = NULL;
+ dl->size[i] = 0;
+ dl->file[i] = NULL;
+ dl->line[i] = 0;
+ }
+
+ dl->ptr[0] = ptr;
+ dl->size[0] = size;
+ dl->file[0] = file;
+ dl->line[0] = line;
+ dl->count = 1;
+
+ ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link);
+ mctx->debuglistcnt++;
+}
+
+static inline void
+delete_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size,
+ const char *file, unsigned int line)
+{
+ debuglink_t *dl;
+ unsigned int i;
+
+ if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
+ fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_DELTRACE,
+ "del %p size %u "
+ "file %s line %u mctx %p\n"),
+ ptr, size, file, line, mctx);
+
+ if (mctx->debuglist == NULL)
+ return;
+
+ if (size > mctx->max_size)
+ size = mctx->max_size;
+
+ dl = ISC_LIST_HEAD(mctx->debuglist[size]);
+ while (dl != NULL) {
+ for (i = 0; i < DEBUGLIST_COUNT; i++) {
+ if (dl->ptr[i] == ptr) {
+ dl->ptr[i] = NULL;
+ dl->size[i] = 0;
+ dl->file[i] = NULL;
+ dl->line[i] = 0;
+
+ INSIST(dl->count > 0);
+ dl->count--;
+ if (dl->count == 0) {
+ ISC_LIST_UNLINK(mctx->debuglist[size],
+ dl, link);
+ free(dl);
+ }
+ return;
+ }
+ }
+ dl = ISC_LIST_NEXT(dl, link);
+ }
+
+ /*
+ * If we get here, we didn't find the item on the list. We're
+ * screwed.
+ */
+ INSIST(dl != NULL);
+}
+#endif /* ISC_MEM_TRACKLINES */
+
+static inline size_t
+rmsize(size_t size) {
+ /*
+ * round down to ALIGNMENT_SIZE
+ */
+ return (size & (~(ALIGNMENT_SIZE - 1)));
+}
+
+static inline size_t
+quantize(size_t size) {
+ /*!
+ * Round up the result in order to get a size big
+ * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
+ * byte boundaries.
+ */
+
+ if (size == 0U)
+ return (ALIGNMENT_SIZE);
+ return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
+}
+
+static inline bool
+more_basic_blocks(isc__mem_t *ctx) {
+ void *tmp;
+ unsigned char *curr, *next;
+ unsigned char *first, *last;
+ unsigned char **table;
+ unsigned int table_size;
+ size_t increment;
+ int i;
+
+ /* Require: we hold the context lock. */
+
+ /*
+ * Did we hit the quota for this context?
+ */
+ increment = NUM_BASIC_BLOCKS * ctx->mem_target;
+ if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
+ return (false);
+
+ INSIST(ctx->basic_table_count <= ctx->basic_table_size);
+ if (ctx->basic_table_count == ctx->basic_table_size) {
+ table_size = ctx->basic_table_size + TABLE_INCREMENT;
+ table = (ctx->memalloc)(ctx->arg,
+ table_size * sizeof(unsigned char *));
+ if (table == NULL) {
+ ctx->memalloc_failures++;
+ return (false);
+ }
+ if (ctx->basic_table_size != 0) {
+ memmove(table, ctx->basic_table,
+ ctx->basic_table_size *
+ sizeof(unsigned char *));
+ (ctx->memfree)(ctx->arg, ctx->basic_table);
+ }
+ ctx->basic_table = table;
+ ctx->basic_table_size = table_size;
+ }
+
+ tmp = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
+ if (tmp == NULL) {
+ ctx->memalloc_failures++;
+ return (false);
+ }
+ ctx->total += increment;
+ ctx->basic_table[ctx->basic_table_count] = tmp;
+ ctx->basic_table_count++;
+
+ curr = tmp;
+ next = curr + ctx->mem_target;
+ for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
+ ((element *)curr)->next = (element *)next;
+ curr = next;
+ next += ctx->mem_target;
+ }
+ /*
+ * curr is now pointing at the last block in the
+ * array.
+ */
+ ((element *)curr)->next = NULL;
+ first = tmp;
+ last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
+ if (first < ctx->lowest || ctx->lowest == NULL)
+ ctx->lowest = first;
+ if (last > ctx->highest)
+ ctx->highest = last;
+ ctx->basic_blocks = tmp;
+
+ return (true);
+}
+
+static inline bool
+more_frags(isc__mem_t *ctx, size_t new_size) {
+ int i, frags;
+ size_t total_size;
+ void *tmp;
+ unsigned char *curr, *next;
+
+ /*!
+ * Try to get more fragments by chopping up a basic block.
+ */
+
+ if (ctx->basic_blocks == NULL) {
+ if (!more_basic_blocks(ctx)) {
+ /*
+ * We can't get more memory from the OS, or we've
+ * hit the quota for this context.
+ */
+ /*
+ * XXXRTH "At quota" notification here.
+ */
+ return (false);
+ }
+ }
+
+ total_size = ctx->mem_target;
+ tmp = ctx->basic_blocks;
+ ctx->basic_blocks = ctx->basic_blocks->next;
+ frags = (int)(total_size / new_size);
+ ctx->stats[new_size].blocks++;
+ ctx->stats[new_size].freefrags += frags;
+ /*
+ * Set up a linked-list of blocks of size
+ * "new_size".
+ */
+ curr = tmp;
+ next = curr + new_size;
+ total_size -= new_size;
+ for (i = 0; i < (frags - 1); i++) {
+ ((element *)curr)->next = (element *)next;
+ curr = next;
+ next += new_size;
+ total_size -= new_size;
+ }
+ /*
+ * Add the remaining fragment of the basic block to a free list.
+ */
+ total_size = rmsize(total_size);
+ if (total_size > 0U) {
+ ((element *)next)->next = ctx->freelists[total_size];
+ ctx->freelists[total_size] = (element *)next;
+ ctx->stats[total_size].freefrags++;
+ }
+ /*
+ * curr is now pointing at the last block in the
+ * array.
+ */
+ ((element *)curr)->next = NULL;
+ ctx->freelists[new_size] = tmp;
+
+ return (true);
+}
+
+static inline void *
+mem_getunlocked(isc__mem_t *ctx, size_t size) {
+ size_t new_size = quantize(size);
+ void *ret;
+
+ if (new_size >= ctx->max_size) {
+ /*
+ * memget() was called on something beyond our upper limit.
+ */
+ if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
+ ret = NULL;
+ goto done;
+ }
+ ret = (ctx->memalloc)(ctx->arg, size);
+ if (ret == NULL) {
+ ctx->memalloc_failures++;
+ goto done;
+ }
+ ctx->total += size;
+ ctx->inuse += size;
+ ctx->stats[ctx->max_size].gets++;
+ ctx->stats[ctx->max_size].totalgets++;
+ /*
+ * If we don't set new_size to size, then the
+ * ISC_MEM_FILL code might write over bytes we
+ * don't own.
+ */
+ new_size = size;
+ goto done;
+ }
+ /*
+ * If there are no blocks in the free list for this size, get a chunk
+ * of memory and then break it up into "new_size"-sized blocks, adding
+ * them to the free list.
+ */
+ if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
+ return (NULL);
+
+ /*
+ * The free list uses the "rounded-up" size "new_size".
+ */
+
+ ret = ctx->freelists[new_size];
+ ctx->freelists[new_size] = ctx->freelists[new_size]->next;
+
+
+ /*
+ * The stats[] uses the _actual_ "size" requested by the
+ * caller, with the caveat (in the code above) that "size" >= the
+ * max. size (max_size) ends up getting recorded as a call to
+ * max_size.
+ */
+ ctx->stats[size].gets++;
+ ctx->stats[size].totalgets++;
+ ctx->stats[new_size].freefrags--;
+ ctx->inuse += new_size;
+
+ done:
+
+#if ISC_MEM_FILL
+ if (ret != NULL)
+ memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
+#endif
+
+ return (ret);
+}
+
+#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
+static inline void
+check_overrun(void *mem, size_t size, size_t new_size) {
+ unsigned char *cp;
+
+ cp = (unsigned char *)mem;
+ cp += size;
+ while (size < new_size) {
+ INSIST(*cp == 0xbe);
+ cp++;
+ size++;
+ }
+}
+#endif
+
+/* coverity[+free : arg-1] */
+static inline void
+mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) {
+ size_t new_size = quantize(size);
+
+ if (new_size >= ctx->max_size) {
+ /*
+ * memput() called on something beyond our upper limit.
+ */
+#if ISC_MEM_FILL
+ memset(mem, 0xde, size); /* Mnemonic for "dead". */
+#endif
+ (ctx->memfree)(ctx->arg, mem);
+ INSIST(ctx->stats[ctx->max_size].gets != 0U);
+ ctx->stats[ctx->max_size].gets--;
+ INSIST(size <= ctx->inuse);
+ ctx->inuse -= size;
+ return;
+ }
+
+#if ISC_MEM_FILL
+#if ISC_MEM_CHECKOVERRUN
+ check_overrun(mem, size, new_size);
+#endif
+ memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
+#endif
+
+ /*
+ * The free list uses the "rounded-up" size "new_size".
+ */
+ ((element *)mem)->next = ctx->freelists[new_size];
+ ctx->freelists[new_size] = (element *)mem;
+
+ /*
+ * The stats[] uses the _actual_ "size" requested by the
+ * caller, with the caveat (in the code above) that "size" >= the
+ * max. size (max_size) ends up getting recorded as a call to
+ * max_size.
+ */
+ INSIST(ctx->stats[size].gets != 0U);
+ ctx->stats[size].gets--;
+ ctx->stats[new_size].freefrags++;
+ ctx->inuse -= new_size;
+}
+
+/*!
+ * Perform a malloc, doing memory filling and overrun detection as necessary.
+ */
+static inline void *
+mem_get(isc__mem_t *ctx, size_t size) {
+ char *ret;
+
+#if ISC_MEM_CHECKOVERRUN
+ size += 1;
+#endif
+
+ ret = (ctx->memalloc)(ctx->arg, size);
+ if (ret == NULL)
+ ctx->memalloc_failures++;
+
+#if ISC_MEM_FILL
+ if (ret != NULL)
+ memset(ret, 0xbe, size); /* Mnemonic for "beef". */
+#else
+# if ISC_MEM_CHECKOVERRUN
+ if (ret != NULL)
+ ret[size-1] = 0xbe;
+# endif
+#endif
+
+ return (ret);
+}
+
+/*!
+ * Perform a free, doing memory filling and overrun detection as necessary.
+ */
+/* coverity[+free : arg-1] */
+static inline void
+mem_put(isc__mem_t *ctx, void *mem, size_t size) {
+#if ISC_MEM_CHECKOVERRUN
+ INSIST(((unsigned char *)mem)[size] == 0xbe);
+#endif
+#if ISC_MEM_FILL
+ memset(mem, 0xde, size); /* Mnemonic for "dead". */
+#else
+ UNUSED(size);
+#endif
+ (ctx->memfree)(ctx->arg, mem);
+}
+
+/*!
+ * Update internal counters after a memory get.
+ */
+static inline void
+mem_getstats(isc__mem_t *ctx, size_t size) {
+ ctx->total += size;
+ ctx->inuse += size;
+
+ if (size > ctx->max_size) {
+ ctx->stats[ctx->max_size].gets++;
+ ctx->stats[ctx->max_size].totalgets++;
+ } else {
+ ctx->stats[size].gets++;
+ ctx->stats[size].totalgets++;
+ }
+}
+
+/*!
+ * Update internal counters after a memory put.
+ */
+static inline void
+mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) {
+ UNUSED(ptr);
+
+ INSIST(ctx->inuse >= size);
+ ctx->inuse -= size;
+
+ if (size > ctx->max_size) {
+ INSIST(ctx->stats[ctx->max_size].gets > 0U);
+ ctx->stats[ctx->max_size].gets--;
+ } else {
+ INSIST(ctx->stats[size].gets > 0U);
+ ctx->stats[size].gets--;
+ }
+}
+
+/*
+ * Private.
+ */
+
+static void *
+default_memalloc(void *arg, size_t size) {
+ UNUSED(arg);
+ if (size == 0U)
+ size = 1;
+ return (malloc(size));
+}
+
+static void
+default_memfree(void *arg, void *ptr) {
+ UNUSED(arg);
+ free(ptr);
+}
+
+static void
+initialize_action(void) {
+ RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_mutex_init(&contextslock) == ISC_R_SUCCESS);
+ ISC_LIST_INIT(contexts);
+ totallost = 0;
+}
+
+/*
+ * Public.
+ */
+
+isc_result_t
+isc_mem_createx(size_t init_max_size, size_t target_size,
+ isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
+ isc_mem_t **ctxp)
+{
+ return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
+ arg, ctxp, isc_mem_defaultflags));
+
+}
+
+isc_result_t
+isc_mem_createx2(size_t init_max_size, size_t target_size,
+ isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
+ isc_mem_t **ctxp, unsigned int flags)
+{
+ isc__mem_t *ctx;
+ isc_result_t result;
+
+ REQUIRE(ctxp != NULL && *ctxp == NULL);
+ REQUIRE(memalloc != NULL);
+ REQUIRE(memfree != NULL);
+
+ INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+ ctx = (memalloc)(arg, sizeof(*ctx));
+ if (ctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
+ result = isc_mutex_init(&ctx->lock);
+ if (result != ISC_R_SUCCESS) {
+ (memfree)(arg, ctx);
+ return (result);
+ }
+ }
+
+ if (init_max_size == 0U)
+ ctx->max_size = DEF_MAX_SIZE;
+ else
+ ctx->max_size = init_max_size;
+ ctx->flags = flags;
+ ctx->references = 1;
+ memset(ctx->name, 0, sizeof(ctx->name));
+ ctx->tag = NULL;
+ ctx->quota = 0;
+ ctx->total = 0;
+ ctx->inuse = 0;
+ ctx->maxinuse = 0;
+ ctx->hi_water = 0;
+ ctx->lo_water = 0;
+ ctx->hi_called = false;
+ ctx->is_overmem = false;
+ ctx->water = NULL;
+ ctx->water_arg = NULL;
+ ctx->common.impmagic = MEM_MAGIC;
+ ctx->common.magic = ISCAPI_MCTX_MAGIC;
+ ctx->common.methods = (isc_memmethods_t *)&memmethods;
+ isc_ondestroy_init(&ctx->ondestroy);
+ ctx->memalloc = memalloc;
+ ctx->memfree = memfree;
+ ctx->arg = arg;
+ ctx->stats = NULL;
+ ctx->checkfree = true;
+#if ISC_MEM_TRACKLINES
+ ctx->debuglist = NULL;
+ ctx->debuglistcnt = 0;
+#endif
+ ISC_LIST_INIT(ctx->pools);
+ ctx->poolcnt = 0;
+ ctx->freelists = NULL;
+ ctx->basic_blocks = NULL;
+ ctx->basic_table = NULL;
+ ctx->basic_table_count = 0;
+ ctx->basic_table_size = 0;
+ ctx->lowest = NULL;
+ ctx->highest = NULL;
+
+ ctx->stats = (memalloc)(arg,
+ (ctx->max_size+1) * sizeof(struct stats));
+ if (ctx->stats == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto error;
+ }
+ memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
+
+ if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ if (target_size == 0U)
+ ctx->mem_target = DEF_MEM_TARGET;
+ else
+ ctx->mem_target = target_size;
+ ctx->freelists = (memalloc)(arg, ctx->max_size *
+ sizeof(element *));
+ if (ctx->freelists == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto error;
+ }
+ memset(ctx->freelists, 0,
+ ctx->max_size * sizeof(element *));
+ }
+
+#if ISC_MEM_TRACKLINES
+ if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
+ unsigned int i;
+
+ ctx->debuglist = (memalloc)(arg,
+ (ctx->max_size+1) * sizeof(debuglist_t));
+ if (ctx->debuglist == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto error;
+ }
+ for (i = 0; i <= ctx->max_size; i++)
+ ISC_LIST_INIT(ctx->debuglist[i]);
+ }
+#endif
+
+ ctx->memalloc_failures = 0;
+
+ LOCK(&contextslock);
+ ISC_LIST_INITANDAPPEND(contexts, ctx, link);
+ UNLOCK(&contextslock);
+
+ *ctxp = (isc_mem_t *)ctx;
+ return (ISC_R_SUCCESS);
+
+ error:
+ if (ctx != NULL) {
+ if (ctx->stats != NULL)
+ (memfree)(arg, ctx->stats);
+ if (ctx->freelists != NULL)
+ (memfree)(arg, ctx->freelists);
+#if ISC_MEM_TRACKLINES
+ if (ctx->debuglist != NULL)
+ (ctx->memfree)(ctx->arg, ctx->debuglist);
+#endif /* ISC_MEM_TRACKLINES */
+ if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
+ DESTROYLOCK(&ctx->lock);
+ (memfree)(arg, ctx);
+ }
+
+ return (result);
+}
+
+static void
+destroy(isc__mem_t *ctx) {
+ unsigned int i;
+ isc_ondestroy_t ondest;
+
+ LOCK(&contextslock);
+ ISC_LIST_UNLINK(contexts, ctx, link);
+ totallost += ctx->inuse;
+ UNLOCK(&contextslock);
+
+ ctx->common.impmagic = 0;
+ ctx->common.magic = 0;
+
+ INSIST(ISC_LIST_EMPTY(ctx->pools));
+
+#if ISC_MEM_TRACKLINES
+ if (ctx->debuglist != NULL) {
+ if (ctx->checkfree) {
+ for (i = 0; i <= ctx->max_size; i++) {
+ if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
+ print_active(ctx, stderr);
+ INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
+ }
+ } else {
+ debuglink_t *dl;
+
+ for (i = 0; i <= ctx->max_size; i++)
+ for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
+ dl != NULL;
+ dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
+ ISC_LIST_UNLINK(ctx->debuglist[i],
+ dl, link);
+ free(dl);
+ }
+ }
+ (ctx->memfree)(ctx->arg, ctx->debuglist);
+ }
+#endif
+ INSIST(ctx->references == 0);
+
+ if (ctx->checkfree) {
+ for (i = 0; i <= ctx->max_size; i++) {
+ if (ctx->stats[i].gets != 0U) {
+ fprintf(stderr,
+ "Failing assertion due to probable "
+ "leaked memory in context %p (\"%s\") "
+ "(stats[%u].gets == %lu).\n",
+ ctx, ctx->name, i, ctx->stats[i].gets);
+#if ISC_MEM_TRACKLINES
+ print_active(ctx, stderr);
+#endif
+ INSIST(ctx->stats[i].gets == 0U);
+ }
+ }
+ }
+
+ (ctx->memfree)(ctx->arg, ctx->stats);
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ for (i = 0; i < ctx->basic_table_count; i++)
+ (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
+ (ctx->memfree)(ctx->arg, ctx->freelists);
+ if (ctx->basic_table != NULL)
+ (ctx->memfree)(ctx->arg, ctx->basic_table);
+ }
+
+ ondest = ctx->ondestroy;
+
+ if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
+ DESTROYLOCK(&ctx->lock);
+ (ctx->memfree)(ctx->arg, ctx);
+
+ isc_ondestroy_notify(&ondest, ctx);
+}
+
+void
+isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) {
+ isc__mem_t *source = (isc__mem_t *)source0;
+
+ REQUIRE(VALID_CONTEXT(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ MCTXLOCK(source, &source->lock);
+ source->references++;
+ MCTXUNLOCK(source, &source->lock);
+
+ *targetp = (isc_mem_t *)source;
+}
+
+void
+isc__mem_detach(isc_mem_t **ctxp) {
+ isc__mem_t *ctx;
+ bool want_destroy = false;
+
+ REQUIRE(ctxp != NULL);
+ ctx = (isc__mem_t *)*ctxp;
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ MCTXLOCK(ctx, &ctx->lock);
+ INSIST(ctx->references > 0);
+ ctx->references--;
+ if (ctx->references == 0)
+ want_destroy = true;
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (want_destroy)
+ destroy(ctx);
+
+ *ctxp = NULL;
+}
+
+/*
+ * isc_mem_putanddetach() is the equivalent of:
+ *
+ * mctx = NULL;
+ * isc_mem_attach(ptr->mctx, &mctx);
+ * isc_mem_detach(&ptr->mctx);
+ * isc_mem_put(mctx, ptr, sizeof(*ptr);
+ * isc_mem_detach(&mctx);
+ */
+
+void
+isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
+ isc__mem_t *ctx;
+ bool want_destroy = false;
+ size_info *si;
+ size_t oldsize;
+
+ REQUIRE(ctxp != NULL);
+ ctx = (isc__mem_t *)*ctxp;
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(ptr != NULL);
+
+ /*
+ * Must be before mem_putunlocked() as ctxp is usually within
+ * [ptr..ptr+size).
+ */
+ *ctxp = NULL;
+
+ if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
+ if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
+ si = &(((size_info *)ptr)[-1]);
+ oldsize = si->u.size - ALIGNMENT_SIZE;
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
+ oldsize -= ALIGNMENT_SIZE;
+ INSIST(oldsize == size);
+ }
+ isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
+
+ MCTXLOCK(ctx, &ctx->lock);
+ ctx->references--;
+ if (ctx->references == 0)
+ want_destroy = true;
+ MCTXUNLOCK(ctx, &ctx->lock);
+ if (want_destroy)
+ destroy(ctx);
+
+ return;
+ }
+
+ MCTXLOCK(ctx, &ctx->lock);
+
+ DELETE_TRACE(ctx, ptr, size, file, line);
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ mem_putunlocked(ctx, ptr, size);
+ } else {
+ mem_putstats(ctx, ptr, size);
+ mem_put(ctx, ptr, size);
+ }
+
+ INSIST(ctx->references > 0);
+ ctx->references--;
+ if (ctx->references == 0)
+ want_destroy = true;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (want_destroy)
+ destroy(ctx);
+}
+
+void
+isc__mem_destroy(isc_mem_t **ctxp) {
+ isc__mem_t *ctx;
+
+ /*
+ * This routine provides legacy support for callers who use mctxs
+ * without attaching/detaching.
+ */
+
+ REQUIRE(ctxp != NULL);
+ ctx = (isc__mem_t *)*ctxp;
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ MCTXLOCK(ctx, &ctx->lock);
+#if ISC_MEM_TRACKLINES
+ if (ctx->references != 1)
+ print_active(ctx, stderr);
+#endif
+ REQUIRE(ctx->references == 1);
+ ctx->references--;
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ destroy(ctx);
+
+ *ctxp = NULL;
+}
+
+isc_result_t
+isc_mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ isc_result_t res;
+
+ MCTXLOCK(ctx, &ctx->lock);
+ res = isc_ondestroy_register(&ctx->ondestroy, task, event);
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ return (res);
+}
+
+void *
+isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ void *ptr;
+ bool call_water = false;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
+ return (isc__mem_allocate(ctx0, size FLARG_PASS));
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ MCTXLOCK(ctx, &ctx->lock);
+ ptr = mem_getunlocked(ctx, size);
+ } else {
+ ptr = mem_get(ctx, size);
+ MCTXLOCK(ctx, &ctx->lock);
+ if (ptr != NULL)
+ mem_getstats(ctx, size);
+ }
+
+ ADD_TRACE(ctx, ptr, size, file, line);
+ if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water) {
+ ctx->is_overmem = true;
+ if (!ctx->hi_called)
+ call_water = true;
+ }
+ if (ctx->inuse > ctx->maxinuse) {
+ ctx->maxinuse = ctx->inuse;
+ if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
+ (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
+ fprintf(stderr, "maxinuse = %lu\n",
+ (unsigned long)ctx->inuse);
+ }
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (call_water && (ctx->water != NULL))
+ (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
+
+ return (ptr);
+}
+
+void
+isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ bool call_water = false;
+ size_info *si;
+ size_t oldsize;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(ptr != NULL);
+
+ if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
+ if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
+ si = &(((size_info *)ptr)[-1]);
+ oldsize = si->u.size - ALIGNMENT_SIZE;
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
+ oldsize -= ALIGNMENT_SIZE;
+ INSIST(oldsize == size);
+ }
+ isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
+ return;
+ }
+
+ MCTXLOCK(ctx, &ctx->lock);
+
+ DELETE_TRACE(ctx, ptr, size, file, line);
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ mem_putunlocked(ctx, ptr, size);
+ } else {
+ mem_putstats(ctx, ptr, size);
+ mem_put(ctx, ptr, size);
+ }
+
+ /*
+ * The check against ctx->lo_water == 0 is for the condition
+ * when the context was pushed over hi_water but then had
+ * isc_mem_setwater() called with 0 for hi_water and lo_water.
+ */
+ if ((ctx->inuse < ctx->lo_water) || (ctx->lo_water == 0U)) {
+ ctx->is_overmem = false;
+ if (ctx->hi_called)
+ call_water = true;
+ }
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (call_water && (ctx->water != NULL))
+ (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
+}
+
+void
+isc__mem_waterack(isc_mem_t *ctx0, int flag) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ MCTXLOCK(ctx, &ctx->lock);
+ if (flag == ISC_MEM_LOWATER)
+ ctx->hi_called = false;
+ else if (flag == ISC_MEM_HIWATER)
+ ctx->hi_called = true;
+ MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+#if ISC_MEM_TRACKLINES
+static void
+print_active(isc__mem_t *mctx, FILE *out) {
+ if (mctx->debuglist != NULL) {
+ debuglink_t *dl;
+ unsigned int i, j;
+ const char *format;
+ bool found;
+
+ fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_DUMPALLOC,
+ "Dump of all outstanding "
+ "memory allocations:\n"));
+ found = false;
+ format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_PTRFILELINE,
+ "\tptr %p size %u file %s line %u\n");
+ for (i = 0; i <= mctx->max_size; i++) {
+ dl = ISC_LIST_HEAD(mctx->debuglist[i]);
+
+ if (dl != NULL)
+ found = true;
+
+ while (dl != NULL) {
+ for (j = 0; j < DEBUGLIST_COUNT; j++)
+ if (dl->ptr[j] != NULL)
+ fprintf(out, format,
+ dl->ptr[j],
+ dl->size[j],
+ dl->file[j],
+ dl->line[j]);
+ dl = ISC_LIST_NEXT(dl, link);
+ }
+ }
+ if (!found)
+ fputs(isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_NONE, "\tNone.\n"), out);
+ }
+}
+#endif
+
+/*
+ * Print the stats[] on the stream "out" with suitable formatting.
+ */
+void
+isc_mem_stats(isc_mem_t *ctx0, FILE *out) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ size_t i;
+ const struct stats *s;
+ const isc__mempool_t *pool;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ for (i = 0; i <= ctx->max_size; i++) {
+ s = &ctx->stats[i];
+
+ if (s->totalgets == 0U && s->gets == 0U)
+ continue;
+ fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
+ (i == ctx->max_size) ? ">=" : " ",
+ (unsigned long) i, s->totalgets, s->gets);
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
+ (s->blocks != 0U || s->freefrags != 0U))
+ fprintf(out, " (%lu bl, %lu ff)",
+ s->blocks, s->freefrags);
+ fputc('\n', out);
+ }
+
+ /*
+ * Note that since a pool can be locked now, these stats might be
+ * somewhat off if the pool is in active use at the time the stats
+ * are dumped. The link fields are protected by the isc_mem_t's
+ * lock, however, so walking this list and extracting integers from
+ * stats fields is always safe.
+ */
+ pool = ISC_LIST_HEAD(ctx->pools);
+ if (pool != NULL) {
+ fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLSTATS,
+ "[Pool statistics]\n"));
+ fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLNAME, "name"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLSIZE, "size"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLMAXALLOC, "maxalloc"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLALLOCATED, "allocated"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLFREECOUNT, "freecount"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLFREEMAX, "freemax"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLFILLCOUNT, "fillcount"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLGETS, "gets"),
+ "L");
+ }
+ while (pool != NULL) {
+ fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
+#if ISC_MEMPOOL_NAMES
+ pool->name,
+#else
+ "(not tracked)",
+#endif
+ (unsigned long) pool->size, pool->maxalloc,
+ pool->allocated, pool->freecount, pool->freemax,
+ pool->fillcount, pool->gets,
+ (pool->lock == NULL ? "N" : "Y"));
+ pool = ISC_LIST_NEXT(pool, link);
+ }
+
+#if ISC_MEM_TRACKLINES
+ print_active(ctx, out);
+#endif
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+/*
+ * Replacements for malloc() and free() -- they implicitly remember the
+ * size of the object allocated (with some additional overhead).
+ */
+
+static void *
+mem_allocateunlocked(isc_mem_t *ctx0, size_t size) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ size_info *si;
+
+ size += ALIGNMENT_SIZE;
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
+ size += ALIGNMENT_SIZE;
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
+ si = mem_getunlocked(ctx, size);
+ else
+ si = mem_get(ctx, size);
+
+ if (si == NULL)
+ return (NULL);
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
+ si->u.ctx = ctx;
+ si++;
+ }
+ si->u.size = size;
+ return (&si[1]);
+}
+
+void *
+isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ size_info *si;
+ bool call_water = false;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ MCTXLOCK(ctx, &ctx->lock);
+ si = mem_allocateunlocked((isc_mem_t *)ctx, size);
+ if (((ctx->flags & ISC_MEMFLAG_INTERNAL) == 0) && (si != NULL))
+ mem_getstats(ctx, si[-1].u.size);
+
+ ADD_TRACE(ctx, si, si[-1].u.size, file, line);
+ if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
+ !ctx->is_overmem) {
+ ctx->is_overmem = true;
+ }
+
+ if (ctx->hi_water != 0U && !ctx->hi_called &&
+ ctx->inuse > ctx->hi_water) {
+ ctx->hi_called = true;
+ call_water = true;
+ }
+ if (ctx->inuse > ctx->maxinuse) {
+ ctx->maxinuse = ctx->inuse;
+ if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
+ (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
+ fprintf(stderr, "maxinuse = %lu\n",
+ (unsigned long)ctx->inuse);
+ }
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (call_water)
+ (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
+
+ return (si);
+}
+
+void *
+isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ void *new_ptr = NULL;
+ size_t oldsize, copysize;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ /*
+ * This function emulates the realloc(3) standard library function:
+ * - if size > 0, allocate new memory; and if ptr is non NULL, copy
+ * as much of the old contents to the new buffer and free the old one.
+ * Note that when allocation fails the original pointer is intact;
+ * the caller must free it.
+ * - if size is 0 and ptr is non NULL, simply free the given ptr.
+ * - this function returns:
+ * pointer to the newly allocated memory, or
+ * NULL if allocation fails or doesn't happen.
+ */
+ if (size > 0U) {
+ new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS);
+ if (new_ptr != NULL && ptr != NULL) {
+ oldsize = (((size_info *)ptr)[-1]).u.size;
+ INSIST(oldsize >= ALIGNMENT_SIZE);
+ oldsize -= ALIGNMENT_SIZE;
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
+ INSIST(oldsize >= ALIGNMENT_SIZE);
+ oldsize -= ALIGNMENT_SIZE;
+ }
+ copysize = (oldsize > size) ? size : oldsize;
+ memmove(new_ptr, ptr, copysize);
+ isc__mem_free(ctx0, ptr FLARG_PASS);
+ }
+ } else if (ptr != NULL)
+ isc__mem_free(ctx0, ptr FLARG_PASS);
+
+ return (new_ptr);
+}
+
+void
+isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ size_info *si;
+ size_t size;
+ bool call_water= false;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(ptr != NULL);
+
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
+ si = &(((size_info *)ptr)[-2]);
+ REQUIRE(si->u.ctx == ctx);
+ size = si[1].u.size;
+ } else {
+ si = &(((size_info *)ptr)[-1]);
+ size = si->u.size;
+ }
+
+ MCTXLOCK(ctx, &ctx->lock);
+
+ DELETE_TRACE(ctx, ptr, size, file, line);
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ mem_putunlocked(ctx, si, size);
+ } else {
+ mem_putstats(ctx, si, size);
+ mem_put(ctx, si, size);
+ }
+
+ /*
+ * The check against ctx->lo_water == 0 is for the condition
+ * when the context was pushed over hi_water but then had
+ * isc_mem_setwater() called with 0 for hi_water and lo_water.
+ */
+ if (ctx->is_overmem &&
+ (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
+ ctx->is_overmem = false;
+ }
+
+ if (ctx->hi_called &&
+ (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
+ ctx->hi_called = false;
+
+ if (ctx->water != NULL)
+ call_water = true;
+ }
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (call_water)
+ (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
+}
+
+
+/*
+ * Other useful things.
+ */
+
+char *
+isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
+ isc__mem_t *mctx = (isc__mem_t *)mctx0;
+ size_t len;
+ char *ns;
+
+ REQUIRE(VALID_CONTEXT(mctx));
+ REQUIRE(s != NULL);
+
+ len = strlen(s) + 1;
+
+ ns = isc__mem_allocate((isc_mem_t *)mctx, len FLARG_PASS);
+
+ if (ns != NULL)
+ strlcpy(ns, s, len);
+
+ return (ns);
+}
+
+void
+isc__mem_setdestroycheck(isc_mem_t *ctx0, bool flag) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ ctx->checkfree = flag;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+/*
+ * Quotas
+ */
+
+void
+isc_mem_setquota(isc_mem_t *ctx0, size_t quota) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ ctx->quota = quota;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+size_t
+isc_mem_getquota(isc_mem_t *ctx0) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ size_t quota;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ quota = ctx->quota;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ return (quota);
+}
+
+size_t
+isc__mem_inuse(isc_mem_t *ctx0) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ size_t inuse;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ inuse = ctx->inuse;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ return (inuse);
+}
+
+size_t
+isc__mem_maxinuse(isc_mem_t *ctx0) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ size_t maxinuse;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ maxinuse = ctx->maxinuse;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ return (maxinuse);
+}
+
+size_t
+isc__mem_total(isc_mem_t *ctx0) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ size_t total;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ total = ctx->total;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ return (total);
+}
+
+void
+isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg,
+ size_t hiwater, size_t lowater)
+{
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ bool callwater = false;
+ isc_mem_water_t oldwater;
+ void *oldwater_arg;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(hiwater >= lowater);
+
+ MCTXLOCK(ctx, &ctx->lock);
+ oldwater = ctx->water;
+ oldwater_arg = ctx->water_arg;
+ if (water == NULL) {
+ callwater = ctx->hi_called;
+ ctx->water = NULL;
+ ctx->water_arg = NULL;
+ ctx->hi_water = 0;
+ ctx->lo_water = 0;
+ } else {
+ if (ctx->hi_called &&
+ (ctx->water != water || ctx->water_arg != water_arg ||
+ ctx->inuse < lowater || lowater == 0U))
+ callwater = true;
+ ctx->water = water;
+ ctx->water_arg = water_arg;
+ ctx->hi_water = hiwater;
+ ctx->lo_water = lowater;
+ }
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (callwater && oldwater != NULL)
+ (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
+}
+
+bool
+isc__mem_isovermem(isc_mem_t *ctx0) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ /*
+ * We don't bother to lock the context because 100% accuracy isn't
+ * necessary (and even if we locked the context the returned value
+ * could be different from the actual state when it's used anyway)
+ */
+ return (ctx->is_overmem);
+}
+
+void
+isc_mem_setname(isc_mem_t *ctx0, const char *name, void *tag) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ LOCK(&ctx->lock);
+ strlcpy(ctx->name, name, sizeof(ctx->name));
+ ctx->tag = tag;
+ UNLOCK(&ctx->lock);
+}
+
+const char *
+isc_mem_getname(isc_mem_t *ctx0) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ if (ctx->name[0] == 0)
+ return ("");
+
+ return (ctx->name);
+}
+
+void *
+isc_mem_gettag(isc_mem_t *ctx0) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ return (ctx->tag);
+}
+
+/*
+ * Memory pool stuff
+ */
+
+isc_result_t
+isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
+ isc__mem_t *mctx = (isc__mem_t *)mctx0;
+ isc__mempool_t *mpctx;
+
+ REQUIRE(VALID_CONTEXT(mctx));
+ REQUIRE(size > 0U);
+ REQUIRE(mpctxp != NULL && *mpctxp == NULL);
+
+ /*
+ * Allocate space for this pool, initialize values, and if all works
+ * well, attach to the memory context.
+ */
+ mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t));
+ if (mpctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods;
+ mpctx->common.impmagic = MEMPOOL_MAGIC;
+ mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
+ mpctx->lock = NULL;
+ mpctx->mctx = mctx;
+ /*
+ * Mempools are stored as a linked list of element.
+ */
+ if (size < sizeof(element)) {
+ size = sizeof(element);
+ }
+ mpctx->size = size;
+ mpctx->maxalloc = UINT_MAX;
+ mpctx->allocated = 0;
+ mpctx->freecount = 0;
+ mpctx->freemax = 1;
+ mpctx->fillcount = 1;
+ mpctx->gets = 0;
+#if ISC_MEMPOOL_NAMES
+ mpctx->name[0] = 0;
+#endif
+ mpctx->items = NULL;
+
+ *mpctxp = (isc_mempool_t *)mpctx;
+
+ MCTXLOCK(mctx, &mctx->lock);
+ ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
+ mctx->poolcnt++;
+ MCTXUNLOCK(mctx, &mctx->lock);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+ REQUIRE(name != NULL);
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+#if ISC_MEMPOOL_NAMES
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ strlcpy(mpctx->name, name, sizeof(mpctx->name));
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+#else
+ UNUSED(mpctx);
+ UNUSED(name);
+#endif
+}
+
+void
+isc__mempool_destroy(isc_mempool_t **mpctxp) {
+ isc__mempool_t *mpctx;
+ isc__mem_t *mctx;
+ isc_mutex_t *lock;
+ element *item;
+
+ REQUIRE(mpctxp != NULL);
+ mpctx = (isc__mempool_t *)*mpctxp;
+ REQUIRE(VALID_MEMPOOL(mpctx));
+#if ISC_MEMPOOL_NAMES
+ if (mpctx->allocated > 0)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc__mempool_destroy(): mempool %s "
+ "leaked memory",
+ mpctx->name);
+#endif
+ REQUIRE(mpctx->allocated == 0);
+
+ mctx = mpctx->mctx;
+
+ lock = mpctx->lock;
+
+ if (lock != NULL)
+ LOCK(lock);
+
+ /*
+ * Return any items on the free list
+ */
+ MCTXLOCK(mctx, &mctx->lock);
+ while (mpctx->items != NULL) {
+ INSIST(mpctx->freecount > 0);
+ mpctx->freecount--;
+ item = mpctx->items;
+ mpctx->items = item->next;
+
+ if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ mem_putunlocked(mctx, item, mpctx->size);
+ } else {
+ mem_putstats(mctx, item, mpctx->size);
+ mem_put(mctx, item, mpctx->size);
+ }
+ }
+ MCTXUNLOCK(mctx, &mctx->lock);
+
+ /*
+ * Remove our linked list entry from the memory context.
+ */
+ MCTXLOCK(mctx, &mctx->lock);
+ ISC_LIST_UNLINK(mctx->pools, mpctx, link);
+ mctx->poolcnt--;
+ MCTXUNLOCK(mctx, &mctx->lock);
+
+ mpctx->common.impmagic = 0;
+ mpctx->common.magic = 0;
+
+ isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t));
+
+ if (lock != NULL)
+ UNLOCK(lock);
+
+ *mpctxp = NULL;
+}
+
+void
+isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+ REQUIRE(mpctx->lock == NULL);
+ REQUIRE(lock != NULL);
+
+ mpctx->lock = lock;
+}
+
+void *
+isc___mempool_get(isc_mempool_t *mpctx0 FLARG) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+ element *item;
+ isc__mem_t *mctx;
+ unsigned int i;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ mctx = mpctx->mctx;
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ /*
+ * Don't let the caller go over quota
+ */
+ if (ISC_UNLIKELY(mpctx->allocated >= mpctx->maxalloc)) {
+ item = NULL;
+ goto out;
+ }
+
+ if (ISC_UNLIKELY(mpctx->items == NULL)) {
+ /*
+ * We need to dip into the well. Lock the memory context
+ * here and fill up our free list.
+ */
+ MCTXLOCK(mctx, &mctx->lock);
+ for (i = 0; i < mpctx->fillcount; i++) {
+ if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ item = mem_getunlocked(mctx, mpctx->size);
+ } else {
+ item = mem_get(mctx, mpctx->size);
+ if (item != NULL)
+ mem_getstats(mctx, mpctx->size);
+ }
+ if (ISC_UNLIKELY(item == NULL))
+ break;
+ item->next = mpctx->items;
+ mpctx->items = item;
+ mpctx->freecount++;
+ }
+ MCTXUNLOCK(mctx, &mctx->lock);
+ }
+
+ /*
+ * If we didn't get any items, return NULL.
+ */
+ item = mpctx->items;
+ if (ISC_UNLIKELY(item == NULL))
+ goto out;
+
+ mpctx->items = item->next;
+ INSIST(mpctx->freecount > 0);
+ mpctx->freecount--;
+ mpctx->gets++;
+ mpctx->allocated++;
+
+ out:
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+#if ISC_MEM_TRACKLINES
+ if (((isc_mem_debugging & TRACE_OR_RECORD) != 0) && item != NULL) {
+ MCTXLOCK(mctx, &mctx->lock);
+ ADD_TRACE(mctx, item, mpctx->size, file, line);
+ MCTXUNLOCK(mctx, &mctx->lock);
+ }
+#endif /* ISC_MEM_TRACKLINES */
+
+ return (item);
+}
+
+/* coverity[+free : arg-1] */
+void
+isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+ isc__mem_t *mctx;
+ element *item;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+ REQUIRE(mem != NULL);
+
+ mctx = mpctx->mctx;
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ INSIST(mpctx->allocated > 0);
+ mpctx->allocated--;
+
+#if ISC_MEM_TRACKLINES
+ if ((isc_mem_debugging & TRACE_OR_RECORD) != 0) {
+ MCTXLOCK(mctx, &mctx->lock);
+ DELETE_TRACE(mctx, mem, mpctx->size, file, line);
+ MCTXUNLOCK(mctx, &mctx->lock);
+ }
+#endif /* ISC_MEM_TRACKLINES */
+
+ /*
+ * If our free list is full, return this to the mctx directly.
+ */
+ if (mpctx->freecount >= mpctx->freemax) {
+ MCTXLOCK(mctx, &mctx->lock);
+ if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ mem_putunlocked(mctx, mem, mpctx->size);
+ } else {
+ mem_putstats(mctx, mem, mpctx->size);
+ mem_put(mctx, mem, mpctx->size);
+ }
+ MCTXUNLOCK(mctx, &mctx->lock);
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+ return;
+ }
+
+ /*
+ * Otherwise, attach it to our free list and bump the counter.
+ */
+ mpctx->freecount++;
+ item = (element *)mem;
+ item->next = mpctx->items;
+ mpctx->items = item;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+}
+
+/*
+ * Quotas
+ */
+
+void
+isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ mpctx->freemax = limit;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+}
+
+unsigned int
+isc_mempool_getfreemax(isc_mempool_t *mpctx0) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+ unsigned int freemax;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ freemax = mpctx->freemax;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+ return (freemax);
+}
+
+unsigned int
+isc_mempool_getfreecount(isc_mempool_t *mpctx0) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+ unsigned int freecount;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ freecount = mpctx->freecount;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+ return (freecount);
+}
+
+void
+isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+ REQUIRE(limit > 0);
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ mpctx->maxalloc = limit;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+}
+
+unsigned int
+isc_mempool_getmaxalloc(isc_mempool_t *mpctx0) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+ unsigned int maxalloc;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ maxalloc = mpctx->maxalloc;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+ return (maxalloc);
+}
+
+unsigned int
+isc__mempool_getallocated(isc_mempool_t *mpctx0) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+ unsigned int allocated;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ allocated = mpctx->allocated;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+ return (allocated);
+}
+
+void
+isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+ REQUIRE(limit > 0);
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ mpctx->fillcount = limit;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+}
+
+unsigned int
+isc_mempool_getfillcount(isc_mempool_t *mpctx0) {
+ isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+ unsigned int fillcount;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ fillcount = mpctx->fillcount;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+ return (fillcount);
+}
+
+isc_result_t
+isc__mem_register(void) {
+ return (isc_mem_register(isc_mem_create2));
+}
+
+void
+isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
+#if ISC_MEM_TRACKLINES
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(file != NULL);
+
+ print_active(ctx, file);
+#else
+ UNUSED(ctx0);
+ UNUSED(file);
+#endif
+}
+
+void
+isc_mem_printallactive(FILE *file) {
+#if !ISC_MEM_TRACKLINES
+ UNUSED(file);
+#else
+ isc__mem_t *ctx;
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+ LOCK(&contextslock);
+ for (ctx = ISC_LIST_HEAD(contexts);
+ ctx != NULL;
+ ctx = ISC_LIST_NEXT(ctx, link)) {
+ fprintf(file, "context: %p\n", ctx);
+ print_active(ctx, file);
+ }
+ UNLOCK(&contextslock);
+#endif
+}
+
+void
+isc_mem_checkdestroyed(FILE *file) {
+#if !ISC_MEM_TRACKLINES
+ UNUSED(file);
+#endif
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+ LOCK(&contextslock);
+ if (!ISC_LIST_EMPTY(contexts)) {
+#if ISC_MEM_TRACKLINES
+ if ((isc_mem_debugging & TRACE_OR_RECORD) != 0) {
+ isc__mem_t *ctx;
+
+ for (ctx = ISC_LIST_HEAD(contexts);
+ ctx != NULL;
+ ctx = ISC_LIST_NEXT(ctx, link)) {
+ fprintf(file, "context: %p\n", ctx);
+ print_active(ctx, file);
+ }
+ fflush(file);
+ }
+#endif
+ INSIST(0);
+ }
+ UNLOCK(&contextslock);
+}
+
+unsigned int
+isc_mem_references(isc_mem_t *ctx0) {
+ isc__mem_t *ctx = (isc__mem_t *)ctx0;
+ unsigned int references;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ MCTXLOCK(ctx, &ctx->lock);
+ references = ctx->references;
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ return (references);
+}
+
+typedef struct summarystat {
+ uint64_t total;
+ uint64_t inuse;
+ uint64_t blocksize;
+ uint64_t contextsize;
+} summarystat_t;
+
+#ifdef HAVE_LIBXML2
+#define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
+static int
+xml_renderctx(isc__mem_t *ctx, summarystat_t *summary,
+ xmlTextWriterPtr writer)
+{
+ int xmlrc;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ MCTXLOCK(ctx, &ctx->lock);
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%p", ctx));
+ TRY0(xmlTextWriterEndElement(writer)); /* id */
+
+ if (ctx->name[0] != 0) {
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%s", ctx->name));
+ TRY0(xmlTextWriterEndElement(writer)); /* name */
+ }
+
+ summary->contextsize += sizeof(*ctx) +
+ (ctx->max_size + 1) * sizeof(struct stats) +
+ ctx->max_size * sizeof(element *) +
+ ctx->basic_table_count * sizeof(char *);
+#if ISC_MEM_TRACKLINES
+ if (ctx->debuglist != NULL) {
+ summary->contextsize +=
+ (ctx->max_size + 1) * sizeof(debuglist_t) +
+ ctx->debuglistcnt * sizeof(debuglink_t);
+ }
+#endif
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d", ctx->references));
+ TRY0(xmlTextWriterEndElement(writer)); /* references */
+
+ summary->total += ctx->total;
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"));
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64,
+ (uint64_t)ctx->total));
+ TRY0(xmlTextWriterEndElement(writer)); /* total */
+
+ summary->inuse += ctx->inuse;
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"));
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64,
+ (uint64_t)ctx->inuse));
+ TRY0(xmlTextWriterEndElement(writer)); /* inuse */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"));
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64,
+ (uint64_t)ctx->maxinuse));
+ TRY0(xmlTextWriterEndElement(writer)); /* maxinuse */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"));
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ summary->blocksize += ctx->basic_table_count *
+ NUM_BASIC_BLOCKS * ctx->mem_target;
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64,
+ (uint64_t)
+ ctx->basic_table_count *
+ NUM_BASIC_BLOCKS *
+ ctx->mem_target));
+ } else
+ TRY0(xmlTextWriterWriteFormatString(writer, "%s", "-"));
+ TRY0(xmlTextWriterEndElement(writer)); /* blocksize */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt));
+ TRY0(xmlTextWriterEndElement(writer)); /* pools */
+ summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"));
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64,
+ (uint64_t)ctx->hi_water));
+ TRY0(xmlTextWriterEndElement(writer)); /* hiwater */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"));
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64 "",
+ (uint64_t)ctx->lo_water));
+ TRY0(xmlTextWriterEndElement(writer)); /* lowater */
+
+ TRY0(xmlTextWriterEndElement(writer)); /* context */
+
+ error:
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ return (xmlrc);
+}
+
+int
+isc_mem_renderxml(xmlTextWriterPtr writer) {
+ isc__mem_t *ctx;
+ summarystat_t summary;
+ uint64_t lost;
+ int xmlrc;
+
+ memset(&summary, 0, sizeof(summary));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"));
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+ LOCK(&contextslock);
+ lost = totallost;
+ for (ctx = ISC_LIST_HEAD(contexts);
+ ctx != NULL;
+ ctx = ISC_LIST_NEXT(ctx, link)) {
+ xmlrc = xml_renderctx(ctx, &summary, writer);
+ if (xmlrc < 0) {
+ UNLOCK(&contextslock);
+ goto error;
+ }
+ }
+ UNLOCK(&contextslock);
+
+ TRY0(xmlTextWriterEndElement(writer)); /* contexts */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"));
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64,
+ summary.total));
+ TRY0(xmlTextWriterEndElement(writer)); /* TotalUse */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"));
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64,
+ summary.inuse));
+ TRY0(xmlTextWriterEndElement(writer)); /* InUse */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"));
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64,
+ summary.blocksize));
+ TRY0(xmlTextWriterEndElement(writer)); /* BlockSize */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"));
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64,
+ summary.contextsize));
+ TRY0(xmlTextWriterEndElement(writer)); /* ContextSize */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"));
+ TRY0(xmlTextWriterWriteFormatString(writer,
+ "%" PRIu64,
+ lost));
+ TRY0(xmlTextWriterEndElement(writer)); /* Lost */
+
+ TRY0(xmlTextWriterEndElement(writer)); /* summary */
+ error:
+ return (xmlrc);
+}
+
+#endif /* HAVE_LIBXML2 */
+
+#ifdef HAVE_JSON
+#define CHECKMEM(m) do { \
+ if (m == NULL) { \
+ result = ISC_R_NOMEMORY;\
+ goto error;\
+ } \
+} while(0)
+
+static isc_result_t
+json_renderctx(isc__mem_t *ctx, summarystat_t *summary, json_object *array) {
+ isc_result_t result = ISC_R_FAILURE;
+ json_object *ctxobj, *obj;
+ char buf[1024];
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(summary != NULL);
+ REQUIRE(array != NULL);
+
+ MCTXLOCK(ctx, &ctx->lock);
+
+ summary->contextsize += sizeof(*ctx) +
+ (ctx->max_size + 1) * sizeof(struct stats) +
+ ctx->max_size * sizeof(element *) +
+ ctx->basic_table_count * sizeof(char *);
+ summary->total += ctx->total;
+ summary->inuse += ctx->inuse;
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
+ summary->blocksize += ctx->basic_table_count *
+ NUM_BASIC_BLOCKS * ctx->mem_target;
+#if ISC_MEM_TRACKLINES
+ if (ctx->debuglist != NULL) {
+ summary->contextsize +=
+ (ctx->max_size + 1) * sizeof(debuglist_t) +
+ ctx->debuglistcnt * sizeof(debuglink_t);
+ }
+#endif
+
+ ctxobj = json_object_new_object();
+ CHECKMEM(ctxobj);
+
+ snprintf(buf, sizeof(buf), "%p", ctx);
+ obj = json_object_new_string(buf);
+ CHECKMEM(obj);
+ json_object_object_add(ctxobj, "id", obj);
+
+ if (ctx->name[0] != 0) {
+ obj = json_object_new_string(ctx->name);
+ CHECKMEM(obj);
+ json_object_object_add(ctxobj, "name", obj);
+ }
+
+ obj = json_object_new_int64(ctx->references);
+ CHECKMEM(obj);
+ json_object_object_add(ctxobj, "references", obj);
+
+ obj = json_object_new_int64(ctx->total);
+ CHECKMEM(obj);
+ json_object_object_add(ctxobj, "total", obj);
+
+ obj = json_object_new_int64(ctx->inuse);
+ CHECKMEM(obj);
+ json_object_object_add(ctxobj, "inuse", obj);
+
+ obj = json_object_new_int64(ctx->maxinuse);
+ CHECKMEM(obj);
+ json_object_object_add(ctxobj, "maxinuse", obj);
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ uint64_t blocksize;
+ blocksize = ctx->basic_table_count * NUM_BASIC_BLOCKS *
+ ctx->mem_target;
+ obj = json_object_new_int64(blocksize);
+ CHECKMEM(obj);
+ json_object_object_add(ctxobj, "blocksize", obj);
+ }
+
+ obj = json_object_new_int64(ctx->poolcnt);
+ CHECKMEM(obj);
+ json_object_object_add(ctxobj, "pools", obj);
+
+ summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
+
+ obj = json_object_new_int64(ctx->hi_water);
+ CHECKMEM(obj);
+ json_object_object_add(ctxobj, "hiwater", obj);
+
+ obj = json_object_new_int64(ctx->lo_water);
+ CHECKMEM(obj);
+ json_object_object_add(ctxobj, "lowater", obj);
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+ json_object_array_add(array, ctxobj);
+ return (ISC_R_SUCCESS);
+
+ error:
+ MCTXUNLOCK(ctx, &ctx->lock);
+ if (ctxobj != NULL)
+ json_object_put(ctxobj);
+ return (result);
+}
+
+isc_result_t
+isc_mem_renderjson(json_object *memobj) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc__mem_t *ctx;
+ summarystat_t summary;
+ uint64_t lost;
+ json_object *ctxarray, *obj;
+
+ memset(&summary, 0, sizeof(summary));
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+ ctxarray = json_object_new_array();
+ CHECKMEM(ctxarray);
+
+ LOCK(&contextslock);
+ lost = totallost;
+ for (ctx = ISC_LIST_HEAD(contexts);
+ ctx != NULL;
+ ctx = ISC_LIST_NEXT(ctx, link)) {
+ result = json_renderctx(ctx, &summary, ctxarray);
+ if (result != ISC_R_SUCCESS) {
+ UNLOCK(&contextslock);
+ goto error;
+ }
+ }
+ UNLOCK(&contextslock);
+
+ obj = json_object_new_int64(summary.total);
+ CHECKMEM(obj);
+ json_object_object_add(memobj, "TotalUse", obj);
+
+ obj = json_object_new_int64(summary.inuse);
+ CHECKMEM(obj);
+ json_object_object_add(memobj, "InUse", obj);
+
+ obj = json_object_new_int64(summary.blocksize);
+ CHECKMEM(obj);
+ json_object_object_add(memobj, "BlockSize", obj);
+
+ obj = json_object_new_int64(summary.contextsize);
+ CHECKMEM(obj);
+ json_object_object_add(memobj, "ContextSize", obj);
+
+ obj = json_object_new_int64(lost);
+ CHECKMEM(obj);
+ json_object_object_add(memobj, "Lost", obj);
+
+ json_object_object_add(memobj, "contexts", ctxarray);
+ return (ISC_R_SUCCESS);
+
+ error:
+ if (ctxarray != NULL)
+ json_object_put(ctxarray);
+ return (result);
+}
+#endif /* HAVE_JSON */
+
+static isc_memcreatefunc_t mem_createfunc = NULL;
+
+isc_result_t
+isc_mem_register(isc_memcreatefunc_t createfunc) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+ LOCK(&createlock);
+ if (mem_createfunc == NULL)
+ mem_createfunc = createfunc;
+ else
+ result = ISC_R_EXISTS;
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+
+isc_result_t
+isc__mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **mctxp,
+ unsigned int flags)
+{
+ isc_result_t result;
+
+ LOCK(&createlock);
+
+ REQUIRE(mem_createfunc != NULL);
+ result = (*mem_createfunc)(init_max_size, target_size, mctxp, flags);
+
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+isc_result_t
+isc_mem_create(size_t init_max_size, size_t target_size, isc_mem_t **mctxp) {
+ isc_result_t result;
+
+ if (isc_bind9)
+ return (isc_mem_createx2(init_max_size, target_size,
+ default_memalloc, default_memfree,
+ NULL, mctxp, isc_mem_defaultflags));
+ LOCK(&createlock);
+
+ REQUIRE(mem_createfunc != NULL);
+ result = (*mem_createfunc)(init_max_size, target_size, mctxp,
+ isc_mem_defaultflags);
+
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+isc_result_t
+isc_mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **mctxp,
+ unsigned int flags)
+{
+ if (isc_bind9)
+ return (isc_mem_createx2(init_max_size, target_size,
+ default_memalloc, default_memfree,
+ NULL, mctxp, flags));
+
+ return (isc_mem_createx2(init_max_size, target_size,
+ default_memalloc, default_memfree,
+ NULL, mctxp, flags));
+}
+
+void
+isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
+ REQUIRE(ISCAPI_MCTX_VALID(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ if (isc_bind9)
+ isc__mem_attach(source, targetp);
+ else
+ source->methods->attach(source, targetp);
+
+ ENSURE(*targetp == source);
+}
+
+void
+isc_mem_detach(isc_mem_t **mctxp) {
+ REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
+
+ if (isc_bind9)
+ isc__mem_detach(mctxp);
+ else
+ (*mctxp)->methods->detach(mctxp);
+
+ ENSURE(*mctxp == NULL);
+}
+
+void
+isc_mem_destroy(isc_mem_t **mctxp) {
+ REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
+
+ if (isc_bind9)
+ isc__mem_destroy(mctxp);
+ else
+ (*mctxp)->methods->destroy(mctxp);
+
+ ENSURE(*mctxp == NULL);
+}
+
+void
+isc_mem_setdestroycheck(isc_mem_t *mctx, bool flag) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ mctx->methods->setdestroycheck(mctx, flag);
+}
+
+void
+isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
+ size_t hiwater, size_t lowater)
+{
+ REQUIRE(ISCAPI_MCTX_VALID(ctx));
+
+ if (isc_bind9)
+ isc__mem_setwater(ctx, water, water_arg, hiwater, lowater);
+ else
+ ctx->methods->setwater(ctx, water, water_arg, hiwater, lowater);
+}
+
+void
+isc_mem_waterack(isc_mem_t *ctx, int flag) {
+ REQUIRE(ISCAPI_MCTX_VALID(ctx));
+
+ if (isc_bind9)
+ isc__mem_waterack(ctx, flag);
+ else
+ ctx->methods->waterack(ctx, flag);
+}
+
+size_t
+isc_mem_inuse(isc_mem_t *mctx) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ if (isc_bind9)
+ return (isc__mem_inuse(mctx));
+
+ return (mctx->methods->inuse(mctx));
+}
+
+size_t
+isc_mem_maxinuse(isc_mem_t *mctx) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ if (isc_bind9)
+ return (isc__mem_maxinuse(mctx));
+
+ return (mctx->methods->maxinuse(mctx));
+}
+
+size_t
+isc_mem_total(isc_mem_t *mctx) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ if (isc_bind9)
+ return (isc__mem_total(mctx));
+
+ return (mctx->methods->total(mctx));
+}
+
+bool
+isc_mem_isovermem(isc_mem_t *mctx) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ if (isc_bind9)
+ return (isc__mem_isovermem(mctx));
+
+ return (mctx->methods->isovermem(mctx));
+}
+
+
+isc_result_t
+isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ return (mctx->methods->mpcreate(mctx, size, mpctxp));
+}
+
+void
+isc_mempool_destroy(isc_mempool_t **mpctxp) {
+ REQUIRE(mpctxp != NULL && ISCAPI_MPOOL_VALID(*mpctxp));
+
+ if (isc_bind9)
+ isc__mempool_destroy(mpctxp);
+ else
+ (*mpctxp)->methods->destroy(mpctxp);
+
+ ENSURE(*mpctxp == NULL);
+}
+
+unsigned int
+isc_mempool_getallocated(isc_mempool_t *mpctx) {
+ REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
+
+ if (isc_bind9)
+ return (isc__mempool_getallocated(mpctx));
+
+ return (mpctx->methods->getallocated(mpctx));
+}
+
+void
+isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
+ REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
+
+ if (isc_bind9)
+ isc__mempool_setmaxalloc(mpctx, limit);
+ else
+ mpctx->methods->setmaxalloc(mpctx, limit);
+}
+
+void
+isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
+ REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
+
+ if (isc_bind9)
+ isc__mempool_setfreemax(mpctx, limit);
+ else
+ mpctx->methods->setfreemax(mpctx, limit);
+}
+
+void
+isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
+ REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
+
+ if (isc_bind9)
+ isc__mempool_setname(mpctx, name);
+ else
+ mpctx->methods->setname(mpctx, name);
+}
+
+void
+isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
+ REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
+
+ if (isc_bind9)
+ isc__mempool_associatelock(mpctx, lock);
+ else
+ mpctx->methods->associatelock(mpctx, lock);
+}
+
+void
+isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
+ REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
+
+ if (isc_bind9)
+ isc__mempool_setfillcount(mpctx, limit);
+ else
+ mpctx->methods->setfillcount(mpctx, limit);
+}
+
+void *
+isc__mem_get(isc_mem_t *mctx, size_t size FLARG) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ if (isc_bind9)
+ return (isc___mem_get(mctx, size FLARG_PASS));
+
+ return (mctx->methods->memget(mctx, size FLARG_PASS));
+
+}
+
+void
+isc__mem_put(isc_mem_t *mctx, void *ptr, size_t size FLARG) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ if (isc_bind9)
+ isc___mem_put(mctx, ptr, size FLARG_PASS);
+ else
+ mctx->methods->memput(mctx, ptr, size FLARG_PASS);
+}
+
+void
+isc__mem_putanddetach(isc_mem_t **mctxp, void *ptr, size_t size FLARG) {
+ REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
+
+ if (isc_bind9)
+ isc___mem_putanddetach(mctxp, ptr, size FLARG_PASS);
+ else
+ (*mctxp)->methods->memputanddetach(mctxp, ptr, size FLARG_PASS);
+
+ /*
+ * XXX: We cannot always ensure *mctxp == NULL here
+ * (see lib/isc/mem.c).
+ */
+}
+
+void *
+isc__mem_allocate(isc_mem_t *mctx, size_t size FLARG) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ if (isc_bind9)
+ return (isc___mem_allocate(mctx, size FLARG_PASS));
+
+ return (mctx->methods->memallocate(mctx, size FLARG_PASS));
+}
+
+void *
+isc__mem_reallocate(isc_mem_t *mctx, void *ptr, size_t size FLARG) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ if (isc_bind9)
+ return (isc___mem_reallocate(mctx, ptr, size FLARG_PASS));
+
+ return (mctx->methods->memreallocate(mctx, ptr, size FLARG_PASS));
+}
+
+char *
+isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ if (isc_bind9)
+ return (isc___mem_strdup(mctx, s FLARG_PASS));
+
+ return (mctx->methods->memstrdup(mctx, s FLARG_PASS));
+}
+
+void
+isc__mem_free(isc_mem_t *mctx, void *ptr FLARG) {
+ REQUIRE(ISCAPI_MCTX_VALID(mctx));
+
+ if (isc_bind9)
+ isc___mem_free(mctx, ptr FLARG_PASS);
+ else
+ mctx->methods->memfree(mctx, ptr FLARG_PASS);
+}
+
+void *
+isc__mempool_get(isc_mempool_t *mpctx FLARG) {
+ REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
+
+ if (isc_bind9)
+ return (isc___mempool_get(mpctx FLARG_PASS));
+
+ return (mpctx->methods->get(mpctx FLARG_PASS));
+}
+
+void
+isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
+ REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
+
+ if (isc_bind9)
+ isc___mempool_put(mpctx, mem FLARG_PASS);
+ else
+ mpctx->methods->put(mpctx, mem FLARG_PASS);
+}
diff --git a/lib/isc/mips/Makefile.in b/lib/isc/mips/Makefile.in
new file mode 100644
index 0000000..419cf9f
--- /dev/null
+++ b/lib/isc/mips/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/mips/include/Makefile.in b/lib/isc/mips/include/Makefile.in
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/lib/isc/mips/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/mips/include/isc/Makefile.in b/lib/isc/mips/include/isc/Makefile.in
new file mode 100644
index 0000000..97b6b41
--- /dev/null
+++ b/lib/isc/mips/include/isc/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
diff --git a/lib/isc/mips/include/isc/atomic.h b/lib/isc/mips/include/isc/atomic.h
new file mode 100644
index 0000000..caba82f
--- /dev/null
+++ b/lib/isc/mips/include/isc/atomic.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <inttypes.h>
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+static inline int32_t
+isc_atomic_xadd(int32_t *p, int val) {
+ int32_t orig;
+
+ __asm__ __volatile__ (
+ " .set push \n"
+ " .set mips2 \n"
+ " .set noreorder \n"
+ " .set noat \n"
+ "1: ll $1, %1 \n"
+ " addu %0, $1, %2 \n"
+ " sc %0, %1 \n"
+ " beqz %0, 1b \n"
+ " move %0, $1 \n"
+ " .set pop \n"
+ : "=&r" (orig), "+R" (*p)
+ : "r" (val)
+ : "memory");
+
+ return (orig);
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(int32_t *p, int32_t val) {
+ *p = val;
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+static inline int32_t
+isc_atomic_cmpxchg(int32_t *p, int cmpval, int val) {
+ int32_t orig;
+ int32_t tmp;
+
+ __asm__ __volatile__ (
+ " .set push \n"
+ " .set mips2 \n"
+ " .set noreorder \n"
+ " .set noat \n"
+ "1: ll $1, %1 \n"
+ " bne $1, %3, 2f \n"
+ " move %2, %4 \n"
+ " sc %2, %1 \n"
+ " beqz %2, 1b \n"
+ "2: move %0, $1 \n"
+ " .set pop \n"
+ : "=&r"(orig), "+R" (*p), "=r" (tmp)
+ : "r"(cmpval), "r"(val)
+ : "memory");
+
+ return (orig);
+}
+
+#else /* !ISC_PLATFORM_USEGCCASM */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/mutexblock.c b/lib/isc/mutexblock.c
new file mode 100644
index 0000000..6a629e7
--- /dev/null
+++ b/lib/isc/mutexblock.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mutexblock.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_mutexblock_init(isc_mutex_t *block, unsigned int count) {
+ isc_result_t result;
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ result = isc_mutex_init(&block[i]);
+ if (result != ISC_R_SUCCESS) {
+ while (i > 0U) {
+ i--;
+ DESTROYLOCK(&block[i]);
+ }
+ return (result);
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_mutexblock_destroy(isc_mutex_t *block, unsigned int count) {
+ isc_result_t result;
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ result = isc_mutex_destroy(&block[i]);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/netaddr.c b/lib/isc/netaddr.c
new file mode 100644
index 0000000..81851a0
--- /dev/null
+++ b/lib/isc/netaddr.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <isc/buffer.h>
+#include <isc/msgs.h>
+#include <isc/net.h>
+#include <isc/netaddr.h>
+#include <isc/print.h>
+#include <isc/sockaddr.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+bool
+isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
+ REQUIRE(a != NULL && b != NULL);
+
+ if (a->family != b->family)
+ return (false);
+
+ if (a->zone != b->zone)
+ return (false);
+
+ switch (a->family) {
+ case AF_INET:
+ if (a->type.in.s_addr != b->type.in.s_addr)
+ return (false);
+ break;
+ case AF_INET6:
+ if (memcmp(&a->type.in6, &b->type.in6,
+ sizeof(a->type.in6)) != 0 ||
+ a->zone != b->zone)
+ return (false);
+ break;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ case AF_UNIX:
+ if (strcmp(a->type.un, b->type.un) != 0)
+ return (false);
+ break;
+#endif
+ default:
+ return (false);
+ }
+ return (true);
+}
+
+bool
+isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
+ unsigned int prefixlen)
+{
+ const unsigned char *pa = NULL, *pb = NULL;
+ unsigned int ipabytes = 0; /* Length of whole IP address in bytes */
+ unsigned int nbytes; /* Number of significant whole bytes */
+ unsigned int nbits; /* Number of significant leftover bits */
+
+ REQUIRE(a != NULL && b != NULL);
+
+ if (a->family != b->family)
+ return (false);
+
+ if (a->zone != b->zone && b->zone != 0)
+ return (false);
+
+ switch (a->family) {
+ case AF_INET:
+ pa = (const unsigned char *) &a->type.in;
+ pb = (const unsigned char *) &b->type.in;
+ ipabytes = 4;
+ break;
+ case AF_INET6:
+ pa = (const unsigned char *) &a->type.in6;
+ pb = (const unsigned char *) &b->type.in6;
+ ipabytes = 16;
+ break;
+ default:
+ return (false);
+ }
+
+ /*
+ * Don't crash if we get a pattern like 10.0.0.1/9999999.
+ */
+ if (prefixlen > ipabytes * 8)
+ prefixlen = ipabytes * 8;
+
+ nbytes = prefixlen / 8;
+ nbits = prefixlen % 8;
+
+ if (nbytes > 0) {
+ if (memcmp(pa, pb, nbytes) != 0)
+ return (false);
+ }
+ if (nbits > 0) {
+ unsigned int bytea, byteb, mask;
+ INSIST(nbytes < ipabytes);
+ INSIST(nbits < 8);
+ bytea = pa[nbytes];
+ byteb = pb[nbytes];
+ mask = (0xFF << (8-nbits)) & 0xFF;
+ if ((bytea & mask) != (byteb & mask))
+ return (false);
+ }
+ return (true);
+}
+
+isc_result_t
+isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
+ char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
+ char zbuf[sizeof("%4294967295")];
+ unsigned int alen;
+ int zlen;
+ const char *r;
+ const void *type;
+
+ REQUIRE(netaddr != NULL);
+
+ switch (netaddr->family) {
+ case AF_INET:
+ type = &netaddr->type.in;
+ break;
+ case AF_INET6:
+ type = &netaddr->type.in6;
+ break;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ case AF_UNIX:
+ alen = strlen(netaddr->type.un);
+ if (alen > isc_buffer_availablelength(target))
+ return (ISC_R_NOSPACE);
+ isc_buffer_putmem(target,
+ (const unsigned char *)(netaddr->type.un),
+ alen);
+ return (ISC_R_SUCCESS);
+#endif
+ default:
+ return (ISC_R_FAILURE);
+ }
+ r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
+ if (r == NULL)
+ return (ISC_R_FAILURE);
+
+ alen = strlen(abuf);
+ INSIST(alen < sizeof(abuf));
+
+ zlen = 0;
+ if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
+ zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
+ if (zlen < 0)
+ return (ISC_R_FAILURE);
+ INSIST((unsigned int)zlen < sizeof(zbuf));
+ }
+
+ if (alen + zlen > isc_buffer_availablelength(target))
+ return (ISC_R_NOSPACE);
+
+ isc_buffer_putmem(target, (unsigned char *)abuf, alen);
+ isc_buffer_putmem(target, (unsigned char *)zbuf, (unsigned int)zlen);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
+ isc_result_t result;
+ isc_buffer_t buf;
+
+ isc_buffer_init(&buf, array, size);
+ result = isc_netaddr_totext(na, &buf);
+
+ if (size == 0)
+ return;
+
+ /*
+ * Null terminate.
+ */
+ if (result == ISC_R_SUCCESS) {
+ if (isc_buffer_availablelength(&buf) >= 1)
+ isc_buffer_putuint8(&buf, 0);
+ else
+ result = ISC_R_NOSPACE;
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ snprintf(array, size,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
+ ISC_MSG_UNKNOWNADDR,
+ "<unknown address, family %u>"),
+ na->family);
+ array[size - 1] = '\0';
+ }
+}
+
+
+isc_result_t
+isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
+ static const unsigned char zeros[16];
+ unsigned int nbits, nbytes, ipbytes = 0;
+ const unsigned char *p;
+
+ switch (na->family) {
+ case AF_INET:
+ p = (const unsigned char *) &na->type.in;
+ ipbytes = 4;
+ if (prefixlen > 32)
+ return (ISC_R_RANGE);
+ break;
+ case AF_INET6:
+ p = (const unsigned char *) &na->type.in6;
+ ipbytes = 16;
+ if (prefixlen > 128)
+ return (ISC_R_RANGE);
+ break;
+ default:
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+ nbytes = prefixlen / 8;
+ nbits = prefixlen % 8;
+ if (nbits != 0) {
+ INSIST(nbytes < ipbytes);
+ if ((p[nbytes] & (0xff>>nbits)) != 0U)
+ return (ISC_R_FAILURE);
+ nbytes++;
+ }
+ if (nbytes < ipbytes && memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0)
+ return (ISC_R_FAILURE);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
+ unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i;
+ const unsigned char *p;
+
+ switch (s->family) {
+ case AF_INET:
+ p = (const unsigned char *) &s->type.in;
+ ipbytes = 4;
+ break;
+ case AF_INET6:
+ p = (const unsigned char *) &s->type.in6;
+ ipbytes = 16;
+ break;
+ default:
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+ for (i = 0; i < ipbytes; i++) {
+ if (p[i] != 0xFF)
+ break;
+ }
+ nbytes = i;
+ if (i < ipbytes) {
+ unsigned int c = p[nbytes];
+ while ((c & 0x80) != 0 && nbits < 8) {
+ c <<= 1; nbits++;
+ }
+ if ((c & 0xFF) != 0)
+ return (ISC_R_MASKNONCONTIG);
+ i++;
+ }
+ for (; i < ipbytes; i++) {
+ if (p[i] != 0)
+ return (ISC_R_MASKNONCONTIG);
+ }
+ *lenp = nbytes * 8 + nbits;
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
+ memset(netaddr, 0, sizeof(*netaddr));
+ netaddr->family = AF_INET;
+ netaddr->type.in = *ina;
+}
+
+void
+isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
+ memset(netaddr, 0, sizeof(*netaddr));
+ netaddr->family = AF_INET6;
+ netaddr->type.in6 = *ina6;
+}
+
+isc_result_t
+isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) {
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ if (strlen(path) > sizeof(netaddr->type.un) - 1)
+ return (ISC_R_NOSPACE);
+
+ memset(netaddr, 0, sizeof(*netaddr));
+ netaddr->family = AF_UNIX;
+ strlcpy(netaddr->type.un, path, sizeof(netaddr->type.un));
+ netaddr->zone = 0;
+ return (ISC_R_SUCCESS);
+#else
+ UNUSED(netaddr);
+ UNUSED(path);
+ return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+
+void
+isc_netaddr_setzone(isc_netaddr_t *netaddr, uint32_t zone) {
+ /* we currently only support AF_INET6. */
+ REQUIRE(netaddr->family == AF_INET6);
+
+ netaddr->zone = zone;
+}
+
+uint32_t
+isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
+ return (netaddr->zone);
+}
+
+void
+isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
+ int family = s->type.sa.sa_family;
+ t->family = family;
+ switch (family) {
+ case AF_INET:
+ t->type.in = s->type.sin.sin_addr;
+ t->zone = 0;
+ break;
+ case AF_INET6:
+ memmove(&t->type.in6, &s->type.sin6.sin6_addr, 16);
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ t->zone = s->type.sin6.sin6_scope_id;
+#else
+ t->zone = 0;
+#endif
+ break;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ case AF_UNIX:
+ memmove(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un));
+ t->zone = 0;
+ break;
+#endif
+ default:
+ INSIST(0);
+ }
+}
+
+void
+isc_netaddr_any(isc_netaddr_t *netaddr) {
+ memset(netaddr, 0, sizeof(*netaddr));
+ netaddr->family = AF_INET;
+ netaddr->type.in.s_addr = INADDR_ANY;
+}
+
+void
+isc_netaddr_any6(isc_netaddr_t *netaddr) {
+ memset(netaddr, 0, sizeof(*netaddr));
+ netaddr->family = AF_INET6;
+ netaddr->type.in6 = in6addr_any;
+}
+
+bool
+isc_netaddr_ismulticast(isc_netaddr_t *na) {
+ switch (na->family) {
+ case AF_INET:
+ return (ISC_IPADDR_ISMULTICAST(na->type.in.s_addr));
+ case AF_INET6:
+ return (IN6_IS_ADDR_MULTICAST(&na->type.in6));
+ default:
+ return (false); /* XXXMLG ? */
+ }
+}
+
+bool
+isc_netaddr_isexperimental(isc_netaddr_t *na) {
+ switch (na->family) {
+ case AF_INET:
+ return (ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr));
+ default:
+ return (false); /* XXXMLG ? */
+ }
+}
+
+bool
+isc_netaddr_islinklocal(isc_netaddr_t *na) {
+ switch (na->family) {
+ case AF_INET:
+ return (false);
+ case AF_INET6:
+ return (IN6_IS_ADDR_LINKLOCAL(&na->type.in6));
+ default:
+ return (false);
+ }
+}
+
+bool
+isc_netaddr_issitelocal(isc_netaddr_t *na) {
+ switch (na->family) {
+ case AF_INET:
+ return (false);
+ case AF_INET6:
+ return (IN6_IS_ADDR_SITELOCAL(&na->type.in6));
+ default:
+ return (false);
+ }
+}
+
+#define ISC_IPADDR_ISNETZERO(i) \
+ (((uint32_t)(i) & ISC__IPADDR(0xff000000)) \
+ == ISC__IPADDR(0x00000000))
+
+bool
+isc_netaddr_isnetzero(isc_netaddr_t *na) {
+ switch (na->family) {
+ case AF_INET:
+ return (ISC_IPADDR_ISNETZERO(na->type.in.s_addr));
+ case AF_INET6:
+ return (false);
+ default:
+ return (false);
+ }
+}
+
+void
+isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
+ isc_netaddr_t *src;
+
+ DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */
+
+ REQUIRE(s->family == AF_INET6);
+ REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
+
+ memset(t, 0, sizeof(*t));
+ t->family = AF_INET;
+ memmove(&t->type.in, (char *)&src->type.in6 + 12, 4);
+ return;
+}
+
+bool
+isc_netaddr_isloopback(const isc_netaddr_t *na) {
+ switch (na->family) {
+ case AF_INET:
+ return ((ntohl(na->type.in.s_addr) & 0xff000000U) ==
+ 0x7f000000U);
+ case AF_INET6:
+ return (IN6_IS_ADDR_LOOPBACK(&na->type.in6));
+ default:
+ return (false);
+ }
+}
diff --git a/lib/isc/netscope.c b/lib/isc/netscope.c
new file mode 100644
index 0000000..1c51d35
--- /dev/null
+++ b/lib/isc/netscope.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/string.h>
+#include <isc/net.h>
+#include <isc/netscope.h>
+#include <isc/result.h>
+
+isc_result_t
+isc_netscope_pton(int af, char *scopename, void *addr, uint32_t *zoneid) {
+ char *ep;
+#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
+ unsigned int ifid;
+ struct in6_addr *in6;
+#endif
+ uint32_t zone;
+ uint64_t llz;
+
+ /* at this moment, we only support AF_INET6 */
+ if (af != AF_INET6)
+ return (ISC_R_FAILURE);
+
+ /*
+ * Basically, "names" are more stable than numeric IDs in terms of
+ * renumbering, and are more preferred. However, since there is no
+ * standard naming convention and APIs to deal with the names. Thus,
+ * we only handle the case of link-local addresses, for which we use
+ * interface names as link names, assuming one to one mapping between
+ * interfaces and links.
+ */
+#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
+ in6 = (struct in6_addr *)addr;
+ if (IN6_IS_ADDR_LINKLOCAL(in6) &&
+ (ifid = if_nametoindex((const char *)scopename)) != 0)
+ zone = (uint32_t)ifid;
+ else {
+#endif
+ llz = isc_string_touint64(scopename, &ep, 10);
+ if (ep == scopename)
+ return (ISC_R_FAILURE);
+
+ /* check overflow */
+ zone = (uint32_t)(llz & 0xffffffffUL);
+ if (zone != llz)
+ return (ISC_R_FAILURE);
+#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
+ }
+#endif
+
+ *zoneid = zone;
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/nls/Makefile.in b/lib/isc/nls/Makefile.in
new file mode 100644
index 0000000..704dead
--- /dev/null
+++ b/lib/isc/nls/Makefile.in
@@ -0,0 +1,29 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+CINCLUDES = -I../unix/include \
+ -I${srcdir}/../unix/include \
+ -I../include \
+ -I${srcdir}/../include
+
+CDEFINES =
+CWARNINGS =
+
+OBJS = msgcat.@O@
+
+SRCS = msgcat.c
+
+SUBDIRS =
+TARGETS = ${OBJS}
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/nls/msgcat.c b/lib/isc/nls/msgcat.c
new file mode 100644
index 0000000..ab09b94
--- /dev/null
+++ b/lib/isc/nls/msgcat.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file msgcat.c */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <isc/magic.h>
+#include <isc/msgcat.h>
+#include <isc/util.h>
+
+#ifdef HAVE_CATGETS
+#include <nl_types.h> /* Required for nl_catd. */
+#endif
+
+/*
+ * Implementation Notes:
+ *
+ * We use malloc() and free() instead of isc_mem_get() and isc_mem_put()
+ * because we don't want to require a memory context to be specified
+ * in order to use a message catalog.
+ */
+
+struct isc_msgcat {
+ unsigned int magic;
+#ifdef HAVE_CATGETS
+ nl_catd catalog;
+#endif
+};
+
+#define MSGCAT_MAGIC ISC_MAGIC('M', 'C', 'a', 't')
+#define VALID_MSGCAT(m) ISC_MAGIC_VALID(m, MSGCAT_MAGIC)
+
+void
+isc_msgcat_open(const char *name, isc_msgcat_t **msgcatp) {
+ isc_msgcat_t *msgcat;
+
+ /*
+ * Open a message catalog.
+ */
+
+ REQUIRE(name != NULL);
+ REQUIRE(msgcatp != NULL && *msgcatp == NULL);
+
+ msgcat = malloc(sizeof(*msgcat));
+ if (msgcat == NULL) {
+ *msgcatp = NULL;
+ return;
+ }
+
+#ifdef HAVE_CATGETS
+ /*
+ * We don't check if catopen() fails because we don't care.
+ * If it does fail, then when we call catgets(), it will use
+ * the default string.
+ */
+ msgcat->catalog = catopen(name, 0);
+#endif
+ msgcat->magic = MSGCAT_MAGIC;
+
+ *msgcatp = msgcat;
+}
+
+void
+isc_msgcat_close(isc_msgcat_t **msgcatp) {
+ isc_msgcat_t *msgcat;
+
+ /*
+ * Close a message catalog.
+ */
+
+ REQUIRE(msgcatp != NULL);
+ msgcat = *msgcatp;
+ REQUIRE(VALID_MSGCAT(msgcat) || msgcat == NULL);
+
+ if (msgcat != NULL) {
+#ifdef HAVE_CATGETS
+ if (msgcat->catalog != (nl_catd)(-1))
+ (void)catclose(msgcat->catalog);
+#endif
+ msgcat->magic = 0;
+ free(msgcat);
+ }
+
+ *msgcatp = NULL;
+}
+
+const char *
+isc_msgcat_get(isc_msgcat_t *msgcat, int set, int message,
+ const char *default_text)
+{
+ /*
+ * Get message 'message' from message set 'set' in 'msgcat'. If it
+ * is not available, use 'default'.
+ */
+
+ REQUIRE(VALID_MSGCAT(msgcat) || msgcat == NULL);
+ REQUIRE(set > 0);
+ REQUIRE(message > 0);
+ REQUIRE(default_text != NULL);
+
+#ifdef HAVE_CATGETS
+ if (msgcat == NULL)
+ return (default_text);
+ return (catgets(msgcat->catalog, set, message, default_text));
+#else
+ return (default_text);
+#endif
+}
diff --git a/lib/isc/noatomic/Makefile.in b/lib/isc/noatomic/Makefile.in
new file mode 100644
index 0000000..419cf9f
--- /dev/null
+++ b/lib/isc/noatomic/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/noatomic/include/Makefile.in b/lib/isc/noatomic/include/Makefile.in
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/lib/isc/noatomic/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/noatomic/include/isc/Makefile.in b/lib/isc/noatomic/include/isc/Makefile.in
new file mode 100644
index 0000000..97b6b41
--- /dev/null
+++ b/lib/isc/noatomic/include/isc/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
diff --git a/lib/isc/noatomic/include/isc/atomic.h b/lib/isc/noatomic/include/isc/atomic.h
new file mode 100644
index 0000000..5953e4b
--- /dev/null
+++ b/lib/isc/noatomic/include/isc/atomic.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+/* This file is inherently empty. */
+
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/nothreads/Makefile.in b/lib/isc/nothreads/Makefile.in
new file mode 100644
index 0000000..c794773
--- /dev/null
+++ b/lib/isc/nothreads/Makefile.in
@@ -0,0 +1,32 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+top_srcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+CINCLUDES = -I${srcdir}/include \
+ -I${srcdir}/../unix/include \
+ -I../include \
+ -I${srcdir}/../include \
+ -I${srcdir}/..
+
+CDEFINES =
+CWARNINGS =
+
+THREADOPTOBJS = condition.@O@ mutex.@O@
+OBJS = @THREADOPTOBJS@ thread.@O@
+
+THREADOPTSRCS = condition.c mutex.c
+SRCS = @THREADOPTSRCS@ thread.c
+
+SUBDIRS = include
+TARGETS = ${OBJS}
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/nothreads/condition.c b/lib/isc/nothreads/condition.c
new file mode 100644
index 0000000..a549c30
--- /dev/null
+++ b/lib/isc/nothreads/condition.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
diff --git a/lib/isc/nothreads/include/Makefile.in b/lib/isc/nothreads/include/Makefile.in
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/lib/isc/nothreads/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/nothreads/include/isc/Makefile.in b/lib/isc/nothreads/include/isc/Makefile.in
new file mode 100644
index 0000000..185534f
--- /dev/null
+++ b/lib/isc/nothreads/include/isc/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = condition.h mutex.h once.h thread.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
diff --git a/lib/isc/nothreads/include/isc/condition.h b/lib/isc/nothreads/include/isc/condition.h
new file mode 100644
index 0000000..0bea23d
--- /dev/null
+++ b/lib/isc/nothreads/include/isc/condition.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * This provides a limited subset of the isc_condition_t
+ * functionality for use by single-threaded programs that
+ * need to block waiting for events. Only a single
+ * call to isc_condition_wait() may be blocked at any given
+ * time, and the _waituntil and _broadcast functions are not
+ * supported. This is intended primarily for use by the omapi
+ * library, and may go away once omapi goes away. Use for
+ * other purposes is strongly discouraged.
+ */
+
+#ifndef ISC_CONDITION_H
+#define ISC_CONDITION_H 1
+
+#include <isc/mutex.h>
+
+typedef int isc_condition_t;
+
+isc_result_t isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp);
+isc_result_t isc__nothread_signal_hack(isc_condition_t *cp);
+
+#define isc_condition_init(cp) \
+ (*(cp) = 0, ISC_R_SUCCESS)
+
+#define isc_condition_wait(cp, mp) \
+ isc__nothread_wait_hack(cp, mp)
+
+#define isc_condition_waituntil(cp, mp, tp) \
+ ((void)(cp), (void)(mp), (void)(tp), ISC_R_NOTIMPLEMENTED)
+
+#define isc_condition_signal(cp) \
+ isc__nothread_signal_hack(cp)
+
+#define isc_condition_broadcast(cp) \
+ ((void)(cp), ISC_R_NOTIMPLEMENTED)
+
+#define isc_condition_destroy(cp) \
+ (*(cp) == 0 ? (*(cp) = -1, ISC_R_SUCCESS) : ISC_R_UNEXPECTED)
+
+#endif /* ISC_CONDITION_H */
diff --git a/lib/isc/nothreads/include/isc/mutex.h b/lib/isc/nothreads/include/isc/mutex.h
new file mode 100644
index 0000000..a9c55f6
--- /dev/null
+++ b/lib/isc/nothreads/include/isc/mutex.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_MUTEX_H
+#define ISC_MUTEX_H 1
+
+#include <isc/result.h> /* for ISC_R_ codes */
+
+typedef int isc_mutex_t;
+
+#define isc_mutex_init(mp) \
+ (*(mp) = 0, ISC_R_SUCCESS)
+#define isc_mutex_lock(mp) \
+ ((*(mp))++ == 0 ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#define isc_mutex_unlock(mp) \
+ (--(*(mp)) == 0 ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#define isc_mutex_trylock(mp) \
+ (*(mp) == 0 ? ((*(mp))++, ISC_R_SUCCESS) : ISC_R_LOCKBUSY)
+#define isc_mutex_destroy(mp) \
+ (*(mp) == 0 ? (*(mp) = -1, ISC_R_SUCCESS) : ISC_R_UNEXPECTED)
+#define isc_mutex_stats(fp)
+
+#endif /* ISC_MUTEX_H */
diff --git a/lib/isc/nothreads/include/isc/once.h b/lib/isc/nothreads/include/isc/once.h
new file mode 100644
index 0000000..c291814
--- /dev/null
+++ b/lib/isc/nothreads/include/isc/once.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ONCE_H
+#define ISC_ONCE_H 1
+
+#include <stdbool.h>
+
+#include <isc/result.h>
+
+typedef bool isc_once_t;
+
+#define ISC_ONCE_INIT false
+
+#define isc_once_do(op, f) \
+ (!*(op) ? (f(), *(op) = true, ISC_R_SUCCESS) : ISC_R_SUCCESS)
+
+#endif /* ISC_ONCE_H */
diff --git a/lib/isc/nothreads/include/isc/thread.h b/lib/isc/nothreads/include/isc/thread.h
new file mode 100644
index 0000000..8486c3f
--- /dev/null
+++ b/lib/isc/nothreads/include/isc/thread.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_THREAD_H
+#define ISC_THREAD_H 1
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+/* Placeholder types (they are not accessed) */
+
+typedef void * isc_thread_t;
+typedef void * isc_threadresult_t;
+typedef void * isc_threadarg_t;
+typedef void * isc_threadfunc_t;
+typedef void * isc_thread_key_t;
+
+void
+isc_thread_setconcurrency(unsigned int level);
+
+void
+isc_thread_setname(isc_thread_t thread, const char *name);
+
+#define isc_thread_self() ((unsigned long)0)
+#define isc_thread_yield() ((void)0)
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_THREAD_H */
diff --git a/lib/isc/nothreads/mutex.c b/lib/isc/nothreads/mutex.c
new file mode 100644
index 0000000..e092ac9
--- /dev/null
+++ b/lib/isc/nothreads/mutex.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
+
diff --git a/lib/isc/nothreads/thread.c b/lib/isc/nothreads/thread.c
new file mode 100644
index 0000000..671261f
--- /dev/null
+++ b/lib/isc/nothreads/thread.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <isc/thread.h>
+#include <isc/util.h>
+
+void
+isc_thread_setconcurrency(unsigned int level) {
+ UNUSED(level);
+}
+
+void isc_thread_setname(isc_thread_t thread, const char *name) {
+ UNUSED(thread);
+ UNUSED(name);
+}
diff --git a/lib/isc/ondestroy.c b/lib/isc/ondestroy.c
new file mode 100644
index 0000000..64d4d91
--- /dev/null
+++ b/lib/isc/ondestroy.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id: ondestroy.c,v 1.16 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/event.h>
+#include <isc/magic.h>
+#include <isc/ondestroy.h>
+#include <isc/task.h>
+#include <isc/util.h>
+
+#define ONDESTROY_MAGIC ISC_MAGIC('D', 'e', 'S', 't')
+#define VALID_ONDESTROY(s) ISC_MAGIC_VALID(s, ONDESTROY_MAGIC)
+
+void
+isc_ondestroy_init(isc_ondestroy_t *ondest) {
+ ondest->magic = ONDESTROY_MAGIC;
+ ISC_LIST_INIT(ondest->events);
+}
+
+isc_result_t
+isc_ondestroy_register(isc_ondestroy_t *ondest, isc_task_t *task,
+ isc_event_t **eventp)
+{
+ isc_event_t *theevent;
+ isc_task_t *thetask = NULL;
+
+ REQUIRE(VALID_ONDESTROY(ondest));
+ REQUIRE(task != NULL);
+ REQUIRE(eventp != NULL);
+
+ theevent = *eventp;
+
+ REQUIRE(theevent != NULL);
+
+ isc_task_attach(task, &thetask);
+
+ theevent->ev_sender = thetask;
+
+ ISC_LIST_APPEND(ondest->events, theevent, ev_link);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_ondestroy_notify(isc_ondestroy_t *ondest, void *sender) {
+ isc_event_t *eventp;
+ isc_task_t *task;
+
+ REQUIRE(VALID_ONDESTROY(ondest));
+
+ eventp = ISC_LIST_HEAD(ondest->events);
+ while (eventp != NULL) {
+ ISC_LIST_UNLINK(ondest->events, eventp, ev_link);
+
+ task = eventp->ev_sender;
+ eventp->ev_sender = sender;
+
+ isc_task_sendanddetach(&task, &eventp);
+
+ eventp = ISC_LIST_HEAD(ondest->events);
+ }
+}
+
+
diff --git a/lib/isc/parseint.c b/lib/isc/parseint.c
new file mode 100644
index 0000000..5859369
--- /dev/null
+++ b/lib/isc/parseint.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <inttypes.h>
+
+#include <isc/parseint.h>
+#include <isc/result.h>
+#include <isc/stdlib.h>
+
+isc_result_t
+isc_parse_uint32(uint32_t *uip, const char *string, int base) {
+ unsigned long n;
+ uint32_t r;
+ char *e;
+ if (! isalnum((unsigned char)(string[0])))
+ return (ISC_R_BADNUMBER);
+ errno = 0;
+ n = strtoul(string, &e, base);
+ if (*e != '\0')
+ return (ISC_R_BADNUMBER);
+ /*
+ * Where long is 64 bits we need to convert to 32 bits then test for
+ * equality. This is a no-op on 32 bit machines and a good compiler
+ * will optimise it away.
+ */
+ r = (uint32_t)n;
+ if ((n == ULONG_MAX && errno == ERANGE) || (n != (unsigned long)r))
+ return (ISC_R_RANGE);
+ *uip = r;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_parse_uint16(uint16_t *uip, const char *string, int base) {
+ uint32_t val;
+ isc_result_t result;
+ result = isc_parse_uint32(&val, string, base);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (val > 0xFFFF)
+ return (ISC_R_RANGE);
+ *uip = (uint16_t) val;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_parse_uint8(uint8_t *uip, const char *string, int base) {
+ uint32_t val;
+ isc_result_t result;
+ result = isc_parse_uint32(&val, string, base);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (val > 0xFF)
+ return (ISC_R_RANGE);
+ *uip = (uint8_t) val;
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c
new file mode 100644
index 0000000..c5d2310
--- /dev/null
+++ b/lib/isc/pk11.c
@@ -0,0 +1,1399 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include <dst/result.h>
+
+#include <pk11/pk11.h>
+#include <pk11/internal.h>
+#include <pk11/result.h>
+#include <pk11/site.h>
+
+#include <pkcs11/cryptoki.h>
+#include <pkcs11/pkcs11.h>
+#include <pkcs11/eddsa.h>
+
+/* was 32 octets, Petr Spacek suggested 1024, SoftHSMv2 uses 256... */
+#ifndef PINLEN
+#define PINLEN 256
+#endif
+
+#ifndef PK11_NO_LOGERR
+#define PK11_NO_LOGERR 1
+#endif
+
+LIBISC_EXTERNAL_DATA bool pk11_verbose_init = false;
+
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_mem_t *pk11_mctx = NULL;
+static int32_t allocsize = 0;
+static bool initialized = false;
+
+typedef struct pk11_session pk11_session_t;
+typedef struct pk11_token pk11_token_t;
+typedef ISC_LIST(pk11_session_t) pk11_sessionlist_t;
+
+struct pk11_session {
+ unsigned int magic;
+ CK_SESSION_HANDLE session;
+ ISC_LINK(pk11_session_t) link;
+ pk11_token_t *token;
+};
+
+struct pk11_token {
+ unsigned int magic;
+ unsigned int operations;
+ ISC_LINK(pk11_token_t) link;
+ CK_SLOT_ID slotid;
+ pk11_sessionlist_t sessions;
+ bool logged;
+ char name[32];
+ char manuf[32];
+ char model[16];
+ char serial[16];
+ char pin[PINLEN + 1];
+};
+static ISC_LIST(pk11_token_t) tokens;
+
+static pk11_token_t *rand_token;
+static pk11_token_t *best_rsa_token;
+static pk11_token_t *best_dsa_token;
+static pk11_token_t *best_dh_token;
+static pk11_token_t *digest_token;
+static pk11_token_t *best_ec_token;
+static pk11_token_t *best_gost_token;
+static pk11_token_t *aes_token;
+
+static isc_result_t free_all_sessions(void);
+static isc_result_t free_session_list(pk11_sessionlist_t *slist);
+static isc_result_t setup_session(pk11_session_t *sp,
+ pk11_token_t *token,
+ bool rw);
+static void scan_slots(void);
+static isc_result_t token_login(pk11_session_t *sp);
+static char *percent_decode(char *x, size_t *len);
+static bool pk11strcmp(const char *x, size_t lenx,
+ const char *y, size_t leny);
+static CK_ATTRIBUTE *push_attribute(pk11_object_t *obj,
+ isc_mem_t *mctx,
+ size_t len);
+
+static isc_mutex_t alloclock;
+static isc_mutex_t sessionlock;
+
+static pk11_sessionlist_t actives;
+
+static CK_C_INITIALIZE_ARGS pk11_init_args = {
+ NULL_PTR, /* CreateMutex */
+ NULL_PTR, /* DestroyMutex */
+ NULL_PTR, /* LockMutex */
+ NULL_PTR, /* UnlockMutex */
+ CKF_OS_LOCKING_OK, /* flags */
+ NULL_PTR, /* pReserved */
+};
+
+#ifndef PK11_LIB_LOCATION
+#define PK11_LIB_LOCATION "unknown_provider"
+#endif
+
+#ifndef WIN32
+static const char *lib_name = PK11_LIB_LOCATION;
+#else
+static const char *lib_name = PK11_LIB_LOCATION ".dll";
+#endif
+
+void
+pk11_set_lib_name(const char *name) {
+ lib_name = name;
+}
+
+const char *
+pk11_get_lib_name(void) {
+ return (lib_name);
+}
+
+static void
+initialize(void) {
+ char *pk11_provider;
+
+ RUNTIME_CHECK(isc_mutex_init(&alloclock) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_mutex_init(&sessionlock) == ISC_R_SUCCESS);
+
+ pk11_provider = getenv("PKCS11_PROVIDER");
+ if (pk11_provider != NULL)
+ lib_name = pk11_provider;
+}
+
+void *
+pk11_mem_get(size_t size) {
+ void *ptr;
+
+ LOCK(&alloclock);
+ if (pk11_mctx != NULL)
+ ptr = isc_mem_get(pk11_mctx, size);
+ else {
+ ptr = malloc(size);
+ if (ptr != NULL)
+ allocsize += (int)size;
+ }
+ UNLOCK(&alloclock);
+
+ if (ptr != NULL)
+ memset(ptr, 0, size);
+ return (ptr);
+}
+
+void
+pk11_mem_put(void *ptr, size_t size) {
+ if (ptr != NULL)
+ memset(ptr, 0, size);
+ LOCK(&alloclock);
+ if (pk11_mctx != NULL)
+ isc_mem_put(pk11_mctx, ptr, size);
+ else {
+ if (ptr != NULL)
+ allocsize -= (int)size;
+ free(ptr);
+ }
+ UNLOCK(&alloclock);
+}
+
+isc_result_t
+pk11_initialize(isc_mem_t *mctx, const char *engine) {
+ isc_result_t result = ISC_R_SUCCESS;
+ CK_RV rv;
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
+
+ LOCK(&sessionlock);
+ LOCK(&alloclock);
+ if ((mctx != NULL) && (pk11_mctx == NULL) && (allocsize == 0))
+ isc_mem_attach(mctx, &pk11_mctx);
+ UNLOCK(&alloclock);
+ if (initialized) {
+ goto unlock;
+ } else {
+ initialized = true;
+ }
+
+ ISC_LIST_INIT(tokens);
+ ISC_LIST_INIT(actives);
+
+ if (engine != NULL)
+ lib_name = engine;
+
+ /* Initialize the CRYPTOKI library */
+ rv = pkcs_C_Initialize((CK_VOID_PTR) &pk11_init_args);
+
+ if (rv == 0xfe) {
+ result = PK11_R_NOPROVIDER;
+ fprintf(stderr, "Can't load PKCS#11 provider: %s\n",
+ pk11_get_load_error_message());
+ goto unlock;
+ }
+ if (rv != CKR_OK) {
+ result = PK11_R_INITFAILED;
+ goto unlock;
+ }
+
+ scan_slots();
+#ifdef PKCS11CRYPTO
+ if (rand_token == NULL) {
+ result = PK11_R_NORANDOMSERVICE;
+ goto unlock;
+ }
+ if (digest_token == NULL) {
+ result = PK11_R_NODIGESTSERVICE;
+ goto unlock;
+ }
+#if defined(AES_CC)
+ if (aes_token == NULL) {
+ result = PK11_R_NOAESSERVICE;
+ goto unlock;
+ }
+#endif
+#endif /* PKCS11CRYPTO */
+ unlock:
+ UNLOCK(&sessionlock);
+ return (result);
+}
+
+isc_result_t
+pk11_finalize(void) {
+ pk11_token_t *token, *next;
+ isc_result_t ret;
+
+ ret = free_all_sessions();
+ (void) pkcs_C_Finalize(NULL_PTR);
+ token = ISC_LIST_HEAD(tokens);
+ while (token != NULL) {
+ next = ISC_LIST_NEXT(token, link);
+ ISC_LIST_UNLINK(tokens, token, link);
+ if (token == rand_token)
+ rand_token = NULL;
+ if (token == best_rsa_token)
+ best_rsa_token = NULL;
+ if (token == best_dsa_token)
+ best_dsa_token = NULL;
+ if (token == best_dh_token)
+ best_dh_token = NULL;
+ if (token == digest_token)
+ digest_token = NULL;
+ if (token == best_ec_token)
+ best_ec_token = NULL;
+ if (token == best_gost_token)
+ best_gost_token = NULL;
+ if (token == aes_token)
+ aes_token = NULL;
+ pk11_mem_put(token, sizeof(*token));
+ token = next;
+ }
+ if (pk11_mctx != NULL)
+ isc_mem_detach(&pk11_mctx);
+ initialized = false;
+ return (ret);
+}
+
+isc_result_t
+pk11_rand_bytes(unsigned char *buf, int num) {
+ isc_result_t ret;
+ CK_RV rv;
+ pk11_context_t ctx;
+
+ ret = pk11_get_session(&ctx, OP_RAND, false, false,
+ false, NULL, 0);
+ if ((ret != ISC_R_SUCCESS) &&
+ (ret != PK11_R_NODIGESTSERVICE) &&
+ (ret != PK11_R_NOAESSERVICE))
+ return (ret);
+ RUNTIME_CHECK(ctx.session != CK_INVALID_HANDLE);
+ rv = pkcs_C_GenerateRandom(ctx.session,
+ (CK_BYTE_PTR) buf, (CK_ULONG) num);
+ pk11_return_session(&ctx);
+ if (rv == CKR_OK)
+ return (ISC_R_SUCCESS);
+ else
+ return (DST_R_CRYPTOFAILURE);
+}
+
+#define SEEDSIZE 1024
+
+static CK_BYTE seed[SEEDSIZE];
+
+void
+pk11_rand_seed_fromfile(const char *randomfile) {
+ pk11_context_t ctx;
+ FILE *stream = NULL;
+ size_t cc = 0;
+ isc_result_t ret;
+
+ ret = pk11_get_session(&ctx, OP_RAND, false, false,
+ false, NULL, 0);
+ if ((ret != ISC_R_SUCCESS) &&
+ (ret != PK11_R_NODIGESTSERVICE) &&
+ (ret != PK11_R_NOAESSERVICE))
+ return;
+ RUNTIME_CHECK(ctx.session != CK_INVALID_HANDLE);
+ ret = isc_stdio_open(randomfile, "r", &stream);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup;
+ ret = isc_stdio_read(seed, 1, SEEDSIZE, stream, &cc);
+ if (ret!= ISC_R_SUCCESS)
+ goto cleanup;
+ ret = isc_stdio_close(stream);
+ stream = NULL;
+ if (ret!= ISC_R_SUCCESS)
+ goto cleanup;
+ (void) pkcs_C_SeedRandom(ctx.session, seed, (CK_ULONG) cc);
+
+ cleanup:
+ if (stream != NULL)
+ (void) isc_stdio_close(stream);
+ pk11_return_session(&ctx);
+}
+
+isc_result_t
+pk11_get_session(pk11_context_t *ctx, pk11_optype_t optype,
+ bool need_services, bool rw,
+ bool logon, const char *pin, CK_SLOT_ID slot)
+{
+ pk11_token_t *token = NULL;
+ pk11_sessionlist_t *freelist;
+ pk11_session_t *sp;
+ isc_result_t ret;
+#ifdef PKCS11CRYPTO
+ isc_result_t service_ret = ISC_R_SUCCESS;
+#else
+ UNUSED(need_services);
+#endif
+
+ memset(ctx, 0, sizeof(pk11_context_t));
+ ctx->handle = NULL;
+ ctx->session = CK_INVALID_HANDLE;
+
+ ret = pk11_initialize(NULL, NULL);
+#ifdef PKCS11CRYPTO
+ if (ret == PK11_R_NORANDOMSERVICE ||
+ ret == PK11_R_NODIGESTSERVICE ||
+ ret == PK11_R_NOAESSERVICE) {
+ if (need_services)
+ return (ret);
+ service_ret = ret;
+ }
+ else
+#endif /* PKCS11CRYPTO */
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ LOCK(&sessionlock);
+ /* wait for initialization to finish */
+ UNLOCK(&sessionlock);
+
+ switch(optype) {
+#ifdef PKCS11CRYPTO
+ case OP_RAND:
+ token = rand_token;
+ break;
+ case OP_DIGEST:
+ token = digest_token;
+ break;
+ case OP_AES:
+ token = aes_token;
+ break;
+ case OP_ANY:
+ for (token = ISC_LIST_HEAD(tokens);
+ token != NULL;
+ token = ISC_LIST_NEXT(token, link))
+ if (token->slotid == slot)
+ break;
+ break;
+#endif
+ default:
+ for (token = ISC_LIST_HEAD(tokens);
+ token != NULL;
+ token = ISC_LIST_NEXT(token, link))
+ if (token->slotid == slot)
+ break;
+#ifdef PKCS11CRYPTO
+ if ((token == NULL) ||
+ ((token->operations & (1 << optype)) == 0))
+ return (ISC_R_NOTFOUND);
+#endif
+ break;
+ }
+ if (token == NULL)
+ return (ISC_R_NOTFOUND);
+
+ /* Override the token's PIN */
+ if (logon && pin != NULL && *pin != '\0') {
+ if (strlen(pin) > PINLEN)
+ return (ISC_R_RANGE);
+ /*
+ * We want to zero out the old pin before
+ * overwriting with a new one.
+ */
+ memset(token->pin, 0, sizeof(token->pin));
+ strlcpy(token->pin, pin, sizeof(token->pin));
+ }
+
+ freelist = &token->sessions;
+
+ LOCK(&sessionlock);
+ sp = ISC_LIST_HEAD(*freelist);
+ if (sp != NULL) {
+ ISC_LIST_UNLINK(*freelist, sp, link);
+ ISC_LIST_APPEND(actives, sp, link);
+ UNLOCK(&sessionlock);
+ if (logon)
+ ret = token_login(sp);
+ ctx->handle = sp;
+ ctx->session = sp->session;
+ return (ret);
+ }
+ UNLOCK(&sessionlock);
+
+ sp = pk11_mem_get(sizeof(*sp));
+ if (sp == NULL)
+ return (ISC_R_NOMEMORY);
+ sp->magic = SES_MAGIC;
+ sp->token = token;
+ sp->session = CK_INVALID_HANDLE;
+ ISC_LINK_INIT(sp, link);
+ ret = setup_session(sp, token, rw);
+ if ((ret == ISC_R_SUCCESS) && logon)
+ ret = token_login(sp);
+ LOCK(&sessionlock);
+ ISC_LIST_APPEND(actives, sp, link);
+ UNLOCK(&sessionlock);
+ ctx->handle = sp;
+ ctx->session = sp->session;
+#ifdef PKCS11CRYPTO
+ if (ret == ISC_R_SUCCESS)
+ ret = service_ret;
+#endif
+ return (ret);
+}
+
+void
+pk11_return_session(pk11_context_t *ctx) {
+ pk11_session_t *sp = (pk11_session_t *) ctx->handle;
+
+ if (sp == NULL)
+ return;
+ ctx->handle = NULL;
+ ctx->session = CK_INVALID_HANDLE;
+
+ LOCK(&sessionlock);
+ ISC_LIST_UNLINK(actives, sp, link);
+ UNLOCK(&sessionlock);
+ if (sp->session == CK_INVALID_HANDLE) {
+ pk11_mem_put(sp, sizeof(*sp));
+ return;
+ }
+
+ LOCK(&sessionlock);
+ ISC_LIST_APPEND(sp->token->sessions, sp, link);
+ UNLOCK(&sessionlock);
+}
+
+static isc_result_t
+free_all_sessions(void) {
+ pk11_token_t *token;
+ isc_result_t ret = ISC_R_SUCCESS;
+ isc_result_t oret;
+
+ for (token = ISC_LIST_HEAD(tokens);
+ token != NULL;
+ token = ISC_LIST_NEXT(token, link)) {
+ oret = free_session_list(&token->sessions);
+ if (oret != ISC_R_SUCCESS)
+ ret = oret;
+ }
+ if (!ISC_LIST_EMPTY(actives)) {
+ ret = ISC_R_ADDRINUSE;
+ oret = free_session_list(&actives);
+ if (oret != ISC_R_SUCCESS)
+ ret = oret;
+ }
+ return (ret);
+}
+
+static isc_result_t
+free_session_list(pk11_sessionlist_t *slist) {
+ pk11_session_t *sp;
+ CK_RV rv;
+ isc_result_t ret;
+
+ ret = ISC_R_SUCCESS;
+ LOCK(&sessionlock);
+ while (!ISC_LIST_EMPTY(*slist)) {
+ sp = ISC_LIST_HEAD(*slist);
+ ISC_LIST_UNLINK(*slist, sp, link);
+ UNLOCK(&sessionlock);
+ if (sp->session != CK_INVALID_HANDLE) {
+ rv = pkcs_C_CloseSession(sp->session);
+ if (rv != CKR_OK)
+ ret = DST_R_CRYPTOFAILURE;
+ }
+ LOCK(&sessionlock);
+ pk11_mem_put(sp, sizeof(*sp));
+ }
+ UNLOCK(&sessionlock);
+
+ return (ret);
+}
+
+static isc_result_t
+setup_session(pk11_session_t *sp, pk11_token_t *token,
+ bool rw)
+{
+ CK_RV rv;
+ CK_FLAGS flags = CKF_SERIAL_SESSION;
+
+ if (rw)
+ flags += CKF_RW_SESSION;
+
+ rv = pkcs_C_OpenSession(token->slotid, flags, NULL_PTR,
+ NULL_PTR, &sp->session);
+ if (rv != CKR_OK)
+ return (DST_R_CRYPTOFAILURE);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+token_login(pk11_session_t *sp) {
+ CK_RV rv;
+ pk11_token_t *token = sp->token;
+ isc_result_t ret = ISC_R_SUCCESS;
+
+ LOCK(&sessionlock);
+ if (!token->logged) {
+ rv = pkcs_C_Login(sp->session, CKU_USER,
+ (CK_UTF8CHAR_PTR) token->pin,
+ (CK_ULONG) strlen(token->pin));
+ if (rv != CKR_OK) {
+ ret = ISC_R_NOPERM;
+#if PK11_NO_LOGERR
+ pk11_error_fatalcheck(__FILE__, __LINE__,
+ "pkcs_C_Login", rv);
+#endif
+ } else
+ token->logged = true;
+ }
+ UNLOCK(&sessionlock);
+ return (ret);
+}
+
+#define PK11_TRACE(fmt) \
+ if (pk11_verbose_init) fprintf(stderr, fmt)
+#define PK11_TRACE1(fmt, arg) \
+ if (pk11_verbose_init) fprintf(stderr, fmt, arg)
+#define PK11_TRACE2(fmt, arg1, arg2) \
+ if (pk11_verbose_init) fprintf(stderr, fmt, arg1, arg2)
+#define PK11_TRACEM(mech) \
+ if (pk11_verbose_init) fprintf(stderr, #mech ": 0x%lx\n", rv)
+
+static void
+scan_slots(void) {
+ CK_MECHANISM_INFO mechInfo;
+ CK_TOKEN_INFO tokenInfo;
+ CK_RV rv;
+ CK_SLOT_ID slot;
+ CK_SLOT_ID_PTR slotList;
+ CK_ULONG slotCount;
+ pk11_token_t *token;
+ unsigned int i;
+ bool bad;
+
+ slotCount = 0;
+ PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, NULL_PTR, &slotCount));
+ PK11_TRACE1("slotCount=%lu\n", slotCount);
+ /* it's not an error if we didn't find any providers */
+ if (slotCount == 0)
+ return;
+ slotList = pk11_mem_get(sizeof(CK_SLOT_ID) * slotCount);
+ RUNTIME_CHECK(slotList != NULL);
+ PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, slotList, &slotCount));
+
+ for (i = 0; i < slotCount; i++) {
+ slot = slotList[i];
+ PK11_TRACE2("slot#%u=0x%lx\n", i, slot);
+
+ rv = pkcs_C_GetTokenInfo(slot, &tokenInfo);
+ if (rv != CKR_OK)
+ continue;
+ token = pk11_mem_get(sizeof(*token));
+ RUNTIME_CHECK(token != NULL);
+ token->magic = TOK_MAGIC;
+ token->slotid = slot;
+ ISC_LINK_INIT(token, link);
+ ISC_LIST_INIT(token->sessions);
+ memmove(token->name, tokenInfo.label, 32);
+ memmove(token->manuf, tokenInfo.manufacturerID, 32);
+ memmove(token->model, tokenInfo.model, 16);
+ memmove(token->serial, tokenInfo.serialNumber, 16);
+ ISC_LIST_APPEND(tokens, token, link);
+ if ((tokenInfo.flags & CKF_RNG) == 0) {
+ PK11_TRACE("no CKF_RNG\n");
+ goto try_rsa;
+ }
+ token->operations |= 1 << OP_RAND;
+ if (rand_token == NULL)
+ rand_token = token;
+
+ try_rsa:
+ bad = false;
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_RSA_PKCS_KEY_PAIR_GEN);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_RSA_PKCS,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_SIGN) == 0) ||
+ ((mechInfo.flags & CKF_VERIFY) == 0)) {
+#if !defined(PK11_MD5_DISABLE) && !defined(PK11_RSA_PKCS_REPLACE)
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_MD5_RSA_PKCS);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA1_RSA_PKCS,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_SIGN) == 0) ||
+ ((mechInfo.flags & CKF_VERIFY) == 0)) {
+#ifndef PK11_RSA_PKCS_REPLACE
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_SHA1_RSA_PKCS);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_RSA_PKCS,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_SIGN) == 0) ||
+ ((mechInfo.flags & CKF_VERIFY) == 0)) {
+#ifndef PK11_RSA_PKCS_REPLACE
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_SHA256_RSA_PKCS);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_RSA_PKCS,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_SIGN) == 0) ||
+ ((mechInfo.flags & CKF_VERIFY) == 0)) {
+#ifndef PK11_RSA_PKCS_REPLACE
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_SHA512_RSA_PKCS);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_RSA_PKCS, &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_SIGN) == 0) ||
+ ((mechInfo.flags & CKF_VERIFY) == 0)) {
+#ifdef PK11_RSA_PKCS_REPLACE
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_RSA_PKCS);
+ }
+ if (bad)
+ goto try_dsa;
+ token->operations |= 1 << OP_RSA;
+ if (best_rsa_token == NULL)
+ best_rsa_token = token;
+
+ try_dsa:
+ bad = false;
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_PARAMETER_GEN,
+ &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_GENERATE) == 0)) {
+#ifndef PK11_DSA_PARAMETER_GEN_SKIP
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_DSA_PARAMETER_GEN);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_KEY_PAIR_GEN,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_DSA_PARAMETER_GEN);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_SHA1, &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_SIGN) == 0) ||
+ ((mechInfo.flags & CKF_VERIFY) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_DSA_SHA1);
+ }
+ if (bad)
+ goto try_dh;
+#ifndef PK11_DSA_DISABLE
+ token->operations |= 1 << OP_DSA;
+ if (best_dsa_token == NULL)
+ best_dsa_token = token;
+#endif
+
+ try_dh:
+ bad = false;
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_PARAMETER_GEN,
+ &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_GENERATE) == 0)) {
+ PK11_TRACEM(CKM_DH_PKCS_PARAMETER_GEN);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_KEY_PAIR_GEN,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
+#ifndef PK11_DH_PKCS_PARAMETER_GEN_SKIP
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_DH_PKCS_KEY_PAIR_GEN);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_DERIVE,
+ &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DERIVE) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_DH_PKCS_DERIVE);
+ }
+ if (bad)
+ goto try_digest;
+#ifndef PK11_DH_DISABLE
+ token->operations |= 1 << OP_DH;
+ if (best_dh_token == NULL)
+ best_dh_token = token;
+#endif
+
+ try_digest:
+ bad = false;
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
+#ifndef PK11_MD5_DISABLE
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_MD5);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_SHA_1);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_SHA224);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_SHA256);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA384, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_SHA384);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_SHA512);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_HMAC, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
+#if !defined(PK11_MD5_DISABLE) && !defined(PK11_MD5_HMAC_REPLACE)
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_MD5_HMAC);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1_HMAC, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
+#ifndef PK11_SHA_1_HMAC_REPLACE
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_SHA_1_HMAC);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224_HMAC, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
+#ifndef PK11_SHA224_HMAC_REPLACE
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_SHA224_HMAC);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_HMAC, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
+#ifndef PK11_SHA256_HMAC_REPLACE
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_SHA256_HMAC);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA384_HMAC, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
+#ifndef PK11_SHA384_HMAC_REPLACE
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_SHA384_HMAC);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_HMAC, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
+#ifndef PK11_SHA512_HMAC_REPLACE
+ bad = true;
+#endif
+ PK11_TRACEM(CKM_SHA512_HMAC);
+ }
+ if (!bad) {
+ token->operations |= 1 << OP_DIGEST;
+ if (digest_token == NULL)
+ digest_token = token;
+ }
+
+ /* ECDSA requires digest */
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_EC_KEY_PAIR_GEN,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_EC_KEY_PAIR_GEN);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_ECDSA, &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_SIGN) == 0) ||
+ ((mechInfo.flags & CKF_VERIFY) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_ECDSA);
+ }
+ if (bad)
+ goto try_gost;
+ token->operations |= 1 << OP_EC;
+ if (best_ec_token == NULL)
+ best_ec_token = token;
+
+ try_gost:
+ bad = false;
+ /* does GOST require digest too? */
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_GOSTR3411, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_GOSTR3411);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_GOSTR3410_KEY_PAIR_GEN,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_GOSTR3410_KEY_PAIR_GEN);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot,
+ CKM_GOSTR3410_WITH_GOSTR3411,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_SIGN) == 0) ||
+ ((mechInfo.flags & CKF_VERIFY) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_GOSTR3410_WITH_GOSTR3411);
+ }
+ if (bad)
+ goto try_eddsa;
+ token->operations |= 1 << OP_GOST;
+ if (best_gost_token == NULL)
+ best_gost_token = token;
+
+ try_eddsa:
+#if defined(CKM_EDDSA_KEY_PAIR_GEN) && defined(CKM_EDDSA) && defined(CKK_EDDSA)
+ bad = false;
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_EDDSA_KEY_PAIR_GEN,
+ &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_EDDSA_KEY_PAIR_GEN);
+ }
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_EDDSA, &mechInfo);
+ if ((rv != CKR_OK) ||
+ ((mechInfo.flags & CKF_SIGN) == 0) ||
+ ((mechInfo.flags & CKF_VERIFY) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_EDDSA);
+ }
+ if (bad)
+ goto try_aes;
+
+ try_aes:
+#endif
+ bad = false;
+ rv = pkcs_C_GetMechanismInfo(slot, CKM_AES_ECB, &mechInfo);
+ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_ENCRYPT) == 0)) {
+ bad = true;
+ PK11_TRACEM(CKM_AES_ECB);
+ }
+ if (bad)
+ continue;
+ token->operations |= 1 << OP_AES;
+ if (aes_token == NULL)
+ aes_token = token;
+ }
+
+ if (slotList != NULL) {
+ pk11_mem_put(slotList, sizeof(CK_SLOT_ID) * slotCount);
+ }
+}
+
+CK_SLOT_ID
+pk11_get_best_token(pk11_optype_t optype) {
+ pk11_token_t *token = NULL;
+
+ switch (optype) {
+ case OP_RAND:
+ token = rand_token;
+ break;
+ case OP_RSA:
+ token = best_rsa_token;
+ break;
+ case OP_DSA:
+ token = best_dsa_token;
+ break;
+ case OP_DH:
+ token = best_dh_token;
+ break;
+ case OP_DIGEST:
+ token = digest_token;
+ break;
+ case OP_EC:
+ token = best_ec_token;
+ break;
+ case OP_GOST:
+ token = best_gost_token;
+ break;
+ case OP_AES:
+ token = aes_token;
+ break;
+ default:
+ break;
+ }
+ if (token == NULL)
+ return (0);
+ return (token->slotid);
+}
+
+unsigned int
+pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) {
+ unsigned int bitcnt, i;
+ CK_BYTE top;
+
+ if (bytecnt == 0)
+ return (0);
+ bitcnt = bytecnt * 8;
+ for (i = 0; i < bytecnt; i++) {
+ top = data[i];
+ if (top == 0) {
+ bitcnt -= 8;
+ continue;
+ }
+ if (top & 0x80)
+ return (bitcnt);
+ if (top & 0x40)
+ return (bitcnt - 1);
+ if (top & 0x20)
+ return (bitcnt - 2);
+ if (top & 0x10)
+ return (bitcnt - 3);
+ if (top & 0x08)
+ return (bitcnt - 4);
+ if (top & 0x04)
+ return (bitcnt - 5);
+ if (top & 0x02)
+ return (bitcnt - 6);
+ if (top & 0x01)
+ return (bitcnt - 7);
+ break;
+ }
+ INSIST(0);
+}
+
+CK_ATTRIBUTE *
+pk11_attribute_first(const pk11_object_t *obj) {
+ return (obj->repr);
+}
+
+CK_ATTRIBUTE *
+pk11_attribute_next(const pk11_object_t *obj, CK_ATTRIBUTE *attr) {
+ CK_ATTRIBUTE *next;
+
+ next = attr + 1;
+ if ((next - obj->repr) >= obj->attrcnt)
+ return (NULL);
+ return (next);
+}
+
+CK_ATTRIBUTE *
+pk11_attribute_bytype(const pk11_object_t *obj, CK_ATTRIBUTE_TYPE type) {
+ CK_ATTRIBUTE *attr;
+
+ for(attr = pk11_attribute_first(obj);
+ attr != NULL;
+ attr = pk11_attribute_next(obj, attr))
+ if (attr->type == type)
+ return (attr);
+ return (NULL);
+}
+
+static char *
+percent_decode(char *x, size_t *len) {
+ char *p, *c;
+ unsigned char v;
+
+ INSIST(len != NULL);
+
+ for (p = c = x; p[0] != '\0'; p++, c++) {
+ switch (p[0]) {
+ case '%':
+ v = 0;
+ switch (p[1]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ v = (p[1] - '0') << 4;
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ v = (p[1] - 'A' + 10) << 4;
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ v = (p[1] - 'a' + 10) << 4;
+ break;
+ default:
+ return (NULL);
+ }
+ switch (p[2]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ v |= (p[2] - '0') & 0x0f;
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ v = (p[2] - 'A' + 10) & 0x0f;
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ v = (p[2] - 'a' + 10) & 0x0f;
+ break;
+ default:
+ return (NULL);
+ }
+ p += 2;
+ *c = (char) v;
+ (*len)++;
+ break;
+ default:
+ *c = *p;
+ (*len)++;
+ }
+ }
+ return (x);
+}
+
+static bool
+pk11strcmp(const char *x, size_t lenx, const char *y, size_t leny) {
+ char buf[32];
+
+ INSIST((leny == 32) || (leny == 16));
+
+ memset(buf, ' ', 32);
+ if (lenx > leny)
+ lenx = leny;
+ memmove(buf, x, lenx);
+ return (memcmp(buf, y, leny) == 0);
+}
+
+static CK_ATTRIBUTE *
+push_attribute(pk11_object_t *obj, isc_mem_t *mctx, size_t len) {
+ CK_ATTRIBUTE *old = obj->repr;
+ CK_ATTRIBUTE *attr;
+ CK_BYTE cnt = obj->attrcnt;
+
+ obj->repr = isc_mem_get(mctx, (cnt + 1) * sizeof(*attr));
+ if (obj->repr == NULL) {
+ obj->repr = old;
+ return (NULL);
+ }
+ memset(obj->repr, 0, (cnt + 1) * sizeof(*attr));
+ memmove(obj->repr, old, cnt * sizeof(*attr));
+ attr = obj->repr + cnt;
+ attr->ulValueLen = (CK_ULONG) len;
+ attr->pValue = isc_mem_get(mctx, len);
+ if (attr->pValue == NULL) {
+ memset(obj->repr, 0, (cnt + 1) * sizeof(*attr));
+ isc_mem_put(mctx, obj->repr, (cnt + 1) * sizeof(*attr));
+ obj->repr = old;
+ return (NULL);
+ }
+ memset(attr->pValue, 0, len);
+ if (old != NULL) {
+ memset(old, 0, cnt * sizeof(*attr));
+ isc_mem_put(mctx, old, cnt * sizeof(*attr));
+ }
+ obj->attrcnt++;
+ return (attr);
+}
+
+#define DST_RET(a) { ret = a; goto err; }
+
+isc_result_t
+pk11_parse_uri(pk11_object_t *obj, const char *label,
+ isc_mem_t *mctx, pk11_optype_t optype)
+{
+ CK_ATTRIBUTE *attr;
+ pk11_token_t *token = NULL;
+ char *uri, *p, *a, *na, *v;
+ size_t len, l;
+ FILE *stream = NULL;
+ char pin[PINLEN + 1];
+ bool gotpin = false;
+ isc_result_t ret;
+
+ /* get values to work on */
+ len = strlen(label) + 1;
+ uri = isc_mem_get(mctx, len);
+ if (uri == NULL)
+ return (ISC_R_NOMEMORY);
+ memmove(uri, label, len);
+
+ /* get the URI scheme */
+ p = strchr(uri, ':');
+ if (p == NULL)
+ DST_RET(PK11_R_NOPROVIDER);
+ *p++ = '\0';
+ if (strcmp(uri, "pkcs11") != 0)
+ DST_RET(PK11_R_NOPROVIDER);
+
+ /* get attributes */
+ for (na = p; na != NULL;) {
+ a = na;
+ p = strchr(a, ';');
+ if (p == NULL) {
+ /* last attribute */
+ na = NULL;
+ } else {
+ *p++ = '\0';
+ na = p;
+ }
+ p = strchr(a, '=');
+ if (p != NULL) {
+ *p++ = '\0';
+ v = p;
+ } else
+ v = a;
+ l = 0;
+ v = percent_decode(v, &l);
+ if (v == NULL)
+ DST_RET(PK11_R_NOPROVIDER);
+ if ((a == v) || (strcmp(a, "object") == 0)) {
+ /* object: CKA_LABEL */
+ attr = pk11_attribute_bytype(obj, CKA_LABEL);
+ if (attr != NULL)
+ DST_RET(PK11_R_NOPROVIDER);
+ attr = push_attribute(obj, mctx, l);
+ if (attr == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ attr->type = CKA_LABEL;
+ memmove(attr->pValue, v, l);
+ } else if (strcmp(a, "token") == 0) {
+ /* token: CK_TOKEN_INFO label */
+ if (token == NULL)
+ for (token = ISC_LIST_HEAD(tokens);
+ token != NULL;
+ token = ISC_LIST_NEXT(token, link))
+ if (pk11strcmp(v, l, token->name, 32))
+ break;
+ } else if (strcmp(a, "manufacturer") == 0) {
+ /* manufacturer: CK_TOKEN_INFO manufacturerID */
+ if (token == NULL)
+ for (token = ISC_LIST_HEAD(tokens);
+ token != NULL;
+ token = ISC_LIST_NEXT(token, link))
+ if (pk11strcmp(v, l, token->manuf, 32))
+ break;
+ } else if (strcmp(a, "serial") == 0) {
+ /* serial: CK_TOKEN_INFO serialNumber */
+ if (token == NULL)
+ for (token = ISC_LIST_HEAD(tokens);
+ token != NULL;
+ token = ISC_LIST_NEXT(token, link))
+ if (pk11strcmp(v, l, token->serial, 16))
+ break;
+ } else if (strcmp(a, "model") == 0) {
+ /* model: CK_TOKEN_INFO model */
+ if (token == NULL)
+ for (token = ISC_LIST_HEAD(tokens);
+ token != NULL;
+ token = ISC_LIST_NEXT(token, link))
+ if (pk11strcmp(v, l, token->model, 16))
+ break;
+ } else if (strcmp(a, "library-manufacturer") == 0) {
+ /* ignored */
+ } else if (strcmp(a, "library-description") == 0) {
+ /* ignored */
+ } else if (strcmp(a, "library-version") == 0) {
+ /* ignored */
+ } else if (strcmp(a, "object-type") == 0) {
+ /* object-type: CKA_CLASS */
+ /* only private makes sense */
+ if (strcmp(v, "private") != 0)
+ DST_RET(PK11_R_NOPROVIDER);
+ } else if (strcmp(a, "id") == 0) {
+ /* id: CKA_ID */
+ attr = pk11_attribute_bytype(obj, CKA_ID);
+ if (attr != NULL)
+ DST_RET(PK11_R_NOPROVIDER);
+ attr = push_attribute(obj, mctx, l);
+ if (attr == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ attr->type = CKA_ID;
+ memmove(attr->pValue, v, l);
+ } else if (strcmp(a, "pin-source") == 0) {
+ /* pin-source: PIN */
+ ret = isc_stdio_open(v, "r", &stream);
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+ memset(pin, 0, PINLEN + 1);
+ ret = isc_stdio_read(pin, 1, PINLEN + 1, stream, &l);
+ if ((ret != ISC_R_SUCCESS) && (ret != ISC_R_EOF))
+ goto err;
+ if (l > PINLEN)
+ DST_RET(ISC_R_RANGE);
+ ret = isc_stdio_close(stream);
+ stream = NULL;
+ if (ret != ISC_R_SUCCESS)
+ goto err;
+ gotpin = true;
+ } else
+ DST_RET(PK11_R_NOPROVIDER);
+ }
+
+ if ((pk11_attribute_bytype(obj, CKA_LABEL) == NULL) &&
+ (pk11_attribute_bytype(obj, CKA_ID) == NULL))
+ DST_RET(ISC_R_NOTFOUND);
+
+ if (token == NULL) {
+ if (optype == OP_RSA)
+ token = best_rsa_token;
+ else if (optype == OP_DSA)
+ token = best_dsa_token;
+ else if (optype == OP_DH)
+ token = best_dh_token;
+ else if (optype == OP_EC)
+ token = best_ec_token;
+ }
+ if (token == NULL)
+ DST_RET(ISC_R_NOTFOUND);
+ obj->slot = token->slotid;
+ if (gotpin) {
+ memmove(token->pin, pin, PINLEN + 1);
+ obj->reqlogon = true;
+ }
+
+ ret = ISC_R_SUCCESS;
+
+ err:
+ if (stream != NULL)
+ (void) isc_stdio_close(stream);
+ isc_mem_put(mctx, uri, len);
+ return (ret);
+}
+
+void
+pk11_error_fatalcheck(const char *file, int line,
+ const char *funcname, CK_RV rv)
+{
+ isc_error_fatal(file, line, "%s: Error = 0x%.8lX\n", funcname, rv);
+}
+
+void
+pk11_dump_tokens(void) {
+ pk11_token_t *token;
+ bool first;
+
+ printf("DEFAULTS\n");
+ printf("\trand_token=%p\n", rand_token);
+ printf("\tbest_rsa_token=%p\n", best_rsa_token);
+ printf("\tbest_dsa_token=%p\n", best_dsa_token);
+ printf("\tbest_dh_token=%p\n", best_dh_token);
+ printf("\tdigest_token=%p\n", digest_token);
+ printf("\tbest_ec_token=%p\n", best_ec_token);
+ printf("\tbest_gost_token=%p\n", best_gost_token);
+ printf("\taes_token=%p\n", aes_token);
+
+ for (token = ISC_LIST_HEAD(tokens);
+ token != NULL;
+ token = ISC_LIST_NEXT(token, link)) {
+ printf("\nTOKEN\n");
+ printf("\taddress=%p\n", token);
+ printf("\tslotID=%lu\n", token->slotid);
+ printf("\tlabel=%.32s\n", token->name);
+ printf("\tmanufacturerID=%.32s\n", token->manuf);
+ printf("\tmodel=%.16s\n", token->model);
+ printf("\tserialNumber=%.16s\n", token->serial);
+ printf("\tsupported operations=0x%x (", token->operations);
+ first = true;
+ if (token->operations & (1 << OP_RAND)) {
+ if (!first)
+ printf(",");
+ first = false;
+ printf("RAND");
+ }
+ if (token->operations & (1 << OP_RSA)) {
+ first = false;
+ printf("RSA");
+ }
+ if (token->operations & (1 << OP_DSA)) {
+ if (!first)
+ printf(",");
+ first = false;
+ printf("DSA");
+ }
+ if (token->operations & (1 << OP_DH)) {
+ if (!first)
+ printf(",");
+ first = false;
+ printf("DH");
+ }
+ if (token->operations & (1 << OP_DIGEST)) {
+ if (!first)
+ printf(",");
+ first = false;
+ printf("DIGEST");
+ }
+ if (token->operations & (1 << OP_EC)) {
+ if (!first)
+ printf(",");
+ first = false;
+ printf("EC");
+ }
+ if (token->operations & (1 << OP_AES)) {
+ if (!first)
+ printf(",");
+ first = false;
+ printf("AES");
+ }
+ printf(")\n");
+ }
+}
diff --git a/lib/isc/pk11_result.c b/lib/isc/pk11_result.c
new file mode 100644
index 0000000..33143f8
--- /dev/null
+++ b/lib/isc/pk11_result.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+#include <stddef.h>
+
+#include <isc/once.h>
+#include <isc/msgcat.h>
+#include <isc/util.h>
+
+#include <pk11/result.h>
+
+LIBISC_EXTERNAL_DATA isc_msgcat_t * pk11_msgcat = NULL;
+
+static isc_once_t msgcat_once = ISC_ONCE_INIT;
+
+static const char *text[PK11_R_NRESULTS] = {
+ "PKCS#11 initialization failed", /*%< 0 */
+ "no PKCS#11 provider", /*%< 1 */
+ "PKCS#11 provider has no random service", /*%< 2 */
+ "PKCS#11 provider has no digest service", /*%< 3 */
+ "PKCS#11 provider has no AES service", /*%< 4 */
+};
+
+static const char *ids[PK11_R_NRESULTS] = {
+ "PK11_R_INITFAILED",
+ "PK11_R_NOPROVIDER",
+ "PK11_R_NORANDOMSERVICE",
+ "PK11_R_NODIGESTSERVICE",
+ "PK11_R_NOAESSERVICE",
+};
+
+#define PK11_RESULT_RESULTSET 2
+
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+open_msgcat(void) {
+ isc_msgcat_open("libpk11.cat", &pk11_msgcat);
+}
+
+void
+pk11_initmsgcat(void) {
+
+ /*
+ * Initialize the PKCS#11 support's message catalog,
+ * pk11_msgcat, if it has not already been initialized.
+ */
+
+ RUNTIME_CHECK(isc_once_do(&msgcat_once, open_msgcat) == ISC_R_SUCCESS);
+}
+
+static void
+initialize_action(void) {
+ isc_result_t result;
+
+ result = isc_result_register(ISC_RESULTCLASS_PK11, PK11_R_NRESULTS,
+ text, pk11_msgcat, PK11_RESULT_RESULTSET);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_result_register() failed: %u", result);
+
+ result = isc_result_registerids(ISC_RESULTCLASS_PK11, PK11_R_NRESULTS,
+ ids, pk11_msgcat,
+ PK11_RESULT_RESULTSET);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_result_registerids() failed: %u", result);
+}
+
+static void
+initialize(void) {
+ pk11_initmsgcat();
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+const char *
+pk11_result_totext(isc_result_t result) {
+ initialize();
+
+ return (isc_result_totext(result));
+}
+
+void
+pk11_result_register(void) {
+ initialize();
+}
diff --git a/lib/isc/pool.c b/lib/isc/pool.c
new file mode 100644
index 0000000..a445d8b
--- /dev/null
+++ b/lib/isc/pool.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <isc/mem.h>
+#include <isc/random.h>
+#include <isc/pool.h>
+#include <isc/util.h>
+
+/***
+ *** Types.
+ ***/
+
+struct isc_pool {
+ isc_mem_t * mctx;
+ unsigned int count;
+ isc_pooldeallocator_t free;
+ isc_poolinitializer_t init;
+ void * initarg;
+ void ** pool;
+};
+
+/***
+ *** Functions.
+ ***/
+
+static isc_result_t
+alloc_pool(isc_mem_t *mctx, unsigned int count, isc_pool_t **poolp) {
+ isc_pool_t *pool;
+
+ pool = isc_mem_get(mctx, sizeof(*pool));
+ if (pool == NULL)
+ return (ISC_R_NOMEMORY);
+ pool->count = count;
+ pool->free = NULL;
+ pool->init = NULL;
+ pool->initarg = NULL;
+ pool->mctx = NULL;
+ isc_mem_attach(mctx, &pool->mctx);
+ pool->pool = isc_mem_get(mctx, count * sizeof(void *));
+ if (pool->pool == NULL) {
+ isc_mem_put(mctx, pool, sizeof(*pool));
+ return (ISC_R_NOMEMORY);
+ }
+ memset(pool->pool, 0, count * sizeof(void *));
+
+ *poolp = pool;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_pool_create(isc_mem_t *mctx, unsigned int count,
+ isc_pooldeallocator_t release,
+ isc_poolinitializer_t init, void *initarg,
+ isc_pool_t **poolp)
+{
+ isc_pool_t *pool = NULL;
+ isc_result_t result;
+ unsigned int i;
+
+ INSIST(count > 0);
+
+ /* Allocate the pool structure */
+ result = alloc_pool(mctx, count, &pool);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ pool->free = release;
+ pool->init = init;
+ pool->initarg = initarg;
+
+ /* Populate the pool */
+ for (i = 0; i < count; i++) {
+ result = init(&pool->pool[i], initarg);
+ if (result != ISC_R_SUCCESS) {
+ isc_pool_destroy(&pool);
+ return (result);
+ }
+ }
+
+ *poolp = pool;
+ return (ISC_R_SUCCESS);
+}
+
+void *
+isc_pool_get(isc_pool_t *pool) {
+ uint32_t i;
+ isc_random_get(&i);
+ return (pool->pool[i % pool->count]);
+}
+
+int
+isc_pool_count(isc_pool_t *pool) {
+ REQUIRE(pool != NULL);
+ return (pool->count);
+}
+
+isc_result_t
+isc_pool_expand(isc_pool_t **sourcep, unsigned int count,
+ isc_pool_t **targetp)
+{
+ isc_result_t result;
+ isc_pool_t *pool;
+
+ REQUIRE(sourcep != NULL && *sourcep != NULL);
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ pool = *sourcep;
+ if (count > pool->count) {
+ isc_pool_t *newpool = NULL;
+ unsigned int i;
+
+ /* Allocate a new pool structure */
+ result = alloc_pool(pool->mctx, count, &newpool);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ newpool->free = pool->free;
+ newpool->init = pool->init;
+ newpool->initarg = pool->initarg;
+
+ /* Copy over the objects from the old pool */
+ for (i = 0; i < pool->count; i++) {
+ newpool->pool[i] = pool->pool[i];
+ pool->pool[i] = NULL;
+ }
+
+ /* Populate the new entries */
+ for (i = pool->count; i < count; i++) {
+ result = pool->init(&newpool->pool[i], pool->initarg);
+ if (result != ISC_R_SUCCESS) {
+ isc_pool_destroy(&pool);
+ return (result);
+ }
+ }
+
+ isc_pool_destroy(&pool);
+ pool = newpool;
+ }
+
+ *sourcep = NULL;
+ *targetp = pool;
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_pool_destroy(isc_pool_t **poolp) {
+ unsigned int i;
+ isc_pool_t *pool = *poolp;
+ for (i = 0; i < pool->count; i++) {
+ if (pool->free != NULL && pool->pool[i] != NULL)
+ pool->free(&pool->pool[i]);
+ }
+ isc_mem_put(pool->mctx, pool->pool, pool->count * sizeof(void *));
+ isc_mem_putanddetach(&pool->mctx, pool, sizeof(*pool));
+ *poolp = NULL;
+}
diff --git a/lib/isc/portset.c b/lib/isc/portset.c
new file mode 100644
index 0000000..b3af46d
--- /dev/null
+++ b/lib/isc/portset.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/mem.h>
+#include <isc/portset.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#define ISC_PORTSET_BUFSIZE (65536 / (sizeof(uint32_t) * 8))
+
+/*%
+ * Internal representation of portset. It's an array of 32-bit integers, each
+ * bit corresponding to a single port in the ascending order. For example,
+ * the second most significant bit of buf[0] corresponds to port 1.
+ */
+struct isc_portset {
+ unsigned int nports; /*%< number of ports in the set */
+ uint32_t buf[ISC_PORTSET_BUFSIZE];
+};
+
+static inline bool
+portset_isset(isc_portset_t *portset, in_port_t port) {
+ return (portset->buf[port >> 5] & ((uint32_t)1 << (port & 31)));
+}
+
+static inline void
+portset_add(isc_portset_t *portset, in_port_t port) {
+ if (!portset_isset(portset, port)) {
+ portset->nports++;
+ portset->buf[port >> 5] |= ((uint32_t)1 << (port & 31));
+ }
+}
+
+static inline void
+portset_remove(isc_portset_t *portset, in_port_t port) {
+ if (portset_isset(portset, port)) {
+ portset->nports--;
+ portset->buf[port >> 5] &= ~((uint32_t)1 << (port & 31));
+ }
+}
+
+isc_result_t
+isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp) {
+ isc_portset_t *portset;
+
+ REQUIRE(portsetp != NULL && *portsetp == NULL);
+
+ portset = isc_mem_get(mctx, sizeof(*portset));
+ if (portset == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /* Make the set 'empty' by default */
+ memset(portset, 0, sizeof(*portset));
+ *portsetp = portset;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp) {
+ isc_portset_t *portset;
+
+ REQUIRE(portsetp != NULL);
+ portset = *portsetp;
+
+ isc_mem_put(mctx, portset, sizeof(*portset));
+}
+
+bool
+isc_portset_isset(isc_portset_t *portset, in_port_t port) {
+ REQUIRE(portset != NULL);
+
+ return (portset_isset(portset, port));
+}
+
+unsigned int
+isc_portset_nports(isc_portset_t *portset) {
+ REQUIRE(portset != NULL);
+
+ return (portset->nports);
+}
+
+void
+isc_portset_add(isc_portset_t *portset, in_port_t port) {
+ REQUIRE(portset != NULL);
+
+ portset_add(portset, port);
+}
+
+void
+isc_portset_remove(isc_portset_t *portset, in_port_t port) {
+ portset_remove(portset, port);
+}
+
+void
+isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo,
+ in_port_t port_hi)
+{
+ in_port_t p;
+
+ REQUIRE(portset != NULL);
+ REQUIRE(port_lo <= port_hi);
+
+ p = port_lo;
+ do {
+ portset_add(portset, p);
+ } while (p++ < port_hi);
+}
+
+void
+isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo,
+ in_port_t port_hi)
+{
+ in_port_t p;
+
+ REQUIRE(portset != NULL);
+ REQUIRE(port_lo <= port_hi);
+
+ p = port_lo;
+ do {
+ portset_remove(portset, p);
+ } while (p++ < port_hi);
+}
diff --git a/lib/isc/powerpc/Makefile.in b/lib/isc/powerpc/Makefile.in
new file mode 100644
index 0000000..419cf9f
--- /dev/null
+++ b/lib/isc/powerpc/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/powerpc/include/Makefile.in b/lib/isc/powerpc/include/Makefile.in
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/lib/isc/powerpc/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/powerpc/include/isc/Makefile.in b/lib/isc/powerpc/include/isc/Makefile.in
new file mode 100644
index 0000000..97b6b41
--- /dev/null
+++ b/lib/isc/powerpc/include/isc/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
diff --git a/lib/isc/powerpc/include/isc/atomic.h b/lib/isc/powerpc/include/isc/atomic.h
new file mode 100644
index 0000000..9899934
--- /dev/null
+++ b/lib/isc/powerpc/include/isc/atomic.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <inttypes.h>
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+/*!\file
+ * static inline int32_t
+ * isc_atomic_xadd(int32_t *p, int32_t val);
+ *
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ *
+ * static inline void
+ * isc_atomic_store(void *p, int32_t val);
+ *
+ * This routine atomically stores the value 'val' in 'p'.
+ *
+ * static inline int32_t
+ * isc_atomic_cmpxchg(int32_t *p, int32_t cmpval, int32_t val);
+ *
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+
+#if defined(_AIX)
+
+#include <sys/atomic_op.h>
+
+#define isc_atomic_store(p, v) _clear_lock(p, v)
+
+#ifdef __GNUC__
+static inline int32_t
+#else
+static int32_t
+#endif
+isc_atomic_xadd(int32_t *p, int32_t val) {
+ int ret;
+
+#ifdef __GNUC__
+ asm("ics");
+#else
+ __isync();
+#endif
+
+ ret = fetch_and_add((atomic_p)p, (int)val);
+
+#ifdef __GNUC__
+ asm("ics");
+#else
+ __isync();
+#endif
+
+ return (ret);
+}
+
+#ifdef __GNUC__
+static inline int
+#else
+static int
+#endif
+isc_atomic_cmpxchg(atomic_p p, int old, int replacement) {
+ int orig = old;
+
+#ifdef __GNUC__
+ asm("ics");
+#else
+ __isync();
+#endif
+ if (compare_and_swap(p, &orig, replacement))
+ orig = old;
+
+#ifdef __GNUC__
+ asm("ics");
+#else
+ __isync();
+#endif
+
+ return (orig);
+}
+
+#elif defined(ISC_PLATFORM_USEGCCASM) || defined(ISC_PLATFORM_USEMACASM)
+static inline int32_t
+isc_atomic_xadd(int32_t *p, int32_t val) {
+ int32_t orig;
+
+ __asm__ volatile (
+#ifdef ISC_PLATFORM_USEMACASM
+ "1:"
+ "lwarx r6, 0, %1\n"
+ "mr %0, r6\n"
+ "add r6, r6, %2\n"
+ "stwcx. r6, 0, %1\n"
+ "bne- 1b\n"
+ "sync"
+#else
+ "1:"
+ "lwarx 6, 0, %1\n"
+ "mr %0, 6\n"
+ "add 6, 6, %2\n"
+ "stwcx. 6, 0, %1\n"
+ "bne- 1b\n"
+ "sync"
+#endif
+ : "=&r"(orig)
+ : "r"(p), "r"(val)
+ : "r6", "memory"
+ );
+
+ return (orig);
+}
+
+static inline void
+isc_atomic_store(void *p, int32_t val) {
+ __asm__ volatile (
+#ifdef ISC_PLATFORM_USEMACASM
+ "1:"
+ "lwarx r6, 0, %0\n"
+ "lwz r6, %1\n"
+ "stwcx. r6, 0, %0\n"
+ "bne- 1b\n"
+ "sync"
+#else
+ "1:"
+ "lwarx 6, 0, %0\n"
+ "lwz 6, %1\n"
+ "stwcx. 6, 0, %0\n"
+ "bne- 1b\n"
+ "sync"
+#endif
+ :
+ : "r"(p), "m"(val)
+ : "r6", "memory"
+ );
+}
+
+static inline int32_t
+isc_atomic_cmpxchg(int32_t *p, int32_t cmpval, int32_t val) {
+ int32_t orig;
+
+ __asm__ volatile (
+#ifdef ISC_PLATFORM_USEMACASM
+ "1:"
+ "lwarx r6, 0, %1\n"
+ "mr %0,r6\n"
+ "cmpw r6, %2\n"
+ "bne 2f\n"
+ "mr r6, %3\n"
+ "stwcx. r6, 0, %1\n"
+ "bne- 1b\n"
+ "2:\n"
+ "sync"
+#else
+ "1:"
+ "lwarx 6, 0, %1\n"
+ "mr %0,6\n"
+ "cmpw 6, %2\n"
+ "bne 2f\n"
+ "mr 6, %3\n"
+ "stwcx. 6, 0, %1\n"
+ "bne- 1b\n"
+ "2:\n"
+ "sync"
+#endif
+ : "=&r" (orig)
+ : "r"(p), "r"(cmpval), "r"(val)
+ : "r6", "memory"
+ );
+
+ return (orig);
+}
+
+#else
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/print.c b/lib/isc/print.c
new file mode 100644
index 0000000..d4d4880
--- /dev/null
+++ b/lib/isc/print.c
@@ -0,0 +1,706 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h> /* for sprintf() */
+#include <string.h> /* for strlen() */
+#include <assert.h> /* for assert() */
+
+#define ISC__PRINT_SOURCE /* Used to get the isc_print_* prototypes. */
+
+#include <isc/assertions.h>
+#include <isc/msgs.h>
+#include <isc/print.h>
+#include <isc/stdlib.h>
+#include <isc/util.h>
+
+/*
+ * We use the system's sprintf so we undef it here.
+ */
+#undef sprintf
+
+static int
+isc__print_printf(void (*emit)(char, void *), void *arg,
+ const char *format, va_list ap);
+
+static void
+file_emit(char c, void *arg) {
+ FILE *fp = arg;
+ int i = c & 0xff;
+
+ putc(i, fp);
+}
+
+#if 0
+static int
+isc_print_vfprintf(FILE *fp, const char *format, va_list ap) {
+ assert(fp != NULL);
+ assert(format != NULL);
+
+ return (isc__print_printf(file_emit, fp, format, ap));
+}
+#endif
+
+int
+isc_print_printf(const char *format, ...) {
+ va_list ap;
+ int n;
+
+ assert(format != NULL);
+
+ va_start(ap, format);
+ n = isc__print_printf(file_emit, stdout, format, ap);
+ va_end(ap);
+ return (n);
+}
+
+int
+isc_print_fprintf(FILE *fp, const char *format, ...) {
+ va_list ap;
+ int n;
+
+ assert(fp != NULL);
+ assert(format != NULL);
+
+ va_start(ap, format);
+ n = isc__print_printf(file_emit, fp, format, ap);
+ va_end(ap);
+ return (n);
+}
+
+static void
+nocheck_emit(char c, void *arg) {
+ struct { char *str; } *a = arg;
+
+ *(a->str)++ = c;
+}
+
+int
+isc_print_sprintf(char *str, const char *format, ...) {
+ struct { char *str; } arg;
+ int n;
+ va_list ap;
+
+ arg.str = str;
+
+ va_start(ap, format);
+ n = isc__print_printf(nocheck_emit, &arg, format, ap);
+ va_end(ap);
+ return (n);
+}
+
+/*!
+ * Return length of string that would have been written if not truncated.
+ */
+
+int
+isc_print_snprintf(char *str, size_t size, const char *format, ...) {
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = isc_print_vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return (ret);
+
+}
+
+/*!
+ * Return length of string that would have been written if not truncated.
+ */
+
+static void
+string_emit(char c, void *arg) {
+ struct { char *str; size_t size; } *p = arg;
+
+ if (p->size > 0U) {
+ *(p->str)++ = c;
+ p->size--;
+ }
+}
+
+int
+isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
+ struct { char *str; size_t size; } arg;
+ int n;
+
+ assert(str != NULL);
+ assert(format != NULL);
+
+ arg.str = str;
+ arg.size = size;
+
+ n = isc__print_printf(string_emit, &arg, format, ap);
+ if (arg.size > 0U)
+ *arg.str = '\0';
+ return (n);
+}
+
+static int
+isc__print_printf(void (*emit)(char, void *), void *arg,
+ const char *format, va_list ap)
+{
+ int h;
+ int l;
+ int z;
+ int q;
+ int alt;
+ int zero;
+ int left;
+ int plus;
+ int space;
+ int neg;
+ int64_t tmpi;
+ uint64_t tmpui;
+ unsigned long width;
+ unsigned long precision;
+ unsigned int length;
+ char buf[1024];
+ char c;
+ void *v;
+ const char *cp;
+ const char *head;
+ int count = 0;
+ int pad;
+ int zeropad;
+ int dot;
+ double dbl;
+ bool precision_set;
+#ifdef HAVE_LONG_DOUBLE
+ long double ldbl;
+#endif
+ char fmt[32];
+
+ assert(emit != NULL);
+ assert(arg != NULL);
+ assert(format != NULL);
+
+ while (*format != '\0') {
+ if (*format != '%') {
+ emit(*format++, arg);
+ count++;
+ continue;
+ }
+ format++;
+
+ /*
+ * Reset flags.
+ */
+ dot = neg = space = plus = left = zero = alt = h = l = q = z = 0;
+ width = precision = 0;
+ head = "";
+ pad = zeropad = 0;
+ precision_set = false;
+
+ do {
+ if (*format == '#') {
+ alt = 1;
+ format++;
+ } else if (*format == '-') {
+ left = 1;
+ zero = 0;
+ format++;
+ } else if (*format == ' ') {
+ if (!plus)
+ space = 1;
+ format++;
+ } else if (*format == '+') {
+ plus = 1;
+ space = 0;
+ format++;
+ } else if (*format == '0') {
+ if (!left)
+ zero = 1;
+ format++;
+ } else
+ break;
+ } while (1);
+
+ /*
+ * Width.
+ */
+ if (*format == '*') {
+ width = va_arg(ap, int);
+ format++;
+ } else if (isdigit((unsigned char)*format)) {
+ char *e;
+ width = strtoul(format, &e, 10);
+ format = e;
+ }
+
+ /*
+ * Precision.
+ */
+ if (*format == '.') {
+ format++;
+ dot = 1;
+ if (*format == '*') {
+ precision = va_arg(ap, int);
+ precision_set = true;
+ format++;
+ } else if (isdigit((unsigned char)*format)) {
+ char *e;
+ precision = strtoul(format, &e, 10);
+ precision_set = true;
+ format = e;
+ }
+ }
+
+ switch (*format) {
+ case '\0':
+ continue;
+ case '%':
+ emit(*format, arg);
+ count++;
+ break;
+ case 'q':
+ q = 1;
+ format++;
+ goto doint;
+ case 'h':
+ h = 1;
+ format++;
+ goto doint;
+ case 'l':
+ l = 1;
+ format++;
+ if (*format == 'l') {
+ q = 1;
+ format++;
+ }
+ goto doint;
+ case 'z':
+ z = 1;
+ format++;
+ goto doint;
+#ifdef WIN32
+ case 'I':
+ /* Windows has I64 as a modifier for a quad. */
+ if (format[1] == '6' && format[2] == '4') {
+ q = 1;
+ format += 3;
+ goto doint;
+ }
+ continue;
+#endif
+ case 'n':
+ case 'i':
+ case 'd':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ doint:
+ if (precision != 0U)
+ zero = 0;
+ switch (*format) {
+ case 'n':
+ if (h) {
+ short int *p;
+ p = va_arg(ap, short *);
+ assert(p != NULL);
+ *p = count;
+ } else if (l) {
+ long int *p;
+ p = va_arg(ap, long *);
+ assert(p != NULL);
+ *p = count;
+ } else if (z) {
+ size_t *p;
+ p = va_arg(ap, size_t *);
+ assert(p != NULL);
+ *p = count;
+ } else {
+ int *p;
+ p = va_arg(ap, int *);
+ assert(p != NULL);
+ *p = count;
+ }
+ break;
+ case 'i':
+ case 'd':
+ if (q)
+ tmpi = va_arg(ap, int64_t);
+ else if (l)
+ tmpi = va_arg(ap, long int);
+ else if (z)
+ tmpi = va_arg(ap, ssize_t);
+ else
+ tmpi = va_arg(ap, int);
+ if (tmpi < 0) {
+ head = "-";
+ tmpui = -tmpi;
+ } else {
+ if (plus)
+ head = "+";
+ else if (space)
+ head = " ";
+ else
+ head = "";
+ tmpui = tmpi;
+ }
+ if (tmpui <= 0xffffffffU)
+ sprintf(buf, "%lu",
+ (unsigned long)tmpui);
+ else {
+ unsigned long mid;
+ unsigned long lo;
+ unsigned long hi;
+ lo = tmpui % 1000000000;
+ tmpui /= 1000000000;
+ mid = tmpui % 1000000000;
+ hi = tmpui / 1000000000;
+ if (hi != 0U) {
+ sprintf(buf, "%lu", hi);
+ sprintf(buf + strlen(buf),
+ "%09lu", mid);
+ } else
+ sprintf(buf, "%lu", mid);
+ sprintf(buf + strlen(buf), "%09lu",
+ lo);
+ }
+ goto printint;
+ case 'o':
+ if (q)
+ tmpui = va_arg(ap, uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, long int);
+ else if (z)
+ tmpui = va_arg(ap, size_t);
+ else
+ tmpui = va_arg(ap, int);
+ if (tmpui <= 0xffffffffU)
+ sprintf(buf, alt ? "%#lo" : "%lo",
+ (unsigned long)tmpui);
+ else {
+ unsigned long mid;
+ unsigned long lo;
+ unsigned long hi;
+ lo = tmpui % 010000000000;
+ tmpui /= 010000000000;
+ mid = tmpui % 010000000000;
+ hi = tmpui / 010000000000;
+ if (hi != 0U) {
+ sprintf(buf,
+ alt ? "%#lo" : "%lo",
+ hi);
+ sprintf(buf + strlen(buf),
+ "%09lo", mid);
+ } else
+ sprintf(buf,
+ alt ? "%#lo" : "%lo",
+ mid);
+ sprintf(buf + strlen(buf), "%09lo", lo);
+ }
+ goto printint;
+ case 'u':
+ if (q)
+ tmpui = va_arg(ap, uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else if (z)
+ tmpui = va_arg(ap, size_t);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ if (tmpui <= 0xffffffffU)
+ sprintf(buf, "%lu",
+ (unsigned long)tmpui);
+ else {
+ unsigned long mid;
+ unsigned long lo;
+ unsigned long hi;
+ lo = tmpui % 1000000000;
+ tmpui /= 1000000000;
+ mid = tmpui % 1000000000;
+ hi = tmpui / 1000000000;
+ if (hi != 0U) {
+ sprintf(buf, "%lu", hi);
+ sprintf(buf + strlen(buf),
+ "%09lu", mid);
+ } else
+ sprintf(buf, "%lu", mid);
+ sprintf(buf + strlen(buf), "%09lu",
+ lo);
+ }
+ goto printint;
+ case 'x':
+ if (q)
+ tmpui = va_arg(ap, uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else if (z)
+ tmpui = va_arg(ap, size_t);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ if (alt) {
+ head = "0x";
+ if (precision > 2U)
+ precision -= 2;
+ }
+ if (tmpui <= 0xffffffffU)
+ sprintf(buf, "%lx",
+ (unsigned long)tmpui);
+ else {
+ unsigned long hi = tmpui>>32;
+ unsigned long lo = tmpui & 0xffffffff;
+ sprintf(buf, "%lx", hi);
+ sprintf(buf + strlen(buf), "%08lx", lo);
+ }
+ goto printint;
+ case 'X':
+ if (q)
+ tmpui = va_arg(ap, uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else if (z)
+ tmpui = va_arg(ap, size_t);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ if (alt) {
+ head = "0X";
+ if (precision > 2U)
+ precision -= 2;
+ }
+ if (tmpui <= 0xffffffffU)
+ sprintf(buf, "%lX",
+ (unsigned long)tmpui);
+ else {
+ unsigned long hi = tmpui>>32;
+ unsigned long lo = tmpui & 0xffffffff;
+ sprintf(buf, "%lX", hi);
+ sprintf(buf + strlen(buf), "%08lX", lo);
+ }
+ goto printint;
+ printint:
+ if (precision_set || width != 0U) {
+ length = strlen(buf);
+ if (length < precision)
+ zeropad = precision - length;
+ else if (length < width && zero)
+ zeropad = width - length;
+ if (width != 0U) {
+ pad = width - length -
+ zeropad - strlen(head);
+ if (pad < 0)
+ pad = 0;
+ }
+ }
+ count += strlen(head) + strlen(buf) + pad +
+ zeropad;
+ if (!left) {
+ while (pad > 0) {
+ emit(' ', arg);
+ pad--;
+ }
+ }
+ cp = head;
+ while (*cp != '\0')
+ emit(*cp++, arg);
+ while (zeropad > 0) {
+ emit('0', arg);
+ zeropad--;
+ }
+ cp = buf;
+ while (*cp != '\0')
+ emit(*cp++, arg);
+ while (pad > 0) {
+ emit(' ', arg);
+ pad--;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 's':
+ cp = va_arg(ap, char *);
+
+ if (precision_set) {
+ /*
+ * cp need not be NULL terminated.
+ */
+ const char *tp;
+ unsigned long n;
+
+ if (precision != 0U)
+ assert(cp != NULL);
+ n = precision;
+ tp = cp;
+ while (n != 0U && *tp != '\0')
+ n--, tp++;
+ length = precision - n;
+ } else {
+ assert(cp != NULL);
+ length = strlen(cp);
+ }
+ if (width != 0U) {
+ pad = width - length;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += pad + length;
+ if (!left)
+ while (pad > 0) {
+ emit(' ', arg);
+ pad--;
+ }
+ if (precision_set)
+ while (precision > 0U && *cp != '\0') {
+ emit(*cp++, arg);
+ precision--;
+ }
+ else
+ while (*cp != '\0')
+ emit(*cp++, arg);
+ while (pad > 0) {
+ emit(' ', arg);
+ pad--;
+ }
+ break;
+ case 'c':
+ c = va_arg(ap, int);
+ if (width > 0U) {
+ count += width;
+ width--;
+ if (left)
+ emit(c, arg);
+ while (width-- > 0U)
+ emit(' ', arg);
+ if (!left)
+ emit(c, arg);
+ } else {
+ count++;
+ emit(c, arg);
+ }
+ break;
+ case 'p':
+ v = va_arg(ap, void *);
+ sprintf(buf, "%p", v);
+ length = strlen(buf);
+ if (precision > length)
+ zeropad = precision - length;
+ if (width > 0U) {
+ pad = width - length - zeropad;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += length + pad + zeropad;
+ if (!left)
+ while (pad > 0) {
+ emit(' ', arg);
+ pad--;
+ }
+ cp = buf;
+ if (zeropad > 0 && buf[0] == '0' &&
+ (buf[1] == 'x' || buf[1] == 'X')) {
+ emit(*cp++, arg);
+ emit(*cp++, arg);
+ while (zeropad > 0) {
+ emit('0', arg);
+ zeropad--;
+ }
+ }
+ while (*cp != '\0')
+ emit(*cp++, arg);
+ while (pad > 0) {
+ emit(' ', arg);
+ pad--;
+ }
+ break;
+ case 'D': /*deprecated*/
+ assert("use %ld instead of %D" == NULL);
+ case 'O': /*deprecated*/
+ assert("use %lo instead of %O" == NULL);
+ case 'U': /*deprecated*/
+ assert("use %lu instead of %U" == NULL);
+
+ case 'L':
+#ifdef HAVE_LONG_DOUBLE
+ l = 1;
+#else
+ assert("long doubles are not supported" == NULL);
+#endif
+ /* FALLTHROUGH */
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (!dot)
+ precision = 6;
+ /*
+ * IEEE floating point.
+ * MIN 2.2250738585072014E-308
+ * MAX 1.7976931348623157E+308
+ * VAX floating point has a smaller range than IEEE.
+ *
+ * precisions > 324 don't make much sense.
+ * if we cap the precision at 512 we will not
+ * overflow buf.
+ */
+ if (precision > 512U)
+ precision = 512;
+ sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
+ plus ? "+" : space ? " " : "",
+ precision, l ? "L" : "", *format);
+ switch (*format) {
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+#ifdef HAVE_LONG_DOUBLE
+ if (l) {
+ ldbl = va_arg(ap, long double);
+ sprintf(buf, fmt, ldbl);
+ } else
+#endif
+ {
+ dbl = va_arg(ap, double);
+ sprintf(buf, fmt, dbl);
+ }
+ length = strlen(buf);
+ if (width > 0U) {
+ pad = width - length;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += length + pad;
+ if (!left)
+ while (pad > 0) {
+ emit(' ', arg);
+ pad--;
+ }
+ cp = buf;
+ while (*cp != '\0')
+ emit(*cp++, arg);
+ while (pad > 0) {
+ emit(' ', arg);
+ pad--;
+ }
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ format++;
+ }
+ return (count);
+}
diff --git a/lib/isc/pthreads/Makefile.in b/lib/isc/pthreads/Makefile.in
new file mode 100644
index 0000000..af4fd6e
--- /dev/null
+++ b/lib/isc/pthreads/Makefile.in
@@ -0,0 +1,30 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+CINCLUDES = -I${srcdir}/include \
+ -I${srcdir}/../unix/include \
+ -I../include \
+ -I${srcdir}/../include \
+ -I${srcdir}/..
+
+CDEFINES =
+CWARNINGS =
+
+OBJS = condition.@O@ mutex.@O@ thread.@O@
+
+SRCS = condition.c mutex.c thread.c
+
+SUBDIRS = include
+TARGETS = ${OBJS}
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/pthreads/condition.c b/lib/isc/pthreads/condition.c
new file mode 100644
index 0000000..a7f1928
--- /dev/null
+++ b/lib/isc/pthreads/condition.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+
+#include <isc/condition.h>
+#include <isc/msgs.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *c, isc_mutex_t *m, isc_time_t *t) {
+ int presult;
+ isc_result_t result;
+ struct timespec ts;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(c != NULL && m != NULL && t != NULL);
+
+ /*
+ * POSIX defines a timespec's tv_sec as time_t.
+ */
+ result = isc_time_secondsastimet(t, &ts.tv_sec);
+
+ /*
+ * If we have a range error ts.tv_sec is most probably a signed
+ * 32 bit value. Set ts.tv_sec to INT_MAX. This is a kludge.
+ */
+ if (result == ISC_R_RANGE)
+ ts.tv_sec = INT_MAX;
+ else if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*!
+ * POSIX defines a timespec's tv_nsec as long. isc_time_nanoseconds
+ * ensures its return value is < 1 billion, which will fit in a long.
+ */
+ ts.tv_nsec = (long)isc_time_nanoseconds(t);
+
+ do {
+#if ISC_MUTEX_PROFILE
+ presult = pthread_cond_timedwait(c, &m->mutex, &ts);
+#else
+ presult = pthread_cond_timedwait(c, m, &ts);
+#endif
+ if (presult == 0)
+ return (ISC_R_SUCCESS);
+ if (presult == ETIMEDOUT)
+ return (ISC_R_TIMEDOUT);
+ } while (presult == EINTR);
+
+ isc__strerror(presult, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "pthread_cond_timedwait() %s %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_RETURNED, "returned"),
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+}
diff --git a/lib/isc/pthreads/include/Makefile.in b/lib/isc/pthreads/include/Makefile.in
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/lib/isc/pthreads/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/pthreads/include/isc/Makefile.in b/lib/isc/pthreads/include/isc/Makefile.in
new file mode 100644
index 0000000..185534f
--- /dev/null
+++ b/lib/isc/pthreads/include/isc/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = condition.h mutex.h once.h thread.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
diff --git a/lib/isc/pthreads/include/isc/condition.h b/lib/isc/pthreads/include/isc/condition.h
new file mode 100644
index 0000000..28338c7
--- /dev/null
+++ b/lib/isc/pthreads/include/isc/condition.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_CONDITION_H
+#define ISC_CONDITION_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/result.h>
+#include <isc/types.h>
+
+typedef pthread_cond_t isc_condition_t;
+
+#define isc_condition_init(cp) \
+ ((pthread_cond_init((cp), NULL) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#if ISC_MUTEX_PROFILE
+#define isc_condition_wait(cp, mp) \
+ ((pthread_cond_wait((cp), &((mp)->mutex)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#else
+#define isc_condition_wait(cp, mp) \
+ ((pthread_cond_wait((cp), (mp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#define isc_condition_signal(cp) \
+ ((pthread_cond_signal((cp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_condition_broadcast(cp) \
+ ((pthread_cond_broadcast((cp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_condition_destroy(cp) \
+ ((pthread_cond_destroy((cp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_CONDITION_H */
diff --git a/lib/isc/pthreads/include/isc/mutex.h b/lib/isc/pthreads/include/isc/mutex.h
new file mode 100644
index 0000000..6c34a69
--- /dev/null
+++ b/lib/isc/pthreads/include/isc/mutex.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_MUTEX_H
+#define ISC_MUTEX_H 1
+
+/*! \file */
+
+#include <pthread.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/result.h> /* for ISC_R_ codes */
+
+ISC_LANG_BEGINDECLS
+
+/*!
+ * Supply mutex attributes that enable deadlock detection
+ * (helpful when debugging). This is system dependent and
+ * currently only supported on NetBSD.
+ */
+#if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
+extern pthread_mutexattr_t isc__mutex_attrs;
+#define ISC__MUTEX_ATTRS &isc__mutex_attrs
+#else
+#define ISC__MUTEX_ATTRS NULL
+#endif
+
+/* XXX We could do fancier error handling... */
+
+/*!
+ * Define ISC_MUTEX_PROFILE to turn on profiling of mutexes by line. When
+ * enabled, isc_mutex_stats() can be used to print a table showing the
+ * number of times each type of mutex was locked and the amount of time
+ * waiting to obtain the lock.
+ */
+#ifndef ISC_MUTEX_PROFILE
+#define ISC_MUTEX_PROFILE 0
+#endif
+
+#if ISC_MUTEX_PROFILE
+typedef struct isc_mutexstats isc_mutexstats_t;
+
+typedef struct {
+ pthread_mutex_t mutex; /*%< The actual mutex. */
+ isc_mutexstats_t * stats; /*%< Mutex statistics. */
+} isc_mutex_t;
+#else
+typedef pthread_mutex_t isc_mutex_t;
+#endif
+
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_init(mp) \
+ isc_mutex_init_profile((mp), __FILE__, __LINE__)
+#else
+#if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)
+#define isc_mutex_init(mp) \
+ isc_mutex_init_errcheck((mp))
+#else
+#define isc_mutex_init(mp) \
+ isc__mutex_init((mp), __FILE__, __LINE__)
+isc_result_t isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line);
+#endif
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_lock(mp) \
+ isc_mutex_lock_profile((mp), __FILE__, __LINE__)
+#else
+#define isc_mutex_lock(mp) \
+ ((pthread_mutex_lock((mp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_unlock(mp) \
+ isc_mutex_unlock_profile((mp), __FILE__, __LINE__)
+#else
+#define isc_mutex_unlock(mp) \
+ ((pthread_mutex_unlock((mp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_trylock(mp) \
+ ((pthread_mutex_trylock((&(mp)->mutex)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_LOCKBUSY)
+#else
+#define isc_mutex_trylock(mp) \
+ ((pthread_mutex_trylock((mp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_LOCKBUSY)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_destroy(mp) \
+ ((pthread_mutex_destroy((&(mp)->mutex)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#else
+#define isc_mutex_destroy(mp) \
+ ((pthread_mutex_destroy((mp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_stats(fp) isc_mutex_statsprofile(fp);
+#else
+#define isc_mutex_stats(fp)
+#endif
+
+#if ISC_MUTEX_PROFILE
+
+isc_result_t
+isc_mutex_init_profile(isc_mutex_t *mp, const char * _file, int _line);
+isc_result_t
+isc_mutex_lock_profile(isc_mutex_t *mp, const char * _file, int _line);
+isc_result_t
+isc_mutex_unlock_profile(isc_mutex_t *mp, const char * _file, int _line);
+
+void
+isc_mutex_statsprofile(FILE *fp);
+
+isc_result_t
+isc_mutex_init_errcheck(isc_mutex_t *mp);
+
+#endif /* ISC_MUTEX_PROFILE */
+
+ISC_LANG_ENDDECLS
+#endif /* ISC_MUTEX_H */
diff --git a/lib/isc/pthreads/include/isc/once.h b/lib/isc/pthreads/include/isc/once.h
new file mode 100644
index 0000000..a0e9559
--- /dev/null
+++ b/lib/isc/pthreads/include/isc/once.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ONCE_H
+#define ISC_ONCE_H 1
+
+/*! \file */
+
+#include <pthread.h>
+
+#include <isc/platform.h>
+#include <isc/result.h>
+
+typedef pthread_once_t isc_once_t;
+
+#ifdef ISC_PLATFORM_BRACEPTHREADONCEINIT
+/*!
+ * This accomodates systems that define PTHRAD_ONCE_INIT improperly.
+ */
+#define ISC_ONCE_INIT { PTHREAD_ONCE_INIT }
+#else
+/*!
+ * This is the usual case.
+ */
+#define ISC_ONCE_INIT PTHREAD_ONCE_INIT
+#endif
+
+/* XXX We could do fancier error handling... */
+
+#define isc_once_do(op, f) \
+ ((pthread_once((op), (f)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#endif /* ISC_ONCE_H */
diff --git a/lib/isc/pthreads/include/isc/thread.h b/lib/isc/pthreads/include/isc/thread.h
new file mode 100644
index 0000000..798af33
--- /dev/null
+++ b/lib/isc/pthreads/include/isc/thread.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_THREAD_H
+#define ISC_THREAD_H 1
+
+/*! \file */
+
+#include <pthread.h>
+
+#if defined(HAVE_PTHREAD_NP_H)
+#include <pthread_np.h>
+#endif
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef pthread_t isc_thread_t;
+typedef void * isc_threadresult_t;
+typedef void * isc_threadarg_t;
+typedef isc_threadresult_t (*isc_threadfunc_t)(isc_threadarg_t);
+typedef pthread_key_t isc_thread_key_t;
+
+isc_result_t
+isc_thread_create(isc_threadfunc_t, isc_threadarg_t, isc_thread_t *);
+
+void
+isc_thread_setconcurrency(unsigned int level);
+
+void
+isc_thread_yield(void);
+
+void
+isc_thread_setname(isc_thread_t thread, const char *name);
+
+/* XXX We could do fancier error handling... */
+
+#define isc_thread_join(t, rp) \
+ ((pthread_join((t), (rp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_thread_self \
+ (unsigned long)pthread_self
+
+#define isc_thread_key_create pthread_key_create
+#define isc_thread_key_getspecific pthread_getspecific
+#define isc_thread_key_setspecific pthread_setspecific
+#define isc_thread_key_delete pthread_key_delete
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_THREAD_H */
diff --git a/lib/isc/pthreads/mutex.c b/lib/isc/pthreads/mutex.c
new file mode 100644
index 0000000..cd45e6b
--- /dev/null
+++ b/lib/isc/pthreads/mutex.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include <isc/mutex.h>
+#include <isc/util.h>
+#include <isc/print.h>
+#include <isc/strerror.h>
+#include <isc/once.h>
+
+#if ISC_MUTEX_PROFILE
+
+/*@{*/
+/*% Operations on timevals; adapted from FreeBSD's sys/time.h */
+#define timevalclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
+#define timevaladd(vvp, uvp) \
+ do { \
+ (vvp)->tv_sec += (uvp)->tv_sec; \
+ (vvp)->tv_usec += (uvp)->tv_usec; \
+ if ((vvp)->tv_usec >= 1000000) { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#define timevalsub(vvp, uvp) \
+ do { \
+ (vvp)->tv_sec -= (uvp)->tv_sec; \
+ (vvp)->tv_usec -= (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+
+/*@}*/
+
+#define ISC_MUTEX_MAX_LOCKERS 32
+
+typedef struct {
+ const char * file;
+ int line;
+ unsigned count;
+ struct timeval locked_total;
+ struct timeval wait_total;
+} isc_mutexlocker_t;
+
+struct isc_mutexstats {
+ const char * file; /*%< File mutex was created in. */
+ int line; /*%< Line mutex was created on. */
+ unsigned count;
+ struct timeval lock_t;
+ struct timeval locked_total;
+ struct timeval wait_total;
+ isc_mutexlocker_t * cur_locker;
+ isc_mutexlocker_t lockers[ISC_MUTEX_MAX_LOCKERS];
+};
+
+#ifndef ISC_MUTEX_PROFTABLESIZE
+#define ISC_MUTEX_PROFTABLESIZE (1024 * 1024)
+#endif
+static isc_mutexstats_t stats[ISC_MUTEX_PROFTABLESIZE];
+static int stats_next = 0;
+static bool stats_init = false;
+static pthread_mutex_t statslock = PTHREAD_MUTEX_INITIALIZER;
+
+
+isc_result_t
+isc_mutex_init_profile(isc_mutex_t *mp, const char *file, int line) {
+ int i, err;
+
+ err = pthread_mutex_init(&mp->mutex, NULL);
+ if (err == ENOMEM)
+ return (ISC_R_NOMEMORY);
+ if (err != 0)
+ return (ISC_R_UNEXPECTED);
+
+ RUNTIME_CHECK(pthread_mutex_lock(&statslock) == 0);
+
+ if (stats_init == false)
+ stats_init = true;
+
+ /*
+ * If all statistics entries have been used, give up and trigger an
+ * assertion failure. There would be no other way to deal with this
+ * because we'd like to keep record of all locks for the purpose of
+ * debugging and the number of necessary locks is unpredictable.
+ * If this failure is triggered while debugging, named should be
+ * rebuilt with an increased ISC_MUTEX_PROFTABLESIZE.
+ */
+ RUNTIME_CHECK(stats_next < ISC_MUTEX_PROFTABLESIZE);
+ mp->stats = &stats[stats_next++];
+
+ RUNTIME_CHECK(pthread_mutex_unlock(&statslock) == 0);
+
+ mp->stats->file = file;
+ mp->stats->line = line;
+ mp->stats->count = 0;
+ timevalclear(&mp->stats->locked_total);
+ timevalclear(&mp->stats->wait_total);
+ for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
+ mp->stats->lockers[i].file = NULL;
+ mp->stats->lockers[i].line = 0;
+ mp->stats->lockers[i].count = 0;
+ timevalclear(&mp->stats->lockers[i].locked_total);
+ timevalclear(&mp->stats->lockers[i].wait_total);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_mutex_lock_profile(isc_mutex_t *mp, const char *file, int line) {
+ struct timeval prelock_t;
+ struct timeval postlock_t;
+ isc_mutexlocker_t *locker = NULL;
+ int i;
+
+ gettimeofday(&prelock_t, NULL);
+
+ if (pthread_mutex_lock(&mp->mutex) != 0)
+ return (ISC_R_UNEXPECTED);
+
+ gettimeofday(&postlock_t, NULL);
+ mp->stats->lock_t = postlock_t;
+
+ timevalsub(&postlock_t, &prelock_t);
+
+ mp->stats->count++;
+ timevaladd(&mp->stats->wait_total, &postlock_t);
+
+ for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
+ if (mp->stats->lockers[i].file == NULL) {
+ locker = &mp->stats->lockers[i];
+ locker->file = file;
+ locker->line = line;
+ break;
+ } else if (mp->stats->lockers[i].file == file &&
+ mp->stats->lockers[i].line == line) {
+ locker = &mp->stats->lockers[i];
+ break;
+ }
+ }
+
+ if (locker != NULL) {
+ locker->count++;
+ timevaladd(&locker->wait_total, &postlock_t);
+ }
+
+ mp->stats->cur_locker = locker;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_mutex_unlock_profile(isc_mutex_t *mp, const char *file, int line) {
+ struct timeval unlock_t;
+
+ UNUSED(file);
+ UNUSED(line);
+
+ if (mp->stats->cur_locker != NULL) {
+ gettimeofday(&unlock_t, NULL);
+ timevalsub(&unlock_t, &mp->stats->lock_t);
+ timevaladd(&mp->stats->locked_total, &unlock_t);
+ timevaladd(&mp->stats->cur_locker->locked_total, &unlock_t);
+ mp->stats->cur_locker = NULL;
+ }
+
+ return ((pthread_mutex_unlock((&mp->mutex)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED);
+}
+
+
+void
+isc_mutex_statsprofile(FILE *fp) {
+ isc_mutexlocker_t *locker;
+ int i, j;
+
+ fprintf(fp, "Mutex stats (in us)\n");
+ for (i = 0; i < stats_next; i++) {
+ fprintf(fp, "%-12s %4d: %10u %lu.%06lu %lu.%06lu %5d\n",
+ stats[i].file, stats[i].line, stats[i].count,
+ stats[i].locked_total.tv_sec,
+ stats[i].locked_total.tv_usec,
+ stats[i].wait_total.tv_sec,
+ stats[i].wait_total.tv_usec,
+ i);
+ for (j = 0; j < ISC_MUTEX_MAX_LOCKERS; j++) {
+ locker = &stats[i].lockers[j];
+ if (locker->file == NULL)
+ continue;
+ fprintf(fp, " %-11s %4d: %10u %lu.%06lu %lu.%06lu %5d\n",
+ locker->file, locker->line, locker->count,
+ locker->locked_total.tv_sec,
+ locker->locked_total.tv_usec,
+ locker->wait_total.tv_sec,
+ locker->wait_total.tv_usec,
+ i);
+ }
+ }
+}
+
+#endif /* ISC_MUTEX_PROFILE */
+
+#if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)
+
+static bool errcheck_initialized = false;
+static pthread_mutexattr_t errcheck;
+static isc_once_t once_errcheck = ISC_ONCE_INIT;
+
+static void
+initialize_errcheck(void) {
+ RUNTIME_CHECK(pthread_mutexattr_init(&errcheck) == 0);
+ RUNTIME_CHECK(pthread_mutexattr_settype
+ (&errcheck, PTHREAD_MUTEX_ERRORCHECK) == 0);
+ errcheck_initialized = true;
+}
+
+isc_result_t
+isc_mutex_init_errcheck(isc_mutex_t *mp) {
+ isc_result_t result;
+ int err;
+
+ result = isc_once_do(&once_errcheck, initialize_errcheck);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ err = pthread_mutex_init(mp, &errcheck);
+ if (err == ENOMEM)
+ return (ISC_R_NOMEMORY);
+ return ((err == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED);
+}
+#endif
+
+#if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
+pthread_mutexattr_t isc__mutex_attrs = {
+ PTHREAD_MUTEX_ERRORCHECK, /* m_type */
+ 0 /* m_flags, which appears to be unused. */
+};
+#endif
+
+#if !(ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)) && !ISC_MUTEX_PROFILE
+
+#ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
+static bool attr_initialized = false;
+static pthread_mutexattr_t attr;
+static isc_once_t once_attr = ISC_ONCE_INIT;
+#endif /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
+
+#ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
+static void
+initialize_attr(void) {
+ RUNTIME_CHECK(pthread_mutexattr_init(&attr) == 0);
+ RUNTIME_CHECK(pthread_mutexattr_settype
+ (&attr, PTHREAD_MUTEX_ADAPTIVE_NP) == 0);
+ attr_initialized = true;
+}
+#endif /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
+
+isc_result_t
+isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc_result_t result = ISC_R_SUCCESS;
+ int err;
+
+#ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
+ result = isc_once_do(&once_attr, initialize_attr);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ err = pthread_mutex_init(mp, &attr);
+#else /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
+ err = pthread_mutex_init(mp, ISC__MUTEX_ATTRS);
+#endif /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
+
+ if (err == ENOMEM)
+ return (ISC_R_NOMEMORY);
+ if (err != 0) {
+ isc__strerror(err, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(file, line, "isc_mutex_init() failed: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ }
+ return (result);
+}
+#endif
diff --git a/lib/isc/pthreads/thread.c b/lib/isc/pthreads/thread.c
new file mode 100644
index 0000000..94fb2c2
--- /dev/null
+++ b/lib/isc/pthreads/thread.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#if defined(HAVE_SCHED_H)
+#include <sched.h>
+#endif
+
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#ifndef THREAD_MINSTACKSIZE
+#define THREAD_MINSTACKSIZE (1024U * 1024)
+#endif
+
+isc_result_t
+isc_thread_create(isc_threadfunc_t func, isc_threadarg_t arg,
+ isc_thread_t *thread)
+{
+ pthread_attr_t attr;
+#if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \
+ defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE)
+ size_t stacksize;
+#endif
+ int ret;
+
+ pthread_attr_init(&attr);
+
+#if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \
+ defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE)
+ ret = pthread_attr_getstacksize(&attr, &stacksize);
+ if (ret != 0)
+ return (ISC_R_UNEXPECTED);
+
+ if (stacksize < THREAD_MINSTACKSIZE) {
+ ret = pthread_attr_setstacksize(&attr, THREAD_MINSTACKSIZE);
+ if (ret != 0)
+ return (ISC_R_UNEXPECTED);
+ }
+#endif
+
+#if defined(PTHREAD_SCOPE_SYSTEM) && defined(NEED_PTHREAD_SCOPE_SYSTEM)
+ ret = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+ if (ret != 0)
+ return (ISC_R_UNEXPECTED);
+#endif
+
+ ret = pthread_create(thread, &attr, func, arg);
+ if (ret != 0)
+ return (ISC_R_UNEXPECTED);
+
+ pthread_attr_destroy(&attr);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_thread_setconcurrency(unsigned int level) {
+#if defined(CALL_PTHREAD_SETCONCURRENCY)
+ (void)pthread_setconcurrency(level);
+#else
+ UNUSED(level);
+#endif
+}
+
+void
+isc_thread_setname(isc_thread_t thread, const char *name) {
+#if defined(HAVE_PTHREAD_SETNAME_NP) && defined(_GNU_SOURCE)
+ /*
+ * macOS has pthread_setname_np but only works on the
+ * current thread so it's not used here
+ */
+ (void)pthread_setname_np(thread, name);
+#elif defined(HAVE_PTHREAD_SET_NAME_NP)
+ (void)pthread_set_name_np(thread, name);
+#else
+ UNUSED(thread);
+ UNUSED(name);
+#endif
+}
+
+void
+isc_thread_yield(void) {
+#if defined(HAVE_SCHED_YIELD)
+ sched_yield();
+#elif defined( HAVE_PTHREAD_YIELD)
+ pthread_yield();
+#elif defined( HAVE_PTHREAD_YIELD_NP)
+ pthread_yield_np();
+#endif
+}
diff --git a/lib/isc/quota.c b/lib/isc/quota.c
new file mode 100644
index 0000000..3ddff0d
--- /dev/null
+++ b/lib/isc/quota.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/quota.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_quota_init(isc_quota_t *quota, int max) {
+ quota->max = max;
+ quota->used = 0;
+ quota->soft = 0;
+ return (isc_mutex_init(&quota->lock));
+}
+
+void
+isc_quota_destroy(isc_quota_t *quota) {
+ INSIST(quota->used == 0);
+ quota->max = 0;
+ quota->used = 0;
+ quota->soft = 0;
+ DESTROYLOCK(&quota->lock);
+}
+
+void
+isc_quota_soft(isc_quota_t *quota, int soft) {
+ LOCK(&quota->lock);
+ quota->soft = soft;
+ UNLOCK(&quota->lock);
+}
+
+void
+isc_quota_max(isc_quota_t *quota, int max) {
+ LOCK(&quota->lock);
+ quota->max = max;
+ UNLOCK(&quota->lock);
+}
+
+isc_result_t
+isc_quota_reserve(isc_quota_t *quota) {
+ isc_result_t result;
+ LOCK(&quota->lock);
+ if (quota->max == 0 || quota->used < quota->max) {
+ if (quota->soft == 0 || quota->used < quota->soft)
+ result = ISC_R_SUCCESS;
+ else
+ result = ISC_R_SOFTQUOTA;
+ quota->used++;
+ } else
+ result = ISC_R_QUOTA;
+ UNLOCK(&quota->lock);
+ return (result);
+}
+
+void
+isc_quota_release(isc_quota_t *quota) {
+ LOCK(&quota->lock);
+ INSIST(quota->used > 0);
+ quota->used--;
+ UNLOCK(&quota->lock);
+}
+
+isc_result_t
+isc_quota_attach(isc_quota_t *quota, isc_quota_t **p)
+{
+ isc_result_t result;
+ INSIST(p != NULL && *p == NULL);
+ result = isc_quota_reserve(quota);
+ if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA)
+ *p = quota;
+ return (result);
+}
+
+void
+isc_quota_detach(isc_quota_t **p)
+{
+ INSIST(p != NULL && *p != NULL);
+ isc_quota_release(*p);
+ *p = NULL;
+}
diff --git a/lib/isc/radix.c b/lib/isc/radix.c
new file mode 100644
index 0000000..6299dfe
--- /dev/null
+++ b/lib/isc/radix.c
@@ -0,0 +1,728 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * This source was adapted from MRT's RCS Ids:
+ * Id: radix.c,v 1.10.2.1 1999/11/29 05:16:24 masaki Exp
+ * Id: prefix.c,v 1.37.2.9 2000/03/10 02:53:19 labovit Exp
+ */
+
+#include <config.h>
+
+#include <inttypes.h>
+
+#include <isc/mem.h>
+#include <isc/types.h>
+#include <isc/util.h>
+#include <isc/radix.h>
+
+static isc_result_t
+_new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family,
+ void *dest, int bitlen);
+
+static void
+_deref_prefix(isc_prefix_t *prefix);
+
+static isc_result_t
+_ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix);
+
+static int
+_comp_with_mask(void *addr, void *dest, u_int mask);
+
+static void
+_clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func);
+
+static isc_result_t
+_new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family, void *dest,
+ int bitlen)
+{
+ isc_prefix_t *prefix;
+
+ REQUIRE(target != NULL);
+
+ if (family != AF_INET6 && family != AF_INET && family != AF_UNSPEC)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ prefix = isc_mem_get(mctx, sizeof(isc_prefix_t));
+ if (prefix == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if (family == AF_INET6) {
+ prefix->bitlen = (bitlen >= 0) ? bitlen : 128;
+ memmove(&prefix->add.sin6, dest, 16);
+ } else {
+ /* AF_UNSPEC is "any" or "none"--treat it as AF_INET */
+ prefix->bitlen = (bitlen >= 0) ? bitlen : 32;
+ memmove(&prefix->add.sin, dest, 4);
+ }
+
+ prefix->family = family;
+ prefix->ecs = false;
+ prefix->mctx = NULL;
+ isc_mem_attach(mctx, &prefix->mctx);
+
+ isc_refcount_init(&prefix->refcount, 1);
+
+ *target = prefix;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+_deref_prefix(isc_prefix_t *prefix) {
+ int refs;
+
+ if (prefix == NULL)
+ return;
+
+ isc_refcount_decrement(&prefix->refcount, &refs);
+
+ if (refs <= 0) {
+ isc_refcount_destroy(&prefix->refcount);
+ isc_mem_putanddetach(&prefix->mctx, prefix,
+ sizeof(isc_prefix_t));
+ }
+}
+
+static isc_result_t
+_ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix) {
+ INSIST(prefix != NULL);
+ INSIST((prefix->family == AF_INET && prefix->bitlen <= 32) ||
+ (prefix->family == AF_INET6 && prefix->bitlen <= 128) ||
+ (prefix->family == AF_UNSPEC && prefix->bitlen == 0));
+ REQUIRE(target != NULL && *target == NULL);
+
+ /*
+ * If this prefix is a static allocation, copy it into new memory.
+ * (Note, the refcount still has to be destroyed by the calling
+ * routine.)
+ */
+ if (isc_refcount_current(&prefix->refcount) == 0) {
+ isc_result_t ret;
+ ret = _new_prefix(mctx, target, prefix->family,
+ &prefix->add, prefix->bitlen);
+ return (ret);
+ }
+
+ isc_refcount_increment(&prefix->refcount, NULL);
+
+ *target = prefix;
+ return (ISC_R_SUCCESS);
+}
+
+static int
+_comp_with_mask(void *addr, void *dest, u_int mask) {
+
+ /* Mask length of zero matches everything */
+ if (mask == 0)
+ return (1);
+
+ if (memcmp(addr, dest, mask / 8) == 0) {
+ u_int n = mask / 8;
+ u_int m = ((~0U) << (8 - (mask % 8)));
+
+ if ((mask % 8) == 0 ||
+ (((u_char *)addr)[n] & m) == (((u_char *)dest)[n] & m))
+ return (1);
+ }
+ return (0);
+}
+
+isc_result_t
+isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, int maxbits) {
+ isc_radix_tree_t *radix;
+
+ REQUIRE(target != NULL && *target == NULL);
+
+ radix = isc_mem_get(mctx, sizeof(isc_radix_tree_t));
+ if (radix == NULL)
+ return (ISC_R_NOMEMORY);
+
+ radix->mctx = NULL;
+ isc_mem_attach(mctx, &radix->mctx);
+ radix->maxbits = maxbits;
+ radix->head = NULL;
+ radix->num_active_node = 0;
+ radix->num_added_node = 0;
+ RUNTIME_CHECK(maxbits <= RADIX_MAXBITS); /* XXX */
+ radix->magic = RADIX_TREE_MAGIC;
+ *target = radix;
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * if func is supplied, it will be called as func(node->data)
+ * before deleting the node
+ */
+
+static void
+_clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) {
+ REQUIRE(radix != NULL);
+
+ if (radix->head != NULL) {
+ isc_radix_node_t *Xstack[RADIX_MAXBITS+1];
+ isc_radix_node_t **Xsp = Xstack;
+ isc_radix_node_t *Xrn = radix->head;
+
+ while (Xrn != NULL) {
+ isc_radix_node_t *l = Xrn->l;
+ isc_radix_node_t *r = Xrn->r;
+
+ if (Xrn->prefix != NULL) {
+ _deref_prefix(Xrn->prefix);
+ if (func != NULL)
+ func(Xrn->data);
+ } else {
+ INSIST(Xrn->data[RADIX_V4] == NULL &&
+ Xrn->data[RADIX_V6] == NULL &&
+ Xrn->data[RADIX_V4_ECS] == NULL &&
+ Xrn->data[RADIX_V6_ECS] == NULL);
+ }
+
+ isc_mem_put(radix->mctx, Xrn, sizeof(*Xrn));
+ radix->num_active_node--;
+
+ if (l != NULL) {
+ if (r != NULL) {
+ *Xsp++ = r;
+ }
+ Xrn = l;
+ } else if (r != NULL) {
+ Xrn = r;
+ } else if (Xsp != Xstack) {
+ Xrn = *(--Xsp);
+ } else {
+ Xrn = NULL;
+ }
+ }
+ }
+ RUNTIME_CHECK(radix->num_active_node == 0);
+}
+
+
+void
+isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) {
+ REQUIRE(radix != NULL);
+ _clear_radix(radix, func);
+ isc_mem_putanddetach(&radix->mctx, radix, sizeof(*radix));
+}
+
+
+/*
+ * func will be called as func(node->prefix, node->data)
+ */
+void
+isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func) {
+ isc_radix_node_t *node;
+
+ REQUIRE(func != NULL);
+
+ RADIX_WALK(radix->head, node) {
+ func(node->prefix, node->data);
+ } RADIX_WALK_END;
+}
+
+
+isc_result_t
+isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target,
+ isc_prefix_t *prefix)
+{
+ isc_radix_node_t *node;
+ isc_radix_node_t *stack[RADIX_MAXBITS + 1];
+ u_char *addr;
+ uint32_t bitlen;
+ int tfam = -1, cnt = 0;
+
+ REQUIRE(radix != NULL);
+ REQUIRE(prefix != NULL);
+ REQUIRE(target != NULL && *target == NULL);
+ RUNTIME_CHECK(prefix->bitlen <= radix->maxbits);
+
+ *target = NULL;
+
+ if (radix->head == NULL) {
+ return (ISC_R_NOTFOUND);
+ }
+
+ node = radix->head;
+ addr = isc_prefix_touchar(prefix);
+ bitlen = prefix->bitlen;
+
+ while (node->bit < bitlen) {
+ if (node->prefix)
+ stack[cnt++] = node;
+
+ if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+ node = node->r;
+ else
+ node = node->l;
+
+ if (node == NULL)
+ break;
+ }
+
+ if (node && node->prefix)
+ stack[cnt++] = node;
+
+ while (cnt-- > 0) {
+ node = stack[cnt];
+
+ if (prefix->bitlen < node->bit)
+ continue;
+
+ if (_comp_with_mask(isc_prefix_tochar(node->prefix),
+ isc_prefix_tochar(prefix),
+ node->prefix->bitlen))
+ {
+ int fam = ISC_RADIX_FAMILY(prefix);
+ if (node->node_num[fam] != -1 &&
+ ((*target == NULL) ||
+ (*target)->node_num[tfam] > node->node_num[fam]))
+ {
+ *target = node;
+ tfam = fam;
+ }
+ }
+ }
+
+ if (*target == NULL) {
+ return (ISC_R_NOTFOUND);
+ } else {
+ return (ISC_R_SUCCESS);
+ }
+}
+
+isc_result_t
+isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
+ isc_radix_node_t *source, isc_prefix_t *prefix)
+{
+ isc_radix_node_t *node, *new_node, *parent, *glue = NULL;
+ u_char *addr, *test_addr;
+ uint32_t bitlen, fam, check_bit, differ_bit;
+ uint32_t i, j, r;
+ isc_result_t result;
+
+ REQUIRE(radix != NULL);
+ REQUIRE(target != NULL && *target == NULL);
+ REQUIRE(prefix != NULL || (source != NULL && source->prefix != NULL));
+ RUNTIME_CHECK(prefix == NULL || prefix->bitlen <= radix->maxbits);
+
+ if (prefix == NULL)
+ prefix = source->prefix;
+
+ INSIST(prefix != NULL);
+
+ bitlen = prefix->bitlen;
+ fam = prefix->family;
+
+ if (radix->head == NULL) {
+ node = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t));
+ if (node == NULL)
+ return (ISC_R_NOMEMORY);
+ node->bit = bitlen;
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ node->node_num[i] = -1;
+ }
+ node->prefix = NULL;
+ result = _ref_prefix(radix->mctx, &node->prefix, prefix);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(radix->mctx, node,
+ sizeof(isc_radix_node_t));
+ return (result);
+ }
+ node->parent = NULL;
+ node->l = node->r = NULL;
+ if (source != NULL) {
+ /*
+ * If source is non-NULL, then we're merging in a
+ * node from an existing radix tree. To keep
+ * the node_num values consistent, the calling
+ * function will add the total number of nodes
+ * added to num_added_node at the end of
+ * the merge operation--we don't do it here.
+ */
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ if (source->node_num[i] != -1) {
+ node->node_num[i] =
+ radix->num_added_node +
+ source->node_num[i];
+ }
+ node->data[i] = source->data[i];
+ }
+ } else {
+ int next = ++radix->num_added_node;
+ if (fam == AF_UNSPEC) {
+ /* "any" or "none" */
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ node->node_num[i] = next;
+ }
+ } else {
+ node->node_num[ISC_RADIX_FAMILY(prefix)] = next;
+ }
+
+ memset(node->data, 0, sizeof(node->data));
+ }
+ radix->head = node;
+ radix->num_active_node++;
+ *target = node;
+ return (ISC_R_SUCCESS);
+ }
+
+ addr = isc_prefix_touchar(prefix);
+ node = radix->head;
+
+ while (node->bit < bitlen || node->prefix == NULL) {
+ if (node->bit < radix->maxbits &&
+ BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+ {
+ if (node->r == NULL)
+ break;
+ node = node->r;
+ } else {
+ if (node->l == NULL)
+ break;
+ node = node->l;
+ }
+
+ INSIST(node != NULL);
+ }
+
+ INSIST(node->prefix != NULL);
+
+ test_addr = isc_prefix_touchar(node->prefix);
+ /* Find the first bit different. */
+ check_bit = (node->bit < bitlen) ? node->bit : bitlen;
+ differ_bit = 0;
+ for (i = 0; i * 8 < check_bit; i++) {
+ if ((r = (addr[i] ^ test_addr[i])) == 0) {
+ differ_bit = (i + 1) * 8;
+ continue;
+ }
+ /* I know the better way, but for now. */
+ for (j = 0; j < 8; j++) {
+ if (BIT_TEST(r, (0x80 >> j)))
+ break;
+ }
+ /* Must be found. */
+ INSIST(j < 8);
+ differ_bit = i * 8 + j;
+ break;
+ }
+
+ if (differ_bit > check_bit)
+ differ_bit = check_bit;
+
+ parent = node->parent;
+ while (parent != NULL && parent->bit >= differ_bit) {
+ node = parent;
+ parent = node->parent;
+ }
+
+ if (differ_bit == bitlen && node->bit == bitlen) {
+ if (node->prefix != NULL) {
+ /* Set node_num only if it hasn't been set before */
+ if (source != NULL) {
+ /* Merging nodes */
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ if (node->node_num[i] == -1 &&
+ source->node_num[i] != -1) {
+ node->node_num[i] =
+ radix->num_added_node +
+ source->node_num[i];
+ node->data[i] = source->data[i];
+ }
+ }
+ } else {
+ if (fam == AF_UNSPEC) {
+ /* "any" or "none" */
+ int next = radix->num_added_node + 1;
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ if (node->node_num[i] == -1) {
+ node->node_num[i] =
+ next;
+ radix->num_added_node =
+ next;
+ }
+ }
+ } else {
+ int foff = ISC_RADIX_FAMILY(prefix);
+ if (node->node_num[foff] == -1) {
+ node->node_num[foff] =
+ ++radix->num_added_node;
+ }
+ }
+ }
+ *target = node;
+ return (ISC_R_SUCCESS);
+ } else {
+ result = _ref_prefix(radix->mctx,
+ &node->prefix, prefix);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ /* Check everything is null and empty before we proceed */
+ INSIST(node->data[RADIX_V4] == NULL &&
+ node->node_num[RADIX_V4] == -1 &&
+ node->data[RADIX_V6] == NULL &&
+ node->node_num[RADIX_V6] == -1 &&
+ node->data[RADIX_V4_ECS] == NULL &&
+ node->node_num[RADIX_V4_ECS] == -1 &&
+ node->data[RADIX_V6_ECS] == NULL &&
+ node->node_num[RADIX_V6_ECS] == -1);
+
+ if (source != NULL) {
+ /* Merging node */
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ int cur = radix->num_added_node;
+ if (source->node_num[i] != -1) {
+ node->node_num[i] =
+ source->node_num[i] + cur;
+ node->data[i] = source->data[i];
+ }
+ }
+ } else {
+ int next = ++radix->num_added_node;
+ if (fam == AF_UNSPEC) {
+ /* "any" or "none" */
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ node->node_num[i] = next;
+ }
+ } else {
+ node->node_num[ISC_RADIX_FAMILY(prefix)] = next;
+ }
+ }
+ *target = node;
+ return (ISC_R_SUCCESS);
+ }
+
+ new_node = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t));
+ if (new_node == NULL)
+ return (ISC_R_NOMEMORY);
+ if (node->bit != differ_bit && bitlen != differ_bit) {
+ glue = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t));
+ if (glue == NULL) {
+ isc_mem_put(radix->mctx, new_node,
+ sizeof(isc_radix_node_t));
+ return (ISC_R_NOMEMORY);
+ }
+ }
+ new_node->bit = bitlen;
+ new_node->prefix = NULL;
+ result = _ref_prefix(radix->mctx, &new_node->prefix, prefix);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(radix->mctx, new_node, sizeof(isc_radix_node_t));
+ if (glue != NULL)
+ isc_mem_put(radix->mctx, glue,
+ sizeof(isc_radix_node_t));
+ return (result);
+ }
+ new_node->parent = NULL;
+ new_node->l = new_node->r = NULL;
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ new_node->node_num[i] = -1;
+ new_node->data[i] = NULL;
+ }
+ radix->num_active_node++;
+
+ if (source != NULL) {
+ /* Merging node */
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ int cur = radix->num_added_node;
+ if (source->node_num[i] != -1) {
+ new_node->node_num[i] =
+ source->node_num[i] + cur;
+ new_node->data[i] = source->data[i];
+ }
+ }
+ } else {
+ int next = ++radix->num_added_node;
+ if (fam == AF_UNSPEC) {
+ /* "any" or "none" */
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ new_node->node_num[i] = next;
+ }
+ } else {
+ new_node->node_num[ISC_RADIX_FAMILY(prefix)] = next;
+ }
+ memset(new_node->data, 0, sizeof(new_node->data));
+ }
+
+ if (node->bit == differ_bit) {
+ INSIST(glue == NULL);
+ new_node->parent = node;
+ if (node->bit < radix->maxbits &&
+ BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+ {
+ INSIST(node->r == NULL);
+ node->r = new_node;
+ } else {
+ INSIST(node->l == NULL);
+ node->l = new_node;
+ }
+ *target = new_node;
+ return (ISC_R_SUCCESS);
+ }
+
+ if (bitlen == differ_bit) {
+ INSIST(glue == NULL);
+ if (bitlen < radix->maxbits &&
+ BIT_TEST(test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07))) {
+ new_node->r = node;
+ } else {
+ new_node->l = node;
+ }
+ new_node->parent = node->parent;
+ if (node->parent == NULL) {
+ INSIST(radix->head == node);
+ radix->head = new_node;
+ } else if (node->parent->r == node) {
+ node->parent->r = new_node;
+ } else {
+ node->parent->l = new_node;
+ }
+ node->parent = new_node;
+ } else {
+ INSIST(glue != NULL);
+ glue->bit = differ_bit;
+ glue->prefix = NULL;
+ glue->parent = node->parent;
+ for (i = 0; i < RADIX_FAMILIES; i++) {
+ glue->data[i] = NULL;
+ glue->node_num[i] = -1;
+ }
+ radix->num_active_node++;
+ if (differ_bit < radix->maxbits &&
+ BIT_TEST(addr[differ_bit>>3], 0x80 >> (differ_bit & 07))) {
+ glue->r = new_node;
+ glue->l = node;
+ } else {
+ glue->r = node;
+ glue->l = new_node;
+ }
+ new_node->parent = glue;
+
+ if (node->parent == NULL) {
+ INSIST(radix->head == node);
+ radix->head = glue;
+ } else if (node->parent->r == node) {
+ node->parent->r = glue;
+ } else {
+ node->parent->l = glue;
+ }
+ node->parent = glue;
+ }
+
+ *target = new_node;
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) {
+ isc_radix_node_t *parent, *child;
+
+ REQUIRE(radix != NULL);
+ REQUIRE(node != NULL);
+
+ if (node->r && node->l) {
+ /*
+ * This might be a placeholder node -- have to check and
+ * make sure there is a prefix associated with it!
+ */
+ if (node->prefix != NULL)
+ _deref_prefix(node->prefix);
+
+ node->prefix = NULL;
+ memset(node->data, 0, sizeof(node->data));
+ return;
+ }
+
+ if (node->r == NULL && node->l == NULL) {
+ parent = node->parent;
+ _deref_prefix(node->prefix);
+
+ if (parent == NULL) {
+ INSIST(radix->head == node);
+ radix->head = NULL;
+ isc_mem_put(radix->mctx, node, sizeof(*node));
+ radix->num_active_node--;
+ return;
+ }
+
+ if (parent->r == node) {
+ parent->r = NULL;
+ child = parent->l;
+ } else {
+ INSIST(parent->l == node);
+ parent->l = NULL;
+ child = parent->r;
+ }
+
+ isc_mem_put(radix->mctx, node, sizeof(*node));
+ radix->num_active_node--;
+
+ if (parent->prefix)
+ return;
+
+ /* We need to remove parent too. */
+ if (parent->parent == NULL) {
+ INSIST(radix->head == parent);
+ radix->head = child;
+ } else if (parent->parent->r == parent) {
+ parent->parent->r = child;
+ } else {
+ INSIST(parent->parent->l == parent);
+ parent->parent->l = child;
+ }
+
+ child->parent = parent->parent;
+ isc_mem_put(radix->mctx, parent, sizeof(*parent));
+ radix->num_active_node--;
+ return;
+ }
+
+ if (node->r) {
+ child = node->r;
+ } else {
+ INSIST(node->l != NULL);
+ child = node->l;
+ }
+
+ parent = node->parent;
+ child->parent = parent;
+
+ _deref_prefix(node->prefix);
+
+ if (parent == NULL) {
+ INSIST(radix->head == node);
+ radix->head = child;
+ isc_mem_put(radix->mctx, node, sizeof(*node));
+ radix->num_active_node--;
+ return;
+ }
+
+ isc_mem_put(radix->mctx, node, sizeof(*node));
+ radix->num_active_node--;
+
+ if (parent->r == node) {
+ parent->r = child;
+ } else {
+ INSIST(parent->l == node);
+ parent->l = child;
+ }
+}
+
+/*
+Local Variables:
+c-basic-offset: 4
+indent-tabs-mode: t
+End:
+*/
diff --git a/lib/isc/random.c b/lib/isc/random.c
new file mode 100644
index 0000000..b79b689
--- /dev/null
+++ b/lib/isc/random.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*%
+ * ChaCha based random number generator derived from OpenBSD.
+ *
+ * The original copyright follows:
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <time.h> /* Required for time(). */
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <isc/magic.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/mem.h>
+#include <isc/entropy.h>
+#include <isc/random.h>
+#include <isc/safe.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define RNG_MAGIC ISC_MAGIC('R', 'N', 'G', 'x')
+#define VALID_RNG(r) ISC_MAGIC_VALID(r, RNG_MAGIC)
+
+#define KEYSTREAM_ONLY
+#include "chacha_private.h"
+
+#define CHACHA_KEYSIZE 32U
+#define CHACHA_IVSIZE 8U
+#define CHACHA_BLOCKSIZE 64
+#define CHACHA_BUFFERSIZE (16 * CHACHA_BLOCKSIZE)
+
+/* ChaCha RNG state */
+struct isc_rng {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ chacha_ctx cpctx;
+ uint8_t buffer[CHACHA_BUFFERSIZE];
+ size_t have;
+ unsigned int references;
+ int count;
+ isc_entropy_t *entropy; /*%< entropy source */
+ isc_mutex_t lock;
+};
+
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+initialize_rand(void) {
+#ifndef HAVE_ARC4RANDOM
+ unsigned int pid = getpid();
+
+ /*
+ * The low bits of pid generally change faster.
+ * Xor them with the high bits of time which change slowly.
+ */
+ pid = ((pid << 16) & 0xffff0000) | ((pid >> 16) & 0xffff);
+
+ srand((unsigned)time(NULL) ^ pid);
+#endif
+}
+
+static void
+initialize(void) {
+ RUNTIME_CHECK(isc_once_do(&once, initialize_rand) == ISC_R_SUCCESS);
+}
+
+void
+isc_random_seed(uint32_t seed) {
+ initialize();
+
+#ifndef HAVE_ARC4RANDOM
+ srand(seed);
+#elif defined(HAVE_ARC4RANDOM_STIR)
+ /* Formally not necessary... */
+ UNUSED(seed);
+ arc4random_stir();
+#elif defined(HAVE_ARC4RANDOM_ADDRANDOM)
+ arc4random_addrandom((u_char *) &seed, sizeof(uint32_t));
+#else
+ /*
+ * If arc4random() is available and no corresponding seeding
+ * function arc4random_addrandom() is available, no seeding is
+ * done on such platforms (e.g., OpenBSD 5.5). This is because
+ * the OS itself is supposed to seed the RNG and it is assumed
+ * that no explicit seeding is required.
+ */
+ UNUSED(seed);
+#endif
+}
+
+void
+isc_random_get(uint32_t *val) {
+ REQUIRE(val != NULL);
+
+ initialize();
+
+#ifndef HAVE_ARC4RANDOM
+ /*
+ * rand()'s lower bits are not random.
+ * rand()'s upper bit is zero.
+ */
+#if RAND_MAX >= 0xfffff
+ /* We have at least 20 bits. Use lower 16 excluding lower most 4 */
+ *val = ((((unsigned int)rand()) & 0xffff0) >> 4) |
+ ((((unsigned int)rand()) & 0xffff0) << 12);
+#elif RAND_MAX >= 0x7fff
+ /* We have at least 15 bits. Use lower 10/11 excluding lower most 4 */
+ *val = ((rand() >> 4) & 0x000007ff) | ((rand() << 7) & 0x003ff800) |
+ ((rand() << 18) & 0xffc00000);
+#else
+#error RAND_MAX is too small
+#endif
+#else
+ *val = arc4random();
+#endif
+}
+
+uint32_t
+isc_random_jitter(uint32_t max, uint32_t jitter) {
+ uint32_t rnd;
+
+ REQUIRE(jitter < max || (jitter == 0 && max == 0));
+
+ if (jitter == 0)
+ return (max);
+
+ isc_random_get(&rnd);
+ return (max - rnd % jitter);
+}
+
+static void
+chacha_reinit(isc_rng_t *rng, uint8_t *buffer, size_t n) {
+ REQUIRE(rng != NULL);
+
+ if (n < CHACHA_KEYSIZE + CHACHA_IVSIZE)
+ return;
+
+ chacha_keysetup(&rng->cpctx, buffer, CHACHA_KEYSIZE * 8, 0);
+ chacha_ivsetup(&rng->cpctx, buffer + CHACHA_KEYSIZE);
+}
+
+isc_result_t
+isc_rng_create(isc_mem_t *mctx, isc_entropy_t *entropy, isc_rng_t **rngp) {
+ union {
+ unsigned char rnd[128];
+ uint32_t rnd32[32];
+ } rnd;
+ isc_result_t result;
+ isc_rng_t *rng;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(rngp != NULL && *rngp == NULL);
+
+ if (entropy != NULL) {
+ /*
+ * We accept any quality of random data to avoid blocking.
+ */
+ result = isc_entropy_getdata(entropy, rnd.rnd,
+ sizeof(rnd), NULL, 0);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ } else {
+ int i;
+ for (i = 0; i < 32; i++)
+ isc_random_get(&rnd.rnd32[i]);
+ }
+
+ rng = isc_mem_get(mctx, sizeof(*rng));
+ if (rng == NULL)
+ return (ISC_R_NOMEMORY);
+
+ chacha_reinit(rng, rnd.rnd, sizeof(rnd.rnd));
+
+ rng->have = 0;
+ memset(rng->buffer, 0, CHACHA_BUFFERSIZE);
+
+ /* Create lock */
+ result = isc_mutex_init(&rng->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, rng, sizeof(*rng));
+ return (result);
+ }
+
+ /* Attach to memory context */
+ rng->mctx = NULL;
+ isc_mem_attach(mctx, &rng->mctx);
+
+ /* Local non-algorithm initializations. */
+ rng->count = 0;
+ rng->entropy = entropy; /* don't have to attach */
+ rng->references = 1;
+ rng->magic = RNG_MAGIC;
+
+ *rngp = rng;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_rng_attach(isc_rng_t *source, isc_rng_t **targetp) {
+
+ REQUIRE(VALID_RNG(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ LOCK(&source->lock);
+ source->references++;
+ UNLOCK(&source->lock);
+
+ *targetp = (isc_rng_t *)source;
+}
+
+static void
+destroy(isc_rng_t *rng) {
+
+ REQUIRE(VALID_RNG(rng));
+
+ rng->magic = 0;
+ isc_mutex_destroy(&rng->lock);
+ isc_mem_putanddetach(&rng->mctx, rng, sizeof(isc_rng_t));
+}
+
+void
+isc_rng_detach(isc_rng_t **rngp) {
+ isc_rng_t *rng;
+ bool dest = false;
+
+ REQUIRE(rngp != NULL && VALID_RNG(*rngp));
+
+ rng = *rngp;
+ *rngp = NULL;
+
+ LOCK(&rng->lock);
+
+ INSIST(rng->references > 0);
+ rng->references--;
+ if (rng->references == 0)
+ dest = true;
+ UNLOCK(&rng->lock);
+
+ if (dest)
+ destroy(rng);
+}
+
+static void
+chacha_rekey(isc_rng_t *rng, u_char *dat, size_t datlen) {
+ REQUIRE(VALID_RNG(rng));
+
+#ifndef KEYSTREAM_ONLY
+ memset(rng->buffer, 0, CHACHA_BUFFERSIZE);
+#endif
+
+ /* Fill buffer with the keystream. */
+ chacha_encrypt_bytes(&rng->cpctx, rng->buffer, rng->buffer,
+ CHACHA_BUFFERSIZE);
+
+ /* Mix in optional user provided data. */
+ if (dat != NULL) {
+ size_t i, m;
+
+ m = ISC_MIN(datlen, CHACHA_KEYSIZE + CHACHA_IVSIZE);
+ for (i = 0; i < m; i++)
+ rng->buffer[i] ^= dat[i];
+ }
+
+ /* Immediately reinit for backtracking resistance. */
+ chacha_reinit(rng, rng->buffer,
+ CHACHA_KEYSIZE + CHACHA_IVSIZE);
+ memset(rng->buffer, 0, CHACHA_KEYSIZE + CHACHA_IVSIZE);
+ rng->have = CHACHA_BUFFERSIZE - CHACHA_KEYSIZE - CHACHA_IVSIZE;
+}
+
+static inline uint16_t
+chacha_getuint16(isc_rng_t *rng) {
+ uint16_t val;
+
+ REQUIRE(VALID_RNG(rng));
+
+ if (rng->have < sizeof(val))
+ chacha_rekey(rng, NULL, 0);
+
+ memmove(&val, rng->buffer + CHACHA_BUFFERSIZE - rng->have,
+ sizeof(val));
+ /* Clear the copied region. */
+ memset(rng->buffer + CHACHA_BUFFERSIZE - rng->have,
+ 0, sizeof(val));
+ rng->have -= sizeof(val);
+
+ return (val);
+}
+
+static void
+chacha_stir(isc_rng_t *rng) {
+ union {
+ unsigned char rnd[128];
+ uint32_t rnd32[32];
+ } rnd;
+ isc_result_t result;
+
+ REQUIRE(VALID_RNG(rng));
+
+ if (rng->entropy != NULL) {
+ /*
+ * We accept any quality of random data to avoid blocking.
+ */
+ result = isc_entropy_getdata(rng->entropy, rnd.rnd,
+ sizeof(rnd), NULL, 0);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ } else {
+ int i;
+ for (i = 0; i < 32; i++)
+ isc_random_get(&rnd.rnd32[i]);
+ }
+
+ chacha_rekey(rng, rnd.rnd, sizeof(rnd.rnd));
+
+ isc_safe_memwipe(rnd.rnd, sizeof(rnd.rnd));
+
+ /* Invalidate the buffer too. */
+ rng->have = 0;
+ memset(rng->buffer, 0, CHACHA_BUFFERSIZE);
+
+ /*
+ * Derived from OpenBSD's implementation. The rationale is not clear,
+ * but should be conservative enough in safety, and reasonably large
+ * for efficiency.
+ */
+ rng->count = 1600000;
+}
+
+uint16_t
+isc_rng_random(isc_rng_t *rng) {
+ uint16_t result;
+
+ REQUIRE(VALID_RNG(rng));
+
+ LOCK(&rng->lock);
+
+ rng->count -= sizeof(uint16_t);
+ if (rng->count <= 0)
+ chacha_stir(rng);
+ result = chacha_getuint16(rng);
+
+ UNLOCK(&rng->lock);
+
+ return (result);
+}
+
+uint16_t
+isc_rng_uniformrandom(isc_rng_t *rng, uint16_t upper_bound) {
+ uint16_t min, r;
+
+ REQUIRE(VALID_RNG(rng));
+
+ if (upper_bound < 2)
+ return (0);
+
+ /*
+ * Ensure the range of random numbers [min, 0xffff] be a multiple of
+ * upper_bound and contain at least a half of the 16 bit range.
+ */
+
+ if (upper_bound > 0x8000)
+ min = 1 + ~upper_bound; /* 0x8000 - upper_bound */
+ else
+ min = (uint16_t)(0x10000 % (uint32_t)upper_bound);
+
+ /*
+ * This could theoretically loop forever but each retry has
+ * p > 0.5 (worst case, usually far better) of selecting a
+ * number inside the range we need, so it should rarely need
+ * to re-roll.
+ */
+ for (;;) {
+ r = isc_rng_random(rng);
+ if (r >= min)
+ break;
+ }
+
+ return (r % upper_bound);
+}
diff --git a/lib/isc/ratelimiter.c b/lib/isc/ratelimiter.c
new file mode 100644
index 0000000..b950298
--- /dev/null
+++ b/lib/isc/ratelimiter.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/mem.h>
+#include <isc/ratelimiter.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+typedef enum {
+ isc_ratelimiter_stalled = 0,
+ isc_ratelimiter_ratelimited = 1,
+ isc_ratelimiter_idle = 2,
+ isc_ratelimiter_shuttingdown = 3
+} isc_ratelimiter_state_t;
+
+struct isc_ratelimiter {
+ isc_mem_t * mctx;
+ isc_mutex_t lock;
+ int refs;
+ isc_task_t * task;
+ isc_timer_t * timer;
+ isc_interval_t interval;
+ uint32_t pertic;
+ bool pushpop;
+ isc_ratelimiter_state_t state;
+ isc_event_t shutdownevent;
+ ISC_LIST(isc_event_t) pending;
+};
+
+#define ISC_RATELIMITEREVENT_SHUTDOWN (ISC_EVENTCLASS_RATELIMITER + 1)
+
+static void
+ratelimiter_tick(isc_task_t *task, isc_event_t *event);
+
+static void
+ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event);
+
+isc_result_t
+isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
+ isc_task_t *task, isc_ratelimiter_t **ratelimiterp)
+{
+ isc_result_t result;
+ isc_ratelimiter_t *rl;
+ INSIST(ratelimiterp != NULL && *ratelimiterp == NULL);
+
+ rl = isc_mem_get(mctx, sizeof(*rl));
+ if (rl == NULL)
+ return ISC_R_NOMEMORY;
+ rl->mctx = mctx;
+ rl->refs = 1;
+ rl->task = task;
+ isc_interval_set(&rl->interval, 0, 0);
+ rl->timer = NULL;
+ rl->pertic = 1;
+ rl->pushpop = false;
+ rl->state = isc_ratelimiter_idle;
+ ISC_LIST_INIT(rl->pending);
+
+ result = isc_mutex_init(&rl->lock);
+ if (result != ISC_R_SUCCESS)
+ goto free_mem;
+
+ result = isc_timer_create(timermgr, isc_timertype_inactive,
+ NULL, NULL, rl->task, ratelimiter_tick,
+ rl, &rl->timer);
+ if (result != ISC_R_SUCCESS)
+ goto free_mutex;
+
+ /*
+ * Increment the reference count to indicate that we may
+ * (soon) have events outstanding.
+ */
+ rl->refs++;
+
+ ISC_EVENT_INIT(&rl->shutdownevent,
+ sizeof(isc_event_t),
+ 0, NULL, ISC_RATELIMITEREVENT_SHUTDOWN,
+ ratelimiter_shutdowncomplete, rl, rl, NULL, NULL);
+
+ *ratelimiterp = rl;
+ return (ISC_R_SUCCESS);
+
+free_mutex:
+ DESTROYLOCK(&rl->lock);
+free_mem:
+ isc_mem_put(mctx, rl, sizeof(*rl));
+ return (result);
+}
+
+isc_result_t
+isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(rl != NULL);
+ REQUIRE(interval != NULL);
+
+ LOCK(&rl->lock);
+ rl->interval = *interval;
+ /*
+ * If the timer is currently running, change its rate.
+ */
+ if (rl->state == isc_ratelimiter_ratelimited) {
+ result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL,
+ &rl->interval, false);
+ }
+ UNLOCK(&rl->lock);
+ return (result);
+}
+
+void
+isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, uint32_t pertic) {
+
+ REQUIRE(rl != NULL);
+
+ if (pertic == 0)
+ pertic = 1;
+ rl->pertic = pertic;
+}
+
+void
+isc_ratelimiter_setpushpop(isc_ratelimiter_t *rl, bool pushpop) {
+
+ REQUIRE(rl != NULL);
+
+ rl->pushpop = pushpop;
+}
+
+isc_result_t
+isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
+ isc_event_t **eventp)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_event_t *ev;
+
+ REQUIRE(rl != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(eventp != NULL && *eventp != NULL);
+ ev = *eventp;
+ REQUIRE(ev->ev_sender == NULL);
+
+ LOCK(&rl->lock);
+ if (rl->state == isc_ratelimiter_ratelimited ||
+ rl->state == isc_ratelimiter_stalled) {
+ ev->ev_sender = task;
+ *eventp = NULL;
+ if (rl->pushpop)
+ ISC_LIST_PREPEND(rl->pending, ev, ev_ratelink);
+ else
+ ISC_LIST_APPEND(rl->pending, ev, ev_ratelink);
+ } else if (rl->state == isc_ratelimiter_idle) {
+ result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL,
+ &rl->interval, false);
+ if (result == ISC_R_SUCCESS) {
+ ev->ev_sender = task;
+ rl->state = isc_ratelimiter_ratelimited;
+ }
+ } else {
+ INSIST(rl->state == isc_ratelimiter_shuttingdown);
+ result = ISC_R_SHUTTINGDOWN;
+ }
+ UNLOCK(&rl->lock);
+ if (*eventp != NULL && result == ISC_R_SUCCESS)
+ isc_task_send(task, eventp);
+ return (result);
+}
+
+isc_result_t
+isc_ratelimiter_dequeue(isc_ratelimiter_t *rl, isc_event_t *event) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(rl != NULL);
+ REQUIRE(event != NULL);
+
+ LOCK(&rl->lock);
+ if (ISC_LINK_LINKED(event, ev_ratelink)) {
+ ISC_LIST_UNLINK(rl->pending, event, ev_ratelink);
+ event->ev_sender = NULL;
+ } else
+ result = ISC_R_NOTFOUND;
+ UNLOCK(&rl->lock);
+ return (result);
+}
+
+static void
+ratelimiter_tick(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg;
+ isc_event_t *p;
+ uint32_t pertic;
+
+ UNUSED(task);
+
+ isc_event_free(&event);
+
+ pertic = rl->pertic;
+ while (pertic != 0) {
+ pertic--;
+ LOCK(&rl->lock);
+ p = ISC_LIST_HEAD(rl->pending);
+ if (p != NULL) {
+ /*
+ * There is work to do. Let's do it after unlocking.
+ */
+ ISC_LIST_UNLINK(rl->pending, p, ev_ratelink);
+ } else {
+ /*
+ * No work left to do. Stop the timer so that we don't
+ * waste resources by having it fire periodically.
+ */
+ result = isc_timer_reset(rl->timer,
+ isc_timertype_inactive,
+ NULL, NULL, false);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ rl->state = isc_ratelimiter_idle;
+ pertic = 0; /* Force the loop to exit. */
+ }
+ UNLOCK(&rl->lock);
+ if (p != NULL) {
+ isc_task_t *evtask = p->ev_sender;
+ isc_task_send(evtask, &p);
+ }
+ INSIST(p == NULL);
+ }
+}
+
+void
+isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) {
+ isc_event_t *ev;
+ isc_task_t *task;
+
+ REQUIRE(rl != NULL);
+
+ LOCK(&rl->lock);
+ rl->state = isc_ratelimiter_shuttingdown;
+ (void)isc_timer_reset(rl->timer, isc_timertype_inactive,
+ NULL, NULL, false);
+ while ((ev = ISC_LIST_HEAD(rl->pending)) != NULL) {
+ ISC_LIST_UNLINK(rl->pending, ev, ev_ratelink);
+ ev->ev_attributes |= ISC_EVENTATTR_CANCELED;
+ task = ev->ev_sender;
+ isc_task_send(task, &ev);
+ }
+ isc_timer_detach(&rl->timer);
+
+ /*
+ * Send an event to our task. The delivery of this event
+ * indicates that no more timer events will be delivered.
+ */
+ ev = &rl->shutdownevent;
+ isc_task_send(rl->task, &ev);
+
+ UNLOCK(&rl->lock);
+}
+
+static void
+ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event) {
+ isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg;
+
+ UNUSED(task);
+
+ isc_ratelimiter_detach(&rl);
+}
+
+static void
+ratelimiter_free(isc_ratelimiter_t *rl) {
+ DESTROYLOCK(&rl->lock);
+ isc_mem_put(rl->mctx, rl, sizeof(*rl));
+}
+
+void
+isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target) {
+
+ REQUIRE(source != NULL);
+ REQUIRE(target != NULL && *target == NULL);
+
+ LOCK(&source->lock);
+ REQUIRE(source->refs > 0);
+ source->refs++;
+ INSIST(source->refs > 0);
+ UNLOCK(&source->lock);
+ *target = source;
+}
+
+void
+isc_ratelimiter_detach(isc_ratelimiter_t **rlp) {
+ isc_ratelimiter_t *rl;
+ bool free_now = false;
+
+ REQUIRE(rlp != NULL && *rlp != NULL);
+
+ rl = *rlp;
+
+ LOCK(&rl->lock);
+ REQUIRE(rl->refs > 0);
+ rl->refs--;
+ if (rl->refs == 0)
+ free_now = true;
+ UNLOCK(&rl->lock);
+
+ if (free_now)
+ ratelimiter_free(rl);
+
+ *rlp = NULL;
+}
+
+isc_result_t
+isc_ratelimiter_stall(isc_ratelimiter_t *rl) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(rl != NULL);
+
+ LOCK(&rl->lock);
+ switch (rl->state) {
+ case isc_ratelimiter_shuttingdown:
+ result = ISC_R_SHUTTINGDOWN;
+ break;
+ case isc_ratelimiter_ratelimited:
+ result = isc_timer_reset(rl->timer, isc_timertype_inactive,
+ NULL, NULL, false);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ /* FALLTHROUGH */
+ case isc_ratelimiter_idle:
+ case isc_ratelimiter_stalled:
+ rl->state = isc_ratelimiter_stalled;
+ break;
+ }
+ UNLOCK(&rl->lock);
+ return (result);
+}
+
+isc_result_t
+isc_ratelimiter_release(isc_ratelimiter_t *rl) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(rl != NULL);
+
+ LOCK(&rl->lock);
+ switch (rl->state) {
+ case isc_ratelimiter_shuttingdown:
+ result = ISC_R_SHUTTINGDOWN;
+ break;
+ case isc_ratelimiter_stalled:
+ if (!ISC_LIST_EMPTY(rl->pending)) {
+ result = isc_timer_reset(rl->timer,
+ isc_timertype_ticker, NULL,
+ &rl->interval, false);
+ if (result == ISC_R_SUCCESS)
+ rl->state = isc_ratelimiter_ratelimited;
+ } else
+ rl->state = isc_ratelimiter_idle;
+ break;
+ case isc_ratelimiter_ratelimited:
+ case isc_ratelimiter_idle:
+ break;
+ }
+ UNLOCK(&rl->lock);
+ return (result);
+}
diff --git a/lib/isc/refcount.c b/lib/isc/refcount.c
new file mode 100644
index 0000000..033af7b
--- /dev/null
+++ b/lib/isc/refcount.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/mutex.h>
+#include <isc/refcount.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_refcount_init(isc_refcount_t *ref, unsigned int n) {
+ REQUIRE(ref != NULL);
+
+ ref->refs = n;
+#if defined(ISC_PLATFORM_USETHREADS) && !defined(ISC_REFCOUNT_HAVEATOMIC)
+ return (isc_mutex_init(&ref->lock));
+#else
+ return (ISC_R_SUCCESS);
+#endif
+}
diff --git a/lib/isc/regex.c b/lib/isc/regex.c
new file mode 100644
index 0000000..63261bb
--- /dev/null
+++ b/lib/isc/regex.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/file.h>
+#include <isc/print.h>
+#include <isc/regex.h>
+#include <isc/string.h>
+
+#if VALREGEX_REPORT_REASON
+#define FAIL(x) do { reason = (x); goto error; } while(0)
+#else
+#define FAIL(x) goto error
+#endif
+
+/*
+ * Validate the regular expression 'C' locale.
+ */
+int
+isc_regex_validate(const char *c) {
+ enum {
+ none, parse_bracket, parse_bound,
+ parse_ce, parse_ec, parse_cc
+ } state = none;
+ /* Well known character classes. */
+ const char *cc[] = {
+ ":alnum:", ":digit:", ":punct:", ":alpha:", ":graph:",
+ ":space:", ":blank:", ":lower:", ":upper:", ":cntrl:",
+ ":print:", ":xdigit:"
+ };
+ bool seen_comma = false;
+ bool seen_high = false;
+ bool seen_char = false;
+ bool seen_ec = false;
+ bool seen_ce = false;
+ bool have_atom = false;
+ int group = 0;
+ int range = 0;
+ int sub = 0;
+ bool empty_ok = false;
+ bool neg = false;
+ bool was_multiple = false;
+ unsigned int low = 0;
+ unsigned int high = 0;
+ const char *ccname = NULL;
+ int range_start = 0;
+#if VALREGEX_REPORT_REASON
+ const char *reason = "";
+#endif
+
+ if (c == NULL || *c == 0)
+ FAIL("empty string");
+
+ while (c != NULL && *c != 0) {
+ switch (state) {
+ case none:
+ switch (*c) {
+ case '\\': /* make literal */
+ ++c;
+ switch (*c) {
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ if ((*c - '0') > sub)
+ FAIL("bad back reference");
+ have_atom = true;
+ was_multiple = false;
+ break;
+ case 0:
+ FAIL("escaped end-of-string");
+ default:
+ goto literal;
+ }
+ ++c;
+ break;
+ case '[': /* bracket start */
+ ++c;
+ neg = false;
+ was_multiple = false;
+ seen_char = false;
+ state = parse_bracket;
+ break;
+ case '{': /* bound start */
+ switch (c[1]) {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9':
+ if (!have_atom)
+ FAIL("no atom");
+ if (was_multiple)
+ FAIL("was multiple");
+ seen_comma = false;
+ seen_high = false;
+ low = high = 0;
+ state = parse_bound;
+ break;
+ default:
+ goto literal;
+ }
+ ++c;
+ have_atom = true;
+ was_multiple = true;
+ break;
+ case '}':
+ goto literal;
+ case '(': /* group start */
+ have_atom = false;
+ was_multiple = false;
+ empty_ok = true;
+ ++group;
+ ++sub;
+ ++c;
+ break;
+ case ')': /* group end */
+ if (group && !have_atom && !empty_ok)
+ FAIL("empty alternative");
+ have_atom = true;
+ was_multiple = false;
+ if (group != 0)
+ --group;
+ ++c;
+ break;
+ case '|': /* alternative seperator */
+ if (!have_atom)
+ FAIL("no atom");
+ have_atom = false;
+ empty_ok = false;
+ was_multiple = false;
+ ++c;
+ break;
+ case '^':
+ case '$':
+ have_atom = true;
+ was_multiple = true;
+ ++c;
+ break;
+ case '+':
+ case '*':
+ case '?':
+ if (was_multiple)
+ FAIL("was multiple");
+ if (!have_atom)
+ FAIL("no atom");
+ have_atom = true;
+ was_multiple = true;
+ ++c;
+ break;
+ case '.':
+ default:
+ literal:
+ have_atom = true;
+ was_multiple = false;
+ ++c;
+ break;
+ }
+ break;
+ case parse_bound:
+ switch (*c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (!seen_comma) {
+ low = low * 10 + *c - '0';
+ if (low > 255)
+ FAIL("lower bound too big");
+ } else {
+ seen_high = true;
+ high = high * 10 + *c - '0';
+ if (high > 255)
+ FAIL("upper bound too big");
+ }
+ ++c;
+ break;
+ case ',':
+ if (seen_comma)
+ FAIL("multiple commas");
+ seen_comma = true;
+ ++c;
+ break;
+ default:
+ case '{':
+ FAIL("non digit/comma");
+ case '}':
+ if (seen_high && low > high)
+ FAIL("bad parse bound");
+ seen_comma = false;
+ state = none;
+ ++c;
+ break;
+ }
+ break;
+ case parse_bracket:
+ switch (*c) {
+ case '^':
+ if (seen_char || neg) goto inside;
+ neg = true;
+ ++c;
+ break;
+ case '-':
+ if (range == 2) goto inside;
+ if (!seen_char) goto inside;
+ if (range == 1)
+ FAIL("bad range");
+ range = 2;
+ ++c;
+ break;
+ case '[':
+ ++c;
+ switch (*c) {
+ case '.': /* collating element */
+ if (range != 0) --range;
+ ++c;
+ state = parse_ce;
+ seen_ce = false;
+ break;
+ case '=': /* equivalence class */
+ if (range == 2)
+ FAIL("equivalence class in range");
+ ++c;
+ state = parse_ec;
+ seen_ec = false;
+ break;
+ case ':': /* character class */
+ if (range == 2)
+ FAIL("character class in range");
+ ccname = c;
+ ++c;
+ state = parse_cc;
+ break;
+ }
+ seen_char = true;
+ break;
+ case ']':
+ if (!c[1] && !seen_char)
+ FAIL("unfinished brace");
+ if (!seen_char)
+ goto inside;
+ ++c;
+ range = 0;
+ have_atom = true;
+ state = none;
+ break;
+ default:
+ inside:
+ seen_char = true;
+ if (range == 2 && (*c & 0xff) < range_start)
+ FAIL("out of order range");
+ if (range != 0)
+ --range;
+ range_start = *c & 0xff;
+ ++c;
+ break;
+ };
+ break;
+ case parse_ce:
+ switch (*c) {
+ case '.':
+ ++c;
+ switch (*c) {
+ case ']':
+ if (!seen_ce)
+ FAIL("empty ce");
+ ++c;
+ state = parse_bracket;
+ break;
+ default:
+ if (seen_ce)
+ range_start = 256;
+ else
+ range_start = '.';
+ seen_ce = true;
+ break;
+ }
+ break;
+ default:
+ if (seen_ce)
+ range_start = 256;
+ else
+ range_start = *c;
+ seen_ce = true;
+ ++c;
+ break;
+ }
+ break;
+ case parse_ec:
+ switch (*c) {
+ case '=':
+ ++c;
+ switch (*c) {
+ case ']':
+ if (!seen_ec)
+ FAIL("no ec");
+ ++c;
+ state = parse_bracket;
+ break;
+ default:
+ seen_ec = true;
+ break;
+ }
+ break;
+ default:
+ seen_ec = true;
+ ++c;
+ break;
+ }
+ break;
+ case parse_cc:
+ switch (*c) {
+ case ':':
+ ++c;
+ switch (*c) {
+ case ']': {
+ unsigned int i;
+ bool found = false;
+ for (i = 0;
+ i < sizeof(cc)/sizeof(*cc);
+ i++)
+ {
+ unsigned int len;
+ len = strlen(cc[i]);
+ if (len !=
+ (unsigned int)(c - ccname))
+ continue;
+ if (strncmp(cc[i], ccname, len))
+ continue;
+ found = true;
+ }
+ if (!found)
+ FAIL("unknown cc");
+ ++c;
+ state = parse_bracket;
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ default:
+ ++c;
+ break;
+ }
+ break;
+ }
+ }
+ if (group != 0)
+ FAIL("group open");
+ if (state != none)
+ FAIL("incomplete");
+ if (!have_atom)
+ FAIL("no atom");
+ return (sub);
+
+ error:
+#if VALREGEX_REPORT_REASON
+ fprintf(stderr, "%s\n", reason);
+#endif
+ return (-1);
+}
diff --git a/lib/isc/region.c b/lib/isc/region.c
new file mode 100644
index 0000000..2f85842
--- /dev/null
+++ b/lib/isc/region.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/region.h>
+#include <isc/util.h>
+
+int
+isc_region_compare(isc_region_t *r1, isc_region_t *r2) {
+ unsigned int l;
+ int result;
+
+ REQUIRE(r1 != NULL);
+ REQUIRE(r2 != NULL);
+
+ l = (r1->length < r2->length) ? r1->length : r2->length;
+
+ if ((result = memcmp(r1->base, r2->base, l)) != 0)
+ return ((result < 0) ? -1 : 1);
+ else
+ return ((r1->length == r2->length) ? 0 :
+ (r1->length < r2->length) ? -1 : 1);
+}
diff --git a/lib/isc/result.c b/lib/isc/result.c
new file mode 100644
index 0000000..a707c32
--- /dev/null
+++ b/lib/isc/result.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <isc/lib.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/resultclass.h>
+#include <isc/util.h>
+
+typedef struct resulttable {
+ unsigned int base;
+ unsigned int last;
+ const char ** text;
+ isc_msgcat_t * msgcat;
+ int set;
+ ISC_LINK(struct resulttable) link;
+} resulttable;
+
+typedef ISC_LIST(resulttable) resulttable_list_t;
+
+static const char *description[ISC_R_NRESULTS] = {
+ "success", /*%< 0 */
+ "out of memory", /*%< 1 */
+ "timed out", /*%< 2 */
+ "no available threads", /*%< 3 */
+ "address not available", /*%< 4 */
+ "address in use", /*%< 5 */
+ "permission denied", /*%< 6 */
+ "no pending connections", /*%< 7 */
+ "network unreachable", /*%< 8 */
+ "host unreachable", /*%< 9 */
+ "network down", /*%< 10 */
+ "host down", /*%< 11 */
+ "connection refused", /*%< 12 */
+ "not enough free resources", /*%< 13 */
+ "end of file", /*%< 14 */
+ "socket already bound", /*%< 15 */
+ "reload", /*%< 16 */
+ "lock busy", /*%< 17 */
+ "already exists", /*%< 18 */
+ "ran out of space", /*%< 19 */
+ "operation canceled", /*%< 20 */
+ "socket is not bound", /*%< 21 */
+ "shutting down", /*%< 22 */
+ "not found", /*%< 23 */
+ "unexpected end of input", /*%< 24 */
+ "failure", /*%< 25 */
+ "I/O error", /*%< 26 */
+ "not implemented", /*%< 27 */
+ "unbalanced parentheses", /*%< 28 */
+ "no more", /*%< 29 */
+ "invalid file", /*%< 30 */
+ "bad base64 encoding", /*%< 31 */
+ "unexpected token", /*%< 32 */
+ "quota reached", /*%< 33 */
+ "unexpected error", /*%< 34 */
+ "already running", /*%< 35 */
+ "ignore", /*%< 36 */
+ "address mask not contiguous", /*%< 37 */
+ "file not found", /*%< 38 */
+ "file already exists", /*%< 39 */
+ "socket is not connected", /*%< 40 */
+ "out of range", /*%< 41 */
+ "out of entropy", /*%< 42 */
+ "invalid use of multicast address", /*%< 43 */
+ "not a file", /*%< 44 */
+ "not a directory", /*%< 45 */
+ "queue is full", /*%< 46 */
+ "address family mismatch", /*%< 47 */
+ "address family not supported", /*%< 48 */
+ "bad hex encoding", /*%< 49 */
+ "too many open files", /*%< 50 */
+ "not blocking", /*%< 51 */
+ "unbalanced quotes", /*%< 52 */
+ "operation in progress", /*%< 53 */
+ "connection reset", /*%< 54 */
+ "soft quota reached", /*%< 55 */
+ "not a valid number", /*%< 56 */
+ "disabled", /*%< 57 */
+ "max size", /*%< 58 */
+ "invalid address format", /*%< 59 */
+ "bad base32 encoding", /*%< 60 */
+ "unset", /*%< 61 */
+ "multiple", /*%< 62 */
+ "would block", /*%< 63 */
+};
+
+static const char *identifier[ISC_R_NRESULTS] = {
+ "ISC_R_SUCCESS",
+ "ISC_R_NOMEMORY",
+ "ISC_R_TIMEDOUT",
+ "ISC_R_NOTHREADS",
+ "ISC_R_ADDRNOTAVAIL",
+ "ISC_R_ADDRINUSE",
+ "ISC_R_NOPERM",
+ "ISC_R_NOCONN",
+ "ISC_R_NETUNREACH",
+ "ISC_R_HOSTUNREACH",
+ "ISC_R_NETDOWN",
+ "ISC_R_HOSTDOWN",
+ "ISC_R_CONNREFUSED",
+ "ISC_R_NORESOURCES",
+ "ISC_R_EOF",
+ "ISC_R_BOUND",
+ "ISC_R_RELOAD",
+ "ISC_R_LOCKBUSY",
+ "ISC_R_EXISTS",
+ "ISC_R_NOSPACE",
+ "ISC_R_CANCELED",
+ "ISC_R_NOTBOUND",
+ "ISC_R_SHUTTINGDOWN",
+ "ISC_R_NOTFOUND",
+ "ISC_R_UNEXPECTEDEND",
+ "ISC_R_FAILURE",
+ "ISC_R_IOERROR",
+ "ISC_R_NOTIMPLEMENTED",
+ "ISC_R_UNBALANCED",
+ "ISC_R_NOMORE",
+ "ISC_R_INVALIDFILE",
+ "ISC_R_BADBASE64",
+ "ISC_R_UNEXPECTEDTOKEN",
+ "ISC_R_QUOTA",
+ "ISC_R_UNEXPECTED",
+ "ISC_R_ALREADYRUNNING",
+ "ISC_R_IGNORE",
+ "ISC_R_MASKNONCONTIG",
+ "ISC_R_FILENOTFOUND",
+ "ISC_R_FILEEXISTS",
+ "ISC_R_NOTCONNECTED",
+ "ISC_R_RANGE",
+ "ISC_R_NOENTROPY",
+ "ISC_R_MULTICAST",
+ "ISC_R_NOTFILE",
+ "ISC_R_NOTDIRECTORY",
+ "ISC_R_QUEUEFULL",
+ "ISC_R_FAMILYMISMATCH",
+ "ISC_R_FAMILYNOSUPPORT",
+ "ISC_R_BADHEX",
+ "ISC_R_TOOMANYOPENFILES",
+ "ISC_R_NOTBLOCKING",
+ "ISC_R_UNBALANCEDQUOTES",
+ "ISC_R_INPROGRESS",
+ "ISC_R_CONNECTIONRESET",
+ "ISC_R_SOFTQUOTA",
+ "ISC_R_BADNUMBER",
+ "ISC_R_DISABLED",
+ "ISC_R_MAXSIZE",
+ "ISC_R_BADADDRESSFORM",
+ "ISC_R_BADBASE32",
+ "ISC_R_UNSET",
+ "ISC_R_MULTIPLE",
+ "ISC_R_WOULDBLOCK",
+};
+
+#define ISC_RESULT_RESULTSET 2
+#define ISC_RESULT_UNAVAILABLESET 3
+
+static isc_once_t once = ISC_ONCE_INIT;
+static resulttable_list_t description_tables;
+static resulttable_list_t identifier_tables;
+static isc_mutex_t lock;
+
+static isc_result_t
+register_table(resulttable_list_t *tables, unsigned int base,
+ unsigned int nresults, const char **text,
+ isc_msgcat_t *msgcat, int set)
+{
+ resulttable *table;
+
+ REQUIRE(base % ISC_RESULTCLASS_SIZE == 0);
+ REQUIRE(nresults <= ISC_RESULTCLASS_SIZE);
+ REQUIRE(text != NULL);
+
+ /*
+ * We use malloc() here because we we want to be able to use
+ * isc_result_totext() even if there is no memory context.
+ */
+ table = malloc(sizeof(*table));
+ if (table == NULL)
+ return (ISC_R_NOMEMORY);
+ table->base = base;
+ table->last = base + nresults - 1;
+ table->text = text;
+ table->msgcat = msgcat;
+ table->set = set;
+ ISC_LINK_INIT(table, link);
+
+ LOCK(&lock);
+
+ ISC_LIST_APPEND(*tables, table, link);
+
+ UNLOCK(&lock);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+initialize_action(void) {
+ isc_result_t result;
+
+ RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
+ ISC_LIST_INIT(description_tables);
+ ISC_LIST_INIT(identifier_tables);
+
+ result = register_table(&description_tables,
+ ISC_RESULTCLASS_ISC, ISC_R_NRESULTS,
+ description, isc_msgcat, ISC_RESULT_RESULTSET);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "register_table() %s: %u",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ result);
+
+ result = register_table(&identifier_tables,
+ ISC_RESULTCLASS_ISC, ISC_R_NRESULTS,
+ identifier, isc_msgcat, ISC_RESULT_RESULTSET);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "register_table() %s: %u",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ result);
+}
+
+static void
+initialize(void) {
+ isc_lib_initmsgcat();
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+static const char *
+isc_result_tomany_helper(resulttable_list_t *tables, isc_result_t result) {
+ resulttable *table;
+ const char *text, *default_text;
+ int index;
+
+ initialize();
+
+ LOCK(&lock);
+
+ text = NULL;
+ for (table = ISC_LIST_HEAD(*tables);
+ table != NULL;
+ table = ISC_LIST_NEXT(table, link)) {
+ if (result >= table->base && result <= table->last) {
+ index = (int)(result - table->base);
+ default_text = table->text[index];
+ /*
+ * Note: we use 'index + 1' as the message number
+ * instead of index because isc_msgcat_get() requires
+ * the message number to be > 0.
+ */
+ text = isc_msgcat_get(table->msgcat, table->set,
+ index + 1, default_text);
+ break;
+ }
+ }
+ if (text == NULL)
+ text = isc_msgcat_get(isc_msgcat, ISC_RESULT_UNAVAILABLESET,
+ 1, "(result code text not available)");
+
+ UNLOCK(&lock);
+
+ return (text);
+}
+
+const char *
+isc_result_totext(isc_result_t result) {
+ return (isc_result_tomany_helper(&description_tables, result));
+}
+
+const char *
+isc_result_toid(isc_result_t result) {
+ return (isc_result_tomany_helper(&identifier_tables, result));
+}
+
+isc_result_t
+isc_result_register(unsigned int base, unsigned int nresults,
+ const char **text, isc_msgcat_t *msgcat, int set)
+{
+ initialize();
+
+ return (register_table(&description_tables, base, nresults, text,
+ msgcat, set));
+}
+
+isc_result_t
+isc_result_registerids(unsigned int base, unsigned int nresults,
+ const char **ids, isc_msgcat_t *msgcat, int set)
+{
+ initialize();
+
+ return (register_table(&identifier_tables, base, nresults, ids,
+ msgcat, set));
+}
diff --git a/lib/isc/rwlock.c b/lib/isc/rwlock.c
new file mode 100644
index 0000000..9533c0f
--- /dev/null
+++ b/lib/isc/rwlock.c
@@ -0,0 +1,982 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <inttypes.h>
+
+#include <isc/atomic.h>
+#include <isc/magic.h>
+#include <isc/msgs.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/rwlock.h>
+#include <isc/util.h>
+
+#define RWLOCK_MAGIC ISC_MAGIC('R', 'W', 'L', 'k')
+#define VALID_RWLOCK(rwl) ISC_MAGIC_VALID(rwl, RWLOCK_MAGIC)
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+#ifndef RWLOCK_DEFAULT_READ_QUOTA
+#define RWLOCK_DEFAULT_READ_QUOTA 4
+#endif
+
+#ifndef RWLOCK_DEFAULT_WRITE_QUOTA
+#define RWLOCK_DEFAULT_WRITE_QUOTA 4
+#endif
+
+#ifndef RWLOCK_MAX_ADAPTIVE_COUNT
+#define RWLOCK_MAX_ADAPTIVE_COUNT 100
+#endif
+
+#if defined(ISC_RWLOCK_USEATOMIC)
+static isc_result_t
+isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+#endif
+
+#ifdef ISC_RWLOCK_TRACE
+#include <stdio.h> /* Required for fprintf/stderr. */
+#include <isc/thread.h> /* Required for isc_thread_self(). */
+
+static void
+print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+ fprintf(stderr,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PRINTLOCK2,
+ "rwlock %p thread %lu %s(%s): "
+ "write_requests=%u, write_completions=%u, "
+ "cnt_and_flag=0x%x, readers_waiting=%u, "
+ "write_granted=%u, write_quota=%u\n"),
+ rwl, isc_thread_self(), operation,
+ (type == isc_rwlocktype_read ?
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_READ, "read") :
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_WRITE, "write")),
+ rwl->write_requests, rwl->write_completions,
+ rwl->cnt_and_flag, rwl->readers_waiting,
+ rwl->write_granted, rwl->write_quota);
+#else
+ fprintf(stderr,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PRINTLOCK,
+ "rwlock %p thread %lu %s(%s): %s, %u active, "
+ "%u granted, %u rwaiting, %u wwaiting\n"),
+ rwl, isc_thread_self(), operation,
+ (type == isc_rwlocktype_read ?
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_READ, "read") :
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_WRITE, "write")),
+ (rwl->type == isc_rwlocktype_read ?
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_READING, "reading") :
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_WRITING, "writing")),
+ rwl->active, rwl->granted,
+ rwl->readers_waiting, rwl->writers_waiting);
+#endif
+}
+#endif /* ISC_RWLOCK_TRACE */
+
+isc_result_t
+isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
+ unsigned int write_quota)
+{
+ isc_result_t result;
+
+ REQUIRE(rwl != NULL);
+
+ /*
+ * In case there's trouble initializing, we zero magic now. If all
+ * goes well, we'll set it to RWLOCK_MAGIC.
+ */
+ rwl->magic = 0;
+
+ rwl->spins = 0;
+#if defined(ISC_RWLOCK_USEATOMIC)
+ rwl->write_requests = 0;
+ rwl->write_completions = 0;
+ rwl->cnt_and_flag = 0;
+ rwl->readers_waiting = 0;
+ rwl->write_granted = 0;
+ if (read_quota != 0) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "read quota is not supported");
+ }
+ if (write_quota == 0)
+ write_quota = RWLOCK_DEFAULT_WRITE_QUOTA;
+ rwl->write_quota = write_quota;
+#else
+ rwl->type = isc_rwlocktype_read;
+ rwl->original = isc_rwlocktype_none;
+ rwl->active = 0;
+ rwl->granted = 0;
+ rwl->readers_waiting = 0;
+ rwl->writers_waiting = 0;
+ if (read_quota == 0)
+ read_quota = RWLOCK_DEFAULT_READ_QUOTA;
+ rwl->read_quota = read_quota;
+ if (write_quota == 0)
+ write_quota = RWLOCK_DEFAULT_WRITE_QUOTA;
+ rwl->write_quota = write_quota;
+#endif
+
+ result = isc_mutex_init(&rwl->lock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = isc_condition_init(&rwl->readable);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init(readable) %s: %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto destroy_lock;
+ }
+ result = isc_condition_init(&rwl->writeable);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init(writeable) %s: %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto destroy_rcond;
+ }
+
+ rwl->magic = RWLOCK_MAGIC;
+
+ return (ISC_R_SUCCESS);
+
+ destroy_rcond:
+ (void)isc_condition_destroy(&rwl->readable);
+ destroy_lock:
+ DESTROYLOCK(&rwl->lock);
+
+ return (result);
+}
+
+void
+isc_rwlock_destroy(isc_rwlock_t *rwl) {
+ REQUIRE(VALID_RWLOCK(rwl));
+
+#if defined(ISC_RWLOCK_USEATOMIC)
+ REQUIRE(rwl->write_requests == rwl->write_completions &&
+ rwl->cnt_and_flag == 0 && rwl->readers_waiting == 0);
+#else
+ LOCK(&rwl->lock);
+ REQUIRE(rwl->active == 0 &&
+ rwl->readers_waiting == 0 &&
+ rwl->writers_waiting == 0);
+ UNLOCK(&rwl->lock);
+#endif
+
+ rwl->magic = 0;
+ (void)isc_condition_destroy(&rwl->readable);
+ (void)isc_condition_destroy(&rwl->writeable);
+ DESTROYLOCK(&rwl->lock);
+}
+
+#if defined(ISC_RWLOCK_USEATOMIC)
+
+/*
+ * When some architecture-dependent atomic operations are available,
+ * rwlock can be more efficient than the generic algorithm defined below.
+ * The basic algorithm is described in the following URL:
+ * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
+ *
+ * The key is to use the following integer variables modified atomically:
+ * write_requests, write_completions, and cnt_and_flag.
+ *
+ * write_requests and write_completions act as a waiting queue for writers
+ * in order to ensure the FIFO order. Both variables begin with the initial
+ * value of 0. When a new writer tries to get a write lock, it increments
+ * write_requests and gets the previous value of the variable as a "ticket".
+ * When write_completions reaches the ticket number, the new writer can start
+ * writing. When the writer completes its work, it increments
+ * write_completions so that another new writer can start working. If the
+ * write_requests is not equal to write_completions, it means a writer is now
+ * working or waiting. In this case, a new readers cannot start reading, or
+ * in other words, this algorithm basically prefers writers.
+ *
+ * cnt_and_flag is a "lock" shared by all readers and writers. This integer
+ * variable is a kind of structure with two members: writer_flag (1 bit) and
+ * reader_count (31 bits). The writer_flag shows whether a writer is working,
+ * and the reader_count shows the number of readers currently working or almost
+ * ready for working. A writer who has the current "ticket" tries to get the
+ * lock by exclusively setting the writer_flag to 1, provided that the whole
+ * 32-bit is 0 (meaning no readers or writers working). On the other hand,
+ * a new reader tries to increment the "reader_count" field provided that
+ * the writer_flag is 0 (meaning there is no writer working).
+ *
+ * If some of the above operations fail, the reader or the writer sleeps
+ * until the related condition changes. When a working reader or writer
+ * completes its work, some readers or writers are sleeping, and the condition
+ * that suspended the reader or writer has changed, it wakes up the sleeping
+ * readers or writers.
+ *
+ * As already noted, this algorithm basically prefers writers. In order to
+ * prevent readers from starving, however, the algorithm also introduces the
+ * "writer quota" (Q). When Q consecutive writers have completed their work,
+ * suspending readers, the last writer will wake up the readers, even if a new
+ * writer is waiting.
+ *
+ * Implementation specific note: due to the combination of atomic operations
+ * and a mutex lock, ordering between the atomic operation and locks can be
+ * very sensitive in some cases. In particular, it is generally very important
+ * to check the atomic variable that requires a reader or writer to sleep after
+ * locking the mutex and before actually sleeping; otherwise, it could be very
+ * likely to cause a deadlock. For example, assume "var" is a variable
+ * atomically modified, then the corresponding code would be:
+ * if (var == need_sleep) {
+ * LOCK(lock);
+ * if (var == need_sleep)
+ * WAIT(cond, lock);
+ * UNLOCK(lock);
+ * }
+ * The second check is important, since "var" is protected by the atomic
+ * operation, not by the mutex, and can be changed just before sleeping.
+ * (The first "if" could be omitted, but this is also important in order to
+ * make the code efficient by avoiding the use of the mutex unless it is
+ * really necessary.)
+ */
+
+#define WRITER_ACTIVE 0x1
+#define READER_INCR 0x2
+
+static isc_result_t
+isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ int32_t cntflag;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PRELOCK, "prelock"), rwl, type);
+#endif
+
+ if (type == isc_rwlocktype_read) {
+ if (rwl->write_requests != rwl->write_completions) {
+ /* there is a waiting or active writer */
+ LOCK(&rwl->lock);
+ if (rwl->write_requests != rwl->write_completions) {
+ rwl->readers_waiting++;
+ WAIT(&rwl->readable, &rwl->lock);
+ rwl->readers_waiting--;
+ }
+ UNLOCK(&rwl->lock);
+ }
+
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ cntflag = atomic_fetch_add_explicit(&rwl->cnt_and_flag,
+ READER_INCR,
+ memory_order_relaxed);
+#else
+ cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+#endif
+ POST(cntflag);
+ while (1) {
+ if ((rwl->cnt_and_flag & WRITER_ACTIVE) == 0)
+ break;
+
+ /* A writer is still working */
+ LOCK(&rwl->lock);
+ rwl->readers_waiting++;
+ if ((rwl->cnt_and_flag & WRITER_ACTIVE) != 0)
+ WAIT(&rwl->readable, &rwl->lock);
+ rwl->readers_waiting--;
+ UNLOCK(&rwl->lock);
+
+ /*
+ * Typically, the reader should be able to get a lock
+ * at this stage:
+ * (1) there should have been no pending writer when
+ * the reader was trying to increment the
+ * counter; otherwise, the writer should be in
+ * the waiting queue, preventing the reader from
+ * proceeding to this point.
+ * (2) once the reader increments the counter, no
+ * more writer can get a lock.
+ * Still, it is possible another writer can work at
+ * this point, e.g. in the following scenario:
+ * A previous writer unlocks the writer lock.
+ * This reader proceeds to point (1).
+ * A new writer appears, and gets a new lock before
+ * the reader increments the counter.
+ * The reader then increments the counter.
+ * The previous writer notices there is a waiting
+ * reader who is almost ready, and wakes it up.
+ * So, the reader needs to confirm whether it can now
+ * read explicitly (thus we loop). Note that this is
+ * not an infinite process, since the reader has
+ * incremented the counter at this point.
+ */
+ }
+
+ /*
+ * If we are temporarily preferred to writers due to the writer
+ * quota, reset the condition (race among readers doesn't
+ * matter).
+ */
+ rwl->write_granted = 0;
+ } else {
+ int32_t prev_writer;
+
+ /* enter the waiting queue, and wait for our turn */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ prev_writer = atomic_fetch_add_explicit(&rwl->write_requests, 1,
+ memory_order_relaxed);
+#else
+ prev_writer = isc_atomic_xadd(&rwl->write_requests, 1);
+#endif
+ while (rwl->write_completions != prev_writer) {
+ LOCK(&rwl->lock);
+ if (rwl->write_completions != prev_writer) {
+ WAIT(&rwl->writeable, &rwl->lock);
+ UNLOCK(&rwl->lock);
+ continue;
+ }
+ UNLOCK(&rwl->lock);
+ break;
+ }
+
+ while (1) {
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ int_fast32_t cntflag2 = 0;
+ atomic_compare_exchange_strong_explicit
+ (&rwl->cnt_and_flag, &cntflag2, WRITER_ACTIVE,
+ memory_order_relaxed, memory_order_relaxed);
+#else
+ int32_t cntflag2;
+ cntflag2 = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0,
+ WRITER_ACTIVE);
+#endif
+
+ if (cntflag2 == 0)
+ break;
+
+ /* Another active reader or writer is working. */
+ LOCK(&rwl->lock);
+ if (rwl->cnt_and_flag != 0)
+ WAIT(&rwl->writeable, &rwl->lock);
+ UNLOCK(&rwl->lock);
+ }
+
+ INSIST((rwl->cnt_and_flag & WRITER_ACTIVE) != 0);
+ rwl->write_granted++;
+ }
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_POSTLOCK, "postlock"), rwl, type);
+#endif
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ int32_t cnt = 0;
+ int32_t max_cnt = rwl->spins * 2 + 10;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ if (max_cnt > RWLOCK_MAX_ADAPTIVE_COUNT)
+ max_cnt = RWLOCK_MAX_ADAPTIVE_COUNT;
+
+ do {
+ if (cnt++ >= max_cnt) {
+ result = isc__rwlock_lock(rwl, type);
+ break;
+ }
+#ifdef ISC_PLATFORM_BUSYWAITNOP
+ ISC_PLATFORM_BUSYWAITNOP;
+#endif
+ } while (isc_rwlock_trylock(rwl, type) != ISC_R_SUCCESS);
+
+ rwl->spins += (cnt - rwl->spins) / 8;
+
+ return (result);
+}
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ int32_t cntflag;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PRELOCK, "prelock"), rwl, type);
+#endif
+
+ if (type == isc_rwlocktype_read) {
+ /* If a writer is waiting or working, we fail. */
+ if (rwl->write_requests != rwl->write_completions)
+ return (ISC_R_LOCKBUSY);
+
+ /* Otherwise, be ready for reading. */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ cntflag = atomic_fetch_add_explicit(&rwl->cnt_and_flag,
+ READER_INCR,
+ memory_order_relaxed);
+#else
+ cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+#endif
+ if ((cntflag & WRITER_ACTIVE) != 0) {
+ /*
+ * A writer is working. We lose, and cancel the read
+ * request.
+ */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ cntflag = atomic_fetch_sub_explicit
+ (&rwl->cnt_and_flag, READER_INCR,
+ memory_order_relaxed);
+#else
+ cntflag = isc_atomic_xadd(&rwl->cnt_and_flag,
+ -READER_INCR);
+#endif
+ /*
+ * If no other readers are waiting and we've suspended
+ * new writers in this short period, wake them up.
+ */
+ if (cntflag == READER_INCR &&
+ rwl->write_completions != rwl->write_requests) {
+ LOCK(&rwl->lock);
+ BROADCAST(&rwl->writeable);
+ UNLOCK(&rwl->lock);
+ }
+
+ return (ISC_R_LOCKBUSY);
+ }
+ } else {
+ /* Try locking without entering the waiting queue. */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ int_fast32_t zero = 0;
+ if (!atomic_compare_exchange_strong_explicit
+ (&rwl->cnt_and_flag, &zero, WRITER_ACTIVE,
+ memory_order_relaxed, memory_order_relaxed))
+ return (ISC_R_LOCKBUSY);
+#else
+ cntflag = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0,
+ WRITER_ACTIVE);
+ if (cntflag != 0)
+ return (ISC_R_LOCKBUSY);
+#endif
+
+ /*
+ * XXXJT: jump into the queue, possibly breaking the writer
+ * order.
+ */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ atomic_fetch_sub_explicit(&rwl->write_completions, 1,
+ memory_order_relaxed);
+#else
+ (void)isc_atomic_xadd(&rwl->write_completions, -1);
+#endif
+
+ rwl->write_granted++;
+ }
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_POSTLOCK, "postlock"), rwl, type);
+#endif
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
+ REQUIRE(VALID_RWLOCK(rwl));
+
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ {
+ int_fast32_t reader_incr = READER_INCR;
+
+ /* Try to acquire write access. */
+ atomic_compare_exchange_strong_explicit
+ (&rwl->cnt_and_flag, &reader_incr, WRITER_ACTIVE,
+ memory_order_relaxed, memory_order_relaxed);
+ /*
+ * There must have been no writer, and there must have
+ * been at least one reader.
+ */
+ INSIST((reader_incr & WRITER_ACTIVE) == 0 &&
+ (reader_incr & ~WRITER_ACTIVE) != 0);
+
+ if (reader_incr == READER_INCR) {
+ /*
+ * We are the only reader and have been upgraded.
+ * Now jump into the head of the writer waiting queue.
+ */
+ atomic_fetch_sub_explicit(&rwl->write_completions, 1,
+ memory_order_relaxed);
+ } else
+ return (ISC_R_LOCKBUSY);
+
+ }
+#else
+ {
+ int32_t prevcnt;
+
+ /* Try to acquire write access. */
+ prevcnt = isc_atomic_cmpxchg(&rwl->cnt_and_flag,
+ READER_INCR, WRITER_ACTIVE);
+ /*
+ * There must have been no writer, and there must have
+ * been at least one reader.
+ */
+ INSIST((prevcnt & WRITER_ACTIVE) == 0 &&
+ (prevcnt & ~WRITER_ACTIVE) != 0);
+
+ if (prevcnt == READER_INCR) {
+ /*
+ * We are the only reader and have been upgraded.
+ * Now jump into the head of the writer waiting queue.
+ */
+ (void)isc_atomic_xadd(&rwl->write_completions, -1);
+ } else
+ return (ISC_R_LOCKBUSY);
+ }
+#endif
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl) {
+ int32_t prev_readers;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ {
+ /* Become an active reader. */
+ prev_readers = atomic_fetch_add_explicit(&rwl->cnt_and_flag,
+ READER_INCR,
+ memory_order_relaxed);
+ /* We must have been a writer. */
+ INSIST((prev_readers & WRITER_ACTIVE) != 0);
+
+ /* Complete write */
+ atomic_fetch_sub_explicit(&rwl->cnt_and_flag, WRITER_ACTIVE,
+ memory_order_relaxed);
+ atomic_fetch_add_explicit(&rwl->write_completions, 1,
+ memory_order_relaxed);
+ }
+#else
+ {
+ /* Become an active reader. */
+ prev_readers = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+ /* We must have been a writer. */
+ INSIST((prev_readers & WRITER_ACTIVE) != 0);
+
+ /* Complete write */
+ (void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE);
+ (void)isc_atomic_xadd(&rwl->write_completions, 1);
+ }
+#endif
+
+ /* Resume other readers */
+ LOCK(&rwl->lock);
+ if (rwl->readers_waiting > 0)
+ BROADCAST(&rwl->readable);
+ UNLOCK(&rwl->lock);
+}
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ int32_t prev_cnt;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PREUNLOCK, "preunlock"), rwl, type);
+#endif
+
+ if (type == isc_rwlocktype_read) {
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ prev_cnt = atomic_fetch_sub_explicit(&rwl->cnt_and_flag,
+ READER_INCR,
+ memory_order_relaxed);
+#else
+ prev_cnt = isc_atomic_xadd(&rwl->cnt_and_flag, -READER_INCR);
+#endif
+ /*
+ * If we're the last reader and any writers are waiting, wake
+ * them up. We need to wake up all of them to ensure the
+ * FIFO order.
+ */
+ if (prev_cnt == READER_INCR &&
+ rwl->write_completions != rwl->write_requests) {
+ LOCK(&rwl->lock);
+ BROADCAST(&rwl->writeable);
+ UNLOCK(&rwl->lock);
+ }
+ } else {
+ bool wakeup_writers = true;
+
+ /*
+ * Reset the flag, and (implicitly) tell other writers
+ * we are done.
+ */
+#if defined(ISC_RWLOCK_USESTDATOMIC)
+ atomic_fetch_sub_explicit(&rwl->cnt_and_flag, WRITER_ACTIVE,
+ memory_order_relaxed);
+ atomic_fetch_add_explicit(&rwl->write_completions, 1,
+ memory_order_relaxed);
+#else
+ (void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE);
+ (void)isc_atomic_xadd(&rwl->write_completions, 1);
+#endif
+
+ if (rwl->write_granted >= rwl->write_quota ||
+ rwl->write_requests == rwl->write_completions ||
+ (rwl->cnt_and_flag & ~WRITER_ACTIVE) != 0) {
+ /*
+ * We have passed the write quota, no writer is
+ * waiting, or some readers are almost ready, pending
+ * possible writers. Note that the last case can
+ * happen even if write_requests != write_completions
+ * (which means a new writer in the queue), so we need
+ * to catch the case explicitly.
+ */
+ LOCK(&rwl->lock);
+ if (rwl->readers_waiting > 0) {
+ wakeup_writers = false;
+ BROADCAST(&rwl->readable);
+ }
+ UNLOCK(&rwl->lock);
+ }
+
+ if (rwl->write_requests != rwl->write_completions &&
+ wakeup_writers) {
+ LOCK(&rwl->lock);
+ BROADCAST(&rwl->writeable);
+ UNLOCK(&rwl->lock);
+ }
+ }
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_POSTUNLOCK, "postunlock"),
+ rwl, type);
+#endif
+
+ return (ISC_R_SUCCESS);
+}
+
+#else /* ISC_RWLOCK_USEATOMIC */
+
+static isc_result_t
+doit(isc_rwlock_t *rwl, isc_rwlocktype_t type, bool nonblock) {
+ bool skip = false;
+ bool done = false;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+ LOCK(&rwl->lock);
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PRELOCK, "prelock"), rwl, type);
+#endif
+
+ if (type == isc_rwlocktype_read) {
+ if (rwl->readers_waiting != 0)
+ skip = true;
+ while (!done) {
+ if (!skip &&
+ ((rwl->active == 0 ||
+ (rwl->type == isc_rwlocktype_read &&
+ (rwl->writers_waiting == 0 ||
+ rwl->granted < rwl->read_quota)))))
+ {
+ rwl->type = isc_rwlocktype_read;
+ rwl->active++;
+ rwl->granted++;
+ done = true;
+ } else if (nonblock) {
+ result = ISC_R_LOCKBUSY;
+ done = true;
+ } else {
+ skip = false;
+ rwl->readers_waiting++;
+ WAIT(&rwl->readable, &rwl->lock);
+ rwl->readers_waiting--;
+ }
+ }
+ } else {
+ if (rwl->writers_waiting != 0)
+ skip = true;
+ while (!done) {
+ if (!skip && rwl->active == 0) {
+ rwl->type = isc_rwlocktype_write;
+ rwl->active = 1;
+ rwl->granted++;
+ done = true;
+ } else if (nonblock) {
+ result = ISC_R_LOCKBUSY;
+ done = true;
+ } else {
+ skip = false;
+ rwl->writers_waiting++;
+ WAIT(&rwl->writeable, &rwl->lock);
+ rwl->writers_waiting--;
+ }
+ }
+ }
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_POSTLOCK, "postlock"), rwl, type);
+#endif
+
+ UNLOCK(&rwl->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ int32_t cnt = 0;
+ int32_t max_cnt = rwl->spins * 2 + 10;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ if (max_cnt > RWLOCK_MAX_ADAPTIVE_COUNT)
+ max_cnt = RWLOCK_MAX_ADAPTIVE_COUNT;
+
+ do {
+ if (cnt++ >= max_cnt) {
+ result = doit(rwl, type, false);
+ break;
+ }
+#ifdef ISC_PLATFORM_BUSYWAITNOP
+ ISC_PLATFORM_BUSYWAITNOP;
+#endif
+ } while (doit(rwl, type, true) != ISC_R_SUCCESS);
+
+ rwl->spins += (cnt - rwl->spins) / 8;
+
+ return (result);
+}
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ return (doit(rwl, type, true));
+}
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+ LOCK(&rwl->lock);
+ REQUIRE(rwl->type == isc_rwlocktype_read);
+ REQUIRE(rwl->active != 0);
+
+ /* If we are the only reader then succeed. */
+ if (rwl->active == 1) {
+ rwl->original = (rwl->original == isc_rwlocktype_none) ?
+ isc_rwlocktype_read : isc_rwlocktype_none;
+ rwl->type = isc_rwlocktype_write;
+ } else
+ result = ISC_R_LOCKBUSY;
+
+ UNLOCK(&rwl->lock);
+ return (result);
+}
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl) {
+
+ REQUIRE(VALID_RWLOCK(rwl));
+ LOCK(&rwl->lock);
+ REQUIRE(rwl->type == isc_rwlocktype_write);
+ REQUIRE(rwl->active == 1);
+
+ rwl->type = isc_rwlocktype_read;
+ rwl->original = (rwl->original == isc_rwlocktype_none) ?
+ isc_rwlocktype_write : isc_rwlocktype_none;
+ /*
+ * Resume processing any read request that were blocked when
+ * we upgraded.
+ */
+ if (rwl->original == isc_rwlocktype_none &&
+ (rwl->writers_waiting == 0 || rwl->granted < rwl->read_quota) &&
+ rwl->readers_waiting > 0)
+ BROADCAST(&rwl->readable);
+
+ UNLOCK(&rwl->lock);
+}
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+
+ REQUIRE(VALID_RWLOCK(rwl));
+ LOCK(&rwl->lock);
+ REQUIRE(rwl->type == type);
+
+ UNUSED(type);
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PREUNLOCK, "preunlock"), rwl, type);
+#endif
+
+ INSIST(rwl->active > 0);
+ rwl->active--;
+ if (rwl->active == 0) {
+ if (rwl->original != isc_rwlocktype_none) {
+ rwl->type = rwl->original;
+ rwl->original = isc_rwlocktype_none;
+ }
+ if (rwl->type == isc_rwlocktype_read) {
+ rwl->granted = 0;
+ if (rwl->writers_waiting > 0) {
+ rwl->type = isc_rwlocktype_write;
+ SIGNAL(&rwl->writeable);
+ } else if (rwl->readers_waiting > 0) {
+ /* Does this case ever happen? */
+ BROADCAST(&rwl->readable);
+ }
+ } else {
+ if (rwl->readers_waiting > 0) {
+ if (rwl->writers_waiting > 0 &&
+ rwl->granted < rwl->write_quota) {
+ SIGNAL(&rwl->writeable);
+ } else {
+ rwl->granted = 0;
+ rwl->type = isc_rwlocktype_read;
+ BROADCAST(&rwl->readable);
+ }
+ } else if (rwl->writers_waiting > 0) {
+ rwl->granted = 0;
+ SIGNAL(&rwl->writeable);
+ } else {
+ rwl->granted = 0;
+ }
+ }
+ }
+ INSIST(rwl->original == isc_rwlocktype_none);
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_POSTUNLOCK, "postunlock"),
+ rwl, type);
+#endif
+
+ UNLOCK(&rwl->lock);
+
+ return (ISC_R_SUCCESS);
+}
+
+#endif /* ISC_RWLOCK_USEATOMIC */
+#else /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
+ unsigned int write_quota)
+{
+ REQUIRE(rwl != NULL);
+
+ UNUSED(read_quota);
+ UNUSED(write_quota);
+
+ rwl->type = isc_rwlocktype_read;
+ rwl->active = 0;
+ rwl->magic = RWLOCK_MAGIC;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ REQUIRE(VALID_RWLOCK(rwl));
+
+ if (type == isc_rwlocktype_read) {
+ if (rwl->type != isc_rwlocktype_read && rwl->active != 0)
+ return (ISC_R_LOCKBUSY);
+ rwl->type = isc_rwlocktype_read;
+ rwl->active++;
+ } else {
+ if (rwl->active != 0)
+ return (ISC_R_LOCKBUSY);
+ rwl->type = isc_rwlocktype_write;
+ rwl->active = 1;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ return (isc_rwlock_lock(rwl, type));
+}
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+ REQUIRE(rwl->type == isc_rwlocktype_read);
+ REQUIRE(rwl->active != 0);
+
+ /* If we are the only reader then succeed. */
+ if (rwl->active == 1)
+ rwl->type = isc_rwlocktype_write;
+ else
+ result = ISC_R_LOCKBUSY;
+ return (result);
+}
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl) {
+
+ REQUIRE(VALID_RWLOCK(rwl));
+ REQUIRE(rwl->type == isc_rwlocktype_write);
+ REQUIRE(rwl->active == 1);
+
+ rwl->type = isc_rwlocktype_read;
+}
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ REQUIRE(VALID_RWLOCK(rwl));
+ REQUIRE(rwl->type == type);
+
+ UNUSED(type);
+
+ INSIST(rwl->active > 0);
+ rwl->active--;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_rwlock_destroy(isc_rwlock_t *rwl) {
+ REQUIRE(rwl != NULL);
+ REQUIRE(rwl->active == 0);
+ rwl->magic = 0;
+}
+
+#endif /* ISC_PLATFORM_USETHREADS */
diff --git a/lib/isc/safe.c b/lib/isc/safe.c
new file mode 100644
index 0000000..7a464b6
--- /dev/null
+++ b/lib/isc/safe.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/safe.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#ifdef _MSC_VER
+#pragma optimize("", off)
+#endif
+
+bool
+isc_safe_memequal(const void *s1, const void *s2, size_t n) {
+ uint8_t acc = 0;
+
+ if (n != 0U) {
+ const uint8_t *p1 = s1, *p2 = s2;
+
+ do {
+ acc |= *p1++ ^ *p2++;
+ } while (--n != 0U);
+ }
+ return (acc == 0);
+}
+
+
+int
+isc_safe_memcompare(const void *b1, const void *b2, size_t len) {
+ const unsigned char *p1 = b1, *p2 = b2;
+ size_t i;
+ int res = 0, done = 0;
+
+ for (i = 0; i < len; i++) {
+ /* lt is -1 if p1[i] < p2[i]; else 0. */
+ int lt = (p1[i] - p2[i]) >> CHAR_BIT;
+
+ /* gt is -1 if p1[i] > p2[i]; else 0. */
+ int gt = (p2[i] - p1[i]) >> CHAR_BIT;
+
+ /* cmp is 1 if p1[i] > p2[i]; -1 if p1[i] < p2[i]; else 0. */
+ int cmp = lt - gt;
+
+ /* set res = cmp if !done. */
+ res |= cmp & ~done;
+
+ /* set done if p1[i] != p2[i]. */
+ done |= lt | gt;
+ }
+
+ return (res);
+}
+
+void
+isc_safe_memwipe(void *ptr, size_t len) {
+ if (ISC_UNLIKELY(ptr == NULL || len == 0))
+ return;
+
+#ifdef WIN32
+ SecureZeroMemory(ptr, len);
+#elif HAVE_EXPLICIT_BZERO
+ explicit_bzero(ptr, len);
+#else
+ memset(ptr, 0, len);
+#endif
+}
diff --git a/lib/isc/serial.c b/lib/isc/serial.c
new file mode 100644
index 0000000..860a0c6
--- /dev/null
+++ b/lib/isc/serial.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/serial.h>
+
+bool
+isc_serial_lt(uint32_t a, uint32_t b) {
+ /*
+ * Undefined => false
+ */
+ if (a == (b ^ 0x80000000U))
+ return (false);
+ return (((int32_t)(a - b) < 0) ? true : false);
+}
+
+bool
+isc_serial_gt(uint32_t a, uint32_t b) {
+ return (((int32_t)(a - b) > 0) ? true : false);
+}
+
+bool
+isc_serial_le(uint32_t a, uint32_t b) {
+ return ((a == b) ? true : isc_serial_lt(a, b));
+}
+
+bool
+isc_serial_ge(uint32_t a, uint32_t b) {
+ return ((a == b) ? true : isc_serial_gt(a, b));
+}
+
+bool
+isc_serial_eq(uint32_t a, uint32_t b) {
+ return ((a == b) ? true : false);
+}
+
+bool
+isc_serial_ne(uint32_t a, uint32_t b) {
+ return ((a != b) ? true : false);
+}
diff --git a/lib/isc/sha1.c b/lib/isc/sha1.c
new file mode 100644
index 0000000..c0c89b4
--- /dev/null
+++ b/lib/isc/sha1.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id$ */
+
+/* $NetBSD: sha1.c,v 1.5 2000/01/22 22:19:14 mycroft Exp $ */
+/* $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */
+
+/*! \file
+ * SHA-1 in C
+ * \author By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ * \verbatim
+ * Test Vectors (from FIPS PUB 180-1)
+ * "abc"
+ * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * A million repetitions of "a"
+ * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+ * \endverbatim
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+
+#include <isc/assertions.h>
+#include <isc/platform.h>
+#include <isc/safe.h>
+#include <isc/sha1.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#if PKCS11CRYPTO
+#include <pk11/internal.h>
+#include <pk11/pk11.h>
+#endif
+
+#ifdef ISC_PLATFORM_OPENSSLHASH
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#define EVP_MD_CTX_new() &(context->_ctx)
+#define EVP_MD_CTX_free(ptr) EVP_MD_CTX_cleanup(ptr)
+#endif
+
+void
+isc_sha1_init(isc_sha1_t *context)
+{
+ INSIST(context != NULL);
+
+ context->ctx = EVP_MD_CTX_new();
+ RUNTIME_CHECK(context->ctx != NULL);
+ if (EVP_DigestInit(context->ctx, EVP_sha1()) != 1) {
+ FATAL_ERROR(__FILE__, __LINE__, "Cannot initialize SHA1.");
+ }
+}
+
+void
+isc_sha1_invalidate(isc_sha1_t *context) {
+ EVP_MD_CTX_free(context->ctx);
+ context->ctx = NULL;
+}
+
+void
+isc_sha1_update(isc_sha1_t *context, const unsigned char *data,
+ unsigned int len)
+{
+ INSIST(context != 0);
+ INSIST(context->ctx != 0);
+ INSIST(data != 0);
+
+ RUNTIME_CHECK(EVP_DigestUpdate(context->ctx,
+ (const void *) data,
+ (size_t) len) == 1);
+}
+
+void
+isc_sha1_final(isc_sha1_t *context, unsigned char *digest) {
+ INSIST(digest != 0);
+ INSIST(context != 0);
+ INSIST(context->ctx != 0);
+
+ RUNTIME_CHECK(EVP_DigestFinal(context->ctx, digest, NULL) == 1);
+ EVP_MD_CTX_free(context->ctx);
+ context->ctx = NULL;
+}
+
+#elif PKCS11CRYPTO
+
+void
+isc_sha1_init(isc_sha1_t *ctx) {
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA_1, NULL, 0 };
+
+ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
+}
+
+void
+isc_sha1_invalidate(isc_sha1_t *ctx) {
+ CK_BYTE garbage[ISC_SHA1_DIGESTLENGTH];
+ CK_ULONG len = ISC_SHA1_DIGESTLENGTH;
+
+ if (ctx->handle == NULL)
+ return;
+ (void) pkcs_C_DigestFinal(ctx->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ pk11_return_session(ctx);
+}
+
+void
+isc_sha1_update(isc_sha1_t *ctx, const unsigned char *buf, unsigned int len) {
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ DE_CONST(buf, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (ctx->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_sha1_final(isc_sha1_t *ctx, unsigned char *digest) {
+ CK_RV rv;
+ CK_ULONG len = ISC_SHA1_DIGESTLENGTH;
+
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (ctx->session, (CK_BYTE_PTR) digest, &len));
+ pk11_return_session(ctx);
+}
+
+#else
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/*@{*/
+/*!
+ * blk0() and blk() perform the initial expand.
+ * I got the idea of expanding during the round function from SSLeay
+ */
+#if !defined(WORDS_BIGENDIAN)
+# define blk0(i) \
+ (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) \
+ | (rol(block->l[i], 8) & 0x00FF00FF))
+#else
+# define blk0(i) block->l[i]
+#endif
+#define blk(i) \
+ (block->l[i & 15] = rol(block->l[(i + 13) & 15] \
+ ^ block->l[(i + 8) & 15] \
+ ^ block->l[(i + 2) & 15] \
+ ^ block->l[i & 15], 1))
+
+/*@}*/
+/*@{*/
+/*!
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
+ */
+#define R0(v,w,x,y,z,i) \
+ z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
+ w = rol(w, 30);
+#define R1(v,w,x,y,z,i) \
+ z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
+ w = rol(w, 30);
+#define R2(v,w,x,y,z,i) \
+ z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
+ w = rol(w, 30);
+#define R3(v,w,x,y,z,i) \
+ z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
+ w = rol(w, 30);
+#define R4(v,w,x,y,z,i) \
+ z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
+ w = rol(w, 30);
+
+/*@}*/
+
+typedef union {
+ unsigned char c[64];
+ unsigned int l[16];
+} CHAR64LONG16;
+
+#ifdef __sparc_v9__
+static void do_R01(uint32_t *a, uint32_t *b, uint32_t *c,
+ uint32_t *d, uint32_t *e, CHAR64LONG16 *);
+static void do_R2(uint32_t *a, uint32_t *b, uint32_t *c,
+ uint32_t *d, uint32_t *e, CHAR64LONG16 *);
+static void do_R3(uint32_t *a, uint32_t *b, uint32_t *c,
+ uint32_t *d, uint32_t *e, CHAR64LONG16 *);
+static void do_R4(uint32_t *a, uint32_t *b, uint32_t *c,
+ uint32_t *d, uint32_t *e, CHAR64LONG16 *);
+
+#define nR0(v,w,x,y,z,i) R0(*v,*w,*x,*y,*z,i)
+#define nR1(v,w,x,y,z,i) R1(*v,*w,*x,*y,*z,i)
+#define nR2(v,w,x,y,z,i) R2(*v,*w,*x,*y,*z,i)
+#define nR3(v,w,x,y,z,i) R3(*v,*w,*x,*y,*z,i)
+#define nR4(v,w,x,y,z,i) R4(*v,*w,*x,*y,*z,i)
+
+static void
+do_R01(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d,
+ uint32_t *e, CHAR64LONG16 *block)
+{
+ nR0(a,b,c,d,e, 0); nR0(e,a,b,c,d, 1); nR0(d,e,a,b,c, 2);
+ nR0(c,d,e,a,b, 3); nR0(b,c,d,e,a, 4); nR0(a,b,c,d,e, 5);
+ nR0(e,a,b,c,d, 6); nR0(d,e,a,b,c, 7); nR0(c,d,e,a,b, 8);
+ nR0(b,c,d,e,a, 9); nR0(a,b,c,d,e,10); nR0(e,a,b,c,d,11);
+ nR0(d,e,a,b,c,12); nR0(c,d,e,a,b,13); nR0(b,c,d,e,a,14);
+ nR0(a,b,c,d,e,15); nR1(e,a,b,c,d,16); nR1(d,e,a,b,c,17);
+ nR1(c,d,e,a,b,18); nR1(b,c,d,e,a,19);
+}
+
+static void
+do_R2(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d,
+ uint32_t *e, CHAR64LONG16 *block)
+{
+ nR2(a,b,c,d,e,20); nR2(e,a,b,c,d,21); nR2(d,e,a,b,c,22);
+ nR2(c,d,e,a,b,23); nR2(b,c,d,e,a,24); nR2(a,b,c,d,e,25);
+ nR2(e,a,b,c,d,26); nR2(d,e,a,b,c,27); nR2(c,d,e,a,b,28);
+ nR2(b,c,d,e,a,29); nR2(a,b,c,d,e,30); nR2(e,a,b,c,d,31);
+ nR2(d,e,a,b,c,32); nR2(c,d,e,a,b,33); nR2(b,c,d,e,a,34);
+ nR2(a,b,c,d,e,35); nR2(e,a,b,c,d,36); nR2(d,e,a,b,c,37);
+ nR2(c,d,e,a,b,38); nR2(b,c,d,e,a,39);
+}
+
+static void
+do_R3(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d,
+ uint32_t *e, CHAR64LONG16 *block)
+{
+ nR3(a,b,c,d,e,40); nR3(e,a,b,c,d,41); nR3(d,e,a,b,c,42);
+ nR3(c,d,e,a,b,43); nR3(b,c,d,e,a,44); nR3(a,b,c,d,e,45);
+ nR3(e,a,b,c,d,46); nR3(d,e,a,b,c,47); nR3(c,d,e,a,b,48);
+ nR3(b,c,d,e,a,49); nR3(a,b,c,d,e,50); nR3(e,a,b,c,d,51);
+ nR3(d,e,a,b,c,52); nR3(c,d,e,a,b,53); nR3(b,c,d,e,a,54);
+ nR3(a,b,c,d,e,55); nR3(e,a,b,c,d,56); nR3(d,e,a,b,c,57);
+ nR3(c,d,e,a,b,58); nR3(b,c,d,e,a,59);
+}
+
+static void
+do_R4(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d,
+ uint32_t *e, CHAR64LONG16 *block)
+{
+ nR4(a,b,c,d,e,60); nR4(e,a,b,c,d,61); nR4(d,e,a,b,c,62);
+ nR4(c,d,e,a,b,63); nR4(b,c,d,e,a,64); nR4(a,b,c,d,e,65);
+ nR4(e,a,b,c,d,66); nR4(d,e,a,b,c,67); nR4(c,d,e,a,b,68);
+ nR4(b,c,d,e,a,69); nR4(a,b,c,d,e,70); nR4(e,a,b,c,d,71);
+ nR4(d,e,a,b,c,72); nR4(c,d,e,a,b,73); nR4(b,c,d,e,a,74);
+ nR4(a,b,c,d,e,75); nR4(e,a,b,c,d,76); nR4(d,e,a,b,c,77);
+ nR4(c,d,e,a,b,78); nR4(b,c,d,e,a,79);
+}
+#endif
+
+/*!
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+static void
+transform(uint32_t state[5], const unsigned char buffer[64]) {
+ uint32_t a, b, c, d, e;
+ CHAR64LONG16 *block;
+ CHAR64LONG16 workspace;
+
+ INSIST(buffer != NULL);
+ INSIST(state != NULL);
+
+ block = &workspace;
+ (void)memmove(block, buffer, 64);
+
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+#ifdef __sparc_v9__
+ do_R01(&a, &b, &c, &d, &e, block);
+ do_R2(&a, &b, &c, &d, &e, block);
+ do_R3(&a, &b, &c, &d, &e, block);
+ do_R4(&a, &b, &c, &d, &e, block);
+#else
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+#endif
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+ /* Avoid compiler warnings */
+ POST(a); POST(b); POST(c); POST(d); POST(e);
+}
+
+
+/*!
+ * isc_sha1_init - Initialize new context
+ */
+void
+isc_sha1_init(isc_sha1_t *context)
+{
+ INSIST(context != NULL);
+
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = 0;
+ context->count[1] = 0;
+}
+
+void
+isc_sha1_invalidate(isc_sha1_t *context) {
+ isc_safe_memwipe(context, sizeof(*context));
+}
+
+/*!
+ * Run your data through this.
+ */
+void
+isc_sha1_update(isc_sha1_t *context, const unsigned char *data,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ INSIST(context != 0);
+ INSIST(data != 0);
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1] += (len >> 29) + 1;
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ (void)memmove(&context->buffer[j], data, (i = 64 - j));
+ transform(context->state, context->buffer);
+ for (; i + 63 < len; i += 64)
+ transform(context->state, &data[i]);
+ j = 0;
+ } else {
+ i = 0;
+ }
+
+ (void)memmove(&context->buffer[j], &data[i], len - i);
+}
+
+
+/*!
+ * Add padding and return the message digest.
+ */
+
+static const unsigned char final_200 = 128;
+static const unsigned char final_0 = 0;
+
+void
+isc_sha1_final(isc_sha1_t *context, unsigned char *digest) {
+ unsigned int i;
+ unsigned char finalcount[8];
+
+ INSIST(digest != 0);
+ INSIST(context != 0);
+
+ for (i = 0; i < 8; i++) {
+ /* Endian independent */
+ finalcount[i] = (unsigned char)
+ ((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3 - (i & 3)) * 8)) & 255);
+ }
+
+ isc_sha1_update(context, &final_200, 1);
+ while ((context->count[0] & 504) != 448)
+ isc_sha1_update(context, &final_0, 1);
+ /* The next Update should cause a transform() */
+ isc_sha1_update(context, finalcount, 8);
+
+ if (digest) {
+ for (i = 0; i < 20; i++)
+ digest[i] = (unsigned char)
+ ((context->state[i >> 2]
+ >> ((3 - (i & 3)) * 8)) & 255);
+ }
+
+ isc_safe_memwipe(context, sizeof(*context));
+}
+#endif
+
+/*
+ * Check for SHA-1 support; if it does not work, raise a fatal error.
+ *
+ * Use "a" as the test vector.
+ *
+ * Standard use is testing false and result true.
+ * Testing use is testing true and result false;
+ */
+bool
+isc_sha1_check(bool testing) {
+ isc_sha1_t ctx;
+ unsigned char input = 'a';
+ unsigned char digest[ISC_SHA1_DIGESTLENGTH];
+ unsigned char expected[] = {
+ 0x86, 0xf7, 0xe4, 0x37, 0xfa, 0xa5, 0xa7, 0xfc,
+ 0xe1, 0x5d, 0x1d, 0xdc, 0xb9, 0xea, 0xea, 0xea,
+ 0x37, 0x76, 0x67, 0xb8
+ };
+
+ INSIST(sizeof(expected) == ISC_SHA1_DIGESTLENGTH);
+
+ /*
+ * Introduce a fault for testing.
+ */
+ if (testing) {
+ input ^= 0x01;
+ }
+
+ /*
+ * These functions do not return anything; any failure will be fatal.
+ */
+ isc_sha1_init(&ctx);
+ isc_sha1_update(&ctx, &input, 1U);
+ isc_sha1_final(&ctx, digest);
+
+ /*
+ * Must return true in standard case, should return false for testing.
+ */
+ return (memcmp(digest, expected, ISC_SHA1_DIGESTLENGTH) == 0);
+}
diff --git a/lib/isc/sha2.c b/lib/isc/sha2.c
new file mode 100644
index 0000000..8e502bf
--- /dev/null
+++ b/lib/isc/sha2.c
@@ -0,0 +1,1767 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id$ */
+
+/* $FreeBSD: src/sys/crypto/sha2/sha2.c,v 1.2.2.2 2002/03/05 08:36:47 ume Exp $ */
+/* $KAME: sha2.c,v 1.8 2001/11/08 01:07:52 itojun Exp $ */
+
+/*
+ * sha2.c
+ *
+ * Version 1.0.0beta1
+ *
+ * Written by Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright 2000 Aaron D. Gifford. 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. Neither the name of the copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``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(S) OR CONTRIBUTOR(S) 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.
+ *
+ */
+
+
+#include <config.h>
+
+#include <inttypes.h>
+
+#include <isc/assertions.h>
+#include <isc/platform.h>
+#include <isc/safe.h>
+#include <isc/sha2.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#if PKCS11CRYPTO
+#include <pk11/internal.h>
+#include <pk11/pk11.h>
+#endif
+
+#if defined(ISC_PLATFORM_OPENSSLHASH) && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#define EVP_MD_CTX_new() &(context->_ctx)
+#define EVP_MD_CTX_free(ptr) EVP_MD_CTX_cleanup(ptr)
+#define EVP_MD_CTX_reset(c) EVP_MD_CTX_cleanup(c)
+#endif
+
+void
+isc_sha224_init(isc_sha224_t *context) {
+ if (context == (isc_sha224_t *)0) {
+ return;
+ }
+ context->ctx = EVP_MD_CTX_new();
+ RUNTIME_CHECK(context->ctx != NULL);
+ if (EVP_DigestInit(context->ctx, EVP_sha224()) != 1) {
+ FATAL_ERROR(__FILE__, __LINE__, "Cannot initialize SHA224.");
+ }
+}
+
+void
+isc_sha224_invalidate(isc_sha224_t *context) {
+ EVP_MD_CTX_free(context->ctx);
+ context->ctx = NULL;
+}
+
+void
+isc_sha224_update(isc_sha224_t *context, const uint8_t* data, size_t len) {
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha224_t *)0);
+ REQUIRE(context->ctx != (EVP_MD_CTX *)0);
+ REQUIRE(data != (uint8_t*)0);
+
+ RUNTIME_CHECK(EVP_DigestUpdate(context->ctx,
+ (const void *) data, len) == 1);
+}
+
+void
+isc_sha224_final(uint8_t digest[], isc_sha224_t *context) {
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha224_t *)0);
+ REQUIRE(context->ctx != (EVP_MD_CTX *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0)
+ RUNTIME_CHECK(EVP_DigestFinal(context->ctx,
+ digest, NULL) == 1);
+ EVP_MD_CTX_free(context->ctx);
+ context->ctx = NULL;
+}
+
+void
+isc_sha256_init(isc_sha256_t *context) {
+ if (context == (isc_sha256_t *)0) {
+ return;
+ }
+ context->ctx = EVP_MD_CTX_new();
+ RUNTIME_CHECK(context->ctx != NULL);
+ if (EVP_DigestInit(context->ctx, EVP_sha256()) != 1) {
+ FATAL_ERROR(__FILE__, __LINE__, "Cannot initialize SHA256.");
+ }
+}
+
+void
+isc_sha256_invalidate(isc_sha256_t *context) {
+ EVP_MD_CTX_free(context->ctx);
+ context->ctx = NULL;
+}
+
+void
+isc_sha256_update(isc_sha256_t *context, const uint8_t *data, size_t len) {
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha256_t *)0);
+ REQUIRE(context->ctx != (EVP_MD_CTX *)0);
+ REQUIRE(data != (uint8_t*)0);
+
+ RUNTIME_CHECK(EVP_DigestUpdate(context->ctx,
+ (const void *) data, len) == 1);
+}
+
+void
+isc_sha256_final(uint8_t digest[], isc_sha256_t *context) {
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha256_t *)0);
+ REQUIRE(context->ctx != (EVP_MD_CTX *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0)
+ RUNTIME_CHECK(EVP_DigestFinal(context->ctx,
+ digest, NULL) == 1);
+ EVP_MD_CTX_free(context->ctx);
+ context->ctx = NULL;
+}
+
+void
+isc_sha512_init(isc_sha512_t *context) {
+ if (context == (isc_sha512_t *)0) {
+ return;
+ }
+ context->ctx = EVP_MD_CTX_new();
+ RUNTIME_CHECK(context->ctx != NULL);
+ if (EVP_DigestInit(context->ctx, EVP_sha512()) != 1) {
+ FATAL_ERROR(__FILE__, __LINE__, "Cannot initialize SHA512.");
+ }
+}
+
+void
+isc_sha512_invalidate(isc_sha512_t *context) {
+ EVP_MD_CTX_free(context->ctx);
+ context->ctx = NULL;
+}
+
+void isc_sha512_update(isc_sha512_t *context, const uint8_t *data, size_t len) {
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0);
+ REQUIRE(context->ctx != (EVP_MD_CTX *)0);
+ REQUIRE(data != (uint8_t*)0);
+
+ RUNTIME_CHECK(EVP_DigestUpdate(context->ctx,
+ (const void *) data, len) == 1);
+}
+
+void isc_sha512_final(uint8_t digest[], isc_sha512_t *context) {
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0);
+ REQUIRE(context->ctx != (EVP_MD_CTX *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0)
+ RUNTIME_CHECK(EVP_DigestFinal(context->ctx,
+ digest, NULL) == 1);
+ EVP_MD_CTX_free(context->ctx);
+ context->ctx = NULL;
+}
+
+void
+isc_sha384_init(isc_sha384_t *context) {
+ if (context == (isc_sha384_t *)0) {
+ return;
+ }
+ context->ctx = EVP_MD_CTX_new();
+ RUNTIME_CHECK(context->ctx != NULL);
+ if (EVP_DigestInit(context->ctx, EVP_sha384()) != 1) {
+ FATAL_ERROR(__FILE__, __LINE__, "Cannot initialize SHA384.");
+ }
+}
+
+void
+isc_sha384_invalidate(isc_sha384_t *context) {
+ EVP_MD_CTX_free(context->ctx);
+ context->ctx = NULL;
+}
+
+void
+isc_sha384_update(isc_sha384_t *context, const uint8_t* data, size_t len) {
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0);
+ REQUIRE(context->ctx != (EVP_MD_CTX *)0);
+ REQUIRE(data != (uint8_t*)0);
+
+ RUNTIME_CHECK(EVP_DigestUpdate(context->ctx,
+ (const void *) data, len) == 1);
+}
+
+void
+isc_sha384_final(uint8_t digest[], isc_sha384_t *context) {
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha384_t *)0);
+ REQUIRE(context->ctx != (EVP_MD_CTX *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0)
+ RUNTIME_CHECK(EVP_DigestFinal(context->ctx,
+ digest, NULL) == 1);
+ EVP_MD_CTX_free(context->ctx);
+ context->ctx = NULL;
+}
+
+#elif PKCS11CRYPTO
+
+void
+isc_sha224_init(isc_sha224_t *context) {
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA224, NULL, 0 };
+
+ if (context == (isc_sha224_t *)0) {
+ return;
+ }
+ RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech));
+}
+
+void
+isc_sha224_invalidate(isc_sha224_t *context) {
+ CK_BYTE garbage[ISC_SHA224_DIGESTLENGTH];
+ CK_ULONG len = ISC_SHA224_DIGESTLENGTH;
+
+ if (context->handle == NULL)
+ return;
+ (void) pkcs_C_DigestFinal(context->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ pk11_return_session(context);
+}
+
+void
+isc_sha224_update(isc_sha224_t *context, const uint8_t* data, size_t len) {
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha224_t *)0 && data != (uint8_t*)0);
+
+ DE_CONST(data, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (context->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_sha224_final(uint8_t digest[], isc_sha224_t *context) {
+ CK_RV rv;
+ CK_ULONG len = ISC_SHA224_DIGESTLENGTH;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha224_t *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0) {
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (context->session,
+ (CK_BYTE_PTR) digest,
+ &len));
+ } else {
+ CK_BYTE garbage[ISC_SHA224_DIGESTLENGTH];
+
+ (void) pkcs_C_DigestFinal(context->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ }
+ pk11_return_session(context);
+}
+
+void
+isc_sha256_init(isc_sha256_t *context) {
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA256, NULL, 0 };
+
+ if (context == (isc_sha256_t *)0) {
+ return;
+ }
+ RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech));
+}
+
+void
+isc_sha256_invalidate(isc_sha256_t *context) {
+ CK_BYTE garbage[ISC_SHA256_DIGESTLENGTH];
+ CK_ULONG len = ISC_SHA256_DIGESTLENGTH;
+
+ if (context->handle == NULL)
+ return;
+ (void) pkcs_C_DigestFinal(context->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ pk11_return_session(context);
+}
+
+void
+isc_sha256_update(isc_sha256_t *context, const uint8_t* data, size_t len) {
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha256_t *)0 && data != (uint8_t*)0);
+
+ DE_CONST(data, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (context->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_sha256_final(uint8_t digest[], isc_sha256_t *context) {
+ CK_RV rv;
+ CK_ULONG len = ISC_SHA256_DIGESTLENGTH;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha256_t *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0) {
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (context->session,
+ (CK_BYTE_PTR) digest,
+ &len));
+ } else {
+ CK_BYTE garbage[ISC_SHA256_DIGESTLENGTH];
+
+ (void) pkcs_C_DigestFinal(context->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ }
+ pk11_return_session(context);
+}
+
+void
+isc_sha512_init(isc_sha512_t *context) {
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA512, NULL, 0 };
+
+ if (context == (isc_sha512_t *)0) {
+ return;
+ }
+ RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech));
+}
+
+void
+isc_sha512_invalidate(isc_sha512_t *context) {
+ CK_BYTE garbage[ISC_SHA512_DIGESTLENGTH];
+ CK_ULONG len = ISC_SHA512_DIGESTLENGTH;
+
+ if (context->handle == NULL)
+ return;
+ (void) pkcs_C_DigestFinal(context->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ pk11_return_session(context);
+}
+
+void
+isc_sha512_update(isc_sha512_t *context, const uint8_t* data, size_t len) {
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0 && data != (uint8_t*)0);
+
+ DE_CONST(data, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (context->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_sha512_final(uint8_t digest[], isc_sha512_t *context) {
+ CK_RV rv;
+ CK_ULONG len = ISC_SHA512_DIGESTLENGTH;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0) {
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (context->session,
+ (CK_BYTE_PTR) digest,
+ &len));
+ } else {
+ CK_BYTE garbage[ISC_SHA512_DIGESTLENGTH];
+
+ (void) pkcs_C_DigestFinal(context->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ }
+ pk11_return_session(context);
+}
+
+void
+isc_sha384_init(isc_sha384_t *context) {
+ CK_RV rv;
+ CK_MECHANISM mech = { CKM_SHA384, NULL, 0 };
+
+ if (context == (isc_sha384_t *)0) {
+ return;
+ }
+ RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, true, false,
+ false, NULL, 0) == ISC_R_SUCCESS);
+ PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech));
+}
+
+void
+isc_sha384_invalidate(isc_sha384_t *context) {
+ CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH];
+ CK_ULONG len = ISC_SHA384_DIGESTLENGTH;
+
+ if (context->handle == NULL)
+ return;
+ (void) pkcs_C_DigestFinal(context->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ pk11_return_session(context);
+}
+
+void
+isc_sha384_update(isc_sha384_t *context, const uint8_t* data, size_t len) {
+ CK_RV rv;
+ CK_BYTE_PTR pPart;
+
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha384_t *)0 && data != (uint8_t*)0);
+
+ DE_CONST(data, pPart);
+ PK11_FATALCHECK(pkcs_C_DigestUpdate,
+ (context->session, pPart, (CK_ULONG) len));
+}
+
+void
+isc_sha384_final(uint8_t digest[], isc_sha384_t *context) {
+ CK_RV rv;
+ CK_ULONG len = ISC_SHA384_DIGESTLENGTH;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha384_t *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0) {
+ PK11_FATALCHECK(pkcs_C_DigestFinal,
+ (context->session,
+ (CK_BYTE_PTR) digest,
+ &len));
+ } else {
+ CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH];
+
+ (void) pkcs_C_DigestFinal(context->session, garbage, &len);
+ isc_safe_memwipe(garbage, sizeof(garbage));
+ }
+ pk11_return_session(context);
+}
+
+#else
+
+/*
+ * UNROLLED TRANSFORM LOOP NOTE:
+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
+ * loop version for the hash transform rounds (defined using macros
+ * later in this file). Either define on the command line, for example:
+ *
+ * cc -DISC_SHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
+ *
+ * or define below:
+ *
+ * \#define ISC_SHA2_UNROLL_TRANSFORM
+ *
+ */
+
+/*** SHA-256/384/512 Machine Architecture Definitions *****************/
+/*
+ * BYTE_ORDER NOTE:
+ *
+ * Please make sure that your system defines BYTE_ORDER. If your
+ * architecture is little-endian, make sure it also defines
+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
+ * equivalent.
+ *
+ * If your system does not define the above, then you can do so by
+ * hand like this:
+ *
+ * \#define LITTLE_ENDIAN 1234
+ * \#define BIG_ENDIAN 4321
+ *
+ * And for little-endian machines, add:
+ *
+ * \#define BYTE_ORDER LITTLE_ENDIAN
+ *
+ * Or for big-endian machines:
+ *
+ * \#define BYTE_ORDER BIG_ENDIAN
+ *
+ * The FreeBSD machine this was written on defines BYTE_ORDER
+ * appropriately by including <sys/types.h> (which in turn includes
+ * <machine/endian.h> where the appropriate definitions are actually
+ * made).
+ */
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
+#ifndef BYTE_ORDER
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+#ifdef WORDS_BIGENDIAN
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#else
+#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN
+#endif
+#endif
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+/* NOTE: Most of these are in sha2.h */
+#define ISC_SHA256_SHORT_BLOCK_LENGTH (ISC_SHA256_BLOCK_LENGTH - 8)
+#define ISC_SHA384_SHORT_BLOCK_LENGTH (ISC_SHA384_BLOCK_LENGTH - 16)
+#define ISC_SHA512_SHORT_BLOCK_LENGTH (ISC_SHA512_BLOCK_LENGTH - 16)
+
+
+/*** ENDIAN REVERSAL MACROS *******************************************/
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define REVERSE32(w,x) { \
+ uint32_t tmp = (w); \
+ tmp = (tmp >> 16) | (tmp << 16); \
+ (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
+}
+#ifdef WIN32
+#define REVERSE64(w,x) { \
+ uint64_t tmp = (w); \
+ tmp = (tmp >> 32) | (tmp << 32); \
+ tmp = ((tmp & 0xff00ff00ff00ff00UL) >> 8) | \
+ ((tmp & 0x00ff00ff00ff00ffUL) << 8); \
+ (x) = ((tmp & 0xffff0000ffff0000UL) >> 16) | \
+ ((tmp & 0x0000ffff0000ffffUL) << 16); \
+}
+#else
+#define REVERSE64(w,x) { \
+ uint64_t tmp = (w); \
+ tmp = (tmp >> 32) | (tmp << 32); \
+ tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
+ ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
+ (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
+ ((tmp & 0x0000ffff0000ffffULL) << 16); \
+}
+#endif
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+ (w)[0] += (uint64_t)(n); \
+ if ((w)[0] < (n)) { \
+ (w)[1]++; \
+ } \
+}
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ * NOTE: The naming of R and S appears backwards here (R is a SHIFT and
+ * S is a ROTATION) because the SHA-256/384/512 description document
+ * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
+ * same "backwards" definition.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define R(b,x) ((x) >> (b))
+/* 32-bit Rotate-right (used in SHA-256): */
+#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
+
+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Four of six logical functions used in SHA-256: */
+#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
+#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
+#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
+#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
+
+/* Four of six logical functions used in SHA-384 and SHA-512: */
+#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
+#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
+#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x)))
+#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x)))
+
+/*** INTERNAL FUNCTION PROTOTYPES *************************************/
+/* NOTE: These should not be accessed directly from outside this
+ * library -- they are intended for private internal visibility/use
+ * only.
+ */
+void isc_sha512_last(isc_sha512_t *);
+void isc_sha256_transform(isc_sha256_t *, const uint32_t*);
+void isc_sha512_transform(isc_sha512_t *, const uint64_t*);
+
+
+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
+/* Hash constant words K for SHA-224 and SHA-256: */
+static const uint32_t K256[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+ 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+ 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Initial hash value H for SHA-224: */
+static const uint32_t sha224_initial_hash_value[8] = {
+ 0xc1059ed8UL,
+ 0x367cd507UL,
+ 0x3070dd17UL,
+ 0xf70e5939UL,
+ 0xffc00b31UL,
+ 0x68581511UL,
+ 0x64f98fa7UL,
+ 0xbefa4fa4UL
+};
+
+/* Initial hash value H for SHA-256: */
+static const uint32_t sha256_initial_hash_value[8] = {
+ 0x6a09e667UL,
+ 0xbb67ae85UL,
+ 0x3c6ef372UL,
+ 0xa54ff53aUL,
+ 0x510e527fUL,
+ 0x9b05688cUL,
+ 0x1f83d9abUL,
+ 0x5be0cd19UL
+};
+
+#ifdef WIN32
+/* Hash constant words K for SHA-384 and SHA-512: */
+static const uint64_t K512[80] = {
+ 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL,
+ 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL,
+ 0x3956c25bf348b538UL, 0x59f111f1b605d019UL,
+ 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL,
+ 0xd807aa98a3030242UL, 0x12835b0145706fbeUL,
+ 0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL,
+ 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL,
+ 0x9bdc06a725c71235UL, 0xc19bf174cf692694UL,
+ 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL,
+ 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL,
+ 0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL,
+ 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL,
+ 0x983e5152ee66dfabUL, 0xa831c66d2db43210UL,
+ 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL,
+ 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL,
+ 0x06ca6351e003826fUL, 0x142929670a0e6e70UL,
+ 0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL,
+ 0x4d2c6dfc5ac42aedUL, 0x53380d139d95b3dfUL,
+ 0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL,
+ 0x81c2c92e47edaee6UL, 0x92722c851482353bUL,
+ 0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL,
+ 0xc24b8b70d0f89791UL, 0xc76c51a30654be30UL,
+ 0xd192e819d6ef5218UL, 0xd69906245565a910UL,
+ 0xf40e35855771202aUL, 0x106aa07032bbd1b8UL,
+ 0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL,
+ 0x2748774cdf8eeb99UL, 0x34b0bcb5e19b48a8UL,
+ 0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL,
+ 0x5b9cca4f7763e373UL, 0x682e6ff3d6b2b8a3UL,
+ 0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL,
+ 0x84c87814a1f0ab72UL, 0x8cc702081a6439ecUL,
+ 0x90befffa23631e28UL, 0xa4506cebde82bde9UL,
+ 0xbef9a3f7b2c67915UL, 0xc67178f2e372532bUL,
+ 0xca273eceea26619cUL, 0xd186b8c721c0c207UL,
+ 0xeada7dd6cde0eb1eUL, 0xf57d4f7fee6ed178UL,
+ 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL,
+ 0x113f9804bef90daeUL, 0x1b710b35131c471bUL,
+ 0x28db77f523047d84UL, 0x32caab7b40c72493UL,
+ 0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL,
+ 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL,
+ 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL
+};
+
+/* Initial hash value H for SHA-384: */
+static const uint64_t sha384_initial_hash_value[8] = {
+ 0xcbbb9d5dc1059ed8UL,
+ 0x629a292a367cd507UL,
+ 0x9159015a3070dd17UL,
+ 0x152fecd8f70e5939UL,
+ 0x67332667ffc00b31UL,
+ 0x8eb44a8768581511UL,
+ 0xdb0c2e0d64f98fa7UL,
+ 0x47b5481dbefa4fa4UL
+};
+
+/* Initial hash value H for SHA-512: */
+static const uint64_t sha512_initial_hash_value[8] = {
+ 0x6a09e667f3bcc908U,
+ 0xbb67ae8584caa73bUL,
+ 0x3c6ef372fe94f82bUL,
+ 0xa54ff53a5f1d36f1UL,
+ 0x510e527fade682d1UL,
+ 0x9b05688c2b3e6c1fUL,
+ 0x1f83d9abfb41bd6bUL,
+ 0x5be0cd19137e2179UL
+};
+#else
+/* Hash constant words K for SHA-384 and SHA-512: */
+static const uint64_t K512[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+ 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+ 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+ 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+ 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+ 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+ 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+ 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+ 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+ 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+ 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+ 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+ 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+ 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+ 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+ 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+ 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+ 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+ 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+ 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+ 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+ 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+ 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+ 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+ 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+ 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+ 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* Initial hash value H for SHA-384: */
+static const uint64_t sha384_initial_hash_value[8] = {
+ 0xcbbb9d5dc1059ed8ULL,
+ 0x629a292a367cd507ULL,
+ 0x9159015a3070dd17ULL,
+ 0x152fecd8f70e5939ULL,
+ 0x67332667ffc00b31ULL,
+ 0x8eb44a8768581511ULL,
+ 0xdb0c2e0d64f98fa7ULL,
+ 0x47b5481dbefa4fa4ULL
+};
+
+/* Initial hash value H for SHA-512: */
+static const uint64_t sha512_initial_hash_value[8] = {
+ 0x6a09e667f3bcc908ULL,
+ 0xbb67ae8584caa73bULL,
+ 0x3c6ef372fe94f82bULL,
+ 0xa54ff53a5f1d36f1ULL,
+ 0x510e527fade682d1ULL,
+ 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL,
+ 0x5be0cd19137e2179ULL
+};
+#endif
+
+
+/*** SHA-224: *********************************************************/
+void
+isc_sha224_init(isc_sha224_t *context) {
+ if (context == (isc_sha256_t *)0) {
+ return;
+ }
+ memmove(context->state, sha224_initial_hash_value,
+ ISC_SHA256_DIGESTLENGTH);
+ memset(context->buffer, 0, ISC_SHA256_BLOCK_LENGTH);
+ context->bitcount = 0;
+}
+
+void
+isc_sha224_invalidate(isc_sha224_t *context) {
+ isc_safe_memwipe(context, sizeof(*context));
+}
+
+void
+isc_sha224_update(isc_sha224_t *context, const uint8_t* data, size_t len) {
+ isc_sha256_update((isc_sha256_t *)context, data, len);
+}
+
+void
+isc_sha224_final(uint8_t digest[], isc_sha224_t *context) {
+ uint8_t sha256_digest[ISC_SHA256_DIGESTLENGTH];
+ isc_sha256_final(sha256_digest, (isc_sha256_t *)context);
+ memmove(digest, sha256_digest, ISC_SHA224_DIGESTLENGTH);
+ isc_safe_memwipe(sha256_digest, sizeof(sha256_digest));
+}
+
+/*** SHA-256: *********************************************************/
+void
+isc_sha256_init(isc_sha256_t *context) {
+ if (context == (isc_sha256_t *)0) {
+ return;
+ }
+ memmove(context->state, sha256_initial_hash_value,
+ ISC_SHA256_DIGESTLENGTH);
+ memset(context->buffer, 0, ISC_SHA256_BLOCK_LENGTH);
+ context->bitcount = 0;
+}
+
+void
+isc_sha256_invalidate(isc_sha256_t *context) {
+ isc_safe_memwipe(context, sizeof(*context));
+}
+
+#ifdef ISC_SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-256 round macros: */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE32(*data++, W256[j]); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + W256[j]; \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + (W256[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256(a,b,c,d,e,f,g,h) \
+ s0 = W256[(j+1)&0x0f]; \
+ s0 = sigma0_256(s0); \
+ s1 = W256[(j+14)&0x0f]; \
+ s1 = sigma1_256(s1); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+void isc_sha256_transform(isc_sha256_t *context, const uint32_t* data) {
+ uint32_t a, b, c, d, e, f, g, h, s0, s1;
+ uint32_t T1, *W256;
+ int j;
+
+ W256 = (uint32_t*)context->buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+ /* Rounds 0 to 15 (unrolled): */
+ ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds to 64: */
+ do {
+ ROUND256(a,b,c,d,e,f,g,h);
+ ROUND256(h,a,b,c,d,e,f,g);
+ ROUND256(g,h,a,b,c,d,e,f);
+ ROUND256(f,g,h,a,b,c,d,e);
+ ROUND256(e,f,g,h,a,b,c,d);
+ ROUND256(d,e,f,g,h,a,b,c);
+ ROUND256(c,d,e,f,g,h,a,b);
+ ROUND256(b,c,d,e,f,g,h,a);
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+ /* Avoid compiler warnings */
+ POST(a); POST(b); POST(c); POST(d); POST(e); POST(f);
+ POST(g); POST(h); POST(T1);
+}
+
+#else /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void
+isc_sha256_transform(isc_sha256_t *context, const uint32_t* data) {
+ uint32_t a, b, c, d, e, f, g, h, s0, s1;
+ uint32_t T1, T2, *W256;
+ int j;
+
+ W256 = (uint32_t*)context->buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Copy data while converting to host byte order */
+ REVERSE32(*data++,W256[j]);
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ /* Apply the SHA-256 compression function to update a..h with copy */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W256[(j+1)&0x0f];
+ s0 = sigma0_256(s0);
+ s1 = W256[(j+14)&0x0f];
+ s1 = sigma1_256(s1);
+
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+ /* Avoid compiler warnings */
+ POST(a); POST(b); POST(c); POST(d); POST(e); POST(f);
+ POST(g); POST(h); POST(T1); POST(T2);
+}
+
+#endif /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void
+isc_sha256_update(isc_sha256_t *context, const uint8_t *data, size_t len) {
+ unsigned int freespace, usedspace;
+
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha256_t *)0 && data != (uint8_t*)0);
+
+ usedspace = (unsigned int)((context->bitcount >> 3) %
+ ISC_SHA256_BLOCK_LENGTH);
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = ISC_SHA256_BLOCK_LENGTH - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ memmove(&context->buffer[usedspace], data, freespace);
+ context->bitcount += freespace << 3;
+ len -= freespace;
+ data += freespace;
+ isc_sha256_transform(context,
+ (uint32_t*)context->buffer);
+ } else {
+ /* The buffer is not yet full */
+ memmove(&context->buffer[usedspace], data, len);
+ context->bitcount += len << 3;
+ /* Clean up: */
+ usedspace = freespace = 0;
+ /* Avoid compiler warnings: */
+ POST(usedspace); POST(freespace);
+ return;
+ }
+ }
+ while (len >= ISC_SHA256_BLOCK_LENGTH) {
+ /* Process as many complete blocks as we can */
+ memmove(context->buffer, data, ISC_SHA256_BLOCK_LENGTH);
+ isc_sha256_transform(context, (uint32_t*)context->buffer);
+ context->bitcount += ISC_SHA256_BLOCK_LENGTH << 3;
+ len -= ISC_SHA256_BLOCK_LENGTH;
+ data += ISC_SHA256_BLOCK_LENGTH;
+ }
+ if (len > 0U) {
+ /* There's left-overs, so save 'em */
+ memmove(context->buffer, data, len);
+ context->bitcount += len << 3;
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+ /* Avoid compiler warnings: */
+ POST(usedspace); POST(freespace);
+}
+
+void
+isc_sha256_final(uint8_t digest[], isc_sha256_t *context) {
+ uint32_t *d = (uint32_t*)digest;
+ unsigned int usedspace;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha256_t *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0) {
+ usedspace = (unsigned int)((context->bitcount >> 3) %
+ ISC_SHA256_BLOCK_LENGTH);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->bitcount,context->bitcount);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->buffer[usedspace++] = 0x80;
+
+ if (usedspace <= ISC_SHA256_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ memset(&context->buffer[usedspace], 0,
+ ISC_SHA256_SHORT_BLOCK_LENGTH - usedspace);
+ } else {
+ if (usedspace < ISC_SHA256_BLOCK_LENGTH) {
+ memset(&context->buffer[usedspace], 0,
+ ISC_SHA256_BLOCK_LENGTH -
+ usedspace);
+ }
+ /* Do second-to-last transform: */
+ isc_sha256_transform(context,
+ (uint32_t*)context->buffer);
+
+ /* And set-up for the last transform: */
+ memset(context->buffer, 0,
+ ISC_SHA256_SHORT_BLOCK_LENGTH);
+ }
+ } else {
+ /* Set-up for the last transform: */
+ memset(context->buffer, 0, ISC_SHA256_SHORT_BLOCK_LENGTH);
+
+ /* Begin padding with a 1 bit: */
+ *context->buffer = 0x80;
+ }
+ /* Set the bit count: */
+ *(uint64_t*)&context->buffer[ISC_SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;
+
+ /* Final transform: */
+ isc_sha256_transform(context, (uint32_t*)context->buffer);
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 8; j++) {
+ REVERSE32(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ memmove(d, context->state, ISC_SHA256_DIGESTLENGTH);
+#endif
+ }
+
+ /* Clean up state data: */
+ isc_safe_memwipe(context, sizeof(*context));
+ usedspace = 0;
+ POST(usedspace);
+}
+
+/*** SHA-512: *********************************************************/
+void
+isc_sha512_init(isc_sha512_t *context) {
+ if (context == (isc_sha512_t *)0) {
+ return;
+ }
+ memmove(context->state, sha512_initial_hash_value,
+ ISC_SHA512_DIGESTLENGTH);
+ memset(context->buffer, 0, ISC_SHA512_BLOCK_LENGTH);
+ context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+void
+isc_sha512_invalidate(isc_sha512_t *context) {
+ isc_safe_memwipe(context, sizeof(*context));
+}
+
+#ifdef ISC_SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-512 round macros: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE64(*data++, W512[j]); \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+ K512[j] + W512[j]; \
+ (d) += T1, \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
+ j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+ K512[j] + (W512[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512(a,b,c,d,e,f,g,h) \
+ s0 = W512[(j+1)&0x0f]; \
+ s0 = sigma0_512(s0); \
+ s1 = W512[(j+14)&0x0f]; \
+ s1 = sigma1_512(s1); \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ j++
+
+void isc_sha512_transform(isc_sha512_t *context, const uint64_t* data) {
+ uint64_t a, b, c, d, e, f, g, h, s0, s1;
+ uint64_t T1, *W512 = (uint64_t*)context->buffer;
+ int j;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+ ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds up to 79: */
+ do {
+ ROUND512(a,b,c,d,e,f,g,h);
+ ROUND512(h,a,b,c,d,e,f,g);
+ ROUND512(g,h,a,b,c,d,e,f);
+ ROUND512(f,g,h,a,b,c,d,e);
+ ROUND512(e,f,g,h,a,b,c,d);
+ ROUND512(d,e,f,g,h,a,b,c);
+ ROUND512(c,d,e,f,g,h,a,b);
+ ROUND512(b,c,d,e,f,g,h,a);
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+ /* Avoid compiler warnings */
+ POST(a); POST(b); POST(c); POST(d); POST(e); POST(f);
+ POST(g); POST(h); POST(T1);
+}
+
+#else /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void
+isc_sha512_transform(isc_sha512_t *context, const uint64_t* data) {
+ uint64_t a, b, c, d, e, f, g, h, s0, s1;
+ uint64_t T1, T2, *W512 = (uint64_t*)context->buffer;
+ int j;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert TO host byte order */
+ REVERSE64(*data++, W512[j]);
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ /* Apply the SHA-512 compression function to update a..h with copy */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W512[(j+1)&0x0f];
+ s0 = sigma0_512(s0);
+ s1 = W512[(j+14)&0x0f];
+ s1 = sigma1_512(s1);
+
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+ /* Avoid compiler warnings */
+ POST(a); POST(b); POST(c); POST(d); POST(e); POST(f);
+ POST(g); POST(h); POST(T1); POST(T2);
+}
+
+#endif /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void isc_sha512_update(isc_sha512_t *context, const uint8_t *data, size_t len) {
+ unsigned int freespace, usedspace;
+
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0 && data != (uint8_t*)0);
+
+ usedspace = (unsigned int)((context->bitcount[0] >> 3) %
+ ISC_SHA512_BLOCK_LENGTH);
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = ISC_SHA512_BLOCK_LENGTH - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ memmove(&context->buffer[usedspace], data, freespace);
+ ADDINC128(context->bitcount, freespace << 3);
+ len -= freespace;
+ data += freespace;
+ isc_sha512_transform(context,
+ (uint64_t*)context->buffer);
+ } else {
+ /* The buffer is not yet full */
+ memmove(&context->buffer[usedspace], data, len);
+ ADDINC128(context->bitcount, len << 3);
+ /* Clean up: */
+ usedspace = freespace = 0;
+ /* Avoid compiler warnings: */
+ POST(usedspace); POST(freespace);
+ return;
+ }
+ }
+ while (len >= ISC_SHA512_BLOCK_LENGTH) {
+ /* Process as many complete blocks as we can */
+ memmove(context->buffer, data, ISC_SHA512_BLOCK_LENGTH);
+ isc_sha512_transform(context, (uint64_t*)context->buffer);
+ ADDINC128(context->bitcount, ISC_SHA512_BLOCK_LENGTH << 3);
+ len -= ISC_SHA512_BLOCK_LENGTH;
+ data += ISC_SHA512_BLOCK_LENGTH;
+ }
+ if (len > 0U) {
+ /* There's left-overs, so save 'em */
+ memmove(context->buffer, data, len);
+ ADDINC128(context->bitcount, len << 3);
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+ /* Avoid compiler warnings: */
+ POST(usedspace); POST(freespace);
+}
+
+void isc_sha512_last(isc_sha512_t *context) {
+ unsigned int usedspace;
+
+ usedspace = (unsigned int)((context->bitcount[0] >> 3) %
+ ISC_SHA512_BLOCK_LENGTH);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->bitcount[0],context->bitcount[0]);
+ REVERSE64(context->bitcount[1],context->bitcount[1]);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->buffer[usedspace++] = 0x80;
+
+ if (usedspace <= ISC_SHA512_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ memset(&context->buffer[usedspace], 0,
+ ISC_SHA512_SHORT_BLOCK_LENGTH - usedspace);
+ } else {
+ if (usedspace < ISC_SHA512_BLOCK_LENGTH) {
+ memset(&context->buffer[usedspace], 0,
+ ISC_SHA512_BLOCK_LENGTH - usedspace);
+ }
+ /* Do second-to-last transform: */
+ isc_sha512_transform(context,
+ (uint64_t*)context->buffer);
+
+ /* And set-up for the last transform: */
+ memset(context->buffer, 0, ISC_SHA512_BLOCK_LENGTH - 2);
+ }
+ } else {
+ /* Prepare for final transform: */
+ memset(context->buffer, 0, ISC_SHA512_SHORT_BLOCK_LENGTH);
+
+ /* Begin padding with a 1 bit: */
+ *context->buffer = 0x80;
+ }
+ /* Store the length of input data (in bits): */
+ *(uint64_t*)&context->buffer[ISC_SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
+ *(uint64_t*)&context->buffer[ISC_SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];
+
+ /* Final transform: */
+ isc_sha512_transform(context, (uint64_t*)context->buffer);
+}
+
+void isc_sha512_final(uint8_t digest[], isc_sha512_t *context) {
+ uint64_t *d = (uint64_t*)digest;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0) {
+ isc_sha512_last(context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 8; j++) {
+ REVERSE64(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ memmove(d, context->state, ISC_SHA512_DIGESTLENGTH);
+#endif
+ }
+
+ /* Zero out state data */
+ isc_safe_memwipe(context, sizeof(*context));
+}
+
+
+/*** SHA-384: *********************************************************/
+void
+isc_sha384_init(isc_sha384_t *context) {
+ if (context == (isc_sha384_t *)0) {
+ return;
+ }
+ memmove(context->state, sha384_initial_hash_value,
+ ISC_SHA512_DIGESTLENGTH);
+ memset(context->buffer, 0, ISC_SHA384_BLOCK_LENGTH);
+ context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+void
+isc_sha384_invalidate(isc_sha384_t *context) {
+ isc_safe_memwipe(context, sizeof(*context));
+}
+
+void
+isc_sha384_update(isc_sha384_t *context, const uint8_t* data, size_t len) {
+ isc_sha512_update((isc_sha512_t *)context, data, len);
+}
+
+void
+isc_sha384_final(uint8_t digest[], isc_sha384_t *context) {
+ uint64_t *d = (uint64_t*)digest;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha384_t *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (uint8_t*)0) {
+ isc_sha512_last((isc_sha512_t *)context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 6; j++) {
+ REVERSE64(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ memmove(d, context->state, ISC_SHA384_DIGESTLENGTH);
+#endif
+ }
+
+ /* Zero out state data */
+ isc_safe_memwipe(context, sizeof(*context));
+}
+#endif /* !ISC_PLATFORM_OPENSSLHASH */
+
+/*
+ * Constant used by SHA256/384/512_End() functions for converting the
+ * digest to a readable hexadecimal character string:
+ */
+static const char *sha2_hex_digits = "0123456789abcdef";
+
+char *
+isc_sha224_end(isc_sha224_t *context, char buffer[]) {
+ uint8_t digest[ISC_SHA224_DIGESTLENGTH], *d = digest;
+ unsigned int i;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha224_t *)0);
+
+ if (buffer != (char*)0) {
+ isc_sha224_final(digest, context);
+
+ for (i = 0; i < ISC_SHA224_DIGESTLENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+#if defined(ISC_PLATFORM_OPENSSLHASH) && !defined(LIBRESSL_VERSION_NUMBER)
+ EVP_MD_CTX_reset(context->ctx);
+#elif PKCS11CRYPTO
+ pk11_return_session(context);
+#else
+ isc_safe_memwipe(context, sizeof(*context));
+#endif
+ }
+ isc_safe_memwipe(digest, sizeof(digest));
+ return buffer;
+}
+
+char *
+isc_sha224_data(const uint8_t *data, size_t len,
+ char digest[ISC_SHA224_DIGESTSTRINGLENGTH])
+{
+ isc_sha224_t context;
+
+ isc_sha224_init(&context);
+ isc_sha224_update(&context, data, len);
+ return (isc_sha224_end(&context, digest));
+}
+
+char *
+isc_sha256_end(isc_sha256_t *context, char buffer[]) {
+ uint8_t digest[ISC_SHA256_DIGESTLENGTH], *d = digest;
+ unsigned int i;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha256_t *)0);
+
+ if (buffer != (char*)0) {
+ isc_sha256_final(digest, context);
+
+ for (i = 0; i < ISC_SHA256_DIGESTLENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+#if defined(ISC_PLATFORM_OPENSSLHASH) && !defined(LIBRESSL_VERSION_NUMBER)
+ EVP_MD_CTX_reset(context->ctx);
+#elif PKCS11CRYPTO
+ pk11_return_session(context);
+#else
+ isc_safe_memwipe(context, sizeof(*context));
+#endif
+ }
+ isc_safe_memwipe(digest, sizeof(digest));
+ return buffer;
+}
+
+char *
+isc_sha256_data(const uint8_t* data, size_t len,
+ char digest[ISC_SHA256_DIGESTSTRINGLENGTH])
+{
+ isc_sha256_t context;
+
+ isc_sha256_init(&context);
+ isc_sha256_update(&context, data, len);
+ return (isc_sha256_end(&context, digest));
+}
+
+char *
+isc_sha512_end(isc_sha512_t *context, char buffer[]) {
+ uint8_t digest[ISC_SHA512_DIGESTLENGTH], *d = digest;
+ unsigned int i;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0);
+
+ if (buffer != (char*)0) {
+ isc_sha512_final(digest, context);
+
+ for (i = 0; i < ISC_SHA512_DIGESTLENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+#if defined(ISC_PLATFORM_OPENSSLHASH) && !defined(LIBRESSL_VERSION_NUMBER)
+ EVP_MD_CTX_reset(context->ctx);
+#elif PKCS11CRYPTO
+ pk11_return_session(context);
+#else
+ isc_safe_memwipe(context, sizeof(*context));
+#endif
+ }
+ isc_safe_memwipe(digest, sizeof(digest));
+ return buffer;
+}
+
+char *
+isc_sha512_data(const uint8_t *data, size_t len,
+ char digest[ISC_SHA512_DIGESTSTRINGLENGTH])
+{
+ isc_sha512_t context;
+
+ isc_sha512_init(&context);
+ isc_sha512_update(&context, data, len);
+ return (isc_sha512_end(&context, digest));
+}
+
+char *
+isc_sha384_end(isc_sha384_t *context, char buffer[]) {
+ uint8_t digest[ISC_SHA384_DIGESTLENGTH], *d = digest;
+ unsigned int i;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha384_t *)0);
+
+ if (buffer != (char*)0) {
+ isc_sha384_final(digest, context);
+
+ for (i = 0; i < ISC_SHA384_DIGESTLENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+#if defined(ISC_PLATFORM_OPENSSLHASH) && !defined(LIBRESSL_VERSION_NUMBER)
+ EVP_MD_CTX_reset(context->ctx);
+#elif PKCS11CRYPTO
+ pk11_return_session(context);
+#else
+ isc_safe_memwipe(context, sizeof(*context));
+#endif
+ }
+ isc_safe_memwipe(digest, sizeof(digest));
+ return buffer;
+}
+
+char *
+isc_sha384_data(const uint8_t *data, size_t len,
+ char digest[ISC_SHA384_DIGESTSTRINGLENGTH])
+{
+ isc_sha384_t context;
+
+ isc_sha384_init(&context);
+ isc_sha384_update(&context, data, len);
+ return (isc_sha384_end(&context, digest));
+}
diff --git a/lib/isc/sockaddr.c b/lib/isc/sockaddr.c
new file mode 100644
index 0000000..6a97e69
--- /dev/null
+++ b/lib/isc/sockaddr.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/msgs.h>
+#include <isc/netaddr.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/sockaddr.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+bool
+isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
+ return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
+ ISC_SOCKADDR_CMPPORT|
+ ISC_SOCKADDR_CMPSCOPE));
+}
+
+bool
+isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
+ return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
+ ISC_SOCKADDR_CMPSCOPE));
+}
+
+bool
+isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+ unsigned int flags)
+{
+ REQUIRE(a != NULL && b != NULL);
+
+ if (a->length != b->length)
+ return (false);
+
+ /*
+ * We don't just memcmp because the sin_zero field isn't always
+ * zero.
+ */
+
+ if (a->type.sa.sa_family != b->type.sa.sa_family)
+ return (false);
+ switch (a->type.sa.sa_family) {
+ case AF_INET:
+ if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
+ memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
+ sizeof(a->type.sin.sin_addr)) != 0)
+ return (false);
+ if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
+ a->type.sin.sin_port != b->type.sin.sin_port)
+ return (false);
+ break;
+ case AF_INET6:
+ if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
+ memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
+ sizeof(a->type.sin6.sin6_addr)) != 0)
+ return (false);
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ /*
+ * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
+ * false if one of the scopes in zero.
+ */
+ if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
+ a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
+ ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
+ (a->type.sin6.sin6_scope_id != 0 &&
+ b->type.sin6.sin6_scope_id != 0)))
+ return (false);
+#endif
+ if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
+ a->type.sin6.sin6_port != b->type.sin6.sin6_port)
+ return (false);
+ break;
+ default:
+ if (memcmp(&a->type, &b->type, a->length) != 0)
+ return (false);
+ }
+ return (true);
+}
+
+bool
+isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+ unsigned int prefixlen)
+{
+ isc_netaddr_t na, nb;
+ isc_netaddr_fromsockaddr(&na, a);
+ isc_netaddr_fromsockaddr(&nb, b);
+ return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
+}
+
+isc_result_t
+isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
+ isc_result_t result;
+ isc_netaddr_t netaddr;
+ char pbuf[sizeof("65000")];
+ unsigned int plen;
+ isc_region_t avail;
+
+ REQUIRE(sockaddr != NULL);
+
+ /*
+ * Do the port first, giving us the opportunity to check for
+ * unsupported address families before calling
+ * isc_netaddr_fromsockaddr().
+ */
+ switch (sockaddr->type.sa.sa_family) {
+ case AF_INET:
+ snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
+ break;
+ case AF_INET6:
+ snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
+ break;
+#ifdef ISC_PLAFORM_HAVESYSUNH
+ case AF_UNIX:
+ plen = strlen(sockaddr->type.sunix.sun_path);
+ if (plen >= isc_buffer_availablelength(target))
+ return (ISC_R_NOSPACE);
+
+ isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
+
+ /*
+ * Null terminate after used region.
+ */
+ isc_buffer_availableregion(target, &avail);
+ INSIST(avail.length >= 1);
+ avail.base[0] = '\0';
+
+ return (ISC_R_SUCCESS);
+#endif
+ default:
+ return (ISC_R_FAILURE);
+ }
+
+ plen = strlen(pbuf);
+ INSIST(plen < sizeof(pbuf));
+
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ result = isc_netaddr_totext(&netaddr, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (1 + plen + 1 > isc_buffer_availablelength(target))
+ return (ISC_R_NOSPACE);
+
+ isc_buffer_putmem(target, (const unsigned char *)"#", 1);
+ isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
+
+ /*
+ * Null terminate after used region.
+ */
+ isc_buffer_availableregion(target, &avail);
+ INSIST(avail.length >= 1);
+ avail.base[0] = '\0';
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
+ isc_result_t result;
+ isc_buffer_t buf;
+
+ if (size == 0U)
+ return;
+
+ isc_buffer_init(&buf, array, size);
+ result = isc_sockaddr_totext(sa, &buf);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * The message is the same as in netaddr.c.
+ */
+ snprintf(array, size,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
+ ISC_MSG_UNKNOWNADDR,
+ "<unknown address, family %u>"),
+ sa->type.sa.sa_family);
+ array[size - 1] = '\0';
+ }
+}
+
+unsigned int
+isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, bool address_only) {
+ unsigned int length = 0;
+ const unsigned char *s = NULL;
+ unsigned int h = 0;
+ unsigned int p = 0;
+ const struct in6_addr *in6;
+
+ REQUIRE(sockaddr != NULL);
+
+ switch (sockaddr->type.sa.sa_family) {
+ case AF_INET:
+ s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
+ p = ntohs(sockaddr->type.sin.sin_port);
+ length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
+ break;
+ case AF_INET6:
+ in6 = &sockaddr->type.sin6.sin6_addr;
+ s = (const unsigned char *)in6;
+ if (IN6_IS_ADDR_V4MAPPED(in6)) {
+ s += 12;
+ length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
+ } else
+ length = sizeof(sockaddr->type.sin6.sin6_addr);
+ p = ntohs(sockaddr->type.sin6.sin6_port);
+ break;
+ default:
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_SOCKADDR,
+ ISC_MSG_UNKNOWNFAMILY,
+ "unknown address family: %d"),
+ (int)sockaddr->type.sa.sa_family);
+ s = (const unsigned char *)&sockaddr->type;
+ length = sockaddr->length;
+ p = 0;
+ }
+
+ h = isc_hash_function(s, length, true, NULL);
+ if (!address_only)
+ h = isc_hash_function(&p, sizeof(p), true, &h);
+
+ return (h);
+}
+
+void
+isc_sockaddr_any(isc_sockaddr_t *sockaddr)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin.sin_family = AF_INET;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
+#endif
+ sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
+ sockaddr->type.sin.sin_port = 0;
+ sockaddr->length = sizeof(sockaddr->type.sin);
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+void
+isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin6.sin6_family = AF_INET6;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
+#endif
+ sockaddr->type.sin6.sin6_addr = in6addr_any;
+ sockaddr->type.sin6.sin6_port = 0;
+ sockaddr->length = sizeof(sockaddr->type.sin6);
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+void
+isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
+ in_port_t port)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin.sin_family = AF_INET;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
+#endif
+ sockaddr->type.sin.sin_addr = *ina;
+ sockaddr->type.sin.sin_port = htons(port);
+ sockaddr->length = sizeof(sockaddr->type.sin);
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+void
+isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
+ switch (pf) {
+ case AF_INET:
+ isc_sockaddr_any(sockaddr);
+ break;
+ case AF_INET6:
+ isc_sockaddr_any6(sockaddr);
+ break;
+ default:
+ INSIST(0);
+ }
+}
+
+void
+isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
+ in_port_t port)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin6.sin6_family = AF_INET6;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
+#endif
+ sockaddr->type.sin6.sin6_addr = *ina6;
+ sockaddr->type.sin6.sin6_port = htons(port);
+ sockaddr->length = sizeof(sockaddr->type.sin6);
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+void
+isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
+ in_port_t port)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin6.sin6_family = AF_INET6;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
+#endif
+ sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
+ sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
+ memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
+ sockaddr->type.sin6.sin6_port = htons(port);
+ sockaddr->length = sizeof(sockaddr->type.sin6);
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+int
+isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
+
+ /*
+ * Get the protocol family of 'sockaddr'.
+ */
+
+#if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
+ /*
+ * Assume that PF_xxx == AF_xxx for all AF and PF.
+ */
+ return (sockaddr->type.sa.sa_family);
+#else
+ switch (sockaddr->type.sa.sa_family) {
+ case AF_INET:
+ return (PF_INET);
+ case AF_INET6:
+ return (PF_INET6);
+ default:
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
+ ISC_MSG_UNKNOWNFAMILY,
+ "unknown address family: %d"),
+ (int)sockaddr->type.sa.sa_family);
+ }
+#endif
+}
+
+void
+isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
+ in_port_t port)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin.sin_family = na->family;
+ switch (na->family) {
+ case AF_INET:
+ sockaddr->length = sizeof(sockaddr->type.sin);
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
+#endif
+ sockaddr->type.sin.sin_addr = na->type.in;
+ sockaddr->type.sin.sin_port = htons(port);
+ break;
+ case AF_INET6:
+ sockaddr->length = sizeof(sockaddr->type.sin6);
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
+#endif
+ memmove(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
+#endif
+ sockaddr->type.sin6.sin6_port = htons(port);
+ break;
+ default:
+ INSIST(0);
+ }
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+void
+isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
+ switch (sockaddr->type.sa.sa_family) {
+ case AF_INET:
+ sockaddr->type.sin.sin_port = htons(port);
+ break;
+ case AF_INET6:
+ sockaddr->type.sin6.sin6_port = htons(port);
+ break;
+ default:
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
+ ISC_MSG_UNKNOWNFAMILY,
+ "unknown address family: %d"),
+ (int)sockaddr->type.sa.sa_family);
+ }
+}
+
+in_port_t
+isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
+ in_port_t port = 0;
+
+ switch (sockaddr->type.sa.sa_family) {
+ case AF_INET:
+ port = ntohs(sockaddr->type.sin.sin_port);
+ break;
+ case AF_INET6:
+ port = ntohs(sockaddr->type.sin6.sin6_port);
+ break;
+ default:
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
+ ISC_MSG_UNKNOWNFAMILY,
+ "unknown address family: %d"),
+ (int)sockaddr->type.sa.sa_family);
+ }
+
+ return (port);
+}
+
+bool
+isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
+ isc_netaddr_t netaddr;
+
+ if (sockaddr->type.sa.sa_family == AF_INET ||
+ sockaddr->type.sa.sa_family == AF_INET6) {
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ return (isc_netaddr_ismulticast(&netaddr));
+ }
+ return (false);
+}
+
+bool
+isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
+ isc_netaddr_t netaddr;
+
+ if (sockaddr->type.sa.sa_family == AF_INET) {
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ return (isc_netaddr_isexperimental(&netaddr));
+ }
+ return (false);
+}
+
+bool
+isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
+ isc_netaddr_t netaddr;
+
+ if (sockaddr->type.sa.sa_family == AF_INET6) {
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ return (isc_netaddr_issitelocal(&netaddr));
+ }
+ return (false);
+}
+
+bool
+isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
+ isc_netaddr_t netaddr;
+
+ if (sockaddr->type.sa.sa_family == AF_INET6) {
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ return (isc_netaddr_islinklocal(&netaddr));
+ }
+ return (false);
+}
+
+bool
+isc_sockaddr_isnetzero(const isc_sockaddr_t *sockaddr) {
+ isc_netaddr_t netaddr;
+
+ if (sockaddr->type.sa.sa_family == AF_INET) {
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ return (isc_netaddr_isnetzero(&netaddr));
+ }
+ return (false);
+}
+
+isc_result_t
+isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
+ return (ISC_R_NOSPACE);
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->length = sizeof(sockaddr->type.sunix);
+ sockaddr->type.sunix.sun_family = AF_UNIX;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sunix.sun_len =
+ (unsigned char)sizeof(sockaddr->type.sunix);
+#endif
+ strlcpy(sockaddr->type.sunix.sun_path, path,
+ sizeof(sockaddr->type.sunix.sun_path));
+ return (ISC_R_SUCCESS);
+#else
+ UNUSED(sockaddr);
+ UNUSED(path);
+ return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
diff --git a/lib/isc/socket_api.c b/lib/isc/socket_api.c
new file mode 100644
index 0000000..5de98a9
--- /dev/null
+++ b/lib/isc/socket_api.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/app.h>
+#include <isc/magic.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/socket.h>
+#include <isc/util.h>
+
+static isc_mutex_t createlock;
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_socketmgrcreatefunc_t socketmgr_createfunc = NULL;
+
+static void
+initialize(void) {
+ RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_register(isc_socketmgrcreatefunc_t createfunc) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
+
+ LOCK(&createlock);
+ if (socketmgr_createfunc == NULL)
+ socketmgr_createfunc = createfunc;
+ else
+ result = ISC_R_EXISTS;
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+isc_result_t
+isc_socketmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
+ isc_socketmgr_t **managerp)
+{
+ isc_result_t result;
+
+ LOCK(&createlock);
+
+ REQUIRE(socketmgr_createfunc != NULL);
+ result = (*socketmgr_createfunc)(mctx, managerp);
+
+ UNLOCK(&createlock);
+
+ if (result == ISC_R_SUCCESS)
+ isc_appctx_setsocketmgr(actx, *managerp);
+
+ return (result);
+}
+
+isc_result_t
+isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
+ isc_result_t result;
+
+ if (isc_bind9)
+ return (isc__socketmgr_create(mctx, managerp));
+
+ LOCK(&createlock);
+
+ REQUIRE(socketmgr_createfunc != NULL);
+ result = (*socketmgr_createfunc)(mctx, managerp);
+
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+void
+isc_socketmgr_destroy(isc_socketmgr_t **managerp) {
+ REQUIRE(managerp != NULL && ISCAPI_SOCKETMGR_VALID(*managerp));
+
+ if (isc_bind9)
+ isc__socketmgr_destroy(managerp);
+ else
+ (*managerp)->methods->destroy(managerp);
+
+ ENSURE(*managerp == NULL);
+}
+
+isc_result_t
+isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
+ isc_socket_t **socketp)
+{
+ REQUIRE(ISCAPI_SOCKETMGR_VALID(manager));
+
+ if (isc_bind9)
+ return (isc__socket_create(manager, pf, type, socketp));
+
+ return (manager->methods->socketcreate(manager, pf, type, socketp));
+}
+
+void
+isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ if (isc_bind9)
+ isc__socket_attach(sock, socketp);
+ else
+ sock->methods->attach(sock, socketp);
+
+ ENSURE(*socketp == sock);
+}
+
+void
+isc_socket_detach(isc_socket_t **socketp) {
+ REQUIRE(socketp != NULL && ISCAPI_SOCKET_VALID(*socketp));
+
+ if (isc_bind9)
+ isc__socket_detach(socketp);
+ else
+ (*socketp)->methods->detach(socketp);
+
+ ENSURE(*socketp == NULL);
+}
+
+isc_result_t
+isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr,
+ unsigned int options)
+{
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ if (isc_bind9)
+ return (isc__socket_bind(sock, sockaddr, options));
+
+ return (sock->methods->bind(sock, sockaddr, options));
+}
+
+isc_result_t
+isc_socket_sendto(isc_socket_t *sock, isc_region_t *region, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ if (isc_bind9)
+ return (isc__socket_sendto(sock, region, task,
+ action, arg, address, pktinfo));
+
+ return (sock->methods->sendto(sock, region, task, action, arg, address,
+ pktinfo));
+}
+
+isc_result_t
+isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, isc_task_t *task,
+ isc_taskaction_t action, void *arg)
+{
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ if (isc_bind9)
+ return (isc__socket_connect(sock, addr, task, action, arg));
+
+ return (sock->methods->connect(sock, addr, task, action, arg));
+}
+
+isc_result_t
+isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ if (isc_bind9)
+ return (isc__socket_recv(sock, region, minimum,
+ task, action, arg));
+
+ return (sock->methods->recv(sock, region, minimum, task, action, arg));
+}
+
+void
+isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ if (isc_bind9)
+ isc__socket_cancel(sock, task, how);
+ else
+ sock->methods->cancel(sock, task, how);
+}
+
+isc_result_t
+isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ if (isc_bind9)
+ return (isc__socket_getsockname(sock, addressp));
+
+ return (sock->methods->getsockname(sock, addressp));
+}
+
+void
+isc_socket_ipv6only(isc_socket_t *sock, bool yes) {
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ if (isc_bind9)
+ isc__socket_ipv6only(sock, yes);
+ else
+ sock->methods->ipv6only(sock, yes);
+}
+
+void
+isc_socket_dscp(isc_socket_t *sock, isc_dscp_t dscp) {
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ sock->methods->dscp(sock, dscp);
+}
+
+isc_sockettype_t
+isc_socket_gettype(isc_socket_t *sock) {
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ if (isc_bind9)
+ return (isc__socket_gettype(sock));
+
+ return (sock->methods->gettype(sock));
+}
+
+void
+isc_socket_setname(isc_socket_t *sock, const char *name, void *tag) {
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ UNUSED(sock); /* in case REQUIRE() is empty */
+ UNUSED(name);
+ UNUSED(tag);
+}
+
+isc_result_t
+isc_socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags,
+ isc_sockfdwatch_t callback, void *cbarg,
+ isc_task_t *task, isc_socket_t **socketp)
+{
+ REQUIRE(ISCAPI_SOCKETMGR_VALID(manager));
+
+ if (isc_bind9)
+ return (isc__socket_fdwatchcreate(manager, fd, flags,
+ callback, cbarg,
+ task, socketp));
+
+ return (manager->methods->fdwatchcreate(manager, fd, flags,
+ callback, cbarg, task,
+ socketp));
+}
+
+isc_result_t
+isc_socket_fdwatchpoke(isc_socket_t *sock, int flags)
+{
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ if (isc_bind9)
+ return (isc__socket_fdwatchpoke(sock, flags));
+
+ return (sock->methods->fdwatchpoke(sock, flags));
+}
+
+isc_result_t
+isc_socket_dup(isc_socket_t *sock, isc_socket_t **socketp) {
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ if (isc_bind9)
+ return (isc__socket_dup(sock, socketp));
+
+ return (sock->methods->dup(sock, socketp));
+}
+
+int
+isc_socket_getfd(isc_socket_t *sock) {
+ REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+ if (isc_bind9)
+ return (isc__socket_getfd(sock));
+
+ return (sock->methods->getfd(sock));
+}
+
+isc_result_t
+isc_socket_open(isc_socket_t *sock) {
+ return (isc__socket_open(sock));
+}
+
+isc_result_t
+isc_socket_close(isc_socket_t *sock) {
+ return (isc__socket_close(sock));
+}
+
+isc_result_t
+isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
+ unsigned int maxsocks)
+{
+ return (isc__socketmgr_create2(mctx, managerp, maxsocks));
+}
+
+isc_result_t
+isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ unsigned int minimum, isc_task_t *task,
+ isc_taskaction_t action, void *arg)
+{
+ return (isc__socket_recvv(sock, buflist, minimum, task, action, arg));
+}
+
+isc_result_t
+isc_socket_recv2(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_socketevent_t *event, unsigned int flags)
+{
+ return (isc__socket_recv2(sock, region, minimum, task, event, flags));
+}
+
+isc_result_t
+isc_socket_send(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ return (isc__socket_send(sock, region, task, action, arg));
+}
+
+isc_result_t
+isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ return (isc__socket_sendv(sock, buflist, task, action, arg));
+}
+
+isc_result_t
+isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+ return (isc__socket_sendtov(sock, buflist, task, action, arg,
+ address, pktinfo));
+}
+
+isc_result_t
+isc_socket_sendtov2(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ unsigned int flags)
+{
+ return (isc__socket_sendtov2(sock, buflist, task, action, arg,
+ address, pktinfo, flags));
+}
+
+isc_result_t
+isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ isc_socketevent_t *event, unsigned int flags)
+{
+ return (isc__socket_sendto2(sock, region, task, address, pktinfo,
+ event, flags));
+}
+
+void
+isc_socket_cleanunix(isc_sockaddr_t *sockaddr, bool active) {
+ isc__socket_cleanunix(sockaddr, active);
+}
+
+isc_result_t
+isc_socket_permunix(isc_sockaddr_t *sockaddr, uint32_t perm,
+ uint32_t owner, uint32_t group)
+{
+ return (isc__socket_permunix(sockaddr, perm, owner, group));
+}
+
+isc_result_t
+isc_socket_filter(isc_socket_t *sock, const char *filter) {
+ return (isc__socket_filter(sock, filter));
+}
+
+isc_result_t
+isc_socket_listen(isc_socket_t *sock, unsigned int backlog) {
+ return (isc__socket_listen(sock, backlog));
+}
+
+isc_result_t
+isc_socket_accept(isc_socket_t *sock, isc_task_t *task,
+ isc_taskaction_t action, void *arg)
+{
+ return (isc__socket_accept(sock, task, action, arg));
+}
+
+isc_result_t
+isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+ return (isc__socket_getpeername(sock, addressp));
+}
diff --git a/lib/isc/sparc64/Makefile.in b/lib/isc/sparc64/Makefile.in
new file mode 100644
index 0000000..419cf9f
--- /dev/null
+++ b/lib/isc/sparc64/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/sparc64/include/Makefile.in b/lib/isc/sparc64/include/Makefile.in
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/lib/isc/sparc64/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/sparc64/include/isc/Makefile.in b/lib/isc/sparc64/include/isc/Makefile.in
new file mode 100644
index 0000000..6075633
--- /dev/null
+++ b/lib/isc/sparc64/include/isc/Makefile.in
@@ -0,0 +1,29 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
diff --git a/lib/isc/sparc64/include/isc/atomic.h b/lib/isc/sparc64/include/isc/atomic.h
new file mode 100644
index 0000000..21ec67e
--- /dev/null
+++ b/lib/isc/sparc64/include/isc/atomic.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * This code was written based on FreeBSD's kernel source whose copyright
+ * follows:
+ */
+
+/*-
+ * Copyright (c) 1998 Doug Rabson.
+ * Copyright (c) 2001 Jake Burkholder.
+ * 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 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 AUTHOR 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.
+ *
+ * from: FreeBSD: src/sys/i386/include/atomic.h,v 1.20 2001/02/11
+ * $FreeBSD: src/sys/sparc64/include/atomic.h,v 1.8 2004/05/22 00:52:16 marius Exp $
+ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <inttypes.h>
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#define ASI_P 0x80 /* Primary Address Space Identifier */
+
+#ifdef ISC_PLATFORM_USEGCCASM
+
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+static inline int32_t
+isc_atomic_xadd(int32_t *p, int32_t val) {
+ int32_t prev, swapped;
+
+ for (prev = *(volatile int32_t *)p; ; prev = swapped) {
+ swapped = prev + val;
+ __asm__ volatile(
+ "casa [%2] %3, %4, %0"
+ : "+r"(swapped), "=m"(*p)
+ : "r"(p), "n"(ASI_P), "r"(prev), "m"(*p));
+ if (swapped == prev)
+ break;
+ }
+
+ return (prev);
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(int32_t *p, int32_t val) {
+ int32_t prev, swapped;
+
+ for (prev = *(volatile int32_t *)p; ; prev = swapped) {
+ swapped = val;
+ __asm__ volatile(
+ "casa [%2] %3, %4, %0"
+ : "+r"(swapped), "=m"(*p)
+ : "r"(p), "n"(ASI_P), "r"(prev), "m"(*p));
+ if (swapped == prev)
+ break;
+ }
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+static inline int32_t
+isc_atomic_cmpxchg(int32_t *p, int32_t cmpval, int32_t val) {
+ int32_t temp = val;
+
+ __asm__ volatile(
+ "casa [%2] %3, %4, %0"
+ : "+r"(temp), "=m"(*p)
+ : "r"(p), "n"(ASI_P), "r"(cmpval), "m"(*p));
+
+ return (temp);
+}
+
+#else /* ISC_PLATFORM_USEGCCASM */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif /* ISC_PLATFORM_USEGCCASM */
+
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/stats.c b/lib/isc/stats.c
new file mode 100644
index 0000000..196099e
--- /dev/null
+++ b/lib/isc/stats.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <isc/atomic.h>
+#include <isc/buffer.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/rwlock.h>
+#include <isc/stats.h>
+#include <isc/util.h>
+
+#if defined(ISC_PLATFORM_HAVESTDATOMIC)
+#if defined(__cplusplus)
+#include <isc/stdatomic.h>
+#else
+#include <stdatomic.h>
+#endif
+#endif
+
+#define ISC_STATS_MAGIC ISC_MAGIC('S', 't', 'a', 't')
+#define ISC_STATS_VALID(x) ISC_MAGIC_VALID(x, ISC_STATS_MAGIC)
+
+/*%
+ * Local macro confirming prescence of 64-bit
+ * increment and store operations, just to make
+ * the later macros simpler
+ */
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_LONG_LOCK_FREE)) || \
+ (defined(ISC_PLATFORM_HAVEXADDQ) && defined(ISC_PLATFORM_HAVEATOMICSTOREQ))
+#define ISC_STATS_HAVEATOMICQ 1
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_LONG_LOCK_FREE))
+#define ISC_STATS_HAVESTDATOMICQ 1
+#endif
+#else
+#define ISC_STATS_HAVEATOMICQ 0
+#endif
+
+/*%
+ * Only lock the counters if 64-bit atomic operations are
+ * not available but cheap atomic lock operations are.
+ * On a modern 64-bit system this should never be the case.
+ *
+ * Normal locks are too expensive to be used whenever a counter
+ * is updated.
+ */
+#if !ISC_STATS_HAVEATOMICQ && defined(ISC_RWLOCK_HAVEATOMIC)
+#define ISC_STATS_LOCKCOUNTERS 1
+#else
+#define ISC_STATS_LOCKCOUNTERS 0
+#endif
+
+/*%
+ * If 64-bit atomic operations are not available but
+ * 32-bit operations are then split the counter into two,
+ * using the atomic operations to try to ensure that any carry
+ * from the low word is correctly carried into the high word.
+ *
+ * Otherwise, just rely on standard 64-bit data types
+ * and operations
+ */
+#if !ISC_STATS_HAVEATOMICQ && ((defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE)) || defined(ISC_PLATFORM_HAVEXADD))
+#define ISC_STATS_USEMULTIFIELDS 1
+#if (defined(ISC_PLATFORM_HAVESTDATOMIC) && defined(ATOMIC_INT_LOCK_FREE))
+#define ISC_STATS_HAVESTDATOMIC 1
+#endif
+#else
+#define ISC_STATS_USEMULTIFIELDS 0
+#endif
+
+#if ISC_STATS_USEMULTIFIELDS
+typedef struct {
+#if defined(ISC_STATS_HAVESTDATOMIC)
+ atomic_int_fast32_t hi;
+ atomic_int_fast32_t lo;
+#else
+ uint32_t hi;
+ uint32_t lo;
+#endif
+} isc_stat_t;
+#else
+#if defined(ISC_STATS_HAVESTDATOMICQ)
+typedef atomic_int_fast64_t isc_stat_t;
+#else
+typedef uint64_t isc_stat_t;
+#endif
+#endif
+
+struct isc_stats {
+ /*% Unlocked */
+ unsigned int magic;
+ isc_mem_t *mctx;
+ int ncounters;
+
+ isc_mutex_t lock;
+ unsigned int references; /* locked by lock */
+
+ /*%
+ * Locked by counterlock or unlocked if efficient rwlock is not
+ * available.
+ */
+#if ISC_STATS_LOCKCOUNTERS
+ isc_rwlock_t counterlock;
+#endif
+ isc_stat_t *counters;
+
+ /*%
+ * We don't want to lock the counters while we are dumping, so we first
+ * copy the current counter values into a local array. This buffer
+ * will be used as the copy destination. It's allocated on creation
+ * of the stats structure so that the dump operation won't fail due
+ * to memory allocation failure.
+ * XXX: this approach is weird for non-threaded build because the
+ * additional memory and the copy overhead could be avoided. We prefer
+ * simplicity here, however, under the assumption that this function
+ * should be only rarely called.
+ */
+ uint64_t *copiedcounters;
+};
+
+static isc_result_t
+create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) {
+ isc_stats_t *stats;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(statsp != NULL && *statsp == NULL);
+
+ stats = isc_mem_get(mctx, sizeof(*stats));
+ if (stats == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = isc_mutex_init(&stats->lock);
+ if (result != ISC_R_SUCCESS)
+ goto clean_stats;
+
+ stats->counters = isc_mem_get(mctx, sizeof(isc_stat_t) * ncounters);
+ if (stats->counters == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto clean_mutex;
+ }
+ stats->copiedcounters = isc_mem_get(mctx,
+ sizeof(uint64_t) * ncounters);
+ if (stats->copiedcounters == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto clean_counters;
+ }
+
+#if ISC_STATS_LOCKCOUNTERS
+ result = isc_rwlock_init(&stats->counterlock, 0, 0);
+ if (result != ISC_R_SUCCESS)
+ goto clean_copiedcounters;
+#endif
+
+ stats->references = 1;
+ memset(stats->counters, 0, sizeof(isc_stat_t) * ncounters);
+ stats->mctx = NULL;
+ isc_mem_attach(mctx, &stats->mctx);
+ stats->ncounters = ncounters;
+ stats->magic = ISC_STATS_MAGIC;
+
+ *statsp = stats;
+
+ return (result);
+
+clean_counters:
+ isc_mem_put(mctx, stats->counters, sizeof(isc_stat_t) * ncounters);
+
+#if ISC_STATS_LOCKCOUNTERS
+clean_copiedcounters:
+ isc_mem_put(mctx, stats->copiedcounters,
+ sizeof(isc_stat_t) * ncounters);
+#endif
+
+clean_mutex:
+ DESTROYLOCK(&stats->lock);
+
+clean_stats:
+ isc_mem_put(mctx, stats, sizeof(*stats));
+
+ return (result);
+}
+
+void
+isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp) {
+ REQUIRE(ISC_STATS_VALID(stats));
+ REQUIRE(statsp != NULL && *statsp == NULL);
+
+ LOCK(&stats->lock);
+ stats->references++;
+ UNLOCK(&stats->lock);
+
+ *statsp = stats;
+}
+
+void
+isc_stats_detach(isc_stats_t **statsp) {
+ isc_stats_t *stats;
+
+ REQUIRE(statsp != NULL && ISC_STATS_VALID(*statsp));
+
+ stats = *statsp;
+ *statsp = NULL;
+
+ LOCK(&stats->lock);
+ stats->references--;
+
+ if (stats->references == 0) {
+ isc_mem_put(stats->mctx, stats->copiedcounters,
+ sizeof(isc_stat_t) * stats->ncounters);
+ isc_mem_put(stats->mctx, stats->counters,
+ sizeof(isc_stat_t) * stats->ncounters);
+ UNLOCK(&stats->lock);
+ DESTROYLOCK(&stats->lock);
+#if ISC_STATS_LOCKCOUNTERS
+ isc_rwlock_destroy(&stats->counterlock);
+#endif
+ isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
+ return;
+ }
+
+ UNLOCK(&stats->lock);
+}
+
+int
+isc_stats_ncounters(isc_stats_t *stats) {
+ REQUIRE(ISC_STATS_VALID(stats));
+
+ return (stats->ncounters);
+}
+
+static inline void
+incrementcounter(isc_stats_t *stats, int counter) {
+ int32_t prev;
+
+#if ISC_STATS_LOCKCOUNTERS
+ /*
+ * We use a "read" lock to prevent other threads from reading the
+ * counter while we "writing" a counter field. The write access itself
+ * is protected by the atomic operation.
+ */
+ isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_read);
+#endif
+
+#if ISC_STATS_USEMULTIFIELDS
+#if defined(ISC_STATS_HAVESTDATOMIC)
+ prev = atomic_fetch_add_explicit(&stats->counters[counter].lo, 1,
+ memory_order_relaxed);
+#else
+ prev = isc_atomic_xadd((int32_t *)&stats->counters[counter].lo, 1);
+#endif
+ /*
+ * If the lower 32-bit field overflows, increment the higher field.
+ * Note that it's *theoretically* possible that the lower field
+ * overlaps again before the higher field is incremented. It doesn't
+ * matter, however, because we don't read the value until
+ * isc_stats_copy() is called where the whole process is protected
+ * by the write (exclusive) lock.
+ */
+ if (prev == (int32_t)0xffffffff) {
+#if defined(ISC_STATS_HAVESTDATOMIC)
+ atomic_fetch_add_explicit(&stats->counters[counter].hi, 1,
+ memory_order_relaxed);
+#else
+ isc_atomic_xadd((int32_t *)&stats->counters[counter].hi, 1);
+#endif
+ }
+#elif ISC_STATS_HAVEATOMICQ
+ UNUSED(prev);
+#if defined(ISC_STATS_HAVESTDATOMICQ)
+ atomic_fetch_add_explicit(&stats->counters[counter], 1,
+ memory_order_relaxed);
+#else
+ isc_atomic_xaddq((int64_t *)&stats->counters[counter], 1);
+#endif
+#else
+ UNUSED(prev);
+ stats->counters[counter]++;
+#endif
+
+#if ISC_STATS_LOCKCOUNTERS
+ isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_read);
+#endif
+}
+
+static inline void
+decrementcounter(isc_stats_t *stats, int counter) {
+ int32_t prev;
+
+#if ISC_STATS_LOCKCOUNTERS
+ isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_read);
+#endif
+
+#if ISC_STATS_USEMULTIFIELDS
+#if defined(ISC_STATS_HAVESTDATOMIC)
+ prev = atomic_fetch_sub_explicit(&stats->counters[counter].lo, 1,
+ memory_order_relaxed);
+#else
+ prev = isc_atomic_xadd((int32_t *)&stats->counters[counter].lo, -1);
+#endif
+ if (prev == 0) {
+#if defined(ISC_STATS_HAVESTDATOMIC)
+ atomic_fetch_sub_explicit(&stats->counters[counter].hi, 1,
+ memory_order_relaxed);
+#else
+ isc_atomic_xadd((int32_t *)&stats->counters[counter].hi,
+ -1);
+#endif
+ }
+#elif ISC_STATS_HAVEATOMICQ
+ UNUSED(prev);
+#if defined(ISC_STATS_HAVESTDATOMICQ)
+ atomic_fetch_sub_explicit(&stats->counters[counter], 1,
+ memory_order_relaxed);
+#else
+ isc_atomic_xaddq((int64_t *)&stats->counters[counter], -1);
+#endif
+#else
+ UNUSED(prev);
+ stats->counters[counter]--;
+#endif
+
+#if ISC_STATS_LOCKCOUNTERS
+ isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_read);
+#endif
+}
+
+static void
+copy_counters(isc_stats_t *stats) {
+ int i;
+
+#if ISC_STATS_LOCKCOUNTERS
+ /*
+ * We use a "write" lock before "reading" the statistics counters as
+ * an exclusive lock.
+ */
+ isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_write);
+#endif
+
+ for (i = 0; i < stats->ncounters; i++) {
+#if ISC_STATS_USEMULTIFIELDS
+ stats->copiedcounters[i] =
+ (uint64_t)(stats->counters[i].hi) << 32 |
+ stats->counters[i].lo;
+#elif ISC_STATS_HAVEATOMICQ
+#if defined(ISC_STATS_HAVESTDATOMICQ)
+ stats->copiedcounters[i] =
+ atomic_load_explicit(&stats->counters[i],
+ memory_order_relaxed);
+#else
+ /* use xaddq(..., 0) as an atomic load */
+ stats->copiedcounters[i] =
+ (uint64_t)isc_atomic_xaddq((int64_t *)&stats->counters[i], 0);
+#endif
+#else
+ stats->copiedcounters[i] = stats->counters[i];
+#endif
+ }
+
+#if ISC_STATS_LOCKCOUNTERS
+ isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_write);
+#endif
+}
+
+isc_result_t
+isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters) {
+ REQUIRE(statsp != NULL && *statsp == NULL);
+
+ return (create_stats(mctx, ncounters, statsp));
+}
+
+void
+isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter) {
+ REQUIRE(ISC_STATS_VALID(stats));
+ REQUIRE(counter < stats->ncounters);
+
+ incrementcounter(stats, (int)counter);
+}
+
+void
+isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter) {
+ REQUIRE(ISC_STATS_VALID(stats));
+ REQUIRE(counter < stats->ncounters);
+
+ decrementcounter(stats, (int)counter);
+}
+
+void
+isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn,
+ void *arg, unsigned int options)
+{
+ int i;
+
+ REQUIRE(ISC_STATS_VALID(stats));
+
+ copy_counters(stats);
+
+ for (i = 0; i < stats->ncounters; i++) {
+ if ((options & ISC_STATSDUMP_VERBOSE) == 0 &&
+ stats->copiedcounters[i] == 0)
+ continue;
+ dump_fn((isc_statscounter_t)i, stats->copiedcounters[i], arg);
+ }
+}
+
+void
+isc_stats_set(isc_stats_t *stats, uint64_t val,
+ isc_statscounter_t counter)
+{
+ REQUIRE(ISC_STATS_VALID(stats));
+ REQUIRE(counter < stats->ncounters);
+
+#if ISC_STATS_LOCKCOUNTERS
+ /*
+ * We use a "write" lock before "reading" the statistics counters as
+ * an exclusive lock.
+ */
+ isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_write);
+#endif
+
+#if ISC_STATS_USEMULTIFIELDS
+ stats->counters[counter].hi = (uint32_t)((val >> 32) & 0xffffffff);
+ stats->counters[counter].lo = (uint32_t)(val & 0xffffffff);
+#elif ISC_STATS_HAVEATOMICQ
+#if defined(ISC_STATS_HAVESTDATOMICQ)
+ atomic_store_explicit(&stats->counters[counter], val,
+ memory_order_relaxed);
+#else
+ isc_atomic_storeq((int64_t *)&stats->counters[counter], val);
+#endif
+#else
+ stats->counters[counter] = val;
+#endif
+
+#if ISC_STATS_LOCKCOUNTERS
+ isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_write);
+#endif
+}
diff --git a/lib/isc/string.c b/lib/isc/string.c
new file mode 100644
index 0000000..6728cfb
--- /dev/null
+++ b/lib/isc/string.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * Copyright (c) 1990, 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. 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.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+static const char digits[] = "0123456789abcdefghijklmnoprstuvwxyz";
+
+uint64_t
+isc_string_touint64(char *source, char **end, int base) {
+ uint64_t tmp;
+ uint64_t overflow;
+ char *s = source;
+ const char *o;
+ char c;
+
+ if ((base < 0) || (base == 1) || (base > 36)) {
+ *end = source;
+ return (0);
+ }
+
+ while (*s != 0 && isascii(*s&0xff) && isspace(*s&0xff))
+ s++;
+ if (*s == '+' /* || *s == '-' */)
+ s++;
+ if (base == 0) {
+ if (*s == '0' && (*(s+1) == 'X' || *(s+1) == 'x')) {
+ s += 2;
+ base = 16;
+ } else if (*s == '0')
+ base = 8;
+ else
+ base = 10;
+ }
+ if (*s == 0) {
+ *end = source;
+ return (0);
+ }
+ overflow = ~0;
+ overflow /= base;
+ tmp = 0;
+
+ while ((c = *s) != 0) {
+ c = tolower(c&0xff);
+ /* end ? */
+ if ((o = strchr(digits, c)) == NULL) {
+ *end = s;
+ return (tmp);
+ }
+ /* end ? */
+ if ((o - digits) >= base) {
+ *end = s;
+ return (tmp);
+ }
+ /* overflow ? */
+ if (tmp > overflow) {
+ *end = source;
+ return (0);
+ }
+ tmp *= base;
+ /* overflow ? */
+ if ((tmp + (o - digits)) < tmp) {
+ *end = source;
+ return (0);
+ }
+ tmp += o - digits;
+ s++;
+ }
+ *end = s;
+ return (tmp);
+}
+
+isc_result_t
+isc_string_copy(char *target, size_t size, const char *source) {
+ REQUIRE(size > 0U);
+
+ if (strlcpy(target, source, size) >= size) {
+ memset(target, ISC_STRING_MAGIC, size);
+ return (ISC_R_NOSPACE);
+ }
+
+ ENSURE(strlen(target) < size);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_string_copy_truncate(char *target, size_t size, const char *source) {
+ REQUIRE(size > 0U);
+
+ strlcpy(target, source, size);
+
+ ENSURE(strlen(target) < size);
+}
+
+isc_result_t
+isc_string_append(char *target, size_t size, const char *source) {
+ REQUIRE(size > 0U);
+ REQUIRE(strlen(target) < size);
+
+ if (strlcat(target, source, size) >= size) {
+ memset(target, ISC_STRING_MAGIC, size);
+ return (ISC_R_NOSPACE);
+ }
+
+ ENSURE(strlen(target) < size);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_string_append_truncate(char *target, size_t size, const char *source) {
+ REQUIRE(size > 0U);
+ REQUIRE(strlen(target) < size);
+
+ strlcat(target, source, size);
+
+ ENSURE(strlen(target) < size);
+}
+
+isc_result_t
+isc_string_printf(char *target, size_t size, const char *format, ...) {
+ va_list args;
+ size_t n;
+
+ REQUIRE(size > 0U);
+
+ va_start(args, format);
+ n = vsnprintf(target, size, format, args);
+ va_end(args);
+
+ if (n >= size) {
+ memset(target, ISC_STRING_MAGIC, size);
+ return (ISC_R_NOSPACE);
+ }
+
+ ENSURE(strlen(target) < size);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_string_printf_truncate(char *target, size_t size, const char *format, ...)
+{
+ va_list args;
+
+ REQUIRE(size > 0U);
+
+ va_start(args, format);
+ /* check return code? */
+ (void)vsnprintf(target, size, format, args);
+ va_end(args);
+
+ ENSURE(strlen(target) < size);
+}
+
+char *
+isc_string_regiondup(isc_mem_t *mctx, const isc_region_t *source) {
+ char *target;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(source != NULL);
+
+ target = (char *) isc_mem_allocate(mctx, source->length + 1);
+ if (target != NULL) {
+ memmove(source->base, target, source->length);
+ target[source->length] = '\0';
+ }
+
+ return (target);
+}
+
+char *
+isc_string_separate(char **stringp, const char *delim) {
+ char *string = *stringp;
+ char *s;
+ const char *d;
+ char sc, dc;
+
+ if (string == NULL)
+ return (NULL);
+
+ for (s = string; (sc = *s) != '\0'; s++)
+ for (d = delim; (dc = *d) != '\0'; d++)
+ if (sc == dc) {
+ *s++ = '\0';
+ *stringp = s;
+ return (string);
+ }
+ *stringp = NULL;
+ return (string);
+}
+
+size_t
+isc_string_strlcpy(char *dst, const char *src, size_t size)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = size;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0U && --n != 0U) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0U);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0U) {
+ if (size != 0U)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
+size_t
+isc_string_strlcat(char *dst, const char *src, size_t size)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = size;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0U && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = size - dlen;
+
+ if (n == 0U)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1U) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+char *
+isc_string_strcasestr(const char *str, const char *search) {
+ char c, sc, *s;
+ size_t len;
+
+ if ((c = *search++) != 0) {
+ c = tolower((unsigned char) c);
+ len = strlen(search);
+ do {
+ do {
+ if ((sc = *str++) == 0)
+ return (NULL);
+ } while ((char) tolower((unsigned char) sc) != c);
+ } while (strncasecmp(str, search, len) != 0);
+ str--;
+ }
+ DE_CONST(str, s);
+ return (s);
+
+}
diff --git a/lib/isc/strtoul.c b/lib/isc/strtoul.c
new file mode 100644
index 0000000..acc541a
--- /dev/null
+++ b/lib/isc/strtoul.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * Copyright (c) 1990, 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. 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.
+ */
+
+#include <config.h>
+
+/*! \file */
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <isc/stdlib.h>
+#include <isc/util.h>
+
+/*!
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+isc_strtoul(const char *nptr, char **endptr, int base) {
+ const char *s = nptr;
+ unsigned long acc;
+ unsigned char c;
+ unsigned long cutoff;
+ int neg = 0, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
+ cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (!isascii(c))
+ break;
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ DE_CONST(any ? s - 1 : nptr, *endptr);
+ return (acc);
+}
diff --git a/lib/isc/symtab.c b/lib/isc/symtab.c
new file mode 100644
index 0000000..b6466d3
--- /dev/null
+++ b/lib/isc/symtab.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/symtab.h>
+#include <isc/util.h>
+
+typedef struct elt {
+ char * key;
+ unsigned int type;
+ isc_symvalue_t value;
+ LINK(struct elt) link;
+} elt_t;
+
+typedef LIST(elt_t) eltlist_t;
+
+#define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
+#define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
+
+struct isc_symtab {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ unsigned int size;
+ unsigned int count;
+ unsigned int maxload;
+ eltlist_t * table;
+ isc_symtabaction_t undefine_action;
+ void * undefine_arg;
+ bool case_sensitive;
+};
+
+isc_result_t
+isc_symtab_create(isc_mem_t *mctx, unsigned int size,
+ isc_symtabaction_t undefine_action,
+ void *undefine_arg,
+ bool case_sensitive,
+ isc_symtab_t **symtabp)
+{
+ isc_symtab_t *symtab;
+ unsigned int i;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(symtabp != NULL && *symtabp == NULL);
+ REQUIRE(size > 0); /* Should be prime. */
+
+ symtab = (isc_symtab_t *)isc_mem_get(mctx, sizeof(*symtab));
+ if (symtab == NULL)
+ return (ISC_R_NOMEMORY);
+
+ symtab->mctx = NULL;
+ isc_mem_attach(mctx, &symtab->mctx);
+ symtab->table = (eltlist_t *)isc_mem_get(mctx,
+ size * sizeof(eltlist_t));
+ if (symtab->table == NULL) {
+ isc_mem_putanddetach(&symtab->mctx, symtab, sizeof(*symtab));
+ return (ISC_R_NOMEMORY);
+ }
+ for (i = 0; i < size; i++)
+ INIT_LIST(symtab->table[i]);
+ symtab->size = size;
+ symtab->count = 0;
+ symtab->maxload = size * 3 / 4;
+ symtab->undefine_action = undefine_action;
+ symtab->undefine_arg = undefine_arg;
+ symtab->case_sensitive = case_sensitive;
+ symtab->magic = SYMTAB_MAGIC;
+
+ *symtabp = symtab;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_symtab_destroy(isc_symtab_t **symtabp) {
+ isc_symtab_t *symtab;
+ unsigned int i;
+ elt_t *elt, *nelt;
+
+ REQUIRE(symtabp != NULL);
+ symtab = *symtabp;
+ REQUIRE(VALID_SYMTAB(symtab));
+
+ for (i = 0; i < symtab->size; i++) {
+ for (elt = HEAD(symtab->table[i]); elt != NULL; elt = nelt) {
+ nelt = NEXT(elt, link);
+ if (symtab->undefine_action != NULL)
+ (symtab->undefine_action)(elt->key,
+ elt->type,
+ elt->value,
+ symtab->undefine_arg);
+ isc_mem_put(symtab->mctx, elt, sizeof(*elt));
+ }
+ }
+ isc_mem_put(symtab->mctx, symtab->table,
+ symtab->size * sizeof(eltlist_t));
+ symtab->magic = 0;
+ isc_mem_putanddetach(&symtab->mctx, symtab, sizeof(*symtab));
+
+ *symtabp = NULL;
+}
+
+static inline unsigned int
+hash(const char *key, bool case_sensitive) {
+ const char *s;
+ unsigned int h = 0;
+ int c;
+
+ /*
+ * This hash function is similar to the one Ousterhout
+ * uses in Tcl.
+ */
+
+ if (case_sensitive) {
+ for (s = key; *s != '\0'; s++) {
+ h += (h << 3) + *s;
+ }
+ } else {
+ for (s = key; *s != '\0'; s++) {
+ c = *s;
+ c = tolower((unsigned char)c);
+ h += (h << 3) + c;
+ }
+ }
+
+ return (h);
+}
+
+#define FIND(s, k, t, b, e) \
+ b = hash((k), (s)->case_sensitive) % (s)->size; \
+ if ((s)->case_sensitive) { \
+ for (e = HEAD((s)->table[b]); e != NULL; e = NEXT(e, link)) { \
+ if (((t) == 0 || e->type == (t)) && \
+ strcmp(e->key, (k)) == 0) \
+ break; \
+ } \
+ } else { \
+ for (e = HEAD((s)->table[b]); e != NULL; e = NEXT(e, link)) { \
+ if (((t) == 0 || e->type == (t)) && \
+ strcasecmp(e->key, (k)) == 0) \
+ break; \
+ } \
+ }
+
+isc_result_t
+isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type,
+ isc_symvalue_t *value)
+{
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (elt == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (value != NULL)
+ *value = elt->value;
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+grow_table(isc_symtab_t *symtab) {
+ eltlist_t *newtable;
+ unsigned int i, newsize, newmax;
+
+ REQUIRE(symtab != NULL);
+
+ newsize = symtab->size * 2;
+ newmax = newsize * 3 / 4;
+ INSIST(newsize > 0U && newmax > 0U);
+
+ newtable = isc_mem_get(symtab->mctx, newsize * sizeof(eltlist_t));
+ if (newtable == NULL)
+ return;
+
+ for (i = 0; i < newsize; i++)
+ INIT_LIST(newtable[i]);
+
+ for (i = 0; i < symtab->size; i++) {
+ elt_t *elt, *nelt;
+
+ for (elt = HEAD(symtab->table[i]); elt != NULL; elt = nelt) {
+ unsigned int hv;
+
+ nelt = NEXT(elt, link);
+
+ UNLINK(symtab->table[i], elt, link);
+ hv = hash(elt->key, symtab->case_sensitive);
+ APPEND(newtable[hv % newsize], elt, link);
+ }
+ }
+
+ isc_mem_put(symtab->mctx, symtab->table,
+ symtab->size * sizeof(eltlist_t));
+
+ symtab->table = newtable;
+ symtab->size = newsize;
+ symtab->maxload = newmax;
+}
+
+isc_result_t
+isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
+ isc_symvalue_t value, isc_symexists_t exists_policy)
+{
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+ REQUIRE(type != 0);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (exists_policy != isc_symexists_add && elt != NULL) {
+ if (exists_policy == isc_symexists_reject)
+ return (ISC_R_EXISTS);
+ INSIST(exists_policy == isc_symexists_replace);
+ UNLINK(symtab->table[bucket], elt, link);
+ if (symtab->undefine_action != NULL)
+ (symtab->undefine_action)(elt->key, elt->type,
+ elt->value,
+ symtab->undefine_arg);
+ } else {
+ elt = (elt_t *)isc_mem_get(symtab->mctx, sizeof(*elt));
+ if (elt == NULL)
+ return (ISC_R_NOMEMORY);
+ ISC_LINK_INIT(elt, link);
+ symtab->count++;
+ }
+
+ /*
+ * Though the "key" can be const coming in, it is not stored as const
+ * so that the calling program can easily have writable access to
+ * it in its undefine_action function. In the event that it *was*
+ * truly const coming in and then the caller modified it anyway ...
+ * well, don't do that!
+ */
+ DE_CONST(key, elt->key);
+ elt->type = type;
+ elt->value = value;
+
+ /*
+ * We prepend so that the most recent definition will be found.
+ */
+ PREPEND(symtab->table[bucket], elt, link);
+
+ if (symtab->count > symtab->maxload)
+ grow_table(symtab);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type) {
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (elt == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (symtab->undefine_action != NULL)
+ (symtab->undefine_action)(elt->key, elt->type,
+ elt->value, symtab->undefine_arg);
+ UNLINK(symtab->table[bucket], elt, link);
+ isc_mem_put(symtab->mctx, elt, sizeof(*elt));
+ symtab->count--;
+
+ return (ISC_R_SUCCESS);
+}
+
+unsigned int
+isc_symtab_count(isc_symtab_t *symtab) {
+ REQUIRE(VALID_SYMTAB(symtab));
+ return (symtab->count);
+}
diff --git a/lib/isc/task.c b/lib/isc/task.c
new file mode 100644
index 0000000..f9f1eed
--- /dev/null
+++ b/lib/isc/task.c
@@ -0,0 +1,2327 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+/*
+ * XXXRTH Need to document the states a task can be in, and the rules
+ * for changing states.
+ */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/app.h>
+#include <isc/condition.h>
+#include <isc/event.h>
+#include <isc/json.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/once.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/time.h>
+#include <isc/util.h>
+#include <isc/xml.h>
+
+#ifdef OPENSSL_LEAKS
+#include <openssl/err.h>
+#endif
+
+/*%
+ * For BIND9 internal applications:
+ * when built with threads we use multiple worker threads shared by the whole
+ * application.
+ * when built without threads we share a single global task manager and use
+ * an integrated event loop for socket, timer, and other generic task events.
+ * For generic library:
+ * we don't use either of them: an application can have multiple task managers
+ * whether or not it's threaded, and if the application is threaded each thread
+ * is expected to have a separate manager; no "worker threads" are shared by
+ * the application threads.
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+#define USE_WORKER_THREADS
+#else
+#define USE_SHARED_MANAGER
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#include "task_p.h"
+
+#ifdef ISC_TASK_TRACE
+#define XTRACE(m) fprintf(stderr, "task %p thread %lu: %s\n", \
+ task, isc_thread_self(), (m))
+#define XTTRACE(t, m) fprintf(stderr, "task %p thread %lu: %s\n", \
+ (t), isc_thread_self(), (m))
+#define XTHREADTRACE(m) fprintf(stderr, "thread %lu: %s\n", \
+ isc_thread_self(), (m))
+#else
+#define XTRACE(m)
+#define XTTRACE(t, m)
+#define XTHREADTRACE(m)
+#endif
+
+/***
+ *** Types.
+ ***/
+
+typedef enum {
+ task_state_idle, task_state_ready, task_state_running,
+ task_state_done
+} task_state_t;
+
+#if defined(HAVE_LIBXML2) || defined(HAVE_JSON)
+static const char *statenames[] = {
+ "idle", "ready", "running", "done",
+};
+#endif
+
+#define TASK_MAGIC ISC_MAGIC('T', 'A', 'S', 'K')
+#define VALID_TASK(t) ISC_MAGIC_VALID(t, TASK_MAGIC)
+
+typedef struct isc__task isc__task_t;
+typedef struct isc__taskmgr isc__taskmgr_t;
+
+struct isc__task {
+ /* Not locked. */
+ isc_task_t common;
+ isc__taskmgr_t * manager;
+ isc_mutex_t lock;
+ /* Locked by task lock. */
+ task_state_t state;
+ unsigned int references;
+ isc_eventlist_t events;
+ isc_eventlist_t on_shutdown;
+ unsigned int nevents;
+ unsigned int quantum;
+ unsigned int flags;
+ isc_stdtime_t now;
+ isc_time_t tnow;
+ char name[16];
+ void * tag;
+ /* Locked by task manager lock. */
+ LINK(isc__task_t) link;
+ LINK(isc__task_t) ready_link;
+ LINK(isc__task_t) ready_priority_link;
+};
+
+#define TASK_F_SHUTTINGDOWN 0x01
+#define TASK_F_PRIVILEGED 0x02
+
+#define TASK_SHUTTINGDOWN(t) (((t)->flags & TASK_F_SHUTTINGDOWN) \
+ != 0)
+
+#define TASK_MANAGER_MAGIC ISC_MAGIC('T', 'S', 'K', 'M')
+#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TASK_MANAGER_MAGIC)
+
+typedef ISC_LIST(isc__task_t) isc__tasklist_t;
+
+struct isc__taskmgr {
+ /* Not locked. */
+ isc_taskmgr_t common;
+ isc_mem_t * mctx;
+ isc_mutex_t lock;
+#ifdef ISC_PLATFORM_USETHREADS
+ unsigned int workers;
+ isc_thread_t * threads;
+#endif /* ISC_PLATFORM_USETHREADS */
+ /* Locked by task manager lock. */
+ unsigned int default_quantum;
+ LIST(isc__task_t) tasks;
+ isc__tasklist_t ready_tasks;
+ isc__tasklist_t ready_priority_tasks;
+ isc_taskmgrmode_t mode;
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_condition_t work_available;
+ isc_condition_t exclusive_granted;
+ isc_condition_t paused;
+#endif /* ISC_PLATFORM_USETHREADS */
+ unsigned int tasks_running;
+ unsigned int tasks_ready;
+ bool pause_requested;
+ bool exclusive_requested;
+ bool exiting;
+
+ /*
+ * Multiple threads can read/write 'excl' at the same time, so we need
+ * to protect the access. We can't use 'lock' since isc_task_detach()
+ * will try to acquire it.
+ */
+ isc_mutex_t excl_lock;
+ isc__task_t *excl;
+#ifdef USE_SHARED_MANAGER
+ unsigned int refs;
+#endif /* ISC_PLATFORM_USETHREADS */
+};
+
+#define DEFAULT_TASKMGR_QUANTUM 10
+#define DEFAULT_DEFAULT_QUANTUM 5
+#define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks))
+
+#ifdef USE_SHARED_MANAGER
+static isc__taskmgr_t *taskmgr = NULL;
+#endif /* USE_SHARED_MANAGER */
+
+/*%
+ * The following are intended for internal use (indicated by "isc__"
+ * prefix) but are not declared as static, allowing direct access from
+ * unit tests etc.
+ */
+
+isc_result_t
+isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum,
+ isc_task_t **taskp);
+void
+isc__task_attach(isc_task_t *source0, isc_task_t **targetp);
+void
+isc__task_detach(isc_task_t **taskp);
+void
+isc__task_send(isc_task_t *task0, isc_event_t **eventp);
+void
+isc__task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp);
+unsigned int
+isc__task_purgerange(isc_task_t *task0, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag);
+unsigned int
+isc__task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag);
+bool
+isc_task_purgeevent(isc_task_t *task0, isc_event_t *event);
+unsigned int
+isc__task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag,
+ isc_eventlist_t *events);
+unsigned int
+isc__task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag, isc_eventlist_t *events);
+isc_result_t
+isc__task_onshutdown(isc_task_t *task0, isc_taskaction_t action,
+ void *arg);
+void
+isc__task_shutdown(isc_task_t *task0);
+void
+isc__task_destroy(isc_task_t **taskp);
+void
+isc__task_setname(isc_task_t *task0, const char *name, void *tag);
+const char *
+isc__task_getname(isc_task_t *task0);
+void *
+isc__task_gettag(isc_task_t *task0);
+void
+isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t);
+void
+isc__task_getcurrenttimex(isc_task_t *task0, isc_time_t *t);
+isc_result_t
+isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers,
+ unsigned int default_quantum, isc_taskmgr_t **managerp);
+void
+isc__taskmgr_destroy(isc_taskmgr_t **managerp);
+void
+isc_taskmgr_setexcltask(isc_taskmgr_t *mgr0, isc_task_t *task0);
+isc_result_t
+isc_taskmgr_excltask(isc_taskmgr_t *mgr0, isc_task_t **taskp);
+isc_result_t
+isc__task_beginexclusive(isc_task_t *task);
+void
+isc__task_endexclusive(isc_task_t *task0);
+void
+isc__task_setprivilege(isc_task_t *task0, bool priv);
+bool
+isc__task_privilege(isc_task_t *task0);
+void
+isc__taskmgr_setmode(isc_taskmgr_t *manager0, isc_taskmgrmode_t mode);
+isc_taskmgrmode_t
+isc__taskmgr_mode(isc_taskmgr_t *manager0);
+
+static inline bool
+empty_readyq(isc__taskmgr_t *manager);
+
+static inline isc__task_t *
+pop_readyq(isc__taskmgr_t *manager);
+
+static inline void
+push_readyq(isc__taskmgr_t *manager, isc__task_t *task);
+
+static struct isc__taskmethods {
+ isc_taskmethods_t methods;
+
+ /*%
+ * The following are defined just for avoiding unused static functions.
+ */
+ void *purgeevent, *unsendrange, *getname, *gettag,
+ *getcurrenttime, *getcurrenttimex;
+} taskmethods = {
+ {
+ isc__task_attach,
+ isc__task_detach,
+ isc__task_destroy,
+ isc__task_send,
+ isc__task_sendanddetach,
+ isc__task_unsend,
+ isc__task_onshutdown,
+ isc__task_shutdown,
+ isc__task_setname,
+ isc__task_purge,
+ isc__task_purgerange,
+ isc__task_beginexclusive,
+ isc__task_endexclusive,
+ isc__task_setprivilege,
+ isc__task_privilege
+ },
+ (void *)isc_task_purgeevent,
+ (void *)isc__task_unsendrange,
+ (void *)isc__task_getname,
+ (void *)isc__task_gettag,
+ (void *)isc__task_getcurrenttime,
+ (void *)isc__task_getcurrenttimex
+};
+
+static isc_taskmgrmethods_t taskmgrmethods = {
+ isc__taskmgr_destroy,
+ isc__taskmgr_setmode,
+ isc__taskmgr_mode,
+ isc__task_create,
+ isc_taskmgr_setexcltask,
+ isc_taskmgr_excltask
+};
+
+/***
+ *** Tasks.
+ ***/
+
+static void
+task_finished(isc__task_t *task) {
+ isc__taskmgr_t *manager = task->manager;
+
+ REQUIRE(EMPTY(task->events));
+ REQUIRE(task->nevents == 0);
+ REQUIRE(EMPTY(task->on_shutdown));
+ REQUIRE(task->references == 0);
+ REQUIRE(task->state == task_state_done);
+
+ XTRACE("task_finished");
+
+ LOCK(&manager->lock);
+ UNLINK(manager->tasks, task, link);
+#ifdef USE_WORKER_THREADS
+ if (FINISHED(manager)) {
+ /*
+ * All tasks have completed and the
+ * task manager is exiting. Wake up
+ * any idle worker threads so they
+ * can exit.
+ */
+ BROADCAST(&manager->work_available);
+ }
+#endif /* USE_WORKER_THREADS */
+ UNLOCK(&manager->lock);
+
+ DESTROYLOCK(&task->lock);
+ task->common.impmagic = 0;
+ task->common.magic = 0;
+ isc_mem_put(manager->mctx, task, sizeof(*task));
+}
+
+isc_result_t
+isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum,
+ isc_task_t **taskp)
+{
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+ isc__task_t *task;
+ bool exiting;
+ isc_result_t result;
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(taskp != NULL && *taskp == NULL);
+
+ task = isc_mem_get(manager->mctx, sizeof(*task));
+ if (task == NULL)
+ return (ISC_R_NOMEMORY);
+ XTRACE("isc_task_create");
+ task->manager = manager;
+ result = isc_mutex_init(&task->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(manager->mctx, task, sizeof(*task));
+ return (result);
+ }
+ task->state = task_state_idle;
+ task->references = 1;
+ INIT_LIST(task->events);
+ INIT_LIST(task->on_shutdown);
+ task->nevents = 0;
+ task->quantum = quantum;
+ task->flags = 0;
+ task->now = 0;
+ isc_time_settoepoch(&task->tnow);
+ memset(task->name, 0, sizeof(task->name));
+ task->tag = NULL;
+ INIT_LINK(task, link);
+ INIT_LINK(task, ready_link);
+ INIT_LINK(task, ready_priority_link);
+
+ exiting = false;
+ LOCK(&manager->lock);
+ if (!manager->exiting) {
+ if (task->quantum == 0)
+ task->quantum = manager->default_quantum;
+ APPEND(manager->tasks, task, link);
+ } else
+ exiting = true;
+ UNLOCK(&manager->lock);
+
+ if (exiting) {
+ DESTROYLOCK(&task->lock);
+ isc_mem_put(manager->mctx, task, sizeof(*task));
+ return (ISC_R_SHUTTINGDOWN);
+ }
+
+ task->common.methods = (isc_taskmethods_t *)&taskmethods;
+ task->common.magic = ISCAPI_TASK_MAGIC;
+ task->common.impmagic = TASK_MAGIC;
+ *taskp = (isc_task_t *)task;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc__task_attach(isc_task_t *source0, isc_task_t **targetp) {
+ isc__task_t *source = (isc__task_t *)source0;
+
+ /*
+ * Attach *targetp to source.
+ */
+
+ REQUIRE(VALID_TASK(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ XTTRACE(source, "isc_task_attach");
+
+ LOCK(&source->lock);
+ source->references++;
+ UNLOCK(&source->lock);
+
+ *targetp = (isc_task_t *)source;
+}
+
+static inline bool
+task_shutdown(isc__task_t *task) {
+ bool was_idle = false;
+ isc_event_t *event, *prev;
+
+ /*
+ * Caller must be holding the task's lock.
+ */
+
+ XTRACE("task_shutdown");
+
+ if (! TASK_SHUTTINGDOWN(task)) {
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_SHUTTINGDOWN, "shutting down"));
+ task->flags |= TASK_F_SHUTTINGDOWN;
+ if (task->state == task_state_idle) {
+ INSIST(EMPTY(task->events));
+ task->state = task_state_ready;
+ was_idle = true;
+ }
+ INSIST(task->state == task_state_ready ||
+ task->state == task_state_running);
+
+ /*
+ * Note that we post shutdown events LIFO.
+ */
+ for (event = TAIL(task->on_shutdown);
+ event != NULL;
+ event = prev) {
+ prev = PREV(event, ev_link);
+ DEQUEUE(task->on_shutdown, event, ev_link);
+ ENQUEUE(task->events, event, ev_link);
+ task->nevents++;
+ }
+ }
+
+ return (was_idle);
+}
+
+/*
+ * Moves a task onto the appropriate run queue.
+ *
+ * Caller must NOT hold manager lock.
+ */
+static inline void
+task_ready(isc__task_t *task) {
+ isc__taskmgr_t *manager = task->manager;
+#ifdef USE_WORKER_THREADS
+ bool has_privilege = isc__task_privilege((isc_task_t *) task);
+#endif /* USE_WORKER_THREADS */
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(task->state == task_state_ready);
+
+ XTRACE("task_ready");
+
+ LOCK(&manager->lock);
+ push_readyq(manager, task);
+#ifdef USE_WORKER_THREADS
+ if (manager->mode == isc_taskmgrmode_normal || has_privilege)
+ SIGNAL(&manager->work_available);
+#endif /* USE_WORKER_THREADS */
+ UNLOCK(&manager->lock);
+}
+
+static inline bool
+task_detach(isc__task_t *task) {
+
+ /*
+ * Caller must be holding the task lock.
+ */
+
+ REQUIRE(task->references > 0);
+
+ XTRACE("detach");
+
+ task->references--;
+ if (task->references == 0 && task->state == task_state_idle) {
+ INSIST(EMPTY(task->events));
+ /*
+ * There are no references to this task, and no
+ * pending events. We could try to optimize and
+ * either initiate shutdown or clean up the task,
+ * depending on its state, but it's easier to just
+ * make the task ready and allow run() or the event
+ * loop to deal with shutting down and termination.
+ */
+ task->state = task_state_ready;
+ return (true);
+ }
+
+ return (false);
+}
+
+void
+isc__task_detach(isc_task_t **taskp) {
+ isc__task_t *task;
+ bool was_idle;
+
+ /*
+ * Detach *taskp from its task.
+ */
+
+ REQUIRE(taskp != NULL);
+ task = (isc__task_t *)*taskp;
+ REQUIRE(VALID_TASK(task));
+
+ XTRACE("isc_task_detach");
+
+ LOCK(&task->lock);
+ was_idle = task_detach(task);
+ UNLOCK(&task->lock);
+
+ if (was_idle)
+ task_ready(task);
+
+ *taskp = NULL;
+}
+
+static inline bool
+task_send(isc__task_t *task, isc_event_t **eventp) {
+ bool was_idle = false;
+ isc_event_t *event;
+
+ /*
+ * Caller must be holding the task lock.
+ */
+
+ REQUIRE(eventp != NULL);
+ event = *eventp;
+ REQUIRE(event != NULL);
+ REQUIRE(event->ev_type > 0);
+ REQUIRE(task->state != task_state_done);
+ REQUIRE(!ISC_LINK_LINKED(event, ev_ratelink));
+
+ XTRACE("task_send");
+
+ if (task->state == task_state_idle) {
+ was_idle = true;
+ INSIST(EMPTY(task->events));
+ task->state = task_state_ready;
+ }
+ INSIST(task->state == task_state_ready ||
+ task->state == task_state_running);
+ ENQUEUE(task->events, event, ev_link);
+ task->nevents++;
+ *eventp = NULL;
+
+ return (was_idle);
+}
+
+void
+isc__task_send(isc_task_t *task0, isc_event_t **eventp) {
+ isc__task_t *task = (isc__task_t *)task0;
+ bool was_idle;
+
+ /*
+ * Send '*event' to 'task'.
+ */
+
+ REQUIRE(VALID_TASK(task));
+
+ XTRACE("isc_task_send");
+
+ /*
+ * We're trying hard to hold locks for as short a time as possible.
+ * We're also trying to hold as few locks as possible. This is why
+ * some processing is deferred until after the lock is released.
+ */
+ LOCK(&task->lock);
+ was_idle = task_send(task, eventp);
+ UNLOCK(&task->lock);
+
+ if (was_idle) {
+ /*
+ * We need to add this task to the ready queue.
+ *
+ * We've waited until now to do it because making a task
+ * ready requires locking the manager. If we tried to do
+ * this while holding the task lock, we could deadlock.
+ *
+ * We've changed the state to ready, so no one else will
+ * be trying to add this task to the ready queue. The
+ * only way to leave the ready state is by executing the
+ * task. It thus doesn't matter if events are added,
+ * removed, or a shutdown is started in the interval
+ * between the time we released the task lock, and the time
+ * we add the task to the ready queue.
+ */
+ task_ready(task);
+ }
+}
+
+void
+isc__task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) {
+ bool idle1, idle2;
+ isc__task_t *task;
+
+ /*
+ * Send '*event' to '*taskp' and then detach '*taskp' from its
+ * task.
+ */
+
+ REQUIRE(taskp != NULL);
+ task = (isc__task_t *)*taskp;
+ REQUIRE(VALID_TASK(task));
+
+ XTRACE("isc_task_sendanddetach");
+
+ LOCK(&task->lock);
+ idle1 = task_send(task, eventp);
+ idle2 = task_detach(task);
+ UNLOCK(&task->lock);
+
+ /*
+ * If idle1, then idle2 shouldn't be true as well since we're holding
+ * the task lock, and thus the task cannot switch from ready back to
+ * idle.
+ */
+ INSIST(!(idle1 && idle2));
+
+ if (idle1 || idle2)
+ task_ready(task);
+
+ *taskp = NULL;
+}
+
+#define PURGE_OK(event) (((event)->ev_attributes & ISC_EVENTATTR_NOPURGE) == 0)
+
+static unsigned int
+dequeue_events(isc__task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag,
+ isc_eventlist_t *events, bool purging)
+{
+ isc_event_t *event, *next_event;
+ unsigned int count = 0;
+
+ REQUIRE(VALID_TASK(task));
+ REQUIRE(last >= first);
+
+ XTRACE("dequeue_events");
+
+ /*
+ * Events matching 'sender', whose type is >= first and <= last, and
+ * whose tag is 'tag' will be dequeued. If 'purging', matching events
+ * which are marked as unpurgable will not be dequeued.
+ *
+ * sender == NULL means "any sender", and tag == NULL means "any tag".
+ */
+
+ LOCK(&task->lock);
+
+ for (event = HEAD(task->events); event != NULL; event = next_event) {
+ next_event = NEXT(event, ev_link);
+ if (event->ev_type >= first && event->ev_type <= last &&
+ (sender == NULL || event->ev_sender == sender) &&
+ (tag == NULL || event->ev_tag == tag) &&
+ (!purging || PURGE_OK(event))) {
+ DEQUEUE(task->events, event, ev_link);
+ task->nevents--;
+ ENQUEUE(*events, event, ev_link);
+ count++;
+ }
+ }
+
+ UNLOCK(&task->lock);
+
+ return (count);
+}
+
+unsigned int
+isc__task_purgerange(isc_task_t *task0, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag)
+{
+ isc__task_t *task = (isc__task_t *)task0;
+ unsigned int count;
+ isc_eventlist_t events;
+ isc_event_t *event, *next_event;
+
+ /*
+ * Purge events from a task's event queue.
+ */
+
+ XTRACE("isc_task_purgerange");
+
+ ISC_LIST_INIT(events);
+
+ count = dequeue_events(task, sender, first, last, tag, &events,
+ true);
+
+ for (event = HEAD(events); event != NULL; event = next_event) {
+ next_event = NEXT(event, ev_link);
+ ISC_LIST_UNLINK(events, event, ev_link);
+ isc_event_free(&event);
+ }
+
+ /*
+ * Note that purging never changes the state of the task.
+ */
+
+ return (count);
+}
+
+unsigned int
+isc__task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag)
+{
+ /*
+ * Purge events from a task's event queue.
+ */
+
+ XTRACE("isc_task_purge");
+
+ return (isc__task_purgerange(task, sender, type, type, tag));
+}
+
+bool
+isc_task_purgeevent(isc_task_t *task0, isc_event_t *event) {
+ isc__task_t *task = (isc__task_t *)task0;
+ isc_event_t *curr_event, *next_event;
+
+ /*
+ * Purge 'event' from a task's event queue.
+ *
+ * XXXRTH: WARNING: This method may be removed before beta.
+ */
+
+ REQUIRE(VALID_TASK(task));
+
+ /*
+ * If 'event' is on the task's event queue, it will be purged,
+ * unless it is marked as unpurgeable. 'event' does not have to be
+ * on the task's event queue; in fact, it can even be an invalid
+ * pointer. Purging only occurs if the event is actually on the task's
+ * event queue.
+ *
+ * Purging never changes the state of the task.
+ */
+
+ LOCK(&task->lock);
+ for (curr_event = HEAD(task->events);
+ curr_event != NULL;
+ curr_event = next_event) {
+ next_event = NEXT(curr_event, ev_link);
+ if (curr_event == event && PURGE_OK(event)) {
+ DEQUEUE(task->events, curr_event, ev_link);
+ task->nevents--;
+ break;
+ }
+ }
+ UNLOCK(&task->lock);
+
+ if (curr_event == NULL)
+ return (false);
+
+ isc_event_free(&curr_event);
+
+ return (true);
+}
+
+unsigned int
+isc__task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag,
+ isc_eventlist_t *events)
+{
+ /*
+ * Remove events from a task's event queue.
+ */
+
+ XTRACE("isc_task_unsendrange");
+
+ return (dequeue_events((isc__task_t *)task, sender, first,
+ last, tag, events, false));
+}
+
+unsigned int
+isc__task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag, isc_eventlist_t *events)
+{
+ /*
+ * Remove events from a task's event queue.
+ */
+
+ XTRACE("isc_task_unsend");
+
+ return (dequeue_events((isc__task_t *)task, sender, type,
+ type, tag, events, false));
+}
+
+isc_result_t
+isc__task_onshutdown(isc_task_t *task0, isc_taskaction_t action,
+ void *arg)
+{
+ isc__task_t *task = (isc__task_t *)task0;
+ bool disallowed = false;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_event_t *event;
+
+ /*
+ * Send a shutdown event with action 'action' and argument 'arg' when
+ * 'task' is shutdown.
+ */
+
+ REQUIRE(VALID_TASK(task));
+ REQUIRE(action != NULL);
+
+ event = isc_event_allocate(task->manager->mctx,
+ NULL,
+ ISC_TASKEVENT_SHUTDOWN,
+ action,
+ arg,
+ sizeof(*event));
+ if (event == NULL)
+ return (ISC_R_NOMEMORY);
+
+ LOCK(&task->lock);
+ if (TASK_SHUTTINGDOWN(task)) {
+ disallowed = true;
+ result = ISC_R_SHUTTINGDOWN;
+ } else
+ ENQUEUE(task->on_shutdown, event, ev_link);
+ UNLOCK(&task->lock);
+
+ if (disallowed)
+ isc_mem_put(task->manager->mctx, event, sizeof(*event));
+
+ return (result);
+}
+
+void
+isc__task_shutdown(isc_task_t *task0) {
+ isc__task_t *task = (isc__task_t *)task0;
+ bool was_idle;
+
+ /*
+ * Shutdown 'task'.
+ */
+
+ REQUIRE(VALID_TASK(task));
+
+ LOCK(&task->lock);
+ was_idle = task_shutdown(task);
+ UNLOCK(&task->lock);
+
+ if (was_idle)
+ task_ready(task);
+}
+
+void
+isc__task_destroy(isc_task_t **taskp) {
+
+ /*
+ * Destroy '*taskp'.
+ */
+
+ REQUIRE(taskp != NULL);
+
+ isc_task_shutdown(*taskp);
+ isc_task_detach(taskp);
+}
+
+void
+isc__task_setname(isc_task_t *task0, const char *name, void *tag) {
+ isc__task_t *task = (isc__task_t *)task0;
+
+ /*
+ * Name 'task'.
+ */
+
+ REQUIRE(VALID_TASK(task));
+
+ LOCK(&task->lock);
+ strlcpy(task->name, name, sizeof(task->name));
+ task->tag = tag;
+ UNLOCK(&task->lock);
+}
+
+const char *
+isc__task_getname(isc_task_t *task0) {
+ isc__task_t *task = (isc__task_t *)task0;
+
+ REQUIRE(VALID_TASK(task));
+
+ return (task->name);
+}
+
+void *
+isc__task_gettag(isc_task_t *task0) {
+ isc__task_t *task = (isc__task_t *)task0;
+
+ REQUIRE(VALID_TASK(task));
+
+ return (task->tag);
+}
+
+void
+isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t) {
+ isc__task_t *task = (isc__task_t *)task0;
+
+ REQUIRE(VALID_TASK(task));
+ REQUIRE(t != NULL);
+
+ LOCK(&task->lock);
+ *t = task->now;
+ UNLOCK(&task->lock);
+}
+
+void
+isc__task_getcurrenttimex(isc_task_t *task0, isc_time_t *t) {
+ isc__task_t *task = (isc__task_t *)task0;
+
+ REQUIRE(VALID_TASK(task));
+ REQUIRE(t != NULL);
+
+ LOCK(&task->lock);
+ *t = task->tnow;
+ UNLOCK(&task->lock);
+}
+
+/***
+ *** Task Manager.
+ ***/
+
+/*
+ * Return true if the current ready list for the manager, which is
+ * either ready_tasks or the ready_priority_tasks, depending on whether
+ * the manager is currently in normal or privileged execution mode.
+ *
+ * Caller must hold the task manager lock.
+ */
+static inline bool
+empty_readyq(isc__taskmgr_t *manager) {
+ isc__tasklist_t queue;
+
+ if (manager->mode == isc_taskmgrmode_normal)
+ queue = manager->ready_tasks;
+ else
+ queue = manager->ready_priority_tasks;
+
+ return (EMPTY(queue));
+}
+
+/*
+ * Dequeue and return a pointer to the first task on the current ready
+ * list for the manager.
+ * If the task is privileged, dequeue it from the other ready list
+ * as well.
+ *
+ * Caller must hold the task manager lock.
+ */
+static inline isc__task_t *
+pop_readyq(isc__taskmgr_t *manager) {
+ isc__task_t *task;
+
+ if (manager->mode == isc_taskmgrmode_normal)
+ task = HEAD(manager->ready_tasks);
+ else
+ task = HEAD(manager->ready_priority_tasks);
+
+ if (task != NULL) {
+ DEQUEUE(manager->ready_tasks, task, ready_link);
+ if (ISC_LINK_LINKED(task, ready_priority_link))
+ DEQUEUE(manager->ready_priority_tasks, task,
+ ready_priority_link);
+ }
+
+ return (task);
+}
+
+/*
+ * Push 'task' onto the ready_tasks queue. If 'task' has the privilege
+ * flag set, then also push it onto the ready_priority_tasks queue.
+ *
+ * Caller must hold the task manager lock.
+ */
+static inline void
+push_readyq(isc__taskmgr_t *manager, isc__task_t *task) {
+ ENQUEUE(manager->ready_tasks, task, ready_link);
+ if ((task->flags & TASK_F_PRIVILEGED) != 0)
+ ENQUEUE(manager->ready_priority_tasks, task,
+ ready_priority_link);
+ manager->tasks_ready++;
+}
+
+static void
+dispatch(isc__taskmgr_t *manager) {
+ isc__task_t *task;
+#ifndef USE_WORKER_THREADS
+ unsigned int total_dispatch_count = 0;
+ isc__tasklist_t new_ready_tasks;
+ isc__tasklist_t new_priority_tasks;
+ unsigned int tasks_ready = 0;
+#endif /* USE_WORKER_THREADS */
+
+ REQUIRE(VALID_MANAGER(manager));
+
+ /*
+ * Again we're trying to hold the lock for as short a time as possible
+ * and to do as little locking and unlocking as possible.
+ *
+ * In both while loops, the appropriate lock must be held before the
+ * while body starts. Code which acquired the lock at the top of
+ * the loop would be more readable, but would result in a lot of
+ * extra locking. Compare:
+ *
+ * Straightforward:
+ *
+ * LOCK();
+ * ...
+ * UNLOCK();
+ * while (expression) {
+ * LOCK();
+ * ...
+ * UNLOCK();
+ *
+ * Unlocked part here...
+ *
+ * LOCK();
+ * ...
+ * UNLOCK();
+ * }
+ *
+ * Note how if the loop continues we unlock and then immediately lock.
+ * For N iterations of the loop, this code does 2N+1 locks and 2N+1
+ * unlocks. Also note that the lock is not held when the while
+ * condition is tested, which may or may not be important, depending
+ * on the expression.
+ *
+ * As written:
+ *
+ * LOCK();
+ * while (expression) {
+ * ...
+ * UNLOCK();
+ *
+ * Unlocked part here...
+ *
+ * LOCK();
+ * ...
+ * }
+ * UNLOCK();
+ *
+ * For N iterations of the loop, this code does N+1 locks and N+1
+ * unlocks. The while expression is always protected by the lock.
+ */
+
+#ifndef USE_WORKER_THREADS
+ ISC_LIST_INIT(new_ready_tasks);
+ ISC_LIST_INIT(new_priority_tasks);
+#endif
+ LOCK(&manager->lock);
+
+ while (!FINISHED(manager)) {
+#ifdef USE_WORKER_THREADS
+ /*
+ * For reasons similar to those given in the comment in
+ * isc_task_send() above, it is safe for us to dequeue
+ * the task while only holding the manager lock, and then
+ * change the task to running state while only holding the
+ * task lock.
+ *
+ * If a pause has been requested, don't do any work
+ * until it's been released.
+ */
+ while ((empty_readyq(manager) || manager->pause_requested ||
+ manager->exclusive_requested) && !FINISHED(manager))
+ {
+ XTHREADTRACE(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_WAIT, "wait"));
+ WAIT(&manager->work_available, &manager->lock);
+ XTHREADTRACE(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TASK,
+ ISC_MSG_AWAKE, "awake"));
+ }
+#else /* USE_WORKER_THREADS */
+ if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM ||
+ empty_readyq(manager))
+ break;
+#endif /* USE_WORKER_THREADS */
+ XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TASK,
+ ISC_MSG_WORKING, "working"));
+
+ task = pop_readyq(manager);
+ if (task != NULL) {
+ unsigned int dispatch_count = 0;
+ bool done = false;
+ bool requeue = false;
+ bool finished = false;
+ isc_event_t *event;
+
+ INSIST(VALID_TASK(task));
+
+ /*
+ * Note we only unlock the manager lock if we actually
+ * have a task to do. We must reacquire the manager
+ * lock before exiting the 'if (task != NULL)' block.
+ */
+ manager->tasks_ready--;
+ manager->tasks_running++;
+ UNLOCK(&manager->lock);
+
+ LOCK(&task->lock);
+ INSIST(task->state == task_state_ready);
+ task->state = task_state_running;
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_RUNNING, "running"));
+ TIME_NOW(&task->tnow);
+ task->now = isc_time_seconds(&task->tnow);
+ do {
+ if (!EMPTY(task->events)) {
+ event = HEAD(task->events);
+ DEQUEUE(task->events, event, ev_link);
+ task->nevents--;
+
+ /*
+ * Execute the event action.
+ */
+ XTRACE(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TASK,
+ ISC_MSG_EXECUTE,
+ "execute action"));
+ if (event->ev_action != NULL) {
+ UNLOCK(&task->lock);
+ (event->ev_action)(
+ (isc_task_t *)task,
+ event);
+ LOCK(&task->lock);
+ }
+ dispatch_count++;
+#ifndef USE_WORKER_THREADS
+ total_dispatch_count++;
+#endif /* USE_WORKER_THREADS */
+ }
+
+ if (task->references == 0 &&
+ EMPTY(task->events) &&
+ !TASK_SHUTTINGDOWN(task)) {
+ bool was_idle;
+
+ /*
+ * There are no references and no
+ * pending events for this task,
+ * which means it will not become
+ * runnable again via an external
+ * action (such as sending an event
+ * or detaching).
+ *
+ * We initiate shutdown to prevent
+ * it from becoming a zombie.
+ *
+ * We do this here instead of in
+ * the "if EMPTY(task->events)" block
+ * below because:
+ *
+ * If we post no shutdown events,
+ * we want the task to finish.
+ *
+ * If we did post shutdown events,
+ * will still want the task's
+ * quantum to be applied.
+ */
+ was_idle = task_shutdown(task);
+ INSIST(!was_idle);
+ }
+
+ if (EMPTY(task->events)) {
+ /*
+ * Nothing else to do for this task
+ * right now.
+ */
+ XTRACE(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TASK,
+ ISC_MSG_EMPTY,
+ "empty"));
+ if (task->references == 0 &&
+ TASK_SHUTTINGDOWN(task)) {
+ /*
+ * The task is done.
+ */
+ XTRACE(isc_msgcat_get(
+ isc_msgcat,
+ ISC_MSGSET_TASK,
+ ISC_MSG_DONE,
+ "done"));
+ finished = true;
+ task->state = task_state_done;
+ } else
+ task->state = task_state_idle;
+ done = true;
+ } else if (dispatch_count >= task->quantum) {
+ /*
+ * Our quantum has expired, but
+ * there is more work to be done.
+ * We'll requeue it to the ready
+ * queue later.
+ *
+ * We don't check quantum until
+ * dispatching at least one event,
+ * so the minimum quantum is one.
+ */
+ XTRACE(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TASK,
+ ISC_MSG_QUANTUM,
+ "quantum"));
+ task->state = task_state_ready;
+ requeue = true;
+ done = true;
+ }
+ } while (!done);
+ UNLOCK(&task->lock);
+
+ if (finished)
+ task_finished(task);
+
+ LOCK(&manager->lock);
+ manager->tasks_running--;
+#ifdef USE_WORKER_THREADS
+ if (manager->exclusive_requested &&
+ manager->tasks_running == 1) {
+ SIGNAL(&manager->exclusive_granted);
+ } else if (manager->pause_requested &&
+ manager->tasks_running == 0) {
+ SIGNAL(&manager->paused);
+ }
+#endif /* USE_WORKER_THREADS */
+ if (requeue) {
+ /*
+ * We know we're awake, so we don't have
+ * to wakeup any sleeping threads if the
+ * ready queue is empty before we requeue.
+ *
+ * A possible optimization if the queue is
+ * empty is to 'goto' the 'if (task != NULL)'
+ * block, avoiding the ENQUEUE of the task
+ * and the subsequent immediate DEQUEUE
+ * (since it is the only executable task).
+ * We don't do this because then we'd be
+ * skipping the exit_requested check. The
+ * cost of ENQUEUE is low anyway, especially
+ * when you consider that we'd have to do
+ * an extra EMPTY check to see if we could
+ * do the optimization. If the ready queue
+ * were usually nonempty, the 'optimization'
+ * might even hurt rather than help.
+ */
+#ifdef USE_WORKER_THREADS
+ push_readyq(manager, task);
+#else
+ ENQUEUE(new_ready_tasks, task, ready_link);
+ if ((task->flags & TASK_F_PRIVILEGED) != 0)
+ ENQUEUE(new_priority_tasks, task,
+ ready_priority_link);
+ tasks_ready++;
+#endif
+ }
+ }
+
+#ifdef USE_WORKER_THREADS
+ /*
+ * If we are in privileged execution mode and there are no
+ * tasks remaining on the current ready queue, then
+ * we're stuck. Automatically drop privileges at that
+ * point and continue with the regular ready queue.
+ */
+ if (manager->tasks_running == 0 && empty_readyq(manager)) {
+ manager->mode = isc_taskmgrmode_normal;
+ if (!empty_readyq(manager))
+ BROADCAST(&manager->work_available);
+ }
+#endif
+ }
+
+#ifndef USE_WORKER_THREADS
+ ISC_LIST_APPENDLIST(manager->ready_tasks, new_ready_tasks, ready_link);
+ ISC_LIST_APPENDLIST(manager->ready_priority_tasks, new_priority_tasks,
+ ready_priority_link);
+ manager->tasks_ready += tasks_ready;
+ if (empty_readyq(manager))
+ manager->mode = isc_taskmgrmode_normal;
+#endif
+
+ UNLOCK(&manager->lock);
+}
+
+#ifdef USE_WORKER_THREADS
+static isc_threadresult_t
+#ifdef _WIN32
+WINAPI
+#endif
+run(void *uap) {
+ isc__taskmgr_t *manager = uap;
+
+ XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_STARTING, "starting"));
+
+ dispatch(manager);
+
+ XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_EXITING, "exiting"));
+
+#ifdef OPENSSL_LEAKS
+ ERR_remove_state(0);
+#endif
+
+ return ((isc_threadresult_t)0);
+}
+#endif /* USE_WORKER_THREADS */
+
+static void
+manager_free(isc__taskmgr_t *manager) {
+ isc_mem_t *mctx;
+
+#ifdef USE_WORKER_THREADS
+ (void)isc_condition_destroy(&manager->exclusive_granted);
+ (void)isc_condition_destroy(&manager->work_available);
+ (void)isc_condition_destroy(&manager->paused);
+ isc_mem_free(manager->mctx, manager->threads);
+#endif /* USE_WORKER_THREADS */
+ DESTROYLOCK(&manager->lock);
+ DESTROYLOCK(&manager->excl_lock);
+ manager->common.impmagic = 0;
+ manager->common.magic = 0;
+ mctx = manager->mctx;
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ isc_mem_detach(&mctx);
+
+#ifdef USE_SHARED_MANAGER
+ taskmgr = NULL;
+#endif /* USE_SHARED_MANAGER */
+}
+
+isc_result_t
+isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers,
+ unsigned int default_quantum, isc_taskmgr_t **managerp)
+{
+ isc_result_t result;
+ unsigned int i, started = 0;
+ isc__taskmgr_t *manager;
+
+ /*
+ * Create a new task manager.
+ */
+
+ REQUIRE(workers > 0);
+ REQUIRE(managerp != NULL && *managerp == NULL);
+
+#ifndef USE_WORKER_THREADS
+ UNUSED(i);
+ UNUSED(started);
+#endif
+
+#ifdef USE_SHARED_MANAGER
+ if (taskmgr != NULL) {
+ if (taskmgr->refs == 0)
+ return (ISC_R_SHUTTINGDOWN);
+ taskmgr->refs++;
+ *managerp = (isc_taskmgr_t *)taskmgr;
+ return (ISC_R_SUCCESS);
+ }
+#endif /* USE_SHARED_MANAGER */
+
+ manager = isc_mem_get(mctx, sizeof(*manager));
+ if (manager == NULL)
+ return (ISC_R_NOMEMORY);
+ manager->common.methods = &taskmgrmethods;
+ manager->common.impmagic = TASK_MANAGER_MAGIC;
+ manager->common.magic = ISCAPI_TASKMGR_MAGIC;
+ manager->mode = isc_taskmgrmode_normal;
+ manager->mctx = NULL;
+ result = isc_mutex_init(&manager->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_mgr;
+ result = isc_mutex_init(&manager->excl_lock);
+ if (result != ISC_R_SUCCESS) {
+ DESTROYLOCK(&manager->lock);
+ goto cleanup_mgr;
+ }
+
+#ifdef USE_WORKER_THREADS
+ manager->workers = 0;
+ manager->threads = isc_mem_allocate(mctx,
+ workers * sizeof(isc_thread_t));
+ if (manager->threads == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_lock;
+ }
+ if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_threads;
+ }
+ if (isc_condition_init(&manager->exclusive_granted) != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_workavailable;
+ }
+ if (isc_condition_init(&manager->paused) != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_exclusivegranted;
+ }
+#endif /* USE_WORKER_THREADS */
+ if (default_quantum == 0)
+ default_quantum = DEFAULT_DEFAULT_QUANTUM;
+ manager->default_quantum = default_quantum;
+ INIT_LIST(manager->tasks);
+ INIT_LIST(manager->ready_tasks);
+ INIT_LIST(manager->ready_priority_tasks);
+ manager->tasks_running = 0;
+ manager->tasks_ready = 0;
+ manager->exclusive_requested = false;
+ manager->pause_requested = false;
+ manager->exiting = false;
+ manager->excl = NULL;
+
+ isc_mem_attach(mctx, &manager->mctx);
+
+#ifdef USE_WORKER_THREADS
+ LOCK(&manager->lock);
+ /*
+ * Start workers.
+ */
+ for (i = 0; i < workers; i++) {
+ if (isc_thread_create(run, manager,
+ &manager->threads[manager->workers]) ==
+ ISC_R_SUCCESS) {
+ char name[16]; /* thread name limit on Linux */
+ snprintf(name, sizeof(name), "isc-worker%04u", i);
+ isc_thread_setname(manager->threads[manager->workers],
+ name);
+ manager->workers++;
+ started++;
+ }
+ }
+ UNLOCK(&manager->lock);
+
+ if (started == 0) {
+ manager_free(manager);
+ return (ISC_R_NOTHREADS);
+ }
+ isc_thread_setconcurrency(workers);
+#endif /* USE_WORKER_THREADS */
+#ifdef USE_SHARED_MANAGER
+ manager->refs = 1;
+ taskmgr = manager;
+#endif /* USE_SHARED_MANAGER */
+
+ *managerp = (isc_taskmgr_t *)manager;
+
+ return (ISC_R_SUCCESS);
+
+#ifdef USE_WORKER_THREADS
+ cleanup_exclusivegranted:
+ (void)isc_condition_destroy(&manager->exclusive_granted);
+ cleanup_workavailable:
+ (void)isc_condition_destroy(&manager->work_available);
+ cleanup_threads:
+ isc_mem_free(mctx, manager->threads);
+ cleanup_lock:
+ DESTROYLOCK(&manager->lock);
+#endif
+ cleanup_mgr:
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ return (result);
+}
+
+void
+isc__taskmgr_destroy(isc_taskmgr_t **managerp) {
+ isc__taskmgr_t *manager;
+ isc__task_t *task;
+ unsigned int i;
+
+ /*
+ * Destroy '*managerp'.
+ */
+
+ REQUIRE(managerp != NULL);
+ manager = (isc__taskmgr_t *)*managerp;
+ REQUIRE(VALID_MANAGER(manager));
+
+#ifndef USE_WORKER_THREADS
+ UNUSED(i);
+#endif /* USE_WORKER_THREADS */
+
+#ifdef USE_SHARED_MANAGER
+ manager->refs--;
+ if (manager->refs > 0) {
+ *managerp = NULL;
+ return;
+ }
+#endif
+
+ XTHREADTRACE("isc_taskmgr_destroy");
+ /*
+ * Only one non-worker thread may ever call this routine.
+ * If a worker thread wants to initiate shutdown of the
+ * task manager, it should ask some non-worker thread to call
+ * isc_taskmgr_destroy(), e.g. by signalling a condition variable
+ * that the startup thread is sleeping on.
+ */
+
+ /*
+ * Detach the exclusive task before acquiring the manager lock
+ */
+ LOCK(&manager->excl_lock);
+ if (manager->excl != NULL)
+ isc__task_detach((isc_task_t **) &manager->excl);
+ UNLOCK(&manager->excl_lock);
+
+ /*
+ * Unlike elsewhere, we're going to hold this lock a long time.
+ * We need to do so, because otherwise the list of tasks could
+ * change while we were traversing it.
+ *
+ * This is also the only function where we will hold both the
+ * task manager lock and a task lock at the same time.
+ */
+
+ LOCK(&manager->lock);
+
+ /*
+ * Make sure we only get called once.
+ */
+ INSIST(!manager->exiting);
+ manager->exiting = true;
+
+ /*
+ * If privileged mode was on, turn it off.
+ */
+ manager->mode = isc_taskmgrmode_normal;
+
+ /*
+ * Post shutdown event(s) to every task (if they haven't already been
+ * posted).
+ */
+ for (task = HEAD(manager->tasks);
+ task != NULL;
+ task = NEXT(task, link)) {
+ LOCK(&task->lock);
+ if (task_shutdown(task))
+ push_readyq(manager, task);
+ UNLOCK(&task->lock);
+ }
+#ifdef USE_WORKER_THREADS
+ /*
+ * Wake up any sleeping workers. This ensures we get work done if
+ * there's work left to do, and if there are already no tasks left
+ * it will cause the workers to see manager->exiting.
+ */
+ BROADCAST(&manager->work_available);
+ UNLOCK(&manager->lock);
+
+ /*
+ * Wait for all the worker threads to exit.
+ */
+ for (i = 0; i < manager->workers; i++)
+ (void)isc_thread_join(manager->threads[i], NULL);
+#else /* USE_WORKER_THREADS */
+ /*
+ * Dispatch the shutdown events.
+ */
+ UNLOCK(&manager->lock);
+ while (isc__taskmgr_ready((isc_taskmgr_t *)manager))
+ (void)isc__taskmgr_dispatch((isc_taskmgr_t *)manager);
+ if (!ISC_LIST_EMPTY(manager->tasks))
+ isc_mem_printallactive(stderr);
+ INSIST(ISC_LIST_EMPTY(manager->tasks));
+#ifdef USE_SHARED_MANAGER
+ taskmgr = NULL;
+#endif
+#endif /* USE_WORKER_THREADS */
+
+ manager_free(manager);
+
+ *managerp = NULL;
+}
+
+void
+isc__taskmgr_setmode(isc_taskmgr_t *manager0, isc_taskmgrmode_t mode) {
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+
+ LOCK(&manager->lock);
+ manager->mode = mode;
+ UNLOCK(&manager->lock);
+}
+
+isc_taskmgrmode_t
+isc__taskmgr_mode(isc_taskmgr_t *manager0) {
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+ isc_taskmgrmode_t mode;
+ LOCK(&manager->lock);
+ mode = manager->mode;
+ UNLOCK(&manager->lock);
+ return (mode);
+}
+
+#ifndef USE_WORKER_THREADS
+bool
+isc__taskmgr_ready(isc_taskmgr_t *manager0) {
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+ bool is_ready;
+
+#ifdef USE_SHARED_MANAGER
+ if (manager == NULL)
+ manager = taskmgr;
+#endif
+ if (manager == NULL)
+ return (false);
+
+ LOCK(&manager->lock);
+ is_ready = !empty_readyq(manager);
+ UNLOCK(&manager->lock);
+
+ return (is_ready);
+}
+
+isc_result_t
+isc__taskmgr_dispatch(isc_taskmgr_t *manager0) {
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+
+#ifdef USE_SHARED_MANAGER
+ if (manager == NULL)
+ manager = taskmgr;
+#endif
+ if (manager == NULL)
+ return (ISC_R_NOTFOUND);
+
+ dispatch(manager);
+
+ return (ISC_R_SUCCESS);
+}
+
+#else
+void
+isc__taskmgr_pause(isc_taskmgr_t *manager0) {
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+ manager->pause_requested = true;
+ LOCK(&manager->lock);
+ while (manager->tasks_running > 0) {
+ WAIT(&manager->paused, &manager->lock);
+ }
+ UNLOCK(&manager->lock);
+}
+
+void
+isc__taskmgr_resume(isc_taskmgr_t *manager0) {
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+
+ LOCK(&manager->lock);
+ if (manager->pause_requested) {
+ manager->pause_requested = false;
+ BROADCAST(&manager->work_available);
+ }
+ UNLOCK(&manager->lock);
+}
+#endif /* USE_WORKER_THREADS */
+
+void
+isc_taskmgr_setexcltask(isc_taskmgr_t *mgr0, isc_task_t *task0) {
+ isc__taskmgr_t *mgr = (isc__taskmgr_t *) mgr0;
+ isc__task_t *task = (isc__task_t *) task0;
+
+ REQUIRE(VALID_MANAGER(mgr));
+ REQUIRE(VALID_TASK(task));
+ LOCK(&mgr->excl_lock);
+ if (mgr->excl != NULL)
+ isc__task_detach((isc_task_t **) &mgr->excl);
+ isc__task_attach(task0, (isc_task_t **) &mgr->excl);
+ UNLOCK(&mgr->excl_lock);
+}
+
+isc_result_t
+isc_taskmgr_excltask(isc_taskmgr_t *mgr0, isc_task_t **taskp) {
+ isc__taskmgr_t *mgr = (isc__taskmgr_t *) mgr0;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_MANAGER(mgr));
+ REQUIRE(taskp != NULL && *taskp == NULL);
+
+ LOCK(&mgr->excl_lock);
+ if (mgr->excl != NULL)
+ isc__task_attach((isc_task_t *) mgr->excl, taskp);
+ else
+ result = ISC_R_NOTFOUND;
+ UNLOCK(&mgr->excl_lock);
+
+ return (result);
+}
+
+isc_result_t
+isc__task_beginexclusive(isc_task_t *task0) {
+#ifdef USE_WORKER_THREADS
+ isc__task_t *task = (isc__task_t *)task0;
+ isc__taskmgr_t *manager = task->manager;
+
+ REQUIRE(task->state == task_state_running);
+/*
+ * TODO REQUIRE(task == task->manager->excl);
+ * it should be here, it fails on shutdown server->task
+ */
+
+ LOCK(&manager->lock);
+ if (manager->exclusive_requested) {
+ UNLOCK(&manager->lock);
+ return (ISC_R_LOCKBUSY);
+ }
+ manager->exclusive_requested = true;
+ while (manager->tasks_running > 1) {
+ WAIT(&manager->exclusive_granted, &manager->lock);
+ }
+ UNLOCK(&manager->lock);
+#else
+ UNUSED(task0);
+#endif
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc__task_endexclusive(isc_task_t *task0) {
+#ifdef USE_WORKER_THREADS
+ isc__task_t *task = (isc__task_t *)task0;
+ isc__taskmgr_t *manager = task->manager;
+
+ REQUIRE(task->state == task_state_running);
+ LOCK(&manager->lock);
+ REQUIRE(manager->exclusive_requested);
+ manager->exclusive_requested = false;
+ BROADCAST(&manager->work_available);
+ UNLOCK(&manager->lock);
+#else
+ UNUSED(task0);
+#endif
+}
+
+void
+isc__task_setprivilege(isc_task_t *task0, bool priv) {
+ isc__task_t *task = (isc__task_t *)task0;
+ isc__taskmgr_t *manager = task->manager;
+ bool oldpriv;
+
+ LOCK(&task->lock);
+ oldpriv = (task->flags & TASK_F_PRIVILEGED);
+ if (priv)
+ task->flags |= TASK_F_PRIVILEGED;
+ else
+ task->flags &= ~TASK_F_PRIVILEGED;
+ UNLOCK(&task->lock);
+
+ if (priv == oldpriv)
+ return;
+
+ LOCK(&manager->lock);
+ if (priv && ISC_LINK_LINKED(task, ready_link))
+ ENQUEUE(manager->ready_priority_tasks, task,
+ ready_priority_link);
+ else if (!priv && ISC_LINK_LINKED(task, ready_priority_link))
+ DEQUEUE(manager->ready_priority_tasks, task,
+ ready_priority_link);
+ UNLOCK(&manager->lock);
+}
+
+bool
+isc__task_privilege(isc_task_t *task0) {
+ isc__task_t *task = (isc__task_t *)task0;
+ bool priv;
+
+ LOCK(&task->lock);
+ priv = (task->flags & TASK_F_PRIVILEGED);
+ UNLOCK(&task->lock);
+ return (priv);
+}
+
+isc_result_t
+isc__task_register(void) {
+ return (isc_task_register(isc__taskmgr_create));
+}
+
+bool
+isc_task_exiting(isc_task_t *t) {
+ isc__task_t *task = (isc__task_t *)t;
+
+ REQUIRE(VALID_TASK(task));
+ return (TASK_SHUTTINGDOWN(task));
+}
+
+
+#ifdef HAVE_LIBXML2
+#define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
+int
+isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) {
+ isc__taskmgr_t *mgr = (isc__taskmgr_t *)mgr0;
+ isc__task_t *task = NULL;
+ int xmlrc;
+
+ LOCK(&mgr->lock);
+
+ /*
+ * Write out the thread-model, and some details about each depending
+ * on which type is enabled.
+ */
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "thread-model"));
+#ifdef ISC_PLATFORM_USETHREADS
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "type"));
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "threaded"));
+ TRY0(xmlTextWriterEndElement(writer)); /* type */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "worker-threads"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->workers));
+ TRY0(xmlTextWriterEndElement(writer)); /* worker-threads */
+#else /* ISC_PLATFORM_USETHREADS */
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "type"));
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "non-threaded"));
+ TRY0(xmlTextWriterEndElement(writer)); /* type */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->refs));
+ TRY0(xmlTextWriterEndElement(writer)); /* references */
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "default-quantum"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d",
+ mgr->default_quantum));
+ TRY0(xmlTextWriterEndElement(writer)); /* default-quantum */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-running"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_running));
+ TRY0(xmlTextWriterEndElement(writer)); /* tasks-running */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-ready"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_ready));
+ TRY0(xmlTextWriterEndElement(writer)); /* tasks-ready */
+
+ TRY0(xmlTextWriterEndElement(writer)); /* thread-model */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks"));
+ task = ISC_LIST_HEAD(mgr->tasks);
+ while (task != NULL) {
+ LOCK(&task->lock);
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "task"));
+
+ if (task->name[0] != 0) {
+ TRY0(xmlTextWriterStartElement(writer,
+ ISC_XMLCHAR "name"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%s",
+ task->name));
+ TRY0(xmlTextWriterEndElement(writer)); /* name */
+ }
+
+ TRY0(xmlTextWriterStartElement(writer,
+ ISC_XMLCHAR "references"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d",
+ task->references));
+ TRY0(xmlTextWriterEndElement(writer)); /* references */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%p", task));
+ TRY0(xmlTextWriterEndElement(writer)); /* id */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "state"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%s",
+ statenames[task->state]));
+ TRY0(xmlTextWriterEndElement(writer)); /* state */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "quantum"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d",
+ task->quantum));
+ TRY0(xmlTextWriterEndElement(writer)); /* quantum */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "events"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d",
+ task->nevents));
+ TRY0(xmlTextWriterEndElement(writer)); /* events */
+
+ TRY0(xmlTextWriterEndElement(writer));
+
+ UNLOCK(&task->lock);
+ task = ISC_LIST_NEXT(task, link);
+ }
+ TRY0(xmlTextWriterEndElement(writer)); /* tasks */
+
+ error:
+ if (task != NULL)
+ UNLOCK(&task->lock);
+ UNLOCK(&mgr->lock);
+
+ return (xmlrc);
+}
+#endif /* HAVE_LIBXML2 */
+
+#ifdef HAVE_JSON
+#define CHECKMEM(m) do { \
+ if (m == NULL) { \
+ result = ISC_R_NOMEMORY;\
+ goto error;\
+ } \
+} while(0)
+
+isc_result_t
+isc_taskmgr_renderjson(isc_taskmgr_t *mgr0, json_object *tasks) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc__taskmgr_t *mgr = (isc__taskmgr_t *)mgr0;
+ isc__task_t *task = NULL;
+ json_object *obj = NULL, *array = NULL, *taskobj = NULL;
+
+ LOCK(&mgr->lock);
+
+ /*
+ * Write out the thread-model, and some details about each depending
+ * on which type is enabled.
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+ obj = json_object_new_string("threaded");
+ CHECKMEM(obj);
+ json_object_object_add(tasks, "thread-model", obj);
+
+ obj = json_object_new_int(mgr->workers);
+ CHECKMEM(obj);
+ json_object_object_add(tasks, "worker-threads", obj);
+#else /* ISC_PLATFORM_USETHREADS */
+ obj = json_object_new_string("non-threaded");
+ CHECKMEM(obj);
+ json_object_object_add(tasks, "thread-model", obj);
+
+ obj = json_object_new_int(mgr->refs);
+ CHECKMEM(obj);
+ json_object_object_add(tasks, "references", obj);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ obj = json_object_new_int(mgr->default_quantum);
+ CHECKMEM(obj);
+ json_object_object_add(tasks, "default-quantum", obj);
+
+ obj = json_object_new_int(mgr->tasks_running);
+ CHECKMEM(obj);
+ json_object_object_add(tasks, "tasks-running", obj);
+
+ obj = json_object_new_int(mgr->tasks_ready);
+ CHECKMEM(obj);
+ json_object_object_add(tasks, "tasks-ready", obj);
+
+ array = json_object_new_array();
+ CHECKMEM(array);
+
+ for (task = ISC_LIST_HEAD(mgr->tasks);
+ task != NULL;
+ task = ISC_LIST_NEXT(task, link))
+ {
+ char buf[255];
+
+ LOCK(&task->lock);
+
+ taskobj = json_object_new_object();
+ CHECKMEM(taskobj);
+ json_object_array_add(array, taskobj);
+
+ snprintf(buf, sizeof(buf), "%p", task);
+ obj = json_object_new_string(buf);
+ CHECKMEM(obj);
+ json_object_object_add(taskobj, "id", obj);
+
+ if (task->name[0] != 0) {
+ obj = json_object_new_string(task->name);
+ CHECKMEM(obj);
+ json_object_object_add(taskobj, "name", obj);
+ }
+
+ obj = json_object_new_int(task->references);
+ CHECKMEM(obj);
+ json_object_object_add(taskobj, "references", obj);
+
+ obj = json_object_new_string(statenames[task->state]);
+ CHECKMEM(obj);
+ json_object_object_add(taskobj, "state", obj);
+
+ obj = json_object_new_int(task->quantum);
+ CHECKMEM(obj);
+ json_object_object_add(taskobj, "quantum", obj);
+
+ obj = json_object_new_int(task->nevents);
+ CHECKMEM(obj);
+ json_object_object_add(taskobj, "events", obj);
+
+ UNLOCK(&task->lock);
+ }
+
+ json_object_object_add(tasks, "tasks", array);
+ array = NULL;
+ result = ISC_R_SUCCESS;
+
+ error:
+ if (array != NULL)
+ json_object_put(array);
+
+ if (task != NULL)
+ UNLOCK(&task->lock);
+ UNLOCK(&mgr->lock);
+
+ return (result);
+}
+#endif
+
+
+static isc_mutex_t createlock;
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_taskmgrcreatefunc_t taskmgr_createfunc = NULL;
+
+static void
+initialize(void) {
+ RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_task_register(isc_taskmgrcreatefunc_t createfunc) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
+
+ LOCK(&createlock);
+ if (taskmgr_createfunc == NULL)
+ taskmgr_createfunc = createfunc;
+ else
+ result = ISC_R_EXISTS;
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+isc_result_t
+isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
+ unsigned int workers, unsigned int default_quantum,
+ isc_taskmgr_t **managerp)
+{
+ isc_result_t result;
+
+ LOCK(&createlock);
+
+ REQUIRE(taskmgr_createfunc != NULL);
+ result = (*taskmgr_createfunc)(mctx, workers, default_quantum,
+ managerp);
+
+ UNLOCK(&createlock);
+
+ if (result == ISC_R_SUCCESS)
+ isc_appctx_settaskmgr(actx, *managerp);
+
+ return (result);
+}
+
+isc_result_t
+isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
+ unsigned int default_quantum, isc_taskmgr_t **managerp)
+{
+ isc_result_t result;
+
+ if (isc_bind9)
+ return (isc__taskmgr_create(mctx, workers,
+ default_quantum, managerp));
+ LOCK(&createlock);
+
+ REQUIRE(taskmgr_createfunc != NULL);
+ result = (*taskmgr_createfunc)(mctx, workers, default_quantum,
+ managerp);
+
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+void
+isc_taskmgr_destroy(isc_taskmgr_t **managerp) {
+ REQUIRE(managerp != NULL && ISCAPI_TASKMGR_VALID(*managerp));
+
+ if (isc_bind9)
+ isc__taskmgr_destroy(managerp);
+ else
+ (*managerp)->methods->destroy(managerp);
+
+ ENSURE(*managerp == NULL);
+}
+
+void
+isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode) {
+ REQUIRE(ISCAPI_TASKMGR_VALID(manager));
+
+ if (isc_bind9)
+ isc__taskmgr_setmode(manager, mode);
+ else
+ manager->methods->setmode(manager, mode);
+}
+
+isc_taskmgrmode_t
+isc_taskmgr_mode(isc_taskmgr_t *manager) {
+ REQUIRE(ISCAPI_TASKMGR_VALID(manager));
+
+ if (isc_bind9)
+ return (isc__taskmgr_mode(manager));
+
+ return (manager->methods->mode(manager));
+}
+
+isc_result_t
+isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
+ isc_task_t **taskp)
+{
+ REQUIRE(ISCAPI_TASKMGR_VALID(manager));
+ REQUIRE(taskp != NULL && *taskp == NULL);
+
+ if (isc_bind9)
+ return (isc__task_create(manager, quantum, taskp));
+
+ return (manager->methods->taskcreate(manager, quantum, taskp));
+}
+
+void
+isc_task_attach(isc_task_t *source, isc_task_t **targetp) {
+ REQUIRE(ISCAPI_TASK_VALID(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ if (isc_bind9)
+ isc__task_attach(source, targetp);
+ else
+ source->methods->attach(source, targetp);
+
+ ENSURE(*targetp == source);
+}
+
+void
+isc_task_detach(isc_task_t **taskp) {
+ REQUIRE(taskp != NULL && ISCAPI_TASK_VALID(*taskp));
+
+ if (isc_bind9)
+ isc__task_detach(taskp);
+ else
+ (*taskp)->methods->detach(taskp);
+
+ ENSURE(*taskp == NULL);
+}
+
+void
+isc_task_send(isc_task_t *task, isc_event_t **eventp) {
+ REQUIRE(ISCAPI_TASK_VALID(task));
+ REQUIRE(eventp != NULL && *eventp != NULL);
+
+ if (isc_bind9)
+ isc__task_send(task, eventp);
+ else {
+ task->methods->send(task, eventp);
+ ENSURE(*eventp == NULL);
+ }
+}
+
+void
+isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) {
+ REQUIRE(taskp != NULL && ISCAPI_TASK_VALID(*taskp));
+ REQUIRE(eventp != NULL && *eventp != NULL);
+
+ if (isc_bind9)
+ isc__task_sendanddetach(taskp, eventp);
+ else {
+ (*taskp)->methods->sendanddetach(taskp, eventp);
+ ENSURE(*eventp == NULL);
+ }
+
+ ENSURE(*taskp == NULL);
+}
+
+unsigned int
+isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag, isc_eventlist_t *events)
+{
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ if (isc_bind9)
+ return (isc__task_unsend(task, sender, type, tag, events));
+
+ return (task->methods->unsend(task, sender, type, tag, events));
+}
+
+isc_result_t
+isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ if (isc_bind9)
+ return (isc__task_onshutdown(task, action, arg));
+
+ return (task->methods->onshutdown(task, action, arg));
+}
+
+void
+isc_task_shutdown(isc_task_t *task) {
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ if (isc_bind9)
+ isc__task_shutdown(task);
+ else
+ task->methods->shutdown(task);
+}
+
+void
+isc_task_destroy(isc_task_t **taskp) {
+ if (!isc_bind9)
+ return;
+
+ isc__task_destroy(taskp);
+}
+
+void
+isc_task_setname(isc_task_t *task, const char *name, void *tag) {
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ if (isc_bind9)
+ isc__task_setname(task, name, tag);
+ else
+ task->methods->setname(task, name, tag);
+}
+
+unsigned int
+isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, void *tag)
+{
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ if (isc_bind9)
+ return (isc__task_purge(task, sender, type, tag));
+
+ return (task->methods->purgeevents(task, sender, type, tag));
+}
+
+isc_result_t
+isc_task_beginexclusive(isc_task_t *task) {
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ if (isc_bind9)
+ return (isc__task_beginexclusive(task));
+
+ return (task->methods->beginexclusive(task));
+}
+
+void
+isc_task_endexclusive(isc_task_t *task) {
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ if (isc_bind9)
+ isc__task_endexclusive(task);
+ else
+ task->methods->endexclusive(task);
+}
+
+void
+isc_task_setprivilege(isc_task_t *task, bool priv) {
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ if (isc_bind9)
+ isc__task_setprivilege(task, priv);
+ else
+ task->methods->setprivilege(task, priv);
+}
+
+bool
+isc_task_privilege(isc_task_t *task) {
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ if (isc_bind9)
+ return (isc__task_privilege(task));
+
+ return (task->methods->privilege(task));
+}
+
+void
+isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t) {
+ if (!isc_bind9)
+ return;
+
+ isc__task_getcurrenttime(task, t);
+}
+
+void
+isc_task_getcurrenttimex(isc_task_t *task, isc_time_t *t) {
+ if (!isc_bind9)
+ return;
+
+ isc__task_getcurrenttimex(task, t);
+}
+
+/*%
+ * This is necessary for libisc's internal timer implementation. Other
+ * implementation might skip implementing this.
+ */
+unsigned int
+isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag)
+{
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ if (isc_bind9)
+ return (isc__task_purgerange(task, sender, first, last, tag));
+
+ return (task->methods->purgerange(task, sender, first, last, tag));
+}
diff --git a/lib/isc/task_p.h b/lib/isc/task_p.h
new file mode 100644
index 0000000..1fa3bb1
--- /dev/null
+++ b/lib/isc/task_p.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id$ */
+
+#ifndef ISC_TASK_P_H
+#define ISC_TASK_P_H
+
+/*! \file */
+
+#if defined(ISC_PLATFORM_USETHREADS)
+void
+isc__taskmgr_pause(isc_taskmgr_t *taskmgr);
+
+void
+isc__taskmgr_resume(isc_taskmgr_t *taskmgr);
+#else
+bool
+isc__taskmgr_ready(isc_taskmgr_t *taskmgr);
+
+isc_result_t
+isc__taskmgr_dispatch(isc_taskmgr_t *taskmgr);
+#endif /* !ISC_PLATFORM_USETHREADS */
+
+#endif /* ISC_TASK_P_H */
diff --git a/lib/isc/taskpool.c b/lib/isc/taskpool.c
new file mode 100644
index 0000000..5dfc1d1
--- /dev/null
+++ b/lib/isc/taskpool.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/mem.h>
+#include <isc/random.h>
+#include <isc/taskpool.h>
+#include <isc/util.h>
+
+/***
+ *** Types.
+ ***/
+
+struct isc_taskpool {
+ isc_mem_t * mctx;
+ isc_taskmgr_t * tmgr;
+ unsigned int ntasks;
+ unsigned int quantum;
+ isc_task_t ** tasks;
+};
+
+/***
+ *** Functions.
+ ***/
+
+static isc_result_t
+alloc_pool(isc_taskmgr_t *tmgr, isc_mem_t *mctx, unsigned int ntasks,
+ unsigned int quantum, isc_taskpool_t **poolp)
+{
+ isc_taskpool_t *pool;
+ unsigned int i;
+
+ pool = isc_mem_get(mctx, sizeof(*pool));
+ if (pool == NULL)
+ return (ISC_R_NOMEMORY);
+
+ pool->mctx = NULL;
+ isc_mem_attach(mctx, &pool->mctx);
+ pool->ntasks = ntasks;
+ pool->quantum = quantum;
+ pool->tmgr = tmgr;
+ pool->tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
+ if (pool->tasks == NULL) {
+ isc_mem_putanddetach(&pool->mctx, pool, sizeof(*pool));
+ return (ISC_R_NOMEMORY);
+ }
+ for (i = 0; i < ntasks; i++)
+ pool->tasks[i] = NULL;
+
+ *poolp = pool;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx,
+ unsigned int ntasks, unsigned int quantum,
+ isc_taskpool_t **poolp)
+{
+ unsigned int i;
+ isc_taskpool_t *pool = NULL;
+ isc_result_t result;
+
+ INSIST(ntasks > 0);
+
+ /* Allocate the pool structure */
+ result = alloc_pool(tmgr, mctx, ntasks, quantum, &pool);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /* Create the tasks */
+ for (i = 0; i < ntasks; i++) {
+ result = isc_task_create(tmgr, quantum, &pool->tasks[i]);
+ if (result != ISC_R_SUCCESS) {
+ isc_taskpool_destroy(&pool);
+ return (result);
+ }
+ isc_task_setname(pool->tasks[i], "taskpool", NULL);
+ }
+
+ *poolp = pool;
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_taskpool_gettask(isc_taskpool_t *pool, isc_task_t **targetp) {
+ uint32_t i;
+ isc_random_get(&i);
+ isc_task_attach(pool->tasks[i % pool->ntasks], targetp);
+}
+
+int
+isc_taskpool_size(isc_taskpool_t *pool) {
+ REQUIRE(pool != NULL);
+ return (pool->ntasks);
+}
+
+isc_result_t
+isc_taskpool_expand(isc_taskpool_t **sourcep, unsigned int size,
+ isc_taskpool_t **targetp)
+{
+ isc_result_t result;
+ isc_taskpool_t *pool;
+
+ REQUIRE(sourcep != NULL && *sourcep != NULL);
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ pool = *sourcep;
+ if (size > pool->ntasks) {
+ isc_taskpool_t *newpool = NULL;
+ unsigned int i;
+
+ /* Allocate a new pool structure */
+ result = alloc_pool(pool->tmgr, pool->mctx, size,
+ pool->quantum, &newpool);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /* Copy over the tasks from the old pool */
+ for (i = 0; i < pool->ntasks; i++) {
+ newpool->tasks[i] = pool->tasks[i];
+ pool->tasks[i] = NULL;
+ }
+
+ /* Create new tasks */
+ for (i = pool->ntasks; i < size; i++) {
+ result = isc_task_create(pool->tmgr, pool->quantum,
+ &newpool->tasks[i]);
+ if (result != ISC_R_SUCCESS) {
+ isc_taskpool_destroy(&newpool);
+ return (result);
+ }
+ isc_task_setname(newpool->tasks[i], "taskpool", NULL);
+ }
+
+ isc_taskpool_destroy(&pool);
+ pool = newpool;
+ }
+
+ *sourcep = NULL;
+ *targetp = pool;
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_taskpool_destroy(isc_taskpool_t **poolp) {
+ unsigned int i;
+ isc_taskpool_t *pool = *poolp;
+ for (i = 0; i < pool->ntasks; i++) {
+ if (pool->tasks[i] != NULL)
+ isc_task_detach(&pool->tasks[i]);
+ }
+ isc_mem_put(pool->mctx, pool->tasks,
+ pool->ntasks * sizeof(isc_task_t *));
+ isc_mem_putanddetach(&pool->mctx, pool, sizeof(*pool));
+ *poolp = NULL;
+}
+
+void
+isc_taskpool_setprivilege(isc_taskpool_t *pool, bool priv) {
+ unsigned int i;
+
+ REQUIRE(pool != NULL);
+
+ for (i = 0; i < pool->ntasks; i++) {
+ if (pool->tasks[i] != NULL)
+ isc_task_setprivilege(pool->tasks[i], priv);
+ }
+}
diff --git a/lib/isc/tests/Atffile b/lib/isc/tests/Atffile
new file mode 100644
index 0000000..8681844
--- /dev/null
+++ b/lib/isc/tests/Atffile
@@ -0,0 +1,33 @@
+Content-Type: application/X-atf-atffile; version="1"
+
+prop: test-suite = bind9
+
+tp: aes_test
+tp: atomic_test
+tp: buffer_test
+tp: counter_test
+tp: errno_test
+tp: file_test
+tp: hash_test
+tp: heap_test
+tp: ht_test
+tp: inet_ntop_test
+tp: lex_test
+tp: mem_test
+tp: netaddr_test
+tp: parse_test
+tp: pool_test
+tp: print_test
+tp: queue_test
+tp: radix_test
+tp: random_test
+tp: regex_test
+tp: result_test
+tp: safe_test
+tp: sockaddr_test
+tp: socket_test
+tp: symtab_test
+tp: task_test
+tp: taskpool_test
+tp: time_test
+tp: timer_test
diff --git a/lib/isc/tests/Kyuafile b/lib/isc/tests/Kyuafile
new file mode 100644
index 0000000..1c510c1
--- /dev/null
+++ b/lib/isc/tests/Kyuafile
@@ -0,0 +1,32 @@
+syntax(2)
+test_suite('bind9')
+
+atf_test_program{name='aes_test'}
+atf_test_program{name='atomic_test'}
+atf_test_program{name='buffer_test'}
+atf_test_program{name='counter_test'}
+atf_test_program{name='errno_test'}
+atf_test_program{name='file_test'}
+atf_test_program{name='hash_test'}
+atf_test_program{name='heap_test'}
+atf_test_program{name='ht_test'}
+atf_test_program{name='inet_ntop_test'}
+atf_test_program{name='lex_test'}
+atf_test_program{name='mem_test'}
+atf_test_program{name='netaddr_test'}
+atf_test_program{name='parse_test'}
+atf_test_program{name='pool_test'}
+atf_test_program{name='print_test'}
+atf_test_program{name='queue_test'}
+atf_test_program{name='radix_test'}
+atf_test_program{name='random_test'}
+atf_test_program{name='regex_test'}
+atf_test_program{name='result_test'}
+atf_test_program{name='safe_test'}
+atf_test_program{name='sockaddr_test'}
+atf_test_program{name='socket_test'}
+atf_test_program{name='symtab_test'}
+atf_test_program{name='task_test'}
+atf_test_program{name='taskpool_test'}
+atf_test_program{name='time_test'}
+atf_test_program{name='timer_test'}
diff --git a/lib/isc/tests/Makefile.in b/lib/isc/tests/Makefile.in
new file mode 100644
index 0000000..add8068
--- /dev/null
+++ b/lib/isc/tests/Makefile.in
@@ -0,0 +1,177 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+# Attempt to disable parallel processing.
+.NOTPARALLEL:
+.NO_PARALLEL:
+
+VERSION=@BIND9_VERSION@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = -I. -Iinclude ${ISC_INCLUDES} @ISC_OPENSSL_INC@
+CDEFINES = @CRYPTO@ -DTESTS="\"${top_builddir}/lib/isc/tests/\""
+
+ISCLIBS = ../libisc.@A@ @ISC_OPENSSL_LIBS@
+ISCDEPLIBS = ../libisc.@A@
+
+LIBS = @LIBS@ @ATFLIBS@
+
+OBJS = isctest.@O@
+SRCS = isctest.c aes_test.c atomic_test.c buffer_test.c \
+ counter_test.c errno_test.c file_test.c hash_test.c \
+ heap_test.c ht_test.c inet_ntop_test.c lex_test.c \
+ mem_test.c netaddr_test.c parse_test.c pool_test.c \
+ print_test.c queue_test.c radix_test.c random_test.c \
+ regex_test.c result_test.c safe_test.c sockaddr_test.c \
+ socket_test.c socket_test.c symtab_test.c task_test.c \
+ taskpool_test.c time_test.c timer_test.c
+
+SUBDIRS =
+TARGETS = aes_test@EXEEXT@ atomic_test@EXEEXT@ buffer_test@EXEEXT@ \
+ counter_test@EXEEXT@ errno_test@EXEEXT@ file_test@EXEEXT@ \
+ hash_test@EXEEXT@ heap_test@EXEEXT@ ht_test@EXEEXT@ \
+ inet_ntop_test@EXEEXT@ lex_test@EXEEXT@ mem_test@EXEEXT@ \
+ netaddr_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@ \
+ print_test@EXEEXT@ queue_test@EXEEXT@ radix_test@EXEEXT@ \
+ random_test@EXEEXT@ regex_test@EXEEXT@ result_test@EXEEXT@ \
+ safe_test@EXEEXT@ sockaddr_test@EXEEXT@ socket_test@EXEEXT@ \
+ socket_test@EXEEXT@ symtab_test@EXEEXT@ task_test@EXEEXT@ \
+ taskpool_test@EXEEXT@ time_test@EXEEXT@ timer_test@EXEEXT@
+
+@BIND9_MAKE_RULES@
+
+atomic_test@EXEEXT@: atomic_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ atomic_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+aes_test@EXEEXT@: aes_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ aes_test.@O@ ${ISCLIBS} ${LIBS}
+
+buffer_test@EXEEXT@: buffer_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ buffer_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+counter_test@EXEEXT@: counter_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ counter_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+errno_test@EXEEXT@: errno_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ errno_test.@O@ ${ISCLIBS} ${LIBS}
+
+file_test@EXEEXT@: file_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ file_test.@O@ ${ISCLIBS} ${LIBS}
+
+hash_test@EXEEXT@: hash_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ hash_test.@O@ ${ISCLIBS} ${LIBS}
+
+heap_test@EXEEXT@: heap_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ heap_test.@O@ ${ISCLIBS} ${LIBS}
+
+ht_test@EXEEXT@: ht_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ ht_test.@O@ ${ISCLIBS} ${LIBS}
+
+inet_ntop_test.c.@O@: ${top_srcdir}/lib/isc/ntop_test.c
+inet_ntop_test@EXEEXT@: inet_ntop_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ inet_ntop_test.@O@ ${ISCLIBS} ${LIBS}
+
+lex_test@EXEEXT@: lex_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ lex_test.@O@ ${ISCLIBS} ${LIBS}
+
+parse_test@EXEEXT@: parse_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ parse_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+pool_test@EXEEXT@: pool_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ pool_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+print_test.@O@: ${top_srcdir}/lib/isc/print.c
+print_test@EXEEXT@: print_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ print_test.@O@ ${ISCLIBS} ${LIBS}
+
+queue_test@EXEEXT@: queue_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ queue_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+radix_test@EXEEXT@: radix_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ radix_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+random_test@EXEEXT@: random_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ random_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+regex_test@EXEEXT@: regex_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ regex_test.@O@ ${ISCLIBS} ${LIBS}
+
+mem_test@EXEEXT@: mem_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ mem_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+netaddr_test@EXEEXT@: netaddr_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ netaddr_test.@O@ ${ISCLIBS} ${LIBS}
+
+result_test@EXEEXT@: result_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ result_test.@O@ ${ISCLIBS} ${LIBS}
+
+safe_test@EXEEXT@: safe_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ safe_test.@O@ ${ISCLIBS} ${LIBS}
+
+sockaddr_test@EXEEXT@: sockaddr_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ sockaddr_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+socket_test@EXEEXT@: socket_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ socket_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+symtab_test@EXEEXT@: symtab_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ symtab_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+task_test@EXEEXT@: task_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ task_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+taskpool_test@EXEEXT@: taskpool_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ taskpool_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+time_test@EXEEXT@: time_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ time_test.@O@ ${ISCLIBS} ${LIBS}
+
+timer_test@EXEEXT@: timer_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ timer_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
+unit::
+ sh ${top_builddir}/unit/unittest.sh
+
+clean distclean::
+ rm -f ${TARGETS}
+ rm -f atf.out
diff --git a/lib/isc/tests/aes_test.c b/lib/isc/tests/aes_test.c
new file mode 100644
index 0000000..9c15b52
--- /dev/null
+++ b/lib/isc/tests/aes_test.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/* ! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/aes.h>
+#include <isc/buffer.h>
+#include <isc/hex.h>
+#include <isc/platform.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#ifdef ISC_PLATFORM_WANTAES
+
+/*
+ * Test data from NIST KAT
+ */
+
+isc_result_t
+tohexstr(unsigned char *d, char *out);
+
+size_t
+fromhexstr(const char *in, unsigned char *d);
+
+unsigned char plaintext[3 * ISC_AES_BLOCK_LENGTH];
+unsigned char ciphertext[ISC_AES_BLOCK_LENGTH];
+char str[2 * ISC_AES_BLOCK_LENGTH + 1];
+unsigned char key[ISC_AES256_KEYLENGTH + 1];
+size_t len;
+
+isc_result_t
+tohexstr(unsigned char *d, char *out) {
+ isc_buffer_t b;
+ isc_region_t r;
+
+ isc_buffer_init(&b, out, 2 * ISC_AES_BLOCK_LENGTH + 1);
+ r.base = d;
+ r.length = ISC_AES_BLOCK_LENGTH;
+ return (isc_hex_totext(&r, 0, "", &b));
+}
+
+size_t
+fromhexstr(const char *in, unsigned char *d)
+{
+ isc_buffer_t b;
+ isc_result_t ret;
+
+ isc_buffer_init(&b, d, ISC_AES256_KEYLENGTH + 1);
+ ret = isc_hex_decodestring(in, &b);
+ if (ret != ISC_R_SUCCESS)
+ return 0;
+ return isc_buffer_usedlength(&b);
+}
+
+typedef struct aes_testcase {
+ const char *key;
+ const char *input;
+ const char *result;
+} aes_testcase_t;
+
+
+ATF_TC(isc_aes128);
+ATF_TC_HEAD(isc_aes128, tc) {
+ atf_tc_set_md_var(tc, "descr", "AES 128 test vectors");
+}
+ATF_TC_BODY(isc_aes128, tc) {
+ UNUSED(tc);
+
+ aes_testcase_t testcases[] = {
+ /* Test 1 (KAT ECBVarTxt128 #3) */
+ {
+ "00000000000000000000000000000000",
+ "F0000000000000000000000000000000",
+ "96D9FD5CC4F07441727DF0F33E401A36"
+ },
+ /* Test 2 (KAT ECBVarTxt128 #123) */
+ {
+ "00000000000000000000000000000000",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "F9B0FDA0C4A898F5B9E6F661C4CE4D07"
+ },
+ /* Test 3 (KAT ECBVarKey128 #3) */
+ {
+ "F0000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ "970014D634E2B7650777E8E84D03CCD8"
+ },
+ /* Test 4 (KAT ECBVarKey128 #123) */
+ {
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "00000000000000000000000000000000",
+ "41C78C135ED9E98C096640647265DA1E"
+ },
+ /* Test 5 (KAT ECBGFSbox128 #3) */
+ {
+ "00000000000000000000000000000000",
+ "6A118A874519E64E9963798A503F1D35",
+ "DC43BE40BE0E53712F7E2BF5CA707209"
+ },
+ /* Test 6 (KAT ECBKeySbox128 #3) */
+ {
+ "B6364AC4E1DE1E285EAF144A2415F7A0",
+ "00000000000000000000000000000000",
+ "5D9B05578FC944B3CF1CCF0E746CD581"
+ },
+ { NULL, NULL, NULL }
+ };
+
+ aes_testcase_t *testcase = testcases;
+
+ while (testcase->key != NULL) {
+ len = fromhexstr(testcase->key, key);
+ ATF_CHECK_EQ(len, ISC_AES128_KEYLENGTH);
+ len = fromhexstr(testcase->input, plaintext);
+ ATF_CHECK_EQ(len, ISC_AES_BLOCK_LENGTH);
+ isc_aes128_crypt(key, plaintext, ciphertext);
+ ATF_CHECK(tohexstr(ciphertext, str) == ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+ATF_TC(isc_aes192);
+ATF_TC_HEAD(isc_aes192, tc) {
+ atf_tc_set_md_var(tc, "descr", "AES 192 test vectors");
+}
+ATF_TC_BODY(isc_aes192, tc) {
+ UNUSED(tc);
+
+ aes_testcase_t testcases[] = {
+ /* Test 1 (KAT ECBVarTxt192 #3) */
+ {
+ "000000000000000000000000000000000000000000000000",
+ "F0000000000000000000000000000000",
+ "2A560364CE529EFC21788779568D5555"
+ },
+ /* Test 2 (KAT ECBVarTxt192 #123) */
+ {
+ "000000000000000000000000000000000000000000000000",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "2AABB999F43693175AF65C6C612C46FB"
+ },
+ /* Test 3 (KAT ECBVarKey192 #3) */
+ {
+ "F00000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ "180B09F267C45145DB2F826C2582D35C"
+ },
+ /* Test 4 (KAT ECBVarKey192 #187) */
+ {
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "00000000000000000000000000000000",
+ "EACF1E6C4224EFB38900B185AB1DFD42"
+ },
+ /* Test 5 (KAT ECBGFSbox192 #3) */
+ {
+ "000000000000000000000000000000000000000000000000",
+ "51719783D3185A535BD75ADC65071CE1",
+ "4F354592FF7C8847D2D0870CA9481B7C"
+ },
+ /* Test 6 (KAT ECBKeySbox192 #3) */
+ {
+ "CD62376D5EBB414917F0C78F05266433DC9192A1EC943300",
+ "00000000000000000000000000000000",
+ "7F6C25FF41858561BB62F36492E93C29"
+ },
+ { NULL, NULL, NULL }
+ };
+
+ aes_testcase_t *testcase = testcases;
+
+ while (testcase->key != NULL) {
+ len = fromhexstr(testcase->key, key);
+ ATF_CHECK_EQ(len, ISC_AES192_KEYLENGTH);
+ len = fromhexstr(testcase->input, plaintext);
+ ATF_CHECK_EQ(len, ISC_AES_BLOCK_LENGTH);
+ isc_aes192_crypt(key, plaintext, ciphertext);
+ ATF_CHECK(tohexstr(ciphertext, str) == ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+ATF_TC(isc_aes256);
+ATF_TC_HEAD(isc_aes256, tc) {
+ atf_tc_set_md_var(tc, "descr", "AES 256 test vectors");
+}
+ATF_TC_BODY(isc_aes256, tc) {
+ UNUSED(tc);
+
+ aes_testcase_t testcases[] = {
+ /* Test 1 (KAT ECBVarTxt256 #3) */
+ {
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000",
+ "F0000000000000000000000000000000",
+ "7F2C5ECE07A98D8BEE13C51177395FF7"
+ },
+ /* Test 2 (KAT ECBVarTxt256 #123) */
+ {
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "7240E524BC51D8C4D440B1BE55D1062C"
+ },
+ /* Test 3 (KAT ECBVarKey256 #3) */
+ {
+ "F0000000000000000000000000000000"
+ "00000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ "1C777679D50037C79491A94DA76A9A35"
+ },
+ /* Test 4 (KAT ECBVarKey256 #251) */
+ {
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
+ "00000000000000000000000000000000",
+ "03720371A04962EAEA0A852E69972858"
+ },
+ /* Test 5 (KAT ECBGFSbox256 #3) */
+ {
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000",
+ "8A560769D605868AD80D819BDBA03771",
+ "38F2C7AE10612415D27CA190D27DA8B4"
+ },
+ /* Test 6 (KAT ECBKeySbox256 #3) */
+ {
+ "984CA75F4EE8D706F46C2D98C0BF4A45"
+ "F5B00D791C2DFEB191B5ED8E420FD627",
+ "00000000000000000000000000000000",
+ "4307456A9E67813B452E15FA8FFFE398"
+ },
+ { NULL, NULL, NULL }
+ };
+
+ aes_testcase_t *testcase = testcases;
+
+ while (testcase->key != NULL) {
+ len = fromhexstr(testcase->key, key);
+ ATF_CHECK_EQ(len, ISC_AES256_KEYLENGTH);
+ len = fromhexstr(testcase->input, plaintext);
+ ATF_CHECK_EQ(len, ISC_AES_BLOCK_LENGTH);
+ isc_aes256_crypt(key, plaintext, ciphertext);
+ ATF_CHECK(tohexstr(ciphertext, str) == ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+}
+#else
+ATF_TC(untested);
+ATF_TC_HEAD(untested, tc) {
+ atf_tc_set_md_var(tc, "descr", "skipping aes test");
+}
+ATF_TC_BODY(untested, tc) {
+ UNUSED(tc);
+ atf_tc_skip("AES not available");
+}
+#endif
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+#ifdef ISC_PLATFORM_WANTAES
+ ATF_TP_ADD_TC(tp, isc_aes128);
+ ATF_TP_ADD_TC(tp, isc_aes192);
+ ATF_TP_ADD_TC(tp, isc_aes256);
+#else
+ ATF_TP_ADD_TC(tp, untested);
+#endif
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/atomic_test.c b/lib/isc/tests/atomic_test.c
new file mode 100644
index 0000000..8013010
--- /dev/null
+++ b/lib/isc/tests/atomic_test.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+#include <isc/atomic.h>
+#include <isc/print.h>
+#include <isc/result.h>
+
+#include "isctest.h"
+
+#define TASKS 32
+#define ITERATIONS 1000
+#define COUNTS_PER_ITERATION 1000
+#define INCREMENT_64 (int64_t)0x0000000010000000
+#define EXPECTED_COUNT_32 (TASKS * ITERATIONS * COUNTS_PER_ITERATION)
+#define EXPECTED_COUNT_64 (TASKS * ITERATIONS * COUNTS_PER_ITERATION * INCREMENT_64)
+
+typedef struct {
+ uint32_t iteration;
+} counter_t;
+
+counter_t counters[TASKS];
+
+#if defined(ISC_PLATFORM_HAVEXADD)
+static int32_t counter_32;
+
+static void
+do_xadd(isc_task_t *task, isc_event_t *ev) {
+ counter_t *state = (counter_t *)ev->ev_arg;
+ int i;
+
+ for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
+ isc_atomic_xadd(&counter_32, 1);
+ }
+
+ state->iteration++;
+ if (state->iteration < ITERATIONS) {
+ isc_task_send(task, &ev);
+ } else {
+ isc_event_free(&ev);
+ }
+}
+
+ATF_TC(atomic_xadd);
+ATF_TC_HEAD(atomic_xadd, tc) {
+ atf_tc_set_md_var(tc, "descr", "atomic XADD");
+}
+ATF_TC_BODY(atomic_xadd, tc) {
+ isc_result_t result;
+ isc_task_t *tasks[TASKS];
+ isc_event_t *event = NULL;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ memset(counters, 0, sizeof(counters));
+ counter_32 = 0;
+
+ /*
+ * Create our tasks, and allocate an event to get the counters going.
+ */
+ for (i = 0 ; i < TASKS ; i++) {
+ tasks[i] = NULL;
+ ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]),
+ ISC_R_SUCCESS);
+ event = isc_event_allocate(mctx, NULL, 1000, do_xadd,
+ &counters[i],
+ sizeof(struct isc_event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_sendanddetach(&tasks[i], &event);
+ }
+
+ isc_test_end();
+
+ printf("32-bit counter %d, expected %d\n",
+ counter_32, EXPECTED_COUNT_32);
+
+ ATF_CHECK_EQ(counter_32, EXPECTED_COUNT_32);
+ counter_32 = 0;
+}
+#endif
+
+#if defined(ISC_PLATFORM_HAVEXADDQ)
+static int64_t counter_64;
+
+static void
+do_xaddq(isc_task_t *task, isc_event_t *ev) {
+ counter_t *state = (counter_t *)ev->ev_arg;
+ int i;
+
+ for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
+ isc_atomic_xaddq(&counter_64, INCREMENT_64);
+ }
+
+ state->iteration++;
+ if (state->iteration < ITERATIONS) {
+ isc_task_send(task, &ev);
+ } else {
+ isc_event_free(&ev);
+ }
+}
+
+ATF_TC(atomic_xaddq);
+ATF_TC_HEAD(atomic_xaddq, tc) {
+ atf_tc_set_md_var(tc, "descr", "atomic XADDQ");
+}
+ATF_TC_BODY(atomic_xaddq, tc) {
+ isc_result_t result;
+ isc_task_t *tasks[TASKS];
+ isc_event_t *event = NULL;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ memset(counters, 0, sizeof(counters));
+ counter_64 = 0;
+
+ /*
+ * Create our tasks, and allocate an event to get the counters going.
+ */
+ for (i = 0 ; i < TASKS ; i++) {
+ tasks[i] = NULL;
+ ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]),
+ ISC_R_SUCCESS);
+ event = isc_event_allocate(mctx, NULL, 1000, do_xaddq,
+ &counters[i],
+ sizeof(struct isc_event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_sendanddetach(&tasks[i], &event);
+ }
+
+ isc_test_end();
+
+ printf("64-bit counter %" PRId64 ", "
+ "expected %" PRId64 "\n",
+ counter_64, EXPECTED_COUNT_64);
+
+ ATF_CHECK_EQ(counter_64, EXPECTED_COUNT_64);
+ counter_32 = 0;
+}
+#endif
+
+#if defined(ISC_PLATFORM_HAVEATOMICSTORE)
+static int32_t store_32;
+
+static void
+do_store(isc_task_t *task, isc_event_t *ev) {
+ counter_t *state = (counter_t *)ev->ev_arg;
+ int i;
+ uint32_t r;
+ uint32_t val;
+
+ r = random() % 256;
+ val = (r << 24) | (r << 16) | (r << 8) | r;
+
+ for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
+ isc_atomic_store(&store_32, val);
+ }
+
+ state->iteration++;
+ if (state->iteration < ITERATIONS) {
+ isc_task_send(task, &ev);
+ } else {
+ isc_event_free(&ev);
+ }
+}
+
+ATF_TC(atomic_store);
+ATF_TC_HEAD(atomic_store, tc) {
+ atf_tc_set_md_var(tc, "descr", "atomic STORE");
+}
+ATF_TC_BODY(atomic_store, tc) {
+ isc_result_t result;
+ isc_task_t *tasks[TASKS];
+ isc_event_t *event = NULL;
+ uint32_t val;
+ uint32_t r;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ memset(counters, 0, sizeof(counters));
+ store_32 = 0;
+
+ /*
+ * Create our tasks, and allocate an event to get the counters
+ * going.
+ */
+ for (i = 0 ; i < TASKS ; i++) {
+ tasks[i] = NULL;
+ ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]),
+ ISC_R_SUCCESS);
+ event = isc_event_allocate(mctx, NULL, 1000, do_store,
+ &counters[i],
+ sizeof(struct isc_event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_sendanddetach(&tasks[i], &event);
+ }
+
+ isc_test_end();
+
+ r = store_32 & 0xff;
+ val = (r << 24) | (r << 16) | (r << 8) | r;
+
+ printf("32-bit store 0x%x, expected 0x%x\n",
+ (uint32_t) store_32, val);
+
+ ATF_CHECK_EQ((uint32_t) store_32, val);
+ store_32 = 0;
+}
+#endif
+
+#if defined(ISC_PLATFORM_HAVEATOMICSTOREQ)
+static int64_t store_64;
+
+static void
+do_storeq(isc_task_t *task, isc_event_t *ev) {
+ counter_t *state = (counter_t *)ev->ev_arg;
+ int i;
+ uint8_t r;
+ uint64_t val;
+
+ r = random() % 256;
+ val = (((uint64_t) r << 24) |
+ ((uint64_t) r << 16) |
+ ((uint64_t) r << 8) |
+ (uint64_t) r);
+ val |= ((uint64_t) val << 32);
+
+ for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
+ isc_atomic_storeq(&store_64, val);
+ }
+
+ state->iteration++;
+ if (state->iteration < ITERATIONS) {
+ isc_task_send(task, &ev);
+ } else {
+ isc_event_free(&ev);
+ }
+}
+
+ATF_TC(atomic_storeq);
+ATF_TC_HEAD(atomic_storeq, tc) {
+ atf_tc_set_md_var(tc, "descr", "atomic STOREQ");
+}
+ATF_TC_BODY(atomic_storeq, tc) {
+ isc_result_t result;
+ isc_task_t *tasks[TASKS];
+ isc_event_t *event = NULL;
+ uint64_t val;
+ uint32_t r;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ memset(counters, 0, sizeof(counters));
+ store_64 = 0;
+
+ /*
+ * Create our tasks, and allocate an event to get the counters
+ * going.
+ */
+ for (i = 0 ; i < TASKS ; i++) {
+ tasks[i] = NULL;
+ ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]),
+ ISC_R_SUCCESS);
+ event = isc_event_allocate(mctx, NULL, 1000, do_storeq,
+ &counters[i],
+ sizeof(struct isc_event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_sendanddetach(&tasks[i], &event);
+ }
+
+ isc_test_end();
+
+ r = store_64 & 0xff;
+ val = (((uint64_t) r << 24) |
+ ((uint64_t) r << 16) |
+ ((uint64_t) r << 8) |
+ (uint64_t) r);
+ val |= ((uint64_t) val << 32);
+
+ printf("64-bit store 0x%" PRIx64 ", "
+ "expected 0x%" PRIx64 "\n",
+ (uint64_t) store_64, val);
+
+ ATF_CHECK_EQ((uint64_t) store_64, val);
+ store_64 = 0;
+}
+#endif
+
+#if !defined(ISC_PLATFORM_HAVEXADD) && \
+ !defined(ISC_PLATFORM_HAVEXADDQ) && \
+ !defined(ISC_PLATFORM_HAVEATOMICSTOREQ)
+ATF_TC(untested);
+ATF_TC_HEAD(untested, tc) {
+ atf_tc_set_md_var(tc, "descr", "skipping aes test");
+}
+ATF_TC_BODY(untested, tc) {
+ UNUSED(tc);
+ atf_tc_skip("AES not available");
+}
+#endif /* !HAVEXADD, !HAVEXADDQ, !HAVEATOMICSTOREQ */
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+#if defined(ISC_PLATFORM_HAVEXADD)
+ ATF_TP_ADD_TC(tp, atomic_xadd);
+#endif
+#if defined(ISC_PLATFORM_HAVEXADDQ)
+ ATF_TP_ADD_TC(tp, atomic_xaddq);
+#endif
+#ifdef ISC_PLATFORM_HAVEATOMICSTORE
+ ATF_TP_ADD_TC(tp, atomic_store);
+#endif
+#if defined(ISC_PLATFORM_HAVEATOMICSTOREQ)
+ ATF_TP_ADD_TC(tp, atomic_storeq);
+#endif
+#if !defined(ISC_PLATFORM_HAVEXADD) && \
+ !defined(ISC_PLATFORM_HAVEXADDQ) && \
+ !defined(ISC_PLATFORM_HAVEATOMICSTOREQ)
+ ATF_TP_ADD_TC(tp, untested);
+#endif
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/buffer_test.c b/lib/isc/tests/buffer_test.c
new file mode 100644
index 0000000..a2d76cc
--- /dev/null
+++ b/lib/isc/tests/buffer_test.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <atf-c.h>
+
+#include "isctest.h"
+
+#include <isc/buffer.h>
+#include <isc/result.h>
+
+ATF_TC(isc_buffer_reserve);
+ATF_TC_HEAD(isc_buffer_reserve, tc) {
+ atf_tc_set_md_var(tc, "descr", "reserve space in dynamic buffers");
+}
+
+ATF_TC_BODY(isc_buffer_reserve, tc) {
+ isc_result_t result;
+ isc_buffer_t *b;
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ b = NULL;
+ result = isc_buffer_allocate(mctx, &b, 1024);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_EQ(b->length, 1024);
+
+ /*
+ * 1024 bytes should already be available, so this call does
+ * nothing.
+ */
+ result = isc_buffer_reserve(&b, 1024);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(ISC_BUFFER_VALID(b));
+ ATF_REQUIRE(b != NULL);
+ ATF_CHECK_EQ(b->length, 1024);
+
+ /*
+ * This call should grow it to 2048 bytes as only 1024 bytes are
+ * available in the buffer.
+ */
+ result = isc_buffer_reserve(&b, 1025);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(ISC_BUFFER_VALID(b));
+ ATF_REQUIRE(b != NULL);
+ ATF_CHECK_EQ(b->length, 2048);
+
+ /*
+ * 2048 bytes should already be available, so this call does
+ * nothing.
+ */
+ result = isc_buffer_reserve(&b, 2000);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(ISC_BUFFER_VALID(b));
+ ATF_REQUIRE(b != NULL);
+ ATF_CHECK_EQ(b->length, 2048);
+
+ /*
+ * This call should grow it to 4096 bytes as only 2048 bytes are
+ * available in the buffer.
+ */
+ result = isc_buffer_reserve(&b, 3000);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(ISC_BUFFER_VALID(b));
+ ATF_REQUIRE(b != NULL);
+ ATF_CHECK_EQ(b->length, 4096);
+
+ /* Consume some of the buffer so we can run the next test. */
+ isc_buffer_add(b, 4096);
+
+ /*
+ * This call should fail and leave buffer untouched.
+ */
+ result = isc_buffer_reserve(&b, UINT_MAX);
+ ATF_CHECK_EQ(result, ISC_R_NOMEMORY);
+ ATF_CHECK(ISC_BUFFER_VALID(b));
+ ATF_REQUIRE(b != NULL);
+ ATF_CHECK_EQ(b->length, 4096);
+
+ isc_buffer_free(&b);
+
+ isc_test_end();
+}
+
+ATF_TC(isc_buffer_reallocate);
+ATF_TC_HEAD(isc_buffer_reallocate, tc) {
+ atf_tc_set_md_var(tc, "descr", "reallocate dynamic buffers");
+}
+
+ATF_TC_BODY(isc_buffer_reallocate, tc) {
+ isc_result_t result;
+ isc_buffer_t *b;
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ b = NULL;
+ result = isc_buffer_allocate(mctx, &b, 1024);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE(b != NULL);
+ ATF_CHECK_EQ(b->length, 1024);
+
+ result = isc_buffer_reallocate(&b, 512);
+ ATF_CHECK_EQ(result, ISC_R_NOSPACE);
+ ATF_CHECK(ISC_BUFFER_VALID(b));
+ ATF_REQUIRE(b != NULL);
+ ATF_CHECK_EQ(b->length, 1024);
+
+ result = isc_buffer_reallocate(&b, 1536);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(ISC_BUFFER_VALID(b));
+ ATF_REQUIRE(b != NULL);
+ ATF_CHECK_EQ(b->length, 1536);
+
+ isc_buffer_free(&b);
+
+ isc_test_end();
+}
+
+ATF_TC(isc_buffer_dynamic);
+ATF_TC_HEAD(isc_buffer_dynamic, tc) {
+ atf_tc_set_md_var(tc, "descr", "dynamic buffer automatic reallocation");
+}
+
+ATF_TC_BODY(isc_buffer_dynamic, tc) {
+ isc_result_t result;
+ isc_buffer_t *b;
+ size_t last_length = 10;
+ int i;
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ b = NULL;
+ result = isc_buffer_allocate(mctx, &b, last_length);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE(b != NULL);
+ ATF_CHECK_EQ(b->length, last_length);
+
+ isc_buffer_setautorealloc(b, true);
+
+ isc_buffer_putuint8(b, 1);
+
+ for (i = 0; i < 1000; i++) {
+ isc_buffer_putstr(b, "thisisa24charslongstring");
+ }
+ ATF_CHECK(b->length-last_length >= 1000*24);
+ last_length+=1000*24;
+
+ for (i = 0; i < 10000; i++) {
+ isc_buffer_putuint8(b, 1);
+ }
+
+ ATF_CHECK(b->length-last_length >= 10000*1);
+ last_length += 10000*1;
+
+ for (i = 0; i < 10000; i++) {
+ isc_buffer_putuint16(b, 1);
+ }
+
+ ATF_CHECK(b->length-last_length >= 10000*2);
+
+ last_length += 10000*2;
+ for (i = 0; i < 10000; i++) {
+ isc_buffer_putuint24(b, 1);
+ }
+ ATF_CHECK(b->length-last_length >= 10000*3);
+
+ last_length+=10000*3;
+
+ for (i = 0; i < 10000; i++) {
+ isc_buffer_putuint32(b, 1);
+ }
+ ATF_CHECK(b->length-last_length >= 10000*4);
+
+
+ isc_buffer_free(&b);
+
+ isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_buffer_reserve);
+ ATF_TP_ADD_TC(tp, isc_buffer_reallocate);
+ ATF_TP_ADD_TC(tp, isc_buffer_dynamic);
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/counter_test.c b/lib/isc/tests/counter_test.c
new file mode 100644
index 0000000..ddcdae3
--- /dev/null
+++ b/lib/isc/tests/counter_test.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+#include <isc/counter.h>
+#include <isc/result.h>
+
+#include "isctest.h"
+
+ATF_TC(isc_counter);
+ATF_TC_HEAD(isc_counter, tc) {
+ atf_tc_set_md_var(tc, "descr", "isc counter object");
+}
+ATF_TC_BODY(isc_counter, tc) {
+ isc_result_t result;
+ isc_counter_t *counter = NULL;
+ int i;
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_counter_create(mctx, 0, &counter);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ for (i = 0; i < 10; i++) {
+ result = isc_counter_increment(counter);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ }
+
+ ATF_CHECK_EQ(isc_counter_used(counter), 10);
+
+ isc_counter_setlimit(counter, 15);
+ for (i = 0; i < 10; i++) {
+ result = isc_counter_increment(counter);
+ if (result != ISC_R_SUCCESS)
+ break;
+ }
+
+ ATF_CHECK_EQ(isc_counter_used(counter), 15);
+
+ isc_counter_detach(&counter);
+ isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_counter);
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/errno_test.c b/lib/isc/tests/errno_test.c
new file mode 100644
index 0000000..e45bdd8
--- /dev/null
+++ b/lib/isc/tests/errno_test.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <sys/errno.h>
+
+#include <atf-c.h>
+
+#include <isc/errno.h>
+#include <isc/result.h>
+
+typedef struct {
+ int err;
+ isc_result_t result;
+} testpair_t;
+
+testpair_t testpair[] = {
+ { EPERM, ISC_R_NOPERM },
+ { ENOENT, ISC_R_FILENOTFOUND },
+ { EIO, ISC_R_IOERROR },
+ { EBADF, ISC_R_INVALIDFILE },
+ { ENOMEM, ISC_R_NOMEMORY },
+ { EACCES, ISC_R_NOPERM },
+ { EEXIST, ISC_R_FILEEXISTS },
+ { ENOTDIR, ISC_R_INVALIDFILE },
+ { EINVAL, ISC_R_INVALIDFILE },
+ { ENFILE, ISC_R_TOOMANYOPENFILES },
+ { EMFILE, ISC_R_TOOMANYOPENFILES },
+ { EPIPE, ISC_R_CONNECTIONRESET },
+ { ENAMETOOLONG, ISC_R_INVALIDFILE },
+ { ELOOP, ISC_R_INVALIDFILE },
+#ifdef EOVERFLOW
+ { EOVERFLOW, ISC_R_RANGE },
+#endif
+#ifdef EAFNOSUPPORT
+ { EAFNOSUPPORT, ISC_R_FAMILYNOSUPPORT },
+#endif
+#ifdef EADDRINUSE
+ { EADDRINUSE, ISC_R_ADDRINUSE },
+#endif
+ { EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL },
+#ifdef ENETDOWN
+ { ENETDOWN, ISC_R_NETDOWN },
+#endif
+#ifdef ENETUNREACH
+ { ENETUNREACH, ISC_R_NETUNREACH },
+#endif
+#ifdef ECONNABORTED
+ { ECONNABORTED, ISC_R_CONNECTIONRESET },
+#endif
+#ifdef ECONNRESET
+ { ECONNRESET, ISC_R_CONNECTIONRESET },
+#endif
+#ifdef ENOBUFS
+ { ENOBUFS, ISC_R_NORESOURCES },
+#endif
+#ifdef ENOTCONN
+ { ENOTCONN, ISC_R_NOTCONNECTED },
+#endif
+#ifdef ETIMEDOUT
+ { ETIMEDOUT, ISC_R_TIMEDOUT },
+#endif
+ { ECONNREFUSED, ISC_R_CONNREFUSED },
+#ifdef EHOSTDOWN
+ { EHOSTDOWN, ISC_R_HOSTDOWN },
+#endif
+#ifdef EHOSTUNREACH
+ { EHOSTUNREACH, ISC_R_HOSTUNREACH },
+#endif
+ { 0, ISC_R_UNEXPECTED }
+};
+
+ATF_TC(isc_errno_toresult);
+ATF_TC_HEAD(isc_errno_toresult, tc) {
+ atf_tc_set_md_var(tc, "descr", "convert errno to ISC result");
+}
+ATF_TC_BODY(isc_errno_toresult, tc) {
+ isc_result_t result, expect;
+ size_t i;
+
+ for (i = 0; i < sizeof(testpair)/sizeof(testpair[0]); i++) {
+ result = isc_errno_toresult(testpair[i].err);
+ expect = testpair[i].result;
+ ATF_CHECK(result == expect);
+ }
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_errno_toresult);
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/file_test.c b/lib/isc/tests/file_test.c
new file mode 100644
index 0000000..3dadb52
--- /dev/null
+++ b/lib/isc/tests/file_test.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include <isc/file.h>
+#include <isc/result.h>
+
+ATF_TC(isc_file_sanitize);
+ATF_TC_HEAD(isc_file_sanitize, tc) {
+ atf_tc_set_md_var(tc, "descr", "sanitized filenames");
+}
+
+#define NAME "internal"
+#define SHA "3bed2cb3a3acf7b6a8ef408420cc682d5520e26976d354254f528c965612054f"
+#define TRUNC_SHA "3bed2cb3a3acf7b6"
+
+#define BAD1 "in/internal"
+#define BADHASH1 "8bbb97a888791399"
+
+#define BAD2 "Internal"
+#define BADHASH2 "2ea1842b445b0c81"
+
+#define F(x) "testdata/file/" x ".test"
+
+static void
+touch(const char *filename) {
+ int fd;
+
+ unlink(filename);
+ fd = creat(filename, 0644);
+ if (fd != -1)
+ close(fd);
+}
+
+ATF_TC_BODY(isc_file_sanitize, tc) {
+ isc_result_t result;
+ char buf[1024];
+
+ ATF_CHECK(chdir(TESTS) != -1);
+
+ result = isc_file_sanitize("testdata/file", NAME, "test", buf, 1024);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(strcmp(buf, F(NAME)) == 0);
+
+ touch(F(TRUNC_SHA));
+ result = isc_file_sanitize("testdata/file", NAME, "test", buf, 1024);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(strcmp(buf, F(TRUNC_SHA)) == 0);
+
+ touch(F(SHA));
+ result = isc_file_sanitize("testdata/file", NAME, "test", buf, 1024);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(strcmp(buf, F(SHA)) == 0);
+
+ result = isc_file_sanitize("testdata/file", BAD1, "test", buf, 1024);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(strcmp(buf, F(BADHASH1)) == 0);
+
+ result = isc_file_sanitize("testdata/file", BAD2, "test", buf, 1024);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(strcmp(buf, F(BADHASH2)) == 0);
+
+ unlink(F(TRUNC_SHA));
+ unlink(F(SHA));
+}
+
+ATF_TC(isc_file_template);
+ATF_TC_HEAD(isc_file_template, tc) {
+ atf_tc_set_md_var(tc, "descr", "file template");
+}
+
+ATF_TC_BODY(isc_file_template, tc) {
+ isc_result_t result;
+ char buf[1024];
+
+ ATF_CHECK(chdir(TESTS) != -1);
+
+ result = isc_file_template("/absolute/path", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "/absolute/file-XXXXXXXX");
+
+ result = isc_file_template("relative/path", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "relative/file-XXXXXXXX");
+
+ result = isc_file_template("/trailing/slash/", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "/trailing/slash/file-XXXXXXXX");
+
+ result = isc_file_template("relative/trailing/slash/", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "relative/trailing/slash/file-XXXXXXXX");
+
+ result = isc_file_template("/", "file-XXXXXXXX", buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "/file-XXXXXXXX");
+
+ result = isc_file_template("noslash", "file-XXXXXXXX",
+ buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "file-XXXXXXXX");
+
+ result = isc_file_template(NULL, "file-XXXXXXXX", buf, sizeof(buf));
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(buf, "file-XXXXXXXX");
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_file_sanitize);
+ ATF_TP_ADD_TC(tp, isc_file_template);
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/hash_test.c b/lib/isc/tests/hash_test.c
new file mode 100644
index 0000000..8f12342
--- /dev/null
+++ b/lib/isc/tests/hash_test.c
@@ -0,0 +1,2038 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* ! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/hash.h>
+
+#include <isc/crc64.h>
+#include <isc/hmacmd5.h>
+#include <isc/hmacsha.h>
+#include <isc/md5.h>
+#include <isc/sha1.h>
+#include <isc/util.h>
+#include <isc/print.h>
+#include <isc/string.h>
+
+#include <pk11/site.h>
+
+/*
+ * Test data from RFC6234
+ */
+
+unsigned char digest[ISC_SHA512_DIGESTLENGTH];
+unsigned char buffer[1024];
+const char *s;
+char str[2 * ISC_SHA512_DIGESTLENGTH + 3];
+unsigned char key[20];
+
+/*
+ * Precondition: a hexadecimal number in *d, the length of that number in len,
+ * and a pointer to a character array to put the output (*out).
+ * Postcondition: A String representation of the given hexadecimal number is
+ * placed into the array *out
+ *
+ * 'out' MUST point to an array of at least len * 2 + 1
+ *
+ * Return values: ISC_R_SUCCESS if the operation is sucessful
+ */
+static isc_result_t
+tohexstr(unsigned char *d, unsigned int len, char *out, size_t out_size) {
+ char c_ret[] = "AA";
+ unsigned int i;
+
+ out[0] = '\0';
+ strlcat(out, "0x", out_size);
+ for (i = 0; i < len; i++) {
+ snprintf(c_ret, sizeof(c_ret), "%02X", d[i]);
+ strlcat(out, c_ret, out_size);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+
+#define TEST_INPUT(x) (x), sizeof(x)-1
+
+typedef struct hash_testcase {
+ const char *input;
+ size_t input_len;
+ const char *result;
+ int repeats;
+} hash_testcase_t;
+
+typedef struct hash_test_key {
+ const char *key;
+ const int len;
+} hash_test_key_t;
+
+/* non-hmac tests */
+
+ATF_TC(isc_sha1);
+ATF_TC_HEAD(isc_sha1, tc) {
+ atf_tc_set_md_var(tc, "descr", "sha1 examples from RFC4634");
+}
+ATF_TC_BODY(isc_sha1, tc) {
+ isc_sha1_t sha1;
+ int i;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("abc"),
+ "0xA9993E364706816ABA3E25717850C26C9CD0D89D",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("abcdbcdecdefdefgefghfghighijhijkijk"
+ "ljklmklmnlmnomnopnopq"),
+ "0x84983E441C3BD26EBAAE4AA1F95129E5E54670F1",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("a") /* times 1000000 */,
+ "0x34AA973CD4C4DAA4F61EEB2BDBAD27316534016F",
+ 1000000
+ },
+ /* Test 4 -- exact multiple of 512 bits */
+ {
+ TEST_INPUT("01234567012345670123456701234567"),
+ "0xDEA356A2CDDD90C7A7ECEDC5EBB563934F460452",
+ 20 /* 20 times */
+ },
+#if 0
+ /* Test 5 -- optional feature, not implemented */
+ {
+ TEST_INPUT(""),
+ /* "extrabits": 0x98 , "numberextrabits": 5 */
+ "0x29826B003B906E660EFF4027CE98AF3531AC75BA",
+ 1
+ },
+#endif
+ /* Test 6 */
+ {
+ TEST_INPUT("\x5e"),
+ "0x5E6F80A34A9798CAFC6A5DB96CC57BA4C4DB59C2",
+ 1
+ },
+#if 0
+ /* Test 7 -- optional feature, not implemented */
+ {
+ TEST_INPUT("\x49\xb2\xae\xc2\x59\x4b\xbe\x3a"
+ "\x3b\x11\x75\x42\xd9\x4a\xc8"),
+ /* "extrabits": 0x80, "numberextrabits": 3 */
+ "0x6239781E03729919C01955B3FFA8ACB60B988340", 1 },
+#endif
+ /* Test 8 */
+ {
+ TEST_INPUT("\x9a\x7d\xfd\xf1\xec\xea\xd0\x6e\xd6\x46"
+ "\xaa\x55\xfe\x75\x71\x46"),
+ "0x82ABFF6605DBE1C17DEF12A394FA22A82B544A35",
+ 1
+ },
+#if 0
+ /* Test 9 -- optional feature, not implemented */
+ {
+ TEST_INPUT("\x65\xf9\x32\x99\x5b\xa4\xce\x2c\xb1\xb4"
+ "\xa2\xe7\x1a\xe7\x02\x20\xaa\xce\xc8\x96"
+ "\x2d\xd4\x49\x9c\xbd\x7c\x88\x7a\x94\xea"
+ "\xaa\x10\x1e\xa5\xaa\xbc\x52\x9b\x4e\x7e"
+ "\x43\x66\x5a\x5a\xf2\xcd\x03\xfe\x67\x8e"
+ "\xa6\xa5\x00\x5b\xba\x3b\x08\x22\x04\xc2"
+ "\x8b\x91\x09\xf4\x69\xda\xc9\x2a\xaa\xb3"
+ "\xaa\x7c\x11\xa1\xb3\x2a"),
+ /* "extrabits": 0xE0 , "numberextrabits": 3 */
+ "0x8C5B2A5DDAE5A97FC7F9D85661C672ADBF7933D4",
+ 1
+ },
+#endif
+ /* Test 10 */
+ {
+ TEST_INPUT("\xf7\x8f\x92\x14\x1b\xcd\x17\x0a\xe8\x9b"
+ "\x4f\xba\x15\xa1\xd5\x9f\x3f\xd8\x4d\x22"
+ "\x3c\x92\x51\xbd\xac\xbb\xae\x61\xd0\x5e"
+ "\xd1\x15\xa0\x6a\x7c\xe1\x17\xb7\xbe\xea"
+ "\xd2\x44\x21\xde\xd9\xc3\x25\x92\xbd\x57"
+ "\xed\xea\xe3\x9c\x39\xfa\x1f\xe8\x94\x6a"
+ "\x84\xd0\xcf\x1f\x7b\xee\xad\x17\x13\xe2"
+ "\xe0\x95\x98\x97\x34\x7f\x67\xc8\x0b\x04"
+ "\x00\xc2\x09\x81\x5d\x6b\x10\xa6\x83\x83"
+ "\x6f\xd5\x56\x2a\x56\xca\xb1\xa2\x8e\x81"
+ "\xb6\x57\x66\x54\x63\x1c\xf1\x65\x66\xb8"
+ "\x6e\x3b\x33\xa1\x08\xb0\x53\x07\xc0\x0a"
+ "\xff\x14\xa7\x68\xed\x73\x50\x60\x6a\x0f"
+ "\x85\xe6\xa9\x1d\x39\x6f\x5b\x5c\xbe\x57"
+ "\x7f\x9b\x38\x80\x7c\x7d\x52\x3d\x6d\x79"
+ "\x2f\x6e\xbc\x24\xa4\xec\xf2\xb3\xa4\x27"
+ "\xcd\xbb\xfb"),
+ "0xCB0082C8F197D260991BA6A460E76E202BAD27B3",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ isc_sha1_init(&sha1);
+ for(i = 0; i < testcase->repeats; i++) {
+ isc_sha1_update(&sha1,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ }
+ isc_sha1_final(&sha1, digest);
+ tohexstr(digest, ISC_SHA1_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+ATF_TC(isc_sha224);
+ATF_TC_HEAD(isc_sha224, tc) {
+ atf_tc_set_md_var(tc, "descr", "sha224 examples from RFC4634");
+}
+ATF_TC_BODY(isc_sha224, tc) {
+ isc_sha224_t sha224;
+ int i;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("abc"),
+ "0x23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7"
+ "E36C9DA7",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("abcdbcdecdefdefgefghfghighijhijkijklj"
+ "klmklmnlmnomnopnopq"),
+ "0x75388B16512776CC5DBA5DA1FD890150B0C6455CB4F58B"
+ "1952522525",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("a"),
+ "0x20794655980C91D8BBB4C1EA97618A4BF03F42581948B2"
+ "EE4EE7AD67",
+ 1000000
+ },
+ /* Test 4 */
+ {
+ TEST_INPUT("01234567012345670123456701234567"),
+ "0x567F69F168CD7844E65259CE658FE7AADFA25216E68ECA"
+ "0EB7AB8262",
+ 20
+ },
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 6 */
+ {
+ TEST_INPUT("\x07"),
+ "0x00ECD5F138422B8AD74C9799FD826C531BAD2FCABC7450"
+ "BEE2AA8C2A",
+ 1
+ },
+#if 0
+ /* Test 7 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 8 */
+ {
+ TEST_INPUT("\x18\x80\x40\x05\xdd\x4f\xbd\x15\x56\x29"
+ "\x9d\x6f\x9d\x93\xdf\x62"),
+ "0xDF90D78AA78821C99B40BA4C966921ACCD8FFB1E98AC38"
+ "8E56191DB1",
+ 1
+ },
+#if 0
+ /* Test 9 */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 10 */
+ {
+ TEST_INPUT("\x55\xb2\x10\x07\x9c\x61\xb5\x3a\xdd\x52"
+ "\x06\x22\xd1\xac\x97\xd5\xcd\xbe\x8c\xb3"
+ "\x3a\xa0\xae\x34\x45\x17\xbe\xe4\xd7\xba"
+ "\x09\xab\xc8\x53\x3c\x52\x50\x88\x7a\x43"
+ "\xbe\xbb\xac\x90\x6c\x2e\x18\x37\xf2\x6b"
+ "\x36\xa5\x9a\xe3\xbe\x78\x14\xd5\x06\x89"
+ "\x6b\x71\x8b\x2a\x38\x3e\xcd\xac\x16\xb9"
+ "\x61\x25\x55\x3f\x41\x6f\xf3\x2c\x66\x74"
+ "\xc7\x45\x99\xa9\x00\x53\x86\xd9\xce\x11"
+ "\x12\x24\x5f\x48\xee\x47\x0d\x39\x6c\x1e"
+ "\xd6\x3b\x92\x67\x0c\xa5\x6e\xc8\x4d\xee"
+ "\xa8\x14\xb6\x13\x5e\xca\x54\x39\x2b\xde"
+ "\xdb\x94\x89\xbc\x9b\x87\x5a\x8b\xaf\x0d"
+ "\xc1\xae\x78\x57\x36\x91\x4a\xb7\xda\xa2"
+ "\x64\xbc\x07\x9d\x26\x9f\x2c\x0d\x7e\xdd"
+ "\xd8\x10\xa4\x26\x14\x5a\x07\x76\xf6\x7c"
+ "\x87\x82\x73"),
+ "0x0B31894EC8937AD9B91BDFBCBA294D9ADEFAA18E09305E"
+ "9F20D5C3A4",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ isc_sha224_init(&sha224);
+ for(i = 0; i < testcase->repeats; i++) {
+ isc_sha224_update(&sha224,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ }
+ isc_sha224_final(digest, &sha224);
+ /*
+ *API inconsistency BUG HERE
+ * in order to be consistant with the other isc_hash_final
+ * functions the call should be
+ * isc_sha224_final(&sha224, digest);
+ */
+ tohexstr(digest, ISC_SHA224_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+ATF_TC(isc_sha256);
+ATF_TC_HEAD(isc_sha256, tc) {
+ atf_tc_set_md_var(tc, "descr", "sha224 examples from RFC4634");
+}
+ATF_TC_BODY(isc_sha256, tc) {
+ isc_sha256_t sha256;
+ int i;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("abc"),
+ "0xBA7816BF8F01CFEA414140DE5DAE2223B00361A396177A"
+ "9CB410FF61F20015AD",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("abcdbcdecdefdefgefghfghighijhijkijkljk"
+ "lmklmnlmnomnopnopq"),
+ "0x248D6A61D20638B8E5C026930C3E6039A33CE45964FF21"
+ "67F6ECEDD419DB06C1",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("a"),
+ "0xCDC76E5C9914FB9281A1C7E284D73E67F1809A48A49720"
+ "0E046D39CCC7112CD0",
+ 1000000 },
+ /* Test 4 */
+ {
+ TEST_INPUT("01234567012345670123456701234567"),
+ "0x594847328451BDFA85056225462CC1D867D877FB388DF0"
+ "CE35F25AB5562BFBB5",
+ 20
+ },
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 6 */
+ {
+ TEST_INPUT("\x19"),
+ "0x68AA2E2EE5DFF96E3355E6C7EE373E3D6A4E17F75F9518"
+ "D843709C0C9BC3E3D4",
+ 1
+ },
+#if 0
+ /* Test 7 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 8 */
+ {
+ TEST_INPUT("\xe3\xd7\x25\x70\xdc\xdd\x78\x7c\xe3"
+ "\x88\x7a\xb2\xcd\x68\x46\x52"),
+ "0x175EE69B02BA9B58E2B0A5FD13819CEA573F3940A94F82"
+ "5128CF4209BEABB4E8",
+ 1
+ },
+#if 0
+ /* Test 9 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 10 */
+ {
+ TEST_INPUT("\x83\x26\x75\x4e\x22\x77\x37\x2f\x4f\xc1"
+ "\x2b\x20\x52\x7a\xfe\xf0\x4d\x8a\x05\x69"
+ "\x71\xb1\x1a\xd5\x71\x23\xa7\xc1\x37\x76"
+ "\x00\x00\xd7\xbe\xf6\xf3\xc1\xf7\xa9\x08"
+ "\x3a\xa3\x9d\x81\x0d\xb3\x10\x77\x7d\xab"
+ "\x8b\x1e\x7f\x02\xb8\x4a\x26\xc7\x73\x32"
+ "\x5f\x8b\x23\x74\xde\x7a\x4b\x5a\x58\xcb"
+ "\x5c\x5c\xf3\x5b\xce\xe6\xfb\x94\x6e\x5b"
+ "\xd6\x94\xfa\x59\x3a\x8b\xeb\x3f\x9d\x65"
+ "\x92\xec\xed\xaa\x66\xca\x82\xa2\x9d\x0c"
+ "\x51\xbc\xf9\x33\x62\x30\xe5\xd7\x84\xe4"
+ "\xc0\xa4\x3f\x8d\x79\xa3\x0a\x16\x5c\xba"
+ "\xbe\x45\x2b\x77\x4b\x9c\x71\x09\xa9\x7d"
+ "\x13\x8f\x12\x92\x28\x96\x6f\x6c\x0a\xdc"
+ "\x10\x6a\xad\x5a\x9f\xdd\x30\x82\x57\x69"
+ "\xb2\xc6\x71\xaf\x67\x59\xdf\x28\xeb\x39"
+ "\x3d\x54\xd6"),
+ "0x97DBCA7DF46D62C8A422C941DD7E835B8AD3361763F7E9"
+ "B2D95F4F0DA6E1CCBC",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ isc_sha256_init(&sha256);
+ for(i = 0; i < testcase->repeats; i++) {
+ isc_sha256_update(&sha256,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ }
+ isc_sha256_final(digest, &sha256);
+ /*
+ *API inconsistency BUG HERE
+ * in order to be consistant with the other isc_hash_final
+ * functions the call should be
+ * isc_sha224_final(&sha224, digest);
+ */
+ tohexstr(digest, ISC_SHA256_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+ATF_TC(isc_sha384);
+ATF_TC_HEAD(isc_sha384, tc) {
+ atf_tc_set_md_var(tc, "descr", "sha224 examples from RFC4634");
+}
+ATF_TC_BODY(isc_sha384, tc) {
+ isc_sha384_t sha384;
+ int i;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("abc"),
+ "0xCB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1"
+ "631A8B605A43FF5BED8086072BA1E7CC2358BAEC"
+ "A134C825A7",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("abcdefghbcdefghicdefghijdefghijkefghijkl"
+ "fghijklmghijklmnhijklmnoijklmnopjklmnopq"
+ "klmnopqrlmnopqrsmnopqrstnopqrstu"),
+ "0x09330C33F71147E83D192FC782CD1B4753111B173B3B05"
+ "D22FA08086E3B0F712FCC7C71A557E2DB966C3E9"
+ "FA91746039",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("a"),
+ "0x9D0E1809716474CB086E834E310A4A1CED149E9C00F248"
+ "527972CEC5704C2A5B07B8B3DC38ECC4EBAE97DD"
+ "D87F3D8985",
+ 1000000
+ },
+ /* Test 4 */
+ {
+ TEST_INPUT("01234567012345670123456701234567"),
+ "0x2FC64A4F500DDB6828F6A3430B8DD72A368EB7F3A8322A"
+ "70BC84275B9C0B3AB00D27A5CC3C2D224AA6B61A"
+ "0D79FB4596",
+ 20
+ },
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 6 */
+ { TEST_INPUT("\xb9"),
+ "0xBC8089A19007C0B14195F4ECC74094FEC64F01F9092928"
+ "2C2FB392881578208AD466828B1C6C283D2722CF"
+ "0AD1AB6938",
+ 1
+ },
+#if 0
+ /* Test 7 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 8 */
+ {
+ TEST_INPUT("\xa4\x1c\x49\x77\x79\xc0\x37\x5f\xf1"
+ "\x0a\x7f\x4e\x08\x59\x17\x39"),
+ "0xC9A68443A005812256B8EC76B00516F0DBB74FAB26D665"
+ "913F194B6FFB0E91EA9967566B58109CBC675CC2"
+ "08E4C823F7",
+ 1
+ },
+#if 0
+ /* Test 9 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 10 */
+ {
+ TEST_INPUT("\x39\x96\x69\xe2\x8f\x6b\x9c\x6d\xbc\xbb"
+ "\x69\x12\xec\x10\xff\xcf\x74\x79\x03\x49"
+ "\xb7\xdc\x8f\xbe\x4a\x8e\x7b\x3b\x56\x21"
+ "\xdb\x0f\x3e\x7d\xc8\x7f\x82\x32\x64\xbb"
+ "\xe4\x0d\x18\x11\xc9\xea\x20\x61\xe1\xc8"
+ "\x4a\xd1\x0a\x23\xfa\xc1\x72\x7e\x72\x02"
+ "\xfc\x3f\x50\x42\xe6\xbf\x58\xcb\xa8\xa2"
+ "\x74\x6e\x1f\x64\xf9\xb9\xea\x35\x2c\x71"
+ "\x15\x07\x05\x3c\xf4\xe5\x33\x9d\x52\x86"
+ "\x5f\x25\xcc\x22\xb5\xe8\x77\x84\xa1\x2f"
+ "\xc9\x61\xd6\x6c\xb6\xe8\x95\x73\x19\x9a"
+ "\x2c\xe6\x56\x5c\xbd\xf1\x3d\xca\x40\x38"
+ "\x32\xcf\xcb\x0e\x8b\x72\x11\xe8\x3a\xf3"
+ "\x2a\x11\xac\x17\x92\x9f\xf1\xc0\x73\xa5"
+ "\x1c\xc0\x27\xaa\xed\xef\xf8\x5a\xad\x7c"
+ "\x2b\x7c\x5a\x80\x3e\x24\x04\xd9\x6d\x2a"
+ "\x77\x35\x7b\xda\x1a\x6d\xae\xed\x17\x15"
+ "\x1c\xb9\xbc\x51\x25\xa4\x22\xe9\x41\xde"
+ "\x0c\xa0\xfc\x50\x11\xc2\x3e\xcf\xfe\xfd"
+ "\xd0\x96\x76\x71\x1c\xf3\xdb\x0a\x34\x40"
+ "\x72\x0e\x16\x15\xc1\xf2\x2f\xbc\x3c\x72"
+ "\x1d\xe5\x21\xe1\xb9\x9b\xa1\xbd\x55\x77"
+ "\x40\x86\x42\x14\x7e\xd0\x96"),
+ "0x4F440DB1E6EDD2899FA335F09515AA025EE177A79F4B4A"
+ "AF38E42B5C4DE660F5DE8FB2A5B2FBD2A3CBFFD2"
+ "0CFF1288C0",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ isc_sha384_init(&sha384);
+ for(i = 0; i < testcase->repeats; i++) {
+ isc_sha384_update(&sha384,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ }
+ isc_sha384_final(digest, &sha384);
+ /*
+ *API inconsistency BUG HERE
+ * in order to be consistant with the other isc_hash_final
+ * functions the call should be
+ * isc_sha224_final(&sha224, digest);
+ */
+ tohexstr(digest, ISC_SHA384_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+ATF_TC(isc_sha512);
+ATF_TC_HEAD(isc_sha512, tc) {
+ atf_tc_set_md_var(tc, "descr", "sha224 examples from RFC4634");
+}
+ATF_TC_BODY(isc_sha512, tc) {
+ isc_sha512_t sha512;
+ int i;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("abc"),
+ "0xDDAF35A193617ABACC417349AE20413112E6FA4E89A97E"
+ "A20A9EEEE64B55D39A2192992A274FC1A836BA3C"
+ "23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("abcdefghbcdefghicdefghijdefghijkefghijkl"
+ "fghijklmghijklmnhijklmnoijklmnopjklmnopq"
+ "klmnopqrlmnopqrsmnopqrstnopqrstu"),
+ "0x8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7F"
+ "A17299AEADB6889018501D289E4900F7E4331B99"
+ "DEC4B5433AC7D329EEB6DD26545E96E55B874BE909",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("a"),
+ "0xE718483D0CE769644E2E42C7BC15B4638E1F98B13B2044"
+ "285632A803AFA973EBDE0FF244877EA60A4CB043"
+ "2CE577C31BEB009C5C2C49AA2E4EADB217AD8CC09B",
+ 1000000
+ },
+ /* Test 4 */
+ {
+ TEST_INPUT("01234567012345670123456701234567"),
+ "0x89D05BA632C699C31231DED4FFC127D5A894DAD412C0E0"
+ "24DB872D1ABD2BA8141A0F85072A9BE1E2AA04CF"
+ "33C765CB510813A39CD5A84C4ACAA64D3F3FB7BAE9",
+ 20
+ },
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 6 */
+ {
+ TEST_INPUT("\xD0"),
+ "0x9992202938E882E73E20F6B69E68A0A7149090423D93C8"
+ "1BAB3F21678D4ACEEEE50E4E8CAFADA4C85A54EA"
+ "8306826C4AD6E74CECE9631BFA8A549B4AB3FBBA15",
+ 1
+ },
+#if 0
+ /* Test 7 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 8 */
+ {
+ TEST_INPUT("\x8d\x4e\x3c\x0e\x38\x89\x19\x14\x91\x81"
+ "\x6e\x9d\x98\xbf\xf0\xa0"),
+ "0xCB0B67A4B8712CD73C9AABC0B199E9269B20844AFB75AC"
+ "BDD1C153C9828924C3DDEDAAFE669C5FDD0BC66F"
+ "630F6773988213EB1B16F517AD0DE4B2F0C95C90F8",
+ 1
+ },
+#if 0
+ /* Test 9 -- unimplemented optional functionality */
+ {
+ TEST_INPUT(""),
+ "0xXXX",
+ 1
+ },
+#endif
+ /* Test 10 */
+ {
+ TEST_INPUT("\xa5\x5f\x20\xc4\x11\xaa\xd1\x32\x80\x7a"
+ "\x50\x2d\x65\x82\x4e\x31\xa2\x30\x54\x32"
+ "\xaa\x3d\x06\xd3\xe2\x82\xa8\xd8\x4e\x0d"
+ "\xe1\xde\x69\x74\xbf\x49\x54\x69\xfc\x7f"
+ "\x33\x8f\x80\x54\xd5\x8c\x26\xc4\x93\x60"
+ "\xc3\xe8\x7a\xf5\x65\x23\xac\xf6\xd8\x9d"
+ "\x03\xe5\x6f\xf2\xf8\x68\x00\x2b\xc3\xe4"
+ "\x31\xed\xc4\x4d\xf2\xf0\x22\x3d\x4b\xb3"
+ "\xb2\x43\x58\x6e\x1a\x7d\x92\x49\x36\x69"
+ "\x4f\xcb\xba\xf8\x8d\x95\x19\xe4\xeb\x50"
+ "\xa6\x44\xf8\xe4\xf9\x5e\xb0\xea\x95\xbc"
+ "\x44\x65\xc8\x82\x1a\xac\xd2\xfe\x15\xab"
+ "\x49\x81\x16\x4b\xbb\x6d\xc3\x2f\x96\x90"
+ "\x87\xa1\x45\xb0\xd9\xcc\x9c\x67\xc2\x2b"
+ "\x76\x32\x99\x41\x9c\xc4\x12\x8b\xe9\xa0"
+ "\x77\xb3\xac\xe6\x34\x06\x4e\x6d\x99\x28"
+ "\x35\x13\xdc\x06\xe7\x51\x5d\x0d\x73\x13"
+ "\x2e\x9a\x0d\xc6\xd3\xb1\xf8\xb2\x46\xf1"
+ "\xa9\x8a\x3f\xc7\x29\x41\xb1\xe3\xbb\x20"
+ "\x98\xe8\xbf\x16\xf2\x68\xd6\x4f\x0b\x0f"
+ "\x47\x07\xfe\x1e\xa1\xa1\x79\x1b\xa2\xf3"
+ "\xc0\xc7\x58\xe5\xf5\x51\x86\x3a\x96\xc9"
+ "\x49\xad\x47\xd7\xfb\x40\xd2"),
+ "0xC665BEFB36DA189D78822D10528CBF3B12B3EEF7260399"
+ "09C1A16A270D48719377966B957A878E72058477"
+ "9A62825C18DA26415E49A7176A894E7510FD1451F5",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ isc_sha512_init(&sha512);
+ for(i = 0; i < testcase->repeats; i++) {
+ isc_sha512_update(&sha512,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ }
+ isc_sha512_final(digest, &sha512);
+ /*
+ *API inconsistency BUG HERE
+ * in order to be consistant with the other isc_hash_final
+ * functions the call should be
+ * isc_sha224_final(&sha224, digest);
+ */
+ tohexstr(digest, ISC_SHA512_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+#ifndef PK11_MD5_DISABLE
+ATF_TC(isc_md5);
+ATF_TC_HEAD(isc_md5, tc) {
+ atf_tc_set_md_var(tc, "descr", "md5 example from RFC1321");
+}
+ATF_TC_BODY(isc_md5, tc) {
+ isc_md5_t md5;
+ int i;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ {
+ TEST_INPUT(""),
+ "0xD41D8CD98F00B204E9800998ECF8427E",
+ 1
+ },
+ {
+ TEST_INPUT("a"),
+ "0x0CC175B9C0F1B6A831C399E269772661",
+ 1
+ },
+ {
+ TEST_INPUT("abc"),
+ "0x900150983CD24FB0D6963F7D28E17F72",
+ 1
+ },
+ {
+ TEST_INPUT("message digest"),
+ "0xF96B697D7CB7938D525A2F31AAF161D0",
+ 1
+ },
+ {
+ TEST_INPUT("abcdefghijklmnopqrstuvwxyz"),
+ "0xC3FCD3D76192E4007DFB496CCA67E13B",
+ 1
+ },
+ {
+ TEST_INPUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm"
+ "nopqrstuvwxyz0123456789"),
+ "0xD174AB98D277D9F5A5611C2C9F419D9F",
+ 1
+ },
+ {
+ TEST_INPUT("123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890"),
+ "0x57EDF4A22BE3C955AC49DA2E2107B67A",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ isc_md5_init(&md5);
+ for(i = 0; i < testcase->repeats; i++) {
+ isc_md5_update(&md5,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ }
+ isc_md5_final(&md5, digest);
+ tohexstr(digest, ISC_MD5_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+}
+#endif
+
+/* HMAC-SHA1 test */
+ATF_TC(isc_hmacsha1);
+ATF_TC_HEAD(isc_hmacsha1, tc) {
+ atf_tc_set_md_var(tc, "descr", "HMAC-SHA1 examples from RFC2104");
+}
+ATF_TC_BODY(isc_hmacsha1, tc) {
+ isc_hmacsha1_t hmacsha1;
+
+ UNUSED(tc);
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "0xB617318655057264E28BC0B6FB378C8EF146BE00",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61"
+ "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20"
+ "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "0xEFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "0x125D7342B9AC11CD91A39AF48AA17B4F63F175D3",
+ 1
+ },
+ /* Test 4 */
+ {
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "0x4C9007F4026250C6BC8414F9BF50C86C2D7235DA",
+ 1
+ },
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ {
+ TEST_INPUT("Test With Truncation"),
+ "0x4C1A03424B55E07FE7F27BE1",
+ 1
+ },
+#endif
+ /* Test 6 */
+ {
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "0xAA4AE5E15272D00E95705637CE8A3B55ED402112", 1 },
+ /* Test 7 */
+ {
+ TEST_INPUT("Test Using Larger Than Block-Size Key and "
+ "Larger Than One Block-Size Data"),
+ "0xE8E99D0F45237D786D6BBAA7965C7808BBFF1A91",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ hash_test_key_t test_keys[] = {
+ /* Key 1 */
+ { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20 },
+ /* Key 2 */
+ { "Jefe", 4 },
+ /* Key 3 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20 },
+ /* Key 4 */
+ { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19", 25 },
+#if 0
+ /* Key 5 */
+ { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 },
+#endif
+ /* Key 6 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 80 },
+ /* Key 7 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 80 },
+ { "", 0 }
+ };
+
+ hash_test_key_t *test_key = test_keys;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ memmove(buffer, test_key->key, test_key->len);
+ isc_hmacsha1_init(&hmacsha1, buffer, test_key->len);
+ isc_hmacsha1_update(&hmacsha1,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ isc_hmacsha1_sign(&hmacsha1, digest, ISC_SHA1_DIGESTLENGTH);
+ tohexstr(digest, ISC_SHA1_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ test_key++;
+ }
+}
+
+/* HMAC-SHA224 test */
+ATF_TC(isc_hmacsha224);
+ATF_TC_HEAD(isc_hmacsha224, tc) {
+ atf_tc_set_md_var(tc, "descr", "HMAC-SHA224 examples from RFC4634");
+}
+ATF_TC_BODY(isc_hmacsha224, tc) {
+ isc_hmacsha224_t hmacsha224;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "0x896FB1128ABBDF196832107CD49DF33F47B4B1169912BA"
+ "4F53684B22",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61"
+ "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20"
+ "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "0xA30E01098BC6DBBF45690F3A7E9E6D0F8BBEA2A39E61480"
+ "08FD05E44",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "0x7FB3CB3588C6C1F6FFA9694D7D6AD2649365B0C1F65D69"
+ "D1EC8333EA",
+ 1
+ },
+ /* Test 4 */
+ {
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "0x6C11506874013CAC6A2ABC1BB382627CEC6A90D86EFC01"
+ "2DE7AFEC5A",
+ 1
+ },
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ {
+ TEST_INPUT("Test With Truncation"),
+ "0x4C1A03424B55E07FE7F27BE1",
+ 1
+ },
+#endif
+ /* Test 6 */
+ {
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "0x95E9A0DB962095ADAEBE9B2D6F0DBCE2D499F112F2D2B7"
+ "273FA6870E",
+ 1
+ },
+ /* Test 7 */
+ {
+ TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20"
+ "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67"
+ "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b"
+ "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20"
+ "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67"
+ "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c"
+ "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64"
+ "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b"
+ "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74"
+ "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65"
+ "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62"
+ "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20"
+ "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41"
+ "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68"
+ "\x6d\x2e"),
+ "0x3A854166AC5D9F023F54D517D0B39DBD946770DB9C2B95"
+ "C9F6F565D1",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ hash_test_key_t test_keys[] = {
+ /* Key 1 */
+ { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20 },
+ /* Key 2 */
+ { "Jefe", 4 },
+ /* Key 3 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20 },
+ /* Key 4 */
+ { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19", 25 },
+#if 0
+ /* Key 5 */
+ { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 },
+#endif
+ /* Key 6 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 },
+ /* Key 7 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 },
+ { "", 0 }
+ };
+
+ hash_test_key_t *test_key = test_keys;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ memmove(buffer, test_key->key, test_key->len);
+ isc_hmacsha224_init(&hmacsha224, buffer, test_key->len);
+ isc_hmacsha224_update(&hmacsha224,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ isc_hmacsha224_sign(&hmacsha224, digest, ISC_SHA224_DIGESTLENGTH);
+ tohexstr(digest, ISC_SHA224_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ test_key++;
+ }
+}
+
+/* HMAC-SHA256 test */
+ATF_TC(isc_hmacsha256);
+ATF_TC_HEAD(isc_hmacsha256, tc) {
+ atf_tc_set_md_var(tc, "descr", "HMAC-SHA256 examples from RFC4634");
+}
+ATF_TC_BODY(isc_hmacsha256, tc) {
+ isc_hmacsha256_t hmacsha256;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "0xB0344C61D8DB38535CA8AFCEAF0BF12B881DC200C9833D"
+ "A726E9376C2E32CFF7",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61"
+ "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20"
+ "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "0x5BDCC146BF60754E6A042426089575C75A003F089D2739"
+ "839DEC58B964EC3843",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "0x773EA91E36800E46854DB8EBD09181A72959098B3EF8C1"
+ "22D9635514CED565FE",
+ 1
+ },
+ /* Test 4 */
+ {
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "0x82558A389A443C0EA4CC819899F2083A85F0FAA3E578F8"
+ "077A2E3FF46729665B",
+ 1
+ },
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ {
+ TEST_INPUT("Test With Truncation"),
+ "0x4C1A03424B55E07FE7F27BE1",
+ 1
+ },
+#endif
+ /* Test 6 */
+ {
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "0x60E431591EE0B67F0D8A26AACBF5B77F8E0BC6213728C5"
+ "140546040F0EE37F54",
+ 1
+ },
+ /* Test 7 */
+ {
+ TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20"
+ "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67"
+ "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b"
+ "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20"
+ "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67"
+ "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c"
+ "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64"
+ "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b"
+ "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74"
+ "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65"
+ "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62"
+ "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20"
+ "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41"
+ "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68"
+ "\x6d\x2e"),
+ "0x9B09FFA71B942FCB27635FBCD5B0E944BFDC63644F0713"
+ "938A7F51535C3A35E2",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ hash_test_key_t test_keys[] = {
+ /* Key 1 */
+ { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20 },
+ /* Key 2 */
+ { "Jefe", 4 },
+ /* Key 3 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20 },
+ /* Key 4 */
+ { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19", 25 },
+#if 0
+ /* Key 5 */
+ { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 },
+#endif
+ /* Key 6 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 },
+ /* Key 7 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 },
+ { "", 0 }
+ };
+
+ hash_test_key_t *test_key = test_keys;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ memmove(buffer, test_key->key, test_key->len);
+ isc_hmacsha256_init(&hmacsha256, buffer, test_key->len);
+ isc_hmacsha256_update(&hmacsha256,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ isc_hmacsha256_sign(&hmacsha256, digest, ISC_SHA256_DIGESTLENGTH);
+ tohexstr(digest, ISC_SHA256_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ test_key++;
+ }
+}
+
+/* HMAC-SHA384 test */
+ATF_TC(isc_hmacsha384);
+ATF_TC_HEAD(isc_hmacsha384, tc) {
+ atf_tc_set_md_var(tc, "descr", "HMAC-SHA384 examples from RFC4634");
+}
+ATF_TC_BODY(isc_hmacsha384, tc) {
+ isc_hmacsha384_t hmacsha384;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "0xAFD03944D84895626B0825F4AB46907F15F9DADBE4101E"
+ "C682AA034C7CEBC59CFAEA9EA9076EDE7F4AF152"
+ "E8B2FA9CB6",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61"
+ "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20"
+ "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "0xAF45D2E376484031617F78D2B58A6B1B9C7EF464F5A01B"
+ "47E42EC3736322445E8E2240CA5E69E2C78B3239"
+ "ECFAB21649",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "0x88062608D3E6AD8A0AA2ACE014C8A86F0AA635D947AC9F"
+ "EBE83EF4E55966144B2A5AB39DC13814B94E3AB6"
+ "E101A34F27",
+ 1
+ },
+ /* Test 4 */
+ {
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "0x3E8A69B7783C25851933AB6290AF6CA77A998148085000"
+ "9CC5577C6E1F573B4E6801DD23C4A7D679CCF8A3"
+ "86C674CFFB",
+ 1
+ },
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ {
+ TEST_INPUT("Test With Truncation"),
+ "0x4C1A03424B55E07FE7F27BE1",
+ 1
+ },
+#endif
+ /* Test 6 */
+ {
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "0x4ECE084485813E9088D2C63A041BC5B44F9EF1012A2B58"
+ "8F3CD11F05033AC4C60C2EF6AB4030FE8296248D"
+ "F163F44952",
+ 1
+ },
+ /* Test 7 */
+ {
+ TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20"
+ "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67"
+ "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b"
+ "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20"
+ "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67"
+ "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c"
+ "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64"
+ "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b"
+ "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74"
+ "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65"
+ "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62"
+ "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20"
+ "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41"
+ "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68"
+ "\x6d\x2e"),
+ "0x6617178E941F020D351E2F254E8FD32C602420FEB0B8FB"
+ "9ADCCEBB82461E99C5A678CC31E799176D3860E6"
+ "110C46523E",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ hash_test_key_t test_keys[] = {
+ /* Key 1 */
+ { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20 },
+ /* Key 2 */
+ { "Jefe", 4 },
+ /* Key 3 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20 },
+ /* Key 4 */
+ { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19", 25 },
+#if 0
+ /* Key 5 */
+ { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 },
+#endif
+ /* Key 6 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 },
+ /* Key 7 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 },
+ { "", 0 }
+ };
+
+ hash_test_key_t *test_key = test_keys;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ memmove(buffer, test_key->key, test_key->len);
+ isc_hmacsha384_init(&hmacsha384, buffer, test_key->len);
+ isc_hmacsha384_update(&hmacsha384,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ isc_hmacsha384_sign(&hmacsha384, digest, ISC_SHA384_DIGESTLENGTH);
+ tohexstr(digest, ISC_SHA384_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ test_key++;
+ }
+}
+
+/* HMAC-SHA512 test */
+ATF_TC(isc_hmacsha512);
+ATF_TC_HEAD(isc_hmacsha512, tc) {
+ atf_tc_set_md_var(tc, "descr", "HMAC-SHA512 examples from RFC4634");
+}
+ATF_TC_BODY(isc_hmacsha512, tc) {
+ isc_hmacsha512_t hmacsha512;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "0x87AA7CDEA5EF619D4FF0B4241A1D6CB02379F4E2CE4EC2"
+ "787AD0B30545E17CDEDAA833B7D6B8A702038B27"
+ "4EAEA3F4E4BE9D914EEB61F1702E696C203A126854",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61"
+ "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20"
+ "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "0x164B7A7BFCF819E2E395FBE73B56E0A387BD64222E831F"
+ "D610270CD7EA2505549758BF75C05A994A6D034F"
+ "65F8F0E6FDCAEAB1A34D4A6B4B636E070A38BCE737",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "0xFA73B0089D56A284EFB0F0756C890BE9B1B5DBDD8EE81A"
+ "3655F83E33B2279D39BF3E848279A722C806B485"
+ "A47E67C807B946A337BEE8942674278859E13292FB",
+ 1
+ },
+ /* Test 4 */
+ {
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "0xB0BA465637458C6990E5A8C5F61D4AF7E576D97FF94B87"
+ "2DE76F8050361EE3DBA91CA5C11AA25EB4D67927"
+ "5CC5788063A5F19741120C4F2DE2ADEBEB10A298DD",
+ 1
+ },
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ {
+ TEST_INPUT("Test With Truncation"),
+ "0x4C1A03424B55E07FE7F27BE1",
+ 1
+ },
+#endif
+ /* Test 6 */
+ {
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "0x80B24263C7C1A3EBB71493C1DD7BE8B49B46D1F41B4AEE"
+ "C1121B013783F8F3526B56D037E05F2598BD0FD2"
+ "215D6A1E5295E64F73F63F0AEC8B915A985D786598",
+ 1
+ },
+ /* Test 7 */
+ {
+ TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20"
+ "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67"
+ "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b"
+ "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20"
+ "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67"
+ "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c"
+ "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64"
+ "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b"
+ "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74"
+ "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65"
+ "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62"
+ "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20"
+ "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41"
+ "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68"
+ "\x6d\x2e"),
+ "0xE37B6A775DC87DBAA4DFA9F96E5E3FFDDEBD71F8867289"
+ "865DF5A32D20CDC944B6022CAC3C4982B10D5EEB"
+ "55C3E4DE15134676FB6DE0446065C97440FA8C6A58",
+ 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ hash_test_key_t test_keys[] = {
+ /* Key 1 */
+ { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20 },
+ /* Key 2 */
+ { "Jefe", 4 },
+ /* Key 3 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20 },
+ /* Key 4 */
+ { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19", 25 },
+#if 0
+ /* Key 5 */
+ { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 },
+#endif
+ /* Key 6 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 },
+ /* Key 7 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 },
+ { "", 0 }
+ };
+
+ hash_test_key_t *test_key = test_keys;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ memmove(buffer, test_key->key, test_key->len);
+ isc_hmacsha512_init(&hmacsha512, buffer, test_key->len);
+ isc_hmacsha512_update(&hmacsha512,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ isc_hmacsha512_sign(&hmacsha512, digest, ISC_SHA512_DIGESTLENGTH);
+ tohexstr(digest, ISC_SHA512_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ test_key++;
+ }
+}
+
+
+#ifndef PK11_MD5_DISABLE
+/* HMAC-MD5 Test */
+ATF_TC(isc_hmacmd5);
+ATF_TC_HEAD(isc_hmacmd5, tc) {
+ atf_tc_set_md_var(tc, "descr", "HMAC-MD5 examples from RFC2104");
+}
+ATF_TC_BODY(isc_hmacmd5, tc) {
+ isc_hmacmd5_t hmacmd5;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"),
+ "0x9294727A3638BB1C13F48EF8158BFC9D",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79"
+ "\x61\x20\x77\x61\x6e\x74\x20\x66\x6f"
+ "\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f"),
+ "0x750C783E6AB0B503EAA86E310A5DB738", 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"),
+ "0x56BE34521D144C88DBB8C733F0E8B3F6",
+ 1
+ },
+ /* Test 4 */
+ {
+ TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
+ "0x697EAF0ACA3A3AEA3A75164746FFAA79",
+ 1
+ },
+#if 0
+ /* Test 5 -- unimplemented optional functionality */
+ {
+ TEST_INPUT("Test With Truncation"),
+ "0x4C1A03424B55E07FE7F27BE1",
+ 1
+ },
+ /* Test 6 -- unimplemented optional functionality */
+ {
+ TEST_INPUT("Test Using Larger Than Block-Size Key - "
+ "Hash Key First"),
+ "0xAA4AE5E15272D00E95705637CE8A3B55ED402112",
+ 1
+ },
+ /* Test 7 -- unimplemented optional functionality */
+ {
+ TEST_INPUT("Test Using Larger Than Block-Size Key and "
+ "Larger Than One Block-Size Data"),
+ "0xE8E99D0F45237D786D6BBAA7965C7808BBFF1A91",
+ 1
+ },
+#endif
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ hash_test_key_t test_keys[] = {
+ /* Key 1 */
+ { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b", 16 },
+ /* Key 2 */
+ { "Jefe", 4 },
+ /* Key 3 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa", 16 },
+ /* Key 4 */
+ { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19", 25 },
+#if 0
+ /* Key 5 */
+ { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
+ "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 },
+ /* Key 6 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 },
+ /* Key 7 */
+ { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 },
+#endif
+ { "", 0 }
+ };
+
+ hash_test_key_t *test_key = test_keys;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ memmove(buffer, test_key->key, test_key->len);
+ isc_hmacmd5_init(&hmacmd5, buffer, test_key->len);
+ isc_hmacmd5_update(&hmacmd5,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ isc_hmacmd5_sign(&hmacmd5, digest);
+ tohexstr(digest, ISC_MD5_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ test_key++;
+ }
+}
+#endif
+
+/* CRC64 Test */
+ATF_TC(isc_crc64);
+ATF_TC_HEAD(isc_crc64, tc) {
+ atf_tc_set_md_var(tc, "descr", "64-bit cyclic redundancy check");
+}
+ATF_TC_BODY(isc_crc64, tc) {
+ uint64_t crc;
+ int i;
+
+ UNUSED(tc);
+
+ hash_testcase_t testcases[] = {
+ {
+ TEST_INPUT(""),
+ "0x0000000000000000", 1
+ },
+ {
+ TEST_INPUT("a"),
+ "0xCE73F427ACC0A99A", 1
+ },
+ {
+ TEST_INPUT("abc"),
+ "0x048B813AF9F49702", 1
+ },
+ {
+ TEST_INPUT("message digest"),
+ "0x5273F9EA7A357BF4", 1
+ },
+ {
+ TEST_INPUT("abcdefghijklmnopqrstuvwxyz"),
+ "0x59F079F9218BAAA1", 1
+ },
+ {
+ TEST_INPUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm"
+ "nopqrstuvwxyz0123456789"),
+ "0xA36DA8F71E78B6FB", 1
+ },
+ {
+ TEST_INPUT("123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890"),
+ "0x81E5EB73C8E7874A", 1
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ hash_testcase_t *testcase = testcases;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ isc_crc64_init(&crc);
+ for(i = 0; i < testcase->repeats; i++) {
+ isc_crc64_update(&crc,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ }
+ isc_crc64_final(&crc);
+ snprintf(str, sizeof(str),
+ "0x%016" PRIX64, crc);
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+}
+
+ATF_TC(isc_hash_function);
+ATF_TC_HEAD(isc_hash_function, tc) {
+ atf_tc_set_md_var(tc, "descr", "Hash function test");
+}
+ATF_TC_BODY(isc_hash_function, tc) {
+ unsigned int h1;
+ unsigned int h2;
+
+ UNUSED(tc);
+
+ /* Incremental hashing */
+
+ h1 = isc_hash_function(NULL, 0, true, NULL);
+ h1 = isc_hash_function("This ", 5, true, &h1);
+ h1 = isc_hash_function("is ", 3, true, &h1);
+ h1 = isc_hash_function("a long test", 12, true, &h1);
+
+ h2 = isc_hash_function("This is a long test", 20,
+ true, NULL);
+
+ ATF_CHECK_EQ(h1, h2);
+
+ /* Immutability of hash function */
+ h1 = isc_hash_function(NULL, 0, true, NULL);
+ h2 = isc_hash_function(NULL, 0, true, NULL);
+
+ ATF_CHECK_EQ(h1, h2);
+
+ /* Hash function characteristics */
+ h1 = isc_hash_function("Hello world", 12, true, NULL);
+ h2 = isc_hash_function("Hello world", 12, true, NULL);
+
+ ATF_CHECK_EQ(h1, h2);
+
+ /* Case */
+ h1 = isc_hash_function("Hello world", 12, false, NULL);
+ h2 = isc_hash_function("heLLo WorLd", 12, false, NULL);
+
+ ATF_CHECK_EQ(h1, h2);
+
+ /* Unequal */
+ h1 = isc_hash_function("Hello world", 12, true, NULL);
+ h2 = isc_hash_function("heLLo WorLd", 12, true, NULL);
+
+ ATF_CHECK(h1 != h2);
+}
+
+ATF_TC(isc_hash_function_reverse);
+ATF_TC_HEAD(isc_hash_function_reverse, tc) {
+ atf_tc_set_md_var(tc, "descr", "Reverse hash function test");
+}
+ATF_TC_BODY(isc_hash_function_reverse, tc) {
+ unsigned int h1;
+ unsigned int h2;
+
+ UNUSED(tc);
+
+ /* Incremental hashing */
+
+ h1 = isc_hash_function_reverse(NULL, 0, true, NULL);
+ h1 = isc_hash_function_reverse("\000", 1, true, &h1);
+ h1 = isc_hash_function_reverse("\003org", 4, true, &h1);
+ h1 = isc_hash_function_reverse("\007example", 8, true, &h1);
+
+ h2 = isc_hash_function_reverse("\007example\003org\000", 13,
+ true, NULL);
+
+ ATF_CHECK_EQ(h1, h2);
+
+ /* Immutability of hash function */
+ h1 = isc_hash_function_reverse(NULL, 0, true, NULL);
+ h2 = isc_hash_function_reverse(NULL, 0, true, NULL);
+
+ ATF_CHECK_EQ(h1, h2);
+
+ /* Hash function characteristics */
+ h1 = isc_hash_function_reverse("Hello world", 12, true, NULL);
+ h2 = isc_hash_function_reverse("Hello world", 12, true, NULL);
+
+ ATF_CHECK_EQ(h1, h2);
+
+ /* Case */
+ h1 = isc_hash_function_reverse("Hello world", 12, false, NULL);
+ h2 = isc_hash_function_reverse("heLLo WorLd", 12, false, NULL);
+
+ ATF_CHECK_EQ(h1, h2);
+
+ /* Unequal */
+ h1 = isc_hash_function_reverse("Hello world", 12, true, NULL);
+ h2 = isc_hash_function_reverse("heLLo WorLd", 12, true, NULL);
+
+ ATF_CHECK(h1 != h2);
+}
+
+ATF_TC(isc_hash_initializer);
+ATF_TC_HEAD(isc_hash_initializer, tc) {
+ atf_tc_set_md_var(tc, "descr", "Hash function initializer test");
+}
+ATF_TC_BODY(isc_hash_initializer, tc) {
+ unsigned int h1;
+ unsigned int h2;
+
+ UNUSED(tc);
+
+ h1 = isc_hash_function("Hello world", 12, true, NULL);
+ h2 = isc_hash_function("Hello world", 12, true, NULL);
+
+ ATF_CHECK_EQ(h1, h2);
+
+ isc_hash_set_initializer(isc_hash_get_initializer());
+
+ /* Hash value must not change */
+ h2 = isc_hash_function("Hello world", 12, true, NULL);
+
+ ATF_CHECK_EQ(h1, h2);
+}
+
+#ifndef PK11_MD5_DISABLE
+ATF_TC(md5_check);
+ATF_TC_HEAD(md5_check, tc) {
+ atf_tc_set_md_var(tc, "descr", "Startup MD5 check test");
+}
+ATF_TC_BODY(md5_check, tc) {
+ UNUSED(tc);
+
+ ATF_REQUIRE(isc_md5_check(false));
+ ATF_CHECK(!isc_md5_check(true));
+
+ ATF_REQUIRE(isc_hmacmd5_check(0));
+ ATF_CHECK(!isc_hmacmd5_check(1));
+ ATF_CHECK(!isc_hmacmd5_check(2));
+ ATF_CHECK(!isc_hmacmd5_check(3));
+ ATF_CHECK(!isc_hmacmd5_check(4));
+}
+#endif
+
+ATF_TC(sha1_check);
+ATF_TC_HEAD(sha1_check, tc) {
+ atf_tc_set_md_var(tc, "descr", "Startup SHA-1 check test");
+}
+ATF_TC_BODY(sha1_check, tc) {
+ UNUSED(tc);
+
+ ATF_REQUIRE(isc_sha1_check(false));
+ ATF_CHECK(!isc_sha1_check(true));
+
+ ATF_REQUIRE(isc_hmacsha1_check(0));
+ ATF_CHECK(!isc_hmacsha1_check(1));
+ ATF_CHECK(!isc_hmacsha1_check(2));
+ ATF_CHECK(!isc_hmacsha1_check(3));
+ ATF_CHECK(!isc_hmacsha1_check(4));
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ /*
+ * Tests of hash functions, including isc_hash and the
+ * various cryptographic hashes.
+ */
+#ifndef PK11_MD5_DISABLE
+ ATF_TP_ADD_TC(tp, md5_check);
+#endif
+ ATF_TP_ADD_TC(tp, sha1_check);
+
+ ATF_TP_ADD_TC(tp, isc_hash_function);
+ ATF_TP_ADD_TC(tp, isc_hash_function_reverse);
+ ATF_TP_ADD_TC(tp, isc_hash_initializer);
+#ifndef PK11_MD5_DISABLE
+ ATF_TP_ADD_TC(tp, isc_hmacmd5);
+#endif
+ ATF_TP_ADD_TC(tp, isc_hmacsha1);
+ ATF_TP_ADD_TC(tp, isc_hmacsha224);
+ ATF_TP_ADD_TC(tp, isc_hmacsha256);
+ ATF_TP_ADD_TC(tp, isc_hmacsha384);
+ ATF_TP_ADD_TC(tp, isc_hmacsha512);
+#ifndef PK11_MD5_DISABLE
+ ATF_TP_ADD_TC(tp, isc_md5);
+#endif
+ ATF_TP_ADD_TC(tp, isc_sha1);
+ ATF_TP_ADD_TC(tp, isc_sha224);
+ ATF_TP_ADD_TC(tp, isc_sha256);
+ ATF_TP_ADD_TC(tp, isc_sha384);
+ ATF_TP_ADD_TC(tp, isc_sha512);
+ ATF_TP_ADD_TC(tp, isc_crc64);
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/heap_test.c b/lib/isc/tests/heap_test.c
new file mode 100644
index 0000000..c030573
--- /dev/null
+++ b/lib/isc/tests/heap_test.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* ! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <atf-c.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/heap.h>
+#include <isc/mem.h>
+
+#include <isc/util.h>
+
+struct e {
+ unsigned int value;
+ unsigned int index;
+};
+
+static bool
+compare(void *p1, void *p2) {
+ struct e *e1 = p1;
+ struct e *e2 = p2;
+
+ return (e1->value < e2->value);
+}
+
+static void
+idx(void *p, unsigned int i) {
+ struct e *e = p;
+
+ e->index = i;
+}
+
+ATF_TC(isc_heap_delete);
+ATF_TC_HEAD(isc_heap_delete, tc) {
+ atf_tc_set_md_var(tc, "descr", "test isc_heap_delete");
+}
+ATF_TC_BODY(isc_heap_delete, tc) {
+ isc_mem_t *mctx = NULL;
+ isc_heap_t *heap = NULL;
+ isc_result_t result;
+ struct e e1 = { 100, 0 };
+
+ UNUSED(tc);
+
+ result = isc_mem_create(0, 0, &mctx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_heap_create(mctx, compare, idx, 0, &heap);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE(heap != NULL);
+
+ isc_heap_insert(heap, &e1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(e1.index, 1);
+
+ isc_heap_delete(heap, e1.index);
+ ATF_CHECK_EQ(e1.index, 0);
+
+ isc_heap_destroy(&heap);
+ ATF_REQUIRE_EQ(heap, NULL);
+
+ isc_mem_detach(&mctx);
+ ATF_REQUIRE_EQ(mctx, NULL);
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_heap_delete);
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/ht_test.c b/lib/isc/tests/ht_test.c
new file mode 100644
index 0000000..5356142
--- /dev/null
+++ b/lib/isc/tests/ht_test.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* ! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <isc/hash.h>
+#include <isc/ht.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+static void *
+default_memalloc(void *arg, size_t size) {
+ UNUSED(arg);
+ if (size == 0U)
+ size = 1;
+ return (malloc(size));
+}
+
+static void
+default_memfree(void *arg, void *ptr) {
+ UNUSED(arg);
+ free(ptr);
+}
+
+static void test_ht_full(int bits, uintptr_t count) {
+ isc_ht_t *ht = NULL;
+ isc_result_t result;
+ isc_mem_t *mctx = NULL;
+ uintptr_t i;
+
+ result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
+ NULL, &mctx, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_ht_init(&ht, mctx, bits);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE(ht != NULL);
+
+ for (i = 1; i < count; i++) {
+ /*
+ * Note: snprintf() is followed with strlcat()
+ * to ensure we are always filling the 16 byte key.
+ */
+ unsigned char key[16];
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_add(ht, key, 16, (void *) i);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ void *f = NULL;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_find(ht, key, 16, &f);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(i, (uintptr_t) f);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_add(ht, key, 16, (void *) i);
+ ATF_REQUIRE_EQ(result, ISC_R_EXISTS);
+ }
+
+ for (i = 1; i < count; i++) {
+ char key[64];
+ /*
+ * Note: the key size is now strlen(key) which is bigger
+ * then the keys added above.
+ */
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_add(ht, (const unsigned char *) key,
+ strlen(key), (void *) i);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ void *f = NULL;
+ /*
+ * Note: case of KEY is now in capitals,
+ */
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " KEY of a raw hashtable!!", sizeof(key));
+ result = isc_ht_find(ht, key, 16, &f);
+ ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(f, NULL);
+ }
+
+ for (i = 1; i < count; i++) {
+ char key[64];
+ void *f = NULL;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_find(ht, (const unsigned char *) key,
+ strlen(key), &f);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(f, (void *) i);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ void *f = NULL;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_delete(ht, key, 16);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_ht_find(ht, key, 16, &f);
+ ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(f, NULL);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ /*
+ * Note: upper case KEY.
+ */
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " KEY of a raw hashtable!!", sizeof(key));
+ result = isc_ht_add(ht, key, 16, (void *) i);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ }
+
+ for (i = 1; i < count; i++) {
+ char key[64];
+ void *f = NULL;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_delete(ht, (const unsigned char *) key,
+ strlen(key));
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_ht_find(ht, (const unsigned char *) key,
+ strlen(key), &f);
+ ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(f, NULL);
+ }
+
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ void *f = NULL;
+ /*
+ * Note: case of KEY is now in capitals,
+ */
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " KEY of a raw hashtable!!", sizeof(key));
+ result = isc_ht_find(ht, key, 16, &f);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(i, (uintptr_t) f);
+ }
+
+ for (i = 1; i < count; i++) {
+ unsigned char key[16];
+ void *f = NULL;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_find(ht, key, 16, &f);
+ ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(f, NULL);
+ }
+
+ isc_ht_destroy(&ht);
+ ATF_REQUIRE_EQ(ht, NULL);
+}
+
+static void test_ht_iterator() {
+ isc_ht_t *ht = NULL;
+ isc_result_t result;
+ isc_mem_t *mctx = NULL;
+ isc_ht_iter_t * iter = NULL;
+ uintptr_t i;
+ void *v;
+ uintptr_t count = 10000;
+ uint32_t walked;
+ unsigned char key[16];
+ unsigned char *tkey;
+ size_t tksize;
+
+ result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
+ NULL, &mctx, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_ht_init(&ht, mctx, 16);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE(ht != NULL);
+ for (i = 1; i <= count; i++) {
+ /*
+ * Note that the string we're snprintfing is always > 16 bytes
+ * so we are always filling the key.
+ */
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
+ result = isc_ht_add(ht, key, 16, (void *) i);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ }
+
+ walked = 0;
+ result = isc_ht_iter_create(ht, &iter);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ for (result = isc_ht_iter_first(iter);
+ result == ISC_R_SUCCESS;
+ result = isc_ht_iter_next(iter))
+ {
+ isc_ht_iter_current(iter, &v);
+ isc_ht_iter_currentkey(iter, &tkey, &tksize);
+ ATF_REQUIRE_EQ(tksize, 16);
+ i = (uintptr_t)v;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
+ ATF_REQUIRE_EQ(memcmp(key, tkey, 16), 0);
+ walked++;
+ }
+ ATF_REQUIRE_EQ(walked, count);
+ ATF_REQUIRE_EQ(result, ISC_R_NOMORE);
+
+ /* erase odd */
+ walked = 0;
+ result = isc_ht_iter_first(iter);
+ while (result == ISC_R_SUCCESS) {
+ isc_ht_iter_current(iter, &v);
+ isc_ht_iter_currentkey(iter, &tkey, &tksize);
+ ATF_REQUIRE_EQ(tksize, 16);
+ i = (uintptr_t)v;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
+ ATF_REQUIRE_EQ(memcmp(key, tkey, 16), 0);
+ if ((uintptr_t)v % 2 == 0) {
+ result = isc_ht_iter_delcurrent_next(iter);
+ } else {
+ result = isc_ht_iter_next(iter);
+ }
+ walked++;
+ }
+ ATF_REQUIRE_EQ(result, ISC_R_NOMORE);
+ ATF_REQUIRE_EQ(walked, count);
+
+ /* erase even */
+ walked = 0;
+ result = isc_ht_iter_first(iter);
+ while (result == ISC_R_SUCCESS) {
+ isc_ht_iter_current(iter, &v);
+ isc_ht_iter_currentkey(iter, &tkey, &tksize);
+ ATF_REQUIRE_EQ(tksize, 16);
+ i = (uintptr_t)v;
+ snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
+ strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
+ ATF_REQUIRE_EQ(memcmp(key, tkey, 16), 0);
+ if ((uintptr_t)v % 2 == 1) {
+ result = isc_ht_iter_delcurrent_next(iter);
+ } else {
+ result = isc_ht_iter_next(iter);
+ }
+ walked++;
+ }
+ ATF_REQUIRE_EQ(result, ISC_R_NOMORE);
+ ATF_REQUIRE_EQ(walked, count/2);
+
+ walked = 0;
+ for (result = isc_ht_iter_first(iter);
+ result == ISC_R_SUCCESS;
+ result = isc_ht_iter_next(iter))
+ {
+ walked++;
+ }
+
+ ATF_REQUIRE_EQ(result, ISC_R_NOMORE);
+ ATF_REQUIRE_EQ(walked, 0);
+
+ isc_ht_destroy(&ht);
+ ATF_REQUIRE_EQ(ht, NULL);
+}
+
+ATF_TC(isc_ht_20);
+ATF_TC_HEAD(isc_ht_20, tc) {
+ atf_tc_set_md_var(tc, "descr", "20 bit, 200K elements test");
+}
+
+ATF_TC_BODY(isc_ht_20, tc) {
+ UNUSED(tc);
+ test_ht_full(20, 200000);
+}
+
+
+ATF_TC(isc_ht_8);
+ATF_TC_HEAD(isc_ht_8, tc) {
+ atf_tc_set_md_var(tc, "descr", "8 bit, 20000 elements crowded test");
+}
+
+ATF_TC_BODY(isc_ht_8, tc) {
+ UNUSED(tc);
+ test_ht_full(8, 20000);
+}
+
+ATF_TC(isc_ht_1);
+ATF_TC_HEAD(isc_ht_1, tc) {
+ atf_tc_set_md_var(tc, "descr", "1 bit, 100 elements corner case test");
+}
+
+ATF_TC_BODY(isc_ht_1, tc) {
+ UNUSED(tc);
+ test_ht_full(1, 100);
+}
+
+/* xxxwpk we should limit the size of hashtable, 32bit doesn't make sense */
+#if 0
+ATF_TC(isc_ht_32);
+ATF_TC_HEAD(isc_ht_32, tc) {
+ atf_tc_set_md_var(tc, "descr", "32 bit, 10000 elements corner case test");
+}
+
+ATF_TC_BODY(isc_ht_32, tc) {
+ UNUSED(tc);
+ test_ht_full(32, 10000);
+}
+#endif
+
+ATF_TC(isc_ht_iterator);
+ATF_TC_HEAD(isc_ht_iterator, tc) {
+ atf_tc_set_md_var(tc, "descr", "hashtable iterator");
+}
+
+ATF_TC_BODY(isc_ht_iterator, tc) {
+ UNUSED(tc);
+ test_ht_iterator();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_ht_20);
+ ATF_TP_ADD_TC(tp, isc_ht_8);
+ ATF_TP_ADD_TC(tp, isc_ht_1);
+/* ATF_TP_ADD_TC(tp, isc_ht_32); */
+ ATF_TP_ADD_TC(tp, isc_ht_iterator);
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/inet_ntop_test.c b/lib/isc/tests/inet_ntop_test.c
new file mode 100644
index 0000000..2bfe9de
--- /dev/null
+++ b/lib/isc/tests/inet_ntop_test.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+/*
+ * Force the prototype for isc_net_ntop to be declared.
+ */
+#include <isc/platform.h>
+#undef ISC_PLATFORM_NEEDNTOP
+#define ISC_PLATFORM_NEEDNTOP
+#include "../inet_ntop.c"
+
+ATF_TC(isc_net_ntop);
+ATF_TC_HEAD(isc_net_ntop, tc) {
+ atf_tc_set_md_var(tc, "descr", "isc_net_ntop implementation");
+}
+ATF_TC_BODY(isc_net_ntop, tc) {
+ char buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+ int r;
+ size_t i;
+ unsigned char abuf[16];
+ struct {
+ int family;
+ const char * address;
+ } testdata[] = {
+ { AF_INET, "0.0.0.0" },
+ { AF_INET, "0.1.0.0" },
+ { AF_INET, "0.0.2.0" },
+ { AF_INET, "0.0.0.3" },
+ { AF_INET, "255.255.255.255" },
+ { AF_INET6, "::" },
+ { AF_INET6, "::1.2.3.4" },
+ { AF_INET6, "::ffff:1.2.3.4" },
+ { AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" }
+ };
+
+ for (i = 0; i < sizeof(testdata)/sizeof(testdata[0]); i++) {
+ r = inet_pton(testdata[i].family, testdata[i].address, abuf);
+ ATF_REQUIRE_EQ_MSG(r, 1, "%s", testdata[i].address);
+ isc_net_ntop(testdata[i].family, abuf, buf, sizeof(buf));
+ ATF_CHECK_STREQ(buf, testdata[i].address);
+ }
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_net_ntop);
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/isctest.c b/lib/isc/tests/isctest.c
new file mode 100644
index 0000000..cf4ae97
--- /dev/null
+++ b/lib/isc/tests/isctest.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <isc/app.h>
+#include <isc/buffer.h>
+#include <isc/entropy.h>
+#include <isc/hash.h>
+#include <isc/mem.h>
+#include <isc/os.h>
+#include <isc/socket.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include "isctest.h"
+
+isc_mem_t *mctx = NULL;
+isc_entropy_t *ectx = NULL;
+isc_log_t *lctx = NULL;
+isc_taskmgr_t *taskmgr = NULL;
+isc_timermgr_t *timermgr = NULL;
+isc_socketmgr_t *socketmgr = NULL;
+isc_task_t *maintask = NULL;
+int ncpus;
+
+static bool hash_active = false;
+
+/*
+ * Logging categories: this needs to match the list in bin/named/log.c.
+ */
+static isc_logcategory_t categories[] = {
+ { "", 0 },
+ { "client", 0 },
+ { "network", 0 },
+ { "update", 0 },
+ { "queries", 0 },
+ { "unmatched", 0 },
+ { "update-security", 0 },
+ { "query-errors", 0 },
+ { NULL, 0 }
+};
+
+static void
+cleanup_managers(void) {
+ if (maintask != NULL)
+ isc_task_destroy(&maintask);
+ if (socketmgr != NULL)
+ isc_socketmgr_destroy(&socketmgr);
+ if (taskmgr != NULL)
+ isc_taskmgr_destroy(&taskmgr);
+ if (timermgr != NULL)
+ isc_timermgr_destroy(&timermgr);
+}
+
+static isc_result_t
+create_managers(unsigned int workers) {
+ isc_result_t result;
+ char *p;
+
+ if (workers == 0) {
+#ifdef ISC_PLATFORM_USETHREADS
+ workers = isc_os_ncpus();
+#else
+ workers = 1;
+#endif
+ }
+
+ p = getenv("ISC_TASK_WORKERS");
+ if (p != NULL) {
+ workers = atoi(p);
+ }
+
+ CHECK(isc_taskmgr_create(mctx, workers, 0, &taskmgr));
+ CHECK(isc_task_create(taskmgr, 0, &maintask));
+ isc_taskmgr_setexcltask(taskmgr, maintask);
+
+ CHECK(isc_timermgr_create(mctx, &timermgr));
+ CHECK(isc_socketmgr_create(mctx, &socketmgr));
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ cleanup_managers();
+ return (result);
+}
+
+isc_result_t
+isc_test_begin(FILE *logfile, bool start_managers,
+ unsigned int workers)
+{
+ isc_result_t result;
+
+ isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
+ CHECK(isc_mem_create(0, 0, &mctx));
+ CHECK(isc_entropy_create(mctx, &ectx));
+
+ CHECK(isc_hash_create(mctx, ectx, 255));
+ hash_active = true;
+
+ if (logfile != NULL) {
+ isc_logdestination_t destination;
+ isc_logconfig_t *logconfig = NULL;
+
+ CHECK(isc_log_create(mctx, &lctx, &logconfig));
+ isc_log_registercategories(lctx, categories);
+ isc_log_setcontext(lctx);
+
+ destination.file.stream = logfile;
+ destination.file.name = NULL;
+ destination.file.versions = ISC_LOG_ROLLNEVER;
+ destination.file.maximum_size = 0;
+ CHECK(isc_log_createchannel(logconfig, "stderr",
+ ISC_LOG_TOFILEDESC,
+ ISC_LOG_DYNAMIC,
+ &destination, 0));
+ CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL));
+ }
+
+#ifdef ISC_PLATFORM_USETHREADS
+ ncpus = isc_os_ncpus();
+#else
+ ncpus = 1;
+#endif
+
+ if (start_managers) {
+ CHECK(create_managers(workers));
+ }
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ isc_test_end();
+ return (result);
+}
+
+void
+isc_test_end(void) {
+ if (maintask != NULL)
+ isc_task_detach(&maintask);
+ if (taskmgr != NULL)
+ isc_taskmgr_destroy(&taskmgr);
+ if (hash_active) {
+ isc_hash_destroy();
+ hash_active = false;
+ }
+ if (ectx != NULL)
+ isc_entropy_detach(&ectx);
+
+ cleanup_managers();
+
+ if (lctx != NULL)
+ isc_log_destroy(&lctx);
+ if (mctx != NULL)
+ isc_mem_destroy(&mctx);
+}
+
+/*
+ * Sleep for 'usec' microseconds.
+ */
+void
+isc_test_nap(uint32_t usec) {
+#ifdef HAVE_NANOSLEEP
+ struct timespec ts;
+
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ nanosleep(&ts, NULL);
+#elif HAVE_USLEEP
+ usleep(usec);
+#else
+ /*
+ * No fractional-second sleep function is available, so we
+ * round up to the nearest second and sleep instead
+ */
+ sleep((usec / 1000000) + 1);
+#endif
+}
diff --git a/lib/isc/tests/isctest.h b/lib/isc/tests/isctest.h
new file mode 100644
index 0000000..e553b8a
--- /dev/null
+++ b/lib/isc/tests/isctest.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/buffer.h>
+#include <isc/entropy.h>
+#include <isc/hash.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#define CHECK(r) \
+ do { \
+ result = (r); \
+ if (result != ISC_R_SUCCESS) \
+ goto cleanup; \
+ } while (0)
+
+extern isc_mem_t *mctx;
+extern isc_entropy_t *ectx;
+extern isc_log_t *lctx;
+extern isc_taskmgr_t *taskmgr;
+extern isc_timermgr_t *timermgr;
+extern isc_socketmgr_t *socketmgr;
+extern int ncpus;
+
+isc_result_t
+isc_test_begin(FILE *logfile, bool start_managers,
+ unsigned int workers);
+/*%<
+ * Begin test, logging to 'logfile' or default if not specified.
+ *
+ * If 'start_managers' is set, start a task manager, timer manager,
+ * and socket manager.
+ *
+ * If 'workers' is zero, use the number of CPUs on the system as a default;
+ * otherwise, set up the task manager with the specified number of worker
+ * threads. The environment variable ISC_TASK_WORKERS overrides this value.
+ */
+
+void
+isc_test_end(void);
+
+void
+isc_test_nap(uint32_t usec);
diff --git a/lib/isc/tests/lex_test.c b/lib/isc/tests/lex_test.c
new file mode 100644
index 0000000..1315022
--- /dev/null
+++ b/lib/isc/tests/lex_test.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/util.h>
+
+ATF_TC(lex_0xff);
+ATF_TC_HEAD(lex_0xff, tc) {
+ atf_tc_set_md_var(tc, "descr", "check handling of 0xff");
+}
+ATF_TC_BODY(lex_0xff, tc) {
+ isc_mem_t *mctx = NULL;
+ isc_result_t result;
+ isc_lex_t *lex = NULL;
+ isc_buffer_t death_buf;
+ isc_token_t token;
+
+ unsigned char death[] = { EOF, 'A' };
+
+ UNUSED(tc);
+
+ result = isc_mem_create(0, 0, &mctx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_lex_create(mctx, 1024, &lex);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_buffer_init(&death_buf, &death[0], sizeof(death));
+ isc_buffer_add(&death_buf, sizeof(death));
+
+ result = isc_lex_openbuffer(lex, &death_buf);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_lex_gettoken(lex, 0, &token);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+}
+
+ATF_TC(lex_setline);
+ATF_TC_HEAD(lex_setline, tc) {
+ atf_tc_set_md_var(tc, "descr", "check setting of source line");
+}
+ATF_TC_BODY(lex_setline, tc) {
+ isc_mem_t *mctx = NULL;
+ isc_result_t result;
+ isc_lex_t *lex = NULL;
+ unsigned char text[] = "text\nto\nbe\nprocessed\nby\nlexer";
+ isc_buffer_t buf;
+ isc_token_t token;
+ unsigned long line;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_mem_create(0, 0, &mctx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_lex_create(mctx, 1024, &lex);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_buffer_init(&buf, &text[0], sizeof(text));
+ isc_buffer_add(&buf, sizeof(text));
+
+ result = isc_lex_openbuffer(lex, &buf);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_lex_setsourceline(lex, 100);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ for (i = 0; i < 6; i++) {
+ result = isc_lex_gettoken(lex, 0, &token);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ line = isc_lex_getsourceline(lex);
+ ATF_REQUIRE_EQ(line, 100U + i);
+ }
+
+ result = isc_lex_gettoken(lex, 0, &token);
+ ATF_REQUIRE_EQ(result, ISC_R_EOF);
+
+ line = isc_lex_getsourceline(lex);
+ ATF_REQUIRE_EQ(line, 105U);
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, lex_0xff);
+ ATF_TP_ADD_TC(tp, lex_setline);
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/mem_test.c b/lib/isc/tests/mem_test.c
new file mode 100644
index 0000000..22de74f
--- /dev/null
+++ b/lib/isc/tests/mem_test.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <atf-c.h>
+
+#include "isctest.h"
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+
+static void *
+default_memalloc(void *arg, size_t size) {
+ UNUSED(arg);
+ if (size == 0U)
+ size = 1;
+ return (malloc(size));
+}
+
+static void
+default_memfree(void *arg, void *ptr) {
+ UNUSED(arg);
+ free(ptr);
+}
+
+ATF_TC(isc_mem);
+ATF_TC_HEAD(isc_mem, tc) {
+ atf_tc_set_md_var(tc, "descr", "general memory system tests");
+}
+
+#define MP1_FREEMAX 10
+#define MP1_FILLCNT 10
+#define MP1_MAXALLOC 30
+
+#define MP2_FREEMAX 25
+#define MP2_FILLCNT 25
+
+ATF_TC_BODY(isc_mem, tc) {
+ isc_result_t result;
+ void *items1[50];
+ void *items2[50];
+ void *tmp;
+ isc_mem_t *localmctx = NULL;
+ isc_mempool_t *mp1 = NULL, *mp2 = NULL;
+ unsigned int i, j;
+ int rval;
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_mem_create(0, 0, &localmctx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_mempool_create(localmctx, 24, &mp1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_mempool_create(localmctx, 31, &mp2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_mempool_setfreemax(mp1, MP1_FREEMAX);
+ isc_mempool_setfillcount(mp1, MP1_FILLCNT);
+ isc_mempool_setmaxalloc(mp1, MP1_MAXALLOC);
+
+ /*
+ * Allocate MP1_MAXALLOC items from the pool. This is our max.
+ */
+ for (i = 0; i < MP1_MAXALLOC; i++) {
+ items1[i] = isc_mempool_get(mp1);
+ ATF_CHECK(items1[i] != NULL);
+ }
+
+ /*
+ * Try to allocate one more. This should fail.
+ */
+ tmp = isc_mempool_get(mp1);
+ ATF_CHECK_EQ(tmp, NULL);
+
+ /*
+ * Free the first 11 items. Verify that there are 10 free items on
+ * the free list (which is our max).
+ */
+ for (i = 0; i < 11; i++) {
+ isc_mempool_put(mp1, items1[i]);
+ items1[i] = NULL;
+ }
+
+ rval = isc_mempool_getfreecount(mp1);
+ ATF_CHECK_EQ(rval, 10);
+
+ rval = isc_mempool_getallocated(mp1);
+ ATF_CHECK_EQ(rval, 19);
+
+ /*
+ * Now, beat up on mp2 for a while. Allocate 50 items, then free
+ * them, then allocate 50 more, etc.
+ */
+
+ isc_mempool_setfreemax(mp2, 25);
+ isc_mempool_setfillcount(mp2, 25);
+
+ for (j = 0; j < 500000; j++) {
+ for (i = 0; i < 50; i++) {
+ items2[i] = isc_mempool_get(mp2);
+ ATF_CHECK(items2[i] != NULL);
+ }
+ for (i = 0; i < 50; i++) {
+ isc_mempool_put(mp2, items2[i]);
+ items2[i] = NULL;
+ }
+ }
+
+ /*
+ * Free all the other items and blow away this pool.
+ */
+ for (i = 11; i < MP1_MAXALLOC; i++) {
+ isc_mempool_put(mp1, items1[i]);
+ items1[i] = NULL;
+ }
+
+ isc_mempool_destroy(&mp1);
+ isc_mempool_destroy(&mp2);
+
+ isc_mem_destroy(&localmctx);
+
+ result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
+ NULL, &localmctx, ISC_MEMFLAG_INTERNAL);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_mempool_create(localmctx, 2, &mp1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ tmp = isc_mempool_get(mp1);
+ ATF_CHECK(tmp != NULL);
+
+ isc_mempool_put(mp1, tmp);
+
+ isc_mempool_destroy(&mp1);
+
+ isc_test_end();
+}
+
+ATF_TC(isc_mem_total);
+ATF_TC_HEAD(isc_mem_total, tc) {
+ atf_tc_set_md_var(tc, "descr", "test TotalUse calculation");
+}
+
+ATF_TC_BODY(isc_mem_total, tc) {
+ isc_result_t result;
+ isc_mem_t *mctx2 = NULL;
+ size_t before, after;
+ ssize_t diff;
+ int i;
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* Local alloc, free */
+ mctx2 = NULL;
+ result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
+ NULL, &mctx2, 0);
+ if (result != ISC_R_SUCCESS)
+ goto out;
+
+ before = isc_mem_total(mctx2);
+
+ for (i = 0; i < 100000; i++) {
+ void *ptr;
+
+ ptr = isc_mem_allocate(mctx2, 2048);
+ isc_mem_free(mctx2, ptr);
+ }
+
+ after = isc_mem_total(mctx2);
+ diff = after - before;
+
+ printf("total_before=%lu, total_after=%lu, total_diff=%lu\n",
+ (unsigned long)before, (unsigned long)after,
+ (unsigned long)diff);
+ /* 2048 +8 bytes extra for size_info */
+ ATF_CHECK_EQ(diff, (2048 + 8) * 100000);
+
+ /* ISC_MEMFLAG_INTERNAL */
+
+ before = isc_mem_total(mctx);
+
+ for (i = 0; i < 100000; i++) {
+ void *ptr;
+
+ ptr = isc_mem_allocate(mctx, 2048);
+ isc_mem_free(mctx, ptr);
+ }
+
+ after = isc_mem_total(mctx);
+ diff = after - before;
+
+ printf("total_before=%lu, total_after=%lu, total_diff=%lu\n",
+ (unsigned long)before, (unsigned long)after,
+ (unsigned long)diff);
+ /* 2048 +8 bytes extra for size_info */
+ ATF_CHECK_EQ(diff, (2048 + 8) * 100000);
+
+ out:
+ if (mctx2 != NULL)
+ isc_mem_destroy(&mctx2);
+
+ isc_test_end();
+}
+
+ATF_TC(isc_mem_inuse);
+ATF_TC_HEAD(isc_mem_inuse, tc) {
+ atf_tc_set_md_var(tc, "descr", "test InUse calculation");
+}
+
+ATF_TC_BODY(isc_mem_inuse, tc) {
+ isc_result_t result;
+ isc_mem_t *mctx2 = NULL;
+ size_t before, during, after;
+ ssize_t diff;
+ void *ptr;
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ mctx2 = NULL;
+ result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
+ NULL, &mctx2, 0);
+ if (result != ISC_R_SUCCESS)
+ goto out;
+
+ before = isc_mem_inuse(mctx2);
+ ptr = isc_mem_allocate(mctx2, 1024000);
+ during = isc_mem_inuse(mctx2);
+ isc_mem_free(mctx2, ptr);
+ after = isc_mem_inuse(mctx2);
+
+ diff = after - before;
+
+ printf("inuse_before=%lu, inuse_during=%lu, inuse_after=%lu\n",
+ (unsigned long)before, (unsigned long)during,
+ (unsigned long)after);
+ ATF_REQUIRE_EQ(diff, 0);
+
+ out:
+ if (mctx2 != NULL)
+ isc_mem_destroy(&mctx2);
+
+ isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_mem);
+ ATF_TP_ADD_TC(tp, isc_mem_total);
+ ATF_TP_ADD_TC(tp, isc_mem_inuse);
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/netaddr_test.c b/lib/isc/tests/netaddr_test.c
new file mode 100644
index 0000000..aa41b96
--- /dev/null
+++ b/lib/isc/tests/netaddr_test.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* ! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/netaddr.h>
+#include <isc/sockaddr.h>
+#include <isc/util.h>
+
+ATF_TC(netaddr_isnetzero);
+ATF_TC_HEAD(netaddr_isnetzero, tc) {
+ atf_tc_set_md_var(tc, "descr", "test netaddr_isnetzero");
+}
+ATF_TC_BODY(netaddr_isnetzero, tc) {
+ unsigned int i;
+ struct in_addr ina;
+ struct {
+ const char *address;
+ bool expect;
+ } tests[] = {
+ { "0.0.0.0", true },
+ { "0.0.0.1", true },
+ { "0.0.1.2", true },
+ { "0.1.2.3", true },
+ { "10.0.0.0", false },
+ { "10.9.0.0", false },
+ { "10.9.8.0", false },
+ { "10.9.8.7", false },
+ { "127.0.0.0", false },
+ { "127.0.0.1", false }
+ };
+ bool result;
+ isc_netaddr_t netaddr;
+
+ for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
+ ina.s_addr = inet_addr(tests[i].address);
+ isc_netaddr_fromin(&netaddr, &ina);
+ result = isc_netaddr_isnetzero(&netaddr);
+ ATF_CHECK_EQ_MSG(result, tests[i].expect,
+ "%s", tests[i].address);
+ }
+}
+
+ATF_TC(netaddr_masktoprefixlen);
+ATF_TC_HEAD(netaddr_masktoprefixlen, tc) {
+ atf_tc_set_md_var(tc, "descr",
+ "isc_netaddr_masktoprefixlen() "
+ "calculates correct prefix lengths ");
+}
+ATF_TC_BODY(netaddr_masktoprefixlen, tc) {
+ struct in_addr na_a;
+ struct in_addr na_b;
+ struct in_addr na_c;
+ struct in_addr na_d;
+ isc_netaddr_t ina_a;
+ isc_netaddr_t ina_b;
+ isc_netaddr_t ina_c;
+ isc_netaddr_t ina_d;
+ unsigned int plen;
+
+ UNUSED(tc);
+
+ ATF_CHECK(inet_pton(AF_INET, "0.0.0.0", &na_a) >= 0);
+ ATF_CHECK(inet_pton(AF_INET, "255.255.255.254", &na_b) >= 0);
+ ATF_CHECK(inet_pton(AF_INET, "255.255.255.255", &na_c) >= 0);
+ ATF_CHECK(inet_pton(AF_INET, "255.255.255.0", &na_d) >= 0);
+
+ isc_netaddr_fromin(&ina_a, &na_a);
+ isc_netaddr_fromin(&ina_b, &na_b);
+ isc_netaddr_fromin(&ina_c, &na_c);
+ isc_netaddr_fromin(&ina_d, &na_d);
+
+ ATF_CHECK_EQ(isc_netaddr_masktoprefixlen(&ina_a, &plen),
+ ISC_R_SUCCESS);
+ ATF_CHECK_EQ(plen, 0);
+
+ ATF_CHECK_EQ(isc_netaddr_masktoprefixlen(&ina_b, &plen),
+ ISC_R_SUCCESS);
+ ATF_CHECK_EQ(plen, 31);
+
+ ATF_CHECK_EQ(isc_netaddr_masktoprefixlen(&ina_c, &plen),
+ ISC_R_SUCCESS);
+ ATF_CHECK_EQ(plen, 32);
+
+ ATF_CHECK_EQ(isc_netaddr_masktoprefixlen(&ina_d, &plen),
+ ISC_R_SUCCESS);
+ ATF_CHECK_EQ(plen, 24);
+}
+
+ATF_TC(netaddr_multicast);
+ATF_TC_HEAD(netaddr_multicast, tc) {
+ atf_tc_set_md_var(tc, "descr",
+ "check multicast addresses are detected properly");
+}
+ATF_TC_BODY(netaddr_multicast, tc) {
+ unsigned int i;
+ struct {
+ int family;
+ const char *addr;
+ bool is_multicast;
+ } tests[] = {
+ { AF_INET, "1.2.3.4", false },
+ { AF_INET, "4.3.2.1", false },
+ { AF_INET, "224.1.1.1", true },
+ { AF_INET, "1.1.1.244", false },
+ { AF_INET6, "::1", false },
+ { AF_INET6, "ff02::1", true }
+ };
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ isc_netaddr_t na;
+ struct in_addr in;
+ struct in6_addr in6;
+ int r;
+
+ if (tests[i].family == AF_INET) {
+ r = inet_pton(AF_INET, tests[i].addr,
+ (unsigned char *)&in);
+ ATF_REQUIRE_EQ(r, 1);
+ isc_netaddr_fromin(&na, &in);
+ } else {
+ r = inet_pton(AF_INET6, tests[i].addr,
+ (unsigned char *)&in6);
+ ATF_REQUIRE_EQ(r, 1);
+ isc_netaddr_fromin6(&na, &in6);
+ }
+
+ ATF_CHECK_EQ(isc_netaddr_ismulticast(&na),
+ tests[i].is_multicast);
+ }
+}
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, netaddr_isnetzero);
+ ATF_TP_ADD_TC(tp, netaddr_masktoprefixlen);
+ ATF_TP_ADD_TC(tp, netaddr_multicast);
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/parse_test.c b/lib/isc/tests/parse_test.c
new file mode 100644
index 0000000..edc8139
--- /dev/null
+++ b/lib/isc/tests/parse_test.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <inttypes.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <isc/parseint.h>
+
+#include "isctest.h"
+
+/*
+ * Individual unit tests
+ */
+
+/* Test for 32 bit overflow on 64 bit machines in isc_parse_uint32 */
+ATF_TC(parse_overflow);
+ATF_TC_HEAD(parse_overflow, tc) {
+ atf_tc_set_md_var(tc, "descr", "Check for 32 bit overflow");
+}
+ATF_TC_BODY(parse_overflow, tc) {
+ isc_result_t result;
+ uint32_t output;
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_parse_uint32(&output, "1234567890", 10);
+ ATF_CHECK_EQ(ISC_R_SUCCESS, result);
+ ATF_CHECK_EQ(1234567890, output);
+
+ result = isc_parse_uint32(&output, "123456789012345", 10);
+ ATF_CHECK_EQ(ISC_R_RANGE, result);
+
+ result = isc_parse_uint32(&output, "12345678901234567890", 10);
+ ATF_CHECK_EQ(ISC_R_RANGE, result);
+
+ isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, parse_overflow);
+
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/pool_test.c b/lib/isc/tests/pool_test.c
new file mode 100644
index 0000000..fb9197e
--- /dev/null
+++ b/lib/isc/tests/pool_test.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+
+#include <isc/mem.h>
+#include <isc/pool.h>
+
+#include "isctest.h"
+
+static isc_result_t
+poolinit(void **target, void *arg) {
+ isc_result_t result;
+
+ isc_taskmgr_t *mgr = (isc_taskmgr_t *) arg;
+ isc_task_t *task = NULL;
+ result = isc_task_create(mgr, 0, &task);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ *target = (void *) task;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+poolfree(void **target) {
+ isc_task_t *task = *(isc_task_t **) target;
+ isc_task_destroy(&task);
+ *target = NULL;
+}
+
+/*
+ * Individual unit tests
+ */
+
+/* Create a pool */
+ATF_TC(create_pool);
+ATF_TC_HEAD(create_pool, tc) {
+ atf_tc_set_md_var(tc, "descr", "create a pool");
+}
+ATF_TC_BODY(create_pool, tc) {
+ isc_result_t result;
+ isc_pool_t *pool = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_pool_create(mctx, 8, poolfree, poolinit, taskmgr, &pool);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool), 8);
+
+ isc_pool_destroy(&pool);
+ ATF_REQUIRE_EQ(pool, NULL);
+
+ isc_test_end();
+}
+
+/* Resize a pool */
+ATF_TC(expand_pool);
+ATF_TC_HEAD(expand_pool, tc) {
+ atf_tc_set_md_var(tc, "descr", "expand a pool");
+}
+ATF_TC_BODY(expand_pool, tc) {
+ isc_result_t result;
+ isc_pool_t *pool1 = NULL, *pool2 = NULL, *hold = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_pool_create(mctx, 10, poolfree, poolinit, taskmgr, &pool1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool1), 10);
+
+ /* resizing to a smaller size should have no effect */
+ hold = pool1;
+ result = isc_pool_expand(&pool1, 5, &pool2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool2), 10);
+ ATF_REQUIRE_EQ(pool2, hold);
+ ATF_REQUIRE_EQ(pool1, NULL);
+ pool1 = pool2;
+ pool2 = NULL;
+
+ /* resizing to the same size should have no effect */
+ hold = pool1;
+ result = isc_pool_expand(&pool1, 10, &pool2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool2), 10);
+ ATF_REQUIRE_EQ(pool2, hold);
+ ATF_REQUIRE_EQ(pool1, NULL);
+ pool1 = pool2;
+ pool2 = NULL;
+
+ /* resizing to larger size should make a new pool */
+ hold = pool1;
+ result = isc_pool_expand(&pool1, 20, &pool2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool2), 20);
+ ATF_REQUIRE(pool2 != hold);
+ ATF_REQUIRE_EQ(pool1, NULL);
+
+ isc_pool_destroy(&pool2);
+ ATF_REQUIRE_EQ(pool2, NULL);
+
+ isc_test_end();
+}
+
+/* Get objects */
+ATF_TC(get_objects);
+ATF_TC_HEAD(get_objects, tc) {
+ atf_tc_set_md_var(tc, "descr", "get objects");
+}
+ATF_TC_BODY(get_objects, tc) {
+ isc_result_t result;
+ isc_pool_t *pool = NULL;
+ void *item;
+ isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_pool_create(mctx, 2, poolfree, poolinit, taskmgr, &pool);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool), 2);
+
+ item = isc_pool_get(pool);
+ ATF_REQUIRE(item != NULL);
+ isc_task_attach((isc_task_t *) item, &task1);
+
+ item = isc_pool_get(pool);
+ ATF_REQUIRE(item != NULL);
+ isc_task_attach((isc_task_t *) item, &task2);
+
+ item = isc_pool_get(pool);
+ ATF_REQUIRE(item != NULL);
+ isc_task_attach((isc_task_t *) item, &task3);
+
+ isc_task_detach(&task1);
+ isc_task_detach(&task2);
+ isc_task_detach(&task3);
+
+ isc_pool_destroy(&pool);
+ ATF_REQUIRE_EQ(pool, NULL);
+
+ isc_test_end();
+}
+
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, create_pool);
+ ATF_TP_ADD_TC(tp, expand_pool);
+ ATF_TP_ADD_TC(tp, get_objects);
+
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/print_test.c b/lib/isc/tests/print_test.c
new file mode 100644
index 0000000..259e301
--- /dev/null
+++ b/lib/isc/tests/print_test.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * Workout if we need to force the inclusion of print.c so we can test
+ * it on all platforms even if we don't include it in libisc.
+ */
+#include <isc/platform.h>
+#if !defined(ISC_PLATFORM_NEEDPRINTF) && \
+ !defined(ISC_PLATFORM_NEEDFPRINTF) && \
+ !defined(ISC_PLATFORM_NEEDSPRINTF) && \
+ !defined(ISC_PLATFORM_NEEDVSNPRINTF)
+#define ISC__PRINT_SOURCE
+#include "../print.c"
+#else
+#if !defined(ISC_PLATFORM_NEEDPRINTF) || \
+ !defined(ISC_PLATFORM_NEEDFPRINTF) || \
+ !defined(ISC_PLATFORM_NEEDSPRINTF) || \
+ !defined(ISC_PLATFORM_NEEDVSNPRINTF)
+#define ISC__PRINT_SOURCE
+#endif
+#include <isc/print.h>
+#include <isc/types.h>
+#include <isc/util.h>
+#endif
+
+ATF_TC(snprintf);
+ATF_TC_HEAD(snprintf, tc) {
+ atf_tc_set_md_var(tc, "descr", "snprintf implementation");
+}
+ATF_TC_BODY(snprintf, tc) {
+ char buf[10000];
+ uint64_t ll = 8589934592ULL;
+ uint64_t nn = 20000000000000ULL;
+ uint64_t zz = 10000000000000000000ULL;
+ float pi = 3.141;
+ int n;
+ size_t size;
+
+ UNUSED(tc);
+
+ /*
+ * 4294967296 <= 8589934592 < 1000000000^2 to verify fix for
+ * RT#36505.
+ */
+
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "%" PRIu64, ll);
+ ATF_CHECK_EQ(n, 10);
+ ATF_CHECK_STREQ(buf, "8589934592");
+
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "%" PRIu64, ll);
+ ATF_CHECK_EQ(n, 10);
+ ATF_CHECK_STREQ(buf, "8589934592");
+
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "%" PRIu64, nn);
+ ATF_CHECK_EQ(n, 14);
+ ATF_CHECK_STREQ(buf, "20000000000000");
+
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "%" PRIu64, nn);
+ ATF_CHECK_EQ(n, 14);
+ ATF_CHECK_STREQ(buf, "20000000000000");
+
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "%" PRIu64, zz);
+ ATF_CHECK_EQ(n, 20);
+ ATF_CHECK_STREQ(buf, "10000000000000000000");
+
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "%" PRIu64, zz);
+ ATF_CHECK_EQ(n, 20);
+ ATF_CHECK_STREQ(buf, "10000000000000000000");
+
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "%" PRId64, nn);
+ ATF_CHECK_EQ(n, 14);
+ ATF_CHECK_STREQ(buf, "20000000000000");
+
+ size = 1000;
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "%zu", size);
+ ATF_CHECK_EQ(n, 4);
+ ATF_CHECK_STREQ(buf, "1000");
+
+ size = 1000;
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "%zx", size);
+ ATF_CHECK_EQ(n, 3);
+ ATF_CHECK_STREQ(buf, "3e8");
+
+ size = 1000;
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "%zo", size);
+ ATF_CHECK_EQ(n, 4);
+ ATF_CHECK_STREQ(buf, "1750");
+
+ zz = 0xf5f5f5f5f5f5f5f5ULL;
+ memset(buf, 0xff, sizeof(buf));
+ n = isc_print_snprintf(buf, sizeof(buf), "0x%" PRIx64, zz);
+ ATF_CHECK_EQ(n, 18);
+ ATF_CHECK_STREQ(buf, "0xf5f5f5f5f5f5f5f5");
+
+ n = isc_print_snprintf(buf, sizeof(buf), "%.2f", pi);
+ ATF_CHECK_EQ(n, 4);
+ ATF_CHECK_STREQ(buf, "3.14");
+
+ /* Similar to the above, but additional characters follows */
+ n = isc_print_snprintf(buf, sizeof(buf), "%.2f1592", pi);
+ ATF_CHECK_EQ(n, 8);
+ ATF_CHECK_STREQ(buf, "3.141592");
+
+ /* Similar to the above, but with leading spaces */
+ n = isc_print_snprintf(buf, sizeof(buf), "% 8.2f1592", pi);
+ ATF_CHECK_EQ(n, 12);
+ ATF_CHECK_STREQ(buf, " 3.141592");
+
+ /* Similar to the above, but with trail spaces after the 4 */
+ n = isc_print_snprintf(buf, sizeof(buf), "%-8.2f1592", pi);
+ ATF_CHECK_EQ(n, 12);
+ ATF_CHECK_STREQ(buf, "3.14 1592");
+}
+
+ATF_TC(fprintf);
+ATF_TC_HEAD(fprintf, tc) {
+ atf_tc_set_md_var(tc, "descr", "fprintf implementation");
+}
+ATF_TC_BODY(fprintf, tc) {
+ FILE *f;
+ int n;
+ size_t size;
+ char buf[10000];
+
+ UNUSED(tc);
+
+ f = fopen("fprintf.test", "w+");
+ ATF_REQUIRE(f != NULL);
+
+ size = 1000;
+ n = isc_print_fprintf(f, "%zu", size);
+ ATF_CHECK_EQ(n, 4);
+
+ rewind(f);
+
+ memset(buf, 0, sizeof(buf));
+ n = fread(buf, 1, sizeof(buf), f);
+ ATF_CHECK_EQ(n, 4);
+
+ fclose(f);
+
+ ATF_CHECK_STREQ(buf, "1000");
+
+ if ((n > 0) && (!strcmp(buf, "1000")))
+ unlink("fprintf.test");
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, snprintf);
+ ATF_TP_ADD_TC(tp, fprintf);
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/queue_test.c b/lib/isc/tests/queue_test.c
new file mode 100644
index 0000000..843e641
--- /dev/null
+++ b/lib/isc/tests/queue_test.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+#include <time.h>
+
+#include <isc/queue.h>
+
+#include "isctest.h"
+
+typedef struct item item_t;
+struct item {
+ int value;
+ ISC_QLINK(item_t) qlink;
+};
+
+typedef ISC_QUEUE(item_t) item_queue_t;
+
+static void
+item_init(item_t *item, int value) {
+ item->value = value;
+ ISC_QLINK_INIT(item, qlink);
+}
+
+/*
+ * Individual unit tests
+ */
+
+/* Test UDP sendto/recv (IPv4) */
+ATF_TC(queue_valid);
+ATF_TC_HEAD(queue_valid, tc) {
+ atf_tc_set_md_var(tc, "descr", "Check queue validity");
+}
+ATF_TC_BODY(queue_valid, tc) {
+ isc_result_t result;
+ item_queue_t queue;
+ item_t one, two, three, four, five;
+ item_t *p;
+
+ UNUSED(tc);
+
+ ISC_QUEUE_INIT(queue, qlink);
+
+ item_init(&one, 1);
+ item_init(&two, 2);
+ item_init(&three, 3);
+ item_init(&four, 4);
+ item_init(&five, 5);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ ATF_CHECK(ISC_QUEUE_EMPTY(queue));
+
+ ISC_QUEUE_POP(queue, qlink, p);
+ ATF_CHECK(p == NULL);
+
+ ATF_CHECK(! ISC_QLINK_LINKED(&one, qlink));
+ ISC_QUEUE_PUSH(queue, &one, qlink);
+ ATF_CHECK(ISC_QLINK_LINKED(&one, qlink));
+
+ ATF_CHECK(! ISC_QUEUE_EMPTY(queue));
+
+ ISC_QUEUE_POP(queue, qlink, p);
+ ATF_REQUIRE(p != NULL);
+ ATF_CHECK_EQ(p->value, 1);
+ ATF_CHECK(ISC_QUEUE_EMPTY(queue));
+ ATF_CHECK(! ISC_QLINK_LINKED(p, qlink));
+
+ ISC_QUEUE_PUSH(queue, p, qlink);
+ ATF_CHECK(! ISC_QUEUE_EMPTY(queue));
+ ATF_CHECK(ISC_QLINK_LINKED(p, qlink));
+
+ ATF_CHECK(! ISC_QLINK_LINKED(&two, qlink));
+ ISC_QUEUE_PUSH(queue, &two, qlink);
+ ATF_CHECK(ISC_QLINK_LINKED(&two, qlink));
+
+ ATF_CHECK(! ISC_QLINK_LINKED(&three, qlink));
+ ISC_QUEUE_PUSH(queue, &three, qlink);
+ ATF_CHECK(ISC_QLINK_LINKED(&three, qlink));
+
+ ATF_CHECK(! ISC_QLINK_LINKED(&four, qlink));
+ ISC_QUEUE_PUSH(queue, &four, qlink);
+ ATF_CHECK(ISC_QLINK_LINKED(&four, qlink));
+
+ ATF_CHECK(! ISC_QLINK_LINKED(&five, qlink));
+ ISC_QUEUE_PUSH(queue, &five, qlink);
+ ATF_CHECK(ISC_QLINK_LINKED(&five, qlink));
+
+ /* Test unlink by removing one item from the middle */
+ ISC_QUEUE_UNLINK(queue, &three, qlink);
+
+ ISC_QUEUE_POP(queue, qlink, p);
+ ATF_REQUIRE(p != NULL);
+ ATF_CHECK_EQ(p->value, 1);
+
+ ISC_QUEUE_POP(queue, qlink, p);
+ ATF_REQUIRE(p != NULL);
+ ATF_CHECK_EQ(p->value, 2);
+
+ ISC_QUEUE_POP(queue, qlink, p);
+ ATF_REQUIRE(p != NULL);
+ ATF_CHECK_EQ(p->value, 4);
+
+ ISC_QUEUE_POP(queue, qlink, p);
+ ATF_REQUIRE(p != NULL);
+ ATF_CHECK_EQ(p->value, 5);
+
+ ATF_CHECK(ISC_QUEUE_EMPTY(queue));
+
+ ISC_QUEUE_DESTROY(queue);
+ isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, queue_valid);
+
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/radix_test.c b/lib/isc/tests/radix_test.c
new file mode 100644
index 0000000..0a0b534
--- /dev/null
+++ b/lib/isc/tests/radix_test.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/netaddr.h>
+#include <isc/radix.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <atf-c.h>
+
+#include <stdlib.h>
+
+#include "isctest.h"
+
+ATF_TC(isc_radix_search);
+ATF_TC_HEAD(isc_radix_search, tc) {
+ atf_tc_set_md_var(tc, "descr", "test radix seaching");
+}
+ATF_TC_BODY(isc_radix_search, tc) {
+ isc_radix_tree_t *radix = NULL;
+ isc_radix_node_t *node;
+ isc_prefix_t prefix;
+ isc_result_t result;
+ struct in_addr in_addr;
+ isc_netaddr_t netaddr;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_radix_create(mctx, &radix, 32);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ in_addr.s_addr = inet_addr("3.3.3.0");
+ isc_netaddr_fromin(&netaddr, &in_addr);
+ NETADDR_TO_PREFIX_T(&netaddr, prefix, 24, false);
+
+ node = NULL;
+ result = isc_radix_insert(radix, &node, NULL, &prefix);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ node->data[0] = (void *)1;
+ isc_refcount_destroy(&prefix.refcount);
+
+ in_addr.s_addr = inet_addr("3.3.0.0");
+ isc_netaddr_fromin(&netaddr, &in_addr);
+ NETADDR_TO_PREFIX_T(&netaddr, prefix, 16, false);
+
+ node = NULL;
+ result = isc_radix_insert(radix, &node, NULL, &prefix);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ node->data[0] = (void *)2;
+ isc_refcount_destroy(&prefix.refcount);
+
+ in_addr.s_addr = inet_addr("3.3.3.3");
+ isc_netaddr_fromin(&netaddr, &in_addr);
+ NETADDR_TO_PREFIX_T(&netaddr, prefix, 22, false);
+
+ node = NULL;
+ result = isc_radix_search(radix, &node, &prefix);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(node->data[0], (void *)2);
+
+ isc_refcount_destroy(&prefix.refcount);
+
+ isc_radix_destroy(radix, NULL);
+
+ isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_radix_search);
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/random_test.c b/lib/isc/tests/random_test.c
new file mode 100644
index 0000000..5637139
--- /dev/null
+++ b/lib/isc/tests/random_test.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * IMPORTANT NOTE:
+ * These tests work by generating a large number of pseudo-random numbers
+ * and then statistically analyzing them to determine whether they seem
+ * random. The test is expected to fail on occasion by random happenstance.
+ */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/random.h>
+#include <isc/result.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/util.h>
+
+#include <atf-c.h>
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+
+#define REPS 25000
+
+typedef double (pvalue_func_t)(isc_mem_t *mctx,
+ uint16_t *values, size_t length);
+
+/* igamc(), igam(), etc. were adapted (and cleaned up) from the Cephes
+ * math library:
+ *
+ * Cephes Math Library Release 2.8: June, 2000
+ * Copyright 1985, 1987, 2000 by Stephen L. Moshier
+ *
+ * The Cephes math library was released into the public domain as part
+ * of netlib.
+*/
+
+static double MACHEP = 1.11022302462515654042E-16;
+static double MAXLOG = 7.09782712893383996843E2;
+static double big = 4.503599627370496e15;
+static double biginv = 2.22044604925031308085e-16;
+
+static double igamc(double a, double x);
+static double igam(double a, double x);
+
+static double
+igamc(double a, double x) {
+ double ans, ax, c, yc, r, t, y, z;
+ double pk, pkm1, pkm2, qk, qkm1, qkm2;
+
+ if ((x <= 0) || (a <= 0))
+ return (1.0);
+
+ if ((x < 1.0) || (x < a))
+ return (1.0 - igam(a, x));
+
+ ax = a * log(x) - x - lgamma(a);
+ if (ax < -MAXLOG) {
+ fprintf(stderr, "igamc: UNDERFLOW, ax=%f\n", ax);
+ return (0.0);
+ }
+ ax = exp(ax);
+
+ /* continued fraction */
+ y = 1.0 - a;
+ z = x + y + 1.0;
+ c = 0.0;
+ pkm2 = 1.0;
+ qkm2 = x;
+ pkm1 = x + 1.0;
+ qkm1 = z * x;
+ ans = pkm1 / qkm1;
+
+ do {
+ c += 1.0;
+ y += 1.0;
+ z += 2.0;
+ yc = y * c;
+ pk = pkm1 * z - pkm2 * yc;
+ qk = qkm1 * z - qkm2 * yc;
+ if (qk != 0) {
+ r = pk / qk;
+ t = fabs((ans - r) / r);
+ ans = r;
+ } else
+ t = 1.0;
+
+ pkm2 = pkm1;
+ pkm1 = pk;
+ qkm2 = qkm1;
+ qkm1 = qk;
+
+ if (fabs(pk) > big) {
+ pkm2 *= biginv;
+ pkm1 *= biginv;
+ qkm2 *= biginv;
+ qkm1 *= biginv;
+ }
+ } while (t > MACHEP);
+
+ return (ans * ax);
+}
+
+static double
+igam(double a, double x) {
+ double ans, ax, c, r;
+
+ if ((x <= 0) || (a <= 0))
+ return (0.0);
+
+ if ((x > 1.0) && (x > a))
+ return (1.0 - igamc(a, x));
+
+ /* Compute x**a * exp(-x) / md_gamma(a) */
+ ax = a * log(x) - x - lgamma(a);
+ if( ax < -MAXLOG ) {
+ fprintf(stderr, "igam: UNDERFLOW, ax=%f\n", ax);
+ return (0.0);
+ }
+ ax = exp(ax);
+
+ /* power series */
+ r = a;
+ c = 1.0;
+ ans = 1.0;
+
+ do {
+ r += 1.0;
+ c *= x / r;
+ ans += c;
+ } while (c / ans > MACHEP);
+
+ return (ans * ax / a);
+}
+
+static int8_t scounts_table[65536];
+static uint8_t bitcounts_table[65536];
+
+static int8_t
+scount_calculate(uint16_t n) {
+ int i;
+ int8_t sc;
+
+ sc = 0;
+ for (i = 0; i < 16; i++) {
+ uint16_t lsb;
+
+ lsb = n & 1;
+ if (lsb != 0)
+ sc += 1;
+ else
+ sc -= 1;
+
+ n >>= 1;
+ }
+
+ return (sc);
+}
+
+static uint8_t
+bitcount_calculate(uint16_t n) {
+ int i;
+ uint8_t bc;
+
+ bc = 0;
+ for (i = 0; i < 16; i++) {
+ uint16_t lsb;
+
+ lsb = n & 1;
+ if (lsb != 0)
+ bc += 1;
+
+ n >>= 1;
+ }
+
+ return (bc);
+}
+
+static void
+tables_init(void) {
+ uint32_t i;
+
+ for (i = 0; i < 65536; i++) {
+ scounts_table[i] = scount_calculate(i);
+ bitcounts_table[i] = bitcount_calculate(i);
+ }
+}
+
+/*
+ * The following code for computing Marsaglia's rank is based on the
+ * implementation in cdbinrnk.c from the diehard tests by George
+ * Marsaglia.
+ *
+ * This function destroys (modifies) the data passed in bits.
+ */
+static uint32_t
+matrix_binaryrank(uint32_t *bits, size_t rows, size_t cols) {
+ size_t i, j, k;
+ unsigned int rt = 0;
+ uint32_t rank = 0;
+ uint32_t tmp;
+
+ for (k = 0; k < rows; k++) {
+ i = k;
+
+ while (rt >= cols || ((bits[i] >> rt) & 1) == 0) {
+ i++;
+
+ if (i < rows)
+ continue;
+ else {
+ rt++;
+ if (rt < cols) {
+ i = k;
+ continue;
+ }
+ }
+
+ return (rank);
+ }
+
+ rank++;
+ if (i != k) {
+ tmp = bits[i];
+ bits[i] = bits[k];
+ bits[k] = tmp;
+ }
+
+ for (j = i + 1; j < rows; j++) {
+ if (((bits[j] >> rt) & 1) == 0)
+ continue;
+ else
+ bits[j] ^= bits[k];
+ }
+
+ rt++;
+ }
+
+ return (rank);
+}
+
+static void
+random_test(pvalue_func_t *func) {
+ isc_mem_t *mctx = NULL;
+ isc_result_t result;
+ isc_rng_t *rng;
+ uint32_t m;
+ uint32_t j;
+ uint32_t histogram[11] = { 0 };
+ uint32_t passed;
+ double proportion;
+ double p_hat;
+ double lower_confidence, higher_confidence;
+ double chi_square;
+ double p_value_t;
+ double alpha;
+
+ tables_init();
+
+ result = isc_mem_create(0, 0, &mctx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ rng = NULL;
+ result = isc_rng_create(mctx, NULL, &rng);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ m = 1000;
+ passed = 0;
+
+ for (j = 0; j < m; j++) {
+ uint32_t i;
+ uint16_t values[REPS];
+ double p_value;
+
+ for (i = 0; i < REPS; i++)
+ values[i] = isc_rng_random(rng);
+
+ p_value = (*func)(mctx, values, REPS);
+ if (p_value >= 0.01) {
+ passed++;
+ }
+
+ ATF_REQUIRE(p_value >= 0.0);
+ ATF_REQUIRE(p_value <= 1.0);
+
+ i = (int) floor(p_value * 10);
+ histogram[i]++;
+ }
+
+ isc_rng_detach(&rng);
+
+ /*
+ * Check proportion of sequences passing a test (see section
+ * 4.2.1 in NIST SP 800-22).
+ */
+ alpha = 0.01; /* the significance level */
+ proportion = (double) passed / (double) m;
+ p_hat = 1.0 - alpha;
+ lower_confidence = p_hat - (3.0 * sqrt((p_hat * (1.0 - p_hat)) / m));
+ higher_confidence = p_hat + (3.0 * sqrt((p_hat * (1.0 - p_hat)) / m));
+
+ /* Debug message, not displayed when running via atf-run */
+ printf("passed=%u/1000\n", passed);
+ printf("higher_confidence=%f, lower_confidence=%f, proportion=%f\n",
+ higher_confidence, lower_confidence, proportion);
+
+ ATF_REQUIRE(proportion >= lower_confidence);
+ ATF_REQUIRE(proportion <= higher_confidence);
+
+ /*
+ * Check uniform distribution of p-values (see section 4.2.2 in
+ * NIST SP 800-22).
+ */
+
+ /* Fold histogram[10] (p_value = 1.0) into histogram[9] for
+ * interval [0.9, 1.0]
+ */
+ histogram[9] += histogram[10];
+ histogram[10] = 0;
+
+ /* Pre-requisite that at least 55 sequences are processed. */
+ ATF_REQUIRE(m >= 55);
+
+ chi_square = 0.0;
+ for (j = 0; j < 10; j++) {
+ double numer;
+ double denom;
+
+ /* Debug message, not displayed when running via atf-run */
+ printf("hist%u=%u ", j, histogram[j]);
+
+ numer = (histogram[j] - (m / 10.0)) *
+ (histogram[j] - (m / 10.0));
+ denom = m / 10.0;
+ chi_square += numer / denom;
+ }
+
+ printf("\n");
+
+ p_value_t = igamc(9 / 2.0, chi_square / 2.0);
+
+ ATF_REQUIRE(p_value_t >= 0.0001);
+}
+
+/*
+ * This is a frequency (monobits) test taken from the NIST SP 800-22
+ * RNG test suite.
+ */
+static double
+monobit(isc_mem_t *mctx, uint16_t *values, size_t length) {
+ size_t i;
+ int32_t scount;
+ uint32_t numbits;
+ double s_obs;
+ double p_value;
+
+ UNUSED(mctx);
+
+ numbits = length * 16;
+ scount = 0;
+
+ for (i = 0; i < length; i++)
+ scount += scounts_table[values[i]];
+
+ /* Preconditions (section 2.1.7 in NIST SP 800-22) */
+ ATF_REQUIRE(numbits >= 100);
+
+ /* Debug message, not displayed when running via atf-run */
+ printf("numbits=%u, scount=%d\n", numbits, scount);
+
+ s_obs = abs(scount) / sqrt(numbits);
+ p_value = erfc(s_obs / sqrt(2.0));
+
+ return (p_value);
+}
+
+/*
+ * This is the runs test taken from the NIST SP 800-22 RNG test suite.
+ */
+static double
+runs(isc_mem_t *mctx, uint16_t *values, size_t length) {
+ size_t i;
+ uint32_t bcount;
+ uint32_t numbits;
+ double pi;
+ double tau;
+ uint32_t j;
+ uint32_t b;
+ uint8_t bit_this;
+ uint8_t bit_prev;
+ uint32_t v_obs;
+ double numer;
+ double denom;
+ double p_value;
+
+ UNUSED(mctx);
+
+ numbits = length * 16;
+ bcount = 0;
+
+ for (i = 0; i < REPS; i++)
+ bcount += bitcounts_table[values[i]];
+
+ /* Debug message, not displayed when running via atf-run */
+ printf("numbits=%u, bcount=%u\n", numbits, bcount);
+
+ pi = (double) bcount / (double) numbits;
+ tau = 2.0 / sqrt(numbits);
+
+ /* Preconditions (section 2.3.7 in NIST SP 800-22) */
+ ATF_REQUIRE(numbits >= 100);
+
+ /*
+ * Pre-condition implied from the monobit test. This can fail
+ * for some sequences, and the p-value is taken as 0 in these
+ * cases.
+ */
+ if (fabs(pi - 0.5) >= tau)
+ return (0.0);
+
+ /* Compute v_obs */
+ j = 0;
+ b = 14;
+ bit_prev = (values[j] & (1U << 15)) == 0 ? 0 : 1;
+
+ v_obs = 0;
+
+ for (i = 1; i < numbits; i++) {
+ bit_this = (values[j] & (1U << b)) == 0 ? 0 : 1;
+ if (b == 0) {
+ b = 15;
+ j++;
+ } else {
+ b--;
+ }
+
+ v_obs += bit_this ^ bit_prev;
+
+ bit_prev = bit_this;
+ }
+
+ v_obs += 1;
+
+ numer = fabs(v_obs - (2.0 * numbits * pi * (1.0 - pi)));
+ denom = 2.0 * sqrt(2.0 * numbits) * pi * (1.0 - pi);
+
+ p_value = erfc(numer / denom);
+
+ return (p_value);
+}
+
+/*
+ * This is the block frequency test taken from the NIST SP 800-22 RNG
+ * test suite.
+ */
+static double
+blockfrequency(isc_mem_t *mctx, uint16_t *values, size_t length) {
+ uint32_t i;
+ uint32_t numbits;
+ uint32_t mbits;
+ uint32_t mwords;
+ uint32_t numblocks;
+ double *pi;
+ double chi_square;
+ double p_value;
+
+ numbits = length * 16;
+ mbits = 32000;
+ mwords = mbits / 16;
+ numblocks = numbits / mbits;
+
+ /* Debug message, not displayed when running via atf-run */
+ printf("numblocks=%u\n", numblocks);
+
+ /* Preconditions (section 2.2.7 in NIST SP 800-22) */
+ ATF_REQUIRE(numbits >= 100);
+ ATF_REQUIRE(mbits >= 20);
+ ATF_REQUIRE((double) mbits > (0.01 * numbits));
+ ATF_REQUIRE(numblocks < 100);
+ ATF_REQUIRE(numbits >= (mbits * numblocks));
+
+ pi = isc_mem_get(mctx, numblocks * sizeof(double));
+ ATF_REQUIRE(pi != NULL);
+
+ for (i = 0; i < numblocks; i++) {
+ uint32_t j;
+ pi[i] = 0.0;
+ for (j = 0; j < mwords; j++) {
+ uint32_t idx;
+
+ idx = i * mwords + j;
+ pi[i] += bitcounts_table[values[idx]];
+ }
+ pi[i] /= mbits;
+ }
+
+ /* Compute chi_square */
+ chi_square = 0.0;
+ for (i = 0; i < numblocks; i++)
+ chi_square += (pi[i] - 0.5) * (pi[i] - 0.5);
+
+ chi_square *= 4 * mbits;
+
+ isc_mem_put(mctx, pi, numblocks * sizeof(double));
+
+ /* Debug message, not displayed when running via atf-run */
+ printf("chi_square=%f\n", chi_square);
+
+ p_value = igamc(numblocks * 0.5, chi_square * 0.5);
+
+ return (p_value);
+}
+
+/*
+ * This is the binary matrix rank test taken from the NIST SP 800-22 RNG
+ * test suite.
+ */
+static double
+binarymatrixrank(isc_mem_t *mctx, uint16_t *values, size_t length) {
+ uint32_t i;
+ size_t matrix_m;
+ size_t matrix_q;
+ uint32_t num_matrices;
+ size_t numbits;
+ uint32_t fm_0;
+ uint32_t fm_1;
+ uint32_t fm_rest;
+ double term1;
+ double term2;
+ double term3;
+ double chi_square;
+ double p_value;
+
+ UNUSED(mctx);
+
+ matrix_m = 32;
+ matrix_q = 32;
+ num_matrices = length / ((matrix_m * matrix_q) / 16);
+ numbits = num_matrices * matrix_m * matrix_q;
+
+ /* Preconditions (section 2.5.7 in NIST SP 800-22) */
+ ATF_REQUIRE(matrix_m == 32);
+ ATF_REQUIRE(matrix_q == 32);
+ ATF_REQUIRE(numbits >= (38 * matrix_m * matrix_q));
+
+ fm_0 = 0;
+ fm_1 = 0;
+ fm_rest = 0;
+ for (i = 0; i < num_matrices; i++) {
+ /*
+ * Each uint32_t supplies 32 bits, so a 32x32 bit matrix
+ * takes up uint32_t array of size 32.
+ */
+ uint32_t bits[32];
+ int j;
+ uint32_t rank;
+
+ for (j = 0; j < 32; j++) {
+ size_t idx;
+ uint32_t r1;
+ uint32_t r2;
+
+ idx = i * ((matrix_m * matrix_q) / 16);
+ idx += j * 2;
+
+ r1 = values[idx];
+ r2 = values[idx + 1];
+ bits[j] = (r1 << 16) | r2;
+ }
+
+ rank = matrix_binaryrank(bits, matrix_m, matrix_q);
+
+ if (rank == matrix_m)
+ fm_0++;
+ else if (rank == (matrix_m - 1))
+ fm_1++;
+ else
+ fm_rest++;
+ }
+
+ /* Compute chi_square */
+ term1 = ((fm_0 - (0.2888 * num_matrices)) *
+ (fm_0 - (0.2888 * num_matrices))) / (0.2888 * num_matrices);
+ term2 = ((fm_1 - (0.5776 * num_matrices)) *
+ (fm_1 - (0.5776 * num_matrices))) / (0.5776 * num_matrices);
+ term3 = ((fm_rest - (0.1336 * num_matrices)) *
+ (fm_rest - (0.1336 * num_matrices))) / (0.1336 * num_matrices);
+
+ chi_square = term1 + term2 + term3;
+
+ /* Debug message, not displayed when running via atf-run */
+ printf("fm_0=%u, fm_1=%u, fm_rest=%u, chi_square=%f\n",
+ fm_0, fm_1, fm_rest, chi_square);
+
+ p_value = exp(-chi_square * 0.5);
+
+ return (p_value);
+}
+
+ATF_TC(isc_rng_monobit);
+ATF_TC_HEAD(isc_rng_monobit, tc) {
+ atf_tc_set_md_var(tc, "descr", "Monobit test for the RNG");
+}
+
+ATF_TC_BODY(isc_rng_monobit, tc) {
+ UNUSED(tc);
+
+ random_test(monobit);
+}
+
+ATF_TC(isc_rng_runs);
+ATF_TC_HEAD(isc_rng_runs, tc) {
+ atf_tc_set_md_var(tc, "descr", "Runs test for the RNG");
+}
+
+ATF_TC_BODY(isc_rng_runs, tc) {
+ UNUSED(tc);
+
+ random_test(runs);
+}
+
+ATF_TC(isc_rng_blockfrequency);
+ATF_TC_HEAD(isc_rng_blockfrequency, tc) {
+ atf_tc_set_md_var(tc, "descr", "Block frequency test for the RNG");
+}
+
+ATF_TC_BODY(isc_rng_blockfrequency, tc) {
+ UNUSED(tc);
+
+ random_test(blockfrequency);
+}
+
+ATF_TC(isc_rng_binarymatrixrank);
+ATF_TC_HEAD(isc_rng_binarymatrixrank, tc) {
+ atf_tc_set_md_var(tc, "descr", "Binary matrix rank test for the RNG");
+}
+
+/*
+ * This is the binary matrix rank test taken from the NIST SP 800-22 RNG
+ * test suite.
+ */
+ATF_TC_BODY(isc_rng_binarymatrixrank, tc) {
+ UNUSED(tc);
+
+ random_test(binarymatrixrank);
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_rng_monobit);
+ ATF_TP_ADD_TC(tp, isc_rng_runs);
+ ATF_TP_ADD_TC(tp, isc_rng_blockfrequency);
+ ATF_TP_ADD_TC(tp, isc_rng_binarymatrixrank);
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/regex_test.c b/lib/isc/tests/regex_test.c
new file mode 100644
index 0000000..b5e88b3
--- /dev/null
+++ b/lib/isc/tests/regex_test.c
@@ -0,0 +1,1121 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
+
+#include <isc/regex.h>
+#include <isc/print.h>
+#include <isc/util.h>
+
+ATF_TC(regex_validate);
+ATF_TC_HEAD(regex_validate, tc) {
+ atf_tc_set_md_var(tc, "descr", "check isc_regex_validate()");
+}
+ATF_TC_BODY(regex_validate, tc) {
+ /*
+ * test regex were generated using http://code.google.com/p/regfuzz/
+ * modified to use only printable characters
+ */
+ struct {
+ const char * expression;
+ int expect;
+ int exception; /* regcomp accepts but is disallowed. */
+ } tests[] = {
+ { "", -1, 0 },
+ { "*", -1, 0 },
+ { ".*", 0, 0 },
+ { ".**", -1, 0 },
+ { ".*\?", -1, 0 },
+ { ".*+", -1, 0 },
+ { "+", -1, 0 },
+ { ".+", 0, 0 },
+ { ".++", -1, 0 },
+ { ".+\?", -1, 0 },
+ { ".+*", -1, 0 },
+ { "\?", -1, 0 },
+ { ".\?", 0, 0 },
+ { ".\?\?", -1, 0 },
+ { ".\?*", -1, 0 },
+ { ".\?+", -1, 0 },
+ { "(", -1, 0 },
+ { "()", 1, 0 },
+ { "(|)", -1, 0 },
+ { "(a|)", -1, 0 },
+ { "(|b)", -1, 0 },
+ { ".{", 0, 0 },
+ { ".{1", -1, 0 },
+ { ".\\{1", 0, 0 },
+ { ".{1}", 0, 0 },
+ { ".\\{1}", 0, 0 },
+ { ".{,", 0, 0 },
+ { ".{,}", 0, 0 },
+ { ".{1,}", 0, 0 },
+ { ".\\{1,}", 0, 0 },
+ { ".{1,\\}", -1, 0 },
+ { ".{1,", -1, 0 },
+ { ".\\{1,", 0, 0 },
+ { ".{1,2}", 0, 0 },
+ { ".{1,2}*", -1, 0 },
+ { ".{1,2}+", -1, 0 },
+ { ".{1,2}\?", -1, 0 },
+ { ".{1,2", -1, 0 },
+ { ".{2,1}", -1, 0 },
+ { "[", -1, 0 },
+ { "[]", -1, 0 },
+ { "[]]", 0, 0 },
+ { "[[]", 0, 0 },
+ { "[^]", -1, 0 },
+ { "[1-2-3]", -1, 0 },
+ { "[1-22-3]", 0, 0 },
+ { "[+--23]", 0, 0 },
+ { "[+--]", 0, 0 },
+ { "[-1]", 0, 0 },
+ { "[1-]", 0, 0 },
+ { "[[.^.]]", 0, 0 },
+ { "[^]]", 0, 0 },
+ { "[^^]", 0, 0 },
+ { "[]]\?", 0, 0 },
+ { "[[]\?", 0, 0 },
+ { "[[..]]", -1, 0 },
+ { "[[...]]", 0, 0 },
+ { "[[..5.]--]", -1, 0 },
+ { "[[.+.]--]", 0, 0 },
+ { "[[..+.]--]", -1, 0 },
+ { "[[.5.]--]", -1, 0 },
+ { "[1-[=x=]]", -1, 0 },
+ { "[[:alpha:]]", 0, 0 },
+ { "[[:alpha:]", -1, 0 },
+ { "[[:alnum:]]", 0, 0 },
+ { "[[:alnum:]", -1, 0 },
+ { "[[:digit:]]", 0, 0 },
+ { "[[:digit:]", -1, 0 },
+ { "[[:punct:]]", 0, 0 },
+ { "[[:punct:]", -1, 0 },
+ { "[[:graph:]]", 0, 0 },
+ { "[[:graph:]", -1, 0 },
+ { "[[:space:]]", 0, 0 },
+ { "[[:space:]", -1, 0 },
+ { "[[:blank:]]", 0, 0 },
+ { "[[:blank:]", -1, 0 },
+ { "[[:upper:]]", 0, 0 },
+ { "[[:upper:]", -1, 0 },
+ { "[[:cntrl:]]", 0, 0 },
+ { "[[:cntrl:]", -1, 0 },
+ { "[[:print:]]", 0, 0 },
+ { "[[:print:]", -1, 0 },
+ { "[[:xdigit:]]", 0, 0 },
+ { "[[:xdigit:]", -1, 0 },
+ { "[[:unknown:]]", -1, 0 },
+ { "\\[", 0, 0 },
+ { "(a)\\1", 1, 0 },
+ { "(a)\\2", -1, 1 },
+ { "\\0", 0, 0 },
+ { "[[][:g(\?(raph:][:alnu)(\?{m:][:space:]h]<Z3})AAA)S[:space:]{176,}", 0, 0 },
+ { "(()IIIIIIII(III[[[[[[[[[[[[[[[[[[^[[[[[[[[ [^ fX][:ascii:].)N[:a(\?<!lpha:])][:punct:]e*y+)a{-124,223}", 3, 0 },
+ { "(pP\\\\\\(\?<!\\\\\\\\\\\\\\\\\\\\\\lRRRRRRRRRRRRRRRRBBBBBBBBBBBBBBBB))kkkkkkkkkkkkkkkkkkkkk|^", 1, 0 },
+ { "[^[^[{111}(\?=(\?:(\?>/r(\?<(\?=!(\?(\?!<!Q(\?:=0_{Meqipm`(\?((\?{x|N)))))|))+]+]Z)O{,-215}])}))___________________{}", 0, 0 },
+ { "[C{,-218(\?=}E^< ]PP-Ga)t``````````````````````````{138}", 0, 0 },
+ { "[^h(\?<!(\?>Nn(\?#])))", 0, 0 },
+ { "[(\?!(\?<=[^{,37}AAAA(AAAAAAAAAAAAA])", 0, 0 },
+ { "[^((\?(\?:ms(\?<!xims:A{}(\?{*</H(\?=xL $(\?<!,[})))*)qqqqqqqqqqqqqqqqqq)]33333333333333333333333333333{[:graph:]p)-+( oqD]){-10,}-{247}_______________________X-e[:alpha:][:upperword:]_(______wwwwwwwww /c[:upperword:][:alnum:][:alnum:][:pun(\?{ct:])[:blankcntrl:]})*_*", 2, 0 },
+ { "[(\?<!:lowerprin(\?{t:]{}}){113,})[:punct:]IIIIIIIIIIIIIIIIIIIIIIII", 0, 0 },
+ { "PP)", 0, 0 },
+ { "(([^(\?<!((\?>\?=[])p.]}8X[:blankcntrl:],{-119,94})XmF1.{)-)[:upperword:])[:digit:]{zg-q", 2, 0 },
+ { "[^[({(\?#254}))Z[l][x50]=444444444444(4444444444u[:punct:]\?[:punct:(\?!])])", 1, 0 },
+ { "[^[^[^([^((*4[(^((\?<=])Ec)", 0, 0 },
+ { "(0)Y:8biiiiiiiiiiiiiiiiiii", 1, 0 },
+ { "[^w(\?!)P::::::::::::::(\?#::(\?<=:::::::::]\"\"{}[3333333333333333(\?<=33333(\?!)9Xja][:alph(\?<=a:])xB1)(PX8Cf\?4444)qq[:digit:])", 1, 0 },
+ { "([U[^[^].]^m]/306KS7JJJJJJJJ{})", 1, 0 },
+ { "[^[^([^[(\?!(\?>8j`Wg2(\?{,(\?>!#N++++(\?<![++++++)+44444444bA:K(\?<!O3([:digit:]3]}}}}}}}}}}}}}}}}}}}}}}}}LP})S", 0, 0 },
+ { "[({(\?{,(\?(=213}*))})]WWWWWWWWWWWWWWW[:alnum:])", 0, 0 },
+ { "[:(\?<=ascii:])", 0, 0 },
+ { "[U(\?#)(\?<=+HzE])[:punct:]{-207,170}\?s.!", 0, 0 },
+ { "{}z=jU75~n#soD\"&\?UL`X{xxxxxxxxxxxxxxxxxxxx(xxxxxx${-246,27}[:graph:]g\"{_bX)[:alnum:][:punct:]{-79,}-", 1, 0 },
+ { "[^{,-186}@@@@[^(\?{@@(\?>@+(\?>l.]}))*\\BCYX]^W{52,123}(lXislccccccccccccccccc)-*)", 1, 0 },
+ { "(x42+,)7=]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]", 1, 0 },
+ { "[^(*[:graph:]q/TH\?B(\?{P)]})uZn[:digit:]+2", 0, 0 },
+ { "([XXXXXXXXXXXXXXXXXXXXX[(:alnum:][:space:]i%[:upperw(\?=o(\?#rd:])) ", 1, 0 },
+ { "(@@@@)", 1, 0 },
+ { "{-18,}[:as[(\?>^[cii:]]{}>+{-46,}{,95}[:punct:]{}99999999999999])-{-134}'sK$wCKjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", 0, 0 },
+ { "(l[:alpha:(\?!]))", 1, 0 },
+ { "[[^(\?{]|JJ[:alph(a:]X{})B^][:lowerprint:]n-219{-32}{19,105}k4P}){,-144}", 0, 0 },
+ { "[[^]P[:punct:][:alpha:][:xdigit:]syh]|W#JS*(m<2,P-RK)cA@", 1, 0 },
+ { "([^((\?({\?<=)}){[^}^]{}])^P4[:punct:[]$)]", 1, 0 },
+ { "([(\?#:(\?{space:]}):{}{-242,}n)F[:alpha:]3$)d4H3up6qS[:blankcntrl:]B:C{}[:upperword:]r", 1, 0 },
+ { "([(\?:]))[:digit:]mLV.{}", 1, 0 },
+ { "[^PPP-[]{[,50}{128,}]111111111111111]p", 0, 0 },
+ { "[^([^([^([[^[([^[^[[2[[[[[[[[[[[[[^[[[[(\?(\?{:[[[[[[(\?([-[:ascii:]--*)", -1, 0 },
+ { ")!F^DA/ZZZZZZZZZZZZZZZZZZ", 0, 0 },
+ { "[[[[[[[((\?=\?(\?>([[[[[[[^[[[[(\?()[[[K(\?#))])))]7Y[:space:]{,-96}pP)[:ascii:]u{-88}:N{-251}uo", 0, 0 },
+ { "t[:x(\?<=digit:])eYYYYYYYYYYYYYYYYYY{,-220}A", 0, 0 },
+ { "[[({10,}[:graph:]Pdddddd(\?#X)])[:alnum:(]]L-C){,50}[:blankcntrl:]p[:gra(ph:]){66,}", 0, 0 },
+ { "[^[^]*4br]w[:digit(\?::]n99999999999999999)P[:punct:]pP", 0, 0 },
+ { "[:digit:]{67,247}!N{122})VrXe", 0, 0 },
+ { "[:xdigit:]^[:xdigit:]Z[:alnum:]^^^^1[:upperword:(\?=])[:lowerprint:]*JJ-", 0, 0 },
+ { "[[(\?imsximsx:^*e(){,3[6}](V~\?^[:asc(\?!ii:]I.dZ))]$^AAAAAAAAAAAAAAAAAAAAAAAA[:space:]k)]", 1, 0 },
+ { "W{,112}[:lowerp(\?<!rint:]$#GT>R7~t'\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"9,O).", 0, 0 },
+ { "[^{6((\?>\?:4}(\?<=G))f)KKKKKKKKKKKKKKKKKKKKKKKKKKKKKpppppppp(\?=ppppp]{,-101}|[:blankcntrl:]Z{-182})", 0, 0 },
+ { "([:punct:]@^,,,,,,,,,,,,,,,,,,,,,,,,,,0\?:-o8NPIIIIIIIII)pPKKKKKKKKKKKKKKKKKKKK", 1, 0 },
+ { "([^[[^[^]]]])", 1, 0 },
+ { "[([^[(333\"(\?#\\\\[)(\?isx-x:\"Tx]')", 0, 0 },
+ { "[[n>^>T%.zzzzzzzzzzzzzzzzz$&|Fk.1o7^o, ^8{202,-12}$[:alnum:]]G[:upperword:]V[:xdigit:]L|[:upperword:]KKKKKKKKKKKKYX\"\")xJ ~B@[{,-68}/][:upperword:]QI.", 0, 0 },
+ { "[^[]tN^hy3\"d@v T[GE\?^~{124,10(\?{2}]})\?[:upperword:]O", 0, 0 },
+ { "d.``````````````````````````[:up(\?=perword:]RRRRRRRRRRRRRRR)", 0, 0 },
+ { "[Z{{{{{{{{{{{{{(\?={(\?<!{{{{{{{{{(\?>{{J6N:H[tA+mN3Zmf:p\?]\?){-181,82}S4n.b[:lowerpri(\?{nt:]|ggggggggggggggggggggggggggggggg}))4)", 0, 0 },
+ { "[^((/////[^////[^/////////[(^/////]fI{240}{-120}+]R]GA)", 0, 0 },
+ { "[-(\?#.)(\?())[:alpha:](\?={(\?#}r)[:space:]PPW]o)", 0, 0 },
+ { "[:lowerp(\?{rint:]})201{46,}[:a[^scii:]0Q{37,}][:blankcntrl:]1331", 0, 0 },
+ { "[^(\?!(\?#)\\GIwxKKKKKKKKKK'$KKKKKKKK]l)bbb^&\?", 0, 0 },
+ { "[:ascii:]*[:sp(\?<=ace:])", 0, 0 },
+ { "({-66,}Z{})0I{-111,}[:punct(\?():])", 1, 0 },
+ { "[[^(\?!()%%%%%%%%%%%%%(\?:%%%%%%%%%%%%%%%%)t(\?{VX>B#6sUU(\?<!UUUUUU(\?=UUU[^UUUUUUUUUUUU(\?((\?:UPPPPPPPPPPP)PPPPPPPPPPPPPPP]ffffffffffffffffffffffff)^[:space:]wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww{243}9[:lowerprint:]Dv[:graph:])][:blankcntrl:]V%E[:graph:]})[:space:]{-83,}cQZ{}4{-23,135}", 0, 0 },
+ { "({,-76[}]O[:xdi(\?<!git:])\?5))))))))\?d[:lowerprint:]b666666[:graph:]c", 1, 0 },
+ { "{}{-145,}[:(\?(spa)ce:])f", 0, 0 },
+ { "[([^].{116,243}]T*[[^:punct(\?[{[^:(\?<!]]8()])[:alnum:])})]N{}{,243}*[n]][:graph:]", 1, 0 },
+ { "[^w]8888888888888888_________(__________[:ascii:]BdqTE$^0|MNto*i#############[^#################])", 1, 0 },
+ { "[^[[[<[()\?]GGG{,26[}[:alnum:]SSSSS.gggggggg[:graph:]CCCCCCCCCCC{79,}{138,191}][:di(git:]u]@]JJJJJJJJJJJJJJJJJJJJJJJ[:graph:(\?:][:alnum:]])[:alnum:])]", 0, 0 },
+ { "[^(((BBBBBBBBBB(\?>BBBZvvvvvvvvvv(\?m(sximsx:vvv)iiiiiiii)))j>Rs:Sm]0MMMMMMMMMMM|@F)Y]*^#EEEEEEE)*", 0, 0 },
+ { "([^([(U(\?!)<<<<<<<<<<(\?#<<<<(\?<!<<<)(\?=L.{73,})+]n9U}fk%Jn}'b Na<%yyyyyyyyyyyy)){-198,}]))[:space:].pP361U]3s@u_9AU Te/{s`6=IMZdL1|.ySRo", 1, 0 },
+ { "[[((\?<=\?>(\?#){}]{}`){1,82}){-143[,}]^G", 0, 0 },
+ { "[:digit:]W|[:up(\?<!perword:]{,-101}llllllllllllllllll[:upperword:])mmYYYYYYYYYYYYYYYYYYYYYYY*", 0, 0 },
+ { "@NHy)", 0, 0 },
+ { "([^[^]][:alnum:]222[^22222222(\?{2222222222222222][:lo(\?:werprint:][:xdigit:]^[:blankcntrl:]s+N)[:alpha:]-NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWxxxxxxxxxxxxxxxxxxxxxxxxxxD[:space:]U)TTTTTTTTTTfffffffffffzzzzzzzzzzzzzzzzzzzzzzzzz})", 1, 0 },
+ { "[^[^[[^[][^[]pP([^\?[^<=(\?=]){158,})]]]][:digit:]]K22222222222p^dUKJ`\">@]", 1, 0 },
+ { "[^[^[(\?imsximsx::p(\?{unct:][(\?>:ascii:]5w)]{159}\\Q\?@C]4(44444444}[^)|)[:graph:]]C:b)", 1, 0 },
+ { "[^[[(tYri[W<8%1(\?='yt][:lowerprint:[]))1r]][:alnum:][:digit:]{48}{-52,-183}+][:alpha:]r][:upperword:]\?{-105,155}{-55,-87}pPN#############################{63,232}]", 0, 0 },
+ { "[*(\?>L(\?<(\?>=))]&&&&&&&(&&&&&&&&&&&&&&&&&&))[|WIX]{-62,-114}S K=HW60XE<2+W", 1, 0 },
+ { "(00000000000)z\\\\*t{}R{88}[:alnum:]*", 1, 0 },
+ { "(([^(\?=\?gggggg[gLw)]{-250,}[:xdigit:]yZ[:g(raph:]8QNr[:space:][:blankcntrl:]A)][:digit:]D)[:xdigit:])", 2, 0 },
+ { "[^([^,(\?<!]*))]", 0, 0 },
+ { "[^(\?{[:alnum:]]}}}}}}}}}}}}}}}}}}}}}}}){-83}", 0, 0 },
+ { "WWWWWWWW[:alnum(\?<=(\?#:]{,-1})@OSSS)[:digit:]", 0, 0 },
+ { "[^(\?!*]+G)", 0, 0 },
+ { "[LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL>s8.>[^{}$(\?(]]XXXXXXX)XXXXXXXXXXXXXX[:alpha:]Whii\?p[:xdigit:])+", 0, 0 },
+ { "(7777[:blankcntrl:])", 1, 0 },
+ { "[^C[:digit:]]{}YYYY(YYYYYYYYYYYYYYYY)", 1, 0 },
+ { "on|,#tve%F(w-::::::::::::::::::::::::::::*=->)", 1, 0 },
+ { "([((\?=(\?!((\?=')))27(<{})S-vvvvvvvvvv(\?=vvvvvvvvvvvvvvvvv[:punct:][:alnum:]}}}}}}}}}}}}}}}}}}}}}}}PPPPPPPPPPPPPPPPPPPPPPPPPPPPPgggggggggggggggggggggggggg(\?#(\?#gggggg<X){}]{-164,61})>+))uQ)W>[:punct:][:xdigit:][:digit:][:punct:]{}[:digit:][:space:]){,-105}=xiAyf}o[:alpha:]akZSYK+sl{", 1, 0 },
+ { "[^[^]/S:Hq<[:upperword:(\?<=]W[:alnum:]X])1973", 0, 0 },
+ { "[[^[[^([^VVVV(\?!(VVVVVVVVVVVVVVVVVVVVV[VVVVX][^]2))98ppppppppppppppppppppppppppppppp/////////////////////b.]G{-101,}[:[ascii:]P].=~])AAAAAAAAAAAAA2{-153,}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]][:alnum:][:lowerprint:]WN/D!rD]|4444{180}]V_@3lW#lat]", 0, 0 },
+ { "[^[^([^TTTTT(\?:T(\?:T7777{,59}])[:graph:][:ascii(\?<=:]))f]AD{,-43}%%%%%%%%%%%%%%%%)S|[:digit:]FZm<[:blankcntrl:]QT&xj*{-114,}$[:xdigit:]042][:xdig[it:]{-180}027[:alpha:][:ascii:][:lowerprint:][:xdigit:]^|[:alnum:][^Mi]z!suQ{-44,-32}[:digit:]]", 0, 0 },
+ { ")", 0, 0 },
+ { "''''''''''[:a(\?imsxisx:lnum:])P", 0, 0 },
+ { "(([{20(\?<=8}[:alnum:]pP$`(\?#N)wRH[:graph:]aaaaaaaaaaaaaa(\?=aaaaaaaaaaaaaaaaP]a)))[:punct:]-\?)A^", 2, 0 },
+ { "[^(.//[:punct:]&-333333333333333333333333333(\?<!33)LLLLLLLLLLLLLLLLL[:alnum:]$1]~8]|^\"A[:xdigit:]\?[:ascii:]{128,}{,-74}[:graph:]{157}3N){-196,184}D", 0, 0 },
+ { "[^($(\?{(\?<=)[#)]})[:space:]]nWML0D{}", 0, 0 },
+ { ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,[^]x{213,-93}(\?{A7]V{}})", 0, 0 },
+ { "[k(\?=*)+^[f(])r_H6", 0, 0 },
+ { "[(\?#(\?{)]q})", 0, 0 },
+ { "([GLLLLLLLLLL(\?!((\?:LLLLLLLL]))C#T$Y))^|>W90DDDDDDDDDDD[^DDDDDDDDDDDDDDDDDDDD]B[:punct:]c/", 1, 0 },
+ { "[^(\?<!)(\?{b}){,199}A[:space:]+++++++(\?!++++++++{36}Tn])", 0, 0 },
+ { "()[:alpha:]a", 1, 0 },
+ { "[(\?(:blan)kcntrl:])lUUUUUUUUUUUUUUUUUUUUUUU", 0, 0 },
+ { "[^[^(s[[[[[[[[[[[[[[(\?#[[[[[[[)\?`````][:blankcntrl:(\?>]|)p1EmmmmmmmmmmmmmmmmmmmmmmmmmmmmL{-241}666666666666666666666)]^bLDDDDDDDDDDDDD]", 0, 0 },
+ { "[nn(\?<!nnnnn(\?#n8)=````````````````````{41,}]U,cb*%Y[:graph:]).[:alnum:]\\\\\\\\\\gt", 0, 0 },
+ { "()\?5{,-195}lm*Ga[:space:]Y", 1, 0 },
+ { "[(\?:].di)c", 0, 0 },
+ { "([([^([\?{})Za,$S(\?!p(\?{++(\?##V(\?<!Evuil.2(\?<![^[h|[^']C)*\"]5]", 1, 0 },
+ { "[((^24(\?#4[^Kkj{}))]]{232}47)077[:alpha:]zzzzzzzz{}", 0, 0 },
+ { "[^(\?:[^F]o$h)-iV%]", 0, 0 },
+ { "[[^[([((([^(\?{[^((\?=)kaSx(\?imsximsx:w3A[`%+A$I{,62}ns&Y!#ay o9YAo{Y>1((\?>\?#45)Z{,108}{}11111111111111111111111111qqqq)\?][:lowerprint:]mbo#)@", 0, 0 },
+ { "[^iii8(888888(\?<!8^]))s", 0, 0 },
+ { "([[(\?(\?:({^]}[)[(r)])G]{,-87}", 1, 0 },
+ { "([[^{249,}(\?>(\?=)]]T()[:bl(\?!ankcntrl:]=jjjjjjjjjjjjjjjj-)))t{}[:alpha:]-\":i! Gn[A4Ym7<<<<<<<<<<<<<<<<]", 2, 0 },
+ { "^{}{[^,241(\?#}(\?m(\?ixim:sximsx:]t))+oD)", 0, 0 },
+ { "5[(\?#:xdigit:])", 0, 0 },
+ { "[^f{(\?>,22(9}[^[^])6KKKKKKKKKKKKK)]RRRRRRRRfuK99999999C}osnNR]BgCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[:blankcntrl:]", 0, 0 },
+ { "[^(\?=U){24,}W-{,17(\?:3[^}]q.nQ#PU_|i$$$$$$$$$$$$$$+)[:dig(\?<!it:]){-98}\?[:upperword:]]", -1, 0 },
+ { "[(\?<=[0(\?!72])euE.]{,-159}[:alnum:]t-:l\?)$yyyyyyyyyyyyyyyyyyyyyyyyyyfffffffffffffffffffffffffff", 0, 0 },
+ { "[^[^]q[:asc(\?imsxmsx:ii:]JJJJJJJJJJJJJJJJJJJJ[:graph:]]$)`#DdY^qqqqqqqqqqqqqqqqqqqqqqqqqqqu>4^4ta[:alpha:]", 0, 0 },
+ { "(((b0HN)q))p5<T())`7JJv{'cv'#L8BNz", 4, 0 },
+ { "[pFp2VttBg(\?<=7777777777777|TTTTTTTTTTTTTTT[:space:]Z]^p\"[:blankcntrl:])", 0, 0 },
+ { ")aM@@@@@@@@@@@@@", 0, 0 },
+ { "([^[(\?<![^])", 1, 0 },
+ { "()Z[:ascii:]", 1, 0 },
+ { "(fuPPo)..........................[:xdigit:]{}{,4}*kkkkkkkCx#,_=&~)|.2x", 1, 0 },
+ { "[+(\?<=){}++++++[:alnum:](\?=+]s)[:alnum:]~~~~~~XXXXXXXXXXXXXXX.[:digit:]", 0, 0 },
+ { "[{}[^^(\?(]))CCCCCCCCCCCCCCCCCCCCEg2cF]{}3", 0, 0 },
+ { "([[[^[^[^([[^[^([(\?<=G[[)=(\?!===(\?isximsx:==(\?#==[^=====(\?{==================$T[[^^u_TiC.Fo.02>X)uH]$})354b[:alnum:]]]EVVVVVVVVVVVVVVVVVVVVVVVVVVVVVz[:digi(\?(t:][:upperword:])", 1, 0 },
+ { "([:blankcntrl:]t-){121,}[:ascii:]444444{}[:graph:]E040", 1, 0 },
+ { "[^{134,}]DzQ\?{-30,191})z,\?1Vfq!z}cgv)ERK)1T/=f\?>'", 0, 0 },
+ { "@v)<yN]'l-/KKKKKKKBBBBBBBBBBBBBMa2eLA[:digit(\?<!:])\"\"e|l$&m`_yn[:blankcntrl:]uuuuuuuuuuuuuuuuuuu[:punct:]", 0, 0 },
+ { "[[999999999999999(\?<=(\?:(\?ixmx:(\?>))])Y]|){,10}\?{}", 0, 0 },
+ { "([[[(\?!^]P-AA[AAAAAA[A[^A)r]+B]])", 1, 0 },
+ { "3}|[:ascii:][:punct:]()", 1, 0 },
+ { "()dw", 1, 0 },
+ { "[N]{})))))))))))))))))))))))", 0, 0 },
+ { "[[[^([[(\?()(\?#)++([^\?{+++[^+++++++++++(\?!+(\?=+++++++r9/n]N7{-219}{-91}pP[:punct:]T]mROm+~[:digit:][:digit:])Y:", 0, 0 },
+ { "[^'Pu[(\?<!D&]_a[:alnum:]E<,F%4&[:xdigit:])][:lowerprint:]", 0, 0 },
+ { "tttt(tttttttttt*uKKUUUUU)", 1, 0 },
+ { "([:ascii:]GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG)+kX______________{}GGGGG\?TUH3,{67,77}|[:graph:]C{,-136}{}[:upperword:[]{,-6}&]T84]n={C", 1, 0 },
+ { "[:upperword:]DC[:u(\?<=pperword:]*d`H0\?m>~\?N|z#Ar--SO{,-141}076)G\?{,-110}M+-[:alpha:]", 0, 0 },
+ { "{,-214}{,10(9})", 1, 0 },
+ { "([^xxxxxxxxxxxxxxxxxMMMMMMMMMMMMMMXW])].[:punct:]Q`{-63,63}Uua[:alnum:]\?OQssb#L@@@@@@@@(@@@)[:graph:]", 2, 0 },
+ { "[[^(\?!```[^``````````````(\?<=``(\?>````````M/////(\?!////////////////////[^GD!|#li]~)*.$]))Tq!]C[:lowerprint:]Qk[{}]]JJJJJJJJJJJJJJJJJJJJJJJ{e])c", 0, 0 },
+ { "$[5(7ES])[:xdigit:]%{MRMtYD&aS&g6jp&ghJ@:!I~4%{P\?0vvvvvvvvvvvvvvvvvvvv\\\\\\\\\\\\\\\\\\\\\\\\x54[:lowerprint:][:upperword:]", 0, 0 },
+ { "[((([(\?((\?>[:alnum:][):as(\?<!cii:(\?:]Re))K|)|^){-28,89}l<H.<H:N)QKuuuuuuuuw8E136P)^)[:ascii:]][:xdigit:]-", 0, 0 },
+ { "(pjvA'x]=D\"qUby\\+'R)r\?C22[:ascii:]", 1, 0 },
+ { "[]*b~y C=#P\"6(gD%#-[^FBt{}]${-244}", 0, 0 },
+ { "[:up(\?!pe(\?=rword:])lA-'yb\"Xk|K_V\"/@}:&zUA-)W#{-178,-142}(){-202,}", 1, 0 },
+ { "()1.WldRA-!!!!!!!!!!!!!!!!!", 1, 0 },
+ { "lZZZZZZZZZZZZZZZ(Z[:al(\?:num:])ttttttttttttttttttttttttttttttg.)6$yyy", 1, 0 },
+ { "[([^([^[^(([([^[^(([[$(\?{P(\?=(\?<(\?!=(\?#P[^Y])<GA[:ascii:][(\?#(\?<!:alpha:](B{100,})]}))\?)XU=", 1, 0 },
+ { "[[dVw{6(\?{9,}2222kkkkkkkkkkkkkkkkkkkkkkkkkk|{}*E]]{}SB{35}-w%{eh})<{-178,}", 0, 0 },
+ { "(D(~))", 2, 0 },
+ { "[(:alpha:]{,90}Z|)[:ascii:]Du\?[:grap[^h:]^w+|{}][:ascii:]", 0, 0 },
+ { "[:p(\?<=unct:]kkkkkkkkkkkkkkkkkkkk)", 0, 0 },
+ { "{}[:((\?<!dig((\?#it(\?#:]())p))ZZZZZZZZZZ[:blankcntrl:]){}{-124,})[:ascii:]", 1, 0 },
+ { "[[:graph:]{168}lRRRRRRRRRRRRR(\?#RRRRRRRRRRRRRRRRR)rrrr(\?(rrrrrr)rrrrrrrS[(\?<!@f)6>{,-49})q${98,}J\?]){", 0, 0 },
+ { "([:pu(\?(nc)t:]F{-32,-102}+)\?cpP[:lowerprint:].^)", 1, 0 },
+ { "([{}{210,-238}]1:h)", 1, 0 },
+ { "([]QQQQ[QQQQQQQQQQQQQQQQQQ][:digit:]Z{-20,}Slllllll[:space:]C^(@{-174,-156}fx{cf2c}{-242,}rBBBBBBBBBBBBBBBBBBc[:alpha:]N\?))$[:graph:][:ascii:]P+nnnnnnnnnnnnnnnnnnnnnnn1N$r>>>>>>>>>>>>>>>>>>>>>>>>(>>{,88}{,-234}__________)[:upperword:]R.[:alnum:][:lowerprint:]^}\"", 3, 0 },
+ { "([^(\?=]-))$", 1, 0 },
+ { "([:ascii:]\?,D[:upperword:][:xdigit:]tttttttttttt[^tt(\?<!ttttttttt21f|.(pP[:punct:])])rrrrrrrr)", 1, 0 },
+ { "([{1(\?=16}iiiiiiiiii((\?<=iiiiiiiiiiiiiiiiii|ZZZZZZZZZZZ(\?(\?#{ZZZZZZZ))c}))<<<<<(\?#<<<<<<<<<<<d7CVq8]w{-148,-168}\\Gp){-230,}D3", 1, 0 },
+ { "[^8888(88888888888EX].[:alnum:]){}", 0, 0 },
+ { "([^][^)2]-[:lower(\?=print:]{,79}[:graph:]n)", 1, 0 },
+ { "[bSi\?x_mp(C)0{64}[:space:]hhh(\?(hhh)hhL){5,130}'w\"$l&[:xdigit:][:alpha:]IIIIIIIIIIIIIIIIIIIIIII+-SOOOOOOOOOOOO (\?( ) ]f)ed", 0, 0 },
+ { "[[^[(^(C.Jl[^X&Rb64a+Sd])'m[:alpha:])]]]{134,}", 0, 0 },
+ { "()L", 1, 0 },
+ { "[[(({224,(\?#88})@======(\?!=========(\?{=)PPP)i^@p(\?([:punct:]})^^[^^^^^^^^^^^^^^^^^^^^^@)m]|{CS{,-3}168)-[:xdigit:][:upperword:]hnD=Bns)z)AAAAAAAAAAAAAAAAAAAAAAA[^A{}ccccccccccc)SZ]Q-p.sD]]+P", 0, 0 },
+ { "[[^[^]{135,}66666666666666666666[6(666i2M9.!uhmT\?JMm.*(\?!+)[:alpha:]eeeeeeeeeeeeeeeeeeeeeeeeeee]]])ZZ[:blankcntrl:][:ascii:]", 0, 0 },
+ { "(13[3Ux>{,10}[(\?<=:xdigit:]))PL9{-89,-181}F'''''''''", 1, 0 },
+ { "[^.|(\?{af]})^$XE!$", 0, 0 },
+ { "(WWWWWWWWWWWWWWWWWWWWWWWWWWWW#J)", 1, 0 },
+ { "({}}M7we-216)L[:digit:][:upperword:]", 1, 0 },
+ { "([:aln[^u(\?=m:]))].z", 1, 0 },
+ { "([:alpha:]{(92})%6{41,136})Vij@[:alnum:][:lowerprint:]", 2, 0 },
+ { "[[[++(\?{+++{}})n{{137,}{51,-177}Z[]M*[:ascii:]{(-29,-47}2)$e^{,-195}{-156,}^]{}{-225,69}A]{-222,}{,20}m[:blankcntrl:]", 1, 0 },
+ { ")l)[:alnum:][:graph:]g8TTTTTTTTTTTTTTTTLLLLLLLLLLLLLLLLL", 0, 0 },
+ { "[([(\?<=.(\?{)/})mmmmmmmm(\?(mmmmm]{-154,-176}*S)I]", 0, 0 },
+ { "[(([{(\?(\?<!im(\?imsix:sim(sx:,141}])D)l{,42}ttttt[(\?::punct:])){-162,-141}{-26,})dU@@@@@@@@@@@@@@@ S)\\A\?w|VVVVVVVVV)X.kN{,21}{-208,-52}>[:lowerprint:][:ascii:]e-]]]]]]]]]]]]]]]]]]]]]", 0, 0 },
+ { "[^({}(){(66(\?=,}[^]'''''QQQQQQQQQ).P#>^){86,168}Z[(\?<!:lowerprint:]{-166,-70}<k", 0, 0 },
+ { "APP[:alpha:][:alnum:]nd[:upperword:(\?(]^xxxxxxxxxxxxxxxxxxx)xxxxxxxxx{-70}[:punct:]l)U-", 0, 0 },
+ { "[^(.\"od~(6({[^(\?<!228}\?)\?)######(\?:#########z )c(\?<!aQ`(\?{UKSwu[})][^-17]{11,}}][:ascii:]))^RiH+WyspP[qi&)=p6])[:space:]{-221,}]6p", 0, 0 },
+ { "{-78}()[:xdigit:]{155}{,-92}", 1, 0 },
+ { "[(\?>Q{,147}_____________(\?!______uuuuuuuuuuuuuTr]){74,179}{}){,103}{-209,16}*RRRRRRRRRRRRRRRRw{,87}9{144}[:ascii:]'<Ab", 0, 0 },
+ { "([666c] {-171}yc,8-k_)EEEEEEEEEEEEEEEEEEEEE<", 1, 0 },
+ { "[^(\?>(\?<!)2(\?imim:)6HwN)^|fc!(\?(d]75))065)G", 0, 0 },
+ { "[[^xDB[:alnum:][:xdigit:]][:digit:]jW]([:alpha:])", 1, 0 },
+ { "[ds~T+[x55[:digit:]X[JJJJJJJ.[(\?::upperword:]){,-14}][:xdigit:]bbbbbbbbbbb", 0, 0 },
+ { "[qqqqq(\?<=qqqq(\?(qqq)^G[):ascii:]])W", 0, 0 },
+ { "[:space:]JJJJJJ[:alph(\?<!a:]|[:ascii:(\?(])[:x)digit:]- XSstG[:g(\?>raph:])^)Ny6RF_ndoU9@*rxW{4,41}4{}", 0, 0 },
+ { "[:punct:]{162,}j[:aln(um:].....................[^...]\?>z[:l[owerprint:]){55,222}]", 0, 0 },
+ { "(>vWa)OXcccccccccccccccccccccccc[:alpha:]C{,-10}81|m1D^T)[:lowerprint:]''''[:alpha:]l", 1, 0 },
+ { "(XZcgM/UI-/mZq-222){-85,-196}[:alpha:]{114}rrrrrrrrrrrrrrrrrrrrrrrr{,157}ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZLkD-&&&&&&&&&&&&&&&-][:alnum:]{}{,111}[:digit:]", 1, 0 },
+ { "[^(\?:]MMMMMMMMMMMMMMMMMMMMMMMMMMM)cK[KKKKKKKKKKKKKKKKKKKKKKKK]P{146}", 0, 0 },
+ { "([^[^wqesa)n\?L(\?<=FH+G[^rCGmfD]w)m1D\"%}]])", 1, 0 },
+ { "[((\?:[^.HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH|S)xd)*[:space:](])[:xdigit:]ngr'G#/B]-----------------------------", 0, 0 },
+ { ")[:lowerprint(\?<=(:]l))G p", 0, 0 },
+ { "[^[^(\?<(\?<(=(\?imsximx:![(((\?<!\?(^))\?]^)[:xdigit:][:graph:]{-104,})Gf+GD*qc)c]f))])", 0, 0 },
+ { "[^([\?())P[:alnum:]w]{-186,-139}-[:space:]RN3w[Fmvpl[:space:][:digit:]&&&&&&&&&&&&}(\?#}}}}}}}}}}}}}}}}}}}])z", 0, 0 },
+ { "([[^^*C[()f][(\?=:punct([\?#:]o)]V)]%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%[^x{1f948})]]", 1, 0 },
+ { "[(:xdigit:])zE", 0, 0 },
+ { "[:pu(\?(nc)t:])(a*){-51}", 1, 0 },
+ { "[^(.NKKKKKKKKKKKKKKKKKKKKKKKK-[:upperword:][:space:]`MPi>", -1, 0 },
+ { "Nvvv[vv.][:alnu[^m:]+|Crrrrrrrrrrrrrrrrrrrrr[:xdigit:]j1n)v#]", 0, 0 },
+ { "[^#}[(\?>:alnum:]).QQQQ[^QQQQQQ!!![!!!!!!!-s.n]se]{-238,}Tf]p4721", 0, 0 },
+ { "([((\?#\?<=)+)Hr:-H]z[:graph:].{}oooooo(ooooooooo][:punct:]k<gXG@@@@@@@@@@@@@@@@@@@{,-176}){}L`)$", 2, 0 },
+ { "({,249}{-73,}Z&&&&&&&&Ds35MB<v)qqqqqqqqqqqqqqqqqqqqqqqqq", 1, 0 },
+ { "[^.N][:blankcntrl:]))))))))))))))))))))))))))))))", 0, 0 },
+ { "(()*){198,}", 2, 0 },
+ { "{-237,}220{}[:ascii:]```````(`````````````\?{-115,185}){,-18}[:punct:]'|Kk", 1, 0 },
+ { "[(\?()])", 0, 0 },
+ { "([(\?#[:alnum:]CQ)}}}}}}}}(\?>}}}}}}}(}}}}}\?310[|))xA5r][[^:ascii:]^{,-156}{])CCCCCCCCCCC-145]FzwOD_u\?", 1, 0 },
+ { "[^[^[]{-163}{(-203}[(\?!:upperword:]PPGjZ[:xdi(\?=git(\?#:]{-73}s)qqqq(qqqqqqqqqqqqqqqqqq{173,210}[:xdigit:(\?<(\?>=]WW[^WWWWWWW\?*O)))Q){}08)[(\?(\?<=#:blankcntrl:]{90,}]U)])L)ooooooooooooooooooooooooooox--^c[:ascii:]])s)", 2, 0 },
+ { "[(\?!:punc(\?imximx:t[^:]4F<}!)]'M-)tKKKa4904", 0, 0 },
+ { "[^^{}\\(\?<!\\\\\\\\\\\\\\\\\\(\?#\\\\\\\\[:punct:](\?>)T000000000(\?(000)00000))+])", 0, 0 },
+ { "L[:p(\?#unct:])", 0, 0 },
+ { "[:upperw(\?<!ord:])", 0, 0 },
+ { "@$\"\"\"\"\"\"\"[\"\"\"\"\"\"\"\"\"\"[^(\"\"\"\"\"(\"\"][]))*U{223,138}*o```````````````(\?=[```````````````]{238}mmmPPPPPPPPPPPPPPP&&&&&&&&&&&&&&&&&&)sF$[:digit:[]]", 0, 0 },
+ { "[^#Txx[xxxlPB(\?><[^U/)]]{}X3333333333(3333333f*])", 1, 0 },
+ { "<<<<<<<<<<<<<<<[^<<<<<<<<<.][(\?#:ascii:])[:xdigit:]|^", 0, 0 },
+ { "([:punct:]{}){-167,}{-59,}Pd\"", 1, 0 },
+ { "[((\?#{,214})t$)VVV[:xdigit:]{104(\?<=}D][:graph:])|H){1,}{-176,}", 0, 0 },
+ { "[[([[^N,,,,,(\?=,,(\?#(\?:,,,,,,,,,,,[^,,,,,,,,,,]<,~4::_.A]){-52,}-[:alnum:]Pnnnnnnnnnnnnnnnnnn)d", 0, 0 },
+ { "{-18(3,})uT{4,}", 1, 0 },
+ { "[^[^[(p+c(\?<!b$))(\?:EU(\?(.][^{}]3[:xdigi[^t):][:punct(\?>:])[])][:s[^pace:]][:alnum:][:alpha:]]kw06E", 0, 0 },
+ { "[^^^^^^JJJJJJJJ(JJ(\?=JJ(.6[:space:]H]{231,}A^eqqq)[:ascii:(\?>(])[(\?>:spa(\?:ce:]xxxxxxxxx)@_t-))138GNNNNNNNNNNNNNNNNNNNNNNNNNN[:digit:]no!`#E\?&[:lowerprint:].)[:graph:]{86,}[:digit:][:alnum:]", 0, 0 },
+ { "[:g(\?<=raph:]a{114,146}(){}0Y[:bl(ankcntrl:])D)\?", 1, 0 },
+ { "[^[^]*H{-192,96}S|]G)6B-kLB", 0, 0 },
+ { "[[^[^][/NS8`um(\?{82&{((\?{\?<!-[110,-88}]m)})kkkkkkkk$$$$$$$$$$$$[^$$$$$@n%BuK@X!P)y0v!^]YY[YYY[YYYYYYYYYYYYYYYYYY///////{}{{{{{{{{{{{{{oiiii})]8{-2[53}w{82,}]{,245}]{-134}]fffffffffffffffffff]\"I>DW>9tN%{113}{unE", 0, 0 },
+ { "[:(\?(alpha:]`))Y2sCqWQ104", 0, 0 },
+ { "(([^()Wcccccccc(\?{cccccccccccccccccc(\?<!c(ccccc[:space:]$)(\?>)FZ{}{}`|||||||||||||*````````````````````````````'=dLQmx/Y.A7j'o}jn{}:})][:punct:]$|,-)!&Y:Ys#ykL7JJJJJJJJJJJJJJJJJJJJJJJJJ8yex>#mv[:punct:](x@)$[:uppe(\?<!rword:])_)", 3, 0 },
+ { "[[(^HHHHHHHHHHHH(\?imsximx:HH(HHHHHH(\?{HH[HH])qjR>9))i})]a!lBW3p{A=or)ShE%[:punct:]{}]5r", 0, 0 },
+ { "[:pu[nc[^t:]]]}}}}}}}[}}}}}}}(\?#}])@@@@@@@@@@@@@@@@@@DDDDDDDDDDDDDDDDDDD\?]xA2\?", 0, 0 },
+ { "(.[:alpha:]xB7[:alnu(\?{m:]})RRRRRRRRRRRRRRRRRRRRRRRRRRRL)[:space:]G\?", 1, 0 },
+ { "[:blan(\?<!(\?=kcntrl:]){71,})!ooooooooooooN", 0, 0 },
+ { "()e$$$$$$$$$$$$$$$$$$$$iiiiiiii", 1, 0 },
+ { "(b[:ascii:]67777777777777777777777777)({-106}kkk^F-------------------------------{13}A)f00000000sBAddddd{-66}kd!D'", 2, 0 },
+ { "(Q ^])[^lf][:space:][:lowerprint:]\?", 1, 0 },
+ { "[[^]\\S{152}W![:digit:][[^:space:(\?(]=pEhwY][:alnum:][:digit):][:graph:]])QQIC9h-oowf[:xdigit:]{-52}{,190}1111111111111111111fX{-189,226}W", 0, 0 },
+ { "[^(\?!(\?<=)]).h[:as(\?>cii:])[:alnum:]$$$$$[:space:]3$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$1", 0, 0 },
+ { "[[$zQ================(\?<!=(\?>=========(\?====D[^))|i{}\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?)][:s(pace:]]))]", 0, 0 },
+ { "[^{,-[15(\?#6}]Vwjjjjjjjj[jjjjjjjjjjjjjjjjjjS9999)]q]rWWWWWWWWWWWWWWWW[:punct:]@@@@@@@@@@@@@@@@@@@@@@@@gO[:blankcntrl:]>L[:ascii:]:::::::::::::::::::x11uuuuuuuuuuuuuuuuuuuuuuuuuuuuu{-124,114}[:graph:]C#{tcg[:xdigit:]gZZZZ[:lowerprint:]nA(_{{{{{{{{{{{{{{{{{{{{SS)\\D[:alpha:]", 1, 0 },
+ { "[^(\?())]!T\?[:asc[^ii:]E:4},,]I[^b(\?:n4(njj~+{\?'k{7}{189,-194}{ig.[[[[[[(\?#[[[_bs6,JD`1(\?<!WBo]F+{d*VO22z2K1][:xdigit:]))Suuuuuuuuuuu[^u{,117}\?YYYYYYYYYYYYYYYYYYYYYYYYB^]|q]:eY1GGGGGGGGGGGGGGGGGGGGGGGGGGGGe\?)bU[:punct:]", 0, 0 },
+ { "[\?UA(\?:]\?)[:xdigit:]A^mmmmmmmmmmmmmm>>>>>>>>>>>>>>>>>>>>>>>>>>>>[^>>>(\?(>)){,-165}]", 0, 0 },
+ { "([^[][^n(\?{[[p]#})|][^]L|66666666666[:graph:]][:graph:]2[:xdigit:][:space:]9b})[:digit(\?imsximsx::]+PZ):{}|E)[:xdigit[^:]|>]^[:alpha:]::::::::[:ascii:]````[:ascii:]:", 1, 0 },
+ { "[:lowerprint(\?<!:])", 0, 0 },
+ { "[[^[]{-47}[:lowerprint:][:punct:]L[(\?::g(raph:]lY[:alnum:])qWYU)}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}[c%$dp5[:alnum:]DDDDDDDD^^%&{,-94}E]{-8,175}[:alpha:]-.^[:digi(t:]CCCC(CCCCCCCCC]).ax72)", 1, 0 },
+ { "[[^($$$$$$$$$$$$$$$$$$[^$I((\?{\?(u)\"YuK ZpOHq[!(\?>t|LQT(|)L[(:ascii:])", 0, 0 },
+ { "[^[^([:graph:](QpPdyDQ`[:alpha:](.X[:digit:]wwwwwwwwwwwwww(\?imxims:wwwwwwwe(\?<!z)ONNN(\?#)[^])[:space:](KKKKKKKKK{113,}327[:xdigit:]k)]CeeeeeeeeeeeeeeeeeMMMMMMMMMMMMMMMMM)[:lowerprint:]]HHHHHHHHHHHHHHHHHHH]]]]]]]]]]]]]", 1, 0 },
+ { "[Q(r(\?=)v]dm[:alnum:][:b(\?{lankcntrl:][:xdigit(\?=:])})P[:graph:]bd/Rx){50}{-150,-172}", 0, 0 },
+ { "[(\?(im(\?:sxims:))9]))L", 0, 0 },
+ { "[[^[(\?{^Z][^0[:alpha:]]\\XB*{-151}t})][:alnum:]]", 0, 0 },
+ { "[([(D\?/////////////////////.'yvYysU&5AU-]kV)*){,123}z]", 0, 0 },
+ { "[:alnu(\?{m:][:a(\?=lpha:][:alpha:])n}))7[:ascii:][:xdigit:][:punct:]-", 0, 0 },
+ { "[^[:graph:]IIIIIIIIIIIIIIIIIIIIIII][:sp(\?<!ace:])", 0, 0 },
+ { "[[[(\?=[[[cDD(\?<!D(\?:DDDDDDDDDDDD(\?<=DDD(DDDDDD(\?:DDDDDDD(\?<=D(\?()])rvp{243,}D$<[:space:]([:lowerpr)int:])])Ea{}U[:upperword:][:xdigit(\?#:]or}Z+34gD{/P NJ", 1, 0 },
+ { "[^(,H>)*d2K0DNX5)T(].)[:digit:].", 0, 0 },
+ { "([:punct:(\?#])})JJJJJJJJ[:xdigit:]PPUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU.......................0hSk{,89}[:xdigit:].[:xdigit:]Z", 1, 0 },
+ { "(LGTTTTTTTTTTTTTTTTTTTTTTTTTT[:alpha:]){-106,113}[:punct:]d|[:digit:]kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\?wP", 1, 0 },
+ { "([^[^<N_-k\?{(\?#18}]i]::::::::::::::::::::::::::)1+LLLLn{}/){-198}", 1, 0 },
+ { "([[^(AAAAAAAAAA(\?(AAAAA)AAAAf).LzHHHHHHHHHHHHHHHHHHHHH(\?#HHHHH|)[ZEEEEE(\?#EEEEEEEEE(\?<!EEEEEEEEsG)q[:punct:]{}][:upperword:]D)[:space:][:digit:]+e[:ascii:]].i|JJJJJJJJ+n][:xdigit:]Se)P[:lowerprint:]_______________________________.[:punct:]pP{-172,86}iiiiiiiiiiiiiiiiiiiiiiiii){,-178}", 1, 0 },
+ { "([\?=[[^,BDRRPZ{129}*D-[:punct:]]])([:upperword:]ud)\?][:punct:]A", -1, 0 },
+ { "(([(\?#((\?{\?=^])c-)C[:lowerprint:]xvkR}k\")ccccccccccccccccccccNNNNNNN[:alp[ha:]{,93}vhlX:|A]2})nSw)]N.", 2, 0 },
+ { "()g/qzyiV(x3d|A0wllllll){162}[:space:]", 2, 0 },
+ { "qqqqqqqqqqqqqqqqqqqqvvvvvvvvvvvv8[:x(\?imsxmsx:digit:][:alpha:]''''''''''''''''''''''''''')", 0, 0 },
+ { "({,226}nf^W=vs$xK^=A=M#b,)V", 1, 0 },
+ { "(_T 2BC9N'cccccccccc-87EF#&^eQfDDDn._,m&c`tjAwR #~A)[:(\?imsimx:alpha:])/yHYL6|{-40,47}", 1, 0 },
+ { "[[^]{-8(4,138})z[:xdigit:]{180,}]", 1, 0 },
+ { "[([^T____________________(\?:__C(\?<=]-)])+[:ascii:])r[:graph:].----------", 0, 0 },
+ { "[f{}LLLL(LLp((((\?<!((((((((((((((({,56}]BR`{,52}){-22,}\?[:space:]h>Sow", 0, 0 },
+ { "{-179}^[:alpha:(\?!].a'5wacA3\\\\\\\\AAAAAAAA)~^]wC", 0, 0 },
+ { ">[:digit:]{,-212}+(`)LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL[:ascii:][:digit:][:space:]", 1, 0 },
+ { "[[^[[^RBW{,255(}(\?(\?>=(W)_]uu][:blankcntrl:])O)]]", 0, 0 },
+ { "(C_______________________________)2", 1, 0 },
+ { "([/ntf_a3].)", 1, 0 },
+ { "[:space:]+[(:upperword:],c7[:asci(\?<=i:]ggggggggggg)[:ascii:]/1$$$$$$$$$$$$$$$$$$$$$$$$$$)", 0, 0 },
+ { "Xq{109}~EEEEEEEE[:upper[^word:]lgB:X(h[:alpha:]B[:space:]].)IkaH@3}}H'yK~\?[:upperw(\?#ord:(\?:]){=================[:blankcntrl:])", 1, 0 },
+ { "(([[^]]$3Xr^$%%%%%%%%%%%%%%%%%%%%%================U[:ascii:])X).FFFFFFFFFFgO[:punct:]oooooooooooooooooooBC[:blankcntrl:]mmmmmmmmmmmmmmmmmmmm[:lowerprint:]rBM~<HAc#Sb&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Cy", 2, 0 },
+ { "([([([^(\?:)D]-{M#H >rERRRRRRR[^RRRRR(\?>RRRRR])[(\?=^)X]{207,}U])))Z[:blankcntrl:]]yyyyyyyyyyyyyyyy\?", 1, 0 },
+ { "[Q(\?{*[^(\?(\?!!])[:graph:]]})[:alnum:]iE)dGGGGGGG[^GGGGGGGGGG[:xdigit:]w]", 0, 0 },
+ { "[^Z(\?!6(\?(\?><=)[:graph:])]BBBBBBBBBBBBBBBB^)", 0, 0 },
+ { "[[^([^[^][[[[[[[(\?({[[(\?(\?imsxmsx(\?imsi[ms:::[[[[[[[[[}))]$)){12,})|:::::::::::::::::::[:lowerprint:]{}{-96,-147}){13,}`[:digit:]]\"^Ca%%%%%%%%%%%%%%%%%%%%%%%%%%UUUUUUUUUUUUUUUUUU]]9", 0, 0 },
+ { "[^(\?(\?(\?#!<=))JLBS\"zi)'''''''''''['''''''''''''piiiiiiiiiiiii(\?<=iiii]])ZZZZZZZZZZZZZZZZZZ[:space:]", 0, 0 },
+ { "({})[:punct:]", 1, 0 },
+ { "E9[:blankc(\?{ntrl:]})N", 0, 0 },
+ { "[:alph(\?#a:]){198,}sq\?X0B7", 0, 0 },
+ { "[^\\\\\\\\(\\\\\\[\\\\\\\\\\\\[(\?<(\?isximsx:={11(\?(9,}\?0])]]))\?FN3M\?{-128,}Z444444)444fbLiVN8)", 0, 0 },
+ { "[[^[^([[[[[[[[[(\?>[[[[[[[[[[[[[[[[[[[[[{53(\?<=,-175(\?>}ggggggggggggggggg%))[:alnum:])[:punct:]kkkkkkkkkkkkkkkkkkkkkkkkk)+Soooooooooooooooooooooooooooooooo](WR+--)x36+llllllllllll{,35}]Fqb^=F]KKKKKKaaaaa{,131}", 1, 0 },
+ { "(g\"Ssqw<&{Cl{82,}Mdf|9cIlmCW{}[:digit:]4C{}[:alnum:]PP)", 1, 0 },
+ { "OOOOOOOU[*evVIIIIIIIIIIIIIIIII(\?#(\?#IIII)]PP[:xdigit:]2222222222222222[:xdigit:]Kx)p[:digit:]", 0, 0 },
+ { "([[{248,16(\?=5(\?#}][:alpha:])|[:p(\?!unct:(\?(]", 1, 0 },
+ { "[pP((\?=S)(\?#)]$[:aln(\?(um:)]2\?)$GGGGGGGGGGGGGGGGG({-U:c){-61,}[:ascii:]{-202}G", 1, 0 },
+ { "()$D[:alnum:]", 1, 0 },
+ { "[(\?#^]){}[:ascii:]", 0, 0 },
+ { "[uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu]FFFFFFFFFFFFFFFFFFFFFF&2e\?)%oP'mc@z2b}n{<b4_Laz^0LLLLLLLLLLLLLLLLLLLLLLL,,,d", 0, 0 },
+ { "{}(^________________''|$)RRRRRRRRRRRRRRRRRRR", 1, 0 },
+ { "(H)####################bbbbbbbbbbbbbbbbVSSSSSSSSSSS|tdU\"goeAbPP{-248,81}", 1, 0 },
+ { "[^[(\?ims(\?>xisx:)UHpP*n{}]{}fx14<7OEpE>n2150)8888888888888888]^GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGS", 0, 0 },
+ { "(d)+", 1, 0 },
+ { "[^.(\?(>)(\?=e)])al[:space:]x", 0, 0 },
+ { "[^256c(\?!]){-19,}", 0, 0 },
+ { "Q)", 0, 0 },
+ { "[^s\?\?(\?{\?\?\?(\?#\?(\?<!\?\?\?\?\?\?\?\?\?\?\?(\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?{}]F\?j(jjjjjjjjjjjjjjjjjjn)kTI1f[{1|(\?<=^[^+[:digit:]{}^s^))})))T]{-17}{CCCCCCCCCCa{-21,}{,-146}^uZQB]YuLu-|tUGRMz^^", 1, 0 },
+ { "([^.{}.EE[EEEEEEEE(\?<=EEEEEEEEEEEEEEEU]]-@s))$", 1, 0 },
+ { "[^([((\?#[#])|a)])[cccccccccccccccc][:digit:]LLLLLLL[:alnum:]}[P%vzl{}^]&", 0, 0 },
+ { "({}[:space:]E)101+A{-35,11}", 1, 0 },
+ { "(va:7)u[:alpha:]", 1, 0 },
+ { "([^[[rrrrrrrrrr(\?:rrrrrrrrrr(\?<!rrrrrrrrry|D'*AH@a{}\?[:space:][:alpha:]^]$ {-225}[(\?(:as)(\?(>cii:])){-107,-139}6/{^[:upperw(\?imsxmsx:ord:]{,-47} ]wuH#nAn)GGGGGGGGGGGGGGGGGr[)]T{91}lJ))[:lowerprint:][:xdigit:][:lowerprint:])]*", 1, 0 },
+ { "()[:space:]~!$[:alnum:]JJJJ[:ascii:]", 1, 0 },
+ { "[^(\?<=)-]()k", 1, 0 },
+ { "(()W){,8}ea", 2, 0 },
+ { "({,-56}5G&&&&rrrrrrrrrrrrrrrrrrrrrrrrrrk.8) hWJ,TM)0Yd-", 1, 0 },
+ { "(Z-fddddddddddddddddddddddd)-{9}", 1, 0 },
+ { "[^<[(\?!:asc(\?:i(\?<!i:])F])[:alp(ha:]b))-}Wwx8B", 0, 0 },
+ { "[^[^[^([(\?{}(\?=)(\?())-CCCCCCCCCCC(\?=CCCCCCCC(CCCCC(\?:CCCCCCCC(\?{l[(\?!:space:]})[:upperwor(\?:d:]{-27}[:al[^pha:][:xdigit:]^f", 0, 0 },
+ { "[[^]G@>2!+[:punct:(\?<!]{,189}6ZF[:blankcntrl:][:digit:]{,214}){-115,-14}l[:upperword:]{101,}Z[:ascii:]Ld&02|c]<0~<bc", 0, 0 },
+ { "(Q)[:digit:]x", 1, 0 },
+ { "hT[[:alnum:]\?]O[OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOxFF%^(\?(_LN 8uXQT\"*/L)+l)>qQ[^]e[:ascii:]PP()[:digit:]NQ8%6d=&2I{-62,-142}w]].e{}*", 1, 0 },
+ { "{,-219}xxxtEEEEEEEEEEEEEEEE[:pun(\?(ct:])qqq)nnnnnnnnnnnnnnnnnnnnnnnnnnn", 0, 0 },
+ { "[:di(\?>git:])W4", 0, 0 },
+ { "([^y])Fkvto$", 1, 0 },
+ { "[^($$$$$$(\?!$$$$$(\?{$$$$$$(\?<=$$$$$$$$$$$+===)[:alnum:]MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM)Z]{}^[:blankcntrl:]--xxxxxxxxxxxxxxx[^xxxxxxx)\?tVG\?{232,81}{121,}xn{,-226}})tttttttttttttttttttttttmu(\?<!&&&&&&&&&&&&&&&&&&&&&&0b]z)$87{,-192}{}{-242,}", 0, 0 },
+ { "l[:dig(\?(it:]|s*)aA[:digit(\?<=:].^.))x[:digit:]", 0, 0 },
+ { "[:grap[^(\?#h:]').]Z", 0, 0 },
+ { "[:gra[^ph:]t[:digit:]222222222222(22222222222222222H qM]pWZr[:ascii:]-hRb_.)Q{-228,-204}{}", 1, 0 },
+ { "AAAAAAAAAAAAAAA(AA)YeX", 1, 0 },
+ { "(!dqqqF*^){(,-79}s!!!!!!!!!!!!)", 2, 0 },
+ { "[^(\?msxm(\?#sx:]|)ZHYup)j{95}0L:vXB#')d'DX\?m.T034\\\\\\\\\\\\\\\\\\\\\\y5rV{}S", 0, 0 },
+ { "(W*O+yl([\?!P(\?:)I]${}{-195,-14}[:upperword:]{}[:xdi[^git:][:space:]X[:grap[^h:]~]zzzzzzzzzzzzzzzzzzzzzzzL)+)Y b.-=jf{-216,}${/!}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|]", 2, 0 },
+ { "[^\\\\\\\\\\(\?<=\\\\\\\\\\\\\\\\m]{-48,234}[:alpha:]s)", 0, 0 },
+ { "[(\?{U}(\?<!)])LLLLLLLLLLLLLLsssssssssssssssssssssssssss[:ascii:][:blankcntrl:]---------b", 0, 0 },
+ { "[^[^[(\?#)(\?imsxims[x:)<<<<[<<<<<<<<<<(\?<!<<<<<<<([^\?(<<<<<<<<<<z(\?(zu(\?<=~83}aZpIE)[:alnum:](\?imsximsx:(\?!jrE6(\?<!\?V(SzDU)000[000000000((\?=\?)=0])L|lOYuWXk", 0, 0 },
+ { "$o[:dig(it:]nnnnnnnnnnnnnnn{-94}|G)[:alpha(\?!:] {,-108}D=\?>[:digit:]S[:space:]t", 0, 0 },
+ { "()n", 1, 0 },
+ { "[:upp(erword:]$)<}.vZM<lEY5Y*", 0, 0 },
+ { "[^([^\?>)rCD&{5(\?msxisx:7,}qqqqqqqqqqqqqqqqqq{31,}@w#W:(@(\?:zp$YYYYA[:alpha:]{1}A)*dZJ\"5OG|\?(\?#a])]|){-150}[:xdigit:]", 0, 0 },
+ { "[($)gwo{`\"]{-160,}\\\\\\\\\\\\\\\\\\\\\\\\\\66666666666666888888888888", -1, 1 },
+ { "((}DA+Rc000000000000000000)%vvvvvvvvvvvvvvvvvvvvv%C&emZ*[:alnum:]#m/D[:graph:][:blank[^cntrl:]E{,168})kkkkkkkkkk000000000000000]", 2, 0 },
+ { "[^[u*(\?#x01234)oxGGGGG(\?([GGGG)GGGGGGGGG]^U)!!CCCCBM`4QB^XEN]{,-60}[:upperword:]G]", 0, 0 },
+ { "(%)~t{S,K^MI3PMo)=b", 1, 0 },
+ { "[[[^]{}eU([:xdigit:]&&&&&&&&&&&&&&&&&)\"W|43[:alpha:][:graph:]J8b[:blankcntrl:]gggggQ{,183}{,-254}\?[:ascii(:]{,134}", 1, 0 },
+ { "[[([^[^([^(\?=)1RRRRRRRRRRRRRRRRRRRRRR(\?:(\?(\?(\?!=#RRRRR(\?=RRRR(\?<[^!Ru)])]o[:[graph:[^]{,7})[:digit(\?::]{-215,}e[:space:]]", 0, 0 },
+ { "({{{{{{{{{{{{{{{{{{KKKKKKKKKKKKKKKKKKKKKKKKKKKKBBBBBBBBBBBB)[:space:]0[:alnum:]HcctQA", 1, 0 },
+ { "[^(pP7(HsN[^g{186,-87}\?\?]EQ%u:-Y)+>>>>>>>>>>>>>>>>>>>>>pP][:alpha:]", 0, 0 },
+ { "[(.{141}h|)((\?:\?=@Q} ghcC{+*(R)D+][:lo(\?#werprint:]zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz))", 0, 0 },
+ { "[^({}S)PPFl(])-216", 0, 0 },
+ { "[([[^(((([(\?#^[^[^\?4[(:[dig[^it(\?(:]{122,})y\?", 0, 0 },
+ { "[[2${188}u{1(4(\?(1,1(\?{98}e{&tbaoI]q)[:punct:])d}))Nqffffffffffffffffffffffffffff[:ascii:]+]", 0, 0 },
+ { "()K-", 1, 0 },
+ { "[[{2(2((\?(\?!()2})])[:alpha:]fVVVVVVVVV{-47}):::::::::::)\?vwyyyyyyyyyyyyyyyyyyyyyyyyy-]{}", 0, 0 },
+ { "ivcs)g", 0, 0 },
+ { "(hhhh[^hhhh(\?{h\?]})%%%%%%%%%%%%%%%)\"+38mbY:s9{/d# zaNnbQb)b:*zpKI{-26,-189}", 1, 0 },
+ { "S*(#)[:graph:]lllllllll&G)t", 1, 0 },
+ { "([^[(([\?=\?<!)]]___{-63,})]nt", 1, 0 },
+ { "[:b(lankcntrl:][:alpha:]*[:pu[^[nct:][:alpha:]A]$aaaaaaaaaaaa*)A[:digit:]U][:alnum:]", 0, 0 },
+ { "[^f[^p000{68(\?isxmx:,}(\?!vvvvvv)$)]PP#*{(})[:punct:]&&&&&&&&&&&&&[:punct:]\?][:blankcntrl:]", 1, 0 },
+ { "[^(((\?(\?(()))GGGGGGGGG{(\?!($)))((\?!)V^{228,145}))]{-229}Qjjjjj[:punct:]R)", 0, 0 },
+ { "[(Q[^((\?{(\?:]~z)})gE(.<){}|)Kuuuuu$*222222222222222222222D]", -1, 0 },
+ { "([^`(\?<=`````[^`````````M]\?)=L74A[:upperword:]]P", 1, 0 },
+ { "(({}[:space:]qv-T){,-192}{-45}{65}9\?X).d", 2, 0 },
+ { "_[(:upperword:]mU(P}qX>\?%)$Lwq[:alpha:]{-115,}================================{127,}", 1, 0 },
+ { "e)", 0, 0 },
+ { "[{,2[5}Klen+D0'YX(\?<=|_H]I,Y\"*/<3sM[:digit:]])#.", 0, 0 },
+ { "[:(xdigit:]){[:digit(\?mxmsx::][:as(\?<=cii:]d!{135})#)pP[:space:]Syyyyyyyyyyyyyyyyyyyy\"Gg8", 0, 0 },
+ { "[(\?()])", 0, 0 },
+ { "[^([^[^[[^[:alpha:]SIus[^f<f]}}}}}}}}}}][:xdigit(\?=:]Z{-13}*]_[]LLLL)]E[:alnum:]b$)]]]]]]]]]]]]]]]]]]]]]]]]][:lowerprint:][:ascii:]{,40}{86,}333333333999999999999999999999999999*fffffffffffffffffffffffff99999999U9|[:digit:][:upperword:]oowwwwwwww[wwwwwwwwww{195}[:xdigit:]]H{-73,153}R+zAz{}r/////////////{232,}kAoffffffffff[:blankcntrl:]xxxxxxxxxxxxxxx]KKKKKl0,[:alpha:]|{,-165}Qc{96}CCCCCCCCCCCCCCCCCCCC/", 0, 0 },
+ { "{}:V(7O-)[:ascii:][:graph:]PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP#", 1, 0 },
+ { "[^(\?<[^=CC(CC$)]* c)BBBBBBBBBBBBBBBBBBBBBBB]z{-18,}", 0, 0 },
+ { "[[qqqqqqqqqqq(\?(qq235|ttttttttttttttttttttttttttttt[[ttt<<<<(\?{<<<<<<<<<<<<)<<<<<<<<p)/S9(\?{OOOOOOO(\?<!OOOk)})]nIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIb]Z})", 0, 0 },
+ { "[^[^(\?>][^((\?<!C(\?!+(\?=)]^8)6nx).)){,-13}[:blankcntrl:]\"(L{}){,29}nnnnn{-83}]l[:upperword:])", 1, 0 },
+ { "[(ZZ\"#(\?#Nb(\?<!:U)oRRRR])Zei${Ec/)s", 0, 0 },
+ { "[^[^[(\?(t(\?:3```````)`````)|#CB)/////////////////////////////*!liB#|CCCCCCCCCCCCCC(\?=CCCCCCa7N]weTTTTTTTTTTTTTTTT1{}o\?{}BBBBBBBBBBBBBBBBBBBBBBBB.])u{-218,126}.,[:space:]]", 0, 0 },
+ { "[[([:alnum:])yyy(\?!yyyyyyyyyy(\?!yyyyyyyyyyyyyyyyyyy[:graph:]I])Uw*X.^[:ascii:]{,-63}[:digit:]{-88})&&&&&&&&&&&&&&]*", 0, 0 },
+ { "[[[^K(\?=KKKKKKKKKKKK(\?:KKKKKKKKK[KKKKKK]]U[:digit:])]dd)({,16})xy+Pu)JJJJJJJJJJJJJJJ[:space:][:ascii:][:upperword:]ql_jywmt4B+]{-30,}^555555555Xza[:punct:]", 1, 0 },
+ { "[[^^XXX(\?:XXX((XXXXXXXXXXXXXXXXXXXX)v)$N9$r\"\"\"\"\"\"\"\"\"\"\"\"\"].{,239}$[:punct:]\"9999][:alpha:]{}c){,55}s[:upperword:][:xdigit:]310", 0, 0 },
+ { "[@([^I8oNl)]-{-203,-224}{-78,}KKKKKKKKc{-66}[:xdi(\?=git:]==========){}f{-124,}[:upperword:][:lowerprint:]]{}--------l+", 0, 0 },
+ { "[^]ozp+0(\?#\"[(\?()X]))[:blankcntrl:][^e{99,222}JJJJJJJJJJJJJJJ3F]\?[:blankcntrl:]l$ot", 0, 0 },
+ { "[[^[[((\?isximx:)2222222222(\?=22222[:graph:])+U)((\?{\?<=(\?()iYv8qc@#y)G])+}))FvnP\"7OZ-b273[:ascii:]Ak6*`S[:digit:][:graph:]]{2}^G{79,}DDDDDbbbbbbbbbbbbbbbbbbbbbbbb(bbbbbbb)|tP48y{wNJ_S hJbY]]dc", 1, 0 },
+ { "[:alph(\?{a:]p1[:lowerprint:]}){163,}", 0, 0 },
+ { "W()", 1, 0 },
+ { "()``````````````````````````[:ascii:][:alnum:]{,26}[:graph:]", 1, 0 },
+ { "[:al(\?<!num:]|byyy,*)U5%u${190}-{-221,-33}k7777777777777777777777777777777+eXXXXXXXXXXXXXXXXX[X(\?(XX)XX)S'vEAa]*e", -1, 0 },
+ { "[^(([R_AC[lE'{2(\?{28(]8LTt[]b[:punct:]]O)|2[:graph:][:space:]}) x3C[:alpha:])uI+dddddddddddddddddddddddd{-165,}FFFFFFFFFFFFFFFFFFFFFFF)cccc*[:upperword:]]G{,-38}{24,}555555555555555555555555555VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVZ[:blankcntrl:][:ascii:]", 0, 0 },
+ { "[^QQQQQQQ(\?#QQ(QQQQQQ[:punct:][:space:]){(\?(\?:!}[:graph:]t}}[^}}(}}}}}444444[^444444444444444444444]\?]G)E)L{,-103}{84,}r$ii]-[:alp(\?<=ha:]S5G~9>n*)P<3tttttttttttttttttttttttttt)n{}[:graph:]eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{,83}[:digit:])0BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB[:alpha:]{-155,}{151,}", 0, 0 },
+ { "Ue{,254}+f[:lowerp(\?<=rint:]U.fff)", 0, 0 },
+ { "QQQQQQQQQQQQQQQQQQQQQQQQAY<J)'MPi_u%#2doopqU7/{103}[:graph:]e!7{GOr", 0, 0 },
+ { "[^({,[^233}[^d)BBBBBBBBBBBBBBB=======(\?>===========[^=S|[^[:alpha:]G/]qqqqqqqqq{}[:xdigit:])..k", 0, 0 },
+ { "[([^[[:space:]ffffff(\?=ff]M]))[:xdigit:]UbCI,CzalLU*y5I[:digit:]r{-30,180}{-209,-45}Paf]", 0, 0 },
+ { "[^[h(\?{hhhhhhhhhhhhhhhhhhhhh})]{,143}[:lowerprint:][:ascii:((\?(\?=])[:asc)ii:])zp]", 0, 0 },
+ { "[[(\?{]})]", 0, 0 },
+ { "[[1\"3m^,(\?<!2((\?!\?#t```````````````````````````)\?)|c^)A^~]{61}W\\\\\\vvvvrrrrrrrrrrr[:digit(\?#:])]F[:upperword:]dX\\\\", 0, 0 },
+ { "([${144,}(\?<!)-RAk_F(\?imsxisx:=9]z/))", 1, 0 },
+ { "[[^[[[^([[^[^[^([[^([[Uiiiii#####(\?(\?{(\?<!#########(\?=#####).^)(.|>2m[M/2222222222222222222222222222(\?:22222222222(\?#22(\?:(\?=22222{,243}]x68+I/K)11111111111]\\pP[:graph:]$[:space:]^{}A)[:xdigit:]-={>", 0, 0 },
+ { "[(\?>[(^()Vty2vvvvvvvvvvvvvvvvz^])ZZZZZZZZZZZZZZZZZZZ----------------5\\dVLSp8UE2m+z3X/Sd", 0, 0 },
+ { "[}}}}}}}}}}}}}}}}}}}(\?#}}(\?<=)|*C ]*29JW7O9mEB]pE_OoxN)[:alpha:]", 0, 0 },
+ { "([^((\?<=\?)D{,200}.[(\?#:ascii:])[:space:].)[:alpha:]D|[:graph:]{,-41}*LLUUUUUUUUUUUUU{-189,-131}]qHR<k2@P{27}<^e,ub%\?/4){-243}+[:digit:]%*x9lA^", 1, 0 },
+ { "([:alpha:]bT&+_)$Z{,212}x26`", 1, 0 },
+ { "[^([^(A{[^}g(\?()A9p#54b]-------------------------------).wzD#=f\\)A)8a]]DNNNNNNNNNNNNNNNNNNNNNNNNNN", 0, 0 },
+ { "(W000000000000000000000000000000)", 1, 0 },
+ { "www(wwwwwwwwwwwww)", 1, 0 },
+ { "()555555555555{18}i+[:alnum:]E {}U", 1, 0 },
+ { "SqbHoooooooooooo[^oooooo([^ooooooo])\\N[:xdigit:]]oooo`", 0, 0 },
+ { "[999999999999999999uE{193,0}lx{7917}[:punct:]4&d]{221,}[:digit:]{49,156}[:lowe(\?<=rprint:])[:space:]{-33}w+", 0, 0 },
+ { "[^(\?{})<{220,-193}[(\?=:xdigit:]UUUUUUUUUUUUUUUUUUU'{-18}])", 0, 0 },
+ { "b[(\?<=:upperw(\?{ord:][:digit:]})EEEEEEEEEEEEEEEEEEEEE//////////////////){177}C", 0, 0 },
+ { "(^).[:alnum:][^[(\?=[(\?{[})DA5{)[[I~y&O\?9>])]][:blankcntrl:]M[:alpha:]x9[:upperword:]|[:xdigit:]b", 1, 0 },
+ { "()[:digit:][^[U}-]]{,206}V*WJ@R]\?", 1, 0 },
+ { "[^](\?#{}(\?[<=)yv)]r", 0, 0 },
+ { "({,-192}//////////////////////7!eW_0eoL){}", 1, 0 },
+ { "^[:punct:(]+)IIIIIIIII[:punct:]P$pP", 0, 0 },
+ { "[(\?=|U)^-]{-52,-72}[:digit:]*6666666666\?{{{", 0, 0 },
+ { "([^f(\?:+{1((\?=34,}]))^)s0bux7\?5`Bwr[:upperword:])Dy+", 1, 0 },
+ { "AL{}:::::::::::::::::::::::::::::::{,(104}~@,Ysey@h).", 1, 0 },
+ { "[^((.)))(\?()))))))))))))))))))))(\?msxims:))))))))))[)][:upperword:][:alpha:])", 0, 0 },
+ { "[^(()f])G^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^T{}N*nK[G]{,61}^^^^^^^^]", 0, 0 },
+ { "[(N::(\?<=[:digit:][:graph:][:space:]xB5[(:xdigit:]|Yv{}HHHHHHHHHHHHHHHHHHHHHHHHd).[:g(\?<=raph:])[:digit:]<<)[:digit:])[:space:]Q[:punct:]x7C]", 0, 0 },
+ { "[^((\?(\?(())a)(\?!){})W)pP3333333333(33333333333333333333hhh]{})", 0, 0 },
+ { "[^ [ a*FFFFF[^FFFFFFFFFFF(\?<[^!FFFF(\?=FF])])L1]{,-52}{B-bxsPKg{,8}[:digit:][:punct:][:upperword:]DD${,-131}", 0, 0 },
+ { "($$$$$$$$$$$$$$$$$$$$$$$$$$$$$^pP),,,,,,,,,,,,,(,,,,,,,,,,,,)QQQQQQQQQQQQQQQQQQQQQQQQ", 2, 0 },
+ { "[:lowerprint:]|l{(,-54}C{}*-)IIIIIIIIIIIIIIIII", 1, 0 },
+ { "()+", 1, 0 },
+ { "[(([(\?{[:punct:]]|))[[[[[[[[[[})]WWWWWWWW&$$$$$$$[:graph:]", 0, 0 },
+ { "[^(\?{}){(107[(^,}][:space:[]))^w,&aPPPPPP[^PPPPP{117,-213}s\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?]]]222222[:d(\?(igit:]NNNNNN)NNNNNNNNNNNNN8)I", 0, 0 },
+ { "[^(\?<!$)|TTTTTTTTTTTTTTTTTTTTTT(TTTT]a8)2<", 0, 0 },
+ { "([^[]%[^[^]-][:alpha:]37*:[:space:]]lQvu)[:xdigit:][:blankcntrl:]", 1, 0 },
+ { "[[Bl_>9C^:\?X_KK]2sw@hHZT!],uuuuuuut|lFW()'''''''''''''''''''''[:graph:]<~v{-251}0[:digit:]C[{222,}]{,41}{}*g^UuS/{-114}", 1, 0 },
+ { "(D{,-79}[:gra(ph:(\?(]C[:ascii:]))I[tC.%tkllll[^llllllllllllllll]&&&&&&)&&&&&&&&&&&&&&&&&&&&&&)]10435", 1, 0 },
+ { "[:al(\?{[^num:]]})}x'[:(\?#xdigit:])xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxKKKKKKKKKKKKKKKKKKKKKKKKKKKKTTTr*%{~f", 0, 0 },
+ { "[ZQKEEEEEEEEEEEEEEEEE(\?<!]3|.~~~~~~~~~~~~~~303)33333333333333333", 0, 0 },
+ { "(-62([:ascii:]5555){-230,}<<<<<<SM[:punct:]{72}|E{160,})Pfqba!{,-188}DS{ +2tRu\"0JG$", 2, 0 },
+ { "([^(\?:(Ea00000000000000[:punct:][:graph:]{}]))[:xdigit:]{-65}t){164,}", 1, 0 },
+ { "[\?$$$$$$$$$$$$$$$$$$$$$$$$$F......(\?(.).q#R:j6%TTLCdtuM|8*54<GHoqEh9FBW0:W]L0)o][:upperword:]", 0, 0 },
+ { "[(\?>[:alnum:]W[:space:]]D)|L", 0, 0 },
+ { "(M(MM)[:alnum:]|[:lowerprint:]4)", 2, 0 },
+ { "[[^(\?:{}{2[2(\?>0,})]]]Etu)-)", 0, 0 },
+ { "([^[^^z[:graph:]]#{-144,96}[:punct:]!4LY//////////////////SSSSSSSSSSSSSSSSSSSSSSSSS[[^:xdigit:]\?`-!L#p0{52}]%{-121,}[:graph:]]WqJ>$6UBg{,7}[:blankcntrl:])[:upperword:]y2wW!A[:blankcntrl:]0CN\?", 1, 0 },
+ { "[[^(\?:|+bII(IIIIIII(\?(\?>!)275SIIIIIIIIII(IIIIIII(\?=IIIIII[:graph:]|)`]S\?.}A)[:alnum:]Jgggggggggg{-150,}{-89,})[:alpha:]Q)|07be5:j)]", 0, 0 },
+ { "([(\?i(ms(\?=x-x(\?>:))C)]){})>eIqm~lFb[:upperword:][:blankcntrl:]w=[:digit:][:graph:]", 1, 0 },
+ { "([HHHHHHHHHHHHHHHHHHHHHHHHHH[^HHH(\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?!!!!!!!!!!!!!!!!!!!!{23}]~J=[:ascii:]tttttttttttttttt])-216", 1, 0 },
+ { "B{[^-32,246}{13(\?!0}q>GVQw*[:digit:][:punct:].77777777777777777777`T(-t01odD]\?${}{-247}+gV{131})+[:lowerprint:]m/z~d", 0, 0 },
+ { "[t[$FV+(\?=E=[^])]-$U{-22[5,}{253,}08g]$[{}][:xdigit:][:punct:]{-18}{-173,}]{,-191}V_|90", 0, 0 },
+ { "()$", 1, 0 },
+ { "[^[^((((((((((((((W[(\?::blankcntrl:]&-JH]J){93}LLLLLLL|r{,221}tY/172]-AS", 0, 0 },
+ { "[^()(\?{qqqq(\?msimsx:qqqqqqqqqq3999999999999GGGGG|S*W%{,128}][:xdigit:]AJt]}\"Zf!lRpr{>){,36}})", 0, 0 },
+ { "[([]^]^)", 0, 0 },
+ { "([.(\?#){}[:alpha:]\?S{2}P%Gw]nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnYiq5)>i*r<", 1, 0 },
+ { "[ggggggggggg$PPP:S (:]N{239,}|A[:lowerprint:]vvvvvvvvvv[:lower(print:]{-184}({-133,}+)[:punct:]P/Q.OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", 1, 0 },
+ { "(RRRRRRR[^RRRRR[RRRRRRRRR])]", 1, 0 },
+ { "[(\?:^])D%", 0, 0 },
+ { "()[]#C[+[j]{,29}-]", 1, 0 },
+ { "(([(\?(((\?{\?!(\?=\?=#[Es*){02$r'}(\?:3pz)uPPPPPPPPPPPPPPPP(\?(\?>:PPPP][:graph:][:ascii:]`.)[:punct:][:a(\?mxi:lnum:])r)$)[:xdigit:]$[:(\?=digit:])aa[^]a)\?])sQQQQQQQQQQQQQQQQQQQQQQQQQQ^|$)-}))", 2, 0 },
+ { "z@@@@@@@y${}[:(\?:upperword:]l\?{,144}-)", 0, 0 },
+ { "[:aln(\?:(\?>um:(\?imximsx:]){})FGGGGGGGGGG|-p){,105}", 0, 0 },
+ { "[[{17}llllllllllllllll(\?:lllllllll{,(\?#-94}OUUUUUUU(\?#UUUUUUUUUUUUUAA]p[:digit:]{-1(57,}5yyyyyyyyyyyyyyyyyyyyy[:alnum:]v{-185}^^^^^^^^^^^^^)d[[[p)]))", 1, 0 },
+ { "()|[:digit:].E2o", 1, 0 },
+ { "()3[:lowerprint:]", 1, 0 },
+ { "[(\?{(\?#(\?>SN}[^)z+r^t[:digit:]seP[:alnum:]$b1ZY[U(\?<!U4IIIIIIIIIIIII(\?<=IIIIIIIIII]m)]))]4)", 0, 0 },
+ { "{,74} qkk[^p]kbi6>{}000000000000000000000000000000$|)", 0, 0 },
+ { "[:(\?=digit:])v{164}", 0, 0 },
+ { "[:graph:]h[:upper(\?(wo(\?{rd:)])00000[^000000000000}).4OEVf{,-46}]A", 0, 0 },
+ { "[](((((((((((((((N{{{{{{{{{{{{{{{{,-1}e]a{-166,-44}", 0, 0 },
+ { "([[^[^[(^[]]YYYYYYYYYYY]D.cQ{}[:alpha:]ttttttt000000[^0000(\?<!0000000000000000N::::::::].][:alpha:]#5\?{}{-253,-193}]\\[:ascii:]tS{,35}B)ffffffffffffffffffffffff))/", 1, 0 },
+ { "(G)[:alpha:(\?#])W{-197,-220}w8", 1, 0 },
+ { "{-2[^00,(\?#-([84}ig+)]]l[:graph:][:graph:][:space:])aaaaaaaaaaaaaaaaaaa{-208,}ea{,224}", 0, 0 },
+ { "[^[W(\?<=[B[:xdigit:]{255,}FAAAAAAAAAAAAAAAAAAAPP])[:xdigit:]+][:lowerprint:]${-195}", 0, 0 },
+ { "[v{104,}BB].HHHHHHHHHHHH[:ascii:]bbbbbbbbbbbbbbbbbbbbbbbbbbbb(btttttttttttttttttttttttttt){180}", 1, 0 },
+ { "[^(i[^iiiiiiiiiiiiiiiiii(ii)n])#######################]", 0, 0 },
+ { "(([:space:])[:g(\?>raph:])[:punct:][:upperword:]LV\"t+t!)[:ascii:][:lowerprint:]q", 2, 0 },
+ { "[[[^([7(\?[<!)\\PP~D7L (\?imsimsx:(\?= $GS26L3-J(\?()!)]]{-178}%$[:p(\?!unct:]))yyyyyyyyyyyyyy@w,[11!R86:)G*[(\?(:blankcntrl:]267$~L\?{-108}k[:alnum:]So\?Y/eq]-|[:xdigit:]555555555555555555555555555)55555........W*O))][:alnum:]]I{,-126}[:lowerprint:]8\?[:xdigit:]u%wHc6\?:Pc...........................,,,,,,,,,,,,,,,,,,,,,,,,,,,]", 0, 0 },
+ { "((3pPp))QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ", 2, 0 },
+ { "[[^]{-244[}(\?([^|W0E4]UUUUUUUUUUUUUU[:upper)word:][:space:]{-57,})+L>R]]$PeFuufcBA`qr!!!!!!!!!!!!!!!!!!!!!!!!!", 0, 0 },
+ { "[[(\?#F^(\?<!)|)fff(\?!fffffffffffffffff(\?{ffffff(\?:ffffff[:alnum:])]]c.\?-}))", 0, 0 },
+ { "[^[^((\?:)ww[wwww(\?>wwwww)3z/57z){34}]/(/////////////[^//////////////////)]E%)L{-133}]*$]", 1, 0 },
+ { "(!)GS[:ascii:][:punct:]{235}T'&-_h\"", 1, 0 },
+ { "(){}", 1, 0 },
+ { "[[^((\?!(\?<=)*QF[:alpha:])([^[^\?<!x60t(\?<!UUUUUUUUUUUUUUUUUUUU)K&d{118}z7nM.G)```````````````````````````E:(\?(){31,}){}]k]){,109}[:space:]]ZZ[:xdigit:]]{-68,}`{}{}e\?[:alnum:]", 0, 0 },
+ { "[^{223}.^,-qqqqqqqqq((\?!\?>qqqqqqqqqqqqqqqqqqqqqqqP6W0_'O)Bur*'6&*t)]{65})+", 0, 0 },
+ { "([(\?=)]wr$7f5ru){100,}[:xdigit:]y{}[:digit:]{}2n@P|9#mru~97{-189,73}$a", 1, 0 },
+ { "({-113,213}){-172,221}B[:ascii:]{,-48}", 1, 0 },
+ { "[^[[Xf`````((\?{(\?<=\?imsmsx:`````````(\?!`````````[```(\?mximsx:``(\?(&|o{xIaO][:)space:]3))\?])+)*<|@@@@@@@@@@@@@@@@@@@@@@){-251,}{}]*[:graph:]1!azE\?|-120u*][:lowerprint:]})", 0, 0 },
+ { "[[[^##(\?################(\?>(\?(##t)][:punct:])b))<<<<<<<<<<<<<<<<<<<<<<<<<<[:alnum:]y >u=l:rp8i3Ci#]46%NIO-W[:space:]IIIIIIIIIIIIIIIIII]W[:space:]f]l{-253}", 0, 0 },
+ { "[:graph:]L{-136,175}{[^}h(\?=t)Q]ooooooooo(ooooooooooooooooo_)[:space:]q\?", 1, 0 },
+ { "()$.", 1, 0 },
+ { "[(\?<!^$.\?{197}B]$)", 0, 0 },
+ { "[:di(git:])[:low(erprint:])qqqqqqqqqqqqqqqq[:digit:]", 0, 0 },
+ { "((zzzzzzzzzzzzAUUUU)l$]VD z~)n", 2, 0 },
+ { "([^[(\?<=^[]{}][.WWWW)044444444444(\?=44(\?{444(\?{(444444444444e{(\?=}}))..t]+[:(\?<!xdigit:]P]-N}))))|)", 1, 0 },
+ { "\\ce[:(\?#asc(\?{ii:])})[:upperword:]`^", 0, 0 },
+ { "[:graph:(\?<=])[:alpha:]", 0, 0 },
+ { "([:upp(\?=erword:])pC)lp\?", 1, 0 },
+ { "(oooooooooooooo\?fN)-[:alpha:]{-213}[:alnum:]qHEu", 1, 0 },
+ { "[:punct:]TTTTTTTTTTTTTTTTTTT[:d(\?#igit:])[:alpha:]", 0, 0 },
+ { "([^[^[^J4(+++++++++++++++++++++SgDE(\?>\"y8].]:::::::::::::::)pP5-]p)O{,199}xxxxxxxxxxxxxxxxxxxxxx[:ascii:]%", 1, 0 },
+ { "([:alpha:]Fs)Z", 1, 0 },
+ { "[()]{209}[:alpha:]hhhhhhhhh(hhhhhhhhhhhhhhhhhhhhh)pP<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", 1, 0 },
+ { "-{-8,}.[:(\?imsxx:ascii(\?<!:]{-231}aa*{}K^UQL\?)d\?[:lowerprint:]W)q>D9'", 0, 0 },
+ { "[#(\?msximsx:#########################-IIIIIIIIIIIIII(IIII(\?#IIIII((\?#[^III{})N.[(\?=:lowerprint:]))CwT,,,,,,,,,,,,,,,,,,,,Sq]$CCCCCCCCCCCCCCCCCCCCCCCuuuuuuuu])))", 0, 0 },
+ { "[:xdigit:][(\?#]){13}{,75}lllllllll", 0, 0 },
+ { "[c]QQQQQQQQ1+{-252[(\?#}33333])[:upperword:]", 0, 0 },
+ { "P@i #>>PF!@8G<[(\?:^P]-)D", 0, 0 },
+ { "uZZZZZZZZZZZZZZ[^ZZZZZl*-211{199}(\?!p])EEEEEEEEEEEEEEEEEEEEEEEEEEED[:lowerp(\?msximsx:rint:])", 0, 0 },
+ { "[(\?!^])021[:graph:]'", 0, 0 },
+ { "\\(\?>[(\?<=:ascii:]{}[:alpha:]d8}G))", 0, 0 },
+ { "[^[((\?!1)[^,a|]\?{,242}[:alnum:])X\"a", 0, 0 },
+ { "pP[((\?simx::a(\?!lnum:]vvvvvvvvvvvvvvvvvvvvvvvvv)|O0)[:digit:]ooooooooooooooooooooo)\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"", 0, 0 },
+ { "_ L:8J-~ Y$[:uppe(rword:]{,-184}]{}6.A)", 0, 0 },
+ { "{,105}.(9]]{-12})N@0nOOE", 1, 0 },
+ { "HHHHHHHHHH[:xdigit:]uuuuuuuuuuuu{}E^X\\\\\\12601", -1, 1 },
+ { "( o)=\"OU7h{V>", 1, 0 },
+ { "[[:xdigit:])))))$[:xdigit:]+{152}{,-50}(c),,,,,,!!!!!!!!!!!!!!(\?>!!!!!!!!!!!!!.[:digit:]i>\"O'i9])-175d_", 0, 0 },
+ { "[([^[^[^([[Eeee[^eeeeeee(\?(\?<!(eeeeeeeeeeeeeeeeeef|]][:alph()\?>(\?!(\?>a:]a{,166})/////////////////////[:gr[^aph:])Gpu", 0, 0 },
+ { "(7)NNNNNNNNNNN132", 1, 0 },
+ { "[([\?#^[]{QKm$v])][:alp[^ha:]]", 0, 0 },
+ { "(:{86})7{K|[:alpha:]{O", 1, 0 },
+ { "([Y(\?{[[^:alnum:][:alnum:][:digit:][:a(\?(lpha(\?(:].})", 1, 0 },
+ { "[[({29,-30}([[^:digit:])Y]]J=~{,220}[:blankcntrl:])0ooooooooooooooooooooooooooooooo[:punct:]&]", 0, 0 },
+ { "[^1Dx32[:alnum:]]{[(\?::punct:]MMMMMMMMMM)12759", 0, 0 },
+ { "([[[]]*|(_])[:u(\?{pperword:]})", 2, 0 },
+ { "[:upper(\?(wo)rd:]){-16,250}", 0, 0 },
+ { "([^{194}i(\?({161)}PP\\S{}{,-14}]))z{208,225}BpPEt", 1, 0 },
+ { "[(\?m-ms:)}&!@29k0sUqzt9}<-x|A$!+G>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>CCCCCCCCCC-][[:space:]][:space:]El", 0, 0 },
+ { "()[:digit:(\?isx(\?>ix:]K^WQQQQQQQQQQQQQQs)[:lowerprint:])", 1, 0 },
+ { "[a|(\?imix:S(\?(SSSS)SS(\?>S)]W)8t[:ascii:]f$)[:alnum:]111111111111111111111[^[:space:]x{12729}+'''''''''''''''']", 0, 0 },
+ { "[^(\?!(\?(\?#=)a)[:punct:]=2)(){}$$$$$$$$$(\?ims(\?#-isx:$$$$$$$$$$$$$$$$(\?#$$s)x{294b}##############################slllll)]){,209}333333333333333333G:v2/K", 0, 0 },
+ { "[^]ub(\?<=)vQ6(\?#Z\"3.)[:space:]u[[:digit:]]7777777777777777U'{}sssssssssss", 0, 0 },
+ { "(([(])`[:ascii:]b)", 2, 0 },
+ { "[[[^[^([^[^(\?=(\?imxisx:[[^w])", 0, 0 },
+ { "pppp(pppppppppp-{-175}Nb>k&)sssss{-190,-54}", 1, 0 },
+ { "()OJ@`'%[:(as(\?!cii(\?#:]))+pffffffffffffffffffffffffffff{,162}[:ascii:]5)s-[:graph:]", 1, 0 },
+ { "[(M{}Ux5{jaW/{}[^u[:alpha:]s^{84,}PPb@Wt$(\?>nha<Yf41a)]{}[:lowerprint:])*[:lowerprint:]][:upperword:]^1gS.^=pp{}FFFFFFFFFFFFFFFFFFFFFFFFFFF33333333333{}", 0, 0 },
+ { ")\?L9~h4BQnNp F\\Q{}", 0, 0 },
+ { "($)[:upperwor(\?:d:])N[:alnum:]bcccccccc5555555555555555555555555.N[:blankcntrl:]", 1, 0 },
+ { "2222222222222222222ppppppppppppppppp[:lowerprint:]))[^B\\e{{{{{f]6#+{,-104}{{{{{{{{{{{{{", 0, 0 },
+ { "<[(\?>:al[^pha:]])\"O\"vN", 0, 0 },
+ { "[(\?>d8E@b.{(\?<=,-250}(\?=mx48[:punct:]^&)]nAeYY)W)-13272", 0, 0 },
+ { "22222222222222222222222222///////////////////[:digi(\?#t:]eM)[:lowerprint:][:alpha:][:alpha:]EEEEEEEEEEE", 0, 0 },
+ { "[(\?={38,223})^\\\\\\\\\\\\\\\\L(\?:{,-50}3|)}r]aW\\x70U{-110,}8LUf)w]4+oav", 0, 0 },
+ { "G[:upperword:]v[:lowerprint:]-tu)j8CK", 0, 0 },
+ { "[([([^().(\?(\?><=c)'(\?<(='(\?<!''''''''(\?(\?<!!'''''''''''(\?=''''''/(|dHj(P>L\?q!G))|)(\?=n(\?(^tk)T-z$q!D|2<rc[^{,53})]jZy))))6)[:bla)nkcntrl:])010])7pE`l[:space:]([:lowerprint:]eXXXXXXXXXXXXXXXXXXXTTTrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr]+[:alph(\?!a:]7)444444444444444444444444l{34,}]J{}yyyyyyyyyyyyyyyyyyyyyyyyyyy)\?'z9~9s.mA", 1, 0 },
+ { "().", 1, 0 },
+ { "{-205(,}[:al(ph(\?>[^a:]W,[4DLR[^^8THMtVv~KKw(\?>)pPF)].{-245,}]))fffffffffd[:alpha:]zzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 1, 0 },
+ { "[^[[^]{-[1(\?imximx:83,}{,182}][:graph:]]^])-bTO X0P", 0, 0 },
+ { "[11111111111(\?#11111111]U[:asc([\?!ii:]{,37}+{-89}){-170,218}{-21,})f[:xdigit:]]P.[:xdig(\?:it:]145)YYYYYY$S@:@@@@@@@@@{-150,-109}", 0, 0 },
+ { "{-40}<o][^D[(:graph:]]d).Q", 0, 0 },
+ { "()APPLn[:xdigit:]", 1, 0 },
+ { "[([^\?+++++++++++ [ (\?> (\?( (\?{ (\?!]E{-29})pP)})ZpP", 0, 0 },
+ { "(t|{}c[^z^\?(@YLD]bSSSSSSSSSSSSSSS)+{{{{{{{{{{{{{{{[:xdigit:]n>1)WkF}7", 1, 0 },
+ { "W22[0Q[^d-d{}PPPPPPPPPPPPPPP<^FZ(\?<=\"[U]Yo}9H'cYy]S[:alnum:]^8wTDH)^u", 0, 0 },
+ { "([^[(\?:(\?>((\?#$)(\?{^(\?>))///////////(\?>/ggggggggggggggggg{1(\?!90,-13}\\D)Dyyyyyyyyyyyy(\?!y(\?<!yyyyyyy)})]]$)[:xdigit:]|{}-)#a))nPpP[:lowerprint:]AA)V+q^[:blankcntrl:]", 1, 0 },
+ { "([^(\?!]))D{,97}", 1, 0 },
+ { "(c){,141}", 1, 0 },
+ { "nn[:s(\?<=pace:])[:upperword:]ooooooooooooooooooo*^[:space:]`{-188,129}mmmmmmmmmmmmm^.", 0, 0 },
+ { "[[G{(\?imsximsx:2(49}{,-46}r(\?(\?=#Gw]u))[:bl(\?>ankcntrl:]))(^m+)zSiZ F4[!]VV$E{-9,-100}''''('''''''''\?DEOOOOOOOOOOOO###############[:space:])HHHH)[:digit:]'////////////", 2, 0 },
+ { "[^*}(\?>)(\?:7Q=#+]KKKKKKKKKKKKKKKKKKKKKKKKKKKG)]]]]]]]]]]]]]]]]]]]]]]]]]][:alpha:]-{}", 0, 0 },
+ { "[n(\?<(\?#!nnnnnn55555{205,}!)[:alnum:]^]!!!!!!!!!!!!!!!!!!!!!!![:punct:])[:x(\?(digit:]vr)|'n6W5 D&jk[:punct:]5)", 0, 0 },
+ { "[^P(P{(\?i(msxisx:235,}))***])[:alpha:]^", 0, 0 },
+ { "[([t(\?<!(\?<!4])[:u(\?=pperword:]))-])}}}}}}}}}}}}}}}}}c{-39,}[:digit:]$-", 0, 0 },
+ { "([^)]{241}[:xdigit:][:upp(\?=erwo(\?(rd:]-xF5b{})q[:ascii:])T4U{185}9999999999)()X&Ny[:alpha:]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@{69,}[:alnum:]x{d7f8}p-[:digit:]", 2, 0 },
+ { "(f)(${,111}{25,}!\\d{,94}[:blankcntrl:]@[:space:][:ascii:])-237{,232}DQVVVVVVVVVVVVVV)-", 2, 0 },
+ { "PP[:g(\?!raph:]){}", 0, 0 },
+ { "([[^-][^4[:digit:]NNNNNNNNNNN]TVU:])[:ascii:]", 1, 0 },
+ { "(([^(\?[[^<=)][:graph:]+iiiiiiiiiiiiiiiiiiiiiiiiii0INFX[:xdigi(\?(t:][:blankcntrl:]][:graph:]qM6A[:alpha:][:graph:])1*]eFvvvvvvvvvv)v-)U))t{89}", 2, 0 },
+ { "[^ZZZZZZZZZZZZZZZiiiiiiiiiiiii(iiiiiiiiiiiiiii{}))))))))))))))))))]))))))))))))))))))))))))[:digit:]-", 0, 0 },
+ { "ddddddddd+zzzzzzzzzzzz[:graph(:])ssssssM{-223}[:graph:]", 0, 0 },
+ { "[:alph(\?>a:])x11{-144,45}.", 0, 0 },
+ { "[]{#y.^(\?{{}&&&&(\?:[^&&&&&&&&)[:punct:]n{190}OylBQ{(\?!-73})2u',x(\?#Ds(\?#{})j(\?{-})})u0(((((((\?{(((([:alnum:])MC})b=71TncyE>[:xdigit:]*\\f]{}]\"p#!8twZT\")[:punct:][:space:]", 0, 0 },
+ { "[^(Z6]8)|'@p8{}[:upperword:]MMMMMMMMMMMMMMMMMMMMMMMMMMMM{}7c", 0, 0 },
+ { "$0)@#vp,VcJ.Bdh", 0, 0 },
+ { "[[^(-])nnnn+s`[:alpha:][:blankcnt[^rl:][:upperword:]{-15,}][:g(raph:]c]){,-177}6[:upperword:]##################{,-14}", 0, 0 },
+ { "[[(5C{86(,}PPrrrrrrrrrrrrrrrrrrrrr{150,182})N{}LSC|)-[:alnum:]{}KKKKKKKKKKKKKKKK<4=~7K3PPPPPPPPPPPPPPPPPPPPPPP[:lowerprint:]]]", -1, 0 },
+ { "([^(x{145b[5}^hfc.0)+]z@_&lA{-34,}])X\?", 1, 0 },
+ { "([(\?<=)(\?!])l)L", 1, 0 },
+ { "({-104,}DrPPDF4444444444444[:space:])[:space:]", 1, 0 },
+ { "())))", 1, 0 },
+ { "[[^((\?>\?(\?[{})q5v}r7t(P)xtffffffffffff))]{,-66}kdExX&-SCeCzzzzzzzzzEc)E,\"^I]x{e629}|{}]", 0, 0 },
+ { "[h[:punct:]p\\[\\\\(\?:\\\\[^\\\\)Eo#:C$u[^T/ysA[*%nM:f]{,221}[:lowerprin[^t:]{]bx{f285}E]E[:alnum:]+]1oe3B][:alp(ha:]]fh7}M$l)D{17}", 0, 0 },
+ { "IIIIIIII[^IIIIIIX]-_S[:digit(\?#:])33333333333333333333333333[:punct:]iiiiiiiiiiiiiiiiii", 0, 0 },
+ { "[^[[:punct:](\?((\?:^ #Q_po(\?=[:alpha:]{}z()(\?!======'wq$Q2)LLLLLLLLLLLLLLLe(C9gggggggggggggggggg[(\?<=:alnum:]()\?<!{-85,}W[[[[[[[[[[[[[[[[(\?{[[[[[[^)(]\?])|uuu[uuuuuuuuuuuuuuuuuu{,-20}p${}]MHI&7s:\?$[:digit:]-:)_V`*{-52,}{250}$:ME9izF/uP[:blankcntrl:]})''''''''''''''''''''''''''''')CCCCCCCCCCCCCCCCCCCCCCCCdd[:ascii:][:lowerprint:].Mcccccccccc2B{-230,}$[:digit:]", 1, 0 },
+ { "()|mOAuK~P144[:space:]^9dddddddddddddddddddddddddddddd[:blankcntrl:]", 1, 0 },
+ { "[^[^[^.L[^-vEUl(\?>(\?=a!Ib1P]])])~~~~~~~]xE9", 0, 0 },
+ { "X()", 1, 0 },
+ { "[^()(\?#G(\?<!)(\?=^r])*,XXXXXXXXXXXXXXXXX@)444444444", 0, 0 },
+ { "([[((\?<=({,-70})-[:xd(\?=igit:]{,138})", -1, 0 },
+ { "[(^]{62,67})", 0, 0 },
+ { "([((])[:space:]))", 1, 0 },
+ { "(a{(109,})[:alpha:]{,-121}{})]RRRRRRRRRRRRRRRRRRRRRRRR{}{125,}ttttttttt{46,}`[:space:]", 2, 0 },
+ { "[^[^([q[8]~.IPmiBSspP)]QpX[pT==8@lulANS]]{,-98}]", 0, 0 },
+ { "[^77777777777777777777777(\?>777777])", 0, 0 },
+ { "(),e<^X~{[:alpha:]{}G{70}", 1, 0 },
+ { "({-211,}'){}", 1, 0 },
+ { "[^(\?imsxsx:{}[*])cccccccccccccccccccccccccccccccc<z0W8]$", 0, 0 },
+ { "(){2,89}$z", 1, 0 },
+ { "((050[^\"\"\"\"\"\"\"\"z]8|j{}{,-112}$).pP)qq1~hW}L", 2, 0 },
+ { "[[^[(+xx(\?<!xxxxxxxx(\?!xxxxxxxxxx(\?#(\?>[x))(\?:]r.]]]))[:graph(\?<=:])))", 0, 0 },
+ { "[^([(\?#)(\?(\?(<=)l|\?(\?!])kkkkkkkkkkkkkkkkkkkkkkkkkk", 0, 0 },
+ { "[:xdigit:]K(KKKKKKK)^3c.OOO{-240,-10}2{-97,-139}*{-34,}[:xdigit:]", 1, 0 },
+ { "[([^66666666F(\?>FFFFFFFFFFwpP)LLLLLDeDA&Am$l[:xdigit:]!T5#]n[:alpha:]U*)))))))))))))PP]", 0, 0 },
+ { "[[[:punct:]u^[:xdigit:]L(\?:[:xdigit:][[:graph:]PP{21}A[:alpha:]8%I(M%b<eE~#C@r=uG~~~~~~~~~~~~~~~~~~~~~~~~~~~~+w]pP)T]]$$$$$$$$$$$$$$${-121,}|l", 0, 0 },
+ { "([(107{,-4(\?=}~[^D)])f]{,46}+ri<)", 1, 0 },
+ { "[(\?<=]{,208}+~)", 0, 0 },
+ { "[^444(\?<=4444444[:alnum:]&[,i]0)[:alpha:][:upperword:]", 0, 0 },
+ { "[^([^(\?()*+)SS(\?>SSSSSSSSSSSSSSSSSSSSSS]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]{,-1}])[:blankcntrl:]===============================[:punct:][:blankcntrl:]Z[:space:][:ascii:]$|$[:blankcntrl:] JR.{,133}[:alpha:]$\?)<]", -1, 0 },
+ { "(OL[:u[pperword(:][:s[^pace:].[:spac(e:],,,,]*])$)\?)", 1, 0 },
+ { "(VI[:digit:][:alpha:]6)EG", 1, 0 },
+ { "({}){-2,-40}rrrrrrrrrrrrrrrrrrrrrrr[:punct:]", 1, 0 },
+ { "()q", 1, 0 },
+ { "[^([^[([^C|])]{,-56}[:xdigit:]{-144,}V])fYv{-[40,-58}$@@@@@@@@@@@@@]|Y(-]-.]h-[:dig(it:])>>>dddddddddddddddddddddddddd{101,}", 1, 0 },
+ { "([P,{1(\?(\?(<=28,-218[^)}LoZX)])!!!!!!!!!!!!!!*[:blank(\?!cntrl:]ed)\\\\\\\\\\\\\\\\\\\\[\\L\?][:graph:]:*Y{-108,120}xCC)]", 1, 0 },
+ { "(A[:space:]PP{185}a^!!!!!!lllllll)*db\?$Pfr", 1, 0 },
+ { "{-21,-118}kG[(\?{:xdigit:]})[:punct:]{69}Qyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy5{}TTTTTTTTTTTTTTTTTTTTT", 0, 0 },
+ { "[[^[P(\?<=P$X>0^d.[:punct:](\?#ccccccccccccccccccccccccc{}3N000(\?>00000000000000000000000000000]f[:punct:]5)).R================{,222}^wwwwwwww$)]-{} ]{,-22}CjP{242,}", 0, 0 },
+ { "[(\?#^]{})", 0, 0 },
+ { "[^([[([([[([^[^(\?:(\?(\?(!)]\"))h>\"RRRRRRRRRRRRRRRR[^RRRRR{68,-65}7Q(\?{]", 0, 0 },
+ { "(P{}){175,}PP{}rttttttttttt", 1, 0 },
+ { "[:bla(\?{nkcntrl(\?#:]})))))))))))))))))))))))!!!!sR{})", 0, 0 },
+ { " [:digit:]dAAAAAAAAAAAAA^[:ascii(:]55)^", 0, 0 },
+ { "($*)dZY", -1, 0 },
+ { "[:graph:][:lowerprint:]S[:gr(\?=aph:]{-128,}666666666666666666666{}[:upperword:]|nnnnnnnnnnnnnnnnnnnnnnnnnnB)c[:xdigit:]{-225,}{-4,}{-192,}QQQQQQQQQQQQQQQ@@@@@@@@@@@@@@@@@@@@@@.", 0, 0 },
+ { "([:digit:]s{44,}{}{-31,}c{,-130}pP){-241,}UeN", 1, 0 },
+ { "([^)((\?>\?#{}hK\"V2\?d][KKK(\?imsxim:KKKKKKKKKKKKKKKKKKKK[^KKKKKKKKKWWWW[WWWWWWWWWWWWWWWWW)B])_l_3", 1, 0 },
+ { "[(^[(\?!*){[^,91}].j]*]L)*c|[:alpha:]&", 0, 0 },
+ { "[^[[[^[777GGG(\?:W_U(\?imsxms:[:punct:]A]-)[:digit:][:blankcntrl(\?(:]][:alnum:)])]WRRRRRRRRRRRRRRRRRRRRRRRRRRR]{31,}[:xdigit:]][:xdigit:]))))))))))))))))))))))$[:xdigit:]", 0, 0 },
+ { "[:ascii:]m*[:punct:]#[(\?<!:punct:][:alpha:]-,7vyXeeeeeeeeeeeeeeeeeeeeeeeee^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%%%%%%%%%%%%%%%%%%%%%%%%%%%%[:digit:]''''''''''''''''')", 0, 0 },
+ { "([^*[(:punct:]9999999999999999999{147,}]j{,193}{171}Z-)){208}0[:graph:]yDt", 1, 0 },
+ { "(dw[[:alpha:]U]ttt[tttttttttttttttttttt]Q^171e)[:xdigit:]/", 1, 0 },
+ { "[[^((\?#)Tqqqqqqqqqqqqqqqqqqqqqqqqq105++++++++++++++++++++++++++b7V+7dit]])|D", 0, 0 },
+ { "{}P7.Ajh[:xdigit:]^[:blankc((\?(\?<=nt[rl:]FFF)-]){}o|a[:grap(\?!h:]))PsssssssssssssssssssssssssssssssN^{-60,}Kb", 0, 0 },
+ { "[:alpha(\?(:]$!_+777777777777777777777777O)666)lll[^llllll[^l{{{{{{{{{{{{{{{{{{{{{{|]{-217,}MoEl`7)^)LlU[:alph[a:]({-241,27})]]{-212}{,249}n)X", 1, 0 },
+ { "[U|ajP[:alnum:]n[(:digit:]]W)[:graph:]b[:xdigit:].P", 0, 0 },
+ { "(([:low(\?-imsx:erprint:]|{}[:ascii:][:gr(\?:aph:])>>>>>>>>>>>>>{,-129}))\?{-226,}^P)R", 2, 0 },
+ { "[^[[nnnnnnnnnn(\?=nnnn(\?!nnnnnnnnnnnn(\?#nnnnnn{,-38}N){202,}]$[:alnum:])]t][:alnum:[]^=w){237}][:alpha:]-[:alpha:]+e", 0, 0 },
+ { "()[(\?(:digit):]+qc)O88888888{,151}aJ", 1, 0 },
+ { "([^([(\?!sv(\?=)d]{-200,})N))]Z{-73,15}", 1, 0 },
+ { "([\?\?\?\?|||||||||||(\?{||(\?=||||||||-}[))Ehhhhhhhhhhhhh{,202}&TcfL((\?:>)((\?!\?>$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$8[:alpha:]\\d])]C[:graph:]h*,\"\?u{|mU,a)[:blankcntrl:][:lowerp(\?>rint:])PPnP+9.[:xdigit:]*PPjjjjjjjjjj~y<#*scf_\"^e[:xdig(\?(i)t(:])~$y)^){-131,77}^L%", 1, 0 },
+ { "[^[(((\?>)$}h9$B5+yhU/Nqh$YYYYYYYYYYYYYYYYYYYYYShK)3WHw1vMMMMMMMMMMMMM(\?=MMMMMMMMMMMM[:alnum:]/)dddddddddddd(dddddd\"e5zLW)+![:space:]+BHGHfAS]\?IIIIIIIIIIIIIIII*&&&&&&&&&&&&&&&&&&)NNvwDteepjdm<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<${61,219}D][:digit:]0", -1, 0 },
+ { "[:punct:][{177,(\?=234}]ix9*)", 0, 0 },
+ { "([^K{,3(\?<=4}]I)\?U)", 1, 0 },
+ { "[([^[[[^([([^[^(\?=])X", 0, 0 },
+ { "[:blankcntrl:(])qd_R\?{\?r[=\"[^[^6]vX8)a+{C%H84CK6Uy#E]sE{208}", 0, 0 },
+ { "PPPPPPPPPPPPPPPPPPPPPPPPPPnnnnnnnnnn()[:upperword:]us", 1, 0 },
+ { "x{,46}[:graph:]LU{}CU)", 0, 0 },
+ { "()-t|[^W{}][:lo[^werprint:]{}]\?b5", 1, 0 },
+ { "()x5A", 1, 0 },
+ { "[([^]-217)]s{-47,135}0000000000000000000000000000000{,-108}", 0, 0 },
+ { "[^((\?{[^L\?u]})f", 0, 0 },
+ { "()[[^^(\?{y(\?=VF_(\?<=]D}))]-= {46,})^5bIEQ{,-96}Z", 1, 0 },
+ { "([^{}f[:punct:]\"X%%%%%%%%%%%%%%%%%%%%]5{-194}A[:punct:]mnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn+AAAAAAAAAA-)", 1, 0 },
+ { "(CCCCCCCCCCCCCCCCCCCC{-230}352{-182,-68}O4{})", 1, 0 },
+ { "([^[^\?[:space:]$TTTTTTTTTTTTLLLLL[^LLLLLLLLLL[^({}{4,-179}]]J] C]){}C{}{-224,})QQQQQQQQQQQQQQQQQ^", 1, 0 },
+ { "([[:alnum:]].){-155,-82}dzI{55,}^", 1, 0 },
+ { "([[:alnum:](\?#{88,-178})[:graph:]NC\"pI[:punct:]rmWd5y^p+gUP]YYYYYYYYYYYYYYYYYYYY~{,-62}{,200}{-109}{}+333333333333333333333333333333{}p)^.hhhhhhhhhhhhhhh", 1, 0 },
+ { "[000000(\?mmsx:00000000000000000000000)M]]]]2*`[^]QQQQQQQQ(\?<=QQQQQQQQQQQQQQQQQQQQQQQ])\"<h\?", 0, 0 },
+ { "[^((<g(\?>5j[bbbbbbb(\?{bb)o{}3(\?imxisx:E]g})YYYYY[:blankcntr(\?#l:].(()w264[:ascii:]^)[:ascii:]G)&(n {^PGn[:xdigit:])nv_e|]{-103,30}", 3, 0 },
+ { "[^(([(\?!{}@[^HCO[[^^D[|]{,-49}][:xdigit:]]c`4[:ascii(\?<!:])$66666666666)*)]PP$Z[:alpha:]{,-235}UK],(aT/+6rbMqs60EloA)[:g(\?isx:raph:]!)]z$o{-24,}x1E[:blankcntrl:]ZDFvk", 1, 0 },
+ { "[:blank(\?=cntrl:]US@.!\"[:digit:]*E)$16182", 0, 0 },
+ { "[-{}x{3772[}][:(\?<=xdigit:][:u(\?#pperword:].W)aD)<pfN<b=C|-{-38}EZdOP|!>ggggggggggggggg\\\\\\\\\\\\\\\\\\\\\\\\\\Ef[:space:]\?][:ascii:]{21,}", 0, 0 },
+ { "([:xdigit:]W[:u(pperword(\?::]jS [:upperword:]*)[:alpha:]nnnnnnnnnnn))-148}SSu", 1, 0 },
+ { "([^(\?!\?)[(:upperword:])Bx^x$~lCr6*)6", 1, 0 },
+ { "[{,-78}Y[:xdigit:][^s(\?>]P[:space:])]YYYYYYYYY[:punct:][:alnum:][:blankcntrl:]", 0, 0 },
+ { "([MMMMMM(\?(MMM)M(\?<=MMMMMMMMMMMMMMM[^M)]en][:punct:]-[:alpha:]))Nr[:space:]", 1, 0 },
+ { "~=1([^(\?=(\?:l){}])j{-44}{-18}[^u[:graph:]]{-187,}[:xdigit:]w[:alpha:])", 1, 0 },
+ { "[ccccc(\?>c(\?{cccc[ccccwetoCei+)w&-+{,-142}[:alpha:]PP66io4(|zkA=],,,,,,,,,,,,,,,,,,,,,Lx5Cx{d2bb}]{188}U~~~~~~~~~~~~~~~~~~~~~~~})", 0, 0 },
+ { "Q|0\"[:d(\?:igit:]^{,-174})", 0, 0 },
+ { "[^[(\?>rh])]", 0, 0 },
+ { "[ees{{{{{{{{{{{{{{{{{bbbbbbb4`ml******(\?=****+])", 0, 0 },
+ { "((hdG[((\?<=:dig(it:])[^[:alpha:]$(\?sxi:)x{11390}[(\?{:upperword:]~)i 8[:blankcn[trl:(])]+{,-183}Zqp", 2, 0 },
+ { "Dd{D8`+DW={-[53,1(\?<=71}])", 0, 0 },
+ { "[:(\?(alpha:][:punct:])", 0, 0 },
+ { ".LLLLLLLLLLLLLLLLLLLLLLLLLLLL{}pP[:punct:]x0CZ{30,}!!!(!!!!!!!!!!!!!!!!!!!!!!!!!==@77.%[:graph:]D)", 1, 0 },
+ { "[^[^[[r(\?#]){-237,}RRRRRRRRRRRRRRRRRRRRRRRR[^Rll(\?!(\?{lllll]", 0, 0 },
+ { "()*ooooooooooooooooooooyyyyyyyyyyyyyyy", 1, 0 },
+ { "{,4(}D)JJJJJJJJJJJJJJJJJJJJJJJJJ", 1, 0 },
+ { "((b.D{}[:al[pha:]{64}]{})==========================[:alnum:]h>77b)!Ab", 2, 0 },
+ { "([^[^[^oooooooooooooooooooooo][:space:][:punct:]PeniKe*~$g\?${>[:lowerprint:]w))))))))))))))){}yyyyyyyyyyyyyyyyyy]pP.|QhZ]{,190})sssssssssssssr+=[:blankcntrl:]WWWWWWWWWWWWWWWWWWWWW", 1, 0 },
+ { "([*(\?{})hhhhhhhhhhhhhhhh]G{,-170}QdErrrrrrrc-jjjjjjjjjjjjjjjjjjjjn+{-130,-10})PpDS@Bee", 1, 0 },
+ { "([:b(\?=lankcntrl:]))T[:alnum:]{-224}ywt", 1, 0 },
+ { "([633(\?<=333(\?<=3333333333(333333)^\?]aGA)[:digi(\?>(\?{t:])$[[:space:][:xdigit:])|8T\?',_{171}{}{113}b\?5kAv0/7{})`huh>xM]C8pYRz]s$Eu08)", 1, 0 },
+ { "-(pP)[:alnum:]$^", 1, 0 },
+ { "[^x(\?{{17681}]P*)U(_t/8E_\"iN})3333333", 1, 0 },
+ { "(([^([[r(\?=[[^^*kx$][:alpha:]:::[:::::[^[^::::::::((\?{\?{::]).^p[:space:]}){52}{}]W{}fn", 2, 0 },
+ { "[:(\?>punct:]Ef[:xdigit:]x{c07b}{-50}Z{129,}YL1T`\\A)x[:punc(\?=t:]e[:xdigit:]2c6E46Y)+n ", 0, 0 },
+ { "[^(\?!{,-79}[:punct:]'|}>,)][:blankcntrl:]{-118,-231}{-119,-50}:XXXXXXXXXXXXXXXXX-~{}$txlB)3KFL", 0, 0 },
+ { "[^(([^fccccccccccccccccccc(\?<!ccccgQeKMfKzz]X$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$[:l(\?<=(\?<=owerprint:]))s{-97}{}))EUi${,-132}'{79}---------{,-93}77777777777777777[:lowerprint:].:H)[:punct:]nnnnnncP\?s1:dGed{186}N@pppppppppppppppppppppP{-212,-110}[:space:][:lowerprint:]$S}7{-112,164}-*.{-184,}OOOOOOOOOO]f\?", 0, 0 },
+ { "(([\?#(\?>)])qcU$Q7|82\?{})", 2, 0 },
+ { "[^yyyyyyyyyyyyyyyyyyyy(\?#yyyyyyyyyyya][:ascii:]\?)", 0, 0 },
+ { "(([((\?{)EEEE(\?<!EEEEE(\?:EEEEEE~)}){244,}QQQQQQQQQQQQQQQQQQQ(\?>QQQQQQ(\?!QQQQQ][:digit:]\?))99999999999999)[:digit:][:upperword:]b))PP{}{}", 2, 0 },
+ { "(K(c=B))", 2, 0 },
+ { "(G`*s\?b[:g(raph:]))", 1, 0 },
+ { "[^[([[[*QQQQQQQQQQQQQQQQ(\?=(\?=QQQQQQ(\?<!QQQQQQQQZddddddddd((\?{\?>ddddddddddc{22,}iiiiiiiii(iiiiiiiiiiiiiii(\?#iiiiiii[^i))\?\?\?\?\?\?]WWW)[:lowerprint:])]{-60,202}+[:upperword:]f[:xdigit:][:alnum:]{,-214})1~~~~~~~MMMMMMMMMMMMMMMMMM.", 0, 0 },
+ { "({-102,})A.", 1, 0 },
+ { "[((((\?<!(\?[^>(\?#\?()))p\"JD.{}(\?>)))((\?{l(\?<=).'053][:xdigit:]N+)})]WWWW%[:asc(\?{ii:]}))B[:alnum:]X){}s[:digit:]", 0, 0 },
+ { "x7&{139}WWWWWWWWWWWWWW[:blankcntr[^(\?<!l:]-71]\"{-167}cqkI)[:dig[^it:]{}{}[:digit:]*[:punct:]-[l11111111111111111(\?(111111111{175,-216}~[:alnum:]`+X1F)vCpWSp(\?>~[^n@f`````````````)````````P])Y,N{}{}]{}pXF@)", 0, 0 },
+ { "G[([(\?(^)$])P]^[:alnum:]){,-48}[:blankcntrl:]{}", 0, 0 },
+ { "[[^[^f(\?=f(\?<=fffffff[^fffffffff[^fffffffff(\?<=fff]){-194,150}fx{e5a4}V", 0, 0 },
+ { "9[:xdigit(\?{:]})", 0, 0 },
+ { "[^([[(\?>()$xxxxxxxxxxxxxx[xxxxxxxxxxxxxxxx((\?=aA)s13]])pp[(\?>pppppppppppppppp|{}){20,}]b)]{-179,183}{-204,}[:ascii:])]-11111111{}{,132}qooooooooooooooooooo{}${}|9t", 0, 0 },
+ { "([^[{}]\"[^6]*-{,-106}{}u]BR~8WG,U-)[:blankcntrl:]", 1, 0 },
+ { "[''''''''(''''''''''z])c", 0, 0 },
+ { "[^[(\?>])[:alnum:]r[:alnum:]+{,215}D]", 0, 0 },
+ { "([({,127}7Qr(\?:z)pPNev%}(\?msximsx:4(\?<!){}&.D5555(\?<=55555555555555555555i$[:xdigit:]){,-157}[:graph:]U[:punct:]nn(\?=nnnnnnnnnnnn(\?>nn(\?:nnnnnnnn_U{}]E)):^oooooooooooooooooooooooooooo)", 1, 0 },
+ { "[^(\?#)(\?<!k2z]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]BW[:alnum:][:graph:]{157}Y]s$C)[:graph:]{,-189}", 0, 0 },
+ { "$+CCCCCCCCC[^CCCCCC(\?<=Ca=]r{-81}[:alpha:][:alpha:])E=", -1, 0 },
+ { "[(((\?=\?{([^(\?<=)])>!(([:alnum:]{252}{}})ffffffffffffl){}A2r\?~ImE\"[:punct:]){}[:digit:]", 2, 0 },
+ { "([:blank[cntrl:]].t^P)", 1, 0 },
+ { "[^[(\?:X])|rrrrrrrrrrrrrrrrrrrrrrrrrr*P]Q", 0, 0 },
+ { "[[[^(\?{((\?<!))s})(\?<!A){14}(\?:L*+TTTTTTT]U{[^-12([\?!,}\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?)Y`Y)L]|]]|]", 0, 0 },
+ { "hkXzf',]yP$+[:u(pperword:])", -1, 0 },
+ { "(#[:blankcnt(\?iximsx:rl:])$QQQQQQ{}[:digit:])\?A", 1, 0 },
+ { "(B{-34,})*{,106}", 1, 0 },
+ { "[(\?{:graph:]})", 0, 0 },
+ { "((){}{,63}[:punct:]^t[:space:])^17737", 2, 0 },
+ { "([^[SSSSSSSSS[SSSSSSSSSSSSSSS[([[[{38,}]Jn][:alpha:]])])$'", 1, 0 },
+ { "[^({}{95})B{1(\?>15}]x{f779}ZZ,Wo)O[:alpha:][:lowerprint:]{81,228}Q[:upperword:]", 0, 0 },
+ { "[[^[^()n[[[[[[[[[[[[^[[[[[[[[[[(\?: G)(\?{K![^m) j(\?:C|((\?:n*Xlaa908:n$m,))[:xdigit:]x(\?{{1a5cd}pppppppppppppp(\?(pppp)p(pQ)))ddddddddddddddddddddddddddddddd]q[:alnum:(\?{]Ga})\?})@[:lowerprint:]{,169}[:blankcntrl:][:graph:]]n{-76,}|U\"{,-54}t]I{}{-64,-232}]\?].\?{-111,227}) @hFp\?j=H$Wbu<{,209}De{,145}{206}-})[:blankcntrl:]", 0, 0 },
+ { "[^[^(LLLLLLLLLLLLLL[^L[L[:alpha:]3{,189}(\?#(\?>n){}^EXXXXXXXXXXXXXXXXXXXXXXXXX]c*)^r=$WWWWWWWWWWWWW", 0, 0 },
+ { ")w###################", 0, 0 },
+ { "{,121}[:d(\?(i)git:])E\?[:punct:]LLLLLLLLL[:ascii:]+", 0, 0 },
+ { "([]]]]]]]]]]]]][:space:]Jrt3o.]b)pwwwwwwwwwwwQfm~", 1, 0 },
+ { "[+-{,-120}*(\?!()t*(\?(\?{>G)F)yd]V{}f<\?}){245}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[:upperword:]", 0, 0 },
+ { "(DDDDDDDDDDDDDDDDDDDDDDDDDDDDDc[:space:][:pu[^nct:]{-11,12}[:ascii:][:alpha:]{,155}P])", 1, 0 },
+ { "()ggggggg{-136,-21}", 1, 0 },
+ { "([^((\?<=U\?)(\?=^^^^^^^^^^^[^^^^^^^^^^^^^///(\?#//[////////////////////(\?()#######b+]$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$^[:digit:])\\U]Q8@}4d)\\U", 1, 0 },
+ { "A[:graph(\?::])-mo=U[:upperword:]ttttttttttttttttttttttttttt", 0, 0 },
+ { "[^(((\?=\?im-m(sx:)c~~[^~~~~~~~~~~~~~(\?>~~~~~~~~~~~~~SSSSSSSSSSSSSSSSSSSS]{51,}[:digit:]{,-179}N))kk[kkkkkkkkkkkkkkg$)[(\?::punct:]zWl)]|)*", 0, 0 },
+ { "[((\?=()+A)][:graph:]x0B)[:graph:]", 0, 0 },
+ { "(nR%B[:blankcntrl:]C=|en-[:digit:]n[:graph:]HHHH[HH]D\?%[:digit:]MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM.z(oF9zW8A7cfff(f))-[:blankcntrl:][:blankcntrl:]A[:digit:])D{,-243}", 3, 0 },
+ { "([[()]]{,-251(})\?L)uw@", 2, 0 },
+ { "\"|{(,-144})A.ooooooooo(ooooooFFFFFFFFFFFFF\?)n{,-18}", 2, 0 },
+ { "([^([(([[^([000000[0(0(\?!0(\?=0000000])45|E]", 1, 0 },
+ { "[B[[[[[[[[[[[|{}*oKqv%(\?<=wsQ{1pMeK1^6%nLNqi<@ge][:punct:]= M@* D|NwL\\-117\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"~Qnd]h.O\"01x:[:alpha:]^){}D}\"", 0, 0 },
+ { "([[RRRRRRRRRRRRRRRRRRRRRRRRRRRRxpSrx{7d79}*oJ2`Ft{n1,3g:1H@bT$D &[n/Cg)=ld@Ir{Fk>*4*`(\?>````````````````````(\?:`````.....................]]{,246})7 \"F4[^F|/g)]+e`rw@{,-69}H)", 1, 0 },
+ { "([(\?<=)X[:digit:]PP.[(\?#:((\?#\?#graph:])[:digit:][Q+)(N][:alpha:]]f)[:graph:])+Elllllllllllllllll[:digit:]=)pP{uU-20bzY|ZKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKt<c", 1, 0 },
+ { "[^(([^$(\?:(\?#w)[(\?::punct:]]d{-149,}[:ascii:])[:blankcntrl:]@@@@@[@@@@@@@@@@@@@@[:graph:][:xdigit:]O[:alpha:]2$-[:graph:])[:lowerprint:]-\?#S[:blankcntrl:][:alnum:]){-77,}]d[:digit:]N5v+Sqqqqqqq^% -I4]*.)^[:alnum:]JDfjMRU7ttttttttttttjjjjjjjjjjjjjjjjjjjjjjCCCCCCCCCCCCCCCCCCCD{,21}{0,67}[:graph:]{,208}B", -1, 0 },
+ { "(%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%[:ascii:])i{}[:lowerprint:]epxxxxxxxxxxxxxx[:lowerprint:]r-", 1, 0 },
+ { "([(^w(\?!)()])-s", 1, 0 },
+ { "[aIIIIIIIIIIIII(\?imsxims(\?=x:IIIIIIIm^NXXXXX(\?!(\?isximsx:XXXXXXXXXXXXXS0]F)z))+rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr{,-237})ZZZZZZZZZZZZZZZZZZZZZZ", 0, 0 },
+ { "(Z)[:alpha:]", 1, 0 },
+ { "U#Z(=)", 1, 0 },
+ { "([:lowerprint:][:punct:])1cVb*[:xdigit:]&&&&&&&&&&&&&&&&&&&&&&&&O", 1, 0 },
+ { "()~K`3/[^*h[]G6[:upperw(\?()ord:]w)[:punct:]]{}", 1, 0 },
+ { "[[[]V[:digit(\?>:])|l*KKKKKKKKKKKKKKKKK,,,,,,,[,,,s.{148,}P33333][:lo(\?<!werprin(\?!t:]ZZZZZZZZZZZZZZZZZZZZZZZ]{,-229}{-160,}){,-211}XPPP].{}z[:alnum:][:alpha:(\?=]t{166,}uuuuu6]i*p(m))[:space:]E|S", 1, 0 },
+ { "[^(h(\?(\?({#2})(\?(\?#>Q){,57}%[:digit:]\?\?\?\?\?\?\?\?\?\?.[)]]d{)-49,}f)^O{,68})\?C", 0, 0 },
+ { "(}u])18621", 1, 0 },
+ { "[:as(\?=cii:][^(\?=)(S-{.F-[:punct:]3-105^[:lowerprint:]111111111111111111111111---)][:alnum:][:ascii:]JJJJJwHSk", -1, 0 },
+ { "[^3>>>>>>-sZ^^^^(\?>]Y[:di(\?(\?imxim:#git:]{-158,-102}[:punct:]{}{87,})))[:upperword:]", 0, 0 },
+ { "[(\?<!^r]$W){}*[:alpha:].[:digit:]", 0, 0 },
+ { "[:ascii(\?::[^])X]-", 0, 0 },
+ { "[([^]Z)[:upperword:]N{}*[:graph:]*^", 0, 0 },
+ { "([[(\?#^[(:graph:]]){205,}[:gr(aph:]T%]^MMMMMMMMMMMMMMMMMMMM){) <v\\[:digit:])", 1, 0 },
+ { "[^Y.h~b(\?<=~P{(\?=169,65}\?[^\?\?\?\?\?\?\?\?\?[\?\?\?\?\?\?\?\?\?K\"s`[yT7oP[:alpha:]{})]zrrrrrrrrrrrrrr)]KKKKKKKKKKKKKKK[:digit:]S][:lowerprint:][:digit:]", 0, 0 },
+ { "(s)", 1, 0 },
+ { "[u(\?!uuuuuuuuuuuuuuuuuuuu[:digit:]{,48}[:graph:]WL[:alnum:]]v=_)VN>{AjBBBBBBBBBBBBBBBBBBBBBBB[:upperword:]`'W)", 0, 0 },
+ { "[^([[()DN1[^][|]\?]{-104,}])[:space:]][:lowerprint:]r[:alpha:].DU", 0, 0 },
+ { "[^((33333333333333333333333(\?<=3333333D))kkkkkkkkkkkkkkkkkkkkkkk[k[:alpha:]])]X+", 0, 0 },
+ { "[({,-17})[@e{220,(\?#41}])]]{-213,-225}", 0, 0 },
+ { "[[^(\?#[(\?:^[[(\?(^]))]])]vvvvvvvvvvvvvvvvvvvvv{,96}|m]{-79,248}[:alpha:])", 0, 0 },
+ { "([[(\?imsisx:^}$,-[:al(\?>num:]Xqqqqqqqqqqqq{-185,154}]b#+T){-241,})A{-27}[(\?<!:lowerprint:]X)[:punct:]ME-]+BBBBBBBBBBBBBBBBa|{-40}M8mhgD 0HU]{16})", -1, 0 },
+ { "[^(\?>([\?()(\?#))]--R1rk^UnP.[(\?!:digit:]])^)[:upperword:]{}0000000000000000000000000000000~U{-139,-19}z<L-228", 0, 0 },
+ { "()-:=3uE$[:alnum:]bP%{-210,}", 1, 0 },
+ { "(U)7777]]]]]]]]]]]]]]]]]]]]]]]]]]]]]c::AA[:alpha:]{,3}f1{NzH@3lTf{}{", 1, 0 },
+ { "[C{(\?>})RR(\?=R<]p'N~&.-})6]", 0, 0 },
+ { "[^\?[^(\?(lFt]).[^7Q-])kkkkkkkkkkkk]XTFy\"1Deiv!,'xVK", 0, 0 },
+ { "[^$[^[:xdigit:](\?{*{245,99}h8v(\?!)]]u)Z[:punct:]})[:alnum:]+|[:blankcntrl:]u{}[:lowerprint:]+bBJ4+k-v{-116}", 0, 0 },
+ { "S)f{,180}[:graph:]&{12,244}", 0, 0 },
+ { "(([[(.()[^^{80(\?>(\?<=,235})ddddddddd[^ddddddddd(\?<=d.__B{36}````````````````(\?:```(\?>```````,,,,,,,(\?:,,)P$U,[:xdigit:])zzzzzzzzzzzzz]UUUU[uB]n<&[(:ascii:].][:alnum:])\?S]{})d{138,}s9========[:lowerprint:]]OOOOOOOOOOOOOOO|yyyyyyyyyyyyyyy$LZ[:lowerprint:]EEEEEEE[:ascii:][:punct:]VpP^{-48}D){,46}x))2P))a[:lowerprint:]r", 2, 0 },
+ { "[^(((\?<!):())PPPPPPPPPPPPPPP(\?=[PPPPPPP(\?{PPPPPPPP$)})77777777777777777]{,-57}::::::::::::(::::::::::::::::)]g{89}__________________[:xdigit:]l[:punct:])N", 1, 0 },
+ { ":02-k\?p3I7aEhJ\\265-[:space:]pP[:space:]x0F[:alnum:]aM4[:lowerprint:]sA@@@@@@@@@@@@@@@@@@@@@@@@@@@@", -1, 1 },
+ { "a[:upper(\?{word:]})X{-173,}-2F[:lowerprint:]", 0, 0 },
+ { "u,w<g*Q002S{,130}{239}[:lower(print:]cr{-165,}#$k<L/&)[:blankcntrl:]aaaaaaaaaaaaaaaaaaaaaa[:ascii:]", 0, 0 },
+ { "(xFA^{-161,93})U[:xdigit:]", 1, 0 },
+ { "[^(\?=]{})mE`", 0, 0 },
+ { "[[((\?(\?#:alnum:]])x6CS[:digit:]{-197,}.)N", 0, 0 },
+ { "[^(\?![])C*[:upp(erword:])-176]", 0, 0 },
+ { "[[^[[^[55555555555555555555555555(\?>555(\?<!555)S][]]A[:l(\?>owerp(rint:]])]*", 0, 0 },
+ { "Au)khgzAfXIZoZ=g[:digit:]){,186}Upvf=x<]Tbd5Rq\?.", 0, 0 },
+ { "b{-176,}B^[:bla(\?(<!nkcntrl:]{-6,133}#B :)<<<<<<<<<<<<<<<<<<<)[:alnum:]$}}}}}}}}}}}}}}}}}}}}}}}[:xdigit:]tw", 0, 0 },
+ { "(4IIIII(IIIIIIIIIIIIIIIII{})W{-152,-238}){,-56}^{-142,}", 2, 0 },
+ { "[^([[(\?(\?(!)>>>>>>>>>>>>>(>>>>>>>>D)Ix{(1(\?imxmsx:762)c}))A)[[[[[[[[[[[[[[5Rp]DDDDDDDDDDDDDDDDDDDD]Us+\\w[:digit:]{-47}[:xdigit:][:blankcntrl:])ddddddddddddddd[^ddddddddddddd[:digit:]|]]*{-165,-230}{-212}{53,}]\?", 0, 0 },
+ { "[^[^]]|[:(\?:alnum:])}}}}}}}}}}}}}}}}}}}}", 0, 0 },
+ { "VVVVVVVVVVVVVVVVVVVVVVVVVVVV[:d(i(\?#git:])){{{{{{[:digit:]ZfQ55555555{}Z", 0, 0 },
+ { "[L][:blankcnt(\?((\?=rl:(\?=]){-35,[^}){)eJb>>>>>>>>>>>>>>>>>>>>>>$ [:xdigit:]l0Tv2Tw2@C[:space:]Zc/{*)>]N3j~.dMBBBB", 0, 0 },
+ { "[[^(\?>(([]))])[:graph:]]{65,}as#Q:lQ", 0, 0 },
+ { "[^[fPPUUUUUUUUUUU(\?#UUU[^UUUUUU(\?<=UUUUUUUUUGGGGGGGGGGGGGGGGGGG((\?{\?=GGGGGG.MK))+]+)&UxFW)rwv\?@D.", 0, 0 },
+ { "{-(60,})m", 1, 0 },
+ { "b[(])^w", 0, 0 },
+ { "[][^qVs(\?:(p])X)\?'", 0, 0 },
+ { "()8", 1, 0 },
+ { "(t[:punc[^t:(\?{][:blankcntrl:])})[^8\?]z*]", 1, 0 },
+ { "[:lowerprint:])[:graph:]lppppppppppppppppppppppppppppf", 0, 0 },
+ { "[:alph(a:])[:ascii:]g +z-Bc-U{,%Gk", 0, 0 },
+ { "u[:graph:(\?=]*)W:::", 0, 0 },
+ { "([:alnum(:])l)", 1, 0 },
+ { "[[[}}}}}}}}(\?<!}}}}}}}+(\?{),,,,,,,,,,,,,,(\?!,,,,,,,,]99999999999&R[:ascii:]ZZZZ-{-10,}{96}Ed*][:graph:])]}){}{}G{-9,}", 0, 0 },
+ { "([^[{}]]Z[[^:graph:]{-47}55555555555555555555555555555[:ascii:]s]6,$:3qAew1Y)+)[:punct:]", 1, 0 },
+ { "[[[[[([[[[[[[[[[[[[[[[[[[[[[[[8!1i]')", 0, 0 },
+ { "([((\?(\?#>)(\?{,)At]%M9FSq5)EB", 1, 0 },
+ { "(}````````````````(``{210,})[:(\?#space:]P[:digit:])PP.{-227,}$pK~mm ImR|{,51}[:alnum:]<)[:alpha:]", 2, 0 },
+ { "[^(\?<=])[:digit:]", 0, 0 },
+ { "[^'''''''{(\?:178,}e{,16}$QQQQQQQQQQQQQQQQQQQQQQQ$])", 0, 0 },
+ { "[^(\?>@K*)(\?#d18]{78,}B)[:digit:]{-193,}=wg{,59}", 0, 0 },
+ { "[^.{156,}!(\?<=!!!!!!!!!!!!!!(\?{!(\?(!!!!!!!!!!!!!)})TTTTTTTTTTTTTTTTTTTTTTTTTTTTT[^}}}}}}}}}}}})}}}}}}}}}}}}}]]){}^L#%-{}FC", 0, 0 },
+ { "(eeeee{-169,-100}-fa[:upperword:]N)$Nellllllllllllll", 1, 0 },
+ { "[[(\?!())\?[(\?!:alnum:]e{,28}M])[:punct:]CCCCCCCCCCCCCCCCCCCC]{-150,}{-167}", 0, 0 },
+ { "[[@[@(\?#@[@]P]Z{')]{-186,117}]+)7f-", 0, 0 },
+ { "\\Q+kD}]AEM)u ", 0, 0 },
+ { "([(\?{(\?=:::::::::::::&){,210}]^})P{-31,}8[:space:]C[:alnum:][:a(scii:]z|[:upperword:])[:alnum:][:graph:])zr~Zk", 1, 0 },
+ { ".[:space:]e[:g(\?{(\?{raph:]})})@@@@@@@@@@@@@wb|~k", 0, 0 },
+ { "()ooooooooo\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"[:graph:]", 1, 0 },
+ { "[^64h(\?(@Eyw][:xdi[git:]pP%%%%%u(uuu[:up[perword:]`8Utdh{)}]]))lW[:punct:]W.hhhhhhhhhhhhhhhhhhhhhhhh'm<<}O8`ZXtG.$", 1, 0 },
+ { "BPP[:digit:]bbbbbbbbbbb(bb)S+[:alnum:]", 1, 0 },
+ { "um.[:ascii((\?#\?!:])*)+KKKKKKKKKKKKKKKKKKKKKKKKKS.=<Bf", 0, 0 },
+ { "", -1, 0 },
+ { "(()$[:lowerprint:][:s[pace:]2]bbbbbbbbbyoooooooooooooooooo*{39,}$')qV`AcH>,eDl", -1, 0 },
+ { "(()[^])e{-241,}", -1, 0 },
+ { "()[:alpha:]rliiiiiiii[:alnum:]Mb*QW9N.>\?{115,}&u*j", -1, 0 },
+ { "()[]p", -1, 0 },
+ { "(I[^]pfL)$[:punct:]", -1, 0 },
+ { "([])>>>>>>>>>>[:alnum:]", -1, 0 },
+ { "([])O\\\\\\\\\\\\\\fffffffffffffffffffffff=s6jCZy/b+ir2'*{151,}", -1, 0 },
+ { "([])nnnnnnnnnnnnnnnnnnnnnnnnnn[:xdigit:]^N$f", -1, 0 },
+ { "([]M)[:lowerprint:]a(pg$Z[:punct:])77777777777.", -1, 0 },
+ { "([]XXXXXXXXXXXXXXXXXXXXXX-===========)", -1, 0 },
+ { "([]lkX{-224}[:blankcntrl:]$gPKIZlSC#F@XX I'^}{234}yZm)uuuuuuuuuuuuuuuuuuuuuurS", -1, 0 },
+ { "([^0kYkg9])IIIIIIIIIIIIIIIIIIIIII/{(192,-118}l+FoSD6\?A)c[:xdigit:]`````````````````e-{-4,-170}x{4620}Z[:upperword:]", -1, 0 },
+ { "([^[^[^()(\?>){}B]XYF+#[:alpha:]{-85((,-55[^}t]n).{,-33}]](bQJ!|O+{175,})RFh)Z+^.{137,}:VpP[:alpha:]-MceqVVkkkk(kkkkkkkkkkkkkkkkkk)\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?{-115,-67})``````````````````````````````", -1, 0 },
+ { "([^]EzU[:alnum:]+^^^^^^^^^^^^^^^^^^^)[:xdigit:]HHHHHHHH$66666666666666666666666666666666UUUUUUUUUUUUUUUUUUUUL{}iiii{-76}X", -1, 0 },
+ { "([^]~~~~~~~~~~{240,})]NOp", -1, 0 },
+ { "(sb)[:digit:]VVVVVVVVx{9569}52,|]", -1, 0 },
+ { "(x{19762}){}", -1, 0 },
+ { "-[:xdigit:][]", -1, 0 },
+ { "121|", -1, 0 },
+ { "141[:xdigit:][:lowerprint:]{24}{59,191}[:digit:]/", -1, 0 },
+ { "G[^],,,,,,,,,,,,,+\"DiX", -1, 0 },
+ { "Gm(ho9:\"8{-188,-200}Z[:blankcntrl:]{,171}\?\?\?\?\?\?\?\?\?\?\?[:blankcntrl:]LLLLLLLLLLLLLLLLLLLLLLL{}^[:graph:][:blankc(\?#ntrl:])w", -1, 0 },
+ { "N\"\"\"\"\"\"\"-------------------------|[:alnum:]AAAAAAAAAAAAAAAAAAAAf\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?", -1, 0 },
+ { "U{-30,}^\?\?\?", -1, 0 },
+ { "W^*04rAY(Ee*>[^o3[]]_)", -1, 0 },
+ { "X[^]}*C[:alnum:]", -1, 0 },
+ { "[${,-3}]+^\?[|x8A|][:space:]'''''['''''JJJJJJJJJJJJJJJJJJJJJJJJJJJJJyl}.Y7G]", -1, 0 },
+ { "[()&[&&&]\?\?[\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?pg%k8ug`Wqk4|NR{h[CK5Ez=]jHpQw&`{:]{,91}D", -1, 0 },
+ { "[(\?#(\?:)[)([\?>)(\?>(\?:[:alnum:])]G]{85}[^)w]N]gYrUs|", -1, 0 },
+ { "[(\?<=)[:digit:]\?]{152,}VR|", -1, 0 },
+ { "[****(\?>**********(\?<!*******Q)Vr){[^25,}*:FFFFFFFFFFFFFFFFFFFFFFFF(\?{FFFF(({}D]|", -1, 0 },
+ { "[:ascii:]+{124,}:*]\?$-{92}D[:lowerprint:]`````````````````````", -1, 0 },
+ { "[:ascii:]\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?A<", -1, 0 },
+ { "[:blankcntrl:]p\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?$\?TTTTTTTTTTTTTTTTT[:ascii:][:upperword:]", -1, 0 },
+ { "[:punct:]{254}DDDDDDDDDDDDDDD@[:alpha:]Z\?\?-----R", -1, 0 },
+ { "[:upperword:]J\?\?nqCAdfyW5", -1, 0 },
+ { "[:upperword:]{-39}|", -1, 0 },
+ { "[:xdigit:]^\?", -1, 0 },
+ { "[Z*e ]NdmP\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?", -1, 0 },
+ { "[[:punct:]q]ex{15625}-", -1, 0 },
+ { "[[[^([^L((\?{b(\?=C\?]-134{,-207}[:ascii:]Hz}XIz}|", -1, 0 },
+ { "[[^V(\?:(\?<!(\?>))TTTTTTTTTTTTTTTTTTTTTTT)[:punct:][:digit:]]GGGGGGGGGGGGGGGGGGGGG,]|.{-224}{96}{239,}1", -1, 0 },
+ { "[[^^PP]{,-222}{182}{141}]zFD}-.", -1, 0 },
+ { "[] Hn&[:xdigit:][:upperword:]f", -1, 0 },
+ { "[]$.B", -1, 0 },
+ { "[]&&&&&&&&&&&&&&&&&&&&&&&", -1, 0 },
+ { "[]()[:xdigit:]er063{132,140}$", -1, 0 },
+ { "[]+1434", -1, 0 },
+ { "[]-", -1, 0 },
+ { "[]-#yyK", -1, 0 },
+ { "[]-(S$5)AxbdTKO[:alnum:]", -1, 0 },
+ { "[]2883", -1, 0 },
+ { "[]2dhd-[:alpha:]sssssssssssssssss55555555555555555555555555555555Z[:punct:]", -1, 0 },
+ { "[]4", -1, 0 },
+ { "[]44444444444444444G", -1, 0 },
+ { "[]\?", -1, 0 },
+ { "[]A", -1, 0 },
+ { "[]Gap8bc", -1, 0 },
+ { "[]OOOO", -1, 0 },
+ { "[]PP", -1, 0 },
+ { "[]QQ", -1, 0 },
+ { "[]WaFaGO,o", -1, 0 },
+ { "[]Z", -1, 0 },
+ { "[][:alpha:]|[:digit:]Ls$I-Ff~+xA3e", -1, 0 },
+ { "[][:ascii:]-218", -1, 0 },
+ { "[][:ascii:]N}}}}}}}}}}}}}}}-{137,}8682", -1, 0 },
+ { "[][:lowerprint:]Ur", -1, 0 },
+ { "[][:space:]15097", -1, 0 },
+ { "[][:xdigit:]", -1, 0 },
+ { "[]dpSSSSSSSS", -1, 0 },
+ { "[]e13768", -1, 0 },
+ { "[]gT", -1, 0 },
+ { "[]h", -1, 0 },
+ { "[]n", -1, 0 },
+ { "[]vvvvvvvvvvvvvvvvvvvvvvvvvv*[:xdigit:]", -1, 0 },
+ { "[]{,-212}1111111111111111111C3821", -1, 0 },
+ { "[]{-128,}hc", -1, 0 },
+ { "[]{-181,}&[:xdigit:].\?}}}}}}}}}}}}}}}}}}}}}}", -1, 0 },
+ { "[]{}F&}i`7|ZAH", -1, 0 },
+ { "[^(\?())u{196,}pP][r^ndddddddddddddddddddddd]{31,246}\?J", -1, 0 },
+ { "[^.ii.1-S]lwwwwwwwwwwwwwwwwww[^wwwwwwwwwwwwww[:alnum:]DOpP+<N][^]44{179}{-194,56}", -1, 0 },
+ { "[^2[:alnum:]]\?t\?\?", -1, 0 },
+ { "[^[((\?{[^^<<<<(\?(\?<!{)})(\?<!]{,184}{-213}|", -1, 0 },
+ { "[^[^[]\?{89,}PPsvf{[:space:]]]vd{161,}", -1, 0 },
+ { "[^[^].]+{0}s", -1, 0 },
+ { "[^]${}", -1, 0 },
+ { "[^]([:punct:]),%[:xdigit:]w^0\?{-233}", -1, 0 },
+ { "[^]-", -1, 0 },
+ { "[^].^", -1, 0 },
+ { "[^]6743", -1, 0 },
+ { "[^]JD", -1, 0 },
+ { "[^]N=[:upperword:]zzzzzzzzzzzzzzzzz.", -1, 0 },
+ { "[^]OLz_6", -1, 0 },
+ { "[^]PP[:digit:]0eBEx=", -1, 0 },
+ { "[^]SHzuKp", -1, 0 },
+ { "[^][:upperword:]{111}-TpmXw", -1, 0 },
+ { "[^]^''''''''z{-73,}", -1, 0 },
+ { "[^]^{,141}e", -1, 0 },
+ { "[^]aaaaaaaaaaaaaaaaaaa{-98,43}", -1, 0 },
+ { "[^]f", -1, 0 },
+ { "[^]l", -1, 0 },
+ { "[^]n\"Wt", -1, 0 },
+ { "[^]pPZ\?q+m0LJ+", -1, 0 },
+ { "[^]p[:upperword:]L:", -1, 0 },
+ { "[^]q\?{,-18}-", -1, 0 },
+ { "[^]s[:space:(\?<=]$", -1, 0 },
+ { "[^]{,58}t", -1, 0 },
+ { "[^]{255,}JJJJJJJJJJJJJJJJJJJJJJJJJJ", -1, 0 },
+ { "[^]{45}", -1, 0 },
+ { "[^]{W", -1, 0 },
+ { "[^]{}{-22}", -1, 0 },
+ { "[^]{}{}{}[:xdigit:]+", -1, 0 },
+ { "[^]|9{,-108}{}.LVIJJJJJJJJJJJJJJJPP", -1, 0 },
+ { "[^{,-254}]|", -1, 0 },
+ { "[o(\?{(\?<=}[))f++++++++++++++++777777777777777777777777yzPPs]\?\?dRRRRRRRRRRRRRRRRRRRRRRRRRRRR&]>%fffffffffff", -1, 0 },
+ { "aW|", -1, 0 },
+ { "cT{}[]C^r2``tm", -1, 0 },
+ { "kkkkkkkkkkkkkkkkkkkkkkk[:blankcntrl:]|{}3{26,}{151,}[:punct:]JJJlH$gP%(2WUE%%%%%%%%%%%%%%%%%%%%a){ibf{}\?", -1, 0 },
+ { "lZ\?\?\?\?\?\?\?\?\?\?\?-P2eZt[:punct:]", -1, 0 },
+ { "vF3qn[^]N.", -1, 0 },
+ { "wwwwwwwwwwwwww{-176,}275[^]>.UUUUUUUUUUUUUUUUUUUUeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee2$Yd", -1, 0 },
+ { "{-197,223}bf]]]]]]]]]]\?&}/s\?\?~c", -1, 0 },
+ { "{-37,}EpP|", -1, 0 },
+ { "{}@]a[][:xdigit:]z{a", -1, 0 },
+ { "}02|", -1, 0 },
+ { "}}}}}}}}}(}}){}[llll]^N|", -1, 0 },
+ };
+ unsigned int i;
+ int r;
+
+ UNUSED(tc);
+
+#ifdef HAVE_REGEX_H
+ /*
+ * Check if we get the expected response.
+ */
+ for (i = 0; i < sizeof(tests)/sizeof(*tests); i++) {
+ regex_t preg;
+
+ memset(&preg, 0, sizeof(preg));
+ r = regcomp(&preg, tests[i].expression, REG_EXTENDED);
+ if (((r != 0 && tests[i].expect != -1) ||
+ (r == 0 && tests[i].expect == -1)) && !tests[i].exception)
+ fprintf(stderr, "regcomp(%s) -> %s expected %s\n",
+ tests[i].expression, r != 0 ? "bad" : "good",
+ tests[i].expect == -1 ? "bad" : "good");
+ else if (r == 0 &&
+ preg.re_nsub != (unsigned int)tests[i].expect &&
+ !tests[i].exception) {
+ fprintf(stderr, "%s preg.re_nsub %lu expected %d\n",
+ tests[i].expression,
+ (unsigned long)preg.re_nsub, tests[i].expect);
+ tests[i].expect = preg.re_nsub;
+ }
+ if (r == 0)
+ regfree(&preg);
+ }
+#endif
+
+ /*
+ * Check if we get the expected response.
+ */
+ for (i = 0; i < sizeof(tests)/sizeof(*tests); i++) {
+ r = isc_regex_validate(tests[i].expression);
+ if (r != tests[i].expect)
+ fprintf(stderr, "%s -> %d expected %d\n",
+ tests[i].expression, r, tests[i].expect);
+ ATF_CHECK_EQ(r, tests[i].expect);
+ }
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, regex_validate);
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/result_test.c b/lib/isc/tests/result_test.c
new file mode 100644
index 0000000..cfaabb3
--- /dev/null
+++ b/lib/isc/tests/result_test.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <string.h>
+
+#include <isc/result.h>
+
+ATF_TC(isc_result_toid);
+ATF_TC_HEAD(isc_result_toid, tc) {
+ atf_tc_set_md_var(tc, "descr", "convert result to identifier string");
+}
+ATF_TC_BODY(isc_result_toid, tc) {
+ const char *id;
+
+ id = isc_result_toid(ISC_R_SUCCESS);
+ ATF_REQUIRE_STREQ("ISC_R_SUCCESS", id);
+
+ id = isc_result_toid(ISC_R_FAILURE);
+ ATF_REQUIRE_STREQ("ISC_R_FAILURE", id);
+}
+
+ATF_TC(isc_result_totext);
+ATF_TC_HEAD(isc_result_totext, tc) {
+ atf_tc_set_md_var(tc, "descr", "convert result to description string");
+}
+ATF_TC_BODY(isc_result_totext, tc) {
+ const char *str;
+
+ str = isc_result_totext(ISC_R_SUCCESS);
+ ATF_REQUIRE_STREQ("success", str);
+
+ str = isc_result_totext(ISC_R_FAILURE);
+ ATF_REQUIRE_STREQ("failure", str);
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_result_toid);
+ ATF_TP_ADD_TC(tp, isc_result_totext);
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/safe_test.c b/lib/isc/tests/safe_test.c
new file mode 100644
index 0000000..f721cd1
--- /dev/null
+++ b/lib/isc/tests/safe_test.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/* ! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/safe.h>
+#include <isc/util.h>
+
+ATF_TC(isc_safe_memequal);
+ATF_TC_HEAD(isc_safe_memequal, tc) {
+ atf_tc_set_md_var(tc, "descr", "safe memequal()");
+}
+ATF_TC_BODY(isc_safe_memequal, tc) {
+ UNUSED(tc);
+
+ ATF_CHECK(isc_safe_memequal("test", "test", 4));
+ ATF_CHECK(!isc_safe_memequal("test", "tesc", 4));
+ ATF_CHECK(isc_safe_memequal("\x00\x00\x00\x00",
+ "\x00\x00\x00\x00", 4));
+ ATF_CHECK(!isc_safe_memequal("\x00\x00\x00\x00",
+ "\x00\x00\x00\x01", 4));
+ ATF_CHECK(!isc_safe_memequal("\x00\x00\x00\x02",
+ "\x00\x00\x00\x00", 4));
+}
+
+ATF_TC(isc_safe_memcompare);
+ATF_TC_HEAD(isc_safe_memcompare, tc) {
+ atf_tc_set_md_var(tc, "descr", "safe memcompare()");
+}
+ATF_TC_BODY(isc_safe_memcompare, tc) {
+ UNUSED(tc);
+
+ ATF_CHECK(isc_safe_memcompare("test", "test", 4) == 0);
+ ATF_CHECK(isc_safe_memcompare("test", "tesc", 4) > 0);
+ ATF_CHECK(isc_safe_memcompare("test", "tesy", 4) < 0);
+ ATF_CHECK(isc_safe_memcompare("\x00\x00\x00\x00",
+ "\x00\x00\x00\x00", 4) == 0);
+ ATF_CHECK(isc_safe_memcompare("\x00\x00\x00\x00",
+ "\x00\x00\x00\x01", 4) < 0);
+ ATF_CHECK(isc_safe_memcompare("\x00\x00\x00\x02",
+ "\x00\x00\x00\x00", 4) > 0);
+}
+
+ATF_TC(isc_safe_memwipe);
+ATF_TC_HEAD(isc_safe_memwipe, tc) {
+ atf_tc_set_md_var(tc, "descr", "isc_safe_memwipe()");
+}
+ATF_TC_BODY(isc_safe_memwipe, tc) {
+ UNUSED(tc);
+
+ /* These should pass. */
+ isc_safe_memwipe(NULL, 0);
+ isc_safe_memwipe((void *) -1, 0);
+ isc_safe_memwipe(NULL, 42);
+
+ /*
+ * isc_safe_memwipe(ptr, size) should function same as
+ * memset(ptr, 0, size);
+ */
+ {
+ char buf1[4] = { 1, 2, 3, 4 };
+ char buf2[4] = { 1, 2, 3, 4 };
+
+ isc_safe_memwipe(buf1, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+
+ ATF_CHECK(memcmp(buf1, buf2, sizeof(buf1)) == 0);
+ }
+
+ /*
+ * Boundary test.
+ */
+ {
+ char buf1[4] = { 1, 2, 3, 4 };
+ char buf2[4] = { 1, 2, 3, 4 };
+
+ /*
+ * We wipe 3 elements on purpose, keeping the 4th in
+ * place.
+ */
+ isc_safe_memwipe(buf1, 3);
+ memset(buf2, 0, 3);
+
+ ATF_CHECK(memcmp(buf1, buf2, sizeof(buf1)) == 0);
+ }
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_safe_memequal);
+ ATF_TP_ADD_TC(tp, isc_safe_memcompare);
+ ATF_TP_ADD_TC(tp, isc_safe_memwipe);
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/sockaddr_test.c b/lib/isc/tests/sockaddr_test.c
new file mode 100644
index 0000000..fd6494f
--- /dev/null
+++ b/lib/isc/tests/sockaddr_test.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <stdbool.h>
+#include <unistd.h>
+
+#include <isc/netaddr.h>
+#include <isc/sockaddr.h>
+#include <isc/print.h>
+
+#include "isctest.h"
+
+/*
+ * Individual unit tests
+ */
+
+ATF_TC(sockaddr_hash);
+ATF_TC_HEAD(sockaddr_hash, tc) {
+ atf_tc_set_md_var(tc, "descr", "sockaddr hash");
+}
+ATF_TC_BODY(sockaddr_hash, tc) {
+ isc_result_t result;
+ isc_sockaddr_t addr;
+ struct in_addr in;
+ struct in6_addr in6;
+ unsigned int h1, h2, h3, h4;
+ int ret;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ in.s_addr = inet_addr("127.0.0.1");
+ isc_sockaddr_fromin(&addr, &in, 1);
+ h1 = isc_sockaddr_hash(&addr, true);
+ h2 = isc_sockaddr_hash(&addr, false);
+ ATF_CHECK(h1 != h2);
+
+ ret = inet_pton(AF_INET6, "::ffff:127.0.0.1", &in6);
+ ATF_CHECK(ret == 1);
+ isc_sockaddr_fromin6(&addr, &in6, 1);
+ h3 = isc_sockaddr_hash(&addr, true);
+ h4 = isc_sockaddr_hash(&addr, false);
+ ATF_CHECK(h1 == h3);
+ ATF_CHECK(h2 == h4);
+
+ isc_test_end();
+}
+
+ATF_TC(sockaddr_isnetzero);
+ATF_TC_HEAD(sockaddr_isnetzero, tc) {
+ atf_tc_set_md_var(tc, "descr", "sockaddr is net zero");
+}
+ATF_TC_BODY(sockaddr_isnetzero, tc) {
+ isc_sockaddr_t addr;
+ struct in_addr in;
+ struct in6_addr in6;
+ bool r;
+ int ret;
+ size_t i;
+ struct {
+ const char *string;
+ bool expect;
+ } data4[] = {
+ { "0.0.0.0", true },
+ { "0.0.0.1", true },
+ { "0.0.1.0", true },
+ { "0.1.0.0", true },
+ { "1.0.0.0", false },
+ { "0.0.0.127", true },
+ { "0.0.0.255", true },
+ { "127.0.0.1", false },
+ { "255.255.255.255", false },
+ };
+ /*
+ * Mapped addresses are currently not netzero.
+ */
+ struct {
+ const char *string;
+ bool expect;
+ } data6[] = {
+ { "::ffff:0.0.0.0", false },
+ { "::ffff:0.0.0.1", false },
+ { "::ffff:0.0.0.127", false },
+ { "::ffff:0.0.0.255", false },
+ { "::ffff:127.0.0.1", false },
+ { "::ffff:255.255.255.255", false },
+ };
+
+ UNUSED(tc);
+
+ for (i = 0; i < sizeof(data4)/sizeof(data4[0]); i++) {
+ in.s_addr = inet_addr(data4[i].string);
+ isc_sockaddr_fromin(&addr, &in, 1);
+ r = isc_sockaddr_isnetzero(&addr);
+ ATF_CHECK_EQ_MSG(r, data4[i].expect, "%s", data4[i].string);
+ }
+
+ for (i = 0; i < sizeof(data6)/sizeof(data6[0]); i++) {
+ ret = inet_pton(AF_INET6, data6[i].string, &in6);
+ ATF_CHECK_EQ(ret, 1);
+ isc_sockaddr_fromin6(&addr, &in6, 1);
+ r = isc_sockaddr_isnetzero(&addr);
+ ATF_CHECK_EQ_MSG(r, data6[i].expect, "%s", data6[i].string);
+ }
+}
+
+ATF_TC(sockaddr_eqaddrprefix);
+ATF_TC_HEAD(sockaddr_eqaddrprefix, tc) {
+ atf_tc_set_md_var(tc, "descr",
+ "isc_sockaddr_eqaddrprefix() returns true when "
+ "prefixes of a and b are equal, and false when "
+ "they are not equal");
+}
+ATF_TC_BODY(sockaddr_eqaddrprefix, tc) {
+ struct in_addr ina_a;
+ struct in_addr ina_b;
+ struct in_addr ina_c;
+ isc_sockaddr_t isa_a;
+ isc_sockaddr_t isa_b;
+ isc_sockaddr_t isa_c;
+
+ UNUSED(tc);
+
+ ATF_CHECK(inet_pton(AF_INET, "194.100.32.87", &ina_a) >= 0);
+ ATF_CHECK(inet_pton(AF_INET, "194.100.32.80", &ina_b) >= 0);
+ ATF_CHECK(inet_pton(AF_INET, "194.101.32.87", &ina_c) >= 0);
+
+ isc_sockaddr_fromin(&isa_a, &ina_a, 0);
+ isc_sockaddr_fromin(&isa_b, &ina_b, 42);
+ isc_sockaddr_fromin(&isa_c, &ina_c, 0);
+
+ ATF_CHECK(isc_sockaddr_eqaddrprefix(&isa_a, &isa_b, 0));
+ ATF_CHECK(isc_sockaddr_eqaddrprefix(&isa_a, &isa_b, 29));
+ ATF_CHECK(isc_sockaddr_eqaddrprefix(&isa_a, &isa_c, 8));
+
+ ATF_CHECK(! isc_sockaddr_eqaddrprefix(&isa_a, &isa_b, 30));
+ ATF_CHECK(! isc_sockaddr_eqaddrprefix(&isa_a, &isa_b, 32));
+ ATF_CHECK(! isc_sockaddr_eqaddrprefix(&isa_a, &isa_c, 16));
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, sockaddr_hash);
+ ATF_TP_ADD_TC(tp, sockaddr_isnetzero);
+ ATF_TP_ADD_TC(tp, sockaddr_eqaddrprefix);
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/socket_test.c b/lib/isc/tests/socket_test.c
new file mode 100644
index 0000000..3f3f249
--- /dev/null
+++ b/lib/isc/tests/socket_test.c
@@ -0,0 +1,923 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <isc/platform.h>
+#include <isc/socket.h>
+#include <isc/print.h>
+
+#include "../task_p.h"
+#include "../unix/socket_p.h"
+#include "isctest.h"
+
+static bool recv_dscp;
+static unsigned int recv_dscp_value;
+static bool recv_trunc;
+
+/*
+ * Helper functions
+ */
+
+typedef struct {
+ bool done;
+ isc_result_t result;
+ isc_socket_t *socket;
+} completion_t;
+
+static void
+completion_init(completion_t *completion) {
+ completion->done = false;
+ completion->socket = NULL;
+}
+
+static void
+accept_done(isc_task_t *task, isc_event_t *event) {
+ isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
+ completion_t *completion = event->ev_arg;
+
+ UNUSED(task);
+
+ completion->result = nevent->result;
+ completion->done = true;
+ if (completion->result == ISC_R_SUCCESS)
+ completion->socket = nevent->newsocket;
+
+ isc_event_free(&event);
+}
+
+static void
+event_done(isc_task_t *task, isc_event_t *event) {
+ isc_socketevent_t *dev;
+ completion_t *completion = event->ev_arg;
+
+ UNUSED(task);
+
+ dev = (isc_socketevent_t *) event;
+ completion->result = dev->result;
+ completion->done = true;
+ if ((dev->attributes & ISC_SOCKEVENTATTR_DSCP) != 0) {
+ recv_dscp = true;
+ recv_dscp_value = dev->dscp;;
+ } else {
+ recv_dscp = false;
+ }
+ recv_trunc = (dev->attributes & ISC_SOCKEVENTATTR_TRUNC);
+ isc_event_free(&event);
+}
+
+static isc_result_t
+waitfor(completion_t *completion) {
+ int i = 0;
+ while (!completion->done && i++ < 5000) {
+#ifndef ISC_PLATFORM_USETHREADS
+ while (isc__taskmgr_ready(taskmgr))
+ isc__taskmgr_dispatch(taskmgr);
+#endif
+ isc_test_nap(1000);
+ }
+ if (completion->done)
+ return (ISC_R_SUCCESS);
+ return (ISC_R_FAILURE);
+}
+
+#if 0
+static isc_result_t
+waitfor(completion_t *completion) {
+ int i = 0;
+ while (!completion->done && i++ < 5000) {
+ waitbody();
+ }
+ if (completion->done)
+ return (ISC_R_SUCCESS);
+ return (ISC_R_FAILURE);
+}
+#endif
+
+static void
+waitbody(void) {
+#ifndef ISC_PLATFORM_USETHREADS
+ struct timeval tv;
+ isc_socketwait_t *swait = NULL;
+
+ while (isc__taskmgr_ready(taskmgr))
+ isc__taskmgr_dispatch(taskmgr);
+ if (socketmgr != NULL) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000 ;
+ if (isc__socketmgr_waitevents(socketmgr, &tv, &swait) > 0)
+ isc__socketmgr_dispatch(socketmgr, swait);
+ } else
+#endif
+ isc_test_nap(1000);
+}
+
+static isc_result_t
+waitfor2(completion_t *c1, completion_t *c2) {
+ int i = 0;
+
+ while (!(c1->done && c2->done) && i++ < 5000) {
+ waitbody();
+ }
+ if (c1->done && c2->done)
+ return (ISC_R_SUCCESS);
+ return (ISC_R_FAILURE);
+}
+
+/*
+ * Individual unit tests
+ */
+
+/* Test UDP sendto/recv (IPv4) */
+ATF_TC(udp_sendto);
+ATF_TC_HEAD(udp_sendto, tc) {
+ atf_tc_set_md_var(tc, "descr", "UDP sendto/recv");
+}
+ATF_TC_BODY(udp_sendto, tc) {
+ isc_result_t result;
+ isc_sockaddr_t addr1, addr2;
+ struct in_addr in;
+ isc_socket_t *s1 = NULL, *s2 = NULL;
+ isc_task_t *task = NULL;
+ char sendbuf[BUFSIZ], recvbuf[BUFSIZ];
+ completion_t completion;
+ isc_region_t r;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ in.s_addr = inet_addr("127.0.0.1");
+ isc_sockaddr_fromin(&addr1, &in, 0);
+ isc_sockaddr_fromin(&addr2, &in, 0);
+
+ result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_socket_bind(s1, &addr1, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_socket_getsockname(s1, &addr1);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr1) != 0);
+
+ result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_socket_bind(s2, &addr2, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_socket_getsockname(s2, &addr2);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr2) != 0);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ snprintf(sendbuf, sizeof(sendbuf), "Hello");
+ r.base = (void *) sendbuf;
+ r.length = strlen(sendbuf) + 1;
+
+ completion_init(&completion);
+ result = isc_socket_sendto(s1, &r, task, event_done, &completion,
+ &addr2, NULL);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+ r.base = (void *) recvbuf;
+ r.length = BUFSIZ;
+ completion_init(&completion);
+ result = isc_socket_recv(s2, &r, 1, task, event_done, &completion);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(recvbuf, "Hello");
+
+ isc_task_detach(&task);
+
+ isc_socket_detach(&s1);
+ isc_socket_detach(&s2);
+
+ isc_test_end();
+}
+
+/* Test UDP sendto/recv with duplicated socket */
+ATF_TC(udp_dup);
+ATF_TC_HEAD(udp_dup, tc) {
+ atf_tc_set_md_var(tc, "descr", "duplicated socket sendto/recv");
+}
+ATF_TC_BODY(udp_dup, tc) {
+ isc_result_t result;
+ isc_sockaddr_t addr1, addr2;
+ struct in_addr in;
+ isc_socket_t *s1 = NULL, *s2 = NULL, *s3 = NULL;
+ isc_task_t *task = NULL;
+ char sendbuf[BUFSIZ], recvbuf[BUFSIZ];
+ completion_t completion;
+ isc_region_t r;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ in.s_addr = inet_addr("127.0.0.1");
+ isc_sockaddr_fromin(&addr1, &in, 0);
+ isc_sockaddr_fromin(&addr2, &in, 0);
+
+ result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_socket_bind(s1, &addr1, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_socket_getsockname(s1, &addr1);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr1) != 0);
+
+ result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_socket_bind(s2, &addr2, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_socket_getsockname(s2, &addr2);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr2) != 0);
+
+ result = isc_socket_dup(s2, &s3);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ snprintf(sendbuf, sizeof(sendbuf), "Hello");
+ r.base = (void *) sendbuf;
+ r.length = strlen(sendbuf) + 1;
+
+ completion_init(&completion);
+ result = isc_socket_sendto(s1, &r, task, event_done, &completion,
+ &addr2, NULL);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+ snprintf(sendbuf, sizeof(sendbuf), "World");
+ r.base = (void *) sendbuf;
+ r.length = strlen(sendbuf) + 1;
+
+ completion_init(&completion);
+ result = isc_socket_sendto(s1, &r, task, event_done, &completion,
+ &addr2, NULL);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+ r.base = (void *) recvbuf;
+ r.length = BUFSIZ;
+ completion_init(&completion);
+ result = isc_socket_recv(s2, &r, 1, task, event_done, &completion);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(recvbuf, "Hello");
+
+ r.base = (void *) recvbuf;
+ r.length = BUFSIZ;
+ completion_init(&completion);
+ result = isc_socket_recv(s3, &r, 1, task, event_done, &completion);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(recvbuf, "World");
+
+ isc_task_detach(&task);
+
+ isc_socket_detach(&s1);
+ isc_socket_detach(&s2);
+ isc_socket_detach(&s3);
+
+ isc_test_end();
+}
+
+/* Test TCP sendto/recv (IPv4) */
+ATF_TC(udp_dscp_v4);
+ATF_TC_HEAD(udp_dscp_v4, tc) {
+ atf_tc_set_md_var(tc, "descr", "UDP DSCP IPV4");
+}
+ATF_TC_BODY(udp_dscp_v4, tc) {
+ isc_result_t result;
+ isc_sockaddr_t addr1, addr2;
+ struct in_addr in;
+ isc_socket_t *s1 = NULL, *s2 = NULL;
+ isc_task_t *task = NULL;
+ char sendbuf[BUFSIZ], recvbuf[BUFSIZ];
+ completion_t completion;
+ isc_region_t r;
+ isc_socketevent_t *socketevent;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ in.s_addr = inet_addr("127.0.0.1");
+ isc_sockaddr_fromin(&addr1, &in, 0);
+ isc_sockaddr_fromin(&addr2, &in, 0);
+
+ result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_getsockname(s1, &addr1);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr1) != 0);
+
+ result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_bind(s2, &addr2, ISC_SOCKET_REUSEADDRESS);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_getsockname(s2, &addr2);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr2) != 0);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+
+ snprintf(sendbuf, sizeof(sendbuf), "Hello");
+ r.base = (void *) sendbuf;
+ r.length = strlen(sendbuf) + 1;
+
+ completion_init(&completion);
+
+ socketevent = isc_socket_socketevent(mctx, s1, ISC_SOCKEVENT_SENDDONE,
+ event_done, &completion);
+ ATF_REQUIRE(socketevent != NULL);
+
+ if ((isc_net_probedscp() & ISC_NET_DSCPPKTV4) != 0) {
+ socketevent->dscp = 056; /* EF */
+ socketevent->attributes |= ISC_SOCKEVENTATTR_DSCP;
+ } else if ((isc_net_probedscp() & ISC_NET_DSCPSETV4) != 0) {
+ isc_socket_dscp(s1, 056); /* EF */
+ socketevent->dscp = 0;
+ socketevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP;
+ }
+
+ recv_dscp = false;
+ recv_dscp_value = 0;
+
+ result = isc_socket_sendto2(s1, &r, task, &addr2, NULL, socketevent, 0);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+ r.base = (void *) recvbuf;
+ r.length = BUFSIZ;
+ completion_init(&completion);
+ result = isc_socket_recv(s2, &r, 1, task, event_done, &completion);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(recvbuf, "Hello");
+
+ if ((isc_net_probedscp() & ISC_NET_DSCPRECVV4) != 0) {
+ ATF_CHECK(recv_dscp);
+ ATF_CHECK_EQ(recv_dscp_value, 056);
+ } else
+ ATF_CHECK(!recv_dscp);
+ isc_task_detach(&task);
+
+ isc_socket_detach(&s1);
+ isc_socket_detach(&s2);
+
+ isc_test_end();
+}
+
+/* Test TCP sendto/recv (IPv4) */
+ATF_TC(udp_dscp_v6);
+ATF_TC_HEAD(udp_dscp_v6, tc) {
+ atf_tc_set_md_var(tc, "descr", "udp dscp ipv6");
+}
+ATF_TC_BODY(udp_dscp_v6, tc) {
+#if defined(ISC_PLATFORM_HAVEIPV6) && defined(WANT_IPV6)
+ isc_result_t result;
+ isc_sockaddr_t addr1, addr2;
+ struct in6_addr in6;
+ isc_socket_t *s1 = NULL, *s2 = NULL;
+ isc_task_t *task = NULL;
+ char sendbuf[BUFSIZ], recvbuf[BUFSIZ];
+ completion_t completion;
+ isc_region_t r;
+ isc_socketevent_t *socketevent;
+ int n;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ n = inet_pton(AF_INET6, "::1", &in6.s6_addr);
+ ATF_REQUIRE(n == 1);
+ isc_sockaddr_fromin6(&addr1, &in6, 0);
+ isc_sockaddr_fromin6(&addr2, &in6, 0);
+
+ result = isc_socket_create(socketmgr, PF_INET6, isc_sockettype_udp,
+ &s1);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_bind(s1, &addr1, 0);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_getsockname(s1, &addr1);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr1) != 0);
+
+ result = isc_socket_create(socketmgr, PF_INET6, isc_sockettype_udp,
+ &s2);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_bind(s2, &addr2, 0);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_getsockname(s2, &addr2);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr2) != 0);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+
+ snprintf(sendbuf, sizeof(sendbuf), "Hello");
+ r.base = (void *) sendbuf;
+ r.length = strlen(sendbuf) + 1;
+
+ completion_init(&completion);
+
+ socketevent = isc_socket_socketevent(mctx, s1, ISC_SOCKEVENT_SENDDONE,
+ event_done, &completion);
+ ATF_REQUIRE(socketevent != NULL);
+
+ if ((isc_net_probedscp() & ISC_NET_DSCPPKTV6) != 0) {
+ socketevent->dscp = 056; /* EF */
+ socketevent->attributes = ISC_SOCKEVENTATTR_DSCP;
+ } else if ((isc_net_probedscp() & ISC_NET_DSCPSETV6) != 0)
+ isc_socket_dscp(s1, 056); /* EF */
+
+ recv_dscp = false;
+ recv_dscp_value = 0;
+
+ result = isc_socket_sendto2(s1, &r, task, &addr2, NULL, socketevent, 0);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+ r.base = (void *) recvbuf;
+ r.length = BUFSIZ;
+ completion_init(&completion);
+ result = isc_socket_recv(s2, &r, 1, task, event_done, &completion);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(recvbuf, "Hello");
+ if ((isc_net_probedscp() & ISC_NET_DSCPRECVV6) != 0) {
+ ATF_CHECK(recv_dscp);
+ ATF_CHECK_EQ(recv_dscp_value, 056);
+ } else
+ ATF_CHECK(!recv_dscp);
+
+ isc_task_detach(&task);
+
+ isc_socket_detach(&s1);
+ isc_socket_detach(&s2);
+
+ isc_test_end();
+#else
+ UNUSED(tc);
+ atf_tc_skip("IPv6 not available");
+#endif
+}
+
+/* Test TCP sendto/recv (IPv4) */
+ATF_TC(tcp_dscp_v4);
+ATF_TC_HEAD(tcp_dscp_v4, tc) {
+ atf_tc_set_md_var(tc, "descr", "tcp dscp ipv4");
+}
+ATF_TC_BODY(tcp_dscp_v4, tc) {
+ isc_result_t result;
+ isc_sockaddr_t addr1;
+ struct in_addr in;
+ isc_socket_t *s1 = NULL, *s2 = NULL, *s3 = NULL;
+ isc_task_t *task = NULL;
+ char sendbuf[BUFSIZ], recvbuf[BUFSIZ];
+ completion_t completion, completion2;
+ isc_region_t r;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ in.s_addr = inet_addr("127.0.0.1");
+ isc_sockaddr_fromin(&addr1, &in, 0);
+
+ result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_tcp, &s1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_socket_bind(s1, &addr1, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_socket_getsockname(s1, &addr1);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr1) != 0);
+
+ result = isc_socket_listen(s1, 3);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_tcp, &s2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ completion_init(&completion2);
+ result = isc_socket_accept(s1, task, accept_done, &completion2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ completion_init(&completion);
+ result = isc_socket_connect(s2, &addr1, task, event_done, &completion);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ waitfor2(&completion, &completion2);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK(completion2.done);
+ ATF_CHECK_EQ(completion2.result, ISC_R_SUCCESS);
+ s3 = completion2.socket;
+
+ isc_socket_dscp(s2, 056); /* EF */
+
+ snprintf(sendbuf, sizeof(sendbuf), "Hello");
+ r.base = (void *) sendbuf;
+ r.length = strlen(sendbuf) + 1;
+
+ recv_dscp = false;
+ recv_dscp_value = 0;
+
+ completion_init(&completion);
+ result = isc_socket_sendto(s2, &r, task, event_done, &completion,
+ NULL, NULL);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+ r.base = (void *) recvbuf;
+ r.length = BUFSIZ;
+ completion_init(&completion);
+ result = isc_socket_recv(s3, &r, 1, task, event_done, &completion);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(recvbuf, "Hello");
+
+ if ((isc_net_probedscp() & ISC_NET_DSCPRECVV4) != 0) {
+ if (recv_dscp)
+ ATF_CHECK_EQ(recv_dscp_value, 056);
+ } else
+ ATF_CHECK(!recv_dscp);
+
+ isc_task_detach(&task);
+
+ isc_socket_detach(&s1);
+ isc_socket_detach(&s2);
+ isc_socket_detach(&s3);
+
+ isc_test_end();
+}
+
+/* Test TCP sendto/recv (IPv6) */
+ATF_TC(tcp_dscp_v6);
+ATF_TC_HEAD(tcp_dscp_v6, tc) {
+ atf_tc_set_md_var(tc, "descr", "tcp dscp ipv6");
+}
+ATF_TC_BODY(tcp_dscp_v6, tc) {
+#ifdef ISC_PLATFORM_HAVEIPV6
+ isc_result_t result;
+ isc_sockaddr_t addr1;
+ struct in6_addr in6;
+ isc_socket_t *s1 = NULL, *s2 = NULL, *s3 = NULL;
+ isc_task_t *task = NULL;
+ char sendbuf[BUFSIZ], recvbuf[BUFSIZ];
+ completion_t completion, completion2;
+ isc_region_t r;
+ int n;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ n = inet_pton(AF_INET6, "::1", &in6.s6_addr);
+ ATF_REQUIRE(n == 1);
+ isc_sockaddr_fromin6(&addr1, &in6, 0);
+
+ result = isc_socket_create(socketmgr, PF_INET6, isc_sockettype_tcp,
+ &s1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_socket_bind(s1, &addr1, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_socket_getsockname(s1, &addr1);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr1) != 0);
+
+ result = isc_socket_listen(s1, 3);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_socket_create(socketmgr, PF_INET6, isc_sockettype_tcp,
+ &s2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ completion_init(&completion2);
+ result = isc_socket_accept(s1, task, accept_done, &completion2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ completion_init(&completion);
+ result = isc_socket_connect(s2, &addr1, task, event_done, &completion);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ waitfor2(&completion, &completion2);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK(completion2.done);
+ ATF_CHECK_EQ(completion2.result, ISC_R_SUCCESS);
+ s3 = completion2.socket;
+
+ isc_socket_dscp(s2, 056); /* EF */
+
+ snprintf(sendbuf, sizeof(sendbuf), "Hello");
+ r.base = (void *) sendbuf;
+ r.length = strlen(sendbuf) + 1;
+
+ recv_dscp = false;
+ recv_dscp_value = 0;
+
+ completion_init(&completion);
+ result = isc_socket_sendto(s2, &r, task, event_done, &completion,
+ NULL, NULL);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+ r.base = (void *) recvbuf;
+ r.length = BUFSIZ;
+ completion_init(&completion);
+ result = isc_socket_recv(s3, &r, 1, task, event_done, &completion);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(recvbuf, "Hello");
+
+ if ((isc_net_probedscp() & ISC_NET_DSCPRECVV6) != 0) {
+ /*
+ * IPV6_RECVTCLASS is undefined for TCP however
+ * if we do get it it should be the value we set.
+ */
+ if (recv_dscp)
+ ATF_CHECK_EQ(recv_dscp_value, 056);
+ } else
+ ATF_CHECK(!recv_dscp);
+
+ isc_task_detach(&task);
+
+ isc_socket_detach(&s1);
+ isc_socket_detach(&s2);
+ isc_socket_detach(&s3);
+
+ isc_test_end();
+#else
+ UNUSED(tc);
+ atf_tc_skip("IPv6 not available");
+#endif
+}
+
+ATF_TC(net_probedscp);
+ATF_TC_HEAD(net_probedscp, tc) {
+ atf_tc_set_md_var(tc, "descr", "probe dscp capabilities");
+}
+ATF_TC_BODY(net_probedscp, tc) {
+ unsigned int n;
+
+ UNUSED(tc);
+
+ n = isc_net_probedscp();
+ ATF_CHECK((n & ~ISC_NET_DSCPALL) == 0);
+
+ /* ISC_NET_DSCPSETV4 MUST be set if any is set. */
+ if (n & (ISC_NET_DSCPSETV4|ISC_NET_DSCPPKTV4|ISC_NET_DSCPRECVV4))
+ ATF_CHECK_MSG((n & ISC_NET_DSCPSETV4) != 0,
+ "IPv4:%s%s%s\n",
+ (n & ISC_NET_DSCPSETV4) ? " set" : " none",
+ (n & ISC_NET_DSCPPKTV4) ? " packet" : "",
+ (n & ISC_NET_DSCPRECVV4) ? " receive" : "");
+
+ /* ISC_NET_DSCPSETV6 MUST be set if any is set. */
+ if (n & (ISC_NET_DSCPSETV6|ISC_NET_DSCPPKTV6|ISC_NET_DSCPRECVV6))
+ ATF_CHECK_MSG((n & ISC_NET_DSCPSETV6) != 0,
+ "IPv6:%s%s%s\n",
+ (n & ISC_NET_DSCPSETV6) ? " set" : " none",
+ (n & ISC_NET_DSCPPKTV6) ? " packet" : "",
+ (n & ISC_NET_DSCPRECVV6) ? " receive" : "");
+
+#if 0
+ fprintf(stdout, "IPv4:%s%s%s\n",
+ (n & ISC_NET_DSCPSETV4) ? " set" : "none",
+ (n & ISC_NET_DSCPPKTV4) ? " packet" : "",
+ (n & ISC_NET_DSCPRECVV4) ? " receive" : "");
+
+ fprintf(stdout, "IPv6:%s%s%s\n",
+ (n & ISC_NET_DSCPSETV6) ? " set" : "none",
+ (n & ISC_NET_DSCPPKTV6) ? " packet" : "",
+ (n & ISC_NET_DSCPRECVV6) ? " receive" : "");
+#endif
+}
+
+/* Test UDP truncation detection */
+ATF_TC(udp_trunc);
+ATF_TC_HEAD(udp_trunc, tc) {
+ atf_tc_set_md_var(tc, "descr", "UDP Truncation detection");
+}
+ATF_TC_BODY(udp_trunc, tc) {
+ isc_result_t result;
+ isc_sockaddr_t addr1, addr2;
+ struct in_addr in;
+ isc_socket_t *s1 = NULL, *s2 = NULL;
+ isc_task_t *task = NULL;
+ char sendbuf[BUFSIZ*2], recvbuf[BUFSIZ];
+ completion_t completion;
+ isc_region_t r;
+ isc_socketevent_t *socketevent;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ in.s_addr = inet_addr("127.0.0.1");
+ isc_sockaddr_fromin(&addr1, &in, 0);
+ isc_sockaddr_fromin(&addr2, &in, 0);
+
+ result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_getsockname(s1, &addr1);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr1) != 0);
+
+ result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_bind(s2, &addr2, ISC_SOCKET_REUSEADDRESS);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ result = isc_socket_getsockname(s2, &addr2);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ ATF_REQUIRE(isc_sockaddr_getport(&addr2) != 0);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+
+ /*
+ * Send a message that will not be truncated.
+ */
+ memset(sendbuf, 0xff, sizeof(sendbuf));
+ snprintf(sendbuf, sizeof(sendbuf), "Hello");
+ r.base = (void *) sendbuf;
+ r.length = strlen(sendbuf) + 1;
+
+ completion_init(&completion);
+
+ socketevent = isc_socket_socketevent(mctx, s1, ISC_SOCKEVENT_SENDDONE,
+ event_done, &completion);
+ ATF_REQUIRE(socketevent != NULL);
+
+ result = isc_socket_sendto2(s1, &r, task, &addr2, NULL, socketevent, 0);
+ ATF_REQUIRE_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+ r.base = (void *) recvbuf;
+ r.length = BUFSIZ;
+ completion_init(&completion);
+ recv_trunc = false;
+ result = isc_socket_recv(s2, &r, 1, task, event_done, &completion);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(recvbuf, "Hello");
+ ATF_CHECK_EQ(recv_trunc, false);
+
+ /*
+ * Send a message that will be truncated.
+ */
+ memset(sendbuf, 0xff, sizeof(sendbuf));
+ snprintf(sendbuf, sizeof(sendbuf), "Hello");
+ r.base = (void *) sendbuf;
+ r.length = sizeof(sendbuf);
+
+ completion_init(&completion);
+
+ socketevent = isc_socket_socketevent(mctx, s1, ISC_SOCKEVENT_SENDDONE,
+ event_done, &completion);
+ ATF_REQUIRE(socketevent != NULL);
+
+ result = isc_socket_sendto2(s1, &r, task, &addr2, NULL, socketevent, 0);
+ ATF_REQUIRE_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+ isc_result_totext(result));
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+ r.base = (void *) recvbuf;
+ r.length = BUFSIZ;
+ completion_init(&completion);
+ recv_trunc = false;
+ result = isc_socket_recv(s2, &r, 1, task, event_done, &completion);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ waitfor(&completion);
+ ATF_CHECK(completion.done);
+ ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(recvbuf, "Hello");
+ ATF_CHECK_EQ(recv_trunc, true);
+
+ isc_task_detach(&task);
+
+ isc_socket_detach(&s1);
+ isc_socket_detach(&s2);
+
+ isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, udp_sendto);
+ ATF_TP_ADD_TC(tp, udp_dup);
+ ATF_TP_ADD_TC(tp, tcp_dscp_v4);
+ ATF_TP_ADD_TC(tp, tcp_dscp_v6);
+ ATF_TP_ADD_TC(tp, udp_dscp_v4);
+ ATF_TP_ADD_TC(tp, udp_dscp_v6);
+ ATF_TP_ADD_TC(tp, net_probedscp);
+ ATF_TP_ADD_TC(tp, udp_trunc);
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/symtab_test.c b/lib/isc/tests/symtab_test.c
new file mode 100644
index 0000000..a50553b
--- /dev/null
+++ b/lib/isc/tests/symtab_test.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+
+#include <isc/symtab.h>
+#include <isc/print.h>
+
+#include "isctest.h"
+
+static void
+undefine(char *key, unsigned int type, isc_symvalue_t value, void *arg) {
+ UNUSED(arg);
+
+ ATF_REQUIRE_EQ(type, 1);
+ isc_mem_free(mctx, key);
+ isc_mem_free(mctx, value.as_pointer);
+}
+
+/*
+ * Individual unit tests
+ */
+
+ATF_TC(symtab_grow);
+ATF_TC_HEAD(symtab_grow, tc) {
+ atf_tc_set_md_var(tc, "descr", "symbol table growth");
+}
+ATF_TC_BODY(symtab_grow, tc) {
+ isc_result_t result;
+ isc_symtab_t *st = NULL;
+ isc_symvalue_t value;
+ isc_symexists_t policy = isc_symexists_reject;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_symtab_create(mctx, 3, undefine, NULL, false, &st);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE(st != NULL);
+
+ /* Nothing should be in the table yet */
+
+ /*
+ * Put 1024 entries in the table (this should necessate
+ * regrowing the hash table several times
+ */
+ for (i = 0; i < 1024; i++) {
+ char str[16], *key;
+
+ snprintf(str, sizeof(str), "%04x", i);
+ key = isc_mem_strdup(mctx, str);
+ ATF_REQUIRE(key != NULL);
+ value.as_pointer = isc_mem_strdup(mctx, str);
+ ATF_REQUIRE(value.as_pointer != NULL);
+ result = isc_symtab_define(st, key, 1, value, policy);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ undefine(key, 1, value, NULL);
+ }
+
+ /*
+ * Try to put them in again; this should fail
+ */
+ for (i = 0; i < 1024; i++) {
+ char str[16], *key;
+
+ snprintf(str, sizeof(str), "%04x", i);
+ key = isc_mem_strdup(mctx, str);
+ ATF_REQUIRE(key != NULL);
+ value.as_pointer = isc_mem_strdup(mctx, str);
+ ATF_REQUIRE(value.as_pointer != NULL);
+ result = isc_symtab_define(st, key, 1, value, policy);
+ ATF_CHECK_EQ(result, ISC_R_EXISTS);
+ undefine(key, 1, value, NULL);
+ }
+
+ /*
+ * Retrieve them; this should succeed
+ */
+ for (i = 0; i < 1024; i++) {
+ char str[16];
+
+ snprintf(str, sizeof(str), "%04x", i);
+ result = isc_symtab_lookup(st, str, 0, &value);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_STREQ(str, (char *)value.as_pointer);
+ }
+
+ /*
+ * Undefine them
+ */
+ for (i = 0; i < 1024; i++) {
+ char str[16];
+
+ snprintf(str, sizeof(str), "%04x", i);
+ result = isc_symtab_undefine(st, str, 1);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ }
+
+ /*
+ * Retrieve them again; this should fail
+ */
+ for (i = 0; i < 1024; i++) {
+ char str[16];
+
+ snprintf(str, sizeof(str), "%04x", i);
+ result = isc_symtab_lookup(st, str, 0, &value);
+ ATF_CHECK_EQ(result, ISC_R_NOTFOUND);
+ }
+
+ isc_symtab_destroy(&st);
+ isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, symtab_grow);
+
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/task_test.c b/lib/isc/tests/task_test.c
new file mode 100644
index 0000000..c991272
--- /dev/null
+++ b/lib/isc/tests/task_test.c
@@ -0,0 +1,1474 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <isc/condition.h>
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include "../task_p.h"
+#include "isctest.h"
+
+/*
+ * Helper functions
+ */
+
+static isc_mutex_t lock;
+int counter = 0;
+static int active[10];
+static bool done = false;
+
+#ifdef ISC_PLATFORM_USETHREADS
+static isc_condition_t cv;
+#endif
+
+static void
+set(isc_task_t *task, isc_event_t *event) {
+ int *value = (int *) event->ev_arg;
+
+ UNUSED(task);
+
+ isc_event_free(&event);
+ LOCK(&lock);
+ *value = counter++;
+ UNLOCK(&lock);
+}
+
+static void
+set_and_drop(isc_task_t *task, isc_event_t *event) {
+ int *value = (int *) event->ev_arg;
+
+ UNUSED(task);
+
+ isc_event_free(&event);
+ LOCK(&lock);
+ *value = (int) isc_taskmgr_mode(taskmgr);
+ counter++;
+ UNLOCK(&lock);
+ isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal);
+}
+
+/*
+ * Individual unit tests
+ */
+
+/* Create a task */
+ATF_TC(create_task);
+ATF_TC_HEAD(create_task, tc) {
+ atf_tc_set_md_var(tc, "descr", "create and destroy a task");
+}
+ATF_TC_BODY(create_task, tc) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_task_destroy(&task);
+ ATF_REQUIRE_EQ(task, NULL);
+
+ isc_test_end();
+}
+
+/* Process events */
+ATF_TC(all_events);
+ATF_TC_HEAD(all_events, tc) {
+ atf_tc_set_md_var(tc, "descr", "process task events");
+}
+ATF_TC_BODY(all_events, tc) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+ isc_event_t *event = NULL;
+ int a = 0, b = 0;
+ int i = 0;
+
+ UNUSED(tc);
+
+ counter = 1;
+
+ result = isc_mutex_init(&lock);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* First event */
+ event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST,
+ set, &a, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(a, 0);
+ isc_task_send(task, &event);
+
+ event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST,
+ set, &b, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(b, 0);
+ isc_task_send(task, &event);
+
+ while ((a == 0 || b == 0) && i++ < 5000) {
+#ifndef ISC_PLATFORM_USETHREADS
+ while (isc__taskmgr_ready(taskmgr))
+ isc__taskmgr_dispatch(taskmgr);
+#endif
+ isc_test_nap(1000);
+ }
+
+ ATF_CHECK(a != 0);
+ ATF_CHECK(b != 0);
+
+ isc_task_destroy(&task);
+ ATF_REQUIRE_EQ(task, NULL);
+
+ isc_test_end();
+}
+
+/* Privileged events */
+ATF_TC(privileged_events);
+ATF_TC_HEAD(privileged_events, tc) {
+ atf_tc_set_md_var(tc, "descr", "process privileged events");
+}
+ATF_TC_BODY(privileged_events, tc) {
+ isc_result_t result;
+ isc_task_t *task1 = NULL, *task2 = NULL;
+ isc_event_t *event = NULL;
+ int a = 0, b = 0, c = 0, d = 0, e = 0;
+ int i = 0;
+
+ UNUSED(tc);
+
+ counter = 1;
+ result = isc_mutex_init(&lock);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Pause the task manager so we can fill up the work queue
+ * without things happening while we do it.
+ */
+ isc__taskmgr_pause(taskmgr);
+#endif
+
+ result = isc_task_create(taskmgr, 0, &task1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ isc_task_setname(task1, "privileged", NULL);
+ ATF_CHECK(!isc_task_privilege(task1));
+ isc_task_setprivilege(task1, true);
+ ATF_CHECK(isc_task_privilege(task1));
+
+ result = isc_task_create(taskmgr, 0, &task2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ isc_task_setname(task2, "normal", NULL);
+ ATF_CHECK(!isc_task_privilege(task2));
+
+ /* First event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set, &a, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(a, 0);
+ isc_task_send(task1, &event);
+
+ /* Second event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
+ set, &b, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(b, 0);
+ isc_task_send(task2, &event);
+
+ /* Third event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set, &c, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(c, 0);
+ isc_task_send(task1, &event);
+
+ /* Fourth event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set, &d, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(d, 0);
+ isc_task_send(task1, &event);
+
+ /* Fifth event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
+ set, &e, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(e, 0);
+ isc_task_send(task2, &event);
+
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);
+ isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ isc__taskmgr_resume(taskmgr);
+#endif
+
+ /* We're waiting for *all* variables to be set */
+ while ((a == 0 || b == 0 || c == 0 || d == 0 || e == 0) && i++ < 5000) {
+#ifndef ISC_PLATFORM_USETHREADS
+ while (isc__taskmgr_ready(taskmgr))
+ isc__taskmgr_dispatch(taskmgr);
+#endif
+ isc_test_nap(1000);
+ }
+
+ /*
+ * We can't guarantee what order the events fire, but
+ * we do know the privileged tasks that set a, c, and d
+ * would have fired first.
+ */
+ ATF_CHECK(a <= 3);
+ ATF_CHECK(c <= 3);
+ ATF_CHECK(d <= 3);
+
+ /* ...and the non-privileged tasks that set b and e, last */
+ ATF_CHECK(b >= 4);
+ ATF_CHECK(e >= 4);
+
+ ATF_CHECK_EQ(counter, 6);
+
+ isc_task_setprivilege(task1, false);
+ ATF_CHECK(!isc_task_privilege(task1));
+
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);
+
+ isc_task_destroy(&task1);
+ ATF_REQUIRE_EQ(task1, NULL);
+ isc_task_destroy(&task2);
+ ATF_REQUIRE_EQ(task2, NULL);
+
+ isc_test_end();
+}
+
+/*
+ * Edge case: this tests that the task manager behaves as expected when
+ * we explicitly set it into normal mode *while* running privileged.
+ */
+ATF_TC(privilege_drop);
+ATF_TC_HEAD(privilege_drop, tc) {
+ atf_tc_set_md_var(tc, "descr", "process privileged events");
+}
+ATF_TC_BODY(privilege_drop, tc) {
+ isc_result_t result;
+ isc_task_t *task1 = NULL, *task2 = NULL;
+ isc_event_t *event = NULL;
+ int a = -1, b = -1, c = -1, d = -1, e = -1; /* non valid states */
+ int i = 0;
+
+ UNUSED(tc);
+
+ counter = 1;
+ result = isc_mutex_init(&lock);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Pause the task manager so we can fill up the work queue
+ * without things happening while we do it.
+ */
+ isc__taskmgr_pause(taskmgr);
+#endif
+
+ result = isc_task_create(taskmgr, 0, &task1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ isc_task_setname(task1, "privileged", NULL);
+ ATF_CHECK(!isc_task_privilege(task1));
+ isc_task_setprivilege(task1, true);
+ ATF_CHECK(isc_task_privilege(task1));
+
+ result = isc_task_create(taskmgr, 0, &task2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ isc_task_setname(task2, "normal", NULL);
+ ATF_CHECK(!isc_task_privilege(task2));
+
+ /* First event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set_and_drop, &a, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(a, -1);
+ isc_task_send(task1, &event);
+
+ /* Second event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
+ set_and_drop, &b, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(b, -1);
+ isc_task_send(task2, &event);
+
+ /* Third event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set_and_drop, &c, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(c, -1);
+ isc_task_send(task1, &event);
+
+ /* Fourth event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set_and_drop, &d, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(d, -1);
+ isc_task_send(task1, &event);
+
+ /* Fifth event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
+ set_and_drop, &e, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(e, -1);
+ isc_task_send(task2, &event);
+
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);
+ isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ isc__taskmgr_resume(taskmgr);
+#endif
+
+ /* We're waiting for all variables to be set. */
+ while ((a == -1 || b == -1 || c == -1 || d == -1 || e == -1) &&
+ i++ < 5000) {
+#ifndef ISC_PLATFORM_USETHREADS
+ while (isc__taskmgr_ready(taskmgr))
+ isc__taskmgr_dispatch(taskmgr);
+#endif
+ isc_test_nap(1000);
+ }
+
+ /*
+ * We can't guarantee what order the events fire, but
+ * we do know *exactly one* of the privileged tasks will
+ * have run in privileged mode...
+ */
+ ATF_CHECK(a == isc_taskmgrmode_privileged ||
+ c == isc_taskmgrmode_privileged ||
+ d == isc_taskmgrmode_privileged);
+ ATF_CHECK(a + c + d == isc_taskmgrmode_privileged);
+
+ /* ...and neither of the non-privileged tasks did... */
+ ATF_CHECK(b == isc_taskmgrmode_normal || e == isc_taskmgrmode_normal);
+
+ /* ...but all five of them did run. */
+ ATF_CHECK_EQ(counter, 6);
+
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);
+
+ isc_task_destroy(&task1);
+ ATF_REQUIRE_EQ(task1, NULL);
+ isc_task_destroy(&task2);
+ ATF_REQUIRE_EQ(task2, NULL);
+
+ isc_test_end();
+}
+
+/*
+ * Basic task functions:
+ */
+static void
+basic_cb(isc_task_t *task, isc_event_t *event) {
+ int i;
+ int j;
+
+ UNUSED(task);
+
+ j = 0;
+ for (i = 0; i < 1000000; i++) {
+ j += 100;
+ }
+
+ printf("task %s\n", (char *)event->ev_arg);
+ isc_event_free(&event);
+}
+
+static void
+basic_shutdown(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ printf("shutdown %s\n", (char *)event->ev_arg);
+ isc_event_free(&event);
+}
+
+static void
+basic_tick(isc_task_t *task, isc_event_t *event) {
+
+ UNUSED(task);
+
+ printf("%s\n", (char *)event->ev_arg);
+ isc_event_free(&event);
+}
+
+static char one[] = "1";
+static char two[] = "2";
+static char three[] = "3";
+static char four[] = "4";
+static char tick[] = "tick";
+static char tock[] = "tock";
+
+
+ATF_TC(basic);
+ATF_TC_HEAD(basic, tc) {
+ atf_tc_set_md_var(tc, "descr", "basic task system check");
+}
+ATF_TC_BODY(basic, tc) {
+ isc_result_t result;
+ isc_task_t *task1 = NULL;
+ isc_task_t *task2 = NULL;
+ isc_task_t *task3 = NULL;
+ isc_task_t *task4 = NULL;
+ isc_event_t *event = NULL;
+ isc_timer_t *ti1 = NULL;
+ isc_timer_t *ti2 = NULL;
+ isc_time_t absolute;
+ isc_interval_t interval;
+ char *testarray[] = {
+ one, one, one, one, one, one, one, one, one,
+ two, three, four, two, three, four, NULL
+ };
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_task_create(taskmgr, 0, &task2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_task_create(taskmgr, 0, &task3);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_task_create(taskmgr, 0, &task4);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task1, basic_shutdown, one);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_task_onshutdown(task2, basic_shutdown, two);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_task_onshutdown(task3, basic_shutdown, three);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = isc_task_onshutdown(task4, basic_shutdown, four);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_time_settoepoch(&absolute);
+ isc_interval_set(&interval, 1, 0);
+ result = isc_timer_create(timermgr, isc_timertype_ticker,
+ &absolute, &interval,
+ task1, basic_tick, tick, &ti1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ ti2 = NULL;
+ isc_time_settoepoch(&absolute);
+ isc_interval_set(&interval, 1, 0);
+ result = isc_timer_create(timermgr, isc_timertype_ticker,
+ &absolute, &interval,
+ task2, basic_tick, tock, &ti2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+#ifndef WIN32
+ sleep(2);
+#else
+ Sleep(2000);
+#endif
+
+ for (i = 0; testarray[i] != NULL; i++) {
+ /*
+ * Note: (void *)1 is used as a sender here, since some
+ * compilers don't like casting a function pointer to a
+ * (void *).
+ *
+ * In a real use, it is more likely the sender would be a
+ * structure (socket, timer, task, etc) but this is just a
+ * test program.
+ */
+ event = isc_event_allocate(mctx, (void *)1, 1, basic_cb,
+ testarray[i], sizeof(*event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_send(task1, &event);
+ }
+
+ (void)isc_task_purge(task3, NULL, 0, 0);
+
+ isc_task_detach(&task1);
+ isc_task_detach(&task2);
+ isc_task_detach(&task3);
+ isc_task_detach(&task4);
+
+#ifndef WIN32
+ sleep(10);
+#else
+ Sleep(10000);
+#endif
+ isc_timer_detach(&ti1);
+ isc_timer_detach(&ti2);
+
+ isc_test_end();
+}
+
+/*
+ * Exclusive mode test:
+ * When one task enters exclusive mode, all other active
+ * tasks complete first.
+ */
+static
+int spin(int n) {
+ int i;
+ int r = 0;
+ for (i = 0; i < n; i++) {
+ r += i;
+ if (r > 1000000)
+ r = 0;
+ }
+ return (r);
+}
+
+static void
+exclusive_cb(isc_task_t *task, isc_event_t *event) {
+ int taskno = *(int *)(event->ev_arg);
+
+ printf("task enter %d\n", taskno);
+
+ /* task chosen from the middle of the range */
+ if (taskno == 6) {
+ isc_result_t result;
+ int i;
+
+ result = isc_task_beginexclusive(task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ for (i = 0; i < 10; i++) {
+ ATF_CHECK(active[i] == 0);
+ }
+
+ isc_task_endexclusive(task);
+ done = true;
+ } else {
+ active[taskno]++;
+ (void) spin(10000000);
+ active[taskno]--;
+ }
+
+ printf("task exit %d\n", taskno);
+
+ if (done) {
+ isc_mem_put(event->ev_destroy_arg, event->ev_arg, sizeof (int));
+ isc_event_free(&event);
+ } else {
+ isc_task_send(task, &event);
+ }
+}
+
+ATF_TC(task_exclusive);
+ATF_TC_HEAD(task_exclusive, tc) {
+ atf_tc_set_md_var(tc, "descr", "test exclusive mode");
+}
+ATF_TC_BODY(task_exclusive, tc) {
+ isc_task_t *tasks[10];
+ isc_result_t result;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 4);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ for (i = 0; i < 10; i++) {
+ isc_event_t *event = NULL;
+ int *v;
+
+ tasks[i] = NULL;
+
+ result = isc_task_create(taskmgr, 0, &tasks[i]);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ v = isc_mem_get(mctx, sizeof *v);
+ ATF_REQUIRE(v != NULL);
+
+ *v = i;
+
+ event = isc_event_allocate(mctx, NULL, 1, exclusive_cb,
+ v, sizeof(*event));
+ ATF_REQUIRE(event != NULL);
+
+ isc_task_send(tasks[i], &event);
+ }
+
+ for (i = 0; i < 10; i++) {
+ isc_task_detach(&tasks[i]);
+ }
+ isc_test_end();
+}
+
+/*
+ * The remainder of these tests require threads
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+/*
+ * Max tasks test:
+ * The task system can create and execute many tasks. Tests with 10000.
+ */
+static void
+maxtask_shutdown(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ if (event->ev_arg != NULL) {
+ isc_task_destroy((isc_task_t**) &event->ev_arg);
+ } else {
+ LOCK(&lock);
+ done = true;
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+ isc_taskmgr_destroy(&taskmgr);
+ isc_mem_destroy(&mctx);
+
+ isc_condition_destroy(&cv);
+ DESTROYLOCK(&lock);
+ }
+}
+
+static void
+maxtask_cb(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+
+ if (event->ev_arg != NULL) {
+ isc_task_t *newtask = NULL;
+
+ event->ev_arg = (void *)(((uintptr_t) event->ev_arg) - 1);
+
+ /*
+ * Create a new task and forward the message.
+ */
+ result = isc_task_create(taskmgr, 0, &newtask);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(newtask, maxtask_shutdown,
+ (void *)task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_task_send(newtask, &event);
+ } else if (task != NULL) {
+ isc_task_destroy(&task);
+ }
+}
+
+ATF_TC(manytasks);
+ATF_TC_HEAD(manytasks, tc) {
+ atf_tc_set_md_var(tc, "descr", "many tasks");
+}
+ATF_TC_BODY(manytasks, tc) {
+ isc_result_t result;
+ isc_event_t *event = NULL;
+ uintptr_t ntasks = 10000;
+
+ UNUSED(tc);
+
+ printf("Testing with %lu tasks\n", (unsigned long)ntasks);
+
+ result = isc_mutex_init(&lock);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_condition_init(&cv);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_mem_create(0, 0, &mctx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_taskmgr_create(mctx, 4, 0, &taskmgr);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, maxtask_cb,
+ (void *)ntasks, sizeof(*event));
+ ATF_REQUIRE(event != NULL);
+
+ LOCK(&lock);
+ maxtask_cb(NULL, event);
+ while (!done) {
+ WAIT(&cv, &lock);
+ }
+}
+
+
+/*
+ * Shutdown test:
+ * When isc_task_shutdown() is called, shutdown events are posted
+ * in LIFO order.
+ */
+
+static int senders[4];
+static int nevents = 0;
+static int nsdevents = 0;
+
+static void
+sd_sde1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ ATF_CHECK_EQ(nevents, 256);
+ ATF_REQUIRE_EQ(nsdevents, 1);
+ ++nsdevents;
+ printf("shutdown 1\n");
+
+ isc_event_free(&event);
+}
+
+static void
+sd_sde2(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ ATF_CHECK_EQ(nevents, 256);
+ ATF_REQUIRE_EQ(nsdevents, 0);
+ ++nsdevents;
+ printf("shutdown 2\n");
+
+ isc_event_free(&event);
+}
+
+static void
+sd_event1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+ while (!done) {
+ WAIT(&cv, &lock);
+ }
+
+ printf("event 1\n");
+
+ isc_event_free(&event);
+}
+
+static void
+sd_event2(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ ++nevents;
+
+ printf("event 2\n");
+
+ isc_event_free(&event);
+}
+
+ATF_TC(shutdown);
+ATF_TC_HEAD(shutdown, tc) {
+ atf_tc_set_md_var(tc, "descr", "task shutdown");
+}
+ATF_TC_BODY(shutdown, tc) {
+ isc_result_t result;
+ isc_eventtype_t event_type;
+ isc_event_t *event = NULL;
+ isc_task_t *task = NULL;
+ int i;
+
+ nevents = nsdevents = 0;
+ done = false;
+
+ event_type = 3;
+
+ result = isc_test_begin(NULL, true, 4);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_mutex_init(&lock);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_condition_init(&cv);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ LOCK(&lock);
+
+ task = NULL;
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * This event causes the task to wait on cv.
+ */
+ event = isc_event_allocate(mctx, &senders[1], event_type, sd_event1,
+ NULL, sizeof(*event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_send(task, &event);
+
+ /*
+ * Now we fill up the task's event queue with some events.
+ */
+ for (i = 0; i < 256; ++i) {
+ event = isc_event_allocate(mctx, &senders[1], event_type,
+ sd_event2, NULL, sizeof(*event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_send(task, &event);
+ }
+
+ /*
+ * Now we register two shutdown events.
+ */
+ result = isc_task_onshutdown(task, sd_sde1, NULL);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task, sd_sde2, NULL);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_task_shutdown(task);
+
+ /*
+ * Now we free the task by signaling cv.
+ */
+ done = true;
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+
+ isc_task_detach(&task);
+
+ isc_test_end();
+
+ ATF_REQUIRE_EQ(nsdevents, 2);
+}
+
+/*
+ * Post-shutdown test:
+ * After isc_task_shutdown() has been called, any call to
+ * isc_task_onshutdown() will return ISC_R_SHUTTINGDOWN.
+ */
+static void
+psd_event1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+
+ while (!done) {
+ WAIT(&cv, &lock);
+ }
+
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+}
+
+static void
+psd_sde(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ isc_event_free(&event);
+}
+
+ATF_TC(post_shutdown);
+ATF_TC_HEAD(post_shutdown, tc) {
+ atf_tc_set_md_var(tc, "descr", "post-shutdown");
+}
+ATF_TC_BODY(post_shutdown, tc) {
+ isc_result_t result;
+ isc_eventtype_t event_type;
+ isc_event_t *event;
+ isc_task_t *task;
+
+ done = false;
+ event_type = 4;
+
+ result = isc_mutex_init(&lock);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_condition_init(&cv);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_test_begin(NULL, true, 2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ LOCK(&lock);
+
+ task = NULL;
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * This event causes the task to wait on cv.
+ */
+ event = isc_event_allocate(mctx, &senders[1], event_type, psd_event1,
+ NULL, sizeof(*event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_send(task, &event);
+
+ isc_task_shutdown(task);
+
+ result = isc_task_onshutdown(task, psd_sde, NULL);
+ ATF_CHECK_EQ(result, ISC_R_SHUTTINGDOWN);
+
+ /*
+ * Release the task.
+ */
+ done = true;
+
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+
+ isc_task_detach(&task);
+ isc_test_end();
+
+ (void) isc_condition_destroy(&cv);
+ DESTROYLOCK(&lock);
+}
+
+/*
+ * Helper for the purge tests below:
+ */
+
+#define SENDERCNT 3
+#define TYPECNT 4
+#define TAGCNT 5
+#define NEVENTS (SENDERCNT * TYPECNT * TAGCNT)
+
+static bool testrange;
+static void *purge_sender;
+static isc_eventtype_t purge_type_first;
+static isc_eventtype_t purge_type_last;
+static void *purge_tag;
+static int eventcnt;
+
+bool started = false;
+
+static void
+pg_event1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+ while (!started) {
+ WAIT(&cv, &lock);
+ }
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+}
+
+static void
+pg_event2(isc_task_t *task, isc_event_t *event) {
+ bool sender_match = false;
+ bool type_match = false;
+ bool tag_match = false;
+
+ UNUSED(task);
+
+ if ((purge_sender == NULL) || (purge_sender == event->ev_sender)) {
+ sender_match = true;
+ }
+
+ if (testrange) {
+ if ((purge_type_first <= event->ev_type) &&
+ (event->ev_type <= purge_type_last))
+ {
+ type_match = true;
+ }
+ } else {
+ if (purge_type_first == event->ev_type) {
+ type_match = true;
+ }
+ }
+
+ if ((purge_tag == NULL) || (purge_tag == event->ev_tag)) {
+ tag_match = true;
+ }
+
+ if (sender_match && type_match && tag_match) {
+ if (event->ev_attributes & ISC_EVENTATTR_NOPURGE) {
+ printf("event %p,%d,%p matched but was not purgeable\n",
+ event->ev_sender, (int)event->ev_type,
+ event->ev_tag);
+ ++eventcnt;
+ } else {
+ printf("*** event %p,%d,%p not purged\n",
+ event->ev_sender, (int)event->ev_type,
+ event->ev_tag);
+ }
+ } else {
+ ++eventcnt;
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+pg_sde(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+ done = true;
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+}
+
+static void
+test_purge(int sender, int type, int tag, int exp_purged) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+ isc_event_t *eventtab[NEVENTS];
+ isc_event_t *event = NULL;
+ isc_interval_t interval;
+ isc_time_t now;
+ int sender_cnt, type_cnt, tag_cnt, event_cnt, i;
+ int purged = 0;
+
+ started = false;
+ done = false;
+ eventcnt = 0;
+
+ result = isc_test_begin(NULL, true, 2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_mutex_init(&lock);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_condition_init(&cv);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task, pg_sde, NULL);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * Block the task on cv.
+ */
+ event = isc_event_allocate(mctx, (void *)1, 9999,
+ pg_event1, NULL, sizeof(*event));
+
+ ATF_REQUIRE(event != NULL);
+ isc_task_send(task, &event);
+
+ /*
+ * Fill the task's queue with some messages with varying
+ * sender, type, tag, and purgeable attribute values.
+ */
+ event_cnt = 0;
+ for (sender_cnt = 0; sender_cnt < SENDERCNT; ++sender_cnt) {
+ for (type_cnt = 0; type_cnt < TYPECNT; ++type_cnt) {
+ for (tag_cnt = 0; tag_cnt < TAGCNT; ++tag_cnt) {
+ eventtab[event_cnt] =
+ isc_event_allocate(mctx,
+ &senders[sender + sender_cnt],
+ (isc_eventtype_t)(type + type_cnt),
+ pg_event2, NULL, sizeof(*event));
+
+ ATF_REQUIRE(eventtab[event_cnt] != NULL);
+
+ eventtab[event_cnt]->ev_tag =
+ (void *)((uintptr_t)tag + tag_cnt);
+
+ /*
+ * Mark events as non-purgeable if
+ * sender, type and tag are all
+ * odd-numbered. (There should be 4
+ * of these out of 60 events total.)
+ */
+ if (((sender_cnt % 2) != 0) &&
+ ((type_cnt % 2) != 0) &&
+ ((tag_cnt % 2) != 0))
+ {
+ eventtab[event_cnt]->ev_attributes |=
+ ISC_EVENTATTR_NOPURGE;
+ }
+ ++event_cnt;
+ }
+ }
+ }
+
+ for (i = 0; i < event_cnt; ++i) {
+ isc_task_send(task, &eventtab[i]);
+ }
+
+ if (testrange) {
+ /*
+ * We're testing isc_task_purgerange.
+ */
+ purged = isc_task_purgerange(task, purge_sender,
+ (isc_eventtype_t)purge_type_first,
+ (isc_eventtype_t)purge_type_last,
+ purge_tag);
+ ATF_CHECK_EQ(purged, exp_purged);
+ } else {
+ /*
+ * We're testing isc_task_purge.
+ */
+ printf("purge events %p,%u,%p\n",
+ purge_sender, purge_type_first, purge_tag);
+ purged = isc_task_purge(task, purge_sender,
+ (isc_eventtype_t)purge_type_first,
+ purge_tag);
+ printf("purged %d expected %d\n", purged, exp_purged);
+ ATF_CHECK_EQ(purged, exp_purged);
+ }
+
+ /*
+ * Unblock the task, allowing event processing.
+ */
+ LOCK(&lock);
+ started = true;
+ SIGNAL(&cv);
+
+ isc_task_shutdown(task);
+
+ isc_interval_set(&interval, 5, 0);
+
+ /*
+ * Wait for shutdown processing to complete.
+ */
+ while (!done) {
+ result = isc_time_nowplusinterval(&now, &interval);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ WAITUNTIL(&cv, &lock, &now);
+ }
+
+ UNLOCK(&lock);
+
+ isc_task_detach(&task);
+
+ isc_test_end();
+ DESTROYLOCK(&lock);
+ (void) isc_condition_destroy(&cv);
+
+ ATF_CHECK_EQ(eventcnt, event_cnt - exp_purged);
+}
+
+/*
+ * Purge test:
+ * A call to isc_task_purge(task, sender, type, tag) purges all events of
+ * type 'type' and with tag 'tag' not marked as unpurgeable from sender
+ * from the task's " queue and returns the number of events purged.
+ */
+ATF_TC(purge);
+ATF_TC_HEAD(purge, tc) {
+ atf_tc_set_md_var(tc, "descr", "purge");
+}
+ATF_TC_BODY(purge, tc) {
+ /* Try purging on a specific sender. */
+ printf("testing purge on 2,4,8 expecting 1\n");
+ purge_sender = &senders[2];
+ purge_type_first = 4;
+ purge_type_last = 4;
+ purge_tag = (void *)8;
+ testrange = false;
+ test_purge(1, 4, 7, 1);
+
+ /* Try purging on all senders. */
+ printf("testing purge on 0,4,8 expecting 3\n");
+ purge_sender = NULL;
+ purge_type_first = 4;
+ purge_type_last = 4;
+ purge_tag = (void *)8;
+ testrange = false;
+ test_purge(1, 4, 7, 3);
+
+ /* Try purging on all senders, specified type, all tags. */
+ printf("testing purge on 0,4,0 expecting 15\n");
+ purge_sender = NULL;
+ purge_type_first = 4;
+ purge_type_last = 4;
+ purge_tag = NULL;
+ testrange = false;
+ test_purge(1, 4, 7, 15);
+
+ /* Try purging on a specified tag, no such type. */
+ printf("testing purge on 0,99,8 expecting 0\n");
+ purge_sender = NULL;
+ purge_type_first = 99;
+ purge_type_last = 99;
+ purge_tag = (void *)8;
+ testrange = false;
+ test_purge(1, 4, 7, 0);
+
+ /*
+ * Try purging on specified sender, type, all tags.
+ */
+ printf("testing purge on 3,5,0 expecting 5\n");
+ purge_sender = &senders[3];
+ purge_type_first = 5;
+ purge_type_last = 5;
+ purge_tag = NULL;
+ testrange = false;
+ test_purge(1, 4, 7, 5);
+}
+
+/*
+ * Purge range test:
+ * A call to isc_event_purgerange(task, sender, first, last, tag) purges
+ * all events not marked unpurgeable from sender 'sender' and of type within
+ * the range 'first' to 'last' inclusive from the task's event queue and
+ * returns the number of tasks purged.
+ */
+
+ATF_TC(purgerange);
+ATF_TC_HEAD(purgerange, tc) {
+ atf_tc_set_md_var(tc, "descr", "purge-range");
+}
+ATF_TC_BODY(purgerange, tc) {
+ /* Now let's try some ranges. */
+ printf("testing purgerange on 2,4-5,8 expecting 1\n");
+ purge_sender = &senders[2];
+ purge_type_first = 4;
+ purge_type_last = 5;
+ purge_tag = (void *)8;
+ testrange = true;
+ test_purge(1, 4, 7, 1);
+
+ /* Try purging on all senders. */
+ printf("testing purge on 0,4-5,8 expecting 5\n");
+ purge_sender = NULL;
+ purge_type_first = 4;
+ purge_type_last = 5;
+ purge_tag = (void *)8;
+ testrange = true;
+ test_purge(1, 4, 7, 5);
+
+ /* Try purging on all senders, specified type, all tags. */
+ printf("testing purge on 0,5-6,0 expecting 28\n");
+ purge_sender = NULL;
+ purge_type_first = 5;
+ purge_type_last = 6;
+ purge_tag = NULL;
+ testrange = true;
+ test_purge(1, 4, 7, 28);
+
+ /* Try purging on a specified tag, no such type. */
+ printf("testing purge on 0,99-101,8 expecting 0\n");
+ purge_sender = NULL;
+ purge_type_first = 99;
+ purge_type_last = 101;
+ purge_tag = (void *)8;
+ testrange = true;
+ test_purge(1, 4, 7, 0);
+
+ /* Try purging on specified sender, type, all tags. */
+ printf("testing purge on 3,5-6,0 expecting 10\n");
+ purge_sender = &senders[3];
+ purge_type_first = 5;
+ purge_type_last = 6;
+ purge_tag = NULL;
+ testrange = true;
+ test_purge(1, 4, 7, 10);
+}
+
+/*
+ * Helpers for purge event tests
+ */
+static void
+pge_event1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+ while (!started) {
+ WAIT(&cv, &lock);
+ }
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+}
+
+static void
+pge_event2(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ ++eventcnt;
+ isc_event_free(&event);
+}
+
+
+static void
+pge_sde(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ LOCK(&lock);
+ done = true;
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+
+ isc_event_free(&event);
+}
+
+static void
+try_purgeevent(bool purgeable) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+ bool purged;
+ isc_event_t *event1 = NULL;
+ isc_event_t *event2 = NULL;
+ isc_event_t *event2_clone = NULL;;
+ isc_time_t now;
+ isc_interval_t interval;
+
+ started = false;
+ done = false;
+ eventcnt = 0;
+
+ result = isc_mutex_init(&lock);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_condition_init(&cv);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_test_begin(NULL, true, 2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task, pge_sde, NULL);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * Block the task on cv.
+ */
+ event1 = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)1,
+ pge_event1, NULL, sizeof(*event1));
+ ATF_REQUIRE(event1 != NULL);
+ isc_task_send(task, &event1);
+
+ event2 = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)1,
+ pge_event2, NULL, sizeof(*event2));
+ ATF_REQUIRE(event2 != NULL);
+
+ event2_clone = event2;
+
+ if (purgeable) {
+ event2->ev_attributes &= ~ISC_EVENTATTR_NOPURGE;
+ } else {
+ event2->ev_attributes |= ISC_EVENTATTR_NOPURGE;
+ }
+
+ isc_task_send(task, &event2);
+
+ purged = isc_task_purgeevent(task, event2_clone);
+ ATF_CHECK_EQ(purgeable, purged);
+
+ /*
+ * Unblock the task, allowing event processing.
+ */
+ LOCK(&lock);
+ started = true;
+ SIGNAL(&cv);
+
+ isc_task_shutdown(task);
+
+ isc_interval_set(&interval, 5, 0);
+
+ /*
+ * Wait for shutdown processing to complete.
+ */
+ while (!done) {
+ result = isc_time_nowplusinterval(&now, &interval);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ WAITUNTIL(&cv, &lock, &now);
+ }
+
+ UNLOCK(&lock);
+
+ isc_task_detach(&task);
+
+ isc_test_end();
+ DESTROYLOCK(&lock);
+ (void) isc_condition_destroy(&cv);
+
+ ATF_REQUIRE_EQ(eventcnt, (purgeable ? 0 : 1));
+}
+
+/*
+ * Purge event test:
+ * When the event is marked as purgeable, a call to
+ * isc_task_purgeevent(task, event) purges the event 'event' from the
+ * task's queue and returns true.
+ */
+
+ATF_TC(purgeevent);
+ATF_TC_HEAD(purgeevent, tc) {
+ atf_tc_set_md_var(tc, "descr", "purge-event");
+}
+ATF_TC_BODY(purgeevent, tc) {
+ try_purgeevent(true);
+}
+
+/*
+ * Purge event not purgeable test:
+ * When the event is not marked as purgable, a call to
+ * isc_task_purgeevent(task, event) does not purge the event
+ * 'event' from the task's queue and returns false.
+ */
+
+ATF_TC(purgeevent_notpurge);
+ATF_TC_HEAD(purgeevent_notpurge, tc) {
+ atf_tc_set_md_var(tc, "descr", "purge-event");
+}
+ATF_TC_BODY(purgeevent_notpurge, tc) {
+ try_purgeevent(false);
+}
+#endif
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, create_task);
+ ATF_TP_ADD_TC(tp, all_events);
+ ATF_TP_ADD_TC(tp, privileged_events);
+ ATF_TP_ADD_TC(tp, privilege_drop);
+ ATF_TP_ADD_TC(tp, basic);
+ ATF_TP_ADD_TC(tp, task_exclusive);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ ATF_TP_ADD_TC(tp, manytasks);
+ ATF_TP_ADD_TC(tp, shutdown);
+ ATF_TP_ADD_TC(tp, post_shutdown);
+ ATF_TP_ADD_TC(tp, purge);
+ ATF_TP_ADD_TC(tp, purgerange);
+ ATF_TP_ADD_TC(tp, purgeevent);
+ ATF_TP_ADD_TC(tp, purgeevent_notpurge);
+#endif
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/tests/taskpool_test.c b/lib/isc/tests/taskpool_test.c
new file mode 100644
index 0000000..ff2de9e
--- /dev/null
+++ b/lib/isc/tests/taskpool_test.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+
+#include <isc/task.h>
+#include <isc/taskpool.h>
+
+#include "isctest.h"
+
+/*
+ * Individual unit tests
+ */
+
+/* Create a taskpool */
+ATF_TC(create_pool);
+ATF_TC_HEAD(create_pool, tc) {
+ atf_tc_set_md_var(tc, "descr", "create a taskpool");
+}
+ATF_TC_BODY(create_pool, tc) {
+ isc_result_t result;
+ isc_taskpool_t *pool = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_taskpool_create(taskmgr, mctx, 8, 2, &pool);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_taskpool_size(pool), 8);
+
+ isc_taskpool_destroy(&pool);
+ ATF_REQUIRE_EQ(pool, NULL);
+
+ isc_test_end();
+}
+
+/* Resize a taskpool */
+ATF_TC(expand_pool);
+ATF_TC_HEAD(expand_pool, tc) {
+ atf_tc_set_md_var(tc, "descr", "expand a taskpool");
+}
+ATF_TC_BODY(expand_pool, tc) {
+ isc_result_t result;
+ isc_taskpool_t *pool1 = NULL, *pool2 = NULL, *hold = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_taskpool_create(taskmgr, mctx, 10, 2, &pool1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_taskpool_size(pool1), 10);
+
+ /* resizing to a smaller size should have no effect */
+ hold = pool1;
+ result = isc_taskpool_expand(&pool1, 5, &pool2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_taskpool_size(pool2), 10);
+ ATF_REQUIRE_EQ(pool2, hold);
+ ATF_REQUIRE_EQ(pool1, NULL);
+ pool1 = pool2;
+ pool2 = NULL;
+
+ /* resizing to the same size should have no effect */
+ hold = pool1;
+ result = isc_taskpool_expand(&pool1, 10, &pool2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_taskpool_size(pool2), 10);
+ ATF_REQUIRE_EQ(pool2, hold);
+ ATF_REQUIRE_EQ(pool1, NULL);
+ pool1 = pool2;
+ pool2 = NULL;
+
+ /* resizing to larger size should make a new pool */
+ hold = pool1;
+ result = isc_taskpool_expand(&pool1, 20, &pool2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_taskpool_size(pool2), 20);
+ ATF_REQUIRE(pool2 != hold);
+ ATF_REQUIRE_EQ(pool1, NULL);
+
+ isc_taskpool_destroy(&pool2);
+ ATF_REQUIRE_EQ(pool2, NULL);
+
+ isc_test_end();
+}
+
+/* Get tasks */
+ATF_TC(get_tasks);
+ATF_TC_HEAD(get_tasks, tc) {
+ atf_tc_set_md_var(tc, "descr", "create a taskpool");
+}
+ATF_TC_BODY(get_tasks, tc) {
+ isc_result_t result;
+ isc_taskpool_t *pool = NULL;
+ isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_taskpool_create(taskmgr, mctx, 2, 2, &pool);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_taskpool_size(pool), 2);
+
+ /* two tasks in pool; make sure we can access them more than twice */
+ isc_taskpool_gettask(pool, &task1);
+ ATF_REQUIRE(ISCAPI_TASK_VALID(task1));
+
+ isc_taskpool_gettask(pool, &task2);
+ ATF_REQUIRE(ISCAPI_TASK_VALID(task2));
+
+ isc_taskpool_gettask(pool, &task3);
+ ATF_REQUIRE(ISCAPI_TASK_VALID(task3));
+
+ isc_task_destroy(&task1);
+ isc_task_destroy(&task2);
+ isc_task_destroy(&task3);
+
+ isc_taskpool_destroy(&pool);
+ ATF_REQUIRE_EQ(pool, NULL);
+
+ isc_test_end();
+}
+
+/* Get tasks */
+ATF_TC(set_privilege);
+ATF_TC_HEAD(set_privilege, tc) {
+ atf_tc_set_md_var(tc, "descr", "create a taskpool");
+}
+ATF_TC_BODY(set_privilege, tc) {
+ isc_result_t result;
+ isc_taskpool_t *pool = NULL;
+ isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_taskpool_create(taskmgr, mctx, 2, 2, &pool);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_taskpool_size(pool), 2);
+
+ isc_taskpool_setprivilege(pool, true);
+
+ isc_taskpool_gettask(pool, &task1);
+ isc_taskpool_gettask(pool, &task2);
+ isc_taskpool_gettask(pool, &task3);
+
+ ATF_CHECK(ISCAPI_TASK_VALID(task1));
+ ATF_CHECK(ISCAPI_TASK_VALID(task2));
+ ATF_CHECK(ISCAPI_TASK_VALID(task3));
+
+ ATF_CHECK(isc_task_privilege(task1));
+ ATF_CHECK(isc_task_privilege(task2));
+ ATF_CHECK(isc_task_privilege(task3));
+
+ isc_taskpool_setprivilege(pool, false);
+
+ ATF_CHECK(!isc_task_privilege(task1));
+ ATF_CHECK(!isc_task_privilege(task2));
+ ATF_CHECK(!isc_task_privilege(task3));
+
+ isc_task_destroy(&task1);
+ isc_task_destroy(&task2);
+ isc_task_destroy(&task3);
+
+ isc_taskpool_destroy(&pool);
+ ATF_REQUIRE_EQ(pool, NULL);
+
+ isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, create_pool);
+ ATF_TP_ADD_TC(tp, expand_pool);
+ ATF_TP_ADD_TC(tp, get_tasks);
+ ATF_TP_ADD_TC(tp, set_privilege);
+
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/testdata/file/keep b/lib/isc/tests/testdata/file/keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/isc/tests/testdata/file/keep
diff --git a/lib/isc/tests/time_test.c b/lib/isc/tests/time_test.c
new file mode 100644
index 0000000..c548869
--- /dev/null
+++ b/lib/isc/tests/time_test.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+#include <isc/time.h>
+#include <isc/result.h>
+
+ATF_TC(isc_time_parsehttptimestamp);
+ATF_TC_HEAD(isc_time_parsehttptimestamp, tc) {
+ atf_tc_set_md_var(tc, "descr", "parse http time stamp");
+}
+ATF_TC_BODY(isc_time_parsehttptimestamp, tc) {
+ isc_result_t result;
+ isc_time_t t, x;
+ char buf[ISC_FORMATHTTPTIMESTAMP_SIZE];
+
+ setenv("TZ", "PST8PDT", 1);
+ result = isc_time_now(&t);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_time_formathttptimestamp(&t, buf, sizeof(buf));
+ result = isc_time_parsehttptimestamp(buf, &x);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_time_seconds(&t), isc_time_seconds(&x));
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, isc_time_parsehttptimestamp);
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/timer_test.c b/lib/isc/tests/timer_test.c
new file mode 100644
index 0000000..7a32f1d
--- /dev/null
+++ b/lib/isc/tests/timer_test.c
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+
+#include <isc/condition.h>
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+#include <isc/util.h>
+
+#include "isctest.h"
+
+/*
+ * This entire test requires threads.
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+
+/*
+ * Helper functions
+ */
+#define FUDGE_SECONDS 0 /* in absence of clock_getres() */
+#define FUDGE_NANOSECONDS 500000000 /* in absence of clock_getres() */
+
+static isc_timer_t *timer = NULL;
+static isc_condition_t cv;
+static isc_mutex_t mx;
+static isc_time_t endtime;
+static isc_time_t lasttime;
+static int seconds;
+static int nanoseconds;
+static int eventcnt;
+static int nevents;
+
+static void
+shutdown(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+
+ UNUSED(task);
+
+ /*
+ * Signal shutdown processing complete.
+ */
+ result = isc_mutex_lock(&mx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_condition_signal(&cv);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_mutex_unlock(&mx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_event_free(&event);
+}
+
+static void
+setup_test(isc_timertype_t timertype, isc_time_t *expires,
+ isc_interval_t *interval,
+ void (*action)(isc_task_t *, isc_event_t *))
+{
+ isc_result_t result;
+ isc_task_t *task = NULL;
+ isc_time_settoepoch(&endtime);
+ eventcnt = 0;
+
+ result = isc_mutex_init(&mx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_condition_init(&cv);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ LOCK(&mx);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task, shutdown, NULL);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_time_now(&lasttime);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_timer_create(timermgr, timertype, expires, interval,
+ task, action, (void *)timertype,
+ &timer);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * Wait for shutdown processing to complete.
+ */
+ while (eventcnt != nevents) {
+ result = isc_condition_wait(&cv, &mx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ }
+
+ UNLOCK(&mx);
+
+ isc_task_detach(&task);
+ DESTROYLOCK(&mx);
+ (void) isc_condition_destroy(&cv);
+}
+
+static void
+ticktock(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ isc_time_t now;
+ isc_time_t base;
+ isc_time_t ulim;
+ isc_time_t llim;
+ isc_interval_t interval;
+ isc_eventtype_t expected_event_type;
+
+ ++eventcnt;
+
+ printf("tick %d\n", eventcnt);
+
+ expected_event_type = ISC_TIMEREVENT_LIFE;
+ if ((isc_timertype_t) event->ev_arg == isc_timertype_ticker) {
+ expected_event_type = ISC_TIMEREVENT_TICK;
+ }
+
+ if (event->ev_type != expected_event_type) {
+ printf("expected event type %u, got %u\n",
+ expected_event_type, event->ev_type);
+ }
+
+ result = isc_time_now(&now);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ result = isc_time_add(&lasttime, &interval, &base);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, FUDGE_SECONDS, FUDGE_NANOSECONDS);
+ result = isc_time_add(&base, &interval, &ulim);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_time_subtract(&base, &interval, &llim);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ ATF_CHECK(isc_time_compare(&llim, &now) <= 0);
+ ATF_CHECK(isc_time_compare(&ulim, &now) >= 0);
+ lasttime = now;
+
+ if (eventcnt == nevents) {
+ result = isc_time_now(&endtime);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ isc_timer_detach(&timer);
+ isc_task_shutdown(task);
+ }
+
+ isc_event_free(&event);
+}
+
+/*
+ * Individual unit tests
+ */
+
+ATF_TC(ticker);
+ATF_TC_HEAD(ticker, tc) {
+ atf_tc_set_md_var(tc, "descr", "timer type ticker");
+}
+ATF_TC_BODY(ticker, tc) {
+ isc_result_t result;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(tc);
+
+ nevents = 12;
+ seconds = 0;
+ nanoseconds = 500000000;
+
+ result = isc_test_begin(NULL, true, 2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ isc_time_settoepoch(&expires);
+
+ setup_test(isc_timertype_ticker, &expires, &interval, ticktock);
+
+ isc_test_end();
+}
+
+ATF_TC(once_life);
+ATF_TC_HEAD(once_life, tc) {
+ atf_tc_set_md_var(tc, "descr", "timer type once reaches lifetime");
+}
+ATF_TC_BODY(once_life, tc) {
+ isc_result_t result;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(tc);
+
+ nevents = 1;
+ seconds = 1;
+ nanoseconds = 100000000;
+
+ result = isc_test_begin(NULL, true, 2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ result = isc_time_nowplusinterval(&expires, &interval);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, 0, 0);
+
+ setup_test(isc_timertype_once, &expires, &interval, ticktock);
+
+ isc_test_end();
+}
+
+
+static void
+test_idle(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ isc_time_t now;
+ isc_time_t base;
+ isc_time_t ulim;
+ isc_time_t llim;
+ isc_interval_t interval;
+
+ ++eventcnt;
+
+ printf("tick %d\n", eventcnt);
+
+ result = isc_time_now(&now);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ result = isc_time_add(&lasttime, &interval, &base);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, FUDGE_SECONDS, FUDGE_NANOSECONDS);
+ result = isc_time_add(&base, &interval, &ulim);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_time_subtract(&base, &interval, &llim);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ ATF_CHECK(isc_time_compare(&llim, &now) <= 0);
+ ATF_CHECK(isc_time_compare(&ulim, &now) >= 0);
+ lasttime = now;
+
+ ATF_CHECK_EQ(event->ev_type, ISC_TIMEREVENT_IDLE);
+
+ isc_timer_detach(&timer);
+ isc_task_shutdown(task);
+ isc_event_free(&event);
+}
+
+ATF_TC(once_idle);
+ATF_TC_HEAD(once_idle, tc) {
+ atf_tc_set_md_var(tc, "descr", "timer type once idles out");
+}
+ATF_TC_BODY(once_idle, tc) {
+ isc_result_t result;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(tc);
+
+ nevents = 1;
+ seconds = 1;
+ nanoseconds = 200000000;
+
+ result = isc_test_begin(NULL, true, 2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds + 1, nanoseconds);
+ result = isc_time_nowplusinterval(&expires, &interval);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+
+ setup_test(isc_timertype_once, &expires, &interval, test_idle);
+
+ isc_test_end();
+}
+
+static void
+test_reset(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ isc_time_t now;
+ isc_time_t base;
+ isc_time_t ulim;
+ isc_time_t llim;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ ++eventcnt;
+
+ printf("tick %d\n", eventcnt);
+
+ /*
+ * Check expired time.
+ */
+
+ result = isc_time_now(&now);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ result = isc_time_add(&lasttime, &interval, &base);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, FUDGE_SECONDS, FUDGE_NANOSECONDS);
+ result = isc_time_add(&base, &interval, &ulim);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_time_subtract(&base, &interval, &llim);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ ATF_CHECK(isc_time_compare(&llim, &now) <= 0);
+ ATF_CHECK(isc_time_compare(&ulim, &now) >= 0);
+ lasttime = now;
+
+ if (eventcnt < 3) {
+ ATF_CHECK_EQ(event->ev_type, ISC_TIMEREVENT_TICK);
+
+ if (eventcnt == 2) {
+ isc_interval_set(&interval, seconds, nanoseconds);
+ result = isc_time_nowplusinterval(&expires, &interval);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, 0, 0);
+ result = isc_timer_reset(timer, isc_timertype_once,
+ &expires, &interval,
+ false);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ }
+ } else {
+ ATF_CHECK_EQ(event->ev_type, ISC_TIMEREVENT_LIFE);
+
+ isc_timer_detach(&timer);
+ isc_task_shutdown(task);
+ }
+
+ isc_event_free(&event);
+}
+
+ATF_TC(reset);
+ATF_TC_HEAD(reset, tc) {
+ atf_tc_set_md_var(tc, "descr", "timer reset");
+}
+ATF_TC_BODY(reset, tc) {
+ isc_result_t result;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ nevents = 3;
+ seconds = 0;
+ nanoseconds = 750000000;
+
+ isc_interval_set(&interval, seconds, nanoseconds);
+ isc_time_settoepoch(&expires);
+
+ setup_test(isc_timertype_ticker, &expires, &interval, test_reset);
+
+ isc_test_end();
+}
+
+static int startflag;
+static int shutdownflag;
+static isc_timer_t *tickertimer = NULL;
+static isc_timer_t *oncetimer = NULL;
+static isc_task_t *task1 = NULL;
+static isc_task_t *task2 = NULL;
+
+/*
+ * task1 blocks on mx while events accumulate
+ * in its queue, until signaled by task2.
+ */
+
+static void
+start_event(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ printf("start_event\n");
+
+ LOCK(&mx);
+ while (! startflag) {
+ (void) isc_condition_wait(&cv, &mx);
+ }
+ UNLOCK(&mx);
+
+ isc_event_free(&event);
+}
+
+static void
+tick_event(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(task);
+
+ ++eventcnt;
+ printf("tick_event %d\n", eventcnt);
+
+ /*
+ * On the first tick, purge all remaining tick events
+ * and then shut down the task.
+ */
+ if (eventcnt == 1) {
+ isc_time_settoepoch(&expires);
+ isc_interval_set(&interval, seconds, 0);
+ result = isc_timer_reset(tickertimer, isc_timertype_ticker,
+ &expires, &interval, true);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_task_shutdown(task);
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+once_event(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+
+ printf("once_event\n");
+
+ /*
+ * Allow task1 to start processing events.
+ */
+ LOCK(&mx);
+ startflag = 1;
+
+ result = isc_condition_broadcast(&cv);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ UNLOCK(&mx);
+
+ isc_event_free(&event);
+ isc_task_shutdown(task);
+}
+
+static void
+shutdown_purge(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+
+ UNUSED(task);
+ UNUSED(event);
+
+ printf("shutdown_event\n");
+
+ /*
+ * Signal shutdown processing complete.
+ */
+ LOCK(&mx);
+ shutdownflag = 1;
+
+ result = isc_condition_signal(&cv);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ UNLOCK(&mx);
+
+ isc_event_free(&event);
+}
+
+ATF_TC(purge);
+ATF_TC_HEAD(purge, tc) {
+ atf_tc_set_md_var(tc, "descr", "timer events purged");
+}
+ATF_TC_BODY(purge, tc) {
+ isc_result_t result;
+ isc_event_t *event = NULL;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ startflag = 0;
+ shutdownflag = 0;
+ eventcnt = 0;
+ seconds = 1;
+ nanoseconds = 0;
+
+ result = isc_mutex_init(&mx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_condition_init(&cv);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_onshutdown(task1, shutdown_purge, NULL);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ LOCK(&mx);
+
+ event = isc_event_allocate(mctx, (void *)1 , (isc_eventtype_t)1,
+ start_event, NULL, sizeof(*event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_send(task1, &event);
+
+ isc_time_settoepoch(&expires);
+ isc_interval_set(&interval, seconds, 0);
+
+ tickertimer = NULL;
+ result = isc_timer_create(timermgr, isc_timertype_ticker,
+ &expires, &interval, task1,
+ tick_event, NULL, &tickertimer);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ oncetimer = NULL;
+
+ isc_interval_set(&interval, (seconds * 2) + 1, 0);
+ result = isc_time_nowplusinterval(&expires, &interval);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, 0, 0);
+ result = isc_timer_create(timermgr, isc_timertype_once,
+ &expires, &interval, task2,
+ once_event, NULL, &oncetimer);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * Wait for shutdown processing to complete.
+ */
+ while (! shutdownflag) {
+ result = isc_condition_wait(&cv, &mx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ }
+
+ UNLOCK(&mx);
+
+ ATF_CHECK_EQ(eventcnt, 1);
+
+ isc_timer_detach(&tickertimer);
+ isc_timer_detach(&oncetimer);
+ isc_task_destroy(&task1);
+ isc_task_destroy(&task2);
+ DESTROYLOCK(&mx);
+
+ isc_test_end();
+}
+#else
+ATF_TC(untested);
+ATF_TC_HEAD(untested, tc) {
+ atf_tc_set_md_var(tc, "descr", "skipping nsec3 test");
+}
+ATF_TC_BODY(untested, tc) {
+ UNUSED(tc);
+ atf_tc_skip("DNSSEC not available");
+}
+#endif
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+#ifdef ISC_PLATFORM_USETHREADS
+ ATF_TP_ADD_TC(tp, ticker);
+ ATF_TP_ADD_TC(tp, once_life);
+ ATF_TP_ADD_TC(tp, once_idle);
+ ATF_TP_ADD_TC(tp, reset);
+ ATF_TP_ADD_TC(tp, purge);
+#else
+ ATF_TP_ADD_TC(tp, untested);
+#endif
+
+ return (atf_no_error());
+}
diff --git a/lib/isc/timer.c b/lib/isc/timer.c
new file mode 100644
index 0000000..2baa9e6
--- /dev/null
+++ b/lib/isc/timer.c
@@ -0,0 +1,1191 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/app.h>
+#include <isc/condition.h>
+#include <isc/heap.h>
+#include <isc/log.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/once.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#ifdef OPENSSL_LEAKS
+#include <openssl/err.h>
+#endif
+
+/* See task.c about the following definition: */
+#ifdef ISC_PLATFORM_USETHREADS
+#define USE_TIMER_THREAD
+#else
+#define USE_SHARED_MANAGER
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifndef USE_TIMER_THREAD
+#include "timer_p.h"
+#endif /* USE_TIMER_THREAD */
+
+#ifdef ISC_TIMER_TRACE
+#define XTRACE(s) fprintf(stderr, "%s\n", (s))
+#define XTRACEID(s, t) fprintf(stderr, "%s %p\n", (s), (t))
+#define XTRACETIME(s, d) fprintf(stderr, "%s %u.%09u\n", (s), \
+ (d).seconds, (d).nanoseconds)
+#define XTRACETIME2(s, d, n) fprintf(stderr, "%s %u.%09u %u.%09u\n", (s), \
+ (d).seconds, (d).nanoseconds, (n).seconds, (n).nanoseconds)
+#define XTRACETIMER(s, t, d) fprintf(stderr, "%s %p %u.%09u\n", (s), (t), \
+ (d).seconds, (d).nanoseconds)
+#else
+#define XTRACE(s)
+#define XTRACEID(s, t)
+#define XTRACETIME(s, d)
+#define XTRACETIME2(s, d, n)
+#define XTRACETIMER(s, t, d)
+#endif /* ISC_TIMER_TRACE */
+
+#define TIMER_MAGIC ISC_MAGIC('T', 'I', 'M', 'R')
+#define VALID_TIMER(t) ISC_MAGIC_VALID(t, TIMER_MAGIC)
+
+typedef struct isc__timer isc__timer_t;
+typedef struct isc__timermgr isc__timermgr_t;
+
+struct isc__timer {
+ /*! Not locked. */
+ isc_timer_t common;
+ isc__timermgr_t * manager;
+ isc_mutex_t lock;
+ /*! Locked by timer lock. */
+ unsigned int references;
+ isc_time_t idle;
+ /*! Locked by manager lock. */
+ isc_timertype_t type;
+ isc_time_t expires;
+ isc_interval_t interval;
+ isc_task_t * task;
+ isc_taskaction_t action;
+ void * arg;
+ unsigned int index;
+ isc_time_t due;
+ LINK(isc__timer_t) link;
+};
+
+#define TIMER_MANAGER_MAGIC ISC_MAGIC('T', 'I', 'M', 'M')
+#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TIMER_MANAGER_MAGIC)
+
+struct isc__timermgr {
+ /* Not locked. */
+ isc_timermgr_t common;
+ isc_mem_t * mctx;
+ isc_mutex_t lock;
+ /* Locked by manager lock. */
+ bool done;
+ LIST(isc__timer_t) timers;
+ unsigned int nscheduled;
+ isc_time_t due;
+#ifdef USE_TIMER_THREAD
+ isc_condition_t wakeup;
+ isc_thread_t thread;
+#endif /* USE_TIMER_THREAD */
+#ifdef USE_SHARED_MANAGER
+ unsigned int refs;
+#endif /* USE_SHARED_MANAGER */
+ isc_heap_t * heap;
+};
+
+/*%
+ * The following are intended for internal use (indicated by "isc__"
+ * prefix) but are not declared as static, allowing direct access from
+ * unit tests etc.
+ */
+
+isc_result_t
+isc__timer_create(isc_timermgr_t *manager, isc_timertype_t type,
+ const isc_time_t *expires, const isc_interval_t *interval,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_timer_t **timerp);
+isc_result_t
+isc__timer_reset(isc_timer_t *timer, isc_timertype_t type,
+ const isc_time_t *expires, const isc_interval_t *interval,
+ bool purge);
+isc_timertype_t
+isc_timer_gettype(isc_timer_t *timer);
+isc_result_t
+isc__timer_touch(isc_timer_t *timer);
+void
+isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp);
+void
+isc__timer_detach(isc_timer_t **timerp);
+isc_result_t
+isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp);
+void
+isc_timermgr_poke(isc_timermgr_t *manager0);
+void
+isc__timermgr_destroy(isc_timermgr_t **managerp);
+
+static struct isc__timermethods {
+ isc_timermethods_t methods;
+
+ /*%
+ * The following are defined just for avoiding unused static functions.
+ */
+ void *gettype;
+} timermethods = {
+ {
+ isc__timer_attach,
+ isc__timer_detach,
+ isc__timer_reset,
+ isc__timer_touch
+ },
+ (void *)isc_timer_gettype
+};
+
+static struct isc__timermgrmethods {
+ isc_timermgrmethods_t methods;
+ void *poke; /* see above */
+} timermgrmethods = {
+ {
+ isc__timermgr_destroy,
+ isc__timer_create
+ },
+ (void *)isc_timermgr_poke
+};
+
+#ifdef USE_SHARED_MANAGER
+/*!
+ * If the manager is supposed to be shared, there can be only one.
+ */
+static isc__timermgr_t *timermgr = NULL;
+#endif /* USE_SHARED_MANAGER */
+
+static inline isc_result_t
+schedule(isc__timer_t *timer, isc_time_t *now, bool signal_ok) {
+ isc_result_t result;
+ isc__timermgr_t *manager;
+ isc_time_t due;
+ int cmp;
+#ifdef USE_TIMER_THREAD
+ bool timedwait;
+#endif
+
+ /*!
+ * Note: the caller must ensure locking.
+ */
+
+ REQUIRE(timer->type != isc_timertype_inactive);
+
+#ifndef USE_TIMER_THREAD
+ UNUSED(signal_ok);
+#endif /* USE_TIMER_THREAD */
+
+ manager = timer->manager;
+
+#ifdef USE_TIMER_THREAD
+ /*!
+ * If the manager was timed wait, we may need to signal the
+ * manager to force a wakeup.
+ */
+ timedwait = (manager->nscheduled > 0 &&
+ isc_time_seconds(&manager->due) != 0);
+#endif
+
+ /*
+ * Compute the new due time.
+ */
+ if (timer->type != isc_timertype_once) {
+ result = isc_time_add(now, &timer->interval, &due);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (timer->type == isc_timertype_limited &&
+ isc_time_compare(&timer->expires, &due) < 0)
+ due = timer->expires;
+ } else {
+ if (isc_time_isepoch(&timer->idle))
+ due = timer->expires;
+ else if (isc_time_isepoch(&timer->expires))
+ due = timer->idle;
+ else if (isc_time_compare(&timer->idle, &timer->expires) < 0)
+ due = timer->idle;
+ else
+ due = timer->expires;
+ }
+
+ /*
+ * Schedule the timer.
+ */
+
+ if (timer->index > 0) {
+ /*
+ * Already scheduled.
+ */
+ cmp = isc_time_compare(&due, &timer->due);
+ timer->due = due;
+ switch (cmp) {
+ case -1:
+ isc_heap_increased(manager->heap, timer->index);
+ break;
+ case 1:
+ isc_heap_decreased(manager->heap, timer->index);
+ break;
+ case 0:
+ /* Nothing to do. */
+ break;
+ }
+ } else {
+ timer->due = due;
+ result = isc_heap_insert(manager->heap, timer);
+ if (result != ISC_R_SUCCESS) {
+ INSIST(result == ISC_R_NOMEMORY);
+ return (ISC_R_NOMEMORY);
+ }
+ manager->nscheduled++;
+ }
+
+ XTRACETIMER(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+ ISC_MSG_SCHEDULE, "schedule"), timer, due);
+
+ /*
+ * If this timer is at the head of the queue, we need to ensure
+ * that we won't miss it if it has a more recent due time than
+ * the current "next" timer. We do this either by waking up the
+ * run thread, or explicitly setting the value in the manager.
+ */
+#ifdef USE_TIMER_THREAD
+
+ /*
+ * This is a temporary (probably) hack to fix a bug on tru64 5.1
+ * and 5.1a. Sometimes, pthread_cond_timedwait() doesn't actually
+ * return when the time expires, so here, we check to see if
+ * we're 15 seconds or more behind, and if we are, we signal
+ * the dispatcher. This isn't such a bad idea as a general purpose
+ * watchdog, so perhaps we should just leave it in here.
+ */
+ if (signal_ok && timedwait) {
+ isc_interval_t fifteen;
+ isc_time_t then;
+
+ isc_interval_set(&fifteen, 15, 0);
+ result = isc_time_add(&manager->due, &fifteen, &then);
+
+ if (result == ISC_R_SUCCESS &&
+ isc_time_compare(&then, now) < 0) {
+ SIGNAL(&manager->wakeup);
+ signal_ok = false;
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_TIMER, ISC_LOG_WARNING,
+ "*** POKED TIMER ***");
+ }
+ }
+
+ if (timer->index == 1 && signal_ok) {
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+ ISC_MSG_SIGNALSCHED,
+ "signal (schedule)"));
+ SIGNAL(&manager->wakeup);
+ }
+#else /* USE_TIMER_THREAD */
+ if (timer->index == 1 &&
+ isc_time_compare(&timer->due, &manager->due) < 0)
+ manager->due = timer->due;
+#endif /* USE_TIMER_THREAD */
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+deschedule(isc__timer_t *timer) {
+#ifdef USE_TIMER_THREAD
+ bool need_wakeup = false;
+#endif
+ isc__timermgr_t *manager;
+
+ /*
+ * The caller must ensure locking.
+ */
+
+ manager = timer->manager;
+ if (timer->index > 0) {
+#ifdef USE_TIMER_THREAD
+ if (timer->index == 1)
+ need_wakeup = true;
+#endif
+ isc_heap_delete(manager->heap, timer->index);
+ timer->index = 0;
+ INSIST(manager->nscheduled > 0);
+ manager->nscheduled--;
+#ifdef USE_TIMER_THREAD
+ if (need_wakeup) {
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+ ISC_MSG_SIGNALDESCHED,
+ "signal (deschedule)"));
+ SIGNAL(&manager->wakeup);
+ }
+#endif /* USE_TIMER_THREAD */
+ }
+}
+
+static void
+destroy(isc__timer_t *timer) {
+ isc__timermgr_t *manager = timer->manager;
+
+ /*
+ * The caller must ensure it is safe to destroy the timer.
+ */
+
+ LOCK(&manager->lock);
+
+ (void)isc_task_purgerange(timer->task,
+ timer,
+ ISC_TIMEREVENT_FIRSTEVENT,
+ ISC_TIMEREVENT_LASTEVENT,
+ NULL);
+ deschedule(timer);
+ UNLINK(manager->timers, timer, link);
+
+ UNLOCK(&manager->lock);
+
+ isc_task_detach(&timer->task);
+ DESTROYLOCK(&timer->lock);
+ timer->common.impmagic = 0;
+ timer->common.magic = 0;
+ isc_mem_put(manager->mctx, timer, sizeof(*timer));
+}
+
+isc_result_t
+isc__timer_create(isc_timermgr_t *manager0, isc_timertype_t type,
+ const isc_time_t *expires, const isc_interval_t *interval,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_timer_t **timerp)
+{
+ isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
+ isc__timer_t *timer;
+ isc_result_t result;
+ isc_time_t now;
+
+ /*
+ * Create a new 'type' timer managed by 'manager'. The timers
+ * parameters are specified by 'expires' and 'interval'. Events
+ * will be posted to 'task' and when dispatched 'action' will be
+ * called with 'arg' as the arg value. The new timer is returned
+ * in 'timerp'.
+ */
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+ if (expires == NULL)
+ expires = isc_time_epoch;
+ if (interval == NULL)
+ interval = isc_interval_zero;
+ REQUIRE(type == isc_timertype_inactive ||
+ !(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
+ REQUIRE(timerp != NULL && *timerp == NULL);
+ REQUIRE(type != isc_timertype_limited ||
+ !(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
+
+ /*
+ * Get current time.
+ */
+ if (type != isc_timertype_inactive) {
+ TIME_NOW(&now);
+ } else {
+ /*
+ * We don't have to do this, but it keeps the compiler from
+ * complaining about "now" possibly being used without being
+ * set, even though it will never actually happen.
+ */
+ isc_time_settoepoch(&now);
+ }
+
+
+ timer = isc_mem_get(manager->mctx, sizeof(*timer));
+ if (timer == NULL)
+ return (ISC_R_NOMEMORY);
+
+ timer->manager = manager;
+ timer->references = 1;
+
+ if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
+ result = isc_time_add(&now, interval, &timer->idle);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(manager->mctx, timer, sizeof(*timer));
+ return (result);
+ }
+ } else
+ isc_time_settoepoch(&timer->idle);
+
+ timer->type = type;
+ timer->expires = *expires;
+ timer->interval = *interval;
+ timer->task = NULL;
+ isc_task_attach(task, &timer->task);
+ timer->action = action;
+ /*
+ * Removing the const attribute from "arg" is the best of two
+ * evils here. If the timer->arg member is made const, then
+ * it affects a great many recipients of the timer event
+ * which did not pass in an "arg" that was truly const.
+ * Changing isc_timer_create() to not have "arg" prototyped as const,
+ * though, can cause compilers warnings for calls that *do*
+ * have a truly const arg. The caller will have to carefully
+ * keep track of whether arg started as a true const.
+ */
+ DE_CONST(arg, timer->arg);
+ timer->index = 0;
+ result = isc_mutex_init(&timer->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_task_detach(&timer->task);
+ isc_mem_put(manager->mctx, timer, sizeof(*timer));
+ return (result);
+ }
+ ISC_LINK_INIT(timer, link);
+ timer->common.impmagic = TIMER_MAGIC;
+ timer->common.magic = ISCAPI_TIMER_MAGIC;
+ timer->common.methods = (isc_timermethods_t *)&timermethods;
+
+ LOCK(&manager->lock);
+
+ /*
+ * Note we don't have to lock the timer like we normally would because
+ * there are no external references to it yet.
+ */
+
+ if (type != isc_timertype_inactive)
+ result = schedule(timer, &now, true);
+ else
+ result = ISC_R_SUCCESS;
+ if (result == ISC_R_SUCCESS) {
+ *timerp = (isc_timer_t *)timer;
+ APPEND(manager->timers, timer, link);
+ }
+
+ UNLOCK(&manager->lock);
+
+ if (result != ISC_R_SUCCESS) {
+ timer->common.impmagic = 0;
+ timer->common.magic = 0;
+ DESTROYLOCK(&timer->lock);
+ isc_task_detach(&timer->task);
+ isc_mem_put(manager->mctx, timer, sizeof(*timer));
+ return (result);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__timer_reset(isc_timer_t *timer0, isc_timertype_t type,
+ const isc_time_t *expires, const isc_interval_t *interval,
+ bool purge)
+{
+ isc__timer_t *timer = (isc__timer_t *)timer0;
+ isc_time_t now;
+ isc__timermgr_t *manager;
+ isc_result_t result;
+
+ /*
+ * Change the timer's type, expires, and interval values to the given
+ * values. If 'purge' is true, any pending events from this timer
+ * are purged from its task's event queue.
+ */
+
+ REQUIRE(VALID_TIMER(timer));
+ manager = timer->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ if (expires == NULL)
+ expires = isc_time_epoch;
+ if (interval == NULL)
+ interval = isc_interval_zero;
+ REQUIRE(type == isc_timertype_inactive ||
+ !(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
+ REQUIRE(type != isc_timertype_limited ||
+ !(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
+
+ /*
+ * Get current time.
+ */
+ if (type != isc_timertype_inactive) {
+ TIME_NOW(&now);
+ } else {
+ /*
+ * We don't have to do this, but it keeps the compiler from
+ * complaining about "now" possibly being used without being
+ * set, even though it will never actually happen.
+ */
+ isc_time_settoepoch(&now);
+ }
+
+ LOCK(&manager->lock);
+ LOCK(&timer->lock);
+
+ if (purge)
+ (void)isc_task_purgerange(timer->task,
+ timer,
+ ISC_TIMEREVENT_FIRSTEVENT,
+ ISC_TIMEREVENT_LASTEVENT,
+ NULL);
+ timer->type = type;
+ timer->expires = *expires;
+ timer->interval = *interval;
+ if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
+ result = isc_time_add(&now, interval, &timer->idle);
+ } else {
+ isc_time_settoepoch(&timer->idle);
+ result = ISC_R_SUCCESS;
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ if (type == isc_timertype_inactive) {
+ deschedule(timer);
+ result = ISC_R_SUCCESS;
+ } else
+ result = schedule(timer, &now, true);
+ }
+
+ UNLOCK(&timer->lock);
+ UNLOCK(&manager->lock);
+
+ return (result);
+}
+
+isc_timertype_t
+isc_timer_gettype(isc_timer_t *timer0) {
+ isc__timer_t *timer = (isc__timer_t *)timer0;
+ isc_timertype_t t;
+
+ REQUIRE(VALID_TIMER(timer));
+
+ LOCK(&timer->lock);
+ t = timer->type;
+ UNLOCK(&timer->lock);
+
+ return (t);
+}
+
+isc_result_t
+isc__timer_touch(isc_timer_t *timer0) {
+ isc__timer_t *timer = (isc__timer_t *)timer0;
+ isc_result_t result;
+ isc_time_t now;
+
+ /*
+ * Set the last-touched time of 'timer' to the current time.
+ */
+
+ REQUIRE(VALID_TIMER(timer));
+
+ LOCK(&timer->lock);
+
+ /*
+ * We'd like to
+ *
+ * REQUIRE(timer->type == isc_timertype_once);
+ *
+ * but we cannot without locking the manager lock too, which we
+ * don't want to do.
+ */
+
+ TIME_NOW(&now);
+ result = isc_time_add(&now, &timer->interval, &timer->idle);
+
+ UNLOCK(&timer->lock);
+
+ return (result);
+}
+
+void
+isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp) {
+ isc__timer_t *timer = (isc__timer_t *)timer0;
+
+ /*
+ * Attach *timerp to timer.
+ */
+
+ REQUIRE(VALID_TIMER(timer));
+ REQUIRE(timerp != NULL && *timerp == NULL);
+
+ LOCK(&timer->lock);
+ timer->references++;
+ UNLOCK(&timer->lock);
+
+ *timerp = (isc_timer_t *)timer;
+}
+
+void
+isc__timer_detach(isc_timer_t **timerp) {
+ isc__timer_t *timer;
+ bool free_timer = false;
+
+ /*
+ * Detach *timerp from its timer.
+ */
+
+ REQUIRE(timerp != NULL);
+ timer = (isc__timer_t *)*timerp;
+ REQUIRE(VALID_TIMER(timer));
+
+ LOCK(&timer->lock);
+ REQUIRE(timer->references > 0);
+ timer->references--;
+ if (timer->references == 0)
+ free_timer = true;
+ UNLOCK(&timer->lock);
+
+ if (free_timer)
+ destroy(timer);
+
+ *timerp = NULL;
+}
+
+static void
+dispatch(isc__timermgr_t *manager, isc_time_t *now) {
+ bool done = false, post_event, need_schedule;
+ isc_timerevent_t *event;
+ isc_eventtype_t type = 0;
+ isc__timer_t *timer;
+ isc_result_t result;
+ bool idle;
+
+ /*!
+ * The caller must be holding the manager lock.
+ */
+
+ while (manager->nscheduled > 0 && !done) {
+ timer = isc_heap_element(manager->heap, 1);
+ INSIST(timer != NULL && timer->type != isc_timertype_inactive);
+ if (isc_time_compare(now, &timer->due) >= 0) {
+ if (timer->type == isc_timertype_ticker) {
+ type = ISC_TIMEREVENT_TICK;
+ post_event = true;
+ need_schedule = true;
+ } else if (timer->type == isc_timertype_limited) {
+ int cmp;
+ cmp = isc_time_compare(now, &timer->expires);
+ if (cmp >= 0) {
+ type = ISC_TIMEREVENT_LIFE;
+ post_event = true;
+ need_schedule = false;
+ } else {
+ type = ISC_TIMEREVENT_TICK;
+ post_event = true;
+ need_schedule = true;
+ }
+ } else if (!isc_time_isepoch(&timer->expires) &&
+ isc_time_compare(now,
+ &timer->expires) >= 0) {
+ type = ISC_TIMEREVENT_LIFE;
+ post_event = true;
+ need_schedule = false;
+ } else {
+ idle = false;
+
+ LOCK(&timer->lock);
+ if (!isc_time_isepoch(&timer->idle) &&
+ isc_time_compare(now,
+ &timer->idle) >= 0) {
+ idle = true;
+ }
+ UNLOCK(&timer->lock);
+ if (idle) {
+ type = ISC_TIMEREVENT_IDLE;
+ post_event = true;
+ need_schedule = false;
+ } else {
+ /*
+ * Idle timer has been touched;
+ * reschedule.
+ */
+ XTRACEID(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TIMER,
+ ISC_MSG_IDLERESCHED,
+ "idle reschedule"),
+ timer);
+ post_event = false;
+ need_schedule = true;
+ }
+ }
+
+ if (post_event) {
+ XTRACEID(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TIMER,
+ ISC_MSG_POSTING,
+ "posting"), timer);
+ /*
+ * XXX We could preallocate this event.
+ */
+ event = (isc_timerevent_t *)isc_event_allocate(manager->mctx,
+ timer,
+ type,
+ timer->action,
+ timer->arg,
+ sizeof(*event));
+
+ if (event != NULL) {
+ event->due = timer->due;
+ isc_task_send(timer->task,
+ ISC_EVENT_PTR(&event));
+ } else
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "%s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TIMER,
+ ISC_MSG_EVENTNOTALLOC,
+ "couldn't "
+ "allocate event"));
+ }
+
+ timer->index = 0;
+ isc_heap_delete(manager->heap, 1);
+ manager->nscheduled--;
+
+ if (need_schedule) {
+ result = schedule(timer, now, false);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s: %u",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TIMER,
+ ISC_MSG_SCHEDFAIL,
+ "couldn't schedule "
+ "timer"),
+ result);
+ }
+ } else {
+ manager->due = timer->due;
+ done = true;
+ }
+ }
+}
+
+#ifdef USE_TIMER_THREAD
+static isc_threadresult_t
+#ifdef _WIN32 /* XXXDCL */
+WINAPI
+#endif
+run(void *uap) {
+ isc__timermgr_t *manager = uap;
+ isc_time_t now;
+ isc_result_t result;
+
+ LOCK(&manager->lock);
+ while (!manager->done) {
+ TIME_NOW(&now);
+
+ XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_RUNNING,
+ "running"), now);
+
+ dispatch(manager, &now);
+
+ if (manager->nscheduled > 0) {
+ XTRACETIME2(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_WAITUNTIL,
+ "waituntil"),
+ manager->due, now);
+ result = WAITUNTIL(&manager->wakeup, &manager->lock, &manager->due);
+ INSIST(result == ISC_R_SUCCESS ||
+ result == ISC_R_TIMEDOUT);
+ } else {
+ XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_WAIT, "wait"), now);
+ WAIT(&manager->wakeup, &manager->lock);
+ }
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+ ISC_MSG_WAKEUP, "wakeup"));
+ }
+ UNLOCK(&manager->lock);
+
+#ifdef OPENSSL_LEAKS
+ ERR_remove_state(0);
+#endif
+
+ return ((isc_threadresult_t)0);
+}
+#endif /* USE_TIMER_THREAD */
+
+static bool
+sooner(void *v1, void *v2) {
+ isc__timer_t *t1, *t2;
+
+ t1 = v1;
+ t2 = v2;
+ REQUIRE(VALID_TIMER(t1));
+ REQUIRE(VALID_TIMER(t2));
+
+ if (isc_time_compare(&t1->due, &t2->due) < 0)
+ return (true);
+ return (false);
+}
+
+static void
+set_index(void *what, unsigned int index) {
+ isc__timer_t *timer;
+
+ timer = what;
+ REQUIRE(VALID_TIMER(timer));
+
+ timer->index = index;
+}
+
+isc_result_t
+isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) {
+ isc__timermgr_t *manager;
+ isc_result_t result;
+
+ /*
+ * Create a timer manager.
+ */
+
+ REQUIRE(managerp != NULL && *managerp == NULL);
+
+#ifdef USE_SHARED_MANAGER
+ if (timermgr != NULL) {
+ timermgr->refs++;
+ *managerp = (isc_timermgr_t *)timermgr;
+ return (ISC_R_SUCCESS);
+ }
+#endif /* USE_SHARED_MANAGER */
+
+ manager = isc_mem_get(mctx, sizeof(*manager));
+ if (manager == NULL)
+ return (ISC_R_NOMEMORY);
+
+ manager->common.impmagic = TIMER_MANAGER_MAGIC;
+ manager->common.magic = ISCAPI_TIMERMGR_MAGIC;
+ manager->common.methods = (isc_timermgrmethods_t *)&timermgrmethods;
+ manager->mctx = NULL;
+ manager->done = false;
+ INIT_LIST(manager->timers);
+ manager->nscheduled = 0;
+ isc_time_settoepoch(&manager->due);
+ manager->heap = NULL;
+ result = isc_heap_create(mctx, sooner, set_index, 0, &manager->heap);
+ if (result != ISC_R_SUCCESS) {
+ INSIST(result == ISC_R_NOMEMORY);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ return (ISC_R_NOMEMORY);
+ }
+ result = isc_mutex_init(&manager->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_heap_destroy(&manager->heap);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ return (result);
+ }
+ isc_mem_attach(mctx, &manager->mctx);
+#ifdef USE_TIMER_THREAD
+ if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) {
+ isc_mem_detach(&manager->mctx);
+ DESTROYLOCK(&manager->lock);
+ isc_heap_destroy(&manager->heap);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ return (ISC_R_UNEXPECTED);
+ }
+ if (isc_thread_create(run, manager, &manager->thread) !=
+ ISC_R_SUCCESS) {
+ isc_mem_detach(&manager->mctx);
+ (void)isc_condition_destroy(&manager->wakeup);
+ DESTROYLOCK(&manager->lock);
+ isc_heap_destroy(&manager->heap);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_thread_create() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ return (ISC_R_UNEXPECTED);
+ }
+ isc_thread_setname(manager->thread, "isc-timer");
+#endif
+#ifdef USE_SHARED_MANAGER
+ manager->refs = 1;
+ timermgr = manager;
+#endif /* USE_SHARED_MANAGER */
+
+ *managerp = (isc_timermgr_t *)manager;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_timermgr_poke(isc_timermgr_t *manager0) {
+#ifdef USE_TIMER_THREAD
+ isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
+
+ REQUIRE(VALID_MANAGER(manager));
+
+ SIGNAL(&manager->wakeup);
+#else
+ UNUSED(manager0);
+#endif
+}
+
+void
+isc__timermgr_destroy(isc_timermgr_t **managerp) {
+ isc__timermgr_t *manager;
+ isc_mem_t *mctx;
+
+ /*
+ * Destroy a timer manager.
+ */
+
+ REQUIRE(managerp != NULL);
+ manager = (isc__timermgr_t *)*managerp;
+ REQUIRE(VALID_MANAGER(manager));
+
+ LOCK(&manager->lock);
+
+#ifdef USE_SHARED_MANAGER
+ manager->refs--;
+ if (manager->refs > 0) {
+ UNLOCK(&manager->lock);
+ *managerp = NULL;
+ return;
+ }
+ timermgr = NULL;
+#endif /* USE_SHARED_MANAGER */
+
+#ifndef USE_TIMER_THREAD
+ isc__timermgr_dispatch((isc_timermgr_t *)manager);
+#endif
+
+ REQUIRE(EMPTY(manager->timers));
+ manager->done = true;
+
+#ifdef USE_TIMER_THREAD
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+ ISC_MSG_SIGNALDESTROY, "signal (destroy)"));
+ SIGNAL(&manager->wakeup);
+#endif /* USE_TIMER_THREAD */
+
+ UNLOCK(&manager->lock);
+
+#ifdef USE_TIMER_THREAD
+ /*
+ * Wait for thread to exit.
+ */
+ if (isc_thread_join(manager->thread, NULL) != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_thread_join() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+#endif /* USE_TIMER_THREAD */
+
+ /*
+ * Clean up.
+ */
+#ifdef USE_TIMER_THREAD
+ (void)isc_condition_destroy(&manager->wakeup);
+#endif /* USE_TIMER_THREAD */
+ DESTROYLOCK(&manager->lock);
+ isc_heap_destroy(&manager->heap);
+ manager->common.impmagic = 0;
+ manager->common.magic = 0;
+ mctx = manager->mctx;
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ isc_mem_detach(&mctx);
+
+ *managerp = NULL;
+
+#ifdef USE_SHARED_MANAGER
+ timermgr = NULL;
+#endif
+}
+
+#ifndef USE_TIMER_THREAD
+isc_result_t
+isc__timermgr_nextevent(isc_timermgr_t *manager0, isc_time_t *when) {
+ isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
+
+#ifdef USE_SHARED_MANAGER
+ if (manager == NULL)
+ manager = timermgr;
+#endif
+ if (manager == NULL || manager->nscheduled == 0)
+ return (ISC_R_NOTFOUND);
+ *when = manager->due;
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc__timermgr_dispatch(isc_timermgr_t *manager0) {
+ isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
+ isc_time_t now;
+
+#ifdef USE_SHARED_MANAGER
+ if (manager == NULL)
+ manager = timermgr;
+#endif
+ if (manager == NULL)
+ return;
+ TIME_NOW(&now);
+ dispatch(manager, &now);
+}
+#endif /* USE_TIMER_THREAD */
+
+isc_result_t
+isc__timer_register(void) {
+ return (isc_timer_register(isc__timermgr_create));
+}
+
+static isc_mutex_t createlock;
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_timermgrcreatefunc_t timermgr_createfunc = NULL;
+
+static void
+initialize(void) {
+ RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_timer_register(isc_timermgrcreatefunc_t createfunc) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
+
+ LOCK(&createlock);
+ if (timermgr_createfunc == NULL)
+ timermgr_createfunc = createfunc;
+ else
+ result = ISC_R_EXISTS;
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+isc_result_t
+isc_timermgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
+ isc_timermgr_t **managerp)
+{
+ isc_result_t result;
+
+ LOCK(&createlock);
+
+ REQUIRE(timermgr_createfunc != NULL);
+ result = (*timermgr_createfunc)(mctx, managerp);
+
+ UNLOCK(&createlock);
+
+ if (result == ISC_R_SUCCESS)
+ isc_appctx_settimermgr(actx, *managerp);
+
+ return (result);
+}
+
+isc_result_t
+isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) {
+ isc_result_t result;
+
+ if (isc_bind9)
+ return (isc__timermgr_create(mctx, managerp));
+
+ LOCK(&createlock);
+
+ REQUIRE(timermgr_createfunc != NULL);
+ result = (*timermgr_createfunc)(mctx, managerp);
+
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+void
+isc_timermgr_destroy(isc_timermgr_t **managerp) {
+ REQUIRE(*managerp != NULL && ISCAPI_TIMERMGR_VALID(*managerp));
+
+ if (isc_bind9)
+ isc__timermgr_destroy(managerp);
+ else
+ (*managerp)->methods->destroy(managerp);
+
+ ENSURE(*managerp == NULL);
+}
+
+isc_result_t
+isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type,
+ const isc_time_t *expires, const isc_interval_t *interval,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_timer_t **timerp)
+{
+ REQUIRE(ISCAPI_TIMERMGR_VALID(manager));
+
+ if (isc_bind9)
+ return (isc__timer_create(manager, type, expires, interval,
+ task, action, arg, timerp));
+
+ return (manager->methods->timercreate(manager, type, expires,
+ interval, task, action, arg,
+ timerp));
+}
+
+void
+isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) {
+ REQUIRE(ISCAPI_TIMER_VALID(timer));
+ REQUIRE(timerp != NULL && *timerp == NULL);
+
+ if (isc_bind9)
+ isc__timer_attach(timer, timerp);
+ else
+ timer->methods->attach(timer, timerp);
+
+ ENSURE(*timerp == timer);
+}
+
+void
+isc_timer_detach(isc_timer_t **timerp) {
+ REQUIRE(timerp != NULL && ISCAPI_TIMER_VALID(*timerp));
+
+ if (isc_bind9)
+ isc__timer_detach(timerp);
+ else
+ (*timerp)->methods->detach(timerp);
+
+ ENSURE(*timerp == NULL);
+}
+
+isc_result_t
+isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
+ const isc_time_t *expires, const isc_interval_t *interval,
+ bool purge)
+{
+ REQUIRE(ISCAPI_TIMER_VALID(timer));
+
+ if (isc_bind9)
+ return (isc__timer_reset(timer, type, expires,
+ interval, purge));
+
+ return (timer->methods->reset(timer, type, expires, interval, purge));
+}
+
+isc_result_t
+isc_timer_touch(isc_timer_t *timer) {
+ REQUIRE(ISCAPI_TIMER_VALID(timer));
+
+ if (isc_bind9)
+ return (isc__timer_touch(timer));
+
+ return (timer->methods->touch(timer));
+}
diff --git a/lib/isc/timer_p.h b/lib/isc/timer_p.h
new file mode 100644
index 0000000..815f611
--- /dev/null
+++ b/lib/isc/timer_p.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id: timer_p.h,v 1.12 2009/09/02 23:48:02 tbox Exp $ */
+
+#ifndef ISC_TIMER_P_H
+#define ISC_TIMER_P_H
+
+/*! \file */
+
+isc_result_t
+isc__timermgr_nextevent(isc_timermgr_t *timermgr, isc_time_t *when);
+
+void
+isc__timermgr_dispatch(isc_timermgr_t *timermgr);
+
+#endif /* ISC_TIMER_P_H */
diff --git a/lib/isc/tm.c b/lib/isc/tm.c
new file mode 100644
index 0000000..c390396
--- /dev/null
+++ b/lib/isc/tm.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*-
+ * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code was contributed to The NetBSD Foundation by Klaus Klein.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include <isc/tm.h>
+#include <isc/util.h>
+
+/*
+ * Portable conversion routines for struct tm, replacing
+ * timegm() and strptime(), which are not available on all
+ * platforms and don't always behave the same way when they
+ * are.
+ */
+
+/*
+ * We do not implement alternate representations. However, we always
+ * check whether a given modifier is allowed for a certain conversion.
+ */
+#define ALT_E 0x01
+#define ALT_O 0x02
+#define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
+
+#ifndef TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif
+
+static const char *day[7] = {
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday"
+};
+static const char *abday[7] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+static const char *mon[12] = {
+ "January", "February", "March", "April", "May", "June", "July",
+ "August", "September", "October", "November", "December"
+};
+static const char *abmon[12] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+static const char *am_pm[2] = {
+ "AM", "PM"
+};
+
+static int
+conv_num(const char **buf, int *dest, int llim, int ulim) {
+ int result = 0;
+
+ /* The limit also determines the number of valid digits. */
+ int rulim = ulim;
+
+ if (**buf < '0' || **buf > '9')
+ return (0);
+
+ do {
+ result *= 10;
+ result += *(*buf)++ - '0';
+ rulim /= 10;
+ } while ((result * 10 <= ulim) &&
+ rulim && **buf >= '0' && **buf <= '9');
+
+ if (result < llim || result > ulim)
+ return (0);
+
+ *dest = result;
+ return (1);
+}
+
+time_t
+isc_tm_timegm(struct tm *tm) {
+ time_t ret;
+ int i, yday = 0, leapday;
+ int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 };
+
+ leapday = ((((tm->tm_year + 1900 ) % 4) == 0 &&
+ ((tm->tm_year + 1900 ) % 100) != 0) ||
+ ((tm->tm_year + 1900 ) % 400) == 0) ? 1 : 0;
+ mdays[1] += leapday;
+
+ yday = tm->tm_mday - 1;
+ for (i = 1; i <= tm->tm_mon; i++)
+ yday += mdays[i - 1];
+ ret = tm->tm_sec +
+ (60 * tm->tm_min) +
+ (3600 * tm->tm_hour) +
+ (86400 * (yday +
+ ((tm->tm_year - 70) * 365) +
+ ((tm->tm_year - 69) / 4) -
+ ((tm->tm_year - 1) / 100) +
+ ((tm->tm_year + 299) / 400)));
+ return (ret);
+}
+
+char *
+isc_tm_strptime(const char *buf, const char *fmt, struct tm *tm) {
+ char c, *ret;
+ const char *bp;
+ size_t len = 0;
+ int alt_format, i, split_year = 0;
+
+ REQUIRE(buf != NULL);
+ REQUIRE(fmt != NULL);
+ REQUIRE(tm != NULL);
+
+ memset(tm, 0, sizeof(struct tm));
+
+ bp = buf;
+
+ while ((c = *fmt) != '\0') {
+ /* Clear `alternate' modifier prior to new conversion. */
+ alt_format = 0;
+
+ /* Eat up white-space. */
+ if (isspace((unsigned char) c)) {
+ while (isspace((unsigned char) *bp))
+ bp++;
+
+ fmt++;
+ continue;
+ }
+
+ if ((c = *fmt++) != '%')
+ goto literal;
+
+
+again: switch (c = *fmt++) {
+ case '%': /* "%%" is converted to "%". */
+literal:
+ if (c != *bp++)
+ return (0);
+ break;
+
+ /*
+ * "Alternative" modifiers. Just set the appropriate flag
+ * and start over again.
+ */
+ case 'E': /* "%E?" alternative conversion modifier. */
+ LEGAL_ALT(0);
+ alt_format |= ALT_E;
+ goto again;
+
+ case 'O': /* "%O?" alternative conversion modifier. */
+ LEGAL_ALT(0);
+ alt_format |= ALT_O;
+ goto again;
+
+ /*
+ * "Complex" conversion rules, implemented through recursion.
+ */
+ case 'c': /* Date and time, using the locale's format. */
+ LEGAL_ALT(ALT_E);
+ if (!(bp = isc_tm_strptime(bp, "%x %X", tm)))
+ return (0);
+ break;
+
+ case 'D': /* The date as "%m/%d/%y". */
+ LEGAL_ALT(0);
+ if (!(bp = isc_tm_strptime(bp, "%m/%d/%y", tm)))
+ return (0);
+ break;
+
+ case 'R': /* The time as "%H:%M". */
+ LEGAL_ALT(0);
+ if (!(bp = isc_tm_strptime(bp, "%H:%M", tm)))
+ return (0);
+ break;
+
+ case 'r': /* The time in 12-hour clock representation. */
+ LEGAL_ALT(0);
+ if (!(bp = isc_tm_strptime(bp, "%I:%M:%S %p", tm)))
+ return (0);
+ break;
+
+ case 'T': /* The time as "%H:%M:%S". */
+ LEGAL_ALT(0);
+ if (!(bp = isc_tm_strptime(bp, "%H:%M:%S", tm)))
+ return (0);
+ break;
+
+ case 'X': /* The time, using the locale's format. */
+ LEGAL_ALT(ALT_E);
+ if (!(bp = isc_tm_strptime(bp, "%H:%M:%S", tm)))
+ return (0);
+ break;
+
+ case 'x': /* The date, using the locale's format. */
+ LEGAL_ALT(ALT_E);
+ if (!(bp = isc_tm_strptime(bp, "%m/%d/%y", tm)))
+ return (0);
+ break;
+
+ /*
+ * "Elementary" conversion rules.
+ */
+ case 'A': /* The day of week, using the locale's form. */
+ case 'a':
+ LEGAL_ALT(0);
+ for (i = 0; i < 7; i++) {
+ /* Full name. */
+ len = strlen(day[i]);
+ if (strncasecmp(day[i], bp, len) == 0)
+ break;
+
+ /* Abbreviated name. */
+ len = strlen(abday[i]);
+ if (strncasecmp(abday[i], bp, len) == 0)
+ break;
+ }
+
+ /* Nothing matched. */
+ if (i == 7)
+ return (0);
+
+ tm->tm_wday = i;
+ bp += len;
+ break;
+
+ case 'B': /* The month, using the locale's form. */
+ case 'b':
+ case 'h':
+ LEGAL_ALT(0);
+ for (i = 0; i < 12; i++) {
+ /* Full name. */
+ len = strlen(mon[i]);
+ if (strncasecmp(mon[i], bp, len) == 0)
+ break;
+
+ /* Abbreviated name. */
+ len = strlen(abmon[i]);
+ if (strncasecmp(abmon[i], bp, len) == 0)
+ break;
+ }
+
+ /* Nothing matched. */
+ if (i == 12)
+ return (0);
+
+ tm->tm_mon = i;
+ bp += len;
+ break;
+
+ case 'C': /* The century number. */
+ LEGAL_ALT(ALT_E);
+ if (!(conv_num(&bp, &i, 0, 99)))
+ return (0);
+
+ if (split_year) {
+ tm->tm_year = (tm->tm_year % 100) + (i * 100);
+ } else {
+ tm->tm_year = i * 100;
+ split_year = 1;
+ }
+ break;
+
+ case 'd': /* The day of month. */
+ case 'e':
+ LEGAL_ALT(ALT_O);
+ if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
+ return (0);
+ break;
+
+ case 'k': /* The hour (24-hour clock representation). */
+ LEGAL_ALT(0);
+ /* FALLTHROUGH */
+ case 'H':
+ LEGAL_ALT(ALT_O);
+ if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
+ return (0);
+ break;
+
+ case 'l': /* The hour (12-hour clock representation). */
+ LEGAL_ALT(0);
+ /* FALLTHROUGH */
+ case 'I':
+ LEGAL_ALT(ALT_O);
+ if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
+ return (0);
+ if (tm->tm_hour == 12)
+ tm->tm_hour = 0;
+ break;
+
+ case 'j': /* The day of year. */
+ LEGAL_ALT(0);
+ if (!(conv_num(&bp, &i, 1, 366)))
+ return (0);
+ tm->tm_yday = i - 1;
+ break;
+
+ case 'M': /* The minute. */
+ LEGAL_ALT(ALT_O);
+ if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
+ return (0);
+ break;
+
+ case 'm': /* The month. */
+ LEGAL_ALT(ALT_O);
+ if (!(conv_num(&bp, &i, 1, 12)))
+ return (0);
+ tm->tm_mon = i - 1;
+ break;
+
+ case 'p': /* The locale's equivalent of AM/PM. */
+ LEGAL_ALT(0);
+ /* AM? */
+ if (strcasecmp(am_pm[0], bp) == 0) {
+ if (tm->tm_hour > 11)
+ return (0);
+
+ bp += strlen(am_pm[0]);
+ break;
+ }
+ /* PM? */
+ else if (strcasecmp(am_pm[1], bp) == 0) {
+ if (tm->tm_hour > 11)
+ return (0);
+
+ tm->tm_hour += 12;
+ bp += strlen(am_pm[1]);
+ break;
+ }
+
+ /* Nothing matched. */
+ return (0);
+
+ case 'S': /* The seconds. */
+ LEGAL_ALT(ALT_O);
+ if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
+ return (0);
+ break;
+
+ case 'U': /* The week of year, beginning on sunday. */
+ case 'W': /* The week of year, beginning on monday. */
+ LEGAL_ALT(ALT_O);
+ /*
+ * XXX This is bogus, as we can not assume any valid
+ * information present in the tm structure at this
+ * point to calculate a real value, so just check the
+ * range for now.
+ */
+ if (!(conv_num(&bp, &i, 0, 53)))
+ return (0);
+ break;
+
+ case 'w': /* The day of week, beginning on sunday. */
+ LEGAL_ALT(ALT_O);
+ if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
+ return (0);
+ break;
+
+ case 'Y': /* The year. */
+ LEGAL_ALT(ALT_E);
+ if (!(conv_num(&bp, &i, 0, 9999)))
+ return (0);
+
+ tm->tm_year = i - TM_YEAR_BASE;
+ break;
+
+ case 'y': /* The year within 100 years of the epoch. */
+ LEGAL_ALT(ALT_E | ALT_O);
+ if (!(conv_num(&bp, &i, 0, 99)))
+ return (0);
+
+ if (split_year) {
+ tm->tm_year = ((tm->tm_year / 100) * 100) + i;
+ break;
+ }
+ split_year = 1;
+ if (i <= 68)
+ tm->tm_year = i + 2000 - TM_YEAR_BASE;
+ else
+ tm->tm_year = i + 1900 - TM_YEAR_BASE;
+ break;
+
+ /*
+ * Miscellaneous conversions.
+ */
+ case 'n': /* Any kind of white-space. */
+ case 't':
+ LEGAL_ALT(0);
+ while (isspace((unsigned char) *bp))
+ bp++;
+ break;
+
+
+ default: /* Unknown/unsupported conversion. */
+ return (0);
+ }
+
+
+ }
+
+ /* LINTED functional specification */
+ DE_CONST(bp, ret);
+ return (ret);
+}
diff --git a/lib/isc/unix/Makefile.in b/lib/isc/unix/Makefile.in
new file mode 100644
index 0000000..bdd7bfd
--- /dev/null
+++ b/lib/isc/unix/Makefile.in
@@ -0,0 +1,44 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+CINCLUDES = -I${srcdir}/include \
+ -I${srcdir}/../@ISC_THREAD_DIR@/include \
+ -I../include \
+ -I${srcdir}/../include \
+ -I${srcdir}/.. @ISC_OPENSSL_INC@
+
+CDEFINES = @CRYPTO@
+CWARNINGS =
+
+# Alphabetically
+OBJS = @ISC_IPV6_O@ @ISC_PK11_API_O@ \
+ app.@O@ dir.@O@ entropy.@O@ errno.@O@ errno2result.@O@ \
+ file.@O@ fsaccess.@O@ interfaceiter.@O@ \
+ keyboard.@O@ meminfo.@O@ \
+ net.@O@ os.@O@ resource.@O@ socket.@O@ stdio.@O@ stdtime.@O@ \
+ strerror.@O@ syslog.@O@ time.@O@
+
+# Alphabetically
+SRCS = @ISC_IPV6_C@ @ISC_PK11_API_C@ \
+ app.c dir.c entropy.c errno.c errno2result.c \
+ file.c fsaccess.c interfaceiter.c keyboard.c meminfo.c \
+ net.c os.c resource.c socket.c stdio.c stdtime.c \
+ strerror.c syslog.c time.c
+
+SUBDIRS = include
+TARGETS = ${OBJS}
+
+@BIND9_MAKE_RULES@
+
+interfaceiter.@O@: interfaceiter.c ifiter_ioctl.c ifiter_sysctl.c ifiter_getifaddrs.c
+
diff --git a/lib/isc/unix/app.c b/lib/isc/unix/app.c
new file mode 100644
index 0000000..7e5a0ee
--- /dev/null
+++ b/lib/isc/unix/app.c
@@ -0,0 +1,1038 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/time.h>
+#ifdef HAVE_EPOLL
+#include <sys/epoll.h>
+#endif
+
+#include <isc/app.h>
+#include <isc/condition.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/event.h>
+#include <isc/platform.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#ifdef ISC_PLATFORM_USETHREADS
+#include <pthread.h>
+#endif
+
+/*%
+ * For BIND9 internal applications built with threads, we use a single app
+ * context and let multiple worker, I/O, timer threads do actual jobs.
+ * For other cases (including BIND9 built without threads) an app context acts
+ * as an event loop dispatching various events.
+ */
+#ifndef ISC_PLATFORM_USETHREADS
+#include "../timer_p.h"
+#include "../task_p.h"
+#include "socket_p.h"
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifdef ISC_PLATFORM_USETHREADS
+static pthread_t blockedthread;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/*%
+ * The following are intended for internal use (indicated by "isc__"
+ * prefix) but are not declared as static, allowing direct access from
+ * unit tests etc.
+ */
+isc_result_t isc__app_start(void);
+isc_result_t isc__app_ctxstart(isc_appctx_t *ctx);
+isc_result_t isc__app_onrun(isc_mem_t *mctx, isc_task_t *task,
+ isc_taskaction_t action, void *arg);
+isc_result_t isc__app_ctxrun(isc_appctx_t *ctx);
+isc_result_t isc__app_run(void);
+isc_result_t isc__app_ctxshutdown(isc_appctx_t *ctx);
+isc_result_t isc__app_shutdown(void);
+isc_result_t isc__app_reload(void);
+isc_result_t isc__app_ctxsuspend(isc_appctx_t *ctx);
+void isc__app_ctxfinish(isc_appctx_t *ctx);
+void isc__app_finish(void);
+void isc__app_block(void);
+void isc__app_unblock(void);
+isc_result_t isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp);
+void isc__appctx_destroy(isc_appctx_t **ctxp);
+void isc__appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr);
+void isc__appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr);
+void isc__appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr);
+isc_result_t isc__app_ctxonrun(isc_appctx_t *ctx, isc_mem_t *mctx,
+ isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+
+/*
+ * The application context of this module. This implementation actually
+ * doesn't use it. (This may change in the future).
+ */
+#define APPCTX_MAGIC ISC_MAGIC('A', 'p', 'c', 'x')
+#define VALID_APPCTX(c) ISC_MAGIC_VALID(c, APPCTX_MAGIC)
+
+typedef struct isc__appctx {
+ isc_appctx_t common;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ isc_eventlist_t on_run;
+ bool shutdown_requested;
+ bool running;
+
+ /*!
+ * We assume that 'want_shutdown' can be read and written atomically.
+ */
+ bool want_shutdown;
+ /*
+ * We assume that 'want_reload' can be read and written atomically.
+ */
+ bool want_reload;
+
+ bool blocked;
+
+ isc_taskmgr_t *taskmgr;
+ isc_socketmgr_t *socketmgr;
+ isc_timermgr_t *timermgr;
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_mutex_t readylock;
+ isc_condition_t ready;
+#endif /* ISC_PLATFORM_USETHREADS */
+} isc__appctx_t;
+
+static isc__appctx_t isc_g_appctx;
+
+static struct {
+ isc_appmethods_t methods;
+
+ /*%
+ * The following are defined just for avoiding unused static functions.
+ */
+ void *run, *shutdown, *start, *reload, *finish, *block, *unblock;
+} appmethods = {
+ {
+ isc__appctx_destroy,
+ isc__app_ctxstart,
+ isc__app_ctxrun,
+ isc__app_ctxsuspend,
+ isc__app_ctxshutdown,
+ isc__app_ctxfinish,
+ isc__appctx_settaskmgr,
+ isc__appctx_setsocketmgr,
+ isc__appctx_settimermgr,
+ isc__app_ctxonrun
+ },
+ (void *)isc__app_run,
+ (void *)isc__app_shutdown,
+ (void *)isc__app_start,
+ (void *)isc__app_reload,
+ (void *)isc__app_finish,
+ (void *)isc__app_block,
+ (void *)isc__app_unblock
+};
+
+#ifdef HAVE_LINUXTHREADS
+/*!
+ * Linux has sigwait(), but it appears to prevent signal handlers from
+ * running, even if they're not in the set being waited for. This makes
+ * it impossible to get the default actions for SIGILL, SIGSEGV, etc.
+ * Instead of messing with it, we just use sigsuspend() instead.
+ */
+#undef HAVE_SIGWAIT
+/*!
+ * We need to remember which thread is the main thread...
+ */
+static pthread_t main_thread;
+#endif
+
+#ifndef HAVE_SIGWAIT
+static void
+exit_action(int arg) {
+ UNUSED(arg);
+ isc_g_appctx.want_shutdown = true;
+}
+
+static void
+reload_action(int arg) {
+ UNUSED(arg);
+ isc_g_appctx.want_reload = true;
+}
+#endif
+
+static isc_result_t
+handle_signal(int sig, void (*handler)(int)) {
+ struct sigaction sa;
+ char strbuf[ISC_STRERRORSIZE];
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handler;
+
+ if (sigfillset(&sa.sa_mask) != 0 ||
+ sigaction(sig, &sa, NULL) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_APP,
+ ISC_MSG_SIGNALSETUP,
+ "handle_signal() %d setup: %s"),
+ sig, strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__app_ctxstart(isc_appctx_t *ctx0) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+ isc_result_t result;
+ int presult;
+ sigset_t sset;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ /*
+ * Start an ISC library application.
+ */
+
+#ifdef NEED_PTHREAD_INIT
+ /*
+ * BSDI 3.1 seg faults in pthread_sigmask() if we don't do this.
+ */
+ presult = pthread_init();
+ if (presult != 0) {
+ isc__strerror(presult, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_start() pthread_init: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+#endif
+
+#ifdef ISC_PLATFORM_USETHREADS
+#ifdef HAVE_LINUXTHREADS
+ main_thread = pthread_self();
+#endif /* HAVE_LINUXTHREADS */
+
+ result = isc_mutex_init(&ctx->readylock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = isc_condition_init(&ctx->ready);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_rlock;
+
+ result = isc_mutex_init(&ctx->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_rcond;
+#else /* ISC_PLATFORM_USETHREADS */
+ result = isc_mutex_init(&ctx->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ ISC_LIST_INIT(ctx->on_run);
+
+ ctx->shutdown_requested = false;
+ ctx->running = false;
+ ctx->want_shutdown = false;
+ ctx->want_reload = false;
+ ctx->blocked = false;
+
+#ifndef HAVE_SIGWAIT
+ /*
+ * Install do-nothing handlers for SIGINT and SIGTERM.
+ *
+ * We install them now because BSDI 3.1 won't block
+ * the default actions, regardless of what we do with
+ * pthread_sigmask().
+ */
+ result = handle_signal(SIGINT, exit_action);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = handle_signal(SIGTERM, exit_action);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+#endif
+
+ /*
+ * Always ignore SIGPIPE.
+ */
+ result = handle_signal(SIGPIPE, SIG_IGN);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /*
+ * On Solaris 2, delivery of a signal whose action is SIG_IGN
+ * will not cause sigwait() to return. We may have inherited
+ * unexpected actions for SIGHUP, SIGINT, and SIGTERM from our parent
+ * process (e.g, Solaris cron). Set an action of SIG_DFL to make
+ * sure sigwait() works as expected. Only do this for SIGTERM and
+ * SIGINT if we don't have sigwait(), since a different handler is
+ * installed above.
+ */
+ result = handle_signal(SIGHUP, SIG_DFL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+#ifdef HAVE_SIGWAIT
+ result = handle_signal(SIGTERM, SIG_DFL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = handle_signal(SIGINT, SIG_DFL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+#endif
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Block SIGHUP, SIGINT, SIGTERM.
+ *
+ * If isc_app_start() is called from the main thread before any other
+ * threads have been created, then the pthread_sigmask() call below
+ * will result in all threads having SIGHUP, SIGINT and SIGTERM
+ * blocked by default, ensuring that only the thread that calls
+ * sigwait() for them will get those signals.
+ */
+ if (sigemptyset(&sset) != 0 ||
+ sigaddset(&sset, SIGHUP) != 0 ||
+ sigaddset(&sset, SIGINT) != 0 ||
+ sigaddset(&sset, SIGTERM) != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_start() sigsetops: %s", strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+ presult = pthread_sigmask(SIG_BLOCK, &sset, NULL);
+ if (presult != 0) {
+ isc__strerror(presult, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_start() pthread_sigmask: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+#else /* ISC_PLATFORM_USETHREADS */
+ /*
+ * Unblock SIGHUP, SIGINT, SIGTERM.
+ *
+ * If we're not using threads, we need to make sure that SIGHUP,
+ * SIGINT and SIGTERM are not inherited as blocked from the parent
+ * process.
+ */
+ if (sigemptyset(&sset) != 0 ||
+ sigaddset(&sset, SIGHUP) != 0 ||
+ sigaddset(&sset, SIGINT) != 0 ||
+ sigaddset(&sset, SIGTERM) != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_start() sigsetops: %s", strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+ presult = sigprocmask(SIG_UNBLOCK, &sset, NULL);
+ if (presult != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_start() sigprocmask: %s", strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+#ifdef ISC_PLATFORM_USETHREADS
+ cleanup_rcond:
+ (void)isc_condition_destroy(&ctx->ready);
+
+ cleanup_rlock:
+ (void)isc_mutex_destroy(&ctx->readylock);
+#endif /* ISC_PLATFORM_USETHREADS */
+ return (result);
+}
+
+isc_result_t
+isc__app_start(void) {
+ isc_g_appctx.common.impmagic = APPCTX_MAGIC;
+ isc_g_appctx.common.magic = ISCAPI_APPCTX_MAGIC;
+ isc_g_appctx.common.methods = &appmethods.methods;
+ isc_g_appctx.mctx = NULL;
+ /* The remaining members will be initialized in ctxstart() */
+
+ return (isc__app_ctxstart((isc_appctx_t *)&isc_g_appctx));
+}
+
+isc_result_t
+isc__app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
+ void *arg)
+{
+ return (isc__app_ctxonrun((isc_appctx_t *)&isc_g_appctx, mctx,
+ task, action, arg));
+}
+
+isc_result_t
+isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task,
+ isc_taskaction_t action, void *arg)
+{
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+ isc_event_t *event;
+ isc_task_t *cloned_task = NULL;
+ isc_result_t result;
+
+ LOCK(&ctx->lock);
+
+ if (ctx->running) {
+ result = ISC_R_ALREADYRUNNING;
+ goto unlock;
+ }
+
+ /*
+ * Note that we store the task to which we're going to send the event
+ * in the event's "sender" field.
+ */
+ isc_task_attach(task, &cloned_task);
+ event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN,
+ action, arg, sizeof(*event));
+ if (event == NULL) {
+ isc_task_detach(&cloned_task);
+ result = ISC_R_NOMEMORY;
+ goto unlock;
+ }
+
+ ISC_LIST_APPEND(ctx->on_run, event, ev_link);
+
+ result = ISC_R_SUCCESS;
+
+ unlock:
+ UNLOCK(&ctx->lock);
+
+ return (result);
+}
+
+#ifndef ISC_PLATFORM_USETHREADS
+/*!
+ * Event loop for nonthreaded programs.
+ */
+static isc_result_t
+evloop(isc__appctx_t *ctx) {
+ isc_result_t result;
+
+ while (!ctx->want_shutdown) {
+ int n;
+ isc_time_t when, now;
+ struct timeval tv, *tvp;
+ isc_socketwait_t *swait;
+ bool readytasks;
+ bool call_timer_dispatch = false;
+
+ /*
+ * Check the reload (or suspend) case first for exiting the
+ * loop as fast as possible in case:
+ * - the direct call to isc__taskmgr_dispatch() in
+ * isc__app_ctxrun() completes all the tasks so far,
+ * - there is thus currently no active task, and
+ * - there is a timer event
+ */
+ if (ctx->want_reload) {
+ ctx->want_reload = false;
+ return (ISC_R_RELOAD);
+ }
+
+ readytasks = isc__taskmgr_ready(ctx->taskmgr);
+ if (readytasks) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ call_timer_dispatch = true;
+ } else {
+ result = isc__timermgr_nextevent(ctx->timermgr, &when);
+ if (result != ISC_R_SUCCESS)
+ tvp = NULL;
+ else {
+ uint64_t us;
+
+ TIME_NOW(&now);
+ us = isc_time_microdiff(&when, &now);
+ if (us == 0)
+ call_timer_dispatch = true;
+ tv.tv_sec = us / 1000000;
+ tv.tv_usec = us % 1000000;
+ tvp = &tv;
+ }
+ }
+
+ swait = NULL;
+ n = isc__socketmgr_waitevents(ctx->socketmgr, tvp, &swait);
+
+ if (n == 0 || call_timer_dispatch) {
+ /*
+ * We call isc__timermgr_dispatch() only when
+ * necessary, in order to reduce overhead. If the
+ * select() call indicates a timeout, we need the
+ * dispatch. Even if not, if we set the 0-timeout
+ * for the select() call, we need to check the timer
+ * events. In the 'readytasks' case, there may be no
+ * timeout event actually, but there is no other way
+ * to reduce the overhead.
+ * Note that we do not have to worry about the case
+ * where a new timer is inserted during the select()
+ * call, since this loop only runs in the non-thread
+ * mode.
+ */
+ isc__timermgr_dispatch(ctx->timermgr);
+ }
+ if (n > 0)
+ (void)isc__socketmgr_dispatch(ctx->socketmgr, swait);
+ (void)isc__taskmgr_dispatch(ctx->taskmgr);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This is a gross hack to support waiting for condition
+ * variables in nonthreaded programs in a limited way;
+ * see lib/isc/nothreads/include/isc/condition.h.
+ * We implement isc_condition_wait() by entering the
+ * event loop recursively until the want_shutdown flag
+ * is set by isc_condition_signal().
+ */
+
+/*!
+ * \brief True if we are currently executing in the recursive
+ * event loop.
+ */
+static bool in_recursive_evloop = false;
+
+/*!
+ * \brief True if we are exiting the event loop as the result of
+ * a call to isc_condition_signal() rather than a shutdown
+ * or reload.
+ */
+static bool signalled = false;
+
+isc_result_t
+isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp) {
+ isc_result_t result;
+
+ UNUSED(cp);
+ UNUSED(mp);
+
+ INSIST(!in_recursive_evloop);
+ in_recursive_evloop = true;
+
+ INSIST(*mp == 1); /* Mutex must be locked on entry. */
+ --*mp;
+
+ result = evloop(&isc_g_appctx);
+ if (result == ISC_R_RELOAD)
+ isc_g_appctx.want_reload = true;
+ if (signalled) {
+ isc_g_appctx.want_shutdown = false;
+ signalled = false;
+ }
+
+ ++*mp;
+ in_recursive_evloop = false;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__nothread_signal_hack(isc_condition_t *cp) {
+
+ UNUSED(cp);
+
+ INSIST(in_recursive_evloop);
+
+ isc_g_appctx.want_shutdown = true;
+ signalled = true;
+ return (ISC_R_SUCCESS);
+}
+#endif /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc__app_ctxrun(isc_appctx_t *ctx0) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+ int result;
+ isc_event_t *event, *next_event;
+ isc_task_t *task;
+#ifdef ISC_PLATFORM_USETHREADS
+ sigset_t sset;
+ char strbuf[ISC_STRERRORSIZE];
+#ifdef HAVE_SIGWAIT
+ int sig;
+#endif /* HAVE_SIGWAIT */
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+#ifdef HAVE_LINUXTHREADS
+ REQUIRE(main_thread == pthread_self());
+#endif
+
+ LOCK(&ctx->lock);
+
+ if (!ctx->running) {
+ ctx->running = true;
+
+ /*
+ * Post any on-run events (in FIFO order).
+ */
+ for (event = ISC_LIST_HEAD(ctx->on_run);
+ event != NULL;
+ event = next_event) {
+ next_event = ISC_LIST_NEXT(event, ev_link);
+ ISC_LIST_UNLINK(ctx->on_run, event, ev_link);
+ task = event->ev_sender;
+ event->ev_sender = NULL;
+ isc_task_sendanddetach(&task, &event);
+ }
+
+ }
+
+ UNLOCK(&ctx->lock);
+
+#ifndef ISC_PLATFORM_USETHREADS
+ if (isc_bind9 && ctx == &isc_g_appctx) {
+ result = handle_signal(SIGHUP, reload_action);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_SUCCESS);
+ }
+
+ (void) isc__taskmgr_dispatch(ctx->taskmgr);
+ result = evloop(ctx);
+ return (result);
+#else /* ISC_PLATFORM_USETHREADS */
+ /*
+ * BIND9 internal tools using multiple contexts do not
+ * rely on signal.
+ */
+ if (isc_bind9 && ctx != &isc_g_appctx)
+ return (ISC_R_SUCCESS);
+
+ /*
+ * There is no danger if isc_app_shutdown() is called before we
+ * wait for signals. Signals are blocked, so any such signal will
+ * simply be made pending and we will get it when we call
+ * sigwait().
+ */
+ while (!ctx->want_shutdown) {
+#ifdef HAVE_SIGWAIT
+ if (isc_bind9) {
+ /*
+ * BIND9 internal; single context:
+ * Wait for SIGHUP, SIGINT, or SIGTERM.
+ */
+ if (sigemptyset(&sset) != 0 ||
+ sigaddset(&sset, SIGHUP) != 0 ||
+ sigaddset(&sset, SIGINT) != 0 ||
+ sigaddset(&sset, SIGTERM) != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_run() sigsetops: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+
+#ifndef HAVE_UNIXWARE_SIGWAIT
+ result = sigwait(&sset, &sig);
+ if (result == 0) {
+ if (sig == SIGINT || sig == SIGTERM)
+ ctx->want_shutdown = true;
+ else if (sig == SIGHUP)
+ ctx->want_reload = true;
+ }
+
+#else /* Using UnixWare sigwait semantics. */
+ sig = sigwait(&sset);
+ if (sig >= 0) {
+ if (sig == SIGINT || sig == SIGTERM)
+ ctx->want_shutdown = true;
+ else if (sig == SIGHUP)
+ ctx->want_reload = true;
+ }
+#endif /* HAVE_UNIXWARE_SIGWAIT */
+ } else {
+ /*
+ * External, or BIND9 using multiple contexts:
+ * wait until woken up.
+ */
+ LOCK(&ctx->readylock);
+ if (ctx->want_shutdown) {
+ /* shutdown() won the race. */
+ UNLOCK(&ctx->readylock);
+ break;
+ }
+ if (!ctx->want_reload)
+ WAIT(&ctx->ready, &ctx->readylock);
+ UNLOCK(&ctx->readylock);
+ }
+#else /* Don't have sigwait(). */
+ if (isc_bind9) {
+ /*
+ * BIND9 internal; single context:
+ * Install a signal handler for SIGHUP, then wait for
+ * all signals.
+ */
+ result = handle_signal(SIGHUP, reload_action);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_SUCCESS);
+
+ if (sigemptyset(&sset) != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_run() sigsetops: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+#ifdef HAVE_GPERFTOOLS_PROFILER
+ if (sigaddset(&sset, SIGALRM) != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_run() sigsetops: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+#endif
+ (void)sigsuspend(&sset);
+ } else {
+ /*
+ * External, or BIND9 using multiple contexts:
+ * wait until woken up.
+ */
+ LOCK(&ctx->readylock);
+ if (ctx->want_shutdown) {
+ /* shutdown() won the race. */
+ UNLOCK(&ctx->readylock);
+ break;
+ }
+ if (!ctx->want_reload)
+ WAIT(&ctx->ready, &ctx->readylock);
+ UNLOCK(&ctx->readylock);
+ }
+#endif /* HAVE_SIGWAIT */
+
+ if (ctx->want_reload) {
+ ctx->want_reload = false;
+ return (ISC_R_RELOAD);
+ }
+
+ if (ctx->want_shutdown && ctx->blocked)
+ exit(1);
+ }
+
+ return (ISC_R_SUCCESS);
+#endif /* ISC_PLATFORM_USETHREADS */
+}
+
+isc_result_t
+isc__app_run(void) {
+ return (isc__app_ctxrun((isc_appctx_t *)&isc_g_appctx));
+}
+
+isc_result_t
+isc__app_ctxshutdown(isc_appctx_t *ctx0) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+ bool want_kill = true;
+#ifdef ISC_PLATFORM_USETHREADS
+ char strbuf[ISC_STRERRORSIZE];
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ LOCK(&ctx->lock);
+
+ REQUIRE(ctx->running);
+
+ if (ctx->shutdown_requested)
+ want_kill = false;
+ else
+ ctx->shutdown_requested = true;
+
+ UNLOCK(&ctx->lock);
+
+ if (want_kill) {
+ if (isc_bind9 && ctx != &isc_g_appctx)
+ /* BIND9 internal, but using multiple contexts */
+ ctx->want_shutdown = true;
+ else {
+#ifndef ISC_PLATFORM_USETHREADS
+ ctx->want_shutdown = true;
+#else /* ISC_PLATFORM_USETHREADS */
+#ifdef HAVE_LINUXTHREADS
+ if (isc_bind9) {
+ /* BIND9 internal, single context */
+ int result;
+
+ result = pthread_kill(main_thread, SIGTERM);
+ if (result != 0) {
+ isc__strerror(result,
+ strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_shutdown() "
+ "pthread_kill: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+#else
+ if (isc_bind9) {
+ /* BIND9 internal, single context */
+ if (kill(getpid(), SIGTERM) < 0) {
+ isc__strerror(errno,
+ strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_shutdown() "
+ "kill: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+#endif /* HAVE_LINUXTHREADS */
+ else {
+ /* External, multiple contexts */
+ LOCK(&ctx->readylock);
+ ctx->want_shutdown = true;
+ UNLOCK(&ctx->readylock);
+ SIGNAL(&ctx->ready);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__app_shutdown(void) {
+ return (isc__app_ctxshutdown((isc_appctx_t *)&isc_g_appctx));
+}
+
+isc_result_t
+isc__app_ctxsuspend(isc_appctx_t *ctx0) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+ bool want_kill = true;
+#ifdef ISC_PLATFORM_USETHREADS
+ char strbuf[ISC_STRERRORSIZE];
+#endif
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ LOCK(&ctx->lock);
+
+ REQUIRE(ctx->running);
+
+ /*
+ * Don't send the reload signal if we're shutting down.
+ */
+ if (ctx->shutdown_requested)
+ want_kill = false;
+
+ UNLOCK(&ctx->lock);
+
+ if (want_kill) {
+ if (isc_bind9 && ctx != &isc_g_appctx)
+ /* BIND9 internal, but using multiple contexts */
+ ctx->want_reload = true;
+ else {
+#ifndef ISC_PLATFORM_USETHREADS
+ ctx->want_reload = true;
+#else /* ISC_PLATFORM_USETHREADS */
+#ifdef HAVE_LINUXTHREADS
+ if (isc_bind9) {
+ /* BIND9 internal, single context */
+ int result;
+
+ result = pthread_kill(main_thread, SIGHUP);
+ if (result != 0) {
+ isc__strerror(result,
+ strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_reload() "
+ "pthread_kill: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+#else
+ if (isc_bind9) {
+ /* BIND9 internal, single context */
+ if (kill(getpid(), SIGHUP) < 0) {
+ isc__strerror(errno,
+ strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_reload() "
+ "kill: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+#endif /* HAVE_LINUXTHREADS */
+ else {
+ /* External, multiple contexts */
+ LOCK(&ctx->readylock);
+ ctx->want_reload = true;
+ UNLOCK(&ctx->readylock);
+ SIGNAL(&ctx->ready);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__app_reload(void) {
+ return (isc__app_ctxsuspend((isc_appctx_t *)&isc_g_appctx));
+}
+
+void
+isc__app_ctxfinish(isc_appctx_t *ctx0) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ DESTROYLOCK(&ctx->lock);
+}
+
+void
+isc__app_finish(void) {
+ isc__app_ctxfinish((isc_appctx_t *)&isc_g_appctx);
+}
+
+void
+isc__app_block(void) {
+#ifdef ISC_PLATFORM_USETHREADS
+ sigset_t sset;
+#endif /* ISC_PLATFORM_USETHREADS */
+ REQUIRE(isc_g_appctx.running);
+ REQUIRE(!isc_g_appctx.blocked);
+
+ isc_g_appctx.blocked = true;
+#ifdef ISC_PLATFORM_USETHREADS
+ blockedthread = pthread_self();
+ RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
+ sigaddset(&sset, SIGINT) == 0 &&
+ sigaddset(&sset, SIGTERM) == 0);
+ RUNTIME_CHECK(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) == 0);
+#endif /* ISC_PLATFORM_USETHREADS */
+}
+
+void
+isc__app_unblock(void) {
+#ifdef ISC_PLATFORM_USETHREADS
+ sigset_t sset;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ REQUIRE(isc_g_appctx.running);
+ REQUIRE(isc_g_appctx.blocked);
+
+ isc_g_appctx.blocked = false;
+
+#ifdef ISC_PLATFORM_USETHREADS
+ REQUIRE(blockedthread == pthread_self());
+
+ RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
+ sigaddset(&sset, SIGINT) == 0 &&
+ sigaddset(&sset, SIGTERM) == 0);
+ RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0);
+#endif /* ISC_PLATFORM_USETHREADS */
+}
+
+isc_result_t
+isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) {
+ isc__appctx_t *ctx;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(ctxp != NULL && *ctxp == NULL);
+
+ ctx = isc_mem_get(mctx, sizeof(*ctx));
+ if (ctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ ctx->common.impmagic = APPCTX_MAGIC;
+ ctx->common.magic = ISCAPI_APPCTX_MAGIC;
+ ctx->common.methods = &appmethods.methods;
+
+ ctx->mctx = NULL;
+ isc_mem_attach(mctx, &ctx->mctx);
+
+ ctx->taskmgr = NULL;
+ ctx->socketmgr = NULL;
+ ctx->timermgr = NULL;
+
+ *ctxp = (isc_appctx_t *)ctx;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc__appctx_destroy(isc_appctx_t **ctxp) {
+ isc__appctx_t *ctx;
+
+ REQUIRE(ctxp != NULL);
+ ctx = (isc__appctx_t *)*ctxp;
+ REQUIRE(VALID_APPCTX(ctx));
+
+ isc_mem_putanddetach(&ctx->mctx, ctx, sizeof(*ctx));
+
+ *ctxp = NULL;
+}
+
+void
+isc__appctx_settaskmgr(isc_appctx_t *ctx0, isc_taskmgr_t *taskmgr) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ ctx->taskmgr = taskmgr;
+}
+
+void
+isc__appctx_setsocketmgr(isc_appctx_t *ctx0, isc_socketmgr_t *socketmgr) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ ctx->socketmgr = socketmgr;
+}
+
+void
+isc__appctx_settimermgr(isc_appctx_t *ctx0, isc_timermgr_t *timermgr) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ ctx->timermgr = timermgr;
+}
+
+isc_result_t
+isc__app_register(void) {
+ return (isc_app_register(isc__appctx_create));
+}
+
+#include "../app_api.c"
diff --git a/lib/isc/unix/dir.c b/lib/isc/unix/dir.c
new file mode 100644
index 0000000..dae0e66
--- /dev/null
+++ b/lib/isc/unix/dir.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <isc/dir.h>
+#include <isc/magic.h>
+#include <isc/netdb.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+#define ISC_DIR_MAGIC ISC_MAGIC('D', 'I', 'R', '*')
+#define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC)
+
+void
+isc_dir_init(isc_dir_t *dir) {
+ REQUIRE(dir != NULL);
+
+ dir->entry.name[0] = '\0';
+ dir->entry.length = 0;
+
+ dir->handle = NULL;
+
+ dir->magic = ISC_DIR_MAGIC;
+}
+
+/*!
+ * \brief Allocate workspace and open directory stream. If either one fails,
+ * NULL will be returned.
+ */
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname) {
+ char *p;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_DIR(dir));
+ REQUIRE(dirname != NULL);
+
+ /*
+ * Copy directory name. Need to have enough space for the name,
+ * a possible path separator, the wildcard, and the final NUL.
+ */
+ if (strlen(dirname) + 3 > sizeof(dir->dirname)) {
+ /* XXXDCL ? */
+ return (ISC_R_NOSPACE);
+ }
+ strlcpy(dir->dirname, dirname, sizeof(dir->dirname));
+
+ /*
+ * Append path separator, if needed, and "*".
+ */
+ p = dir->dirname + strlen(dir->dirname);
+ if (dir->dirname < p && *(p - 1) != '/')
+ *p++ = '/';
+ *p++ = '*';
+ *p = '\0';
+
+ /*
+ * Open stream.
+ */
+ dir->handle = opendir(dirname);
+
+ if (dir->handle == NULL) {
+ return (isc__errno2result(errno));
+ }
+
+ return (result);
+}
+
+/*!
+ * \brief Return previously retrieved file or get next one.
+
+ * Unix's dirent has
+ * separate open and read functions, but the Win32 and DOS interfaces open
+ * the dir stream and reads the first file in one operation.
+ */
+isc_result_t
+isc_dir_read(isc_dir_t *dir) {
+ struct dirent *entry;
+
+ REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
+
+ /*
+ * Fetch next file in directory.
+ */
+ entry = readdir(dir->handle);
+
+ if (entry == NULL)
+ return (ISC_R_NOMORE);
+
+ /*
+ * Make sure that the space for the name is long enough.
+ */
+ if (sizeof(dir->entry.name) <= strlen(entry->d_name))
+ return (ISC_R_UNEXPECTED);
+
+ strlcpy(dir->entry.name, entry->d_name, sizeof(dir->entry.name));
+
+ /*
+ * Some dirents have d_namlen, but it is not portable.
+ */
+ dir->entry.length = strlen(entry->d_name);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*!
+ * \brief Close directory stream.
+ */
+void
+isc_dir_close(isc_dir_t *dir) {
+ REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
+
+ (void)closedir(dir->handle);
+ dir->handle = NULL;
+}
+
+/*!
+ * \brief Reposition directory stream at start.
+ */
+isc_result_t
+isc_dir_reset(isc_dir_t *dir) {
+ REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
+
+ rewinddir(dir->handle);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chdir(const char *dirname) {
+ /*!
+ * \brief Change the current directory to 'dirname'.
+ */
+
+ REQUIRE(dirname != NULL);
+
+ if (chdir(dirname) < 0)
+ return (isc__errno2result(errno));
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chroot(const char *dirname) {
+#ifdef HAVE_CHROOT
+ void *tmp;
+#endif
+
+ REQUIRE(dirname != NULL);
+
+#ifdef HAVE_CHROOT
+ /*
+ * Try to use getservbyname and getprotobyname before chroot.
+ * If WKS records are used in a zone under chroot, Name Service Switch
+ * may fail to load library in chroot.
+ * Do not report errors if it fails, we do not need any result now.
+ */
+ tmp = getprotobyname("udp");
+ if (tmp != NULL)
+ (void) getservbyname("domain", "udp");
+
+ if (chroot(dirname) < 0 || chdir("/") < 0)
+ return (isc__errno2result(errno));
+
+ return (ISC_R_SUCCESS);
+#else
+ return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+isc_result_t
+isc_dir_createunique(char *templet) {
+ isc_result_t result;
+ char *x;
+ char *p;
+ int i;
+ int pid;
+
+ REQUIRE(templet != NULL);
+
+ /*!
+ * \brief mkdtemp is not portable, so this emulates it.
+ */
+
+ pid = getpid();
+
+ /*
+ * Replace trailing Xs with the process-id, zero-filled.
+ */
+ for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet;
+ x--, pid /= 10)
+ *x = pid % 10 + '0';
+
+ x++; /* Set x to start of ex-Xs. */
+
+ do {
+ i = mkdir(templet, 0700);
+ if (i == 0 || errno != EEXIST)
+ break;
+
+ /*
+ * The BSD algorithm.
+ */
+ p = x;
+ while (*p != '\0') {
+ if (isdigit(*p & 0xff))
+ *p = 'a';
+ else if (*p != 'z')
+ ++*p;
+ else {
+ /*
+ * Reset character and move to next.
+ */
+ *p++ = 'a';
+ continue;
+ }
+
+ break;
+ }
+
+ if (*p == '\0') {
+ /*
+ * Tried all combinations. errno should already
+ * be EEXIST, but ensure it is anyway for
+ * isc__errno2result().
+ */
+ errno = EEXIST;
+ break;
+ }
+ } while (1);
+
+ if (i == -1)
+ result = isc__errno2result(errno);
+ else
+ result = ISC_R_SUCCESS;
+
+ return (result);
+}
diff --git a/lib/isc/unix/entropy.c b/lib/isc/unix/entropy.c
new file mode 100644
index 0000000..18eb938
--- /dev/null
+++ b/lib/isc/unix/entropy.c
@@ -0,0 +1,603 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* \file unix/entropy.c
+ * \brief
+ * This is the system dependent part of the ISC entropy API.
+ */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#ifdef HAVE_NANOSLEEP
+#include <time.h>
+#endif
+#include <unistd.h>
+
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+
+#ifdef ISC_PLATFORM_NEEDSYSSELECTH
+#include <sys/select.h>
+#endif
+
+#include "errno2result.h"
+
+/*%
+ * There is only one variable in the entropy data structures that is not
+ * system independent, but pulling the structure that uses it into this file
+ * ultimately means pulling several other independent structures here also to
+ * resolve their interdependencies. Thus only the problem variable's type
+ * is defined here.
+ */
+#define FILESOURCE_HANDLE_TYPE int
+
+typedef struct {
+ int handle;
+ enum {
+ isc_usocketsource_disconnected,
+ isc_usocketsource_connecting,
+ isc_usocketsource_connected,
+ isc_usocketsource_ndesired,
+ isc_usocketsource_wrote,
+ isc_usocketsource_reading
+ } status;
+ size_t sz_to_recv;
+} isc_entropyusocketsource_t;
+
+#include "../entropy.c"
+
+static unsigned int
+get_from_filesource(isc_entropysource_t *source, uint32_t desired) {
+ isc_entropy_t *ent = source->ent;
+ unsigned char buf[128];
+ int fd = source->sources.file.handle;
+ ssize_t n, ndesired;
+ unsigned int added;
+
+ if (source->bad)
+ return (0);
+
+ desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
+
+ added = 0;
+ while (desired > 0) {
+ ndesired = ISC_MIN(desired, sizeof(buf));
+ n = read(fd, buf, ndesired);
+ if (n < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ goto out;
+ goto err;
+ }
+ if (n == 0)
+ goto err;
+
+ entropypool_adddata(ent, buf, n, n * 8);
+ added += n * 8;
+ desired -= n;
+ }
+ goto out;
+
+ err:
+ (void)close(fd);
+ source->sources.file.handle = -1;
+ source->bad = true;
+
+ out:
+ return (added);
+}
+
+static unsigned int
+get_from_usocketsource(isc_entropysource_t *source, uint32_t desired) {
+ isc_entropy_t *ent = source->ent;
+ unsigned char buf[128];
+ int fd = source->sources.usocket.handle;
+ ssize_t n = 0, ndesired;
+ unsigned int added;
+ size_t sz_to_recv = source->sources.usocket.sz_to_recv;
+
+ if (source->bad)
+ return (0);
+
+ desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
+
+ added = 0;
+ while (desired > 0) {
+ ndesired = ISC_MIN(desired, sizeof(buf));
+ eagain_loop:
+
+ switch ( source->sources.usocket.status ) {
+ case isc_usocketsource_ndesired:
+ buf[0] = ndesired;
+ if ((n = sendto(fd, buf, 1, 0, NULL, 0)) < 0) {
+ if (errno == EWOULDBLOCK || errno == EINTR ||
+ errno == ECONNRESET)
+ goto out;
+ goto err;
+ }
+ INSIST(n == 1);
+ source->sources.usocket.status =
+ isc_usocketsource_wrote;
+ goto eagain_loop;
+
+ case isc_usocketsource_connecting:
+ case isc_usocketsource_connected:
+ buf[0] = 1;
+ buf[1] = ndesired;
+ if ((n = sendto(fd, buf, 2, 0, NULL, 0)) < 0) {
+ if (errno == EWOULDBLOCK || errno == EINTR ||
+ errno == ECONNRESET)
+ goto out;
+ goto err;
+ }
+ if (n == 1) {
+ source->sources.usocket.status =
+ isc_usocketsource_ndesired;
+ goto eagain_loop;
+ }
+ INSIST(n == 2);
+ source->sources.usocket.status =
+ isc_usocketsource_wrote;
+ /* FALLTHROUGH */
+
+ case isc_usocketsource_wrote:
+ if (recvfrom(fd, buf, 1, 0, NULL, NULL) != 1) {
+ if (errno == EAGAIN) {
+ /*
+ * The problem of EAGAIN (try again
+ * later) is a major issue on HP-UX.
+ * Solaris actually tries the recvfrom
+ * call again, while HP-UX just dies.
+ * This code is an attempt to let the
+ * entropy pool fill back up (at least
+ * that's what I think the problem is.)
+ * We go to eagain_loop because if we
+ * just "break", then the "desired"
+ * amount gets borked.
+ */
+#ifdef HAVE_NANOSLEEP
+ struct timespec ts;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+#else
+ usleep(1000);
+#endif
+ goto eagain_loop;
+ }
+ if (errno == EWOULDBLOCK || errno == EINTR)
+ goto out;
+ goto err;
+ }
+ source->sources.usocket.status =
+ isc_usocketsource_reading;
+ sz_to_recv = buf[0];
+ source->sources.usocket.sz_to_recv = sz_to_recv;
+ if (sz_to_recv > sizeof(buf))
+ goto err;
+ /* FALLTHROUGH */
+
+ case isc_usocketsource_reading:
+ if (sz_to_recv != 0U) {
+ n = recv(fd, buf, sz_to_recv, 0);
+ if (n < 0) {
+ if (errno == EWOULDBLOCK ||
+ errno == EINTR)
+ goto out;
+ goto err;
+ }
+ } else
+ n = 0;
+ break;
+
+ default:
+ goto err;
+ }
+
+ if ((size_t)n != sz_to_recv)
+ source->sources.usocket.sz_to_recv -= n;
+ else
+ source->sources.usocket.status =
+ isc_usocketsource_connected;
+
+ if (n == 0)
+ goto out;
+
+ entropypool_adddata(ent, buf, n, n * 8);
+ added += n * 8;
+ desired -= n;
+ }
+ goto out;
+
+ err:
+ close(fd);
+ source->bad = true;
+ source->sources.usocket.status = isc_usocketsource_disconnected;
+ source->sources.usocket.handle = -1;
+
+ out:
+ return (added);
+}
+
+/*
+ * Poll each source, trying to get data from it to stuff into the entropy
+ * pool.
+ */
+static void
+fillpool(isc_entropy_t *ent, unsigned int desired, bool blocking) {
+ unsigned int added;
+ unsigned int remaining;
+ unsigned int needed;
+ unsigned int nsource;
+ isc_entropysource_t *source;
+
+ REQUIRE(VALID_ENTROPY(ent));
+
+ needed = desired;
+
+ /*
+ * This logic is a little strange, so an explanation is in order.
+ *
+ * If needed is 0, it means we are being asked to "fill to whatever
+ * we think is best." This means that if we have at least a
+ * partially full pool (say, > 1/4th of the pool) we probably don't
+ * need to add anything.
+ *
+ * Also, we will check to see if the "pseudo" count is too high.
+ * If it is, try to mix in better data. Too high is currently
+ * defined as 1/4th of the pool.
+ *
+ * Next, if we are asked to add a specific bit of entropy, make
+ * certain that we will do so. Clamp how much we try to add to
+ * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
+ *
+ * Note that if we are in a blocking mode, we will only try to
+ * get as much data as we need, not as much as we might want
+ * to build up.
+ */
+ if (needed == 0) {
+ REQUIRE(!blocking);
+
+ if ((ent->pool.entropy >= RND_POOLBITS / 4)
+ && (ent->pool.pseudo <= RND_POOLBITS / 4))
+ return;
+
+ needed = THRESHOLD_BITS * 4;
+ } else {
+ needed = ISC_MAX(needed, THRESHOLD_BITS);
+ needed = ISC_MIN(needed, RND_POOLBITS);
+ }
+
+ /*
+ * In any case, clamp how much we need to how much we can add.
+ */
+ needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
+
+ /*
+ * But wait! If we're not yet initialized, we need at least
+ * THRESHOLD_BITS
+ * of randomness.
+ */
+ if (ent->initialized < THRESHOLD_BITS)
+ needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
+
+ /*
+ * Poll each file source to see if we can read anything useful from
+ * it. XXXMLG When where are multiple sources, we should keep a
+ * record of which one we last used so we can start from it (or the
+ * next one) to avoid letting some sources build up entropy while
+ * others are always drained.
+ */
+
+ added = 0;
+ remaining = needed;
+ if (ent->nextsource == NULL) {
+ ent->nextsource = ISC_LIST_HEAD(ent->sources);
+ if (ent->nextsource == NULL)
+ return;
+ }
+ source = ent->nextsource;
+ again_file:
+ for (nsource = 0; nsource < ent->nsources; nsource++) {
+ unsigned int got;
+
+ if (remaining == 0)
+ break;
+
+ got = 0;
+
+ switch ( source->type ) {
+ case ENTROPY_SOURCETYPE_FILE:
+ got = get_from_filesource(source, remaining);
+ break;
+
+ case ENTROPY_SOURCETYPE_USOCKET:
+ got = get_from_usocketsource(source, remaining);
+ break;
+ }
+
+ added += got;
+
+ remaining -= ISC_MIN(remaining, got);
+
+ source = ISC_LIST_NEXT(source, link);
+ if (source == NULL)
+ source = ISC_LIST_HEAD(ent->sources);
+ }
+ ent->nextsource = source;
+
+ if (blocking && remaining != 0) {
+ int fds;
+
+ fds = wait_for_sources(ent);
+ if (fds > 0)
+ goto again_file;
+ }
+
+ /*
+ * Here, if there are bits remaining to be had and we can block,
+ * check to see if we have a callback source. If so, call them.
+ */
+ source = ISC_LIST_HEAD(ent->sources);
+ while ((remaining != 0) && (source != NULL)) {
+ unsigned int got;
+
+ got = 0;
+
+ if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
+ got = get_from_callback(source, remaining, blocking);
+
+ added += got;
+ remaining -= ISC_MIN(remaining, got);
+
+ if (added >= needed)
+ break;
+
+ source = ISC_LIST_NEXT(source, link);
+ }
+
+ /*
+ * Mark as initialized if we've added enough data.
+ */
+ if (ent->initialized < THRESHOLD_BITS)
+ ent->initialized += added;
+}
+
+static int
+wait_for_sources(isc_entropy_t *ent) {
+ isc_entropysource_t *source;
+ int maxfd, fd;
+ int cc;
+ fd_set reads;
+ fd_set writes;
+
+ maxfd = -1;
+ FD_ZERO(&reads);
+ FD_ZERO(&writes);
+
+ source = ISC_LIST_HEAD(ent->sources);
+ while (source != NULL) {
+ if (source->type == ENTROPY_SOURCETYPE_FILE) {
+ fd = source->sources.file.handle;
+ if (fd >= 0) {
+ maxfd = ISC_MAX(maxfd, fd);
+ FD_SET(fd, &reads);
+ }
+ }
+ if (source->type == ENTROPY_SOURCETYPE_USOCKET) {
+ fd = source->sources.usocket.handle;
+ if (fd >= 0) {
+ switch (source->sources.usocket.status) {
+ case isc_usocketsource_disconnected:
+ break;
+ case isc_usocketsource_connecting:
+ case isc_usocketsource_connected:
+ case isc_usocketsource_ndesired:
+ maxfd = ISC_MAX(maxfd, fd);
+ FD_SET(fd, &writes);
+ break;
+ case isc_usocketsource_wrote:
+ case isc_usocketsource_reading:
+ maxfd = ISC_MAX(maxfd, fd);
+ FD_SET(fd, &reads);
+ break;
+ }
+ }
+ }
+ source = ISC_LIST_NEXT(source, link);
+ }
+
+ if (maxfd < 0)
+ return (-1);
+
+ cc = select(maxfd + 1, &reads, &writes, NULL, NULL);
+ if (cc < 0)
+ return (-1);
+
+ return (cc);
+}
+
+static void
+destroyfilesource(isc_entropyfilesource_t *source) {
+ (void)close(source->handle);
+}
+
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source) {
+ close(source->handle);
+}
+
+/*
+ * Make a fd non-blocking
+ */
+static isc_result_t
+make_nonblock(int fd) {
+ int ret;
+ char strbuf[ISC_STRERRORSIZE];
+#ifdef USE_FIONBIO_IOCTL
+ int on = 1;
+#else
+ int flags;
+#endif
+
+#ifdef USE_FIONBIO_IOCTL
+ ret = ioctl(fd, FIONBIO, (char *)&on);
+#else
+ flags = fcntl(fd, F_GETFL, 0);
+ flags |= PORT_NONBLOCK;
+ ret = fcntl(fd, F_SETFL, flags);
+#endif
+
+ if (ret == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+#ifdef USE_FIONBIO_IOCTL
+ "ioctl(%d, FIONBIO, &on): %s", fd,
+#else
+ "fcntl(%d, F_SETFL, %d): %s", fd, flags,
+#endif
+ strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
+ int fd;
+ struct stat _stat;
+ bool is_usocket = false;
+ bool is_connected = false;
+ isc_result_t ret;
+ isc_entropysource_t *source;
+
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(fname != NULL);
+
+ LOCK(&ent->lock);
+
+ if (stat(fname, &_stat) < 0) {
+ ret = isc__errno2result(errno);
+ goto errout;
+ }
+ /*
+ * Solaris 2.5.1 does not have support for sockets (S_IFSOCK),
+ * but it does return type S_IFIFO (the OS believes that
+ * the socket is a fifo). This may be an issue if we tell
+ * the program to look at an actual FIFO as its source of
+ * entropy.
+ */
+#if defined(S_ISSOCK)
+ if (S_ISSOCK(_stat.st_mode))
+ is_usocket = true;
+#endif
+#if defined(S_ISFIFO) && defined(sun)
+ if (S_ISFIFO(_stat.st_mode))
+ is_usocket = true;
+#endif
+ if (is_usocket)
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ else
+ fd = open(fname, O_RDONLY | PORT_NONBLOCK, 0);
+
+ if (fd < 0) {
+ ret = isc__errno2result(errno);
+ goto errout;
+ }
+
+ ret = make_nonblock(fd);
+ if (ret != ISC_R_SUCCESS)
+ goto closefd;
+
+ if (is_usocket) {
+ struct sockaddr_un sname;
+
+ memset(&sname, 0, sizeof(sname));
+ sname.sun_family = AF_UNIX;
+ strlcpy(sname.sun_path, fname, sizeof(sname.sun_path));
+#ifdef ISC_PLATFORM_HAVESALEN
+#if !defined(SUN_LEN)
+#define SUN_LEN(su) \
+ (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
+ sname.sun_len = SUN_LEN(&sname);
+#endif
+
+ if (connect(fd, (struct sockaddr *) &sname,
+ sizeof(struct sockaddr_un)) < 0) {
+ if (errno != EINPROGRESS) {
+ ret = isc__errno2result(errno);
+ goto closefd;
+ }
+ } else
+ is_connected = true;
+ }
+
+ source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+ if (source == NULL) {
+ ret = ISC_R_NOMEMORY;
+ goto closefd;
+ }
+
+ /*
+ * From here down, no failures can occur.
+ */
+ source->magic = SOURCE_MAGIC;
+ source->ent = ent;
+ source->total = 0;
+ source->bad = false;
+ memset(source->name, 0, sizeof(source->name));
+ ISC_LINK_INIT(source, link);
+ if (is_usocket) {
+ source->sources.usocket.handle = fd;
+ if (is_connected)
+ source->sources.usocket.status =
+ isc_usocketsource_connected;
+ else
+ source->sources.usocket.status =
+ isc_usocketsource_connecting;
+ source->sources.usocket.sz_to_recv = 0;
+ source->type = ENTROPY_SOURCETYPE_USOCKET;
+ } else {
+ source->sources.file.handle = fd;
+ source->type = ENTROPY_SOURCETYPE_FILE;
+ }
+
+ /*
+ * Hook it into the entropy system.
+ */
+ ISC_LIST_APPEND(ent->sources, source, link);
+ ent->nsources++;
+
+ UNLOCK(&ent->lock);
+ return (ISC_R_SUCCESS);
+
+ closefd:
+ (void)close(fd);
+
+ errout:
+ UNLOCK(&ent->lock);
+
+ return (ret);
+}
diff --git a/lib/isc/unix/errno.c b/lib/isc/unix/errno.c
new file mode 100644
index 0000000..a2445f3
--- /dev/null
+++ b/lib/isc/unix/errno.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/errno.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+isc_result_t
+isc_errno_toresult(int err) {
+ return (isc___errno2result(err, false, 0, 0));
+}
diff --git a/lib/isc/unix/errno2result.c b/lib/isc/unix/errno2result.c
new file mode 100644
index 0000000..2f12bcc
--- /dev/null
+++ b/lib/isc/unix/errno2result.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/result.h>
+#include <isc/strerror.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+/*%
+ * Convert a POSIX errno value into an isc_result_t. The
+ * list of supported errno values is not complete; new users
+ * of this function should add any expected errors that are
+ * not already there.
+ */
+isc_result_t
+isc___errno2result(int posixerrno, bool dolog,
+ const char *file, unsigned int line)
+{
+ char strbuf[ISC_STRERRORSIZE];
+
+ switch (posixerrno) {
+ case ENOTDIR:
+ case ELOOP:
+ case EINVAL: /* XXX sometimes this is not for files */
+ case ENAMETOOLONG:
+ case EBADF:
+ return (ISC_R_INVALIDFILE);
+ case ENOENT:
+ return (ISC_R_FILENOTFOUND);
+ case EACCES:
+ case EPERM:
+ return (ISC_R_NOPERM);
+ case EEXIST:
+ return (ISC_R_FILEEXISTS);
+ case EIO:
+ return (ISC_R_IOERROR);
+ case ENOMEM:
+ return (ISC_R_NOMEMORY);
+ case ENFILE:
+ case EMFILE:
+ return (ISC_R_TOOMANYOPENFILES);
+#ifdef EOVERFLOW
+ case EOVERFLOW:
+ return (ISC_R_RANGE);
+#endif
+ case EPIPE:
+#ifdef ECONNRESET
+ case ECONNRESET:
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED:
+#endif
+ return (ISC_R_CONNECTIONRESET);
+#ifdef ENOTCONN
+ case ENOTCONN:
+ return (ISC_R_NOTCONNECTED);
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT:
+ return (ISC_R_TIMEDOUT);
+#endif
+#ifdef ENOBUFS
+ case ENOBUFS:
+ return (ISC_R_NORESOURCES);
+#endif
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT:
+ return (ISC_R_FAMILYNOSUPPORT);
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN:
+ return (ISC_R_NETDOWN);
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN:
+ return (ISC_R_HOSTDOWN);
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH:
+ return (ISC_R_NETUNREACH);
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH:
+ return (ISC_R_HOSTUNREACH);
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE:
+ return (ISC_R_ADDRINUSE);
+#endif
+ case EADDRNOTAVAIL:
+ return (ISC_R_ADDRNOTAVAIL);
+ case ECONNREFUSED:
+ return (ISC_R_CONNREFUSED);
+ default:
+ if (dolog) {
+ isc__strerror(posixerrno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(file, line, "unable to convert errno "
+ "to isc_result: %d: %s",
+ posixerrno, strbuf);
+ }
+ /*
+ * XXXDCL would be nice if perhaps this function could
+ * return the system's error string, so the caller
+ * might have something more descriptive than "unexpected
+ * error" to log with.
+ */
+ return (ISC_R_UNEXPECTED);
+ }
+}
diff --git a/lib/isc/unix/errno2result.h b/lib/isc/unix/errno2result.h
new file mode 100644
index 0000000..7733ab3
--- /dev/null
+++ b/lib/isc/unix/errno2result.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef UNIX_ERRNO2RESULT_H
+#define UNIX_ERRNO2RESULT_H 1
+
+/*! \file */
+
+/* XXXDCL this should be moved to lib/isc/include/isc/errno2result.h. */
+
+#include <errno.h> /* Provides errno. */
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define isc__errno2result(x) isc___errno2result(x, true, __FILE__, __LINE__)
+
+isc_result_t
+isc___errno2result(int posixerrno, bool dolog,
+ const char *file, unsigned int line);
+
+ISC_LANG_ENDDECLS
+
+#endif /* UNIX_ERRNO2RESULT_H */
diff --git a/lib/isc/unix/file.c b/lib/isc/unix/file.c
new file mode 100644
index 0000000..64d9596
--- /dev/null
+++ b/lib/isc/unix/file.c
@@ -0,0 +1,781 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * Portions Copyright (c) 1987, 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. 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.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <time.h> /* Required for utimes on some platforms. */
+#include <unistd.h> /* Required for mkstemp on NetBSD. */
+
+
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include <isc/dir.h>
+#include <isc/file.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/sha2.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+/*
+ * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
+ * it might be good to provide a mechanism that allows for the results
+ * of a previous stat() to be used again without having to do another stat,
+ * such as perl's mechanism of using "_" in place of a file name to indicate
+ * that the results of the last stat should be used. But then you get into
+ * annoying MP issues. BTW, Win32 has stat().
+ */
+static isc_result_t
+file_stats(const char *file, struct stat *stats) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(file != NULL);
+ REQUIRE(stats != NULL);
+
+ if (stat(file, stats) != 0)
+ result = isc__errno2result(errno);
+
+ return (result);
+}
+
+static isc_result_t
+fd_stats(int fd, struct stat *stats) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(stats != NULL);
+
+ if (fstat(fd, stats) != 0)
+ result = isc__errno2result(errno);
+
+ return (result);
+}
+
+isc_result_t
+isc_file_getsizefd(int fd, off_t *size) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(size != NULL);
+
+ result = fd_stats(fd, &stats);
+
+ if (result == ISC_R_SUCCESS)
+ *size = stats.st_size;
+
+ return (result);
+}
+
+isc_result_t
+isc_file_mode(const char *file, mode_t *modep) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(modep != NULL);
+
+ result = file_stats(file, &stats);
+ if (result == ISC_R_SUCCESS)
+ *modep = (stats.st_mode & 07777);
+
+ return (result);
+}
+
+isc_result_t
+isc_file_getmodtime(const char *file, isc_time_t *modtime) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(file != NULL);
+ REQUIRE(modtime != NULL);
+
+ result = file_stats(file, &stats);
+
+ if (result == ISC_R_SUCCESS)
+#ifdef ISC_PLATFORM_HAVESTATNSEC
+ isc_time_set(modtime, stats.st_mtime, stats.st_mtim.tv_nsec);
+#else
+ isc_time_set(modtime, stats.st_mtime, 0);
+#endif
+
+ return (result);
+}
+
+isc_result_t
+isc_file_getsize(const char *file, off_t *size) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(file != NULL);
+ REQUIRE(size != NULL);
+
+ result = file_stats(file, &stats);
+
+ if (result == ISC_R_SUCCESS)
+ *size = stats.st_size;
+
+ return (result);
+}
+
+isc_result_t
+isc_file_settime(const char *file, isc_time_t *when) {
+ struct timeval times[2];
+
+ REQUIRE(file != NULL && when != NULL);
+
+ /*
+ * tv_sec is at least a 32 bit quantity on all platforms we're
+ * dealing with, but it is signed on most (all?) of them,
+ * so we need to make sure the high bit isn't set. This unfortunately
+ * loses when either:
+ * * tv_sec becomes a signed 64 bit integer but long is 32 bits
+ * and isc_time_seconds > LONG_MAX, or
+ * * isc_time_seconds is changed to be > 32 bits but long is 32 bits
+ * and isc_time_seconds has at least 33 significant bits.
+ */
+ times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(when);
+
+ /*
+ * Here is the real check for the high bit being set.
+ */
+ if ((times[0].tv_sec &
+ (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0)
+ return (ISC_R_RANGE);
+
+ /*
+ * isc_time_nanoseconds guarantees a value that divided by 1000 will
+ * fit into the minimum possible size tv_usec field. Unfortunately,
+ * we don't know what that type is so can't cast directly ... but
+ * we can at least cast to signed so the IRIX compiler shuts up.
+ */
+ times[0].tv_usec = times[1].tv_usec =
+ (int32_t)(isc_time_nanoseconds(when) / 1000);
+
+ if (utimes(file, times) < 0)
+ return (isc__errno2result(errno));
+
+ return (ISC_R_SUCCESS);
+}
+
+#undef TEMPLATE
+#define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */
+
+isc_result_t
+isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
+ return (isc_file_template(path, TEMPLATE, buf, buflen));
+}
+
+isc_result_t
+isc_file_template(const char *path, const char *templet, char *buf,
+ size_t buflen)
+{
+ const char *s;
+
+ REQUIRE(templet != NULL);
+ REQUIRE(buf != NULL);
+
+ if (path == NULL)
+ path = "";
+
+ s = strrchr(templet, '/');
+ if (s != NULL)
+ templet = s + 1;
+
+ s = strrchr(path, '/');
+
+ if (s != NULL) {
+ size_t prefixlen = s - path + 1;
+ if ((prefixlen + strlen(templet) + 1) > buflen)
+ return (ISC_R_NOSPACE);
+
+ /* Copy 'prefixlen' bytes and NUL terminate. */
+ strlcpy(buf, path, ISC_MIN(prefixlen + 1, buflen));
+ strlcat(buf, templet, buflen);
+ } else {
+ if ((strlen(templet) + 1) > buflen)
+ return (ISC_R_NOSPACE);
+
+ strlcpy(buf, templet, buflen);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static const char alphnum[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+isc_result_t
+isc_file_renameunique(const char *file, char *templet) {
+ char *x;
+ char *cp;
+
+ REQUIRE(file != NULL);
+ REQUIRE(templet != NULL);
+
+ cp = templet;
+ while (*cp != '\0')
+ cp++;
+ if (cp == templet)
+ return (ISC_R_FAILURE);
+
+ x = cp--;
+ while (cp >= templet && *cp == 'X') {
+ uint32_t which;
+
+ isc_random_get(&which);
+ *cp = alphnum[which % (sizeof(alphnum) - 1)];
+ x = cp--;
+ }
+ while (link(file, templet) == -1) {
+ if (errno != EEXIST)
+ return (isc__errno2result(errno));
+ for (cp = x;;) {
+ const char *t;
+ if (*cp == '\0')
+ return (ISC_R_FAILURE);
+ t = strchr(alphnum, *cp);
+ if (t == NULL || *++t == '\0')
+ *cp++ = alphnum[0];
+ else {
+ *cp = *t;
+ break;
+ }
+ }
+ }
+ if (unlink(file) < 0)
+ if (errno != ENOENT)
+ return (isc__errno2result(errno));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_openunique(char *templet, FILE **fp) {
+ int mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+ return (isc_file_openuniquemode(templet, mode, fp));
+}
+
+isc_result_t
+isc_file_openuniqueprivate(char *templet, FILE **fp) {
+ int mode = S_IWUSR|S_IRUSR;
+ return (isc_file_openuniquemode(templet, mode, fp));
+}
+
+isc_result_t
+isc_file_openuniquemode(char *templet, int mode, FILE **fp) {
+ int fd;
+ FILE *f;
+ isc_result_t result = ISC_R_SUCCESS;
+ char *x;
+ char *cp;
+
+ REQUIRE(templet != NULL);
+ REQUIRE(fp != NULL && *fp == NULL);
+
+ cp = templet;
+ while (*cp != '\0')
+ cp++;
+ if (cp == templet)
+ return (ISC_R_FAILURE);
+
+ x = cp--;
+ while (cp >= templet && *cp == 'X') {
+ uint32_t which;
+
+ isc_random_get(&which);
+ *cp = alphnum[which % (sizeof(alphnum) - 1)];
+ x = cp--;
+ }
+
+
+ while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) {
+ if (errno != EEXIST)
+ return (isc__errno2result(errno));
+ for (cp = x;;) {
+ char *t;
+ if (*cp == '\0')
+ return (ISC_R_FAILURE);
+ t = strchr(alphnum, *cp);
+ if (t == NULL || *++t == '\0')
+ *cp++ = alphnum[0];
+ else {
+ *cp = *t;
+ break;
+ }
+ }
+ }
+ f = fdopen(fd, "w+");
+ if (f == NULL) {
+ result = isc__errno2result(errno);
+ if (remove(templet) < 0) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_FILE, ISC_LOG_ERROR,
+ "remove '%s': failed", templet);
+ }
+ (void)close(fd);
+ } else
+ *fp = f;
+
+ return (result);
+}
+
+isc_result_t
+isc_file_bopenunique(char *templet, FILE **fp) {
+ int mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+ return (isc_file_openuniquemode(templet, mode, fp));
+}
+
+isc_result_t
+isc_file_bopenuniqueprivate(char *templet, FILE **fp) {
+ int mode = S_IWUSR|S_IRUSR;
+ return (isc_file_openuniquemode(templet, mode, fp));
+}
+
+isc_result_t
+isc_file_bopenuniquemode(char *templet, int mode, FILE **fp) {
+ return (isc_file_openuniquemode(templet, mode, fp));
+}
+
+isc_result_t
+isc_file_remove(const char *filename) {
+ int r;
+
+ REQUIRE(filename != NULL);
+
+ r = unlink(filename);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_file_rename(const char *oldname, const char *newname) {
+ int r;
+
+ REQUIRE(oldname != NULL);
+ REQUIRE(newname != NULL);
+
+ r = rename(oldname, newname);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+bool
+isc_file_exists(const char *pathname) {
+ struct stat stats;
+
+ REQUIRE(pathname != NULL);
+
+ return (file_stats(pathname, &stats) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_isplainfile(const char *filename) {
+ /*
+ * This function returns success if filename is a plain file.
+ */
+ struct stat filestat;
+ memset(&filestat,0,sizeof(struct stat));
+
+ if ((stat(filename, &filestat)) == -1)
+ return(isc__errno2result(errno));
+
+ if(! S_ISREG(filestat.st_mode))
+ return(ISC_R_INVALIDFILE);
+
+ return(ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_isplainfilefd(int fd) {
+ /*
+ * This function returns success if filename is a plain file.
+ */
+ struct stat filestat;
+ memset(&filestat,0,sizeof(struct stat));
+
+ if ((fstat(fd, &filestat)) == -1)
+ return(isc__errno2result(errno));
+
+ if(! S_ISREG(filestat.st_mode))
+ return(ISC_R_INVALIDFILE);
+
+ return(ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_isdirectory(const char *filename) {
+ /*
+ * This function returns success if filename exists and is a
+ * directory.
+ */
+ struct stat filestat;
+ memset(&filestat,0,sizeof(struct stat));
+
+ if ((stat(filename, &filestat)) == -1)
+ return(isc__errno2result(errno));
+
+ if(! S_ISDIR(filestat.st_mode))
+ return(ISC_R_INVALIDFILE);
+
+ return(ISC_R_SUCCESS);
+}
+
+
+bool
+isc_file_isabsolute(const char *filename) {
+ REQUIRE(filename != NULL);
+ return (filename[0] == '/');
+}
+
+bool
+isc_file_iscurrentdir(const char *filename) {
+ REQUIRE(filename != NULL);
+ return (filename[0] == '.' && filename[1] == '\0');
+}
+
+bool
+isc_file_ischdiridempotent(const char *filename) {
+ REQUIRE(filename != NULL);
+ if (isc_file_isabsolute(filename))
+ return (true);
+ if (isc_file_iscurrentdir(filename))
+ return (true);
+ return (false);
+}
+
+const char *
+isc_file_basename(const char *filename) {
+ const char *s;
+
+ REQUIRE(filename != NULL);
+
+ s = strrchr(filename, '/');
+ if (s == NULL)
+ return (filename);
+
+ return (s + 1);
+}
+
+isc_result_t
+isc_file_progname(const char *filename, char *buf, size_t buflen) {
+ const char *base;
+ size_t len;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(buf != NULL);
+
+ base = isc_file_basename(filename);
+ len = strlen(base) + 1;
+
+ if (len > buflen)
+ return (ISC_R_NOSPACE);
+ memmove(buf, base, len);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Put the absolute name of the current directory into 'dirname', which is
+ * a buffer of at least 'length' characters. End the string with the
+ * appropriate path separator, such that the final product could be
+ * concatenated with a relative pathname to make a valid pathname string.
+ */
+static isc_result_t
+dir_current(char *dirname, size_t length) {
+ char *cwd;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(dirname != NULL);
+ REQUIRE(length > 0U);
+
+ cwd = getcwd(dirname, length);
+
+ if (cwd == NULL) {
+ if (errno == ERANGE) {
+ result = ISC_R_NOSPACE;
+ } else {
+ result = isc__errno2result(errno);
+ }
+ } else {
+ if (strlen(dirname) + 1 == length) {
+ result = ISC_R_NOSPACE;
+ } else if (dirname[1] != '\0') {
+ strlcat(dirname, "/", length);
+ }
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
+ isc_result_t result;
+ result = dir_current(path, pathlen);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (strlen(path) + strlen(filename) + 1 > pathlen)
+ return (ISC_R_NOSPACE);
+ strlcat(path, filename, pathlen);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_truncate(const char *filename, isc_offset_t size) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ if (truncate(filename, size) < 0)
+ result = isc__errno2result(errno);
+ return (result);
+}
+
+isc_result_t
+isc_file_safecreate(const char *filename, FILE **fp) {
+ isc_result_t result;
+ int flags;
+ struct stat sb;
+ FILE *f;
+ int fd;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(fp != NULL && *fp == NULL);
+
+ result = file_stats(filename, &sb);
+ if (result == ISC_R_SUCCESS) {
+ if ((sb.st_mode & S_IFREG) == 0)
+ return (ISC_R_INVALIDFILE);
+ flags = O_WRONLY | O_TRUNC;
+ } else if (result == ISC_R_FILENOTFOUND) {
+ flags = O_WRONLY | O_CREAT | O_EXCL;
+ } else
+ return (result);
+
+ fd = open(filename, flags, S_IRUSR | S_IWUSR);
+ if (fd == -1)
+ return (isc__errno2result(errno));
+
+ f = fdopen(fd, "w");
+ if (f == NULL) {
+ result = isc__errno2result(errno);
+ close(fd);
+ return (result);
+ }
+
+ *fp = f;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_splitpath(isc_mem_t *mctx, const char *path, char **dirname,
+ char const **bname)
+{
+ char *dir;
+ const char *file, *slash;
+
+ if (path == NULL)
+ return (ISC_R_INVALIDFILE);
+
+ slash = strrchr(path, '/');
+
+ if (slash == path) {
+ file = ++slash;
+ dir = isc_mem_strdup(mctx, "/");
+ } else if (slash != NULL) {
+ file = ++slash;
+ dir = isc_mem_allocate(mctx, slash - path);
+ if (dir != NULL)
+ strlcpy(dir, path, slash - path);
+ } else {
+ file = path;
+ dir = isc_mem_strdup(mctx, ".");
+ }
+
+ if (dir == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if (*file == '\0') {
+ isc_mem_free(mctx, dir);
+ return (ISC_R_INVALIDFILE);
+ }
+
+ *dirname = dir;
+ *bname = file;
+
+ return (ISC_R_SUCCESS);
+}
+
+void *
+isc_file_mmap(void *addr, size_t len, int prot,
+ int flags, int fd, off_t offset)
+{
+#ifdef HAVE_MMAP
+ return (mmap(addr, len, prot, flags, fd, offset));
+#else
+ void *buf;
+ ssize_t ret;
+ off_t end;
+
+ UNUSED(addr);
+ UNUSED(prot);
+ UNUSED(flags);
+
+ end = lseek(fd, 0, SEEK_END);
+ lseek(fd, offset, SEEK_SET);
+ if (end - offset < (off_t) len)
+ len = end - offset;
+
+ buf = malloc(len);
+ if (buf == NULL)
+ return (NULL);
+
+ ret = read(fd, buf, len);
+ if (ret != (ssize_t) len) {
+ free(buf);
+ buf = NULL;
+ }
+
+ return (buf);
+#endif
+}
+
+int
+isc_file_munmap(void *addr, size_t len) {
+#ifdef HAVE_MMAP
+ return (munmap(addr, len));
+#else
+ UNUSED(len);
+
+ free(addr);
+ return (0);
+#endif
+}
+
+#define DISALLOW "\\/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+isc_result_t
+isc_file_sanitize(const char *dir, const char *base, const char *ext,
+ char *path, size_t length)
+{
+ char buf[PATH_MAX], hash[ISC_SHA256_DIGESTSTRINGLENGTH];
+ size_t l = 0;
+
+ REQUIRE(base != NULL);
+ REQUIRE(path != NULL);
+
+ l = strlen(base) + 1;
+
+ /*
+ * allow room for a full sha256 hash (64 chars
+ * plus null terminator)
+ */
+ if (l < 65U)
+ l = 65;
+
+ if (dir != NULL)
+ l += strlen(dir) + 1;
+ if (ext != NULL)
+ l += strlen(ext) + 1;
+
+ if (l > length || l > (unsigned)PATH_MAX)
+ return (ISC_R_NOSPACE);
+
+ /* Check whether the full-length SHA256 hash filename exists */
+ isc_sha256_data((const void *) base, strlen(base), hash);
+ snprintf(buf, sizeof(buf), "%s%s%s%s%s",
+ dir != NULL ? dir : "", dir != NULL ? "/" : "",
+ hash, ext != NULL ? "." : "", ext != NULL ? ext : "");
+ if (isc_file_exists(buf)) {
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+ }
+
+ /* Check for a truncated SHA256 hash filename */
+ hash[16] = '\0';
+ snprintf(buf, sizeof(buf), "%s%s%s%s%s",
+ dir != NULL ? dir : "", dir != NULL ? "/" : "",
+ hash, ext != NULL ? "." : "", ext != NULL ? ext : "");
+ if (isc_file_exists(buf)) {
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * If neither hash filename already exists, then we'll use
+ * the original base name if it has no disallowed characters,
+ * or the truncated hash name if it does.
+ */
+ if (strpbrk(base, DISALLOW) != NULL) {
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+ }
+
+ snprintf(buf, sizeof(buf), "%s%s%s%s%s",
+ dir != NULL ? dir : "", dir != NULL ? "/" : "",
+ base, ext != NULL ? "." : "", ext != NULL ? ext : "");
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+}
+
+bool
+isc_file_isdirwritable(const char *path) {
+ return (access(path, W_OK|X_OK) == 0);
+}
diff --git a/lib/isc/unix/fsaccess.c b/lib/isc/unix/fsaccess.c
new file mode 100644
index 0000000..e3cd0bf
--- /dev/null
+++ b/lib/isc/unix/fsaccess.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdbool.h>
+#include <errno.h>
+
+#include "errno2result.h"
+
+/*! \file
+ * \brief
+ * The OS-independent part of the API is in lib/isc.
+ */
+#include "../fsaccess.c"
+
+isc_result_t
+isc_fsaccess_set(const char *path, isc_fsaccess_t access) {
+ struct stat statb;
+ mode_t mode;
+ bool is_dir = false;
+ isc_fsaccess_t bits;
+ isc_result_t result;
+
+ if (stat(path, &statb) != 0)
+ return (isc__errno2result(errno));
+
+ if ((statb.st_mode & S_IFDIR) != 0)
+ is_dir = true;
+ else if ((statb.st_mode & S_IFREG) == 0)
+ return (ISC_R_INVALIDFILE);
+
+ result = check_bad_bits(access, is_dir);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Done with checking bad bits. Set mode_t.
+ */
+ mode = 0;
+
+#define SET_AND_CLEAR1(modebit) \
+ if ((access & bits) != 0) { \
+ mode |= modebit; \
+ access &= ~bits; \
+ }
+#define SET_AND_CLEAR(user, group, other) \
+ SET_AND_CLEAR1(user); \
+ bits <<= STEP; \
+ SET_AND_CLEAR1(group); \
+ bits <<= STEP; \
+ SET_AND_CLEAR1(other);
+
+ bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY;
+
+ SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH);
+
+ bits = ISC_FSACCESS_WRITE |
+ ISC_FSACCESS_CREATECHILD |
+ ISC_FSACCESS_DELETECHILD;
+
+ SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH);
+
+ bits = ISC_FSACCESS_EXECUTE |
+ ISC_FSACCESS_ACCESSCHILD;
+
+ SET_AND_CLEAR(S_IXUSR, S_IXGRP, S_IXOTH);
+
+ INSIST(access == 0);
+
+ if (chmod(path, mode) < 0)
+ return (isc__errno2result(errno));
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/unix/ifiter_getifaddrs.c b/lib/isc/unix/ifiter_getifaddrs.c
new file mode 100644
index 0000000..de6f060
--- /dev/null
+++ b/lib/isc/unix/ifiter_getifaddrs.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file
+ * \brief
+ * Obtain the list of network interfaces using the getifaddrs(3) library.
+ */
+
+#include <stdbool.h>
+#include <ifaddrs.h>
+
+/*% Iterator Magic */
+#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'G')
+/*% Valid Iterator */
+#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
+
+#ifdef __linux
+static bool seenv6 = false;
+#endif
+
+/*% Iterator structure */
+struct isc_interfaceiter {
+ unsigned int magic; /*%< Magic number. */
+ isc_mem_t *mctx;
+ void *buf; /*%< (unused) */
+ unsigned int bufsize; /*%< (always 0) */
+ struct ifaddrs *ifaddrs; /*%< List of ifaddrs */
+ struct ifaddrs *pos; /*%< Ptr to current ifaddr */
+ isc_interface_t current; /*%< Current interface data. */
+ isc_result_t result; /*%< Last result code. */
+#ifdef __linux
+ FILE * proc;
+ char entry[ISC_IF_INET6_SZ];
+ isc_result_t valid;
+#endif
+};
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
+ isc_interfaceiter_t *iter;
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(iterp != NULL);
+ REQUIRE(*iterp == NULL);
+
+ iter = isc_mem_get(mctx, sizeof(*iter));
+ if (iter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ iter->mctx = mctx;
+ iter->buf = NULL;
+ iter->bufsize = 0;
+ iter->ifaddrs = NULL;
+#ifdef __linux
+ /*
+ * Only open "/proc/net/if_inet6" if we have never seen a IPv6
+ * address returned by getifaddrs().
+ */
+ if (!seenv6)
+ iter->proc = fopen("/proc/net/if_inet6", "r");
+ else
+ iter->proc = NULL;
+ iter->valid = ISC_R_FAILURE;
+#endif
+
+ if (getifaddrs(&iter->ifaddrs) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERGETIFADDRS,
+ ISC_MSG_GETIFADDRS,
+ "getting interface "
+ "addresses: getifaddrs: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto failure;
+ }
+
+ /*
+ * A newly created iterator has an undefined position
+ * until isc_interfaceiter_first() is called.
+ */
+ iter->pos = NULL;
+ iter->result = ISC_R_FAILURE;
+
+ iter->magic = IFITER_MAGIC;
+ *iterp = iter;
+ return (ISC_R_SUCCESS);
+
+ failure:
+#ifdef __linux
+ if (iter->proc != NULL)
+ fclose(iter->proc);
+#endif
+ if (iter->ifaddrs != NULL) /* just in case */
+ freeifaddrs(iter->ifaddrs);
+ isc_mem_put(mctx, iter, sizeof(*iter));
+ return (result);
+}
+
+/*
+ * Get information about the current interface to iter->current.
+ * If successful, return ISC_R_SUCCESS.
+ * If the interface has an unsupported address family,
+ * return ISC_R_IGNORE.
+ */
+
+static isc_result_t
+internal_current(isc_interfaceiter_t *iter) {
+ struct ifaddrs *ifa;
+ int family;
+ unsigned int namelen;
+
+ REQUIRE(VALID_IFITER(iter));
+
+ ifa = iter->pos;
+
+#ifdef __linux
+ if (iter->pos == NULL)
+ return (linux_if_inet6_current(iter));
+#endif
+
+ INSIST(ifa != NULL);
+ INSIST(ifa->ifa_name != NULL);
+
+ if (ifa->ifa_addr == NULL)
+ return (ISC_R_IGNORE);
+
+ family = ifa->ifa_addr->sa_family;
+ if (family != AF_INET && family != AF_INET6)
+ return (ISC_R_IGNORE);
+
+#ifdef __linux
+ if (family == AF_INET6)
+ seenv6 = true;
+#endif
+
+ memset(&iter->current, 0, sizeof(iter->current));
+
+ namelen = strlen(ifa->ifa_name);
+ if (namelen > sizeof(iter->current.name) - 1)
+ namelen = sizeof(iter->current.name) - 1;
+
+ memset(iter->current.name, 0, sizeof(iter->current.name));
+ memmove(iter->current.name, ifa->ifa_name, namelen);
+
+ iter->current.flags = 0;
+
+ if ((ifa->ifa_flags & IFF_UP) != 0)
+ iter->current.flags |= INTERFACE_F_UP;
+
+ if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
+ iter->current.flags |= INTERFACE_F_POINTTOPOINT;
+
+ if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
+ iter->current.flags |= INTERFACE_F_LOOPBACK;
+
+ iter->current.af = family;
+
+ get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
+
+ if (ifa->ifa_netmask != NULL)
+ get_addr(family, &iter->current.netmask, ifa->ifa_netmask,
+ ifa->ifa_name);
+
+ if (ifa->ifa_dstaddr != NULL &&
+ (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
+ get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
+ ifa->ifa_name);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Step the iterator to the next interface. Unlike
+ * isc_interfaceiter_next(), this may leave the iterator
+ * positioned on an interface that will ultimately
+ * be ignored. Return ISC_R_NOMORE if there are no more
+ * interfaces, otherwise ISC_R_SUCCESS.
+ */
+static isc_result_t
+internal_next(isc_interfaceiter_t *iter) {
+
+ if (iter->pos != NULL)
+ iter->pos = iter->pos->ifa_next;
+ if (iter->pos == NULL) {
+#ifdef __linux
+ if (!seenv6)
+ return (linux_if_inet6_next(iter));
+#endif
+ return (ISC_R_NOMORE);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+internal_destroy(isc_interfaceiter_t *iter) {
+
+#ifdef __linux
+ if (iter->proc != NULL)
+ fclose(iter->proc);
+ iter->proc = NULL;
+#endif
+ if (iter->ifaddrs)
+ freeifaddrs(iter->ifaddrs);
+ iter->ifaddrs = NULL;
+}
+
+static
+void internal_first(isc_interfaceiter_t *iter) {
+
+#ifdef __linux
+ linux_if_inet6_first(iter);
+#endif
+ iter->pos = iter->ifaddrs;
+}
diff --git a/lib/isc/unix/ifiter_ioctl.c b/lib/isc/unix/ifiter_ioctl.c
new file mode 100644
index 0000000..9702fae
--- /dev/null
+++ b/lib/isc/unix/ifiter_ioctl.c
@@ -0,0 +1,931 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <isc/print.h>
+
+/*! \file
+ * \brief
+ * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
+ * See netintro(4).
+ */
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
+#define lifc_len iflc_len
+#define lifc_buf iflc_buf
+#define lifc_req iflc_req
+#define LIFCONF if_laddrconf
+#else
+#define ISC_HAVE_LIFC_FAMILY 1
+#define ISC_HAVE_LIFC_FLAGS 1
+#define LIFCONF lifconf
+#endif
+
+#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
+#define lifr_addr iflr_addr
+#define lifr_name iflr_name
+#define lifr_dstaddr iflr_dstaddr
+#define lifr_flags iflr_flags
+#define ss_family sa_family
+#define LIFREQ if_laddrreq
+#else
+#define LIFREQ lifreq
+#endif
+#endif
+
+#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'T')
+#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
+
+struct isc_interfaceiter {
+ unsigned int magic; /* Magic number. */
+ isc_mem_t *mctx;
+ int mode;
+ int socket;
+ struct ifconf ifc;
+ void *buf; /* Buffer for sysctl data. */
+ unsigned int bufsize; /* Bytes allocated. */
+ unsigned int pos; /* Current offset in
+ SIOCGIFCONF data */
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ int socket6;
+ struct LIFCONF lifc;
+ void *buf6; /* Buffer for sysctl data. */
+ unsigned int bufsize6; /* Bytes allocated. */
+ unsigned int pos6; /* Current offset in
+ SIOCGLIFCONF data */
+ isc_result_t result6; /* Last result code. */
+ bool first6;
+#endif
+#ifdef HAVE_TRUCLUSTER
+ int clua_context; /* Cluster alias context */
+ bool clua_done;
+ struct sockaddr clua_sa;
+#endif
+#ifdef __linux
+ FILE * proc;
+ char entry[ISC_IF_INET6_SZ];
+ isc_result_t valid;
+#endif
+ isc_interface_t current; /* Current interface data. */
+ isc_result_t result; /* Last result code. */
+};
+
+#ifdef HAVE_TRUCLUSTER
+#include <clua/clua.h>
+#include <sys/socket.h>
+#endif
+
+
+/*%
+ * Size of buffer for SIOCGLIFCONF, in bytes. We assume no sane system
+ * will have more than a megabyte of interface configuration data.
+ */
+#define IFCONF_BUFSIZE_INITIAL 4096
+#define IFCONF_BUFSIZE_MAX 1048576
+
+#ifdef __linux
+#ifndef IF_NAMESIZE
+# ifdef IFNAMSIZ
+# define IF_NAMESIZE IFNAMSIZ
+# else
+# define IF_NAMESIZE 16
+# endif
+#endif
+#endif
+
+static isc_result_t
+getbuf4(isc_interfaceiter_t *iter) {
+ char strbuf[ISC_STRERRORSIZE];
+
+ iter->bufsize = IFCONF_BUFSIZE_INITIAL;
+
+ for (;;) {
+ iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
+ if (iter->buf == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
+ iter->ifc.ifc_len = iter->bufsize;
+ iter->ifc.ifc_buf = iter->buf;
+ /*
+ * Ignore the HP/UX warning about "integer overflow during
+ * conversion". It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
+ == -1) {
+ if (errno != EINVAL) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETIFCONFIG,
+ "get interface "
+ "configuration: %s"),
+ strbuf);
+ goto unexpected;
+ }
+ /*
+ * EINVAL. Retry with a bigger buffer.
+ */
+ } else {
+ /*
+ * The ioctl succeeded.
+ * Some OS's just return what will fit rather
+ * than set EINVAL if the buffer is too small
+ * to fit all the interfaces in. If
+ * ifc.lifc_len is too near to the end of the
+ * buffer we will grow it just in case and
+ * retry.
+ */
+ if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
+ < iter->bufsize)
+ break;
+ }
+ if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_BUFFERMAX,
+ "get interface "
+ "configuration: "
+ "maximum buffer "
+ "size exceeded"));
+ goto unexpected;
+ }
+ isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
+
+ iter->bufsize *= 2;
+ }
+ return (ISC_R_SUCCESS);
+
+ unexpected:
+ isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
+ iter->buf = NULL;
+ return (ISC_R_UNEXPECTED);
+}
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+static isc_result_t
+getbuf6(isc_interfaceiter_t *iter) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc_result_t result;
+
+ iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
+
+ for (;;) {
+ iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
+ if (iter->buf6 == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(&iter->lifc, 0, sizeof(iter->lifc));
+#ifdef ISC_HAVE_LIFC_FAMILY
+ iter->lifc.lifc_family = AF_INET6;
+#endif
+#ifdef ISC_HAVE_LIFC_FLAGS
+ iter->lifc.lifc_flags = 0;
+#endif
+ iter->lifc.lifc_len = iter->bufsize6;
+ iter->lifc.lifc_buf = iter->buf6;
+ /*
+ * Ignore the HP/UX warning about "integer overflow during
+ * conversion". It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
+ == -1) {
+#ifdef __hpux
+ /*
+ * IPv6 interface scanning is not available on all
+ * kernels w/ IPv6 sockets.
+ */
+ if (errno == ENOENT) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_INTERFACE,
+ ISC_LOG_DEBUG(1),
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETIFCONFIG,
+ "get interface "
+ "configuration: %s"),
+ strbuf);
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+#endif
+ if (errno != EINVAL) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETIFCONFIG,
+ "get interface "
+ "configuration: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+ /*
+ * EINVAL. Retry with a bigger buffer.
+ */
+ } else {
+ /*
+ * The ioctl succeeded.
+ * Some OS's just return what will fit rather
+ * than set EINVAL if the buffer is too small
+ * to fit all the interfaces in. If
+ * ifc.ifc_len is too near to the end of the
+ * buffer we will grow it just in case and
+ * retry.
+ */
+ if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
+ < iter->bufsize6)
+ break;
+ }
+ if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_BUFFERMAX,
+ "get interface "
+ "configuration: "
+ "maximum buffer "
+ "size exceeded"));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+ isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
+
+ iter->bufsize6 *= 2;
+ }
+
+ if (iter->lifc.lifc_len != 0)
+ iter->mode = 6;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
+ iter->buf6 = NULL;
+ return (result);
+}
+#endif
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
+ isc_interfaceiter_t *iter;
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(iterp != NULL);
+ REQUIRE(*iterp == NULL);
+
+ iter = isc_mem_get(mctx, sizeof(*iter));
+ if (iter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ iter->mctx = mctx;
+ iter->mode = 4;
+ iter->buf = NULL;
+ iter->pos = (unsigned int) -1;
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ iter->buf6 = NULL;
+ iter->pos6 = (unsigned int) -1;
+ iter->result6 = ISC_R_NOMORE;
+ iter->socket6 = -1;
+ iter->first6 = false;
+#endif
+
+ /*
+ * Get the interface configuration, allocating more memory if
+ * necessary.
+ */
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ result = isc_net_probeipv6();
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * Create an unbound datagram socket to do the SIOCGLIFCONF
+ * ioctl on. HP/UX requires an AF_INET6 socket for
+ * SIOCGLIFCONF to get IPv6 addresses.
+ */
+ if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_MAKESCANSOCKET,
+ "making interface "
+ "scan socket: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto socket6_failure;
+ }
+ result = iter->result6 = getbuf6(iter);
+ if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS)
+ goto ioctl6_failure;
+ }
+#endif
+ if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_MAKESCANSOCKET,
+ "making interface "
+ "scan socket: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto socket_failure;
+ }
+ result = getbuf4(iter);
+ if (result != ISC_R_SUCCESS)
+ goto ioctl_failure;
+
+ /*
+ * A newly created iterator has an undefined position
+ * until isc_interfaceiter_first() is called.
+ */
+#ifdef HAVE_TRUCLUSTER
+ iter->clua_context = -1;
+ iter->clua_done = true;
+#endif
+#ifdef __linux
+ iter->proc = fopen("/proc/net/if_inet6", "r");
+ iter->valid = ISC_R_FAILURE;
+#endif
+ iter->result = ISC_R_FAILURE;
+
+ iter->magic = IFITER_MAGIC;
+ *iterp = iter;
+ return (ISC_R_SUCCESS);
+
+ ioctl_failure:
+ if (iter->buf != NULL)
+ isc_mem_put(mctx, iter->buf, iter->bufsize);
+ (void) close(iter->socket);
+
+ socket_failure:
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ if (iter->buf6 != NULL)
+ isc_mem_put(mctx, iter->buf6, iter->bufsize6);
+ ioctl6_failure:
+ if (iter->socket6 != -1)
+ (void) close(iter->socket6);
+ socket6_failure:
+#endif
+
+ isc_mem_put(mctx, iter, sizeof(*iter));
+ return (result);
+}
+
+#ifdef HAVE_TRUCLUSTER
+static void
+get_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
+ dst->family = AF_INET;
+ memmove(&dst->type.in, src, sizeof(struct in_addr));
+}
+
+static isc_result_t
+internal_current_clusteralias(isc_interfaceiter_t *iter) {
+ struct clua_info ci;
+ if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
+ return (ISC_R_IGNORE);
+ memset(&iter->current, 0, sizeof(iter->current));
+ iter->current.af = iter->clua_sa.sa_family;
+ memset(iter->current.name, 0, sizeof(iter->current.name));
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "clua%d", ci.aliasid);
+ iter->current.flags = INTERFACE_F_UP;
+ get_inaddr(&iter->current.address, &ci.addr);
+ get_inaddr(&iter->current.netmask, &ci.netmask);
+ return (ISC_R_SUCCESS);
+}
+#endif
+
+/*
+ * Get information about the current interface to iter->current.
+ * If successful, return ISC_R_SUCCESS.
+ * If the interface has an unsupported address family, or if
+ * some operation on it fails, return ISC_R_IGNORE to make
+ * the higher-level iterator code ignore it.
+ */
+
+static isc_result_t
+internal_current4(isc_interfaceiter_t *iter) {
+ struct ifreq *ifrp;
+ struct ifreq ifreq;
+ int family;
+ char strbuf[ISC_STRERRORSIZE];
+#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
+ struct lifreq lifreq;
+#else
+ char sabuf[256];
+#endif
+ int i, bits, prefixlen;
+
+ REQUIRE(VALID_IFITER(iter));
+
+ if (iter->ifc.ifc_len == 0 ||
+ iter->pos == (unsigned int)iter->ifc.ifc_len) {
+#ifdef __linux
+ return (linux_if_inet6_current(iter));
+#else
+ return (ISC_R_NOMORE);
+#endif
+ }
+
+ INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len);
+
+ ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
+
+ memset(&ifreq, 0, sizeof(ifreq));
+ memmove(&ifreq, ifrp, sizeof(ifreq));
+
+ family = ifreq.ifr_addr.sa_family;
+#if defined(ISC_PLATFORM_HAVEIPV6)
+ if (family != AF_INET && family != AF_INET6)
+#else
+ if (family != AF_INET)
+#endif
+ return (ISC_R_IGNORE);
+
+ memset(&iter->current, 0, sizeof(iter->current));
+ iter->current.af = family;
+
+ INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
+ memset(iter->current.name, 0, sizeof(iter->current.name));
+ memmove(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
+
+ get_addr(family, &iter->current.address,
+ (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
+
+ /*
+ * If the interface does not have a address ignore it.
+ */
+ switch (family) {
+ case AF_INET:
+ if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
+ return (ISC_R_IGNORE);
+ break;
+ case AF_INET6:
+ if (memcmp(&iter->current.address.type.in6, &in6addr_any,
+ sizeof(in6addr_any)) == 0)
+ return (ISC_R_IGNORE);
+ break;
+ }
+
+ /*
+ * Get interface flags.
+ */
+
+ iter->current.flags = 0;
+
+ /*
+ * Ignore the HP/UX warning about "integer overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s: getting interface flags: %s",
+ ifreq.ifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+
+ if ((ifreq.ifr_flags & IFF_UP) != 0)
+ iter->current.flags |= INTERFACE_F_UP;
+
+#ifdef IFF_POINTOPOINT
+ if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
+ iter->current.flags |= INTERFACE_F_POINTTOPOINT;
+#endif
+
+ if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
+ iter->current.flags |= INTERFACE_F_LOOPBACK;
+
+ if (family == AF_INET)
+ goto inet;
+
+#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
+ memset(&lifreq, 0, sizeof(lifreq));
+ memmove(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
+ memmove(&lifreq.lifr_addr, &iter->current.address.type.in6,
+ sizeof(iter->current.address.type.in6));
+
+ if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s: getting interface address: %s",
+ ifreq.ifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+ prefixlen = lifreq.lifr_addrlen;
+#else
+ isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_INTERFACE,
+ ISC_LOG_INFO,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETIFCONFIG,
+ "prefix length for %s is unknown "
+ "(assume 128)"), sabuf);
+ prefixlen = 128;
+#endif
+
+ /*
+ * Netmask already zeroed.
+ */
+ iter->current.netmask.family = family;
+ for (i = 0; i < 16; i++) {
+ if (prefixlen > 8) {
+ bits = 0;
+ prefixlen -= 8;
+ } else {
+ bits = 8 - prefixlen;
+ prefixlen = 0;
+ }
+ iter->current.netmask.type.in6.s6_addr[i] =
+ (~0U << bits) & 0xff;
+ }
+ return (ISC_R_SUCCESS);
+
+ inet:
+ if (family != AF_INET)
+ return (ISC_R_IGNORE);
+#ifdef IFF_POINTOPOINT
+ /*
+ * If the interface is point-to-point, get the destination address.
+ */
+ if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
+ /*
+ * Ignore the HP/UX warning about "integer overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
+ < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETDESTADDR,
+ "%s: getting "
+ "destination address: %s"),
+ ifreq.ifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+ get_addr(family, &iter->current.dstaddress,
+ (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
+ }
+#endif
+
+ /*
+ * Get the network mask.
+ */
+ memset(&ifreq, 0, sizeof(ifreq));
+ memmove(&ifreq, ifrp, sizeof(ifreq));
+ /*
+ * Ignore the HP/UX warning about "integer overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETNETMASK,
+ "%s: getting netmask: %s"),
+ ifreq.ifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+ get_addr(family, &iter->current.netmask,
+ (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
+ return (ISC_R_SUCCESS);
+}
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+static isc_result_t
+internal_current6(isc_interfaceiter_t *iter) {
+ struct LIFREQ *ifrp;
+ struct LIFREQ lifreq;
+ int family;
+ char strbuf[ISC_STRERRORSIZE];
+ int fd;
+
+ REQUIRE(VALID_IFITER(iter));
+ if (iter->result6 != ISC_R_SUCCESS)
+ return (iter->result6);
+ REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
+
+ ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
+
+ memset(&lifreq, 0, sizeof(lifreq));
+ memmove(&lifreq, ifrp, sizeof(lifreq));
+
+ family = lifreq.lifr_addr.ss_family;
+#ifdef ISC_PLATFORM_HAVEIPV6
+ if (family != AF_INET && family != AF_INET6)
+#else
+ if (family != AF_INET)
+#endif
+ return (ISC_R_IGNORE);
+
+ memset(&iter->current, 0, sizeof(iter->current));
+ iter->current.af = family;
+
+ INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
+ memset(iter->current.name, 0, sizeof(iter->current.name));
+ memmove(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
+
+ get_addr(family, &iter->current.address,
+ (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
+
+ /*
+ * If the interface does not have a address ignore it.
+ */
+ switch (family) {
+ case AF_INET:
+ if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
+ return (ISC_R_IGNORE);
+ break;
+ case AF_INET6:
+ if (memcmp(&iter->current.address.type.in6, &in6addr_any,
+ sizeof(in6addr_any)) == 0)
+ return (ISC_R_IGNORE);
+ break;
+ }
+
+ /*
+ * Get interface flags.
+ */
+
+ iter->current.flags = 0;
+
+ if (family == AF_INET6)
+ fd = iter->socket6;
+ else
+ fd = iter->socket;
+
+ /*
+ * Ignore the HP/UX warning about "integer overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s: getting interface flags: %s",
+ lifreq.lifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+
+ if ((lifreq.lifr_flags & IFF_UP) != 0)
+ iter->current.flags |= INTERFACE_F_UP;
+
+#ifdef IFF_POINTOPOINT
+ if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
+ iter->current.flags |= INTERFACE_F_POINTTOPOINT;
+#endif
+
+ if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
+ iter->current.flags |= INTERFACE_F_LOOPBACK;
+
+#ifdef IFF_POINTOPOINT
+ /*
+ * If the interface is point-to-point, get the destination address.
+ */
+ if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
+ /*
+ * Ignore the HP/UX warning about "integer overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
+ < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETDESTADDR,
+ "%s: getting "
+ "destination address: %s"),
+ lifreq.lifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+ get_addr(family, &iter->current.dstaddress,
+ (struct sockaddr *)&lifreq.lifr_dstaddr,
+ lifreq.lifr_name);
+ }
+#endif
+
+ /*
+ * Get the network mask. Netmask already zeroed.
+ */
+ memset(&lifreq, 0, sizeof(lifreq));
+ memmove(&lifreq, ifrp, sizeof(lifreq));
+
+#ifdef lifr_addrlen
+ /*
+ * Special case: if the system provides lifr_addrlen member, the
+ * netmask of an IPv6 address can be derived from the length, since
+ * an IPv6 address always has a contiguous mask.
+ */
+ if (family == AF_INET6) {
+ int i, bits;
+
+ iter->current.netmask.family = family;
+ for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
+ bits = lifreq.lifr_addrlen - i;
+ bits = (bits < 8) ? (8 - bits) : 0;
+ iter->current.netmask.type.in6.s6_addr[i / 8] =
+ (~0U << bits) & 0xff;
+ }
+
+ return (ISC_R_SUCCESS);
+ }
+#endif
+
+ /*
+ * Ignore the HP/UX warning about "integer overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETNETMASK,
+ "%s: getting netmask: %s"),
+ lifreq.lifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+ get_addr(family, &iter->current.netmask,
+ (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
+
+ return (ISC_R_SUCCESS);
+}
+#endif
+
+static isc_result_t
+internal_current(isc_interfaceiter_t *iter) {
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ if (iter->mode == 6) {
+ iter->result6 = internal_current6(iter);
+ if (iter->result6 != ISC_R_NOMORE)
+ return (iter->result6);
+ }
+#endif
+#ifdef HAVE_TRUCLUSTER
+ if (!iter->clua_done)
+ return(internal_current_clusteralias(iter));
+#endif
+ return (internal_current4(iter));
+}
+
+/*
+ * Step the iterator to the next interface. Unlike
+ * isc_interfaceiter_next(), this may leave the iterator
+ * positioned on an interface that will ultimately
+ * be ignored. Return ISC_R_NOMORE if there are no more
+ * interfaces, otherwise ISC_R_SUCCESS.
+ */
+static isc_result_t
+internal_next4(isc_interfaceiter_t *iter) {
+#ifdef ISC_PLATFORM_HAVESALEN
+ struct ifreq *ifrp;
+#endif
+
+ if (iter->pos < (unsigned int) iter->ifc.ifc_len) {
+#ifdef ISC_PLATFORM_HAVESALEN
+ ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
+
+ if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
+ iter->pos += sizeof(ifrp->ifr_name) +
+ ifrp->ifr_addr.sa_len;
+ else
+#endif
+ iter->pos += sizeof(struct ifreq);
+
+ } else {
+ INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len);
+#ifdef __linux
+ return (linux_if_inet6_next(iter));
+#else
+ return (ISC_R_NOMORE);
+#endif
+ }
+ return (ISC_R_SUCCESS);
+}
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+static isc_result_t
+internal_next6(isc_interfaceiter_t *iter) {
+#ifdef ISC_PLATFORM_HAVESALEN
+ struct LIFREQ *ifrp;
+#endif
+
+ if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
+ return (iter->result6);
+
+ REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
+
+#ifdef ISC_PLATFORM_HAVESALEN
+ ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
+
+ if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
+ iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
+ else
+#endif
+ iter->pos6 += sizeof(struct LIFREQ);
+
+ if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+#endif
+
+static isc_result_t
+internal_next(isc_interfaceiter_t *iter) {
+#ifdef HAVE_TRUCLUSTER
+ int clua_result;
+#endif
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ if (iter->mode == 6) {
+ iter->result6 = internal_next6(iter);
+ if (iter->result6 != ISC_R_NOMORE)
+ return (iter->result6);
+ if (iter->first6) {
+ iter->first6 = false;
+ return (ISC_R_SUCCESS);
+ }
+ }
+#endif
+#ifdef HAVE_TRUCLUSTER
+ if (!iter->clua_done) {
+ clua_result = clua_getaliasaddress(&iter->clua_sa,
+ &iter->clua_context);
+ if (clua_result != CLUA_SUCCESS)
+ iter->clua_done = true;
+ return (ISC_R_SUCCESS);
+ }
+#endif
+ return (internal_next4(iter));
+}
+
+static void
+internal_destroy(isc_interfaceiter_t *iter) {
+ (void) close(iter->socket);
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ if (iter->socket6 != -1)
+ (void) close(iter->socket6);
+ if (iter->buf6 != NULL) {
+ isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
+ }
+#endif
+#ifdef __linux
+ if (iter->proc != NULL)
+ fclose(iter->proc);
+#endif
+}
+
+static
+void internal_first(isc_interfaceiter_t *iter) {
+#ifdef HAVE_TRUCLUSTER
+ int clua_result;
+#endif
+ iter->pos = 0;
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ iter->pos6 = 0;
+ if (iter->result6 == ISC_R_NOMORE)
+ iter->result6 = ISC_R_SUCCESS;
+ iter->first6 = true;
+#endif
+#ifdef HAVE_TRUCLUSTER
+ iter->clua_context = 0;
+ clua_result = clua_getaliasaddress(&iter->clua_sa,
+ &iter->clua_context);
+ iter->clua_done = (clua_result != CLUA_SUCCESS);
+#endif
+#ifdef __linux
+ linux_if_inet6_first(iter);
+#endif
+}
diff --git a/lib/isc/unix/ifiter_sysctl.c b/lib/isc/unix/ifiter_sysctl.c
new file mode 100644
index 0000000..ebbefe9
--- /dev/null
+++ b/lib/isc/unix/ifiter_sysctl.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file
+ * \brief
+ * Obtain the list of network interfaces using sysctl.
+ * See TCP/IP Illustrated Volume 2, sections 19.8, 19.14,
+ * and 19.16.
+ */
+
+#include <inttypes.h>
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <net/if_dl.h>
+
+#include <isc/print.h>
+
+/* XXX what about Alpha? */
+#ifdef sgi
+#define ROUNDUP(a) ((a) > 0 ? \
+ (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) : \
+ sizeof(__uint64_t))
+#else
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
+ : sizeof(long))
+#endif
+
+#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'S')
+#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
+
+struct isc_interfaceiter {
+ unsigned int magic; /* Magic number. */
+ isc_mem_t *mctx;
+ void *buf; /* Buffer for sysctl data. */
+ unsigned int bufsize; /* Bytes allocated. */
+ unsigned int bufused; /* Bytes used. */
+ unsigned int pos; /* Current offset in
+ sysctl data. */
+ isc_interface_t current; /* Current interface data. */
+ isc_result_t result; /* Last result code. */
+};
+
+static int mib[6] = {
+ CTL_NET,
+ PF_ROUTE,
+ 0,
+ 0, /* Any address family. */
+ NET_RT_IFLIST,
+ 0 /* Flags. */
+};
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
+ isc_interfaceiter_t *iter;
+ isc_result_t result;
+ size_t bufsize;
+ size_t bufused;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(iterp != NULL);
+ REQUIRE(*iterp == NULL);
+
+ iter = isc_mem_get(mctx, sizeof(*iter));
+ if (iter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ iter->mctx = mctx;
+ iter->buf = 0;
+
+ /*
+ * Determine the amount of memory needed.
+ */
+ bufsize = 0;
+ if (sysctl(mib, 6, NULL, &bufsize, NULL, (size_t) 0) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERSYSCTL,
+ ISC_MSG_GETIFLISTSIZE,
+ "getting interface "
+ "list size: sysctl: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto failure;
+ }
+ iter->bufsize = bufsize;
+
+ iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
+ if (iter->buf == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+
+ bufused = bufsize;
+ if (sysctl(mib, 6, iter->buf, &bufused, NULL, (size_t) 0) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERSYSCTL,
+ ISC_MSG_GETIFLIST,
+ "getting interface list: "
+ "sysctl: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto failure;
+ }
+ iter->bufused = bufused;
+ INSIST(iter->bufused <= iter->bufsize);
+
+ /*
+ * A newly created iterator has an undefined position
+ * until isc_interfaceiter_first() is called.
+ */
+ iter->pos = (unsigned int) -1;
+ iter->result = ISC_R_FAILURE;
+
+ iter->magic = IFITER_MAGIC;
+ *iterp = iter;
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (iter->buf != NULL)
+ isc_mem_put(mctx, iter->buf, iter->bufsize);
+ isc_mem_put(mctx, iter, sizeof(*iter));
+ return (result);
+}
+
+/*
+ * Get information about the current interface to iter->current.
+ * If successful, return ISC_R_SUCCESS.
+ * If the interface has an unsupported address family,
+ * return ISC_R_IGNORE. In case of other failure,
+ * return ISC_R_UNEXPECTED.
+ */
+
+static isc_result_t
+internal_current(isc_interfaceiter_t *iter) {
+ struct ifa_msghdr *ifam, *ifam_end;
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE (iter->pos < (unsigned int) iter->bufused);
+
+ ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
+ ifam_end = (struct ifa_msghdr *) ((char *) iter->buf + iter->bufused);
+
+ if (ifam->ifam_type == RTM_IFINFO) {
+ struct if_msghdr *ifm = (struct if_msghdr *) ifam;
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *) (ifm + 1);
+ unsigned int namelen;
+
+ memset(&iter->current, 0, sizeof(iter->current));
+
+ namelen = sdl->sdl_nlen;
+ if (namelen > sizeof(iter->current.name) - 1)
+ namelen = sizeof(iter->current.name) - 1;
+
+ memset(iter->current.name, 0, sizeof(iter->current.name));
+ memmove(iter->current.name, sdl->sdl_data, namelen);
+
+ iter->current.flags = 0;
+
+ if ((ifam->ifam_flags & IFF_UP) != 0)
+ iter->current.flags |= INTERFACE_F_UP;
+
+ if ((ifam->ifam_flags & IFF_POINTOPOINT) != 0)
+ iter->current.flags |= INTERFACE_F_POINTTOPOINT;
+
+ if ((ifam->ifam_flags & IFF_LOOPBACK) != 0)
+ iter->current.flags |= INTERFACE_F_LOOPBACK;
+
+ /*
+ * This is not an interface address.
+ * Force another iteration.
+ */
+ return (ISC_R_IGNORE);
+ } else if (ifam->ifam_type == RTM_NEWADDR) {
+ int i;
+ int family;
+ struct sockaddr *mask_sa = NULL;
+ struct sockaddr *addr_sa = NULL;
+ struct sockaddr *dst_sa = NULL;
+
+ struct sockaddr *sa = (struct sockaddr *)(ifam + 1);
+ family = sa->sa_family;
+
+ for (i = 0; i < RTAX_MAX; i++)
+ {
+ if ((ifam->ifam_addrs & (1 << i)) == 0)
+ continue;
+
+ INSIST(sa < (struct sockaddr *) ifam_end);
+
+ switch (i) {
+ case RTAX_NETMASK: /* Netmask */
+ mask_sa = sa;
+ break;
+ case RTAX_IFA: /* Interface address */
+ addr_sa = sa;
+ break;
+ case RTAX_BRD: /* Broadcast or destination address */
+ dst_sa = sa;
+ break;
+ }
+#ifdef ISC_PLATFORM_HAVESALEN
+ sa = (struct sockaddr *)((char*)(sa)
+ + ROUNDUP(sa->sa_len));
+#else
+#ifdef sgi
+ /*
+ * Do as the contributed SGI code does.
+ */
+ sa = (struct sockaddr *)((char*)(sa)
+ + ROUNDUP(_FAKE_SA_LEN_DST(sa)));
+#else
+ /* XXX untested. */
+ sa = (struct sockaddr *)((char*)(sa)
+ + ROUNDUP(sizeof(struct sockaddr)));
+#endif
+#endif
+ }
+
+ if (addr_sa == NULL)
+ return (ISC_R_IGNORE);
+
+ family = addr_sa->sa_family;
+ if (family != AF_INET && family != AF_INET6)
+ return (ISC_R_IGNORE);
+
+ iter->current.af = family;
+
+ get_addr(family, &iter->current.address, addr_sa,
+ iter->current.name);
+
+ if (mask_sa != NULL)
+ get_addr(family, &iter->current.netmask, mask_sa,
+ iter->current.name);
+
+ if (dst_sa != NULL &&
+ (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
+ get_addr(family, &iter->current.dstaddress, dst_sa,
+ iter->current.name);
+
+ return (ISC_R_SUCCESS);
+ } else {
+ printf("%s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERSYSCTL,
+ ISC_MSG_UNEXPECTEDTYPE,
+ "warning: unexpected interface list "
+ "message type\n"));
+ return (ISC_R_IGNORE);
+ }
+}
+
+/*
+ * Step the iterator to the next interface. Unlike
+ * isc_interfaceiter_next(), this may leave the iterator
+ * positioned on an interface that will ultimately
+ * be ignored. Return ISC_R_NOMORE if there are no more
+ * interfaces, otherwise ISC_R_SUCCESS.
+ */
+static isc_result_t
+internal_next(isc_interfaceiter_t *iter) {
+ struct ifa_msghdr *ifam;
+ REQUIRE (iter->pos < (unsigned int) iter->bufused);
+
+ ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
+
+ iter->pos += ifam->ifam_msglen;
+
+ if (iter->pos >= iter->bufused)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+internal_destroy(isc_interfaceiter_t *iter) {
+ UNUSED(iter); /* Unused. */
+ /*
+ * Do nothing.
+ */
+}
+
+static
+void internal_first(isc_interfaceiter_t *iter) {
+ iter->pos = 0;
+}
diff --git a/lib/isc/unix/include/Makefile.in b/lib/isc/unix/include/Makefile.in
new file mode 100644
index 0000000..2cbf021
--- /dev/null
+++ b/lib/isc/unix/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc pkcs11
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/unix/include/isc/Makefile.in b/lib/isc/unix/include/isc/Makefile.in
new file mode 100644
index 0000000..977defe
--- /dev/null
+++ b/lib/isc/unix/include/isc/Makefile.in
@@ -0,0 +1,35 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = dir.h keyboard.h net.h netdb.h offset.h stat.h \
+ stdtime.h strerror.h syslog.h time.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
diff --git a/lib/isc/unix/include/isc/dir.h b/lib/isc/unix/include/isc/dir.h
new file mode 100644
index 0000000..36d0aad
--- /dev/null
+++ b/lib/isc/unix/include/isc/dir.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_DIR_H
+#define ISC_DIR_H 1
+
+/*! \file */
+
+#include <sys/types.h> /* Required on some systems. */
+#include <dirent.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+#define ISC_DIR_NAMEMAX 256
+#define ISC_DIR_PATHMAX 1024
+
+/*% Directory Entry */
+typedef struct isc_direntry {
+ /*!
+ * Ideally, this should be NAME_MAX, but AIX does not define it by
+ * default and dynamically allocating the space based on pathconf()
+ * complicates things undesirably, as does adding special conditionals
+ * just for AIX. So a comfortably sized buffer is chosen instead.
+ */
+ char name[ISC_DIR_NAMEMAX];
+ unsigned int length;
+} isc_direntry_t;
+
+/*% Directory */
+typedef struct isc_dir {
+ unsigned int magic;
+ /*!
+ * As with isc_direntry_t->name, making this "right" for all systems
+ * is slightly problematic because AIX does not define PATH_MAX.
+ */
+ char dirname[ISC_DIR_PATHMAX];
+ isc_direntry_t entry;
+ DIR * handle;
+} isc_dir_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_dir_init(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname);
+
+isc_result_t
+isc_dir_read(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_reset(isc_dir_t *dir);
+
+void
+isc_dir_close(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_chdir(const char *dirname);
+
+isc_result_t
+isc_dir_chroot(const char *dirname);
+
+isc_result_t
+isc_dir_createunique(char *templet);
+/*!<
+ * Use a templet (such as from isc_file_mktemplate()) to create a uniquely
+ * named, empty directory. The templet string is modified in place.
+ * If result == ISC_R_SUCCESS, it is the name of the directory that was
+ * created.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_DIR_H */
diff --git a/lib/isc/unix/include/isc/keyboard.h b/lib/isc/unix/include/isc/keyboard.h
new file mode 100644
index 0000000..4dc8745
--- /dev/null
+++ b/lib/isc/unix/include/isc/keyboard.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_KEYBOARD_H
+#define ISC_KEYBOARD_H 1
+
+/*! \file */
+
+#include <stdbool.h>
+#include <termios.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef struct {
+ int fd;
+ struct termios saved_mode;
+ isc_result_t result;
+} isc_keyboard_t;
+
+isc_result_t
+isc_keyboard_open(isc_keyboard_t *keyboard);
+
+isc_result_t
+isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleepseconds);
+
+isc_result_t
+isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp);
+
+bool
+isc_keyboard_canceled(isc_keyboard_t *keyboard);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_KEYBOARD_H */
diff --git a/lib/isc/unix/include/isc/net.h b/lib/isc/unix/include/isc/net.h
new file mode 100644
index 0000000..08be590
--- /dev/null
+++ b/lib/isc/unix/include/isc/net.h
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_NET_H
+#define ISC_NET_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Basic Networking Types
+ *
+ * This module is responsible for defining the following basic networking
+ * types:
+ *
+ *\li struct in_addr
+ *\li struct in6_addr
+ *\li struct in6_pktinfo
+ *\li struct sockaddr
+ *\li struct sockaddr_in
+ *\li struct sockaddr_in6
+ *\li struct sockaddr_storage
+ *\li in_port_t
+ *
+ * It ensures that the AF_ and PF_ macros are defined.
+ *
+ * It declares ntoh[sl]() and hton[sl]().
+ *
+ * It declares inet_aton(), inet_ntop(), and inet_pton().
+ *
+ * It ensures that #INADDR_LOOPBACK, #INADDR_ANY, #IN6ADDR_ANY_INIT,
+ * IN6ADDR_V4MAPPED_INIT, in6addr_any, and in6addr_loopback are available.
+ *
+ * It ensures that IN_MULTICAST() is available to check for multicast
+ * addresses.
+ *
+ * MP:
+ *\li No impact.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li N/A.
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li BSD Socket API
+ *\li RFC2553
+ */
+
+/***
+ *** Imports.
+ ***/
+#include <isc/platform.h>
+
+#include <inttypes.h>
+
+#include <sys/types.h>
+#include <sys/socket.h> /* Contractual promise. */
+
+#include <net/if.h>
+
+#include <netinet/in.h> /* Contractual promise. */
+#include <arpa/inet.h> /* Contractual promise. */
+#ifdef ISC_PLATFORM_NEEDNETINETIN6H
+#include <netinet/in6.h> /* Required on UnixWare. */
+#endif
+#ifdef ISC_PLATFORM_NEEDNETINET6IN6H
+#include <netinet6/in6.h> /* Required on BSD/OS for in6_pktinfo. */
+#endif
+
+#ifndef ISC_PLATFORM_HAVEIPV6
+#include <isc/ipv6.h> /* Contractual promise. */
+#endif
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_HAVEINADDR6
+#define in6_addr in_addr6 /*%< Required for pre RFC2133 implementations. */
+#endif
+
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifndef IN6ADDR_ANY_INIT
+#ifdef s6_addr
+/*%
+ * Required for some pre RFC2133 implementations.
+ * IN6ADDR_ANY_INIT and IN6ADDR_LOOPBACK_INIT were added in
+ * draft-ietf-ipngwg-bsd-api-04.txt or draft-ietf-ipngwg-bsd-api-05.txt.
+ * If 's6_addr' is defined then assume that there is a union and three
+ * levels otherwise assume two levels required.
+ */
+#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
+#else
+#define IN6ADDR_ANY_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }
+#endif
+#endif
+
+#ifndef IN6ADDR_LOOPBACK_INIT
+#ifdef s6_addr
+/*% IPv6 address loopback init */
+#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+#else
+#define IN6ADDR_LOOPBACK_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } }
+#endif
+#endif
+
+#ifndef IN6ADDR_V4MAPPED_INIT
+#ifdef s6_addr
+/*% IPv6 v4mapped prefix init */
+#define IN6ADDR_V4MAPPED_INIT { { { 0,0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0 } } }
+#else
+#define IN6ADDR_V4MAPPED_INIT { { 0,0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0 } }
+#endif
+#endif
+
+#ifndef IN6_IS_ADDR_V4MAPPED
+/*% Is IPv6 address V4 mapped? */
+#define IN6_IS_ADDR_V4MAPPED(x) \
+ (memcmp((x)->s6_addr, in6addr_any.s6_addr, 10) == 0 && \
+ (x)->s6_addr[10] == 0xff && (x)->s6_addr[11] == 0xff)
+#endif
+
+#ifndef IN6_IS_ADDR_V4COMPAT
+/*% Is IPv6 address V4 compatible? */
+#define IN6_IS_ADDR_V4COMPAT(x) \
+ (memcmp((x)->s6_addr, in6addr_any.s6_addr, 12) == 0 && \
+ ((x)->s6_addr[12] != 0 || (x)->s6_addr[13] != 0 || \
+ (x)->s6_addr[14] != 0 || \
+ ((x)->s6_addr[15] != 0 && (x)->s6_addr[15] != 1)))
+#endif
+
+#ifndef IN6_IS_ADDR_MULTICAST
+/*% Is IPv6 address multicast? */
+#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff)
+#endif
+
+#ifndef IN6_IS_ADDR_LINKLOCAL
+/*% Is IPv6 address linklocal? */
+#define IN6_IS_ADDR_LINKLOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
+#endif
+
+#ifndef IN6_IS_ADDR_SITELOCAL
+/*% is IPv6 address sitelocal? */
+#define IN6_IS_ADDR_SITELOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
+#endif
+
+
+#ifndef IN6_IS_ADDR_LOOPBACK
+/*% is IPv6 address loopback? */
+#define IN6_IS_ADDR_LOOPBACK(x) \
+ (memcmp((x)->s6_addr, in6addr_loopback.s6_addr, 16) == 0)
+#endif
+#endif
+
+#ifndef AF_INET6
+/*% IPv6 */
+#define AF_INET6 99
+#endif
+
+#ifndef PF_INET6
+/*% IPv6 */
+#define PF_INET6 AF_INET6
+#endif
+
+#ifndef INADDR_ANY
+/*% inaddr any */
+#define INADDR_ANY 0x00000000UL
+#endif
+
+#ifndef INADDR_LOOPBACK
+/*% inaddr loopback */
+#define INADDR_LOOPBACK 0x7f000001UL
+#endif
+
+#ifndef ISC_PLATFORM_HAVEIN6PKTINFO
+/*% IPv6 packet info */
+struct in6_pktinfo {
+ struct in6_addr ipi6_addr; /*%< src/dst IPv6 address */
+ unsigned int ipi6_ifindex; /*%< send/recv interface index */
+};
+#endif
+
+
+#ifndef ISC_PLATFORM_HAVESOCKADDRSTORAGE
+#define _SS_MAXSIZE 128
+#define _SS_ALIGNSIZE (sizeof (uint64_t))
+#ifdef ISC_PLATFORM_HAVESALEN
+#define _SS_PAD1SIZE (_SS_ALIGNSIZE - (2 * sizeof(uint8_t)))
+#define _SS_PAD2SIZE (_SS_MAXSIZE - (_SS_ALIGNSIZE + _SS_PAD1SIZE \
+ + 2 * sizeof(uint8_t)))
+#else
+#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(uint16_t))
+#define _SS_PAD2SIZE (_SS_MAXSIZE - (_SS_ALIGNSIZE + _SS_PAD1SIZE \
+ + sizeof(uint16_t)))
+#endif
+
+struct sockaddr_storage {
+#ifdef ISC_PLATFORM_HAVESALEN
+ uint8_t ss_len;
+ uint8_t ss_family;
+#else
+ uint16_t ss_family;
+#endif
+ char __ss_pad1[_SS_PAD1SIZE];
+ uint64_t __ss_align; /* field to force desired structure */
+ char __ss_pad2[_SS_PAD2SIZE];
+};
+#endif
+
+#if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRANY)
+extern const struct in6_addr isc_net_in6addrany;
+/*%
+ * Cope with a missing in6addr_any and in6addr_loopback.
+ */
+#define in6addr_any isc_net_in6addrany
+#endif
+
+#if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
+extern const struct in6_addr isc_net_in6addrloop;
+#define in6addr_loopback isc_net_in6addrloop
+#endif
+
+#ifdef ISC_PLATFORM_FIXIN6ISADDR
+#undef IN6_IS_ADDR_GEOGRAPHIC
+/*!
+ * \brief
+ * Fix UnixWare 7.1.1's broken IN6_IS_ADDR_* definitions.
+ */
+#define IN6_IS_ADDR_GEOGRAPHIC(a) (((a)->S6_un.S6_l[0] & 0xE0) == 0x80)
+#undef IN6_IS_ADDR_IPX
+#define IN6_IS_ADDR_IPX(a) (((a)->S6_un.S6_l[0] & 0xFE) == 0x04)
+#undef IN6_IS_ADDR_LINKLOCAL
+#define IN6_IS_ADDR_LINKLOCAL(a) (((a)->S6_un.S6_l[0] & 0xC0FF) == 0x80FE)
+#undef IN6_IS_ADDR_MULTICAST
+#define IN6_IS_ADDR_MULTICAST(a) (((a)->S6_un.S6_l[0] & 0xFF) == 0xFF)
+#undef IN6_IS_ADDR_NSAP
+#define IN6_IS_ADDR_NSAP(a) (((a)->S6_un.S6_l[0] & 0xFE) == 0x02)
+#undef IN6_IS_ADDR_PROVIDER
+#define IN6_IS_ADDR_PROVIDER(a) (((a)->S6_un.S6_l[0] & 0xE0) == 0x40)
+#undef IN6_IS_ADDR_SITELOCAL
+#define IN6_IS_ADDR_SITELOCAL(a) (((a)->S6_un.S6_l[0] & 0xC0FF) == 0xC0FE)
+#endif /* ISC_PLATFORM_FIXIN6ISADDR */
+
+#ifdef ISC_PLATFORM_NEEDPORTT
+/*%
+ * Ensure type in_port_t is defined.
+ */
+typedef uint16_t in_port_t;
+#endif
+
+#ifndef MSG_TRUNC
+/*%
+ * If this system does not have MSG_TRUNC (as returned from recvmsg())
+ * ISC_PLATFORM_RECVOVERFLOW will be defined. This will enable the MSG_TRUNC
+ * faking code in socket.c.
+ */
+#define ISC_PLATFORM_RECVOVERFLOW
+#endif
+
+/*% IP address. */
+#define ISC__IPADDR(x) ((uint32_t)htonl((uint32_t)(x)))
+
+/*% Is IP address multicast? */
+#define ISC_IPADDR_ISMULTICAST(i) \
+ (((uint32_t)(i) & ISC__IPADDR(0xf0000000)) \
+ == ISC__IPADDR(0xe0000000))
+
+#define ISC_IPADDR_ISEXPERIMENTAL(i) \
+ (((uint32_t)(i) & ISC__IPADDR(0xf0000000)) \
+ == ISC__IPADDR(0xf0000000))
+
+/***
+ *** Functions.
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_net_probeipv4(void);
+/*%<
+ * Check if the system's kernel supports IPv4.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS IPv4 is supported.
+ *\li #ISC_R_NOTFOUND IPv4 is not supported.
+ *\li #ISC_R_DISABLED IPv4 is disabled.
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probeipv6(void);
+/*%<
+ * Check if the system's kernel supports IPv6.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS IPv6 is supported.
+ *\li #ISC_R_NOTFOUND IPv6 is not supported.
+ *\li #ISC_R_DISABLED IPv6 is disabled.
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probe_ipv6only(void);
+/*%<
+ * Check if the system's kernel supports the IPV6_V6ONLY socket option.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS the option is supported for both TCP and UDP.
+ *\li #ISC_R_NOTFOUND IPv6 itself or the option is not supported.
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probe_ipv6pktinfo(void);
+/*
+ * Check if the system's kernel supports the IPV6_(RECV)PKTINFO socket option
+ * for UDP sockets.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS the option is supported.
+ * \li #ISC_R_NOTFOUND IPv6 itself or the option is not supported.
+ * \li #ISC_R_UNEXPECTED
+ */
+
+void
+isc_net_disableipv4(void);
+
+void
+isc_net_disableipv6(void);
+
+void
+isc_net_enableipv4(void);
+
+void
+isc_net_enableipv6(void);
+
+isc_result_t
+isc_net_probeunix(void);
+/*
+ * Returns whether UNIX domain sockets are supported.
+ */
+
+#define ISC_NET_DSCPRECVV4 0x01 /* Can receive sent DSCP value IPv4 */
+#define ISC_NET_DSCPRECVV6 0x02 /* Can receive sent DSCP value IPv6 */
+#define ISC_NET_DSCPSETV4 0x04 /* Can set DSCP on socket IPv4 */
+#define ISC_NET_DSCPSETV6 0x08 /* Can set DSCP on socket IPv6 */
+#define ISC_NET_DSCPPKTV4 0x10 /* Can set DSCP on per packet IPv4 */
+#define ISC_NET_DSCPPKTV6 0x20 /* Can set DSCP on per packet IPv6 */
+#define ISC_NET_DSCPALL 0x3f /* All valid flags */
+
+unsigned int
+isc_net_probedscp(void);
+/*%<
+ * Probe the level of DSCP support.
+ */
+
+
+isc_result_t
+isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high);
+/*%<
+ * Returns system's default range of ephemeral UDP ports, if defined.
+ * If the range is not available or unknown, ISC_NET_PORTRANGELOW and
+ * ISC_NET_PORTRANGEHIGH will be returned.
+ *
+ * Requires:
+ *
+ *\li 'low' and 'high' must be non NULL.
+ *
+ * Returns:
+ *
+ *\li *low and *high will be the ports specifying the low and high ends of
+ * the range.
+ */
+
+#ifdef ISC_PLATFORM_NEEDNTOP
+const char *
+isc_net_ntop(int af, const void *src, char *dst, size_t size);
+#undef inet_ntop
+#define inet_ntop isc_net_ntop
+#endif
+
+#ifdef ISC_PLATFORM_NEEDPTON
+int
+isc_net_pton(int af, const char *src, void *dst);
+#undef inet_pton
+#define inet_pton isc_net_pton
+#endif
+
+int
+isc_net_aton(const char *cp, struct in_addr *addr);
+#undef inet_aton
+#define inet_aton isc_net_aton
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NET_H */
diff --git a/lib/isc/unix/include/isc/netdb.h b/lib/isc/unix/include/isc/netdb.h
new file mode 100644
index 0000000..5aaa9f6
--- /dev/null
+++ b/lib/isc/unix/include/isc/netdb.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_NETDB_H
+#define ISC_NETDB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Portable netdb.h support.
+ *
+ * This module is responsible for defining the get<x>by<y> APIs.
+ *
+ * MP:
+ *\li No impact.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li N/A.
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li BSD API
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/net.h>
+
+#include <netdb.h>
+
+#endif /* ISC_NETDB_H */
diff --git a/lib/isc/unix/include/isc/offset.h b/lib/isc/unix/include/isc/offset.h
new file mode 100644
index 0000000..cf57292
--- /dev/null
+++ b/lib/isc/unix/include/isc/offset.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_OFFSET_H
+#define ISC_OFFSET_H 1
+
+/*! \file
+ * \brief
+ * File offsets are operating-system dependent.
+ */
+#include <limits.h> /* Required for CHAR_BIT. */
+#include <sys/types.h>
+#include <stddef.h> /* For Linux Standard Base. */
+
+typedef off_t isc_offset_t;
+
+#endif /* ISC_OFFSET_H */
diff --git a/lib/isc/unix/include/isc/stat.h b/lib/isc/unix/include/isc/stat.h
new file mode 100644
index 0000000..24c4ce5
--- /dev/null
+++ b/lib/isc/unix/include/isc/stat.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_STAT_H
+#define ISC_STAT_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * Portable <sys/stat.h> support.
+ *
+ * This module is responsible for defining S_IS??? macros.
+ *
+ * MP:
+ * No impact.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * N/A.
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#endif /* ISC_STAT_H */
diff --git a/lib/isc/unix/include/isc/stdtime.h b/lib/isc/unix/include/isc/stdtime.h
new file mode 100644
index 0000000..1a3da82
--- /dev/null
+++ b/lib/isc/unix/include/isc/stdtime.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_STDTIME_H
+#define ISC_STDTIME_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <inttypes.h>
+
+/*%
+ * It's public information that 'isc_stdtime_t' is an unsigned integral type.
+ * Applications that want maximum portability should not assume anything
+ * about its size.
+ */
+typedef uint32_t isc_stdtime_t;
+
+/* but this flag helps... */
+#define STDTIME_ON_32BITS 1
+
+/*
+ * isc_stdtime32_t is a 32-bit version of isc_stdtime_t. A variable of this
+ * type should only be used as an opaque integer (e.g.,) to compare two
+ * time values.
+ */
+typedef uint32_t isc_stdtime32_t;
+
+ISC_LANG_BEGINDECLS
+/* */
+void
+isc_stdtime_get(isc_stdtime_t *t);
+/*%<
+ * Set 't' to the number of seconds since 00:00:00 UTC, January 1, 1970.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+#define isc_stdtime_convert32(t, t32p) (*(t32p) = t)
+/*
+ * Convert the standard time to its 32-bit version.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STDTIME_H */
diff --git a/lib/isc/unix/include/isc/strerror.h b/lib/isc/unix/include/isc/strerror.h
new file mode 100644
index 0000000..fa0e429
--- /dev/null
+++ b/lib/isc/unix/include/isc/strerror.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_STRERROR_H
+#define ISC_STRERROR_H
+
+/*! \file */
+
+#include <sys/types.h>
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% String Error Size */
+#define ISC_STRERRORSIZE 128
+
+/*%
+ * Provide a thread safe wrapper to strerror().
+ *
+ * Requires:
+ * 'buf' to be non NULL.
+ */
+void
+isc__strerror(int num, char *buf, size_t bufsize);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STRERROR_H */
diff --git a/lib/isc/unix/include/isc/syslog.h b/lib/isc/unix/include/isc/syslog.h
new file mode 100644
index 0000000..e0b8e85
--- /dev/null
+++ b/lib/isc/unix/include/isc/syslog.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_SYSLOG_H
+#define ISC_SYSLOG_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp);
+/*%<
+ * Convert 'str' to the appropriate syslog facility constant.
+ *
+ * Requires:
+ *
+ *\li 'str' is not NULL
+ *\li 'facilityp' is not NULL
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SYSLOG_H */
diff --git a/lib/isc/unix/include/isc/time.h b/lib/isc/unix/include/isc/time.h
new file mode 100644
index 0000000..b864c29
--- /dev/null
+++ b/lib/isc/unix/include/isc/time.h
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_TIME_H
+#define ISC_TIME_H 1
+
+/*! \file */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/***
+ *** Intervals
+ ***/
+
+/*!
+ * \brief
+ * The contents of this structure are private, and MUST NOT be accessed
+ * directly by callers.
+ *
+ * The contents are exposed only to allow callers to avoid dynamic allocation.
+ */
+struct isc_interval {
+ unsigned int seconds;
+ unsigned int nanoseconds;
+};
+
+extern const isc_interval_t * const isc_interval_zero;
+
+/*
+ * ISC_FORMATHTTPTIMESTAMP_SIZE needs to be 30 in C locale and potentially
+ * more for other locales to handle longer national abbreviations when
+ * expanding strftime's %a and %b.
+ */
+#define ISC_FORMATHTTPTIMESTAMP_SIZE 50
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_interval_set(isc_interval_t *i,
+ unsigned int seconds, unsigned int nanoseconds);
+/*%<
+ * Set 'i' to a value representing an interval of 'seconds' seconds and
+ * 'nanoseconds' nanoseconds, suitable for use in isc_time_add() and
+ * isc_time_subtract().
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ *\li nanoseconds < 1000000000.
+ */
+
+bool
+isc_interval_iszero(const isc_interval_t *i);
+/*%<
+ * Returns true iff. 'i' is the zero interval.
+ *
+ * Requires:
+ *
+ *\li 'i' is a valid pointer.
+ */
+
+/***
+ *** Absolute Times
+ ***/
+
+/*%
+ * The contents of this structure are private, and MUST NOT be accessed
+ * directly by callers.
+ *
+ * The contents are exposed only to allow callers to avoid dynamic allocation.
+ */
+
+struct isc_time {
+ unsigned int seconds;
+ unsigned int nanoseconds;
+};
+
+extern const isc_time_t * const isc_time_epoch;
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds);
+/*%<
+ * Set 't' to a value which represents the given number of seconds and
+ * nanoseconds since 00:00:00 January 1, 1970, UTC.
+ *
+ * Notes:
+ *\li The Unix version of this call is equivalent to:
+ *\code
+ * isc_time_settoepoch(t);
+ * isc_interval_set(i, seconds, nanoseconds);
+ * isc_time_add(t, i, t);
+ *\endcode
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *\li nanoseconds < 1000000000.
+ */
+
+void
+isc_time_settoepoch(isc_time_t *t);
+/*%<
+ * Set 't' to the time of the epoch.
+ *
+ * Notes:
+ *\li The date of the epoch is platform-dependent.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+bool
+isc_time_isepoch(const isc_time_t *t);
+/*%<
+ * Returns true iff. 't' is the epoch ("time zero").
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+isc_result_t
+isc_time_now(isc_time_t *t);
+/*%<
+ * Set 't' to the current absolute time.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ * Getting the time from the system failed.
+ *\li Out of range
+ * The time from the system is too large to be represented
+ * in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i);
+/*%<
+ * Set *t to the current absolute time + i.
+ *
+ * Note:
+ *\li This call is equivalent to:
+ *
+ *\code
+ * isc_time_now(t);
+ * isc_time_add(t, i, t);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li 't' and 'i' are valid pointers.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ * Getting the time from the system failed.
+ *\li Out of range
+ * The interval added to the time from the system is too large to
+ * be represented in the current definition of isc_time_t.
+ */
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2);
+/*%<
+ * Compare the times referenced by 't1' and 't2'
+ *
+ * Requires:
+ *
+ *\li 't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ *
+ *\li -1 t1 < t2 (comparing times, not pointers)
+ *\li 0 t1 = t2
+ *\li 1 t1 > t2
+ */
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result);
+/*%<
+ * Add 'i' to 't', storing the result in 'result'.
+ *
+ * Requires:
+ *
+ *\li 't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ *\li Success
+ *\li Out of range
+ * The interval added to the time is too large to
+ * be represented in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+ isc_time_t *result);
+/*%<
+ * Subtract 'i' from 't', storing the result in 'result'.
+ *
+ * Requires:
+ *
+ *\li 't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ *\li Success
+ *\li Out of range
+ * The interval is larger than the time since the epoch.
+ */
+
+uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2);
+/*%<
+ * Find the difference in microseconds between time t1 and time t2.
+ * t2 is the subtrahend of t1; ie, difference = t1 - t2.
+ *
+ * Requires:
+ *
+ *\li 't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ *\li The difference of t1 - t2, or 0 if t1 <= t2.
+ */
+
+uint32_t
+isc_time_seconds(const isc_time_t *t);
+/*%<
+ * Return the number of seconds since the epoch stored in a time structure.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+isc_result_t
+isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp);
+/*%<
+ * Ensure the number of seconds in an isc_time_t is representable by a time_t.
+ *
+ * Notes:
+ *\li The number of seconds stored in an isc_time_t might be larger
+ * than the number of seconds a time_t is able to handle. Since
+ * time_t is mostly opaque according to the ANSI/ISO standard
+ * (essentially, all you can be sure of is that it is an arithmetic type,
+ * not even necessarily integral), it can be tricky to ensure that
+ * the isc_time_t is in the range a time_t can handle. Use this
+ * function in place of isc_time_seconds() any time you need to set a
+ * time_t from an isc_time_t.
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *
+ * Returns:
+ *\li Success
+ *\li Out of range
+ */
+
+uint32_t
+isc_time_nanoseconds(const isc_time_t *t);
+/*%<
+ * Return the number of nanoseconds stored in a time structure.
+ *
+ * Notes:
+ *\li This is the number of nanoseconds in excess of the number
+ * of seconds since the epoch; it will always be less than one
+ * full second.
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *
+ * Ensures:
+ *\li The returned value is less than 1*10^9.
+ */
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using a format like "30-Aug-2000 04:06:47.997" and the local time zone.
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using a format like "Mon, 30 Aug 2000 04:06:47 GMT"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+isc_result_t
+isc_time_parsehttptimestamp(char *input, isc_time_t *t);
+/*%<
+ * Parse the time in 'input' into the isc_time_t pointed to by 't',
+ * expecting a format like "Mon, 30 Aug 2000 04:06:47 GMT"
+ *
+ * Requires:
+ *\li 'buf' and 't' are not NULL.
+ */
+
+void
+isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ssZ"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sssZ"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TIME_H */
diff --git a/lib/isc/unix/include/pkcs11/Makefile.in b/lib/isc/unix/include/pkcs11/Makefile.in
new file mode 100644
index 0000000..420fec1
--- /dev/null
+++ b/lib/isc/unix/include/pkcs11/Makefile.in
@@ -0,0 +1,31 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+HEADERS = cryptoki.h
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/pkcs11
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/pkcs11 || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/pkcs11/$$i || exit 1; \
+ done
diff --git a/lib/isc/unix/include/pkcs11/cryptoki.h b/lib/isc/unix/include/pkcs11/cryptoki.h
new file mode 100644
index 0000000..7dc48b0
--- /dev/null
+++ b/lib/isc/unix/include/pkcs11/cryptoki.h
@@ -0,0 +1,66 @@
+/* cryptoki.h include file for PKCS #11. */
+/*
+ * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
+ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* $Revision: 1.3 $ */
+
+/*
+ * Portions Copyright RSA Security Inc.
+ *
+ * License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* This is a sample file containing the top level include directives
+ * for building Unix Cryptoki libraries and applications.
+ */
+
+#ifndef ___CRYPTOKI_H_INC___
+#define ___CRYPTOKI_H_INC___
+
+#define CK_PTR *
+
+#define CK_DEFINE_FUNCTION(returnType, name) \
+ returnType name
+
+#define CK_DECLARE_FUNCTION(returnType, name) \
+ returnType name
+
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ returnType (* name)
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+ returnType (* name)
+
+/* NULL is in unistd.h */
+#include <unistd.h>
+#define NULL_PTR NULL
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+#include <pkcs11/pkcs11.h>
+
+#endif /* ___CRYPTOKI_H_INC___ */
diff --git a/lib/isc/unix/interfaceiter.c b/lib/isc/unix/interfaceiter.c
new file mode 100644
index 0000000..4df4d34
--- /dev/null
+++ b/lib/isc/unix/interfaceiter.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h> /* Required for ifiter_ioctl.c. */
+#endif
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <isc/interfaceiter.h>
+#include <isc/log.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/net.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+/* Must follow <isc/net.h>. */
+#ifdef HAVE_NET_IF6_H
+#include <net/if6.h>
+#endif
+#include <net/if.h>
+
+/* Common utility functions */
+
+/*%
+ * Extract the network address part from a "struct sockaddr".
+ * \brief
+ * The address family is given explicitly
+ * instead of using src->sa_family, because the latter does not work
+ * for copying a network mask obtained by SIOCGIFNETMASK (it does
+ * not have a valid address family).
+ */
+
+static void
+get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
+ char *ifname)
+{
+ struct sockaddr_in6 *sa6;
+
+#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
+ !defined(ISC_PLATFORM_HAVESCOPEID)
+ UNUSED(ifname);
+#endif
+
+ /* clear any remaining value for safety */
+ memset(dst, 0, sizeof(*dst));
+
+ dst->family = family;
+ switch (family) {
+ case AF_INET:
+ memmove(&dst->type.in,
+ &((struct sockaddr_in *) src)->sin_addr,
+ sizeof(struct in_addr));
+ break;
+ case AF_INET6:
+ sa6 = (struct sockaddr_in6 *)src;
+ memmove(&dst->type.in6, &sa6->sin6_addr,
+ sizeof(struct in6_addr));
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ if (sa6->sin6_scope_id != 0)
+ isc_netaddr_setzone(dst, sa6->sin6_scope_id);
+ else {
+ /*
+ * BSD variants embed scope zone IDs in the 128bit
+ * address as a kernel internal form. Unfortunately,
+ * the embedded IDs are not hidden from applications
+ * when getting access to them by sysctl or ioctl.
+ * We convert the internal format to the pure address
+ * part and the zone ID part.
+ * Since multicast addresses should not appear here
+ * and they cannot be distinguished from netmasks,
+ * we only consider unicast link-local addresses.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
+ uint16_t zone16;
+
+ memmove(&zone16, &sa6->sin6_addr.s6_addr[2],
+ sizeof(zone16));
+ zone16 = ntohs(zone16);
+ if (zone16 != 0) {
+ /* the zone ID is embedded */
+ isc_netaddr_setzone(dst,
+ (uint32_t)zone16);
+ dst->type.in6.s6_addr[2] = 0;
+ dst->type.in6.s6_addr[3] = 0;
+#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
+ } else if (ifname != NULL) {
+ unsigned int zone;
+
+ /*
+ * sin6_scope_id is still not provided,
+ * but the corresponding interface name
+ * is know. Use the interface ID as
+ * the link ID.
+ */
+ zone = if_nametoindex(ifname);
+ if (zone != 0) {
+ isc_netaddr_setzone(dst,
+ (uint32_t)zone);
+ }
+#endif
+ }
+ }
+ }
+#endif
+ break;
+ default:
+ INSIST(0);
+ break;
+ }
+}
+
+/*
+ * Include system-dependent code.
+ */
+
+#ifdef __linux
+#define ISC_IF_INET6_SZ \
+ sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
+static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *);
+static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *);
+static void linux_if_inet6_first(isc_interfaceiter_t *iter);
+#endif
+
+#if HAVE_GETIFADDRS
+#include "ifiter_getifaddrs.c"
+#elif HAVE_IFLIST_SYSCTL
+#include "ifiter_sysctl.c"
+#else
+#include "ifiter_ioctl.c"
+#endif
+
+#ifdef __linux
+static void
+linux_if_inet6_first(isc_interfaceiter_t *iter) {
+ if (iter->proc != NULL) {
+ rewind(iter->proc);
+ (void)linux_if_inet6_next(iter);
+ } else
+ iter->valid = ISC_R_NOMORE;
+}
+
+static isc_result_t
+linux_if_inet6_next(isc_interfaceiter_t *iter) {
+ if (iter->proc != NULL &&
+ fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
+ iter->valid = ISC_R_SUCCESS;
+ else
+ iter->valid = ISC_R_NOMORE;
+ return (iter->valid);
+}
+
+static isc_result_t
+linux_if_inet6_current(isc_interfaceiter_t *iter) {
+ char address[33];
+ char name[IF_NAMESIZE+1];
+ struct in6_addr addr6;
+ unsigned int ifindex, prefix, flag3, flag4;
+ int res;
+ unsigned int i;
+
+ if (iter->valid != ISC_R_SUCCESS)
+ return (iter->valid);
+ if (iter->proc == NULL) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
+ "/proc/net/if_inet6:iter->proc == NULL");
+ return (ISC_R_FAILURE);
+ }
+
+ res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
+ address, &ifindex, &prefix, &flag3, &flag4, name);
+ if (res != 6) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
+ "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
+ res);
+ return (ISC_R_FAILURE);
+ }
+ if (strlen(address) != 32) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
+ "/proc/net/if_inet6:strlen(%s) != 32", address);
+ return (ISC_R_FAILURE);
+ }
+ for (i = 0; i < 16; i++) {
+ unsigned char byte;
+ static const char hex[] = "0123456789abcdef";
+ byte = ((strchr(hex, address[i * 2]) - hex) << 4) |
+ (strchr(hex, address[i * 2 + 1]) - hex);
+ addr6.s6_addr[i] = byte;
+ }
+ iter->current.af = AF_INET6;
+ iter->current.flags = INTERFACE_F_UP;
+ isc_netaddr_fromin6(&iter->current.address, &addr6);
+ if (isc_netaddr_islinklocal(&iter->current.address)) {
+ isc_netaddr_setzone(&iter->current.address,
+ (uint32_t)ifindex);
+ }
+ for (i = 0; i < 16; i++) {
+ if (prefix > 8) {
+ addr6.s6_addr[i] = 0xff;
+ prefix -= 8;
+ } else {
+ addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
+ prefix = 0;
+ }
+ }
+ isc_netaddr_fromin6(&iter->current.netmask, &addr6);
+ strlcpy(iter->current.name, name, sizeof(iter->current.name));
+ return (ISC_R_SUCCESS);
+}
+#endif
+
+/*
+ * The remaining code is common to the sysctl and ioctl case.
+ */
+
+isc_result_t
+isc_interfaceiter_current(isc_interfaceiter_t *iter,
+ isc_interface_t *ifdata)
+{
+ REQUIRE(iter->result == ISC_R_SUCCESS);
+ memmove(ifdata, &iter->current, sizeof(*ifdata));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_interfaceiter_first(isc_interfaceiter_t *iter) {
+ isc_result_t result;
+
+ REQUIRE(VALID_IFITER(iter));
+
+ internal_first(iter);
+ for (;;) {
+ result = internal_current(iter);
+ if (result != ISC_R_IGNORE)
+ break;
+ result = internal_next(iter);
+ if (result != ISC_R_SUCCESS)
+ break;
+ }
+ iter->result = result;
+ return (result);
+}
+
+isc_result_t
+isc_interfaceiter_next(isc_interfaceiter_t *iter) {
+ isc_result_t result;
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE(iter->result == ISC_R_SUCCESS);
+
+ for (;;) {
+ result = internal_next(iter);
+ if (result != ISC_R_SUCCESS)
+ break;
+ result = internal_current(iter);
+ if (result != ISC_R_IGNORE)
+ break;
+ }
+ iter->result = result;
+ return (result);
+}
+
+void
+isc_interfaceiter_destroy(isc_interfaceiter_t **iterp)
+{
+ isc_interfaceiter_t *iter;
+ REQUIRE(iterp != NULL);
+ iter = *iterp;
+ REQUIRE(VALID_IFITER(iter));
+
+ internal_destroy(iter);
+ if (iter->buf != NULL)
+ isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
+
+ iter->magic = 0;
+ isc_mem_put(iter->mctx, iter, sizeof(*iter));
+ *iterp = NULL;
+}
diff --git a/lib/isc/unix/ipv6.c b/lib/isc/unix/ipv6.c
new file mode 100644
index 0000000..eb77377
--- /dev/null
+++ b/lib/isc/unix/ipv6.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/ipv6.h>
+
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
diff --git a/lib/isc/unix/keyboard.c b/lib/isc/unix/keyboard.c
new file mode 100644
index 0000000..cb5f116
--- /dev/null
+++ b/lib/isc/unix/keyboard.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <isc/keyboard.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_keyboard_open(isc_keyboard_t *keyboard) {
+ int fd;
+ isc_result_t ret;
+ struct termios current_mode;
+
+ REQUIRE(keyboard != NULL);
+
+ fd = open("/dev/tty", O_RDONLY, 0);
+ if (fd < 0)
+ return (ISC_R_IOERROR);
+
+ keyboard->fd = fd;
+
+ if (tcgetattr(fd, &keyboard->saved_mode) < 0) {
+ ret = ISC_R_IOERROR;
+ goto errout;
+ }
+
+ current_mode = keyboard->saved_mode;
+
+ current_mode.c_iflag &=
+ ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+ current_mode.c_oflag &= ~OPOST;
+ current_mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+ current_mode.c_cflag &= ~(CSIZE|PARENB);
+ current_mode.c_cflag |= CS8;
+
+ current_mode.c_cc[VMIN] = 1;
+ current_mode.c_cc[VTIME] = 0;
+ if (tcsetattr(fd, TCSAFLUSH, &current_mode) < 0) {
+ ret = ISC_R_IOERROR;
+ goto errout;
+ }
+
+ keyboard->result = ISC_R_SUCCESS;
+
+ return (ISC_R_SUCCESS);
+
+ errout:
+ close (fd);
+
+ return (ret);
+}
+
+isc_result_t
+isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleeptime) {
+ REQUIRE(keyboard != NULL);
+
+ if (sleeptime > 0 && keyboard->result != ISC_R_CANCELED)
+ (void)sleep(sleeptime);
+
+ (void)tcsetattr(keyboard->fd, TCSAFLUSH, &keyboard->saved_mode);
+ (void)close(keyboard->fd);
+
+ keyboard->fd = -1;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp) {
+ ssize_t cc;
+ unsigned char c;
+ cc_t *controlchars;
+
+ REQUIRE(keyboard != NULL);
+ REQUIRE(cp != NULL);
+
+ cc = read(keyboard->fd, &c, 1);
+ if (cc < 0) {
+ keyboard->result = ISC_R_IOERROR;
+ return (keyboard->result);
+ }
+
+ controlchars = keyboard->saved_mode.c_cc;
+ if (c == controlchars[VINTR] || c == controlchars[VQUIT]) {
+ keyboard->result = ISC_R_CANCELED;
+ return (keyboard->result);
+ }
+
+ *cp = c;
+
+ return (ISC_R_SUCCESS);
+}
+
+bool
+isc_keyboard_canceled(isc_keyboard_t *keyboard) {
+ return (keyboard->result == ISC_R_CANCELED);
+}
diff --git a/lib/isc/unix/meminfo.c b/lib/isc/unix/meminfo.c
new file mode 100644
index 0000000..ad750a7
--- /dev/null
+++ b/lib/isc/unix/meminfo.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <isc/meminfo.h>
+#include <inttypes.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+
+uint64_t
+isc_meminfo_totalphys(void) {
+#if defined(CTL_HW) && (defined(HW_PHYSMEM64) || defined(HW_MEMSIZE))
+ int mib[2];
+ mib[0] = CTL_HW;
+#if defined(HW_MEMSIZE)
+ mib[1] = HW_MEMSIZE;
+#elif defined(HW_PHYSMEM64)
+ mib[1] = HW_PHYSMEM64;
+#endif
+ uint64_t size = 0;
+ size_t len = sizeof(size);
+ if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
+ return (size);
+#endif
+#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
+ return ((size_t) (sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)));
+#endif
+ return (0);
+}
diff --git a/lib/isc/unix/net.c b/lib/isc/unix/net.c
new file mode 100644
index 0000000..efe17bd
--- /dev/null
+++ b/lib/isc/unix/net.c
@@ -0,0 +1,913 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#if defined(HAVE_SYS_SYSCTL_H)
+#if defined(HAVE_SYS_PARAM_H)
+#include <sys/param.h>
+#endif
+#include <sys/sysctl.h>
+#endif
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <isc/log.h>
+#include <isc/msgs.h>
+#include <isc/net.h>
+#include <isc/netdb.h>
+#include <isc/once.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#ifndef ISC_SOCKADDR_LEN_T
+#define ISC_SOCKADDR_LEN_T unsigned int
+#endif
+
+/*%
+ * Definitions about UDP port range specification. This is a total mess of
+ * portability variants: some use sysctl (but the sysctl names vary), some use
+ * system-specific interfaces, some have the same interface for IPv4 and IPv6,
+ * some separate them, etc...
+ */
+
+/*%
+ * The last resort defaults: use all non well known port space
+ */
+#ifndef ISC_NET_PORTRANGELOW
+#define ISC_NET_PORTRANGELOW 1024
+#endif /* ISC_NET_PORTRANGELOW */
+#ifndef ISC_NET_PORTRANGEHIGH
+#define ISC_NET_PORTRANGEHIGH 65535
+#endif /* ISC_NET_PORTRANGEHIGH */
+
+#ifdef HAVE_SYSCTLBYNAME
+
+/*%
+ * sysctl variants
+ */
+#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
+#define USE_SYSCTL_PORTRANGE
+#define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
+#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
+#define SYSCTL_V6PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
+#define SYSCTL_V6PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
+#endif
+
+#ifdef __NetBSD__
+#define USE_SYSCTL_PORTRANGE
+#define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.anonportmin"
+#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.anonportmax"
+#define SYSCTL_V6PORTRANGE_LOW "net.inet6.ip6.anonportmin"
+#define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.anonportmax"
+#endif
+
+#else /* !HAVE_SYSCTLBYNAME */
+
+#ifdef __OpenBSD__
+#define USE_SYSCTL_PORTRANGE
+#define SYSCTL_V4PORTRANGE_LOW { CTL_NET, PF_INET, IPPROTO_IP, \
+ IPCTL_IPPORT_HIFIRSTAUTO }
+#define SYSCTL_V4PORTRANGE_HIGH { CTL_NET, PF_INET, IPPROTO_IP, \
+ IPCTL_IPPORT_HILASTAUTO }
+/* Same for IPv6 */
+#define SYSCTL_V6PORTRANGE_LOW SYSCTL_V4PORTRANGE_LOW
+#define SYSCTL_V6PORTRANGE_HIGH SYSCTL_V4PORTRANGE_HIGH
+#endif
+
+#endif /* HAVE_SYSCTLBYNAME */
+
+#if defined(ISC_PLATFORM_HAVEIPV6)
+# if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
+const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
+# endif
+
+# if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
+const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
+# endif
+
+# if defined(WANT_IPV6)
+static isc_once_t once_ipv6only = ISC_ONCE_INIT;
+
+# if defined(ISC_PLATFORM_HAVEIN6PKTINFO)
+static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
+# endif
+# endif /* WANT_IPV6 */
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+
+#ifndef ISC_CMSG_IP_TOS
+#ifdef __APPLE__
+#define ISC_CMSG_IP_TOS 0 /* As of 10.8.2. */
+#else /* ! __APPLE__ */
+#define ISC_CMSG_IP_TOS 1
+#endif /* ! __APPLE__ */
+#endif /* ! ISC_CMSG_IP_TOS */
+
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_once_t once_dscp = ISC_ONCE_INIT;
+
+static isc_result_t ipv4_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6_result = ISC_R_NOTFOUND;
+static isc_result_t unix_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
+static unsigned int dscp_result = 0;
+
+static isc_result_t
+try_proto(int domain) {
+ int s;
+ isc_result_t result = ISC_R_SUCCESS;
+ char strbuf[ISC_STRERRORSIZE];
+
+ s = socket(domain, SOCK_STREAM, 0);
+ if (s == -1) {
+ switch (errno) {
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT:
+#endif
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT:
+#endif
+#ifdef EPROTONOSUPPORT
+ case EPROTONOSUPPORT:
+#endif
+#ifdef EINVAL
+ case EINVAL:
+#endif
+ return (ISC_R_NOTFOUND);
+ default:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ if (domain == PF_INET6) {
+ struct sockaddr_in6 sin6;
+ unsigned int len;
+
+ /*
+ * Check to see if IPv6 is broken, as is common on Linux.
+ */
+ len = sizeof(sin6);
+ if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
+ {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "retrieving the address of an IPv6 "
+ "socket from the kernel failed.");
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "IPv6 is not supported.");
+ result = ISC_R_NOTFOUND;
+ } else {
+ if (len == sizeof(struct sockaddr_in6))
+ result = ISC_R_SUCCESS;
+ else {
+ isc_log_write(isc_lctx,
+ ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET,
+ ISC_LOG_ERROR,
+ "IPv6 structures in kernel and "
+ "user space do not match.");
+ isc_log_write(isc_lctx,
+ ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET,
+ ISC_LOG_ERROR,
+ "IPv6 is not supported.");
+ result = ISC_R_NOTFOUND;
+ }
+ }
+ }
+#endif
+#endif
+#endif
+
+ (void)close(s);
+
+ return (result);
+}
+
+static void
+initialize_action(void) {
+ ipv4_result = try_proto(PF_INET);
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ ipv6_result = try_proto(PF_INET6);
+#endif
+#endif
+#endif
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ unix_result = try_proto(PF_UNIX);
+#endif
+}
+
+static void
+initialize(void) {
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_net_probeipv4(void) {
+ initialize();
+ return (ipv4_result);
+}
+
+isc_result_t
+isc_net_probeipv6(void) {
+ initialize();
+ return (ipv6_result);
+}
+
+isc_result_t
+isc_net_probeunix(void) {
+ initialize();
+ return (unix_result);
+}
+
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+static void
+try_ipv6only(void) {
+#ifdef IPV6_V6ONLY
+ int s, on;
+ char strbuf[ISC_STRERRORSIZE];
+#endif
+ isc_result_t result;
+
+ result = isc_net_probeipv6();
+ if (result != ISC_R_SUCCESS) {
+ ipv6only_result = result;
+ return;
+ }
+
+#ifndef IPV6_V6ONLY
+ ipv6only_result = ISC_R_NOTFOUND;
+ return;
+#else
+ /* check for TCP sockets */
+ s = socket(PF_INET6, SOCK_STREAM, 0);
+ if (s == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ ipv6only_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
+ ipv6only_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ close(s);
+
+ /* check for UDP sockets */
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ ipv6only_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
+ ipv6only_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ ipv6only_result = ISC_R_SUCCESS;
+
+close:
+ close(s);
+ return;
+#endif /* IPV6_V6ONLY */
+}
+
+static void
+initialize_ipv6only(void) {
+ RUNTIME_CHECK(isc_once_do(&once_ipv6only,
+ try_ipv6only) == ISC_R_SUCCESS);
+}
+#endif /* WANT_IPV6 */
+
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+#ifdef WANT_IPV6
+static void
+try_ipv6pktinfo(void) {
+ int s, on;
+ char strbuf[ISC_STRERRORSIZE];
+ isc_result_t result;
+ int optname;
+
+ result = isc_net_probeipv6();
+ if (result != ISC_R_SUCCESS) {
+ ipv6pktinfo_result = result;
+ return;
+ }
+
+ /* we only use this for UDP sockets */
+ s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ ipv6pktinfo_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+#ifdef IPV6_RECVPKTINFO
+ optname = IPV6_RECVPKTINFO;
+#else
+ optname = IPV6_PKTINFO;
+#endif
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
+ ipv6pktinfo_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ ipv6pktinfo_result = ISC_R_SUCCESS;
+
+close:
+ close(s);
+ return;
+}
+
+static void
+initialize_ipv6pktinfo(void) {
+ RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
+ try_ipv6pktinfo) == ISC_R_SUCCESS);
+}
+#endif /* WANT_IPV6 */
+#endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+
+isc_result_t
+isc_net_probe_ipv6only(void) {
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+ initialize_ipv6only();
+#else
+ ipv6only_result = ISC_R_NOTFOUND;
+#endif
+#endif
+ return (ipv6only_result);
+}
+
+isc_result_t
+isc_net_probe_ipv6pktinfo(void) {
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+#ifdef WANT_IPV6
+ initialize_ipv6pktinfo();
+#else
+ ipv6pktinfo_result = ISC_R_NOTFOUND;
+#endif
+#endif
+#endif
+ return (ipv6pktinfo_result);
+}
+
+#if ISC_CMSG_IP_TOS || \
+ defined(ISC_NET_BSD44MSGHDR) && defined(IPV6_TCLASS) && defined(WANT_IPV6)
+
+static inline ISC_SOCKADDR_LEN_T
+cmsg_len(ISC_SOCKADDR_LEN_T len) {
+#ifdef CMSG_LEN
+ return (CMSG_LEN(len));
+#else
+ ISC_SOCKADDR_LEN_T hdrlen;
+
+ /*
+ * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
+ * is correct.
+ */
+ hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(((struct cmsghdr *)NULL));
+ return (hdrlen + len);
+#endif
+}
+
+static inline ISC_SOCKADDR_LEN_T
+cmsg_space(ISC_SOCKADDR_LEN_T len) {
+#ifdef CMSG_SPACE
+ return (CMSG_SPACE(len));
+#else
+ struct msghdr msg;
+ struct cmsghdr *cmsgp;
+ /*
+ * XXX: The buffer length is an ad-hoc value, but should be enough
+ * in a practical sense.
+ */
+ char dummybuf[sizeof(struct cmsghdr) + 1024];
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_control = dummybuf;
+ msg.msg_controllen = sizeof(dummybuf);
+
+ cmsgp = (struct cmsghdr *)dummybuf;
+ cmsgp->cmsg_len = cmsg_len(len);
+
+ cmsgp = CMSG_NXTHDR(&msg, cmsgp);
+ if (cmsgp != NULL)
+ return ((char *)cmsgp - (char *)msg.msg_control);
+ else
+ return (0);
+#endif
+}
+
+#ifdef ISC_NET_BSD44MSGHDR
+/*
+ * Make a fd non-blocking.
+ */
+static isc_result_t
+make_nonblock(int fd) {
+ int ret;
+ int flags;
+ char strbuf[ISC_STRERRORSIZE];
+#ifdef USE_FIONBIO_IOCTL
+ int on = 1;
+
+ ret = ioctl(fd, FIONBIO, (char *)&on);
+#else
+ flags = fcntl(fd, F_GETFL, 0);
+ flags |= PORT_NONBLOCK;
+ ret = fcntl(fd, F_SETFL, flags);
+#endif
+
+ if (ret == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+#ifdef USE_FIONBIO_IOCTL
+ "ioctl(%d, FIONBIO, &on): %s", fd,
+#else
+ "fcntl(%d, F_SETFL, %d): %s", fd, flags,
+#endif
+ strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static bool
+cmsgsend(int s, int level, int type, struct addrinfo *res) {
+ char strbuf[ISC_STRERRORSIZE];
+ struct sockaddr_storage ss;
+ ISC_SOCKADDR_LEN_T len = sizeof(ss);
+ struct msghdr msg;
+ union {
+ struct cmsghdr h;
+ unsigned char b[256];
+ } control;
+ struct cmsghdr *cmsgp;
+ int dscp = (46 << 2); /* Expedited forwarding. */
+ struct iovec iovec;
+ char buf[1] = { 0 };
+ isc_result_t result;
+
+ if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
+ "bind: %s", strbuf);
+ return (false);
+ }
+
+ if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
+ "getsockname: %s", strbuf);
+ return (false);
+ }
+
+ iovec.iov_base = buf;
+ iovec.iov_len = sizeof(buf);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (struct sockaddr *)&ss;
+ msg.msg_namelen = len;
+ msg.msg_iov = &iovec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = (void*)&control;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ cmsgp = msg.msg_control;
+
+ switch (type) {
+#ifdef IP_TOS
+ case IP_TOS:
+ memset(cmsgp, 0, cmsg_space(sizeof(char)));
+ cmsgp->cmsg_level = level;
+ cmsgp->cmsg_type = type;
+ cmsgp->cmsg_len = cmsg_len(sizeof(char));
+ *(unsigned char*)CMSG_DATA(cmsgp) = dscp;
+ msg.msg_controllen += cmsg_space(sizeof(char));
+ break;
+#endif
+#ifdef IPV6_TCLASS
+ case IPV6_TCLASS:
+ memset(cmsgp, 0, cmsg_space(sizeof(dscp)));
+ cmsgp->cmsg_level = level;
+ cmsgp->cmsg_type = type;
+ cmsgp->cmsg_len = cmsg_len(sizeof(dscp));
+ memmove(CMSG_DATA(cmsgp), &dscp, sizeof(dscp));
+ msg.msg_controllen += cmsg_space(sizeof(dscp));
+ break;
+#endif
+ default:
+ INSIST(0);
+ }
+
+ if (sendmsg(s, &msg, 0) < 0) {
+ int debug = ISC_LOG_DEBUG(10);
+ const char *typestr;
+ const char *msgstr;
+ switch (errno) {
+#ifdef ENOPROTOOPT
+ case ENOPROTOOPT:
+#endif
+#ifdef EOPNOTSUPP
+ case EOPNOTSUPP:
+#endif
+ case EINVAL:
+ case EPERM:
+ break;
+ default:
+ debug = ISC_LOG_NOTICE;
+ }
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ if (debug != ISC_LOG_NOTICE) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
+ "sendmsg: %s", strbuf);
+ } else {
+ typestr = (type == IP_TOS) ? "IP_TOS" : "IPV6_TCLASS";
+ msgstr = isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed");
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "probing "
+ "sendmsg() with %s=%02x %s: %s",
+ typestr, dscp, msgstr, strbuf);
+ }
+ return (false);
+ }
+
+ /*
+ * Make sure the message actually got sent.
+ */
+ result = make_nonblock(s);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ iovec.iov_base = buf;
+ iovec.iov_len = sizeof(buf);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (struct sockaddr *)&ss;
+ msg.msg_namelen = sizeof(ss);
+ msg.msg_iov = &iovec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ if (recvmsg(s, &msg, 0) < 0)
+ return (false);
+
+ return (true);
+}
+#endif
+#endif
+
+static void
+try_dscp_v4(void) {
+#ifdef IP_TOS
+ char strbuf[ISC_STRERRORSIZE];
+ struct addrinfo hints, *res0;
+ int s, dscp = 0, n;
+#ifdef IP_RECVTOS
+ int on = 1;
+#endif /* IP_RECVTOS */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+#ifdef AI_NUMERICHOST
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+#else
+ hints.ai_flags = AI_PASSIVE;
+#endif
+
+ n = getaddrinfo("127.0.0.1", NULL, &hints, &res0);
+ if (n != 0 || res0 == NULL) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
+ "getaddrinfo(127.0.0.1): %s", gai_strerror(n));
+ return;
+ }
+
+ s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol);
+
+ if (s == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
+ "socket: %s", strbuf);
+ freeaddrinfo(res0);
+ return;
+ }
+
+ if (setsockopt(s, IPPROTO_IP, IP_TOS, &dscp, sizeof(dscp)) == 0)
+ dscp_result |= ISC_NET_DSCPSETV4;
+
+#ifdef IP_RECVTOS
+ on = 1;
+ if (setsockopt(s, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on)) == 0)
+ dscp_result |= ISC_NET_DSCPRECVV4;
+#endif /* IP_RECVTOS */
+
+#ifdef ISC_NET_BSD44MSGHDR
+
+#if ISC_CMSG_IP_TOS
+ if (cmsgsend(s, IPPROTO_IP, IP_TOS, res0))
+ dscp_result |= ISC_NET_DSCPPKTV4;
+#endif /* ISC_CMSG_IP_TOS */
+
+#endif /* ISC_NET_BSD44MSGHDR */
+
+ freeaddrinfo(res0);
+ close(s);
+
+#endif /* IP_TOS */
+}
+
+static void
+try_dscp_v6(void) {
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+#ifdef IPV6_TCLASS
+ char strbuf[ISC_STRERRORSIZE];
+ struct addrinfo hints, *res0;
+ int s, dscp = 0, n;
+#if defined(IPV6_RECVTCLASS)
+ int on = 1;
+#endif /* IPV6_RECVTCLASS */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+#ifdef AI_NUMERICHOST
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+#else
+ hints.ai_flags = AI_PASSIVE;
+#endif
+
+ n = getaddrinfo("::1", NULL, &hints, &res0);
+ if (n != 0 || res0 == NULL) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
+ "getaddrinfo(::1): %s", gai_strerror(n));
+ return;
+ }
+
+ s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol);
+ if (s == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10),
+ "socket: %s", strbuf);
+ freeaddrinfo(res0);
+ return;
+ }
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &dscp, sizeof(dscp)) == 0)
+ dscp_result |= ISC_NET_DSCPSETV6;
+
+#ifdef IPV6_RECVTCLASS
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, sizeof(on)) == 0)
+ dscp_result |= ISC_NET_DSCPRECVV6;
+#endif /* IPV6_RECVTCLASS */
+
+#ifdef ISC_NET_BSD44MSGHDR
+ if (cmsgsend(s, IPPROTO_IPV6, IPV6_TCLASS, res0))
+ dscp_result |= ISC_NET_DSCPPKTV6;
+#endif /* ISC_NET_BSD44MSGHDR */
+
+ freeaddrinfo(res0);
+ close(s);
+
+#endif /* IPV6_TCLASS */
+#endif /* WANT_IPV6 */
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+}
+
+static void
+try_dscp(void) {
+ try_dscp_v4();
+ try_dscp_v6();
+}
+
+static void
+initialize_dscp(void) {
+ RUNTIME_CHECK(isc_once_do(&once_dscp, try_dscp) == ISC_R_SUCCESS);
+}
+
+unsigned int
+isc_net_probedscp(void) {
+ initialize_dscp();
+ return (dscp_result);
+}
+
+#if defined(USE_SYSCTL_PORTRANGE)
+#if defined(HAVE_SYSCTLBYNAME)
+static isc_result_t
+getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
+ int port_low, port_high;
+ size_t portlen;
+ const char *sysctlname_lowport, *sysctlname_hiport;
+
+ if (af == AF_INET) {
+ sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
+ sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
+ } else {
+ sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
+ sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
+ }
+ portlen = sizeof(port_low);
+ if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
+ NULL, 0) < 0) {
+ return (ISC_R_FAILURE);
+ }
+ portlen = sizeof(port_high);
+ if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
+ NULL, 0) < 0) {
+ return (ISC_R_FAILURE);
+ }
+ if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
+ return (ISC_R_RANGE);
+
+ *low = (in_port_t)port_low;
+ *high = (in_port_t)port_high;
+
+ return (ISC_R_SUCCESS);
+}
+#else /* !HAVE_SYSCTLBYNAME */
+static isc_result_t
+getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
+ int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
+ int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
+ int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
+ int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
+ int *mib_lo, *mib_hi, miblen;
+ int port_low, port_high;
+ size_t portlen;
+
+ if (af == AF_INET) {
+ mib_lo = mib_lo4;
+ mib_hi = mib_hi4;
+ miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
+ } else {
+ mib_lo = mib_lo6;
+ mib_hi = mib_hi6;
+ miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
+ }
+
+ portlen = sizeof(port_low);
+ if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
+ return (ISC_R_FAILURE);
+ }
+
+ portlen = sizeof(port_high);
+ if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
+ return (ISC_R_FAILURE);
+ }
+
+ if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
+ return (ISC_R_RANGE);
+
+ *low = (in_port_t) port_low;
+ *high = (in_port_t) port_high;
+
+ return (ISC_R_SUCCESS);
+}
+#endif /* HAVE_SYSCTLBYNAME */
+#endif /* USE_SYSCTL_PORTRANGE */
+
+isc_result_t
+isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
+ int result = ISC_R_FAILURE;
+#if !defined(USE_SYSCTL_PORTRANGE) && defined(__linux)
+ FILE *fp;
+#endif
+
+ REQUIRE(low != NULL && high != NULL);
+
+#if defined(USE_SYSCTL_PORTRANGE)
+ result = getudpportrange_sysctl(af, low, high);
+#elif defined(__linux)
+
+ UNUSED(af);
+
+ /*
+ * Linux local ports are address family agnostic.
+ */
+ fp = fopen("/proc/sys/net/ipv4/ip_local_port_range", "r");
+ if (fp != NULL) {
+ int n;
+ unsigned int l, h;
+
+ n = fscanf(fp, "%u %u", &l, &h);
+ if (n == 2 && (l & ~0xffff) == 0 && (h & ~0xffff) == 0) {
+ *low = l;
+ *high = h;
+ result = ISC_R_SUCCESS;
+ }
+ fclose(fp);
+ }
+#else
+ UNUSED(af);
+#endif
+
+ if (result != ISC_R_SUCCESS) {
+ *low = ISC_NET_PORTRANGELOW;
+ *high = ISC_NET_PORTRANGEHIGH;
+ }
+
+ return (ISC_R_SUCCESS); /* we currently never fail in this function */
+}
+
+void
+isc_net_disableipv4(void) {
+ initialize();
+ if (ipv4_result == ISC_R_SUCCESS)
+ ipv4_result = ISC_R_DISABLED;
+}
+
+void
+isc_net_disableipv6(void) {
+ initialize();
+ if (ipv6_result == ISC_R_SUCCESS)
+ ipv6_result = ISC_R_DISABLED;
+}
+
+void
+isc_net_enableipv4(void) {
+ initialize();
+ if (ipv4_result == ISC_R_DISABLED)
+ ipv4_result = ISC_R_SUCCESS;
+}
+
+void
+isc_net_enableipv6(void) {
+ initialize();
+ if (ipv6_result == ISC_R_DISABLED)
+ ipv6_result = ISC_R_SUCCESS;
+}
diff --git a/lib/isc/unix/os.c b/lib/isc/unix/os.c
new file mode 100644
index 0000000..8cff6b6
--- /dev/null
+++ b/lib/isc/unix/os.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <isc/os.h>
+
+
+#ifdef HAVE_SYSCONF
+
+#include <unistd.h>
+
+#ifndef __hpux
+static inline long
+sysconf_ncpus(void) {
+#if defined(_SC_NPROCESSORS_ONLN)
+ return sysconf((_SC_NPROCESSORS_ONLN));
+#elif defined(_SC_NPROC_ONLN)
+ return sysconf((_SC_NPROC_ONLN));
+#else
+ return (0);
+#endif
+}
+#endif
+#endif /* HAVE_SYSCONF */
+
+
+#ifdef __hpux
+
+#include <sys/pstat.h>
+
+static inline int
+hpux_ncpus(void) {
+ struct pst_dynamic psd;
+ if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) != -1)
+ return (psd.psd_proc_cnt);
+ else
+ return (0);
+}
+
+#endif /* __hpux */
+
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)
+#include <sys/types.h> /* for FreeBSD */
+#include <sys/param.h> /* for NetBSD */
+#include <sys/sysctl.h>
+
+static int
+sysctl_ncpus(void) {
+ int ncpu, result;
+ size_t len;
+
+ len = sizeof(ncpu);
+ result = sysctlbyname("hw.ncpu", &ncpu, &len , 0, 0);
+ if (result != -1)
+ return (ncpu);
+ return (0);
+}
+#endif
+
+unsigned int
+isc_os_ncpus(void) {
+ long ncpus = 0;
+
+#ifdef __hpux
+ ncpus = hpux_ncpus();
+#elif defined(HAVE_SYSCONF)
+ ncpus = sysconf_ncpus();
+#endif
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)
+ if (ncpus <= 0)
+ ncpus = sysctl_ncpus();
+#endif
+ if (ncpus <= 0)
+ ncpus = 1;
+
+ return ((unsigned int)ncpus);
+}
diff --git a/lib/isc/unix/pk11_api.c b/lib/isc/unix/pk11_api.c
new file mode 100644
index 0000000..bbc55af
--- /dev/null
+++ b/lib/isc/unix/pk11_api.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <string.h>
+#include <dlfcn.h>
+
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/stdio.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include <pkcs11/cryptoki.h>
+#include <pkcs11/pkcs11.h>
+
+#define KEEP_PKCS11_NAMES
+#include <pk11/pk11.h>
+#include <pk11/internal.h>
+
+static void *hPK11 = NULL;
+static char loaderrmsg[1024];
+
+CK_RV
+pkcs_C_Initialize(CK_VOID_PTR pReserved) {
+ CK_C_Initialize sym;
+
+ if (hPK11 != NULL)
+ return (CKR_LIBRARY_ALREADY_INITIALIZED);
+
+ hPK11 = dlopen(pk11_get_lib_name(), RTLD_NOW);
+
+ if (hPK11 == NULL) {
+ snprintf(loaderrmsg, sizeof(loaderrmsg),
+ "dlopen(\"%s\") failed: %s\n",
+ pk11_get_lib_name(), dlerror());
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ sym = (CK_C_Initialize)dlsym(hPK11, "C_Initialize");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(pReserved);
+}
+
+char *pk11_get_load_error_message(void) {
+ return (loaderrmsg);
+}
+
+CK_RV
+pkcs_C_Finalize(CK_VOID_PTR pReserved) {
+ CK_C_Finalize sym;
+ CK_RV rv;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ sym = (CK_C_Finalize)dlsym(hPK11, "C_Finalize");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ rv = (*sym)(pReserved);
+ if ((rv == CKR_OK) && (dlclose(hPK11) != 0))
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ hPK11 = NULL;
+ return (rv);
+}
+
+CK_RV
+pkcs_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
+ CK_ULONG_PTR pulCount)
+{
+ static CK_C_GetSlotList sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_GetSlotList)dlsym(hPK11, "C_GetSlotList");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(tokenPresent, pSlotList, pulCount);
+}
+
+CK_RV
+pkcs_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) {
+ static CK_C_GetTokenInfo sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_GetTokenInfo)dlsym(hPK11, "C_GetTokenInfo");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(slotID, pInfo);
+}
+
+CK_RV
+pkcs_C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
+ CK_MECHANISM_INFO_PTR pInfo)
+{
+ static CK_C_GetMechanismInfo sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_GetMechanismInfo)dlsym(hPK11,
+ "C_GetMechanismInfo");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(slotID, type, pInfo);
+}
+
+CK_RV
+pkcs_C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
+ CK_VOID_PTR pApplication,
+ CK_RV (*Notify) (CK_SESSION_HANDLE hSession,
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication),
+ CK_SESSION_HANDLE_PTR phSession)
+{
+ static CK_C_OpenSession sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ hPK11 = dlopen(pk11_get_lib_name(), RTLD_NOW);
+ if (hPK11 == NULL) {
+ snprintf(loaderrmsg, sizeof(loaderrmsg),
+ "dlopen(\"%s\") failed: %s\n",
+ pk11_get_lib_name(), dlerror());
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_OpenSession)dlsym(hPK11, "C_OpenSession");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(slotID, flags, pApplication, Notify, phSession);
+}
+
+CK_RV
+pkcs_C_CloseSession(CK_SESSION_HANDLE hSession) {
+ static CK_C_CloseSession sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_CloseSession)dlsym(hPK11, "C_CloseSession");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession);
+}
+
+CK_RV
+pkcs_C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
+ CK_CHAR_PTR pPin, CK_ULONG usPinLen)
+{
+ static CK_C_Login sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_Login)dlsym(hPK11, "C_Login");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, userType, pPin, usPinLen);
+}
+
+CK_RV
+pkcs_C_Logout(CK_SESSION_HANDLE hSession) {
+ static CK_C_Logout sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_Logout)dlsym(hPK11, "C_Logout");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession);
+}
+
+CK_RV
+pkcs_C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG usCount, CK_OBJECT_HANDLE_PTR phObject)
+{
+ static CK_C_CreateObject sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_CreateObject)dlsym(hPK11, "C_CreateObject");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pTemplate, usCount, phObject);
+}
+
+CK_RV
+pkcs_C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) {
+ static CK_C_DestroyObject sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_DestroyObject)dlsym(hPK11, "C_DestroyObject");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, hObject);
+}
+
+CK_RV
+pkcs_C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount)
+{
+ static CK_C_GetAttributeValue sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_GetAttributeValue)dlsym(hPK11,
+ "C_GetAttributeValue");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, hObject, pTemplate, usCount);
+}
+
+CK_RV
+pkcs_C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount)
+{
+ static CK_C_SetAttributeValue sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_SetAttributeValue)dlsym(hPK11,
+ "C_SetAttributeValue");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, hObject, pTemplate, usCount);
+}
+
+CK_RV
+pkcs_C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG usCount)
+{
+ static CK_C_FindObjectsInit sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_FindObjectsInit)dlsym(hPK11, "C_FindObjectsInit");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pTemplate, usCount);
+}
+
+CK_RV
+pkcs_C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject,
+ CK_ULONG usMaxObjectCount, CK_ULONG_PTR pusObjectCount)
+{
+ static CK_C_FindObjects sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_FindObjects)dlsym(hPK11, "C_FindObjects");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, phObject, usMaxObjectCount, pusObjectCount);
+}
+
+CK_RV
+pkcs_C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
+{
+ static CK_C_FindObjectsFinal sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_FindObjectsFinal)dlsym(hPK11,
+ "C_FindObjectsFinal");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession);
+}
+
+CK_RV
+pkcs_C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{
+ static CK_C_EncryptInit sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_EncryptInit)dlsym(hPK11, "C_EncryptInit");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pMechanism, hKey);
+}
+
+CK_RV
+pkcs_C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
+ CK_ULONG_PTR pulEncryptedDataLen)
+{
+ static CK_C_Encrypt sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_Encrypt)dlsym(hPK11, "C_Encrypt");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pData, ulDataLen,
+ pEncryptedData, pulEncryptedDataLen);
+}
+
+CK_RV
+pkcs_C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) {
+ static CK_C_DigestInit sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_DigestInit)dlsym(hPK11, "C_DigestInit");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pMechanism);
+}
+
+CK_RV
+pkcs_C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen)
+{
+ static CK_C_DigestUpdate sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_DigestUpdate)dlsym(hPK11, "C_DigestUpdate");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pPart, ulPartLen);
+}
+
+CK_RV
+pkcs_C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
+ CK_ULONG_PTR pulDigestLen)
+{
+ static CK_C_DigestFinal sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_DigestFinal)dlsym(hPK11, "C_DigestFinal");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pDigest, pulDigestLen);
+}
+
+CK_RV
+pkcs_C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{
+ static CK_C_SignInit sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_SignInit)dlsym(hPK11, "C_SignInit");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pMechanism, hKey);
+}
+
+CK_RV
+pkcs_C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
+ CK_ULONG_PTR pulSignatureLen)
+{
+ static CK_C_Sign sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_Sign)dlsym(hPK11, "C_Sign");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pData, ulDataLen, pSignature, pulSignatureLen);
+}
+
+CK_RV
+pkcs_C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen)
+{
+ static CK_C_SignUpdate sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_SignUpdate)dlsym(hPK11, "C_SignUpdate");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pPart, ulPartLen);
+}
+
+CK_RV
+pkcs_C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
+ CK_ULONG_PTR pulSignatureLen)
+{
+ static CK_C_SignFinal sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_SignFinal)dlsym(hPK11, "C_SignFinal");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pSignature, pulSignatureLen);
+}
+
+CK_RV
+pkcs_C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{
+ static CK_C_VerifyInit sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_VerifyInit)dlsym(hPK11, "C_VerifyInit");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pMechanism, hKey);
+}
+
+CK_RV
+pkcs_C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
+ CK_ULONG ulSignatureLen)
+{
+ static CK_C_Verify sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_Verify)dlsym(hPK11, "C_Verify");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pData, ulDataLen, pSignature, ulSignatureLen);
+}
+
+CK_RV
+pkcs_C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen)
+{
+ static CK_C_VerifyUpdate sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_VerifyUpdate)dlsym(hPK11, "C_VerifyUpdate");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pPart, ulPartLen);
+}
+
+CK_RV
+pkcs_C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
+ CK_ULONG ulSignatureLen)
+{
+ static CK_C_VerifyFinal sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_VerifyFinal)dlsym(hPK11, "C_VerifyFinal");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pSignature, ulSignatureLen);
+}
+
+CK_RV
+pkcs_C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+ CK_OBJECT_HANDLE_PTR phKey)
+{
+ static CK_C_GenerateKey sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_GenerateKey)dlsym(hPK11, "C_GenerateKey");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pMechanism, pTemplate, ulCount, phKey);
+}
+
+CK_RV
+pkcs_C_GenerateKeyPair(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+ CK_ULONG usPublicKeyAttributeCount,
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+ CK_ULONG usPrivateKeyAttributeCount,
+ CK_OBJECT_HANDLE_PTR phPrivateKey,
+ CK_OBJECT_HANDLE_PTR phPublicKey)
+{
+ static CK_C_GenerateKeyPair sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_GenerateKeyPair)dlsym(hPK11, "C_GenerateKeyPair");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession,
+ pMechanism,
+ pPublicKeyTemplate,
+ usPublicKeyAttributeCount,
+ pPrivateKeyTemplate,
+ usPrivateKeyAttributeCount,
+ phPrivateKey,
+ phPublicKey);
+}
+
+CK_RV
+pkcs_C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
+{
+ static CK_C_DeriveKey sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_DeriveKey)dlsym(hPK11, "C_DeriveKey");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession,
+ pMechanism,
+ hBaseKey,
+ pTemplate,
+ ulAttributeCount,
+ phKey);
+}
+
+CK_RV
+pkcs_C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
+ CK_ULONG ulSeedLen)
+{
+ static CK_C_SeedRandom sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_SeedRandom)dlsym(hPK11, "C_SeedRandom");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pSeed, ulSeedLen);
+}
+
+CK_RV
+pkcs_C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData,
+ CK_ULONG ulRandomLen)
+{
+ static CK_C_GenerateRandom sym = NULL;
+ static void *pPK11 = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if ((sym == NULL) || (hPK11 != pPK11)) {
+ pPK11 = hPK11;
+ sym = (CK_C_GenerateRandom)dlsym(hPK11, "C_GenerateRandom");
+ }
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, RandomData, ulRandomLen);
+}
diff --git a/lib/isc/unix/resource.c b/lib/isc/unix/resource.c
new file mode 100644
index 0000000..6d5c5aa
--- /dev/null
+++ b/lib/isc/unix/resource.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <sys/types.h>
+#include <sys/time.h> /* Required on some systems for <sys/resource.h>. */
+#include <sys/resource.h>
+
+#include <isc/platform.h>
+#include <isc/resource.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#ifdef __linux__
+#include <linux/fs.h> /* To get the large NR_OPEN. */
+#endif
+
+#if defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
+#include <sys/dyntune.h>
+#endif
+
+#include "errno2result.h"
+
+static isc_result_t
+resource2rlim(isc_resource_t resource, int *rlim_resource) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ switch (resource) {
+ case isc_resource_coresize:
+ *rlim_resource = RLIMIT_CORE;
+ break;
+ case isc_resource_cputime:
+ *rlim_resource = RLIMIT_CPU;
+ break;
+ case isc_resource_datasize:
+ *rlim_resource = RLIMIT_DATA;
+ break;
+ case isc_resource_filesize:
+ *rlim_resource = RLIMIT_FSIZE;
+ break;
+ case isc_resource_lockedmemory:
+#ifdef RLIMIT_MEMLOCK
+ *rlim_resource = RLIMIT_MEMLOCK;
+#else
+ result = ISC_R_NOTIMPLEMENTED;
+#endif
+ break;
+ case isc_resource_openfiles:
+#ifdef RLIMIT_NOFILE
+ *rlim_resource = RLIMIT_NOFILE;
+#else
+ result = ISC_R_NOTIMPLEMENTED;
+#endif
+ break;
+ case isc_resource_processes:
+#ifdef RLIMIT_NPROC
+ *rlim_resource = RLIMIT_NPROC;
+#else
+ result = ISC_R_NOTIMPLEMENTED;
+#endif
+ break;
+ case isc_resource_residentsize:
+#ifdef RLIMIT_RSS
+ *rlim_resource = RLIMIT_RSS;
+#else
+ result = ISC_R_NOTIMPLEMENTED;
+#endif
+ break;
+ case isc_resource_stacksize:
+ *rlim_resource = RLIMIT_STACK;
+ break;
+ default:
+ /*
+ * This test is not very robust if isc_resource_t
+ * changes, but generates a clear assertion message.
+ */
+ REQUIRE(resource >= isc_resource_coresize &&
+ resource <= isc_resource_stacksize);
+
+ result = ISC_R_RANGE;
+ break;
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
+ struct rlimit rl;
+ ISC_PLATFORM_RLIMITTYPE rlim_value;
+ int unixresult;
+ int unixresource;
+ isc_result_t result;
+
+ result = resource2rlim(resource, &unixresource);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (value == ISC_RESOURCE_UNLIMITED)
+ rlim_value = RLIM_INFINITY;
+
+ else {
+ /*
+ * isc_resourcevalue_t was chosen as an unsigned 64 bit
+ * integer so that it could contain the maximum range of
+ * reasonable values. Unfortunately, this exceeds the typical
+ * range on Unix systems. Ensure the range of
+ * ISC_PLATFORM_RLIMITTYPE is not overflowed.
+ */
+ isc_resourcevalue_t rlim_max;
+ bool rlim_t_is_signed =
+ (((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0);
+
+ if (rlim_t_is_signed)
+ rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 <<
+ (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1));
+ else
+ rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1;
+
+ if (value > rlim_max)
+ value = rlim_max;
+
+ rlim_value = value;
+ }
+
+ rl.rlim_cur = rl.rlim_max = rlim_value;
+ unixresult = setrlimit(unixresource, &rl);
+
+ if (unixresult == 0)
+ return (ISC_R_SUCCESS);
+
+#if defined(OPEN_MAX) && defined(__APPLE__)
+ /*
+ * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the
+ * maximum possible value is OPEN_MAX. BIND8 used to use
+ * sysconf(_SC_OPEN_MAX) for such a case, but this value is much
+ * smaller than OPEN_MAX and is not really effective.
+ */
+ if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
+ rl.rlim_cur = OPEN_MAX;
+ unixresult = setrlimit(unixresource, &rl);
+ if (unixresult == 0)
+ return (ISC_R_SUCCESS);
+ }
+#elif defined(__linux__)
+#ifndef NR_OPEN
+#define NR_OPEN (1024*1024)
+#endif
+
+ /*
+ * Some Linux kernels don't accept RLIM_INFINIT; the maximum
+ * possible value is the NR_OPEN defined in linux/fs.h.
+ */
+ if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
+ rl.rlim_cur = rl.rlim_max = NR_OPEN;
+ unixresult = setrlimit(unixresource, &rl);
+ if (unixresult == 0)
+ return (ISC_R_SUCCESS);
+ }
+#elif defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
+ if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
+ uint64_t maxfiles;
+ if (gettune("maxfiles_lim", &maxfiles) == 0) {
+ rl.rlim_cur = rl.rlim_max = maxfiles;
+ unixresult = setrlimit(unixresource, &rl);
+ if (unixresult == 0)
+ return (ISC_R_SUCCESS);
+ }
+ }
+#endif
+ if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
+ if (getrlimit(unixresource, &rl) == 0) {
+ rl.rlim_cur = rl.rlim_max;
+ unixresult = setrlimit(unixresource, &rl);
+ if (unixresult == 0)
+ return (ISC_R_SUCCESS);
+ }
+ }
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+ int unixresult;
+ int unixresource;
+ struct rlimit rl;
+ isc_result_t result;
+
+ result = resource2rlim(resource, &unixresource);
+ if (result == ISC_R_SUCCESS) {
+ unixresult = getrlimit(unixresource, &rl);
+ INSIST(unixresult == 0);
+ *value = rl.rlim_max;
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+ int unixresult;
+ int unixresource;
+ struct rlimit rl;
+ isc_result_t result;
+
+ result = resource2rlim(resource, &unixresource);
+ if (result == ISC_R_SUCCESS) {
+ unixresult = getrlimit(unixresource, &rl);
+ INSIST(unixresult == 0);
+ *value = rl.rlim_cur;
+ }
+
+ return (result);
+}
diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c
new file mode 100644
index 0000000..5a40768
--- /dev/null
+++ b/lib/isc/unix/socket.c
@@ -0,0 +1,6848 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/buffer.h>
+#include <isc/bufferlist.h>
+#include <isc/condition.h>
+#include <isc/formatcheck.h>
+#include <isc/json.h>
+#include <isc/list.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/once.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/resource.h>
+#include <isc/socket.h>
+#include <isc/stats.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+#include <isc/xml.h>
+
+#ifdef ISC_PLATFORM_HAVESYSUNH
+#include <sys/un.h>
+#endif
+#ifdef ISC_PLATFORM_HAVEKQUEUE
+#include <sys/event.h>
+#endif
+#ifdef ISC_PLATFORM_HAVEEPOLL
+#include <sys/epoll.h>
+#endif
+#ifdef ISC_PLATFORM_HAVEDEVPOLL
+#if defined(HAVE_SYS_DEVPOLL_H)
+#include <sys/devpoll.h>
+#elif defined(HAVE_DEVPOLL_H)
+#include <devpoll.h>
+#endif
+#endif
+
+#include <netinet/tcp.h>
+
+#include "errno2result.h"
+
+/* See task.c about the following definition: */
+#ifdef ISC_PLATFORM_USETHREADS
+#define USE_WATCHER_THREAD
+#else
+#define USE_SHARED_MANAGER
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifndef USE_WATCHER_THREAD
+#include "socket_p.h"
+#include "../task_p.h"
+#endif /* USE_WATCHER_THREAD */
+
+#if defined(SO_BSDCOMPAT) && defined(__linux__)
+#include <sys/utsname.h>
+#endif
+
+#ifdef ISC_PLATFORM_HAVETFO
+#include <netinet/tcp.h>
+#endif
+
+/*%
+ * Choose the most preferable multiplex method.
+ */
+#ifdef ISC_PLATFORM_HAVEKQUEUE
+#define USE_KQUEUE
+#elif defined (ISC_PLATFORM_HAVEEPOLL)
+#define USE_EPOLL
+#elif defined (ISC_PLATFORM_HAVEDEVPOLL)
+#define USE_DEVPOLL
+typedef struct {
+ unsigned int want_read : 1,
+ want_write : 1;
+} pollinfo_t;
+#else
+#define USE_SELECT
+#endif /* ISC_PLATFORM_HAVEKQUEUE */
+
+#ifndef USE_WATCHER_THREAD
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
+struct isc_socketwait {
+ int nevents;
+};
+#elif defined (USE_SELECT)
+struct isc_socketwait {
+ fd_set *readset;
+ fd_set *writeset;
+ int nfds;
+ int maxfd;
+};
+#endif /* USE_KQUEUE */
+#endif /* !USE_WATCHER_THREAD */
+
+/*
+ * Set by the -T dscp option on the command line. If set to a value
+ * other than -1, we check to make sure DSCP values match it, and
+ * assert if not.
+ */
+int isc_dscp_check_value = -1;
+
+/*%
+ * Maximum number of allowable open sockets. This is also the maximum
+ * allowable socket file descriptor.
+ *
+ * Care should be taken before modifying this value for select():
+ * The API standard doesn't ensure select() accept more than (the system default
+ * of) FD_SETSIZE descriptors, and the default size should in fact be fine in
+ * the vast majority of cases. This constant should therefore be increased only
+ * when absolutely necessary and possible, i.e., the server is exhausting all
+ * available file descriptors (up to FD_SETSIZE) and the select() function
+ * and FD_xxx macros support larger values than FD_SETSIZE (which may not
+ * always by true, but we keep using some of them to ensure as much
+ * portability as possible). Note also that overall server performance
+ * may be rather worsened with a larger value of this constant due to
+ * inherent scalability problems of select().
+ *
+ * As a special note, this value shouldn't have to be touched if
+ * this is a build for an authoritative only DNS server.
+ */
+#ifndef ISC_SOCKET_MAXSOCKETS
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
+#ifdef TUNE_LARGE
+#define ISC_SOCKET_MAXSOCKETS 21000
+#else
+#define ISC_SOCKET_MAXSOCKETS 4096
+#endif /* TUNE_LARGE */
+#elif defined(USE_SELECT)
+#define ISC_SOCKET_MAXSOCKETS FD_SETSIZE
+#endif /* USE_KQUEUE... */
+#endif /* ISC_SOCKET_MAXSOCKETS */
+
+#ifdef USE_SELECT
+/*%
+ * Mac OS X needs a special definition to support larger values in select().
+ * We always define this because a larger value can be specified run-time.
+ */
+#ifdef __APPLE__
+#define _DARWIN_UNLIMITED_SELECT
+#endif /* __APPLE__ */
+#endif /* USE_SELECT */
+
+#ifdef ISC_SOCKET_USE_POLLWATCH
+/*%
+ * If this macro is defined, enable workaround for a Solaris /dev/poll kernel
+ * bug: DP_POLL ioctl could keep sleeping even if socket I/O is possible for
+ * some of the specified FD. The idea is based on the observation that it's
+ * likely for a busy server to keep receiving packets. It specifically works
+ * as follows: the socket watcher is first initialized with the state of
+ * "poll_idle". While it's in the idle state it keeps sleeping until a socket
+ * event occurs. When it wakes up for a socket I/O event, it moves to the
+ * poll_active state, and sets the poll timeout to a short period
+ * (ISC_SOCKET_POLLWATCH_TIMEOUT msec). If timeout occurs in this state, the
+ * watcher goes to the poll_checking state with the same timeout period.
+ * In this state, the watcher tries to detect whether this is a break
+ * during intermittent events or the kernel bug is triggered. If the next
+ * polling reports an event within the short period, the previous timeout is
+ * likely to be a kernel bug, and so the watcher goes back to the active state.
+ * Otherwise, it moves to the idle state again.
+ *
+ * It's not clear whether this is a thread-related bug, but since we've only
+ * seen this with threads, this workaround is used only when enabling threads.
+ */
+
+typedef enum { poll_idle, poll_active, poll_checking } pollstate_t;
+
+#ifndef ISC_SOCKET_POLLWATCH_TIMEOUT
+#define ISC_SOCKET_POLLWATCH_TIMEOUT 10
+#endif /* ISC_SOCKET_POLLWATCH_TIMEOUT */
+#endif /* ISC_SOCKET_USE_POLLWATCH */
+
+/*%
+ * Size of per-FD lock buckets.
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+#define FDLOCK_COUNT 1024
+#define FDLOCK_ID(fd) ((fd) % FDLOCK_COUNT)
+#else
+#define FDLOCK_COUNT 1
+#define FDLOCK_ID(fd) 0
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/*%
+ * Maximum number of events communicated with the kernel. There should normally
+ * be no need for having a large number.
+ */
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
+#ifndef ISC_SOCKET_MAXEVENTS
+#ifdef TUNE_LARGE
+#define ISC_SOCKET_MAXEVENTS 2048
+#else
+#define ISC_SOCKET_MAXEVENTS 64
+#endif /* TUNE_LARGE */
+#endif
+#endif
+
+/*%
+ * Some systems define the socket length argument as an int, some as size_t,
+ * some as socklen_t. This is here so it can be easily changed if needed.
+ */
+#ifndef ISC_SOCKADDR_LEN_T
+#define ISC_SOCKADDR_LEN_T unsigned int
+#endif
+
+/*%
+ * Define what the possible "soft" errors can be. These are non-fatal returns
+ * of various network related functions, like recv() and so on.
+ *
+ * For some reason, BSDI (and perhaps others) will sometimes return <0
+ * from recv() but will have errno==0. This is broken, but we have to
+ * work around it here.
+ */
+#define SOFT_ERROR(e) ((e) == EAGAIN || \
+ (e) == EWOULDBLOCK || \
+ (e) == ENOBUFS || \
+ (e) == EINTR || \
+ (e) == 0)
+
+#define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x)
+
+/*!<
+ * DLVL(90) -- Function entry/exit and other tracing.
+ * DLVL(70) -- Socket "correctness" -- including returning of events, etc.
+ * DLVL(60) -- Socket data send/receive
+ * DLVL(50) -- Event tracing, including receiving/sending completion events.
+ * DLVL(20) -- Socket creation/destruction.
+ */
+#define TRACE_LEVEL 90
+#define CORRECTNESS_LEVEL 70
+#define IOEVENT_LEVEL 60
+#define EVENT_LEVEL 50
+#define CREATION_LEVEL 20
+
+#define TRACE DLVL(TRACE_LEVEL)
+#define CORRECTNESS DLVL(CORRECTNESS_LEVEL)
+#define IOEVENT DLVL(IOEVENT_LEVEL)
+#define EVENT DLVL(EVENT_LEVEL)
+#define CREATION DLVL(CREATION_LEVEL)
+
+typedef isc_event_t intev_t;
+
+#define SOCKET_MAGIC ISC_MAGIC('I', 'O', 'i', 'o')
+#define VALID_SOCKET(s) ISC_MAGIC_VALID(s, SOCKET_MAGIC)
+
+/*!
+ * IPv6 control information. If the socket is an IPv6 socket we want
+ * to collect the destination address and interface so the client can
+ * set them on outgoing packets.
+ */
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+#ifndef USE_CMSG
+#define USE_CMSG 1
+#endif
+#endif
+
+/*%
+ * NetBSD and FreeBSD can timestamp packets. XXXMLG Should we have
+ * a setsockopt() like interface to request timestamps, and if the OS
+ * doesn't do it for us, call gettimeofday() on every UDP receive?
+ */
+#ifdef SO_TIMESTAMP
+#ifndef USE_CMSG
+#define USE_CMSG 1
+#endif
+#endif
+
+/*%
+ * The size to raise the receive buffer to (from BIND 8).
+ */
+#ifdef TUNE_LARGE
+#ifdef sun
+#define RCVBUFSIZE (1*1024*1024)
+#else
+#define RCVBUFSIZE (16*1024*1024)
+#endif
+#else
+#define RCVBUFSIZE (32*1024)
+#endif /* TUNE_LARGE */
+
+/*%
+ * Instead of calculating the cmsgbuf lengths every time we take
+ * a rule of thumb approach - sizes are taken from x86_64 linux,
+ * multiplied by 2, everything should fit. Those sizes are not
+ * large enough to cause any concern.
+ */
+#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
+#define CMSG_SP_IN6PKT 40
+#else
+#define CMSG_SP_IN6PKT 0
+#endif
+
+#if defined(USE_CMSG) && defined(SO_TIMESTAMP)
+#define CMSG_SP_TIMESTAMP 32
+#else
+#define CMSG_SP_TIMESTAMP 0
+#endif
+
+#if defined(USE_CMSG) && (defined(IPV6_TCLASS) || defined(IP_TOS))
+#define CMSG_SP_TCTOS 24
+#else
+#define CMSG_SP_TCTOS 0
+#endif
+
+#define CMSG_SP_INT 24
+
+/* Align cmsg buffers to be safe on SPARC etc. */
+#define RECVCMSGBUFLEN ISC_ALIGN(2*(CMSG_SP_IN6PKT + CMSG_SP_TIMESTAMP + CMSG_SP_TCTOS)+1, sizeof(void*))
+#define SENDCMSGBUFLEN ISC_ALIGN(2*(CMSG_SP_IN6PKT + CMSG_SP_INT + CMSG_SP_TCTOS)+1, sizeof(void*))
+
+/*%
+ * The number of times a send operation is repeated if the result is EINTR.
+ */
+#define NRETRIES 10
+
+typedef struct isc__socket isc__socket_t;
+typedef struct isc__socketmgr isc__socketmgr_t;
+
+#define NEWCONNSOCK(ev) ((isc__socket_t *)(ev)->newsocket)
+
+struct isc__socket {
+ /* Not locked. */
+ isc_socket_t common;
+ isc__socketmgr_t *manager;
+ isc_mutex_t lock;
+ isc_sockettype_t type;
+ const isc_statscounter_t *statsindex;
+
+ /* Locked by socket lock. */
+ ISC_LINK(isc__socket_t) link;
+ unsigned int references;
+ int fd;
+ int pf;
+ char name[16];
+ void * tag;
+
+ ISC_LIST(isc_socketevent_t) send_list;
+ ISC_LIST(isc_socketevent_t) recv_list;
+ ISC_LIST(isc_socket_newconnev_t) accept_list;
+ ISC_LIST(isc_socket_connev_t) connect_list;
+
+ /*
+ * Internal events. Posted when a descriptor is readable or
+ * writable. These are statically allocated and never freed.
+ * They will be set to non-purgable before use.
+ */
+ intev_t readable_ev;
+ intev_t writable_ev;
+
+ isc_sockaddr_t peer_address; /* remote address */
+
+ unsigned int pending_recv : 1,
+ pending_send : 1,
+ pending_accept : 1,
+ listener : 1, /* listener socket */
+ connected : 1,
+ connecting : 1, /* connect pending */
+ bound : 1, /* bound to local addr */
+ dupped : 1,
+ active : 1, /* currently active */
+ pktdscp : 1; /* per packet dscp */
+
+#ifdef ISC_PLATFORM_RECVOVERFLOW
+ unsigned char overflow; /* used for MSG_TRUNC fake */
+#endif
+
+ void *fdwatcharg;
+ isc_sockfdwatch_t fdwatchcb;
+ int fdwatchflags;
+ isc_task_t *fdwatchtask;
+ unsigned int dscp;
+};
+
+#define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g')
+#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC)
+
+struct isc__socketmgr {
+ /* Not locked. */
+ isc_socketmgr_t common;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ isc_mutex_t *fdlock;
+ isc_stats_t *stats;
+#ifdef USE_KQUEUE
+ int kqueue_fd;
+ int nevents;
+ struct kevent *events;
+#endif /* USE_KQUEUE */
+#ifdef USE_EPOLL
+ int epoll_fd;
+ int nevents;
+ struct epoll_event *events;
+#endif /* USE_EPOLL */
+#ifdef USE_DEVPOLL
+ int devpoll_fd;
+ isc_resourcevalue_t open_max;
+ unsigned int calls;
+ int nevents;
+ struct pollfd *events;
+#endif /* USE_DEVPOLL */
+#ifdef USE_SELECT
+ int fd_bufsize;
+#endif /* USE_SELECT */
+ unsigned int maxsocks;
+#ifdef ISC_PLATFORM_USETHREADS
+ int pipe_fds[2];
+#endif
+
+ /* Locked by fdlock. */
+ isc__socket_t **fds;
+ int *fdstate;
+#if defined(USE_EPOLL)
+ uint32_t *epoll_events;
+#endif
+#ifdef USE_DEVPOLL
+ pollinfo_t *fdpollinfo;
+#endif
+
+ /* Locked by manager lock. */
+ ISC_LIST(isc__socket_t) socklist;
+#ifdef USE_SELECT
+ fd_set *read_fds;
+ fd_set *read_fds_copy;
+ fd_set *write_fds;
+ fd_set *write_fds_copy;
+ int maxfd;
+#endif /* USE_SELECT */
+ int reserved; /* unlocked */
+#ifdef USE_WATCHER_THREAD
+ isc_thread_t watcher;
+ isc_condition_t shutdown_ok;
+#else /* USE_WATCHER_THREAD */
+ unsigned int refs;
+#endif /* USE_WATCHER_THREAD */
+ int maxudp;
+};
+
+#ifdef USE_SHARED_MANAGER
+static isc__socketmgr_t *socketmgr = NULL;
+#endif /* USE_SHARED_MANAGER */
+
+#define CLOSED 0 /* this one must be zero */
+#define MANAGED 1
+#define CLOSE_PENDING 2
+
+/*
+ * send() and recv() iovec counts
+ */
+#define MAXSCATTERGATHER_SEND (ISC_SOCKET_MAXSCATTERGATHER)
+#ifdef ISC_PLATFORM_RECVOVERFLOW
+# define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER + 1)
+#else
+# define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER)
+#endif
+
+static isc_result_t socket_create(isc_socketmgr_t *manager0, int pf,
+ isc_sockettype_t type,
+ isc_socket_t **socketp,
+ isc_socket_t *dup_socket);
+static void send_recvdone_event(isc__socket_t *, isc_socketevent_t **);
+static void send_senddone_event(isc__socket_t *, isc_socketevent_t **);
+static void send_connectdone_event(isc__socket_t *, isc_socket_connev_t **);
+static void free_socket(isc__socket_t **);
+static isc_result_t allocate_socket(isc__socketmgr_t *, isc_sockettype_t,
+ isc__socket_t **);
+static void destroy(isc__socket_t **);
+static void internal_accept(isc_task_t *, isc_event_t *);
+static void internal_connect(isc_task_t *, isc_event_t *);
+static void internal_recv(isc_task_t *, isc_event_t *);
+static void internal_send(isc_task_t *, isc_event_t *);
+static void internal_fdwatch_write(isc_task_t *, isc_event_t *);
+static void internal_fdwatch_read(isc_task_t *, isc_event_t *);
+static void process_cmsg(isc__socket_t *, struct msghdr *, isc_socketevent_t *);
+static void build_msghdr_send(isc__socket_t *, char *, isc_socketevent_t *,
+ struct msghdr *, struct iovec *, size_t *);
+static void build_msghdr_recv(isc__socket_t *, char *, isc_socketevent_t *,
+ struct msghdr *, struct iovec *, size_t *);
+#ifdef USE_WATCHER_THREAD
+static bool process_ctlfd(isc__socketmgr_t *manager);
+#endif
+static void setdscp(isc__socket_t *sock, isc_dscp_t dscp);
+
+/*%
+ * The following are intended for internal use (indicated by "isc__"
+ * prefix) but are not declared as static, allowing direct access from
+ * unit tests etc.
+ */
+
+isc_result_t
+isc__socket_open(isc_socket_t *sock0);
+isc_result_t
+isc__socket_close(isc_socket_t *sock0);
+isc_result_t
+isc__socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
+ isc_socket_t **socketp);
+void
+isc__socket_attach(isc_socket_t *sock, isc_socket_t **socketp);
+void
+isc__socket_detach(isc_socket_t **socketp);
+isc_result_t
+isc__socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ unsigned int minimum, isc_task_t *task,
+ isc_taskaction_t action, void *arg);
+isc_result_t
+isc__socket_recv(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_taskaction_t action, void *arg);
+isc_result_t
+isc__socket_recv2(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_socketevent_t *event, unsigned int flags);
+isc_result_t
+isc__socket_send(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+isc_result_t
+isc__socket_sendto(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo);
+isc_result_t
+isc__socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+isc_result_t
+isc__socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo);
+isc_result_t
+isc__socket_sendtov2(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ unsigned int flags);
+isc_result_t
+isc__socket_sendto2(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ isc_socketevent_t *event, unsigned int flags);
+isc_socketevent_t *
+isc_socket_socketevent(isc_mem_t *mctx, void *sender,
+ isc_eventtype_t eventtype, isc_taskaction_t action,
+ void *arg);
+
+void
+isc__socket_cleanunix(isc_sockaddr_t *sockaddr, bool active);
+isc_result_t
+isc__socket_permunix(isc_sockaddr_t *sockaddr, uint32_t perm,
+ uint32_t owner, uint32_t group);
+isc_result_t
+isc__socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr,
+ unsigned int options);
+isc_result_t
+isc__socket_filter(isc_socket_t *sock, const char *filter);
+isc_result_t
+isc__socket_listen(isc_socket_t *sock, unsigned int backlog);
+isc_result_t
+isc__socket_accept(isc_socket_t *sock,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+isc_result_t
+isc__socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr,
+ isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+isc_result_t
+isc__socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp);
+isc_result_t
+isc__socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp);
+void
+isc__socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how);
+isc_sockettype_t
+isc__socket_gettype(isc_socket_t *sock);
+bool
+isc__socket_isbound(isc_socket_t *sock);
+void
+isc__socket_ipv6only(isc_socket_t *sock, bool yes);
+void
+isc__socket_dscp(isc_socket_t *sock, isc_dscp_t dscp);
+isc_result_t
+isc__socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags,
+ isc_sockfdwatch_t callback, void *cbarg,
+ isc_task_t *task, isc_socket_t **socketp);
+isc_result_t
+isc__socket_fdwatchpoke(isc_socket_t *sock, int flags);
+isc_result_t
+isc__socket_dup(isc_socket_t *sock, isc_socket_t **socketp);
+int
+isc__socket_getfd(isc_socket_t *sock);
+
+isc_result_t
+isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp);
+isc_result_t
+isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
+ unsigned int maxsocks);
+isc_result_t
+isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager0, unsigned int *nsockp);
+void
+isc_socketmgr_setstats(isc_socketmgr_t *manager0, isc_stats_t *stats);
+void
+isc__socketmgr_destroy(isc_socketmgr_t **managerp);
+void
+isc__socket_setname(isc_socket_t *socket0, const char *name, void *tag);
+const char *
+isc__socket_getname(isc_socket_t *socket0);
+void *
+isc__socket_gettag(isc_socket_t *socket0);
+
+#ifdef HAVE_LIBXML2
+void
+isc__socketmgr_renderxml(isc_socketmgr_t *mgr0, xmlTextWriterPtr writer);
+#endif
+#ifdef HAVE_JSON
+isc_result_t
+isc__socketmgr_renderjson(isc_socketmgr_t *mgr0, json_object *stats);
+#endif
+
+static struct {
+ isc_socketmethods_t methods;
+
+ /*%
+ * The following are defined just for avoiding unused static functions.
+ */
+ void *recvv, *send, *sendv, *sendto2, *cleanunix, *permunix, *filter,
+ *listen, *accept, *getpeername, *isbound;
+} socketmethods = {
+ {
+ isc__socket_attach,
+ isc__socket_detach,
+ isc__socket_bind,
+ isc__socket_sendto,
+ isc__socket_sendto2,
+ isc__socket_connect,
+ isc__socket_recv,
+ isc__socket_recv2,
+ isc__socket_cancel,
+ isc__socket_getsockname,
+ isc__socket_gettype,
+ isc__socket_ipv6only,
+ isc__socket_fdwatchpoke,
+ isc__socket_dup,
+ isc__socket_getfd,
+ isc__socket_dscp
+ },
+ (void *)isc__socket_recvv, (void *)isc__socket_send,
+ (void *)isc__socket_sendv, (void *)isc__socket_sendto2,
+ (void *)isc__socket_cleanunix, (void *)isc__socket_permunix,
+ (void *)isc__socket_filter, (void *)isc__socket_listen,
+ (void *)isc__socket_accept, (void *)isc__socket_getpeername,
+ (void *)isc__socket_isbound
+};
+
+static isc_socketmgrmethods_t socketmgrmethods = {
+ isc__socketmgr_destroy,
+ isc__socket_create,
+ isc__socket_fdwatchcreate
+};
+
+#define SELECT_POKE_SHUTDOWN (-1)
+#define SELECT_POKE_NOTHING (-2)
+#define SELECT_POKE_READ (-3)
+#define SELECT_POKE_ACCEPT (-3) /*%< Same as _READ */
+#define SELECT_POKE_WRITE (-4)
+#define SELECT_POKE_CONNECT (-4) /*%< Same as _WRITE */
+#define SELECT_POKE_CLOSE (-5)
+
+#define SOCK_DEAD(s) ((s)->references == 0)
+
+/*%
+ * Shortcut index arrays to get access to statistics counters.
+ */
+enum {
+ STATID_OPEN = 0,
+ STATID_OPENFAIL = 1,
+ STATID_CLOSE = 2,
+ STATID_BINDFAIL = 3,
+ STATID_CONNECTFAIL = 4,
+ STATID_CONNECT = 5,
+ STATID_ACCEPTFAIL = 6,
+ STATID_ACCEPT = 7,
+ STATID_SENDFAIL = 8,
+ STATID_RECVFAIL = 9,
+ STATID_ACTIVE = 10
+};
+static const isc_statscounter_t udp4statsindex[] = {
+ isc_sockstatscounter_udp4open,
+ isc_sockstatscounter_udp4openfail,
+ isc_sockstatscounter_udp4close,
+ isc_sockstatscounter_udp4bindfail,
+ isc_sockstatscounter_udp4connectfail,
+ isc_sockstatscounter_udp4connect,
+ -1,
+ -1,
+ isc_sockstatscounter_udp4sendfail,
+ isc_sockstatscounter_udp4recvfail,
+ isc_sockstatscounter_udp4active
+};
+static const isc_statscounter_t udp6statsindex[] = {
+ isc_sockstatscounter_udp6open,
+ isc_sockstatscounter_udp6openfail,
+ isc_sockstatscounter_udp6close,
+ isc_sockstatscounter_udp6bindfail,
+ isc_sockstatscounter_udp6connectfail,
+ isc_sockstatscounter_udp6connect,
+ -1,
+ -1,
+ isc_sockstatscounter_udp6sendfail,
+ isc_sockstatscounter_udp6recvfail,
+ isc_sockstatscounter_udp6active
+};
+static const isc_statscounter_t tcp4statsindex[] = {
+ isc_sockstatscounter_tcp4open,
+ isc_sockstatscounter_tcp4openfail,
+ isc_sockstatscounter_tcp4close,
+ isc_sockstatscounter_tcp4bindfail,
+ isc_sockstatscounter_tcp4connectfail,
+ isc_sockstatscounter_tcp4connect,
+ isc_sockstatscounter_tcp4acceptfail,
+ isc_sockstatscounter_tcp4accept,
+ isc_sockstatscounter_tcp4sendfail,
+ isc_sockstatscounter_tcp4recvfail,
+ isc_sockstatscounter_tcp4active
+};
+static const isc_statscounter_t tcp6statsindex[] = {
+ isc_sockstatscounter_tcp6open,
+ isc_sockstatscounter_tcp6openfail,
+ isc_sockstatscounter_tcp6close,
+ isc_sockstatscounter_tcp6bindfail,
+ isc_sockstatscounter_tcp6connectfail,
+ isc_sockstatscounter_tcp6connect,
+ isc_sockstatscounter_tcp6acceptfail,
+ isc_sockstatscounter_tcp6accept,
+ isc_sockstatscounter_tcp6sendfail,
+ isc_sockstatscounter_tcp6recvfail,
+ isc_sockstatscounter_tcp6active
+};
+static const isc_statscounter_t unixstatsindex[] = {
+ isc_sockstatscounter_unixopen,
+ isc_sockstatscounter_unixopenfail,
+ isc_sockstatscounter_unixclose,
+ isc_sockstatscounter_unixbindfail,
+ isc_sockstatscounter_unixconnectfail,
+ isc_sockstatscounter_unixconnect,
+ isc_sockstatscounter_unixacceptfail,
+ isc_sockstatscounter_unixaccept,
+ isc_sockstatscounter_unixsendfail,
+ isc_sockstatscounter_unixrecvfail,
+ isc_sockstatscounter_unixactive
+};
+static const isc_statscounter_t fdwatchstatsindex[] = {
+ -1,
+ -1,
+ isc_sockstatscounter_fdwatchclose,
+ isc_sockstatscounter_fdwatchbindfail,
+ isc_sockstatscounter_fdwatchconnectfail,
+ isc_sockstatscounter_fdwatchconnect,
+ -1,
+ -1,
+ isc_sockstatscounter_fdwatchsendfail,
+ isc_sockstatscounter_fdwatchrecvfail,
+ -1
+};
+static const isc_statscounter_t rawstatsindex[] = {
+ isc_sockstatscounter_rawopen,
+ isc_sockstatscounter_rawopenfail,
+ isc_sockstatscounter_rawclose,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ isc_sockstatscounter_rawrecvfail,
+ isc_sockstatscounter_rawactive
+};
+
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) || \
+ defined(USE_WATCHER_THREAD)
+static void
+manager_log(isc__socketmgr_t *sockmgr,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6);
+static void
+manager_log(isc__socketmgr_t *sockmgr,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ const char *fmt, ...)
+{
+ char msgbuf[2048];
+ va_list ap;
+
+ if (! isc_log_wouldlog(isc_lctx, level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ isc_log_write(isc_lctx, category, module, level,
+ "sockmgr %p: %s", sockmgr, msgbuf);
+}
+#endif
+
+static void
+socket_log(isc__socket_t *sock, isc_sockaddr_t *address,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10);
+static void
+socket_log(isc__socket_t *sock, isc_sockaddr_t *address,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *fmt, ...)
+{
+ char msgbuf[2048];
+ char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+ va_list ap;
+
+ if (! isc_log_wouldlog(isc_lctx, level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ if (address == NULL) {
+ isc_log_iwrite(isc_lctx, category, module, level,
+ msgcat, msgset, message,
+ "socket %p: %s", sock, msgbuf);
+ } else {
+ isc_sockaddr_format(address, peerbuf, sizeof(peerbuf));
+ isc_log_iwrite(isc_lctx, category, module, level,
+ msgcat, msgset, message,
+ "socket %p %s: %s", sock, peerbuf, msgbuf);
+ }
+}
+
+#if defined(_AIX) && defined(ISC_NET_BSD44MSGHDR) && \
+ defined(USE_CMSG) && defined(IPV6_RECVPKTINFO)
+/*
+ * AIX has a kernel bug where IPV6_RECVPKTINFO gets cleared by
+ * setting IPV6_V6ONLY.
+ */
+static void
+FIX_IPV6_RECVPKTINFO(isc__socket_t *sock)
+{
+ char strbuf[ISC_STRERRORSIZE];
+ int on = 1;
+
+ if (sock->pf != AF_INET6 || sock->type != isc_sockettype_udp)
+ return;
+
+ if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ (void *)&on, sizeof(on)) < 0) {
+
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_RECVPKTINFO) "
+ "%s: %s", sock->fd,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+}
+#else
+#define FIX_IPV6_RECVPKTINFO(sock) (void)0
+#endif
+
+/*%
+ * Increment socket-related statistics counters.
+ */
+static inline void
+inc_stats(isc_stats_t *stats, isc_statscounter_t counterid) {
+ REQUIRE(counterid != -1);
+
+ if (stats != NULL)
+ isc_stats_increment(stats, counterid);
+}
+
+/*%
+ * Decrement socket-related statistics counters.
+ */
+static inline void
+dec_stats(isc_stats_t *stats, isc_statscounter_t counterid) {
+ REQUIRE(counterid != -1);
+
+ if (stats != NULL)
+ isc_stats_decrement(stats, counterid);
+}
+
+static inline isc_result_t
+watch_fd(isc__socketmgr_t *manager, int fd, int msg) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+#ifdef USE_KQUEUE
+ struct kevent evchange;
+
+ memset(&evchange, 0, sizeof(evchange));
+ if (msg == SELECT_POKE_READ)
+ evchange.filter = EVFILT_READ;
+ else
+ evchange.filter = EVFILT_WRITE;
+ evchange.flags = EV_ADD;
+ evchange.ident = fd;
+ if (kevent(manager->kqueue_fd, &evchange, 1, NULL, 0, NULL) != 0)
+ result = isc__errno2result(errno);
+
+ return (result);
+#elif defined(USE_EPOLL)
+ struct epoll_event event;
+ uint32_t oldevents;
+ int ret;
+ int op;
+
+ oldevents = manager->epoll_events[fd];
+ if (msg == SELECT_POKE_READ)
+ manager->epoll_events[fd] |= EPOLLIN;
+ else
+ manager->epoll_events[fd] |= EPOLLOUT;
+
+ event.events = manager->epoll_events[fd];
+ memset(&event.data, 0, sizeof(event.data));
+ event.data.fd = fd;
+
+ op = (oldevents == 0U) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
+ ret = epoll_ctl(manager->epoll_fd, op, fd, &event);
+ if (ret == -1) {
+ if (errno == EEXIST)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "epoll_ctl(ADD/MOD) returned "
+ "EEXIST for fd %d", fd);
+ result = isc__errno2result(errno);
+ }
+
+ return (result);
+#elif defined(USE_DEVPOLL)
+ struct pollfd pfd;
+ int lockid = FDLOCK_ID(fd);
+
+ memset(&pfd, 0, sizeof(pfd));
+ if (msg == SELECT_POKE_READ)
+ pfd.events = POLLIN;
+ else
+ pfd.events = POLLOUT;
+ pfd.fd = fd;
+ pfd.revents = 0;
+ LOCK(&manager->fdlock[lockid]);
+ if (write(manager->devpoll_fd, &pfd, sizeof(pfd)) == -1)
+ result = isc__errno2result(errno);
+ else {
+ if (msg == SELECT_POKE_READ)
+ manager->fdpollinfo[fd].want_read = 1;
+ else
+ manager->fdpollinfo[fd].want_write = 1;
+ }
+ UNLOCK(&manager->fdlock[lockid]);
+
+ return (result);
+#elif defined(USE_SELECT)
+ LOCK(&manager->lock);
+ if (msg == SELECT_POKE_READ)
+ FD_SET(fd, manager->read_fds);
+ if (msg == SELECT_POKE_WRITE)
+ FD_SET(fd, manager->write_fds);
+ UNLOCK(&manager->lock);
+
+ return (result);
+#endif
+}
+
+static inline isc_result_t
+unwatch_fd(isc__socketmgr_t *manager, int fd, int msg) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+#ifdef USE_KQUEUE
+ struct kevent evchange;
+
+ memset(&evchange, 0, sizeof(evchange));
+ if (msg == SELECT_POKE_READ)
+ evchange.filter = EVFILT_READ;
+ else
+ evchange.filter = EVFILT_WRITE;
+ evchange.flags = EV_DELETE;
+ evchange.ident = fd;
+ if (kevent(manager->kqueue_fd, &evchange, 1, NULL, 0, NULL) != 0)
+ result = isc__errno2result(errno);
+
+ return (result);
+#elif defined(USE_EPOLL)
+ struct epoll_event event;
+ int ret;
+ int op;
+
+ if (msg == SELECT_POKE_READ)
+ manager->epoll_events[fd] &= ~(EPOLLIN);
+ else
+ manager->epoll_events[fd] &= ~(EPOLLOUT);
+
+ event.events = manager->epoll_events[fd];
+ memset(&event.data, 0, sizeof(event.data));
+ event.data.fd = fd;
+
+ op = (event.events == 0U) ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
+ ret = epoll_ctl(manager->epoll_fd, op, fd, &event);
+ if (ret == -1 && errno != ENOENT) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "epoll_ctl(DEL), %d: %s", fd, strbuf);
+ result = ISC_R_UNEXPECTED;
+ }
+ return (result);
+#elif defined(USE_DEVPOLL)
+ struct pollfd pfds[2];
+ size_t writelen = sizeof(pfds[0]);
+ int lockid = FDLOCK_ID(fd);
+
+ memset(pfds, 0, sizeof(pfds));
+ pfds[0].events = POLLREMOVE;
+ pfds[0].fd = fd;
+
+ /*
+ * Canceling read or write polling via /dev/poll is tricky. Since it
+ * only provides a way of canceling per FD, we may need to re-poll the
+ * socket for the other operation.
+ */
+ LOCK(&manager->fdlock[lockid]);
+ if (msg == SELECT_POKE_READ &&
+ manager->fdpollinfo[fd].want_write == 1) {
+ pfds[1].events = POLLOUT;
+ pfds[1].fd = fd;
+ writelen += sizeof(pfds[1]);
+ }
+ if (msg == SELECT_POKE_WRITE &&
+ manager->fdpollinfo[fd].want_read == 1) {
+ pfds[1].events = POLLIN;
+ pfds[1].fd = fd;
+ writelen += sizeof(pfds[1]);
+ }
+
+ if (write(manager->devpoll_fd, pfds, writelen) == -1)
+ result = isc__errno2result(errno);
+ else {
+ if (msg == SELECT_POKE_READ)
+ manager->fdpollinfo[fd].want_read = 0;
+ else
+ manager->fdpollinfo[fd].want_write = 0;
+ }
+ UNLOCK(&manager->fdlock[lockid]);
+
+ return (result);
+#elif defined(USE_SELECT)
+ LOCK(&manager->lock);
+ if (msg == SELECT_POKE_READ)
+ FD_CLR(fd, manager->read_fds);
+ else if (msg == SELECT_POKE_WRITE)
+ FD_CLR(fd, manager->write_fds);
+ UNLOCK(&manager->lock);
+
+ return (result);
+#endif
+}
+
+static void
+wakeup_socket(isc__socketmgr_t *manager, int fd, int msg) {
+ isc_result_t result;
+ int lockid = FDLOCK_ID(fd);
+
+ /*
+ * This is a wakeup on a socket. If the socket is not in the
+ * process of being closed, start watching it for either reads
+ * or writes.
+ */
+
+ INSIST(fd >= 0 && fd < (int)manager->maxsocks);
+
+ if (msg == SELECT_POKE_CLOSE) {
+ /* No one should be updating fdstate, so no need to lock it */
+ INSIST(manager->fdstate[fd] == CLOSE_PENDING);
+ manager->fdstate[fd] = CLOSED;
+ (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+ (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+ (void)close(fd);
+ return;
+ }
+
+ LOCK(&manager->fdlock[lockid]);
+ if (manager->fdstate[fd] == CLOSE_PENDING) {
+ UNLOCK(&manager->fdlock[lockid]);
+
+ /*
+ * We accept (and ignore) any error from unwatch_fd() as we are
+ * closing the socket, hoping it doesn't leave dangling state in
+ * the kernel.
+ * Note that unwatch_fd() must be called after releasing the
+ * fdlock; otherwise it could cause deadlock due to a lock order
+ * reversal.
+ */
+ (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+ (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+ return;
+ }
+ if (manager->fdstate[fd] != MANAGED) {
+ UNLOCK(&manager->fdlock[lockid]);
+ return;
+ }
+ UNLOCK(&manager->fdlock[lockid]);
+
+ /*
+ * Set requested bit.
+ */
+ result = watch_fd(manager, fd, msg);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * XXXJT: what should we do? Ignoring the failure of watching
+ * a socket will make the application dysfunctional, but there
+ * seems to be no reasonable recovery process.
+ */
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "failed to start watching FD (%d): %s",
+ fd, isc_result_totext(result));
+ }
+}
+
+#ifdef USE_WATCHER_THREAD
+/*
+ * Poke the select loop when there is something for us to do.
+ * The write is required (by POSIX) to complete. That is, we
+ * will not get partial writes.
+ */
+static void
+select_poke(isc__socketmgr_t *mgr, int fd, int msg) {
+ int cc;
+ int buf[2];
+ char strbuf[ISC_STRERRORSIZE];
+
+ buf[0] = fd;
+ buf[1] = msg;
+
+ do {
+ cc = write(mgr->pipe_fds[1], buf, sizeof(buf));
+#ifdef ENOSR
+ /*
+ * Treat ENOSR as EAGAIN but loop slowly as it is
+ * unlikely to clear fast.
+ */
+ if (cc < 0 && errno == ENOSR) {
+ sleep(1);
+ errno = EAGAIN;
+ }
+#endif
+ } while (cc < 0 && SOFT_ERROR(errno));
+
+ if (cc < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_WRITEFAILED,
+ "write() failed "
+ "during watcher poke: %s"),
+ strbuf);
+ }
+
+ INSIST(cc == sizeof(buf));
+}
+
+/*
+ * Read a message on the internal fd.
+ */
+static void
+select_readmsg(isc__socketmgr_t *mgr, int *fd, int *msg) {
+ int buf[2];
+ int cc;
+ char strbuf[ISC_STRERRORSIZE];
+
+ cc = read(mgr->pipe_fds[0], buf, sizeof(buf));
+ if (cc < 0) {
+ *msg = SELECT_POKE_NOTHING;
+ *fd = -1; /* Silence compiler. */
+ if (SOFT_ERROR(errno))
+ return;
+
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_READFAILED,
+ "read() failed "
+ "during watcher poke: %s"),
+ strbuf);
+ }
+ INSIST(cc == sizeof(buf));
+
+ *fd = buf[0];
+ *msg = buf[1];
+}
+#else /* USE_WATCHER_THREAD */
+/*
+ * Update the state of the socketmgr when something changes.
+ */
+static void
+select_poke(isc__socketmgr_t *manager, int fd, int msg) {
+ if (msg == SELECT_POKE_SHUTDOWN)
+ return;
+ else if (fd >= 0)
+ wakeup_socket(manager, fd, msg);
+ return;
+}
+#endif /* USE_WATCHER_THREAD */
+
+/*
+ * Make a fd non-blocking.
+ */
+static isc_result_t
+make_nonblock(int fd) {
+ int ret;
+ char strbuf[ISC_STRERRORSIZE];
+#ifdef USE_FIONBIO_IOCTL
+ int on = 1;
+#else
+ int flags;
+#endif
+
+#ifdef USE_FIONBIO_IOCTL
+ ret = ioctl(fd, FIONBIO, (char *)&on);
+#else
+ flags = fcntl(fd, F_GETFL, 0);
+ flags |= PORT_NONBLOCK;
+ ret = fcntl(fd, F_SETFL, flags);
+#endif
+
+ if (ret == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+#ifdef USE_FIONBIO_IOCTL
+ "ioctl(%d, FIONBIO, &on): %s", fd,
+#else
+ "fcntl(%d, F_SETFL, %d): %s", fd, flags,
+#endif
+ strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+#ifdef USE_CMSG
+/*
+ * Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
+ * In order to ensure as much portability as possible, we provide wrapper
+ * functions of these macros.
+ * Note that cmsg_space() could run slow on OSes that do not have
+ * CMSG_SPACE.
+ */
+static inline ISC_SOCKADDR_LEN_T
+cmsg_len(ISC_SOCKADDR_LEN_T len) {
+#ifdef CMSG_LEN
+ return (CMSG_LEN(len));
+#else
+ ISC_SOCKADDR_LEN_T hdrlen;
+
+ /*
+ * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
+ * is correct.
+ */
+ hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(((struct cmsghdr *)NULL));
+ return (hdrlen + len);
+#endif
+}
+
+static inline ISC_SOCKADDR_LEN_T
+cmsg_space(ISC_SOCKADDR_LEN_T len) {
+#ifdef CMSG_SPACE
+ return (CMSG_SPACE(len));
+#else
+ struct msghdr msg;
+ struct cmsghdr *cmsgp;
+ /*
+ * XXX: The buffer length is an ad-hoc value, but should be enough
+ * in a practical sense.
+ */
+ char dummybuf[sizeof(struct cmsghdr) + 1024];
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_control = dummybuf;
+ msg.msg_controllen = sizeof(dummybuf);
+
+ cmsgp = (struct cmsghdr *)dummybuf;
+ cmsgp->cmsg_len = cmsg_len(len);
+
+ cmsgp = CMSG_NXTHDR(&msg, cmsgp);
+ if (cmsgp != NULL)
+ return ((char *)cmsgp - (char *)msg.msg_control);
+ else
+ return (0);
+#endif
+}
+#endif /* USE_CMSG */
+
+/*
+ * Process control messages received on a socket.
+ */
+static void
+process_cmsg(isc__socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) {
+#ifdef ISC_NET_BSD44MSGHDR
+#ifdef USE_CMSG
+ struct cmsghdr *cmsgp;
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ struct in6_pktinfo *pktinfop;
+#endif
+#ifdef SO_TIMESTAMP
+ void *timevalp;
+#endif
+#endif
+#endif
+
+ /*
+ * sock is used only when ISC_NET_BSD44MSGHDR and USE_CMSG are defined.
+ * msg and dev are used only when ISC_NET_BSD44MSGHDR is defined.
+ * They are all here, outside of the CPP tests, because it is
+ * more consistent with the usual ISC coding style.
+ */
+ UNUSED(sock);
+ UNUSED(msg);
+ UNUSED(dev);
+
+#ifdef ISC_NET_BSD44MSGHDR
+
+#ifdef MSG_TRUNC
+ if ((msg->msg_flags & MSG_TRUNC) == MSG_TRUNC)
+ dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;
+#endif
+
+#ifdef MSG_CTRUNC
+ if ((msg->msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
+ dev->attributes |= ISC_SOCKEVENTATTR_CTRUNC;
+#endif
+
+#ifndef USE_CMSG
+ return;
+#else
+ if (msg->msg_controllen == 0U || msg->msg_control == NULL)
+ return;
+
+#ifdef SO_TIMESTAMP
+ timevalp = NULL;
+#endif
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ pktinfop = NULL;
+#endif
+
+ cmsgp = CMSG_FIRSTHDR(msg);
+ while (cmsgp != NULL) {
+ socket_log(sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PROCESSCMSG,
+ "processing cmsg %p", cmsgp);
+
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ if (cmsgp->cmsg_level == IPPROTO_IPV6
+ && cmsgp->cmsg_type == IPV6_PKTINFO) {
+
+ pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
+ memmove(&dev->pktinfo, pktinfop,
+ sizeof(struct in6_pktinfo));
+ dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
+ socket_log(sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_IFRECEIVED,
+ "interface received on ifindex %u",
+ dev->pktinfo.ipi6_ifindex);
+ if (IN6_IS_ADDR_MULTICAST(&pktinfop->ipi6_addr))
+ dev->attributes |= ISC_SOCKEVENTATTR_MULTICAST;
+ goto next;
+ }
+#endif
+
+#ifdef SO_TIMESTAMP
+ if (cmsgp->cmsg_level == SOL_SOCKET
+ && cmsgp->cmsg_type == SCM_TIMESTAMP) {
+ struct timeval tv;
+ timevalp = CMSG_DATA(cmsgp);
+ memmove(&tv, timevalp, sizeof(tv));
+ dev->timestamp.seconds = tv.tv_sec;
+ dev->timestamp.nanoseconds = tv.tv_usec * 1000;
+ dev->attributes |= ISC_SOCKEVENTATTR_TIMESTAMP;
+ goto next;
+ }
+#endif
+
+#ifdef IPV6_TCLASS
+ if (cmsgp->cmsg_level == IPPROTO_IPV6
+ && cmsgp->cmsg_type == IPV6_TCLASS) {
+ dev->dscp = *(int *)CMSG_DATA(cmsgp);
+ dev->dscp >>= 2;
+ dev->attributes |= ISC_SOCKEVENTATTR_DSCP;
+ goto next;
+ }
+#endif
+
+#ifdef IP_TOS
+ if (cmsgp->cmsg_level == IPPROTO_IP
+ && (cmsgp->cmsg_type == IP_TOS
+#ifdef IP_RECVTOS
+ || cmsgp->cmsg_type == IP_RECVTOS
+#endif
+ )) {
+ dev->dscp = (int) *(unsigned char *)CMSG_DATA(cmsgp);
+ dev->dscp >>= 2;
+ dev->attributes |= ISC_SOCKEVENTATTR_DSCP;
+ goto next;
+ }
+#endif
+ next:
+ cmsgp = CMSG_NXTHDR(msg, cmsgp);
+ }
+#endif /* USE_CMSG */
+
+#endif /* ISC_NET_BSD44MSGHDR */
+}
+
+/*
+ * Construct an iov array and attach it to the msghdr passed in. This is
+ * the SEND constructor, which will use the used region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
+ *
+ * Nothing can be NULL, and the done event must list at least one buffer
+ * on the buffer linked list for this function to be meaningful.
+ *
+ * If write_countp != NULL, *write_countp will hold the number of bytes
+ * this transaction can send.
+ */
+static void
+build_msghdr_send(isc__socket_t *sock, char* cmsgbuf, isc_socketevent_t *dev,
+ struct msghdr *msg, struct iovec *iov, size_t *write_countp)
+{
+ unsigned int iovcount;
+ isc_buffer_t *buffer;
+ isc_region_t used;
+ size_t write_count;
+ size_t skip_count;
+#ifdef ISC_NET_BSD44MSGHDR
+ struct cmsghdr *cmsgp;
+#endif
+
+ memset(msg, 0, sizeof(*msg));
+
+ if (!sock->connected) {
+ msg->msg_name = (void *)&dev->address.type.sa;
+ msg->msg_namelen = dev->address.length;
+ } else {
+ msg->msg_name = NULL;
+ msg->msg_namelen = 0;
+ }
+
+ buffer = ISC_LIST_HEAD(dev->bufferlist);
+ write_count = 0;
+ iovcount = 0;
+
+ /*
+ * Single buffer I/O? Skip what we've done so far in this region.
+ */
+ if (buffer == NULL) {
+ write_count = dev->region.length - dev->n;
+ iov[0].iov_base = (void *)(dev->region.base + dev->n);
+ iov[0].iov_len = write_count;
+ iovcount = 1;
+
+ goto config;
+ }
+
+ /*
+ * Multibuffer I/O.
+ * Skip the data in the buffer list that we have already written.
+ */
+ skip_count = dev->n;
+ while (buffer != NULL) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ if (skip_count < isc_buffer_usedlength(buffer))
+ break;
+ skip_count -= isc_buffer_usedlength(buffer);
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ while (buffer != NULL) {
+ INSIST(iovcount < MAXSCATTERGATHER_SEND);
+
+ isc_buffer_usedregion(buffer, &used);
+
+ if (used.length > 0) {
+ iov[iovcount].iov_base = (void *)(used.base
+ + skip_count);
+ iov[iovcount].iov_len = used.length - skip_count;
+ write_count += (used.length - skip_count);
+ skip_count = 0;
+ iovcount++;
+ }
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ INSIST(skip_count == 0U);
+
+ config:
+ msg->msg_iov = iov;
+ msg->msg_iovlen = iovcount;
+
+#ifdef ISC_NET_BSD44MSGHDR
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+ msg->msg_flags = 0;
+#if defined(USE_CMSG)
+
+#if defined(ISC_PLATFORM_HAVEIN6PKTINFO)
+ if ((sock->type == isc_sockettype_udp) &&
+ ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0))
+ {
+ struct in6_pktinfo *pktinfop;
+
+ socket_log(sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_SENDTODATA,
+ "sendto pktinfo data, ifindex %u",
+ dev->pktinfo.ipi6_ifindex);
+
+ msg->msg_control = (void *)cmsgbuf;
+ msg->msg_controllen = cmsg_space(sizeof(struct in6_pktinfo));
+ INSIST(msg->msg_controllen <= SENDCMSGBUFLEN);
+
+ cmsgp = (struct cmsghdr *)cmsgbuf;
+ cmsgp->cmsg_level = IPPROTO_IPV6;
+ cmsgp->cmsg_type = IPV6_PKTINFO;
+ cmsgp->cmsg_len = cmsg_len(sizeof(struct in6_pktinfo));
+ pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
+ memmove(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo));
+ }
+#endif
+
+#if defined(IPV6_USE_MIN_MTU)
+ if ((sock->type == isc_sockettype_udp) &&
+ ((dev->attributes & ISC_SOCKEVENTATTR_USEMINMTU) != 0))
+ {
+ int use_min_mtu = 1; /* -1, 0, 1 */
+
+ cmsgp = (struct cmsghdr *)(cmsgbuf +
+ msg->msg_controllen);
+
+ msg->msg_control = (void *)cmsgbuf;
+ msg->msg_controllen += cmsg_space(sizeof(use_min_mtu));
+ INSIST(msg->msg_controllen <= SENDCMSGBUFLEN);
+
+ cmsgp->cmsg_level = IPPROTO_IPV6;
+ cmsgp->cmsg_type = IPV6_USE_MIN_MTU;
+ cmsgp->cmsg_len = cmsg_len(sizeof(use_min_mtu));
+ memmove(CMSG_DATA(cmsgp), &use_min_mtu, sizeof(use_min_mtu));
+ }
+#endif
+
+ if (isc_dscp_check_value > -1) {
+ if (sock->type == isc_sockettype_udp)
+ INSIST((int)dev->dscp == isc_dscp_check_value);
+ else if (sock->type == isc_sockettype_tcp)
+ INSIST((int)sock->dscp == isc_dscp_check_value);
+ }
+
+#if defined(IP_TOS) || (defined(IPPROTO_IPV6) && defined(IPV6_TCLASS))
+ if ((sock->type == isc_sockettype_udp) &&
+ ((dev->attributes & ISC_SOCKEVENTATTR_DSCP) != 0))
+ {
+ int dscp = (dev->dscp << 2) & 0xff;
+
+ INSIST(dev->dscp < 0x40);
+
+#ifdef IP_TOS
+ if (sock->pf == AF_INET && sock->pktdscp) {
+ cmsgp = (struct cmsghdr *)(cmsgbuf +
+ msg->msg_controllen);
+ msg->msg_control = (void *)cmsgbuf;
+ msg->msg_controllen += cmsg_space(sizeof(dscp));
+ INSIST(msg->msg_controllen <= SENDCMSGBUFLEN);
+
+ cmsgp->cmsg_level = IPPROTO_IP;
+ cmsgp->cmsg_type = IP_TOS;
+ cmsgp->cmsg_len = cmsg_len(sizeof(char));
+ *(unsigned char*)CMSG_DATA(cmsgp) = dscp;
+ } else if (sock->pf == AF_INET && sock->dscp != dev->dscp) {
+ if (setsockopt(sock->fd, IPPROTO_IP, IP_TOS,
+ (void *)&dscp, sizeof(int)) < 0)
+ {
+ char strbuf[ISC_STRERRORSIZE];
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IP_TOS, %.02x)"
+ " %s: %s",
+ sock->fd, dscp >> 2,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ } else
+ sock->dscp = dscp;
+ }
+#endif
+#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
+ if (sock->pf == AF_INET6 && sock->pktdscp) {
+ cmsgp = (struct cmsghdr *)(cmsgbuf +
+ msg->msg_controllen);
+ msg->msg_control = (void *)cmsgbuf;
+ msg->msg_controllen += cmsg_space(sizeof(dscp));
+ INSIST(msg->msg_controllen <= SENDCMSGBUFLEN);
+
+ cmsgp->cmsg_level = IPPROTO_IPV6;
+ cmsgp->cmsg_type = IPV6_TCLASS;
+ cmsgp->cmsg_len = cmsg_len(sizeof(dscp));
+ memmove(CMSG_DATA(cmsgp), &dscp, sizeof(dscp));
+ } else if (sock->pf == AF_INET6 && sock->dscp != dev->dscp) {
+ if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_TCLASS,
+ (void *)&dscp, sizeof(int)) < 0) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_TCLASS, "
+ "%.02x) %s: %s",
+ sock->fd, dscp >> 2,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ } else
+ sock->dscp = dscp;
+ }
+#endif
+ if (msg->msg_controllen != 0 &&
+ msg->msg_controllen < SENDCMSGBUFLEN)
+ {
+ memset(cmsgbuf + msg->msg_controllen, 0,
+ SENDCMSGBUFLEN - msg->msg_controllen);
+ }
+ }
+#endif
+#endif /* USE_CMSG */
+#else /* ISC_NET_BSD44MSGHDR */
+ msg->msg_accrights = NULL;
+ msg->msg_accrightslen = 0;
+#endif /* ISC_NET_BSD44MSGHDR */
+
+ if (write_countp != NULL)
+ *write_countp = write_count;
+}
+
+/*
+ * Construct an iov array and attach it to the msghdr passed in. This is
+ * the RECV constructor, which will use the available region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
+ *
+ * Nothing can be NULL, and the done event must list at least one buffer
+ * on the buffer linked list for this function to be meaningful.
+ *
+ * If read_countp != NULL, *read_countp will hold the number of bytes
+ * this transaction can receive.
+ */
+static void
+build_msghdr_recv(isc__socket_t *sock, char *cmsgbuf, isc_socketevent_t *dev,
+ struct msghdr *msg, struct iovec *iov, size_t *read_countp)
+{
+ unsigned int iovcount;
+ isc_buffer_t *buffer;
+ isc_region_t available;
+ size_t read_count;
+
+ memset(msg, 0, sizeof(struct msghdr));
+
+ if (sock->type == isc_sockettype_udp) {
+ memset(&dev->address, 0, sizeof(dev->address));
+#ifdef BROKEN_RECVMSG
+ if (sock->pf == AF_INET) {
+ msg->msg_name = (void *)&dev->address.type.sin;
+ msg->msg_namelen = sizeof(dev->address.type.sin6);
+ } else if (sock->pf == AF_INET6) {
+ msg->msg_name = (void *)&dev->address.type.sin6;
+ msg->msg_namelen = sizeof(dev->address.type.sin6);
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ } else if (sock->pf == AF_UNIX) {
+ msg->msg_name = (void *)&dev->address.type.sunix;
+ msg->msg_namelen = sizeof(dev->address.type.sunix);
+#endif
+ } else {
+ msg->msg_name = (void *)&dev->address.type.sa;
+ msg->msg_namelen = sizeof(dev->address.type);
+ }
+#else
+ msg->msg_name = (void *)&dev->address.type.sa;
+ msg->msg_namelen = sizeof(dev->address.type);
+#endif
+ } else { /* TCP */
+ msg->msg_name = NULL;
+ msg->msg_namelen = 0;
+ dev->address = sock->peer_address;
+ }
+
+ buffer = ISC_LIST_HEAD(dev->bufferlist);
+ read_count = 0;
+
+ /*
+ * Single buffer I/O? Skip what we've done so far in this region.
+ */
+ if (buffer == NULL) {
+ read_count = dev->region.length - dev->n;
+ iov[0].iov_base = (void *)(dev->region.base + dev->n);
+ iov[0].iov_len = read_count;
+ iovcount = 1;
+
+ goto config;
+ }
+
+ /*
+ * Multibuffer I/O.
+ * Skip empty buffers.
+ */
+ while (buffer != NULL) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ if (isc_buffer_availablelength(buffer) != 0)
+ break;
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ iovcount = 0;
+ while (buffer != NULL) {
+ INSIST(iovcount < MAXSCATTERGATHER_RECV);
+
+ isc_buffer_availableregion(buffer, &available);
+
+ if (available.length > 0) {
+ iov[iovcount].iov_base = (void *)(available.base);
+ iov[iovcount].iov_len = available.length;
+ read_count += available.length;
+ iovcount++;
+ }
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ config:
+
+ /*
+ * If needed, set up to receive that one extra byte.
+ */
+#ifdef ISC_PLATFORM_RECVOVERFLOW
+ if (sock->type == isc_sockettype_udp) {
+ INSIST(iovcount < MAXSCATTERGATHER_RECV);
+ iov[iovcount].iov_base = (void *)(&sock->overflow);
+ iov[iovcount].iov_len = 1;
+ iovcount++;
+ }
+#endif
+
+ msg->msg_iov = iov;
+ msg->msg_iovlen = iovcount;
+
+#ifdef ISC_NET_BSD44MSGHDR
+#if defined(USE_CMSG)
+ msg->msg_control = cmsgbuf;
+ msg->msg_controllen = RECVCMSGBUFLEN;
+#else
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+#endif /* USE_CMSG */
+ msg->msg_flags = 0;
+#else /* ISC_NET_BSD44MSGHDR */
+ msg->msg_accrights = NULL;
+ msg->msg_accrightslen = 0;
+#endif /* ISC_NET_BSD44MSGHDR */
+
+ if (read_countp != NULL)
+ *read_countp = read_count;
+}
+
+static void
+set_dev_address(isc_sockaddr_t *address, isc__socket_t *sock,
+ isc_socketevent_t *dev)
+{
+ if (sock->type == isc_sockettype_udp) {
+ if (address != NULL)
+ dev->address = *address;
+ else
+ dev->address = sock->peer_address;
+ } else if (sock->type == isc_sockettype_tcp) {
+ INSIST(address == NULL);
+ dev->address = sock->peer_address;
+ }
+}
+
+static void
+destroy_socketevent(isc_event_t *event) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)event;
+
+ INSIST(ISC_LIST_EMPTY(ev->bufferlist));
+
+ (ev->destroy)(event);
+}
+
+static isc_socketevent_t *
+allocate_socketevent(isc_mem_t *mctx, void *sender,
+ isc_eventtype_t eventtype, isc_taskaction_t action,
+ void *arg)
+{
+ isc_socketevent_t *ev;
+
+ ev = (isc_socketevent_t *)isc_event_allocate(mctx, sender,
+ eventtype, action, arg,
+ sizeof(*ev));
+
+ if (ev == NULL)
+ return (NULL);
+
+ ev->result = ISC_R_UNSET;
+ ISC_LINK_INIT(ev, ev_link);
+ ISC_LIST_INIT(ev->bufferlist);
+ ev->region.base = NULL;
+ ev->n = 0;
+ ev->offset = 0;
+ ev->attributes = 0;
+ ev->destroy = ev->ev_destroy;
+ ev->ev_destroy = destroy_socketevent;
+ ev->dscp = 0;
+
+ return (ev);
+}
+
+#if defined(ISC_SOCKET_DEBUG)
+static void
+dump_msg(struct msghdr *msg) {
+ unsigned int i;
+
+ printf("MSGHDR %p\n", msg);
+ printf("\tname %p, namelen %ld\n", msg->msg_name,
+ (long) msg->msg_namelen);
+ printf("\tiov %p, iovlen %ld\n", msg->msg_iov,
+ (long) msg->msg_iovlen);
+ for (i = 0; i < (unsigned int)msg->msg_iovlen; i++)
+ printf("\t\t%u\tbase %p, len %ld\n", i,
+ msg->msg_iov[i].iov_base,
+ (long) msg->msg_iov[i].iov_len);
+#ifdef ISC_NET_BSD44MSGHDR
+ printf("\tcontrol %p, controllen %ld\n", msg->msg_control,
+ (long) msg->msg_controllen);
+#endif
+}
+#endif
+
+#define DOIO_SUCCESS 0 /* i/o ok, event sent */
+#define DOIO_SOFT 1 /* i/o ok, soft error, no event sent */
+#define DOIO_HARD 2 /* i/o error, event sent */
+#define DOIO_EOF 3 /* EOF, no event sent */
+
+static int
+doio_recv(isc__socket_t *sock, isc_socketevent_t *dev) {
+ int cc;
+ struct iovec iov[MAXSCATTERGATHER_RECV];
+ size_t read_count;
+ size_t actual_count;
+ struct msghdr msghdr;
+ isc_buffer_t *buffer;
+ int recv_errno;
+ char strbuf[ISC_STRERRORSIZE];
+ char cmsgbuf[RECVCMSGBUFLEN] = {0};
+
+ build_msghdr_recv(sock, cmsgbuf, dev, &msghdr, iov, &read_count);
+
+#if defined(ISC_SOCKET_DEBUG)
+ dump_msg(&msghdr);
+#endif
+
+ cc = recvmsg(sock->fd, &msghdr, 0);
+ recv_errno = errno;
+
+#if defined(ISC_SOCKET_DEBUG)
+ dump_msg(&msghdr);
+#endif
+
+ if (cc < 0) {
+ if (SOFT_ERROR(recv_errno))
+ return (DOIO_SOFT);
+
+ if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+ isc__strerror(recv_errno, strbuf, sizeof(strbuf));
+ socket_log(sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_DOIORECV,
+ "doio_recv: recvmsg(%d) %d bytes, err %d/%s",
+ sock->fd, cc, recv_errno, strbuf);
+ }
+
+#define SOFT_OR_HARD(_system, _isc) \
+ if (recv_errno == _system) { \
+ if (sock->connected) { \
+ dev->result = _isc; \
+ inc_stats(sock->manager->stats, \
+ sock->statsindex[STATID_RECVFAIL]); \
+ return (DOIO_HARD); \
+ } \
+ return (DOIO_SOFT); \
+ }
+#define ALWAYS_HARD(_system, _isc) \
+ if (recv_errno == _system) { \
+ dev->result = _isc; \
+ inc_stats(sock->manager->stats, \
+ sock->statsindex[STATID_RECVFAIL]); \
+ return (DOIO_HARD); \
+ }
+
+ SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
+ SOFT_OR_HARD(ENETUNREACH, ISC_R_NETUNREACH);
+ SOFT_OR_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+ SOFT_OR_HARD(EHOSTDOWN, ISC_R_HOSTDOWN);
+ /* HPUX 11.11 can return EADDRNOTAVAIL. */
+ SOFT_OR_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+ SOFT_OR_HARD(ENOBUFS, ISC_R_NORESOURCES);
+ /* Should never get this one but it was seen. */
+#ifdef ENOPROTOOPT
+ SOFT_OR_HARD(ENOPROTOOPT, ISC_R_HOSTUNREACH);
+#endif
+ /*
+ * HPUX returns EPROTO and EINVAL on receiving some ICMP/ICMPv6
+ * errors.
+ */
+#ifdef EPROTO
+ SOFT_OR_HARD(EPROTO, ISC_R_HOSTUNREACH);
+#endif
+ SOFT_OR_HARD(EINVAL, ISC_R_HOSTUNREACH);
+
+#undef SOFT_OR_HARD
+#undef ALWAYS_HARD
+
+ dev->result = isc__errno2result(recv_errno);
+ inc_stats(sock->manager->stats,
+ sock->statsindex[STATID_RECVFAIL]);
+ return (DOIO_HARD);
+ }
+
+ /*
+ * On TCP and UNIX sockets, zero length reads indicate EOF,
+ * while on UDP sockets, zero length reads are perfectly valid,
+ * although strange.
+ */
+ switch (sock->type) {
+ case isc_sockettype_tcp:
+ case isc_sockettype_unix:
+ if (cc == 0)
+ return (DOIO_EOF);
+ break;
+ case isc_sockettype_udp:
+ case isc_sockettype_raw:
+ break;
+ case isc_sockettype_fdwatch:
+ default:
+ INSIST(0);
+ }
+
+ if (sock->type == isc_sockettype_udp) {
+ dev->address.length = msghdr.msg_namelen;
+ if (isc_sockaddr_getport(&dev->address) == 0) {
+ if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+ socket_log(sock, &dev->address, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_ZEROPORT,
+ "dropping source port zero packet");
+ }
+ return (DOIO_SOFT);
+ }
+ /*
+ * Simulate a firewall blocking UDP responses bigger than
+ * 'maxudp' bytes.
+ */
+ if (sock->manager->maxudp != 0 && cc > sock->manager->maxudp)
+ return (DOIO_SOFT);
+ }
+
+ socket_log(sock, &dev->address, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PKTRECV,
+ "packet received correctly");
+
+ /*
+ * Overflow bit detection. If we received MORE bytes than we should,
+ * this indicates an overflow situation. Set the flag in the
+ * dev entry and adjust how much we read by one.
+ */
+#ifdef ISC_PLATFORM_RECVOVERFLOW
+ if ((sock->type == isc_sockettype_udp) && ((size_t)cc > read_count)) {
+ dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;
+ cc--;
+ }
+#endif
+
+ /*
+ * If there are control messages attached, run through them and pull
+ * out the interesting bits.
+ */
+ process_cmsg(sock, &msghdr, dev);
+
+ /*
+ * update the buffers (if any) and the i/o count
+ */
+ dev->n += cc;
+ actual_count = cc;
+ buffer = ISC_LIST_HEAD(dev->bufferlist);
+ while (buffer != NULL && actual_count > 0U) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ if (isc_buffer_availablelength(buffer) <= actual_count) {
+ actual_count -= isc_buffer_availablelength(buffer);
+ isc_buffer_add(buffer,
+ isc_buffer_availablelength(buffer));
+ } else {
+ isc_buffer_add(buffer, actual_count);
+ actual_count = 0;
+ POST(actual_count);
+ break;
+ }
+ buffer = ISC_LIST_NEXT(buffer, link);
+ if (buffer == NULL) {
+ INSIST(actual_count == 0U);
+ }
+ }
+
+ /*
+ * If we read less than we expected, update counters,
+ * and let the upper layer poke the descriptor.
+ */
+ if (((size_t)cc != read_count) && (dev->n < dev->minimum))
+ return (DOIO_SOFT);
+
+ /*
+ * Full reads are posted, or partials if partials are ok.
+ */
+ dev->result = ISC_R_SUCCESS;
+ return (DOIO_SUCCESS);
+}
+
+/*
+ * Returns:
+ * DOIO_SUCCESS The operation succeeded. dev->result contains
+ * ISC_R_SUCCESS.
+ *
+ * DOIO_HARD A hard or unexpected I/O error was encountered.
+ * dev->result contains the appropriate error.
+ *
+ * DOIO_SOFT A soft I/O error was encountered. No senddone
+ * event was sent. The operation should be retried.
+ *
+ * No other return values are possible.
+ */
+static int
+doio_send(isc__socket_t *sock, isc_socketevent_t *dev) {
+ int cc;
+ struct iovec iov[MAXSCATTERGATHER_SEND];
+ size_t write_count;
+ struct msghdr msghdr;
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ int attempts = 0;
+ int send_errno;
+ char strbuf[ISC_STRERRORSIZE];
+ char cmsgbuf[SENDCMSGBUFLEN] = {0};
+
+ build_msghdr_send(sock, cmsgbuf, dev, &msghdr, iov, &write_count);
+
+ resend:
+ if (sock->type == isc_sockettype_udp &&
+ sock->manager->maxudp != 0 &&
+ write_count > (size_t)sock->manager->maxudp)
+ cc = write_count;
+ else
+ cc = sendmsg(sock->fd, &msghdr, 0);
+ send_errno = errno;
+
+ /*
+ * Check for error or block condition.
+ */
+ if (cc < 0) {
+ if (send_errno == EINTR && ++attempts < NRETRIES)
+ goto resend;
+
+ if (SOFT_ERROR(send_errno)) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ dev->result = ISC_R_WOULDBLOCK;
+ return (DOIO_SOFT);
+ }
+
+#define SOFT_OR_HARD(_system, _isc) \
+ if (send_errno == _system) { \
+ if (sock->connected) { \
+ dev->result = _isc; \
+ inc_stats(sock->manager->stats, \
+ sock->statsindex[STATID_SENDFAIL]); \
+ return (DOIO_HARD); \
+ } \
+ return (DOIO_SOFT); \
+ }
+#define ALWAYS_HARD(_system, _isc) \
+ if (send_errno == _system) { \
+ dev->result = _isc; \
+ inc_stats(sock->manager->stats, \
+ sock->statsindex[STATID_SENDFAIL]); \
+ return (DOIO_HARD); \
+ }
+
+ SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
+ ALWAYS_HARD(EACCES, ISC_R_NOPERM);
+ ALWAYS_HARD(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+ ALWAYS_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+ ALWAYS_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+#ifdef EHOSTDOWN
+ ALWAYS_HARD(EHOSTDOWN, ISC_R_HOSTUNREACH);
+#endif
+ ALWAYS_HARD(ENETUNREACH, ISC_R_NETUNREACH);
+ SOFT_OR_HARD(ENOBUFS, ISC_R_NORESOURCES);
+ ALWAYS_HARD(EPERM, ISC_R_HOSTUNREACH);
+ ALWAYS_HARD(EPIPE, ISC_R_NOTCONNECTED);
+ ALWAYS_HARD(ECONNRESET, ISC_R_CONNECTIONRESET);
+
+#undef SOFT_OR_HARD
+#undef ALWAYS_HARD
+
+ /*
+ * The other error types depend on whether or not the
+ * socket is UDP or TCP. If it is UDP, some errors
+ * that we expect to be fatal under TCP are merely
+ * annoying, and are really soft errors.
+ *
+ * However, these soft errors are still returned as
+ * a status.
+ */
+ isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf));
+ isc__strerror(send_errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "internal_send: %s: %s",
+ addrbuf, strbuf);
+ dev->result = isc__errno2result(send_errno);
+ inc_stats(sock->manager->stats,
+ sock->statsindex[STATID_SENDFAIL]);
+ return (DOIO_HARD);
+ }
+
+ if (cc == 0) {
+ inc_stats(sock->manager->stats,
+ sock->statsindex[STATID_SENDFAIL]);
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "doio_send: send() %s 0",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_RETURNED, "returned"));
+ }
+
+ /*
+ * If we write less than we expected, update counters, poke.
+ */
+ dev->n += cc;
+ if ((size_t)cc != write_count)
+ return (DOIO_SOFT);
+
+ /*
+ * Exactly what we wanted to write. We're done with this
+ * entry. Post its completion event.
+ */
+ dev->result = ISC_R_SUCCESS;
+ return (DOIO_SUCCESS);
+}
+
+/*
+ * Kill.
+ *
+ * Caller must ensure that the socket is not locked and no external
+ * references exist.
+ */
+static void
+socketclose(isc__socketmgr_t *manager, isc__socket_t *sock, int fd) {
+ isc_sockettype_t type = sock->type;
+ int lockid = FDLOCK_ID(fd);
+
+ /*
+ * No one has this socket open, so the watcher doesn't have to be
+ * poked, and the socket doesn't have to be locked.
+ */
+ LOCK(&manager->fdlock[lockid]);
+ manager->fds[fd] = NULL;
+ if (type == isc_sockettype_fdwatch)
+ manager->fdstate[fd] = CLOSED;
+ else
+ manager->fdstate[fd] = CLOSE_PENDING;
+ UNLOCK(&manager->fdlock[lockid]);
+ if (type == isc_sockettype_fdwatch) {
+ /*
+ * The caller may close the socket once this function returns,
+ * and `fd' may be reassigned for a new socket. So we do
+ * unwatch_fd() here, rather than defer it via select_poke().
+ * Note: this may complicate data protection among threads and
+ * may reduce performance due to additional locks. One way to
+ * solve this would be to dup() the watched descriptor, but we
+ * take a simpler approach at this moment.
+ */
+ (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+ (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+ } else
+ select_poke(manager, fd, SELECT_POKE_CLOSE);
+
+ inc_stats(manager->stats, sock->statsindex[STATID_CLOSE]);
+ if (sock->active == 1) {
+ dec_stats(manager->stats, sock->statsindex[STATID_ACTIVE]);
+ sock->active = 0;
+ }
+
+ /*
+ * update manager->maxfd here (XXX: this should be implemented more
+ * efficiently)
+ */
+#ifdef USE_SELECT
+ LOCK(&manager->lock);
+ if (manager->maxfd == fd) {
+ int i;
+
+ manager->maxfd = 0;
+ for (i = fd - 1; i >= 0; i--) {
+ lockid = FDLOCK_ID(i);
+
+ LOCK(&manager->fdlock[lockid]);
+ if (manager->fdstate[i] == MANAGED) {
+ manager->maxfd = i;
+ UNLOCK(&manager->fdlock[lockid]);
+ break;
+ }
+ UNLOCK(&manager->fdlock[lockid]);
+ }
+#ifdef ISC_PLATFORM_USETHREADS
+ if (manager->maxfd < manager->pipe_fds[0])
+ manager->maxfd = manager->pipe_fds[0];
+#endif
+ }
+
+ UNLOCK(&manager->lock);
+#endif /* USE_SELECT */
+}
+
+static void
+destroy(isc__socket_t **sockp) {
+ int fd;
+ isc__socket_t *sock = *sockp;
+ isc__socketmgr_t *manager = sock->manager;
+
+ socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_DESTROYING, "destroying");
+
+ INSIST(ISC_LIST_EMPTY(sock->connect_list));
+ INSIST(ISC_LIST_EMPTY(sock->accept_list));
+ INSIST(ISC_LIST_EMPTY(sock->recv_list));
+ INSIST(ISC_LIST_EMPTY(sock->send_list));
+ INSIST(sock->fd >= -1 && sock->fd < (int)manager->maxsocks);
+
+ if (sock->fd >= 0) {
+ fd = sock->fd;
+ sock->fd = -1;
+ socketclose(manager, sock, fd);
+ }
+
+ LOCK(&manager->lock);
+
+ ISC_LIST_UNLINK(manager->socklist, sock, link);
+
+#ifdef USE_WATCHER_THREAD
+ if (ISC_LIST_EMPTY(manager->socklist))
+ SIGNAL(&manager->shutdown_ok);
+#endif /* USE_WATCHER_THREAD */
+
+ /* can't unlock manager as its memory context is still used */
+ free_socket(sockp);
+
+ UNLOCK(&manager->lock);
+}
+
+static isc_result_t
+allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type,
+ isc__socket_t **socketp)
+{
+ isc__socket_t *sock;
+ isc_result_t result;
+
+ sock = isc_mem_get(manager->mctx, sizeof(*sock));
+
+ if (sock == NULL)
+ return (ISC_R_NOMEMORY);
+
+ sock->common.magic = 0;
+ sock->common.impmagic = 0;
+ sock->references = 0;
+
+ sock->manager = manager;
+ sock->type = type;
+ sock->fd = -1;
+ sock->dscp = 0; /* TOS/TCLASS is zero until set. */
+ sock->dupped = 0;
+ sock->statsindex = NULL;
+ sock->active = 0;
+
+ ISC_LINK_INIT(sock, link);
+
+
+ memset(sock->name, 0, sizeof(sock->name));
+ sock->tag = NULL;
+
+ /*
+ * Set up list of readers and writers to be initially empty.
+ */
+ ISC_LIST_INIT(sock->recv_list);
+ ISC_LIST_INIT(sock->send_list);
+ ISC_LIST_INIT(sock->accept_list);
+ ISC_LIST_INIT(sock->connect_list);
+ sock->pending_recv = 0;
+ sock->pending_send = 0;
+ sock->pending_accept = 0;
+ sock->listener = 0;
+ sock->connected = 0;
+ sock->connecting = 0;
+ sock->bound = 0;
+ sock->pktdscp = 0;
+
+ /*
+ * Initialize the lock.
+ */
+ result = isc_mutex_init(&sock->lock);
+ if (result != ISC_R_SUCCESS) {
+ sock->common.magic = 0;
+ sock->common.impmagic = 0;
+ goto error;
+ }
+
+ /*
+ * Initialize readable and writable events.
+ */
+ ISC_EVENT_INIT(&sock->readable_ev, sizeof(intev_t),
+ ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTR,
+ NULL, sock, sock, NULL, NULL);
+ ISC_EVENT_INIT(&sock->writable_ev, sizeof(intev_t),
+ ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTW,
+ NULL, sock, sock, NULL, NULL);
+
+ sock->common.magic = ISCAPI_SOCKET_MAGIC;
+ sock->common.impmagic = SOCKET_MAGIC;
+ *socketp = sock;
+
+ return (ISC_R_SUCCESS);
+
+ error:
+ isc_mem_put(manager->mctx, sock, sizeof(*sock));
+
+ return (result);
+}
+
+/*
+ * This event requires that the various lists be empty, that the reference
+ * count be 1, and that the magic number is valid. The other socket bits,
+ * like the lock, must be initialized as well. The fd associated must be
+ * marked as closed, by setting it to -1 on close, or this routine will
+ * also close the socket.
+ */
+static void
+free_socket(isc__socket_t **socketp) {
+ isc__socket_t *sock = *socketp;
+
+ INSIST(VALID_SOCKET(sock));
+ INSIST(sock->references == 0);
+ INSIST(!sock->connecting);
+ INSIST(!sock->pending_recv);
+ INSIST(!sock->pending_send);
+ INSIST(!sock->pending_accept);
+ INSIST(ISC_LIST_EMPTY(sock->recv_list));
+ INSIST(ISC_LIST_EMPTY(sock->send_list));
+ INSIST(ISC_LIST_EMPTY(sock->accept_list));
+ INSIST(ISC_LIST_EMPTY(sock->connect_list));
+ INSIST(!ISC_LINK_LINKED(sock, link));
+
+ sock->common.magic = 0;
+ sock->common.impmagic = 0;
+
+ DESTROYLOCK(&sock->lock);
+
+ isc_mem_put(sock->manager->mctx, sock, sizeof(*sock));
+
+ *socketp = NULL;
+}
+
+#ifdef SO_RCVBUF
+static isc_once_t rcvbuf_once = ISC_ONCE_INIT;
+static int rcvbuf = RCVBUFSIZE;
+
+static void
+set_rcvbuf(void) {
+ int fd;
+ int max = rcvbuf, min;
+ ISC_SOCKADDR_LEN_T len;
+
+ fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#if defined(ISC_PLATFORM_HAVEIPV6)
+ if (fd == -1) {
+ switch (errno) {
+ case EPROTONOSUPPORT:
+ case EPFNOSUPPORT:
+ case EAFNOSUPPORT:
+ /*
+ * Linux 2.2 (and maybe others) return EINVAL instead of
+ * EAFNOSUPPORT.
+ */
+ case EINVAL:
+ fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ break;
+ }
+ }
+#endif
+ if (fd == -1)
+ return;
+
+ len = sizeof(min);
+ if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&min, &len) == 0 &&
+ min < rcvbuf) {
+ again:
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf,
+ sizeof(rcvbuf)) == -1) {
+ if (errno == ENOBUFS && rcvbuf > min) {
+ max = rcvbuf - 1;
+ rcvbuf = (rcvbuf + min) / 2;
+ goto again;
+ } else {
+ rcvbuf = min;
+ goto cleanup;
+ }
+ } else
+ min = rcvbuf;
+ if (min != max) {
+ rcvbuf = max;
+ goto again;
+ }
+ }
+ cleanup:
+ close (fd);
+}
+#endif
+
+#ifdef SO_BSDCOMPAT
+/*
+ * This really should not be necessary to do. Having to workout
+ * which kernel version we are on at run time so that we don't cause
+ * the kernel to issue a warning about us using a deprecated socket option.
+ * Such warnings should *never* be on by default in production kernels.
+ *
+ * We can't do this a build time because executables are moved between
+ * machines and hence kernels.
+ *
+ * We can't just not set SO_BSDCOMAT because some kernels require it.
+ */
+
+static isc_once_t bsdcompat_once = ISC_ONCE_INIT;
+bool bsdcompat = true;
+
+static void
+clear_bsdcompat(void) {
+#ifdef __linux__
+ struct utsname buf;
+ char *endp;
+ long int major;
+ long int minor;
+
+ uname(&buf); /* Can only fail if buf is bad in Linux. */
+
+ /* Paranoia in parsing can be increased, but we trust uname(). */
+ major = strtol(buf.release, &endp, 10);
+ if (*endp == '.') {
+ minor = strtol(endp+1, &endp, 10);
+ if ((major > 2) || ((major == 2) && (minor >= 4))) {
+ bsdcompat = false;
+ }
+ }
+#endif /* __linux __ */
+}
+#endif
+
+static void
+use_min_mtu(isc__socket_t *sock) {
+#if !defined(IPV6_USE_MIN_MTU) && !defined(IPV6_MTU)
+ UNUSED(sock);
+#endif
+#ifdef IPV6_USE_MIN_MTU
+ /* use minimum MTU */
+ if (sock->pf == AF_INET6) {
+ int on = 1;
+ (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
+ (void *)&on, sizeof(on));
+ }
+#endif
+#if defined(IPV6_MTU)
+ /*
+ * Use minimum MTU on IPv6 sockets.
+ */
+ if (sock->pf == AF_INET6) {
+ int mtu = 1280;
+ (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MTU,
+ &mtu, sizeof(mtu));
+ }
+#endif
+}
+
+static void
+set_tcp_maxseg(isc__socket_t *sock, int size) {
+#ifdef TCP_MAXSEG
+ if (sock->type == isc_sockettype_tcp)
+ (void)setsockopt(sock->fd, IPPROTO_TCP, TCP_MAXSEG,
+ (void *)&size, sizeof(size));
+#endif
+}
+
+static isc_result_t
+opensocket(isc__socketmgr_t *manager, isc__socket_t *sock,
+ isc__socket_t *dup_socket)
+{
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+ const char *err = "socket";
+ int tries = 0;
+#if defined(USE_CMSG) || defined(SO_BSDCOMPAT) || defined(SO_NOSIGPIPE)
+ int on = 1;
+#endif
+#if defined(SO_RCVBUF)
+ ISC_SOCKADDR_LEN_T optlen;
+ int size = 0;
+#endif
+
+ again:
+ if (dup_socket == NULL) {
+ switch (sock->type) {
+ case isc_sockettype_udp:
+ sock->fd = socket(sock->pf, SOCK_DGRAM, IPPROTO_UDP);
+ break;
+ case isc_sockettype_tcp:
+ sock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP);
+ break;
+ case isc_sockettype_unix:
+ sock->fd = socket(sock->pf, SOCK_STREAM, 0);
+ break;
+ case isc_sockettype_raw:
+ errno = EPFNOSUPPORT;
+ /*
+ * PF_ROUTE is a alias for PF_NETLINK on linux.
+ */
+#if defined(PF_ROUTE)
+ if (sock->fd == -1 && sock->pf == PF_ROUTE) {
+#ifdef NETLINK_ROUTE
+ sock->fd = socket(sock->pf, SOCK_RAW,
+ NETLINK_ROUTE);
+#else
+ sock->fd = socket(sock->pf, SOCK_RAW, 0);
+#endif
+ if (sock->fd != -1) {
+#ifdef NETLINK_ROUTE
+ struct sockaddr_nl sa;
+ int n;
+
+ /*
+ * Do an implicit bind.
+ */
+ memset(&sa, 0, sizeof(sa));
+ sa.nl_family = AF_NETLINK;
+ sa.nl_groups = RTMGRP_IPV4_IFADDR |
+ RTMGRP_IPV6_IFADDR;
+ n = bind(sock->fd,
+ (struct sockaddr *) &sa,
+ sizeof(sa));
+ if (n < 0) {
+ close(sock->fd);
+ sock->fd = -1;
+ }
+#endif
+ sock->bound = 1;
+ }
+ }
+#endif
+ break;
+ case isc_sockettype_fdwatch:
+ /*
+ * We should not be called for isc_sockettype_fdwatch
+ * sockets.
+ */
+ INSIST(0);
+ break;
+ }
+ } else {
+ sock->fd = dup(dup_socket->fd);
+ sock->dupped = 1;
+ sock->bound = dup_socket->bound;
+ }
+ if (sock->fd == -1 && errno == EINTR && tries++ < 42)
+ goto again;
+
+#ifdef F_DUPFD
+ /*
+ * Leave a space for stdio and TCP to work in.
+ */
+ if (manager->reserved != 0 && sock->type == isc_sockettype_udp &&
+ sock->fd >= 0 && sock->fd < manager->reserved) {
+ int newfd, tmp;
+ newfd = fcntl(sock->fd, F_DUPFD, manager->reserved);
+ tmp = errno;
+ (void)close(sock->fd);
+ errno = tmp;
+ sock->fd = newfd;
+ err = "isc_socket_create: fcntl/reserved";
+ } else if (sock->fd >= 0 && sock->fd < 20) {
+ int newfd, tmp;
+ newfd = fcntl(sock->fd, F_DUPFD, 20);
+ tmp = errno;
+ (void)close(sock->fd);
+ errno = tmp;
+ sock->fd = newfd;
+ err = "isc_socket_create: fcntl";
+ }
+#endif
+
+ if (sock->fd >= (int)manager->maxsocks) {
+ (void)close(sock->fd);
+ isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_TOOMANYFDS,
+ "socket: file descriptor exceeds limit (%d/%u)",
+ sock->fd, manager->maxsocks);
+ inc_stats(manager->stats, sock->statsindex[STATID_OPENFAIL]);
+ return (ISC_R_NORESOURCES);
+ }
+
+ if (sock->fd < 0) {
+ switch (errno) {
+ case EMFILE:
+ case ENFILE:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_TOOMANYFDS,
+ "%s: %s", err, strbuf);
+ /* fallthrough */
+ case ENOBUFS:
+ inc_stats(manager->stats,
+ sock->statsindex[STATID_OPENFAIL]);
+ return (ISC_R_NORESOURCES);
+
+ case EPROTONOSUPPORT:
+ case EPFNOSUPPORT:
+ case EAFNOSUPPORT:
+ /*
+ * Linux 2.2 (and maybe others) return EINVAL instead of
+ * EAFNOSUPPORT.
+ */
+ case EINVAL:
+ inc_stats(manager->stats,
+ sock->statsindex[STATID_OPENFAIL]);
+ return (ISC_R_FAMILYNOSUPPORT);
+
+ default:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s() %s: %s", err,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ inc_stats(manager->stats,
+ sock->statsindex[STATID_OPENFAIL]);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ if (dup_socket != NULL)
+ goto setup_done;
+
+ result = make_nonblock(sock->fd);
+ if (result != ISC_R_SUCCESS) {
+ (void)close(sock->fd);
+ inc_stats(manager->stats, sock->statsindex[STATID_OPENFAIL]);
+ return (result);
+ }
+
+#ifdef SO_BSDCOMPAT
+ RUNTIME_CHECK(isc_once_do(&bsdcompat_once,
+ clear_bsdcompat) == ISC_R_SUCCESS);
+ if (sock->type != isc_sockettype_unix && bsdcompat &&
+ setsockopt(sock->fd, SOL_SOCKET, SO_BSDCOMPAT,
+ (void *)&on, sizeof(on)) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, SO_BSDCOMPAT) %s: %s",
+ sock->fd,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+ /* Press on... */
+ }
+#endif
+
+#ifdef SO_NOSIGPIPE
+ if (setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE,
+ (void *)&on, sizeof(on)) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, SO_NOSIGPIPE) %s: %s",
+ sock->fd,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+ /* Press on... */
+ }
+#endif
+
+ /*
+ * Use minimum mtu if possible.
+ */
+ if (sock->type == isc_sockettype_tcp && sock->pf == AF_INET6) {
+ use_min_mtu(sock);
+ set_tcp_maxseg(sock, 1280 - 20 - 40); /* 1280 - TCP - IPV6 */
+ }
+
+#if defined(USE_CMSG) || defined(SO_RCVBUF)
+ if (sock->type == isc_sockettype_udp) {
+
+#if defined(USE_CMSG)
+#if defined(SO_TIMESTAMP)
+ if (setsockopt(sock->fd, SOL_SOCKET, SO_TIMESTAMP,
+ (void *)&on, sizeof(on)) < 0
+ && errno != ENOPROTOOPT) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, SO_TIMESTAMP) %s: %s",
+ sock->fd,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ /* Press on... */
+ }
+#endif /* SO_TIMESTAMP */
+
+#if defined(ISC_PLATFORM_HAVEIPV6)
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+#ifdef IPV6_RECVPKTINFO
+ /* RFC 3542 */
+ if ((sock->pf == AF_INET6)
+ && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ (void *)&on, sizeof(on)) < 0)) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_RECVPKTINFO) "
+ "%s: %s", sock->fd,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+#else
+ /* RFC 2292 */
+ if ((sock->pf == AF_INET6)
+ && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO,
+ (void *)&on, sizeof(on)) < 0)) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_PKTINFO) %s: %s",
+ sock->fd,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+#endif /* IPV6_RECVPKTINFO */
+#endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
+#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT)
+ /*
+ * Turn off Path MTU discovery on IPv6/UDP sockets.
+ */
+ if (sock->pf == AF_INET6) {
+ int action = IPV6_PMTUDISC_DONT;
+ (void)setsockopt(sock->fd, IPPROTO_IPV6,
+ IPV6_MTU_DISCOVER, &action,
+ sizeof(action));
+ }
+#endif
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+#endif /* defined(USE_CMSG) */
+
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+ /*
+ * Turn off Path MTU discovery on IPv4/UDP sockets.
+ * Prefer IP_PMTUDISC_OMIT over IP_PMTUDISC_DONT
+ * if it available.
+ */
+ if (sock->pf == AF_INET) {
+ int action;
+#if defined(IP_PMTUDISC_OMIT)
+ action = IP_PMTUDISC_OMIT;
+ if (setsockopt(sock->fd, IPPROTO_IP,
+ IP_MTU_DISCOVER, &action,
+ sizeof(action)) < 0) {
+#endif
+ action = IP_PMTUDISC_DONT;
+ (void)setsockopt(sock->fd, IPPROTO_IP,
+ IP_MTU_DISCOVER,
+ &action, sizeof(action));
+#if defined(IP_PMTUDISC_OMIT)
+ }
+#endif
+ }
+#endif
+#if defined(IP_DONTFRAG)
+ /*
+ * Turn off Path MTU discovery on IPv4/UDP sockets.
+ */
+ if (sock->pf == AF_INET) {
+ int off = 0;
+ (void)setsockopt(sock->fd, IPPROTO_IP, IP_DONTFRAG,
+ &off, sizeof(off));
+ }
+#endif
+
+#if defined(SO_RCVBUF)
+ optlen = sizeof(size);
+ if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+ (void *)&size, &optlen) == 0 && size < rcvbuf) {
+ RUNTIME_CHECK(isc_once_do(&rcvbuf_once,
+ set_rcvbuf) == ISC_R_SUCCESS);
+ if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+ (void *)&rcvbuf, sizeof(rcvbuf)) == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, SO_RCVBUF, %d) %s: %s",
+ sock->fd, rcvbuf,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+ }
+#endif
+ }
+#ifdef IPV6_RECVTCLASS
+ if ((sock->pf == AF_INET6)
+ && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVTCLASS,
+ (void *)&on, sizeof(on)) < 0)) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_RECVTCLASS) "
+ "%s: %s", sock->fd,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+ }
+#endif
+#ifdef IP_RECVTOS
+ if ((sock->pf == AF_INET)
+ && (setsockopt(sock->fd, IPPROTO_IP, IP_RECVTOS,
+ (void *)&on, sizeof(on)) < 0)) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IP_RECVTOS) "
+ "%s: %s", sock->fd,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+ }
+#endif
+#endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */
+
+setup_done:
+ inc_stats(manager->stats, sock->statsindex[STATID_OPEN]);
+ if (sock->active == 0) {
+ inc_stats(manager->stats, sock->statsindex[STATID_ACTIVE]);
+ sock->active = 1;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Create a 'type' socket or duplicate an existing socket, managed
+ * by 'manager'. Events will be posted to 'task' and when dispatched
+ * 'action' will be called with 'arg' as the arg value. The new
+ * socket is returned in 'socketp'.
+ */
+static isc_result_t
+socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type,
+ isc_socket_t **socketp, isc_socket_t *dup_socket)
+{
+ isc__socket_t *sock = NULL;
+ isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0;
+ isc_result_t result;
+ int lockid;
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+ REQUIRE(type != isc_sockettype_fdwatch);
+
+ result = allocate_socket(manager, type, &sock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ switch (sock->type) {
+ case isc_sockettype_udp:
+ sock->statsindex =
+ (pf == AF_INET) ? udp4statsindex : udp6statsindex;
+#define DCSPPKT(pf) ((pf == AF_INET) ? ISC_NET_DSCPPKTV4 : ISC_NET_DSCPPKTV6)
+ sock->pktdscp = (isc_net_probedscp() & DCSPPKT(pf)) != 0;
+ break;
+ case isc_sockettype_tcp:
+ sock->statsindex =
+ (pf == AF_INET) ? tcp4statsindex : tcp6statsindex;
+ break;
+ case isc_sockettype_unix:
+ sock->statsindex = unixstatsindex;
+ break;
+ case isc_sockettype_raw:
+ sock->statsindex = rawstatsindex;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ sock->pf = pf;
+
+ result = opensocket(manager, sock, (isc__socket_t *)dup_socket);
+ if (result != ISC_R_SUCCESS) {
+ free_socket(&sock);
+ return (result);
+ }
+
+ sock->common.methods = (isc_socketmethods_t *)&socketmethods;
+ sock->references = 1;
+ *socketp = (isc_socket_t *)sock;
+
+ /*
+ * Note we don't have to lock the socket like we normally would because
+ * there are no external references to it yet.
+ */
+
+ lockid = FDLOCK_ID(sock->fd);
+ LOCK(&manager->fdlock[lockid]);
+ manager->fds[sock->fd] = sock;
+ manager->fdstate[sock->fd] = MANAGED;
+#if defined(USE_EPOLL)
+ manager->epoll_events[sock->fd] = 0;
+#endif
+#ifdef USE_DEVPOLL
+ INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 &&
+ sock->manager->fdpollinfo[sock->fd].want_write == 0);
+#endif
+ UNLOCK(&manager->fdlock[lockid]);
+
+ LOCK(&manager->lock);
+ ISC_LIST_APPEND(manager->socklist, sock, link);
+#ifdef USE_SELECT
+ if (manager->maxfd < sock->fd)
+ manager->maxfd = sock->fd;
+#endif
+ UNLOCK(&manager->lock);
+
+ socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_CREATED, dup_socket != NULL ? "dupped" : "created");
+
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Create a new 'type' socket managed by 'manager'. Events
+ * will be posted to 'task' and when dispatched 'action' will be
+ * called with 'arg' as the arg value. The new socket is returned
+ * in 'socketp'.
+ */
+isc_result_t
+isc__socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type,
+ isc_socket_t **socketp)
+{
+ return (socket_create(manager0, pf, type, socketp, NULL));
+}
+
+/*%
+ * Duplicate an existing socket. The new socket is returned
+ * in 'socketp'.
+ */
+isc_result_t
+isc__socket_dup(isc_socket_t *sock0, isc_socket_t **socketp) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ return (socket_create((isc_socketmgr_t *) sock->manager,
+ sock->pf, sock->type, socketp,
+ sock0));
+}
+
+isc_result_t
+isc__socket_open(isc_socket_t *sock0) {
+ isc_result_t result;
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ REQUIRE(sock->references == 1);
+ REQUIRE(sock->type != isc_sockettype_fdwatch);
+ UNLOCK(&sock->lock);
+ /*
+ * We don't need to retain the lock hereafter, since no one else has
+ * this socket.
+ */
+ REQUIRE(sock->fd == -1);
+
+ result = opensocket(sock->manager, sock, NULL);
+ if (result != ISC_R_SUCCESS)
+ sock->fd = -1;
+
+ if (result == ISC_R_SUCCESS) {
+ int lockid = FDLOCK_ID(sock->fd);
+
+ LOCK(&sock->manager->fdlock[lockid]);
+ sock->manager->fds[sock->fd] = sock;
+ sock->manager->fdstate[sock->fd] = MANAGED;
+#if defined(USE_EPOLL)
+ sock->manager->epoll_events[sock->fd] = 0;
+#endif
+#ifdef USE_DEVPOLL
+ INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 &&
+ sock->manager->fdpollinfo[sock->fd].want_write == 0);
+#endif
+ UNLOCK(&sock->manager->fdlock[lockid]);
+
+#ifdef USE_SELECT
+ LOCK(&sock->manager->lock);
+ if (sock->manager->maxfd < sock->fd)
+ sock->manager->maxfd = sock->fd;
+ UNLOCK(&sock->manager->lock);
+#endif
+ }
+
+ return (result);
+}
+
+/*
+ * Create a new 'type' socket managed by 'manager'. Events
+ * will be posted to 'task' and when dispatched 'action' will be
+ * called with 'arg' as the arg value. The new socket is returned
+ * in 'socketp'.
+ */
+isc_result_t
+isc__socket_fdwatchcreate(isc_socketmgr_t *manager0, int fd, int flags,
+ isc_sockfdwatch_t callback, void *cbarg,
+ isc_task_t *task, isc_socket_t **socketp)
+{
+ isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0;
+ isc__socket_t *sock = NULL;
+ isc_result_t result;
+ int lockid;
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ if (fd < 0 || (unsigned int)fd >= manager->maxsocks)
+ return (ISC_R_RANGE);
+
+ result = allocate_socket(manager, isc_sockettype_fdwatch, &sock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ sock->fd = fd;
+ sock->fdwatcharg = cbarg;
+ sock->fdwatchcb = callback;
+ sock->fdwatchflags = flags;
+ sock->fdwatchtask = task;
+ sock->statsindex = fdwatchstatsindex;
+
+ sock->common.methods = (isc_socketmethods_t *)&socketmethods;
+ sock->references = 1;
+ *socketp = (isc_socket_t *)sock;
+
+ /*
+ * Note we don't have to lock the socket like we normally would because
+ * there are no external references to it yet.
+ */
+
+ lockid = FDLOCK_ID(sock->fd);
+ LOCK(&manager->fdlock[lockid]);
+ manager->fds[sock->fd] = sock;
+ manager->fdstate[sock->fd] = MANAGED;
+#if defined(USE_EPOLL)
+ manager->epoll_events[sock->fd] = 0;
+#endif
+ UNLOCK(&manager->fdlock[lockid]);
+
+ LOCK(&manager->lock);
+ ISC_LIST_APPEND(manager->socklist, sock, link);
+#ifdef USE_SELECT
+ if (manager->maxfd < sock->fd)
+ manager->maxfd = sock->fd;
+#endif
+ UNLOCK(&manager->lock);
+
+ if (flags & ISC_SOCKFDWATCH_READ)
+ select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+ if (flags & ISC_SOCKFDWATCH_WRITE)
+ select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
+
+ socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_CREATED, "fdwatch-created");
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Indicate to the manager that it should watch the socket again.
+ * This can be used to restart watching if the previous event handler
+ * didn't indicate there was more data to be processed. Primarily
+ * it is for writing but could be used for reading if desired
+ */
+
+isc_result_t
+isc__socket_fdwatchpoke(isc_socket_t *sock0, int flags)
+{
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ /*
+ * We check both flags first to allow us to get the lock
+ * once but only if we need it.
+ */
+
+ if ((flags & (ISC_SOCKFDWATCH_READ | ISC_SOCKFDWATCH_WRITE)) != 0) {
+ LOCK(&sock->lock);
+ if (((flags & ISC_SOCKFDWATCH_READ) != 0) &&
+ !sock->pending_recv)
+ select_poke(sock->manager, sock->fd,
+ SELECT_POKE_READ);
+ if (((flags & ISC_SOCKFDWATCH_WRITE) != 0) &&
+ !sock->pending_send)
+ select_poke(sock->manager, sock->fd,
+ SELECT_POKE_WRITE);
+ UNLOCK(&sock->lock);
+ }
+
+ socket_log(sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_POKED, "fdwatch-poked flags: %d", flags);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Attach to a socket. Caller must explicitly detach when it is done.
+ */
+void
+isc__socket_attach(isc_socket_t *sock0, isc_socket_t **socketp) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ LOCK(&sock->lock);
+ sock->references++;
+ UNLOCK(&sock->lock);
+
+ *socketp = (isc_socket_t *)sock;
+}
+
+/*
+ * Dereference a socket. If this is the last reference to it, clean things
+ * up by destroying the socket.
+ */
+void
+isc__socket_detach(isc_socket_t **socketp) {
+ isc__socket_t *sock;
+ bool kill_socket = false;
+
+ REQUIRE(socketp != NULL);
+ sock = (isc__socket_t *)*socketp;
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ REQUIRE(sock->references > 0);
+ sock->references--;
+ if (sock->references == 0)
+ kill_socket = true;
+ UNLOCK(&sock->lock);
+
+ if (kill_socket)
+ destroy(&sock);
+
+ *socketp = NULL;
+}
+
+isc_result_t
+isc__socket_close(isc_socket_t *sock0) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ int fd;
+ isc__socketmgr_t *manager;
+
+ fflush(stdout);
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+
+ REQUIRE(sock->references == 1);
+ REQUIRE(sock->type != isc_sockettype_fdwatch);
+ REQUIRE(sock->fd >= 0 && sock->fd < (int)sock->manager->maxsocks);
+
+ INSIST(!sock->connecting);
+ INSIST(!sock->pending_recv);
+ INSIST(!sock->pending_send);
+ INSIST(!sock->pending_accept);
+ INSIST(ISC_LIST_EMPTY(sock->recv_list));
+ INSIST(ISC_LIST_EMPTY(sock->send_list));
+ INSIST(ISC_LIST_EMPTY(sock->accept_list));
+ INSIST(ISC_LIST_EMPTY(sock->connect_list));
+
+ manager = sock->manager;
+ fd = sock->fd;
+ sock->fd = -1;
+ sock->dupped = 0;
+ memset(sock->name, 0, sizeof(sock->name));
+ sock->tag = NULL;
+ sock->listener = 0;
+ sock->connected = 0;
+ sock->connecting = 0;
+ sock->bound = 0;
+ isc_sockaddr_any(&sock->peer_address);
+
+ UNLOCK(&sock->lock);
+
+ socketclose(manager, sock, fd);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * I/O is possible on a given socket. Schedule an event to this task that
+ * will call an internal function to do the I/O. This will charge the
+ * task with the I/O operation and let our select loop handler get back
+ * to doing something real as fast as possible.
+ *
+ * The socket and manager must be locked before calling this function.
+ */
+static void
+dispatch_recv(isc__socket_t *sock) {
+ intev_t *iev;
+ isc_socketevent_t *ev;
+ isc_task_t *sender;
+
+ INSIST(!sock->pending_recv);
+
+ if (sock->type != isc_sockettype_fdwatch) {
+ ev = ISC_LIST_HEAD(sock->recv_list);
+ if (ev == NULL)
+ return;
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "dispatch_recv: event %p -> task %p",
+ ev, ev->ev_sender);
+ sender = ev->ev_sender;
+ } else {
+ sender = sock->fdwatchtask;
+ }
+
+ sock->pending_recv = 1;
+ iev = &sock->readable_ev;
+
+ sock->references++;
+ iev->ev_sender = sock;
+ if (sock->type == isc_sockettype_fdwatch)
+ iev->ev_action = internal_fdwatch_read;
+ else
+ iev->ev_action = internal_recv;
+ iev->ev_arg = sock;
+
+ isc_task_send(sender, (isc_event_t **)&iev);
+}
+
+static void
+dispatch_send(isc__socket_t *sock) {
+ intev_t *iev;
+ isc_socketevent_t *ev;
+ isc_task_t *sender;
+
+ INSIST(!sock->pending_send);
+
+ if (sock->type != isc_sockettype_fdwatch) {
+ ev = ISC_LIST_HEAD(sock->send_list);
+ if (ev == NULL)
+ return;
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "dispatch_send: event %p -> task %p",
+ ev, ev->ev_sender);
+ sender = ev->ev_sender;
+ } else {
+ sender = sock->fdwatchtask;
+ }
+
+ sock->pending_send = 1;
+ iev = &sock->writable_ev;
+
+ sock->references++;
+ iev->ev_sender = sock;
+ if (sock->type == isc_sockettype_fdwatch)
+ iev->ev_action = internal_fdwatch_write;
+ else
+ iev->ev_action = internal_send;
+ iev->ev_arg = sock;
+
+ isc_task_send(sender, (isc_event_t **)&iev);
+}
+
+/*
+ * Dispatch an internal accept event.
+ */
+static void
+dispatch_accept(isc__socket_t *sock) {
+ intev_t *iev;
+ isc_socket_newconnev_t *ev;
+
+ INSIST(!sock->pending_accept);
+
+ /*
+ * Are there any done events left, or were they all canceled
+ * before the manager got the socket lock?
+ */
+ ev = ISC_LIST_HEAD(sock->accept_list);
+ if (ev == NULL)
+ return;
+
+ sock->pending_accept = 1;
+ iev = &sock->readable_ev;
+
+ sock->references++; /* keep socket around for this internal event */
+ iev->ev_sender = sock;
+ iev->ev_action = internal_accept;
+ iev->ev_arg = sock;
+
+ isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
+}
+
+static void
+dispatch_connect(isc__socket_t *sock) {
+ intev_t *iev;
+ isc_socket_connev_t *ev;
+
+ iev = &sock->writable_ev;
+
+ ev = ISC_LIST_HEAD(sock->connect_list);
+ INSIST(ev != NULL); /* XXX */
+
+ INSIST(sock->connecting);
+
+ sock->references++; /* keep socket around for this internal event */
+ iev->ev_sender = sock;
+ iev->ev_action = internal_connect;
+ iev->ev_arg = sock;
+
+ isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
+}
+
+/*
+ * Dequeue an item off the given socket's read queue, set the result code
+ * in the done event to the one provided, and send it to the task it was
+ * destined for.
+ *
+ * If the event to be sent is on a list, remove it before sending. If
+ * asked to, send and detach from the socket as well.
+ *
+ * Caller must have the socket locked if the event is attached to the socket.
+ */
+static void
+send_recvdone_event(isc__socket_t *sock, isc_socketevent_t **dev) {
+ isc_task_t *task;
+
+ task = (*dev)->ev_sender;
+
+ (*dev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*dev, ev_link))
+ ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
+
+ if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
+ == ISC_SOCKEVENTATTR_ATTACHED)
+ isc_task_sendanddetach(&task, (isc_event_t **)dev);
+ else
+ isc_task_send(task, (isc_event_t **)dev);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ *
+ * Caller must have the socket locked if the event is attached to the socket.
+ */
+static void
+send_senddone_event(isc__socket_t *sock, isc_socketevent_t **dev) {
+ isc_task_t *task;
+
+ INSIST(dev != NULL && *dev != NULL);
+
+ task = (*dev)->ev_sender;
+ (*dev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*dev, ev_link))
+ ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);
+
+ if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
+ == ISC_SOCKEVENTATTR_ATTACHED)
+ isc_task_sendanddetach(&task, (isc_event_t **)dev);
+ else
+ isc_task_send(task, (isc_event_t **)dev);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ *
+ * Caller must have the socket locked if the event is attached to the socket.
+ */
+static void
+send_connectdone_event(isc__socket_t *sock, isc_socket_connev_t **dev) {
+ isc_task_t *task;
+
+ INSIST(dev != NULL && *dev != NULL);
+
+ task = (*dev)->ev_sender;
+ (*dev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*dev, ev_link))
+ ISC_LIST_DEQUEUE(sock->connect_list, *dev, ev_link);
+
+ isc_task_sendanddetach(&task, (isc_event_t **)dev);
+}
+
+/*
+ * Call accept() on a socket, to get the new file descriptor. The listen
+ * socket is used as a prototype to create a new isc_socket_t. The new
+ * socket has one outstanding reference. The task receiving the event
+ * will be detached from just after the event is delivered.
+ *
+ * On entry to this function, the event delivered is the internal
+ * readable event, and the first item on the accept_list should be
+ * the done event we want to send. If the list is empty, this is a no-op,
+ * so just unlock and return.
+ */
+static void
+internal_accept(isc_task_t *me, isc_event_t *ev) {
+ isc__socket_t *sock;
+ isc__socketmgr_t *manager;
+ isc_socket_newconnev_t *dev;
+ isc_task_t *task;
+ ISC_SOCKADDR_LEN_T addrlen;
+ int fd;
+ isc_result_t result = ISC_R_SUCCESS;
+ char strbuf[ISC_STRERRORSIZE];
+ const char *err = "accept";
+
+ UNUSED(me);
+
+ sock = ev->ev_sender;
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ socket_log(sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+ "internal_accept called, locked socket");
+
+ manager = sock->manager;
+ INSIST(VALID_MANAGER(manager));
+
+ INSIST(sock->listener);
+ INSIST(sock->pending_accept == 1);
+ sock->pending_accept = 0;
+
+ INSIST(sock->references > 0);
+ sock->references--; /* the internal event is done with this socket */
+ if (sock->references == 0) {
+ UNLOCK(&sock->lock);
+ destroy(&sock);
+ return;
+ }
+
+ /*
+ * Get the first item off the accept list.
+ * If it is empty, unlock the socket and return.
+ */
+ dev = ISC_LIST_HEAD(sock->accept_list);
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return;
+ }
+
+ /*
+ * Try to accept the new connection. If the accept fails with
+ * EAGAIN or EINTR, simply poke the watcher to watch this socket
+ * again. Also ignore ECONNRESET, which has been reported to
+ * be spuriously returned on Linux 2.2.19 although it is not
+ * a documented error for accept(). ECONNABORTED has been
+ * reported for Solaris 8. The rest are thrown in not because
+ * we have seen them but because they are ignored by other
+ * daemons such as BIND 8 and Apache.
+ */
+
+ addrlen = sizeof(NEWCONNSOCK(dev)->peer_address.type);
+ memset(&NEWCONNSOCK(dev)->peer_address.type, 0, addrlen);
+ fd = accept(sock->fd, &NEWCONNSOCK(dev)->peer_address.type.sa,
+ (void *)&addrlen);
+
+#ifdef F_DUPFD
+ /*
+ * Leave a space for stdio to work in.
+ */
+ if (fd >= 0 && fd < 20) {
+ int newfd, tmp;
+ newfd = fcntl(fd, F_DUPFD, 20);
+ tmp = errno;
+ (void)close(fd);
+ errno = tmp;
+ fd = newfd;
+ err = "accept/fcntl";
+ }
+#endif
+
+ if (fd < 0) {
+ if (SOFT_ERROR(errno))
+ goto soft_error;
+ switch (errno) {
+ case ENFILE:
+ case EMFILE:
+ isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_TOOMANYFDS,
+ "%s: too many open file descriptors",
+ err);
+ goto soft_error;
+
+ case ENOBUFS:
+ case ENOMEM:
+ case ECONNRESET:
+ case ECONNABORTED:
+ case EHOSTUNREACH:
+ case EHOSTDOWN:
+ case ENETUNREACH:
+ case ENETDOWN:
+ case ECONNREFUSED:
+#ifdef EPROTO
+ case EPROTO:
+#endif
+#ifdef ENONET
+ case ENONET:
+#endif
+ goto soft_error;
+ default:
+ break;
+ }
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_accept: %s() %s: %s", err,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ fd = -1;
+ result = ISC_R_UNEXPECTED;
+ } else {
+ if (addrlen == 0U) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_accept(): "
+ "accept() failed to return "
+ "remote address");
+
+ (void)close(fd);
+ goto soft_error;
+ } else if (NEWCONNSOCK(dev)->peer_address.type.sa.sa_family !=
+ sock->pf)
+ {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_accept(): "
+ "accept() returned peer address "
+ "family %u (expected %u)",
+ NEWCONNSOCK(dev)->peer_address.
+ type.sa.sa_family,
+ sock->pf);
+ (void)close(fd);
+ goto soft_error;
+ } else if (fd >= (int)manager->maxsocks) {
+ isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_TOOMANYFDS,
+ "accept: "
+ "file descriptor exceeds limit (%d/%u)",
+ fd, manager->maxsocks);
+ (void)close(fd);
+ goto soft_error;
+ }
+ }
+
+ if (fd != -1) {
+ NEWCONNSOCK(dev)->peer_address.length = addrlen;
+ NEWCONNSOCK(dev)->pf = sock->pf;
+ }
+
+ /*
+ * Pull off the done event.
+ */
+ ISC_LIST_UNLINK(sock->accept_list, dev, ev_link);
+
+ /*
+ * Poke watcher if there are more pending accepts.
+ */
+ if (!ISC_LIST_EMPTY(sock->accept_list))
+ select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
+
+ UNLOCK(&sock->lock);
+
+ if (fd != -1) {
+ result = make_nonblock(fd);
+ if (result != ISC_R_SUCCESS) {
+ (void)close(fd);
+ fd = -1;
+ }
+ }
+
+ /*
+ * -1 means the new socket didn't happen.
+ */
+ if (fd != -1) {
+ int lockid = FDLOCK_ID(fd);
+
+ NEWCONNSOCK(dev)->fd = fd;
+ NEWCONNSOCK(dev)->bound = 1;
+ NEWCONNSOCK(dev)->connected = 1;
+
+ /*
+ * Use minimum mtu if possible.
+ */
+ use_min_mtu(NEWCONNSOCK(dev));
+ set_tcp_maxseg(NEWCONNSOCK(dev), 1280 - 20 - 40);
+
+ /*
+ * Ensure DSCP settings are inherited across accept.
+ */
+ setdscp(NEWCONNSOCK(dev), sock->dscp);
+
+ /*
+ * Save away the remote address
+ */
+ dev->address = NEWCONNSOCK(dev)->peer_address;
+
+ if (NEWCONNSOCK(dev)->active == 0) {
+ inc_stats(manager->stats,
+ NEWCONNSOCK(dev)->statsindex[STATID_ACTIVE]);
+ NEWCONNSOCK(dev)->active = 1;
+ }
+
+ LOCK(&manager->fdlock[lockid]);
+ manager->fds[fd] = NEWCONNSOCK(dev);
+ manager->fdstate[fd] = MANAGED;
+#if defined(USE_EPOLL)
+ manager->epoll_events[fd] = 0;
+#endif
+ UNLOCK(&manager->fdlock[lockid]);
+
+ LOCK(&manager->lock);
+
+#ifdef USE_SELECT
+ if (manager->maxfd < fd)
+ manager->maxfd = fd;
+#endif
+
+ socket_log(sock, &NEWCONNSOCK(dev)->peer_address, CREATION,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
+ "accepted connection, new socket %p",
+ dev->newsocket);
+
+ ISC_LIST_APPEND(manager->socklist, NEWCONNSOCK(dev), link);
+
+ UNLOCK(&manager->lock);
+
+ inc_stats(manager->stats, sock->statsindex[STATID_ACCEPT]);
+ } else {
+ inc_stats(manager->stats, sock->statsindex[STATID_ACCEPTFAIL]);
+ NEWCONNSOCK(dev)->references--;
+ free_socket((isc__socket_t **)&dev->newsocket);
+ }
+
+ /*
+ * Fill in the done event details and send it off.
+ */
+ dev->result = result;
+ task = dev->ev_sender;
+ dev->ev_sender = sock;
+
+ isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev));
+ return;
+
+ soft_error:
+ select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
+ UNLOCK(&sock->lock);
+
+ inc_stats(manager->stats, sock->statsindex[STATID_ACCEPTFAIL]);
+ return;
+}
+
+static void
+internal_recv(isc_task_t *me, isc_event_t *ev) {
+ isc_socketevent_t *dev;
+ isc__socket_t *sock;
+
+ INSIST(ev->ev_type == ISC_SOCKEVENT_INTR);
+
+ sock = ev->ev_sender;
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ socket_log(sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
+ "internal_recv: task %p got event %p", me, ev);
+
+ INSIST(sock->pending_recv == 1);
+ sock->pending_recv = 0;
+
+ INSIST(sock->references > 0);
+ sock->references--; /* the internal event is done with this socket */
+ if (sock->references == 0) {
+ UNLOCK(&sock->lock);
+ destroy(&sock);
+ return;
+ }
+
+ /*
+ * Try to do as much I/O as possible on this socket. There are no
+ * limits here, currently.
+ */
+ dev = ISC_LIST_HEAD(sock->recv_list);
+ while (dev != NULL) {
+ switch (doio_recv(sock, dev)) {
+ case DOIO_SOFT:
+ goto poke;
+
+ case DOIO_EOF:
+ /*
+ * read of 0 means the remote end was closed.
+ * Run through the event queue and dispatch all
+ * the events with an EOF result code.
+ */
+ do {
+ dev->result = ISC_R_EOF;
+ send_recvdone_event(sock, &dev);
+ dev = ISC_LIST_HEAD(sock->recv_list);
+ } while (dev != NULL);
+ goto poke;
+
+ case DOIO_SUCCESS:
+ case DOIO_HARD:
+ send_recvdone_event(sock, &dev);
+ break;
+ }
+
+ dev = ISC_LIST_HEAD(sock->recv_list);
+ }
+
+ poke:
+ if (!ISC_LIST_EMPTY(sock->recv_list))
+ select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+
+ UNLOCK(&sock->lock);
+}
+
+static void
+internal_send(isc_task_t *me, isc_event_t *ev) {
+ isc_socketevent_t *dev;
+ isc__socket_t *sock;
+
+ INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
+
+ /*
+ * Find out what socket this is and lock it.
+ */
+ sock = (isc__socket_t *)ev->ev_sender;
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ socket_log(sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
+ "internal_send: task %p got event %p", me, ev);
+
+ INSIST(sock->pending_send == 1);
+ sock->pending_send = 0;
+
+ INSIST(sock->references > 0);
+ sock->references--; /* the internal event is done with this socket */
+ if (sock->references == 0) {
+ UNLOCK(&sock->lock);
+ destroy(&sock);
+ return;
+ }
+
+ /*
+ * Try to do as much I/O as possible on this socket. There are no
+ * limits here, currently.
+ */
+ dev = ISC_LIST_HEAD(sock->send_list);
+ while (dev != NULL) {
+ switch (doio_send(sock, dev)) {
+ case DOIO_SOFT:
+ goto poke;
+
+ case DOIO_HARD:
+ case DOIO_SUCCESS:
+ send_senddone_event(sock, &dev);
+ break;
+ }
+
+ dev = ISC_LIST_HEAD(sock->send_list);
+ }
+
+ poke:
+ if (!ISC_LIST_EMPTY(sock->send_list))
+ select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
+
+ UNLOCK(&sock->lock);
+}
+
+static void
+internal_fdwatch_write(isc_task_t *me, isc_event_t *ev) {
+ isc__socket_t *sock;
+ int more_data;
+
+ INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
+
+ /*
+ * Find out what socket this is and lock it.
+ */
+ sock = (isc__socket_t *)ev->ev_sender;
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ socket_log(sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
+ "internal_fdwatch_write: task %p got event %p", me, ev);
+
+ INSIST(sock->pending_send == 1);
+
+ UNLOCK(&sock->lock);
+ more_data = (sock->fdwatchcb)(me, (isc_socket_t *)sock,
+ sock->fdwatcharg, ISC_SOCKFDWATCH_WRITE);
+ LOCK(&sock->lock);
+
+ sock->pending_send = 0;
+
+ INSIST(sock->references > 0);
+ sock->references--; /* the internal event is done with this socket */
+ if (sock->references == 0) {
+ UNLOCK(&sock->lock);
+ destroy(&sock);
+ return;
+ }
+
+ if (more_data)
+ select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
+
+ UNLOCK(&sock->lock);
+}
+
+static void
+internal_fdwatch_read(isc_task_t *me, isc_event_t *ev) {
+ isc__socket_t *sock;
+ int more_data;
+
+ INSIST(ev->ev_type == ISC_SOCKEVENT_INTR);
+
+ /*
+ * Find out what socket this is and lock it.
+ */
+ sock = (isc__socket_t *)ev->ev_sender;
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ socket_log(sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
+ "internal_fdwatch_read: task %p got event %p", me, ev);
+
+ INSIST(sock->pending_recv == 1);
+
+ UNLOCK(&sock->lock);
+ more_data = (sock->fdwatchcb)(me, (isc_socket_t *)sock,
+ sock->fdwatcharg, ISC_SOCKFDWATCH_READ);
+ LOCK(&sock->lock);
+
+ sock->pending_recv = 0;
+
+ INSIST(sock->references > 0);
+ sock->references--; /* the internal event is done with this socket */
+ if (sock->references == 0) {
+ UNLOCK(&sock->lock);
+ destroy(&sock);
+ return;
+ }
+
+ if (more_data)
+ select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+
+ UNLOCK(&sock->lock);
+}
+
+/*
+ * Process read/writes on each fd here. Avoid locking
+ * and unlocking twice if both reads and writes are possible.
+ */
+static void
+process_fd(isc__socketmgr_t *manager, int fd, bool readable,
+ bool writeable)
+{
+ isc__socket_t *sock;
+ bool unlock_sock;
+ bool unwatch_read = false, unwatch_write = false;
+ int lockid = FDLOCK_ID(fd);
+
+ /*
+ * If the socket is going to be closed, don't do more I/O.
+ */
+ LOCK(&manager->fdlock[lockid]);
+ if (manager->fdstate[fd] == CLOSE_PENDING) {
+ UNLOCK(&manager->fdlock[lockid]);
+
+ (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+ (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+ return;
+ }
+
+ sock = manager->fds[fd];
+ unlock_sock = false;
+ if (readable) {
+ if (sock == NULL) {
+ unwatch_read = true;
+ goto check_write;
+ }
+ unlock_sock = true;
+ LOCK(&sock->lock);
+ if (!SOCK_DEAD(sock)) {
+ if (sock->listener)
+ dispatch_accept(sock);
+ else
+ dispatch_recv(sock);
+ }
+ unwatch_read = true;
+ }
+check_write:
+ if (writeable) {
+ if (sock == NULL) {
+ unwatch_write = true;
+ goto unlock_fd;
+ }
+ if (!unlock_sock) {
+ unlock_sock = true;
+ LOCK(&sock->lock);
+ }
+ if (!SOCK_DEAD(sock)) {
+ if (sock->connecting)
+ dispatch_connect(sock);
+ else
+ dispatch_send(sock);
+ }
+ unwatch_write = true;
+ }
+ if (unlock_sock)
+ UNLOCK(&sock->lock);
+
+ unlock_fd:
+ UNLOCK(&manager->fdlock[lockid]);
+ if (unwatch_read)
+ (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+ if (unwatch_write)
+ (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+
+}
+
+#ifdef USE_KQUEUE
+static bool
+process_fds(isc__socketmgr_t *manager, struct kevent *events, int nevents) {
+ int i;
+ bool readable, writable;
+ bool done = false;
+#ifdef USE_WATCHER_THREAD
+ bool have_ctlevent = false;
+#endif
+
+ if (nevents == manager->nevents) {
+ /*
+ * This is not an error, but something unexpected. If this
+ * happens, it may indicate the need for increasing
+ * ISC_SOCKET_MAXEVENTS.
+ */
+ manager_log(manager, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_INFO,
+ "maximum number of FD events (%d) received",
+ nevents);
+ }
+
+ for (i = 0; i < nevents; i++) {
+ REQUIRE(events[i].ident < manager->maxsocks);
+#ifdef USE_WATCHER_THREAD
+ if (events[i].ident == (uintptr_t)manager->pipe_fds[0]) {
+ have_ctlevent = true;
+ continue;
+ }
+#endif
+ readable = (events[i].filter == EVFILT_READ);
+ writable = (events[i].filter == EVFILT_WRITE);
+ process_fd(manager, events[i].ident, readable, writable);
+ }
+
+#ifdef USE_WATCHER_THREAD
+ if (have_ctlevent)
+ done = process_ctlfd(manager);
+#endif
+
+ return (done);
+}
+#elif defined(USE_EPOLL)
+static bool
+process_fds(isc__socketmgr_t *manager, struct epoll_event *events, int nevents)
+{
+ int i;
+ bool done = false;
+#ifdef USE_WATCHER_THREAD
+ bool have_ctlevent = false;
+#endif
+
+ if (nevents == manager->nevents) {
+ manager_log(manager, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_INFO,
+ "maximum number of FD events (%d) received",
+ nevents);
+ }
+
+ for (i = 0; i < nevents; i++) {
+ REQUIRE(events[i].data.fd < (int)manager->maxsocks);
+#ifdef USE_WATCHER_THREAD
+ if (events[i].data.fd == manager->pipe_fds[0]) {
+ have_ctlevent = true;
+ continue;
+ }
+#endif
+ if ((events[i].events & EPOLLERR) != 0 ||
+ (events[i].events & EPOLLHUP) != 0) {
+ /*
+ * epoll does not set IN/OUT bits on an erroneous
+ * condition, so we need to try both anyway. This is a
+ * bit inefficient, but should be okay for such rare
+ * events. Note also that the read or write attempt
+ * won't block because we use non-blocking sockets.
+ */
+ int fd = events[i].data.fd;
+ events[i].events |= manager->epoll_events[fd];
+ }
+ process_fd(manager, events[i].data.fd,
+ (events[i].events & EPOLLIN) != 0,
+ (events[i].events & EPOLLOUT) != 0);
+ }
+
+#ifdef USE_WATCHER_THREAD
+ if (have_ctlevent)
+ done = process_ctlfd(manager);
+#endif
+
+ return (done);
+}
+#elif defined(USE_DEVPOLL)
+static bool
+process_fds(isc__socketmgr_t *manager, struct pollfd *events, int nevents) {
+ int i;
+ bool done = false;
+#ifdef USE_WATCHER_THREAD
+ bool have_ctlevent = false;
+#endif
+
+ if (nevents == manager->nevents) {
+ manager_log(manager, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_INFO,
+ "maximum number of FD events (%d) received",
+ nevents);
+ }
+
+ for (i = 0; i < nevents; i++) {
+ REQUIRE(events[i].fd < (int)manager->maxsocks);
+#ifdef USE_WATCHER_THREAD
+ if (events[i].fd == manager->pipe_fds[0]) {
+ have_ctlevent = true;
+ continue;
+ }
+#endif
+ process_fd(manager, events[i].fd,
+ (events[i].events & POLLIN) != 0,
+ (events[i].events & POLLOUT) != 0);
+ }
+
+#ifdef USE_WATCHER_THREAD
+ if (have_ctlevent)
+ done = process_ctlfd(manager);
+#endif
+
+ return (done);
+}
+#elif defined(USE_SELECT)
+static void
+process_fds(isc__socketmgr_t *manager, int maxfd, fd_set *readfds,
+ fd_set *writefds)
+{
+ int i;
+
+ REQUIRE(maxfd <= (int)manager->maxsocks);
+
+ for (i = 0; i < maxfd; i++) {
+#ifdef USE_WATCHER_THREAD
+ if (i == manager->pipe_fds[0] || i == manager->pipe_fds[1])
+ continue;
+#endif /* USE_WATCHER_THREAD */
+ process_fd(manager, i, FD_ISSET(i, readfds),
+ FD_ISSET(i, writefds));
+ }
+}
+#endif
+
+#ifdef USE_WATCHER_THREAD
+static bool
+process_ctlfd(isc__socketmgr_t *manager) {
+ int msg, fd;
+
+ for (;;) {
+ select_readmsg(manager, &fd, &msg);
+
+ manager_log(manager, IOEVENT,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_WATCHERMSG,
+ "watcher got message %d "
+ "for socket %d"), msg, fd);
+
+ /*
+ * Nothing to read?
+ */
+ if (msg == SELECT_POKE_NOTHING)
+ break;
+
+ /*
+ * Handle shutdown message. We really should
+ * jump out of this loop right away, but
+ * it doesn't matter if we have to do a little
+ * more work first.
+ */
+ if (msg == SELECT_POKE_SHUTDOWN)
+ return (true);
+
+ /*
+ * This is a wakeup on a socket. Look
+ * at the event queue for both read and write,
+ * and decide if we need to watch on it now
+ * or not.
+ */
+ wakeup_socket(manager, fd, msg);
+ }
+
+ return (false);
+}
+
+/*
+ * This is the thread that will loop forever, always in a select or poll
+ * call.
+ *
+ * When select returns something to do, track down what thread gets to do
+ * this I/O and post the event to it.
+ */
+static isc_threadresult_t
+watcher(void *uap) {
+ isc__socketmgr_t *manager = uap;
+ bool done;
+ int cc;
+#ifdef USE_KQUEUE
+ const char *fnname = "kevent()";
+#elif defined (USE_EPOLL)
+ const char *fnname = "epoll_wait()";
+#elif defined(USE_DEVPOLL)
+ isc_result_t result;
+ const char *fnname = "ioctl(DP_POLL)";
+ struct dvpoll dvp;
+ int pass;
+#if defined(ISC_SOCKET_USE_POLLWATCH)
+ pollstate_t pollstate = poll_idle;
+#endif
+#elif defined (USE_SELECT)
+ const char *fnname = "select()";
+ int maxfd;
+ int ctlfd;
+#endif
+ char strbuf[ISC_STRERRORSIZE];
+
+#if defined (USE_SELECT)
+ /*
+ * Get the control fd here. This will never change.
+ */
+ ctlfd = manager->pipe_fds[0];
+#endif
+ done = false;
+ while (!done) {
+ do {
+#ifdef USE_KQUEUE
+ cc = kevent(manager->kqueue_fd, NULL, 0,
+ manager->events, manager->nevents, NULL);
+#elif defined(USE_EPOLL)
+ cc = epoll_wait(manager->epoll_fd, manager->events,
+ manager->nevents, -1);
+#elif defined(USE_DEVPOLL)
+ /*
+ * Re-probe every thousand calls.
+ */
+ if (manager->calls++ > 1000U) {
+ result = isc_resource_getcurlimit(
+ isc_resource_openfiles,
+ &manager->open_max);
+ if (result != ISC_R_SUCCESS)
+ manager->open_max = 64;
+ manager->calls = 0;
+ }
+ for (pass = 0; pass < 2; pass++) {
+ dvp.dp_fds = manager->events;
+ dvp.dp_nfds = manager->nevents;
+ if (dvp.dp_nfds >= manager->open_max)
+ dvp.dp_nfds = manager->open_max - 1;
+#ifndef ISC_SOCKET_USE_POLLWATCH
+ dvp.dp_timeout = -1;
+#else
+ if (pollstate == poll_idle)
+ dvp.dp_timeout = -1;
+ else
+ dvp.dp_timeout =
+ ISC_SOCKET_POLLWATCH_TIMEOUT;
+#endif /* ISC_SOCKET_USE_POLLWATCH */
+ cc = ioctl(manager->devpoll_fd, DP_POLL, &dvp);
+ if (cc == -1 && errno == EINVAL) {
+ /*
+ * {OPEN_MAX} may have dropped. Look
+ * up the current value and try again.
+ */
+ result = isc_resource_getcurlimit(
+ isc_resource_openfiles,
+ &manager->open_max);
+ if (result != ISC_R_SUCCESS)
+ manager->open_max = 64;
+ } else
+ break;
+ }
+#elif defined(USE_SELECT)
+ LOCK(&manager->lock);
+ memmove(manager->read_fds_copy, manager->read_fds,
+ manager->fd_bufsize);
+ memmove(manager->write_fds_copy, manager->write_fds,
+ manager->fd_bufsize);
+ maxfd = manager->maxfd + 1;
+ UNLOCK(&manager->lock);
+
+ cc = select(maxfd, manager->read_fds_copy,
+ manager->write_fds_copy, NULL, NULL);
+#endif /* USE_KQUEUE */
+
+ if (cc < 0 && !SOFT_ERROR(errno)) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ "%s %s: %s", fnname,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"), strbuf);
+ }
+
+#if defined(USE_DEVPOLL) && defined(ISC_SOCKET_USE_POLLWATCH)
+ if (cc == 0) {
+ if (pollstate == poll_active)
+ pollstate = poll_checking;
+ else if (pollstate == poll_checking)
+ pollstate = poll_idle;
+ } else if (cc > 0) {
+ if (pollstate == poll_checking) {
+ /*
+ * XXX: We'd like to use a more
+ * verbose log level as it's actually an
+ * unexpected event, but the kernel bug
+ * reportedly happens pretty frequently
+ * (and it can also be a false positive)
+ * so it would be just too noisy.
+ */
+ manager_log(manager,
+ ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET,
+ ISC_LOG_DEBUG(1),
+ "unexpected POLL timeout");
+ }
+ pollstate = poll_active;
+ }
+#endif
+ } while (cc < 0);
+
+#if defined(USE_KQUEUE) || defined (USE_EPOLL) || defined (USE_DEVPOLL)
+ done = process_fds(manager, manager->events, cc);
+#elif defined(USE_SELECT)
+ process_fds(manager, maxfd, manager->read_fds_copy,
+ manager->write_fds_copy);
+
+ /*
+ * Process reads on internal, control fd.
+ */
+ if (FD_ISSET(ctlfd, manager->read_fds_copy))
+ done = process_ctlfd(manager);
+#endif
+ }
+
+ manager_log(manager, TRACE, "%s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_EXITING, "watcher exiting"));
+
+ return ((isc_threadresult_t)0);
+}
+#endif /* USE_WATCHER_THREAD */
+
+void
+isc__socketmgr_setreserved(isc_socketmgr_t *manager0, uint32_t reserved) {
+ isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0;
+
+ REQUIRE(VALID_MANAGER(manager));
+
+ manager->reserved = reserved;
+}
+
+void
+isc__socketmgr_maxudp(isc_socketmgr_t *manager0, int maxudp) {
+ isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0;
+
+ REQUIRE(VALID_MANAGER(manager));
+
+ manager->maxudp = maxudp;
+}
+
+/*
+ * Create a new socket manager.
+ */
+
+static isc_result_t
+setup_watcher(isc_mem_t *mctx, isc__socketmgr_t *manager) {
+ isc_result_t result;
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
+ char strbuf[ISC_STRERRORSIZE];
+#endif
+
+#ifdef USE_KQUEUE
+ manager->nevents = ISC_SOCKET_MAXEVENTS;
+ manager->events = isc_mem_get(mctx, sizeof(struct kevent) *
+ manager->nevents);
+ if (manager->events == NULL)
+ return (ISC_R_NOMEMORY);
+ manager->kqueue_fd = kqueue();
+ if (manager->kqueue_fd == -1) {
+ result = isc__errno2result(errno);
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "kqueue %s: %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+ isc_mem_put(mctx, manager->events,
+ sizeof(struct kevent) * manager->nevents);
+ return (result);
+ }
+
+#ifdef USE_WATCHER_THREAD
+ result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
+ if (result != ISC_R_SUCCESS) {
+ close(manager->kqueue_fd);
+ isc_mem_put(mctx, manager->events,
+ sizeof(struct kevent) * manager->nevents);
+ return (result);
+ }
+#endif /* USE_WATCHER_THREAD */
+#elif defined(USE_EPOLL)
+ manager->nevents = ISC_SOCKET_MAXEVENTS;
+ manager->events = isc_mem_get(mctx, sizeof(struct epoll_event) *
+ manager->nevents);
+ if (manager->events == NULL)
+ return (ISC_R_NOMEMORY);
+ manager->epoll_fd = epoll_create(manager->nevents);
+ if (manager->epoll_fd == -1) {
+ result = isc__errno2result(errno);
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "epoll_create %s: %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+ isc_mem_put(mctx, manager->events,
+ sizeof(struct epoll_event) * manager->nevents);
+ return (result);
+ }
+#ifdef USE_WATCHER_THREAD
+ result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
+ if (result != ISC_R_SUCCESS) {
+ close(manager->epoll_fd);
+ isc_mem_put(mctx, manager->events,
+ sizeof(struct epoll_event) * manager->nevents);
+ return (result);
+ }
+#endif /* USE_WATCHER_THREAD */
+#elif defined(USE_DEVPOLL)
+ manager->nevents = ISC_SOCKET_MAXEVENTS;
+ result = isc_resource_getcurlimit(isc_resource_openfiles,
+ &manager->open_max);
+ if (result != ISC_R_SUCCESS)
+ manager->open_max = 64;
+ manager->calls = 0;
+ manager->events = isc_mem_get(mctx, sizeof(struct pollfd) *
+ manager->nevents);
+ if (manager->events == NULL)
+ return (ISC_R_NOMEMORY);
+ /*
+ * Note: fdpollinfo should be able to support all possible FDs, so
+ * it must have maxsocks entries (not nevents).
+ */
+ manager->fdpollinfo = isc_mem_get(mctx, sizeof(pollinfo_t) *
+ manager->maxsocks);
+ if (manager->fdpollinfo == NULL) {
+ isc_mem_put(mctx, manager->events,
+ sizeof(struct pollfd) * manager->nevents);
+ return (ISC_R_NOMEMORY);
+ }
+ memset(manager->fdpollinfo, 0, sizeof(pollinfo_t) * manager->maxsocks);
+ manager->devpoll_fd = open("/dev/poll", O_RDWR);
+ if (manager->devpoll_fd == -1) {
+ result = isc__errno2result(errno);
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "open(/dev/poll) %s: %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+ isc_mem_put(mctx, manager->events,
+ sizeof(struct pollfd) * manager->nevents);
+ isc_mem_put(mctx, manager->fdpollinfo,
+ sizeof(pollinfo_t) * manager->maxsocks);
+ return (result);
+ }
+#ifdef USE_WATCHER_THREAD
+ result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
+ if (result != ISC_R_SUCCESS) {
+ close(manager->devpoll_fd);
+ isc_mem_put(mctx, manager->events,
+ sizeof(struct pollfd) * manager->nevents);
+ isc_mem_put(mctx, manager->fdpollinfo,
+ sizeof(pollinfo_t) * manager->maxsocks);
+ return (result);
+ }
+#endif /* USE_WATCHER_THREAD */
+#elif defined(USE_SELECT)
+ UNUSED(result);
+
+#if ISC_SOCKET_MAXSOCKETS > FD_SETSIZE
+ /*
+ * Note: this code should also cover the case of MAXSOCKETS <=
+ * FD_SETSIZE, but we separate the cases to avoid possible portability
+ * issues regarding howmany() and the actual representation of fd_set.
+ */
+ manager->fd_bufsize = howmany(manager->maxsocks, NFDBITS) *
+ sizeof(fd_mask);
+#else
+ manager->fd_bufsize = sizeof(fd_set);
+#endif
+
+ manager->read_fds = NULL;
+ manager->read_fds_copy = NULL;
+ manager->write_fds = NULL;
+ manager->write_fds_copy = NULL;
+
+ manager->read_fds = isc_mem_get(mctx, manager->fd_bufsize);
+ if (manager->read_fds != NULL)
+ manager->read_fds_copy = isc_mem_get(mctx, manager->fd_bufsize);
+ if (manager->read_fds_copy != NULL)
+ manager->write_fds = isc_mem_get(mctx, manager->fd_bufsize);
+ if (manager->write_fds != NULL) {
+ manager->write_fds_copy = isc_mem_get(mctx,
+ manager->fd_bufsize);
+ }
+ if (manager->write_fds_copy == NULL) {
+ if (manager->write_fds != NULL) {
+ isc_mem_put(mctx, manager->write_fds,
+ manager->fd_bufsize);
+ }
+ if (manager->read_fds_copy != NULL) {
+ isc_mem_put(mctx, manager->read_fds_copy,
+ manager->fd_bufsize);
+ }
+ if (manager->read_fds != NULL) {
+ isc_mem_put(mctx, manager->read_fds,
+ manager->fd_bufsize);
+ }
+ return (ISC_R_NOMEMORY);
+ }
+ memset(manager->read_fds, 0, manager->fd_bufsize);
+ memset(manager->write_fds, 0, manager->fd_bufsize);
+
+#ifdef USE_WATCHER_THREAD
+ (void)watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
+ manager->maxfd = manager->pipe_fds[0];
+#else /* USE_WATCHER_THREAD */
+ manager->maxfd = 0;
+#endif /* USE_WATCHER_THREAD */
+#endif /* USE_KQUEUE */
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+cleanup_watcher(isc_mem_t *mctx, isc__socketmgr_t *manager) {
+#ifdef USE_WATCHER_THREAD
+ isc_result_t result;
+
+ result = unwatch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "epoll_ctl(DEL) %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ }
+#endif /* USE_WATCHER_THREAD */
+
+#ifdef USE_KQUEUE
+ close(manager->kqueue_fd);
+ isc_mem_put(mctx, manager->events,
+ sizeof(struct kevent) * manager->nevents);
+#elif defined(USE_EPOLL)
+ close(manager->epoll_fd);
+ isc_mem_put(mctx, manager->events,
+ sizeof(struct epoll_event) * manager->nevents);
+#elif defined(USE_DEVPOLL)
+ close(manager->devpoll_fd);
+ isc_mem_put(mctx, manager->events,
+ sizeof(struct pollfd) * manager->nevents);
+ isc_mem_put(mctx, manager->fdpollinfo,
+ sizeof(pollinfo_t) * manager->maxsocks);
+#elif defined(USE_SELECT)
+ if (manager->read_fds != NULL)
+ isc_mem_put(mctx, manager->read_fds, manager->fd_bufsize);
+ if (manager->read_fds_copy != NULL)
+ isc_mem_put(mctx, manager->read_fds_copy, manager->fd_bufsize);
+ if (manager->write_fds != NULL)
+ isc_mem_put(mctx, manager->write_fds, manager->fd_bufsize);
+ if (manager->write_fds_copy != NULL)
+ isc_mem_put(mctx, manager->write_fds_copy, manager->fd_bufsize);
+#endif /* USE_KQUEUE */
+}
+
+isc_result_t
+isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
+ return (isc__socketmgr_create2(mctx, managerp, 0));
+}
+
+isc_result_t
+isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
+ unsigned int maxsocks)
+{
+ int i;
+ isc__socketmgr_t *manager;
+#ifdef USE_WATCHER_THREAD
+ char strbuf[ISC_STRERRORSIZE];
+#endif
+ isc_result_t result;
+
+ REQUIRE(managerp != NULL && *managerp == NULL);
+
+#ifdef USE_SHARED_MANAGER
+ if (socketmgr != NULL) {
+ /* Don't allow maxsocks to be updated */
+ if (maxsocks > 0 && socketmgr->maxsocks != maxsocks)
+ return (ISC_R_EXISTS);
+
+ socketmgr->refs++;
+ *managerp = (isc_socketmgr_t *)socketmgr;
+ return (ISC_R_SUCCESS);
+ }
+#endif /* USE_SHARED_MANAGER */
+
+ if (maxsocks == 0)
+ maxsocks = ISC_SOCKET_MAXSOCKETS;
+
+ manager = isc_mem_get(mctx, sizeof(*manager));
+ if (manager == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /* zero-clear so that necessary cleanup on failure will be easy */
+ memset(manager, 0, sizeof(*manager));
+ manager->maxsocks = maxsocks;
+ manager->reserved = 0;
+ manager->maxudp = 0;
+ manager->fds = isc_mem_get(mctx,
+ manager->maxsocks * sizeof(isc__socket_t *));
+ if (manager->fds == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto free_manager;
+ }
+ manager->fdstate = isc_mem_get(mctx, manager->maxsocks * sizeof(int));
+ if (manager->fdstate == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto free_manager;
+ }
+#if defined(USE_EPOLL)
+ manager->epoll_events = isc_mem_get(mctx, (manager->maxsocks *
+ sizeof(uint32_t)));
+ if (manager->epoll_events == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto free_manager;
+ }
+ memset(manager->epoll_events, 0, manager->maxsocks * sizeof(uint32_t));
+#endif
+ manager->stats = NULL;
+
+ manager->common.methods = &socketmgrmethods;
+ manager->common.magic = ISCAPI_SOCKETMGR_MAGIC;
+ manager->common.impmagic = SOCKET_MANAGER_MAGIC;
+ manager->mctx = NULL;
+ memset(manager->fds, 0, manager->maxsocks * sizeof(isc_socket_t *));
+ ISC_LIST_INIT(manager->socklist);
+ result = isc_mutex_init(&manager->lock);
+ if (result != ISC_R_SUCCESS)
+ goto free_manager;
+ manager->fdlock = isc_mem_get(mctx, FDLOCK_COUNT * sizeof(isc_mutex_t));
+ if (manager->fdlock == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_lock;
+ }
+ for (i = 0; i < FDLOCK_COUNT; i++) {
+ result = isc_mutex_init(&manager->fdlock[i]);
+ if (result != ISC_R_SUCCESS) {
+ while (--i >= 0)
+ DESTROYLOCK(&manager->fdlock[i]);
+ isc_mem_put(mctx, manager->fdlock,
+ FDLOCK_COUNT * sizeof(isc_mutex_t));
+ manager->fdlock = NULL;
+ goto cleanup_lock;
+ }
+ }
+
+#ifdef USE_WATCHER_THREAD
+ if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_lock;
+ }
+
+ /*
+ * Create the special fds that will be used to wake up the
+ * select/poll loop when something internal needs to be done.
+ */
+ if (pipe(manager->pipe_fds) != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "pipe() %s: %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_condition;
+ }
+
+ RUNTIME_CHECK(make_nonblock(manager->pipe_fds[0]) == ISC_R_SUCCESS);
+#if 0
+ RUNTIME_CHECK(make_nonblock(manager->pipe_fds[1]) == ISC_R_SUCCESS);
+#endif
+#endif /* USE_WATCHER_THREAD */
+
+#ifdef USE_SHARED_MANAGER
+ manager->refs = 1;
+#endif /* USE_SHARED_MANAGER */
+
+ /*
+ * Set up initial state for the select loop
+ */
+ result = setup_watcher(mctx, manager);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ memset(manager->fdstate, 0, manager->maxsocks * sizeof(int));
+
+#ifdef USE_WATCHER_THREAD
+ /*
+ * Start up the select/poll thread.
+ */
+ if (isc_thread_create(watcher, manager, &manager->watcher) !=
+ ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_thread_create() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ cleanup_watcher(mctx, manager);
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+ isc_thread_setname(manager->watcher, "isc-socket");
+#endif /* USE_WATCHER_THREAD */
+ isc_mem_attach(mctx, &manager->mctx);
+
+#ifdef USE_SHARED_MANAGER
+ socketmgr = manager;
+#endif /* USE_SHARED_MANAGER */
+ *managerp = (isc_socketmgr_t *)manager;
+
+ return (ISC_R_SUCCESS);
+
+cleanup:
+#ifdef USE_WATCHER_THREAD
+ (void)close(manager->pipe_fds[0]);
+ (void)close(manager->pipe_fds[1]);
+#endif /* USE_WATCHER_THREAD */
+
+#ifdef USE_WATCHER_THREAD
+cleanup_condition:
+ (void)isc_condition_destroy(&manager->shutdown_ok);
+#endif /* USE_WATCHER_THREAD */
+
+
+cleanup_lock:
+ if (manager->fdlock != NULL) {
+ for (i = 0; i < FDLOCK_COUNT; i++)
+ DESTROYLOCK(&manager->fdlock[i]);
+ }
+ DESTROYLOCK(&manager->lock);
+
+free_manager:
+ if (manager->fdlock != NULL) {
+ isc_mem_put(mctx, manager->fdlock,
+ FDLOCK_COUNT * sizeof(isc_mutex_t));
+ }
+#if defined(USE_EPOLL)
+ if (manager->epoll_events != NULL) {
+ isc_mem_put(mctx, manager->epoll_events,
+ manager->maxsocks * sizeof(uint32_t));
+ }
+#endif
+ if (manager->fdstate != NULL) {
+ isc_mem_put(mctx, manager->fdstate,
+ manager->maxsocks * sizeof(int));
+ }
+ if (manager->fds != NULL) {
+ isc_mem_put(mctx, manager->fds,
+ manager->maxsocks * sizeof(isc_socket_t *));
+ }
+ isc_mem_put(mctx, manager, sizeof(*manager));
+
+ return (result);
+}
+
+isc_result_t
+isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager0, unsigned int *nsockp) {
+ isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0;
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(nsockp != NULL);
+
+ *nsockp = manager->maxsocks;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_socketmgr_setstats(isc_socketmgr_t *manager0, isc_stats_t *stats) {
+ isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0;
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(ISC_LIST_EMPTY(manager->socklist));
+ REQUIRE(manager->stats == NULL);
+ REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max);
+
+ isc_stats_attach(stats, &manager->stats);
+}
+
+void
+isc__socketmgr_destroy(isc_socketmgr_t **managerp) {
+ isc__socketmgr_t *manager;
+ int i;
+ isc_mem_t *mctx;
+
+ /*
+ * Destroy a socket manager.
+ */
+
+ REQUIRE(managerp != NULL);
+ manager = (isc__socketmgr_t *)*managerp;
+ REQUIRE(VALID_MANAGER(manager));
+
+#ifdef USE_SHARED_MANAGER
+ manager->refs--;
+ if (manager->refs > 0) {
+ *managerp = NULL;
+ return;
+ }
+ socketmgr = NULL;
+#endif /* USE_SHARED_MANAGER */
+
+ LOCK(&manager->lock);
+
+ /*
+ * Wait for all sockets to be destroyed.
+ */
+ while (!ISC_LIST_EMPTY(manager->socklist)) {
+#ifdef USE_WATCHER_THREAD
+ manager_log(manager, CREATION, "%s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_SOCKETSREMAIN,
+ "sockets exist"));
+ WAIT(&manager->shutdown_ok, &manager->lock);
+#else /* USE_WATCHER_THREAD */
+ UNLOCK(&manager->lock);
+ isc__taskmgr_dispatch(NULL);
+ LOCK(&manager->lock);
+#endif /* USE_WATCHER_THREAD */
+ }
+
+ UNLOCK(&manager->lock);
+
+ /*
+ * Here, poke our select/poll thread. Do this by closing the write
+ * half of the pipe, which will send EOF to the read half.
+ * This is currently a no-op in the non-threaded case.
+ */
+ select_poke(manager, 0, SELECT_POKE_SHUTDOWN);
+
+#ifdef USE_WATCHER_THREAD
+ /*
+ * Wait for thread to exit.
+ */
+ if (isc_thread_join(manager->watcher, NULL) != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_thread_join() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+#endif /* USE_WATCHER_THREAD */
+
+ /*
+ * Clean up.
+ */
+ cleanup_watcher(manager->mctx, manager);
+
+#ifdef USE_WATCHER_THREAD
+ (void)close(manager->pipe_fds[0]);
+ (void)close(manager->pipe_fds[1]);
+ (void)isc_condition_destroy(&manager->shutdown_ok);
+#endif /* USE_WATCHER_THREAD */
+
+ for (i = 0; i < (int)manager->maxsocks; i++)
+ if (manager->fdstate[i] == CLOSE_PENDING) /* no need to lock */
+ (void)close(i);
+
+#if defined(USE_EPOLL)
+ isc_mem_put(manager->mctx, manager->epoll_events,
+ manager->maxsocks * sizeof(uint32_t));
+#endif
+ isc_mem_put(manager->mctx, manager->fds,
+ manager->maxsocks * sizeof(isc__socket_t *));
+ isc_mem_put(manager->mctx, manager->fdstate,
+ manager->maxsocks * sizeof(int));
+
+ if (manager->stats != NULL)
+ isc_stats_detach(&manager->stats);
+
+ if (manager->fdlock != NULL) {
+ for (i = 0; i < FDLOCK_COUNT; i++)
+ DESTROYLOCK(&manager->fdlock[i]);
+ isc_mem_put(manager->mctx, manager->fdlock,
+ FDLOCK_COUNT * sizeof(isc_mutex_t));
+ }
+ DESTROYLOCK(&manager->lock);
+ manager->common.magic = 0;
+ manager->common.impmagic = 0;
+ mctx= manager->mctx;
+ isc_mem_put(mctx, manager, sizeof(*manager));
+
+ isc_mem_detach(&mctx);
+
+ *managerp = NULL;
+
+#ifdef USE_SHARED_MANAGER
+ socketmgr = NULL;
+#endif
+}
+
+static isc_result_t
+socket_recv(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+ unsigned int flags)
+{
+ int io_state;
+ bool have_lock = false;
+ isc_task_t *ntask = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ dev->ev_sender = task;
+
+ if (sock->type == isc_sockettype_udp) {
+ io_state = doio_recv(sock, dev);
+ } else {
+ LOCK(&sock->lock);
+ have_lock = true;
+
+ if (ISC_LIST_EMPTY(sock->recv_list))
+ io_state = doio_recv(sock, dev);
+ else
+ io_state = DOIO_SOFT;
+ }
+
+ switch (io_state) {
+ case DOIO_SOFT:
+ /*
+ * We couldn't read all or part of the request right now, so
+ * queue it.
+ *
+ * Attach to socket and to task
+ */
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ if (!have_lock) {
+ LOCK(&sock->lock);
+ have_lock = true;
+ }
+
+ /*
+ * Enqueue the request. If the socket was previously not being
+ * watched, poke the watcher to start paying attention to it.
+ */
+ if (ISC_LIST_EMPTY(sock->recv_list) && !sock->pending_recv)
+ select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+ ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
+
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "socket_recv: event %p -> task %p",
+ dev, ntask);
+
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
+ result = ISC_R_INPROGRESS;
+ break;
+
+ case DOIO_EOF:
+ dev->result = ISC_R_EOF;
+ /* fallthrough */
+
+ case DOIO_HARD:
+ case DOIO_SUCCESS:
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
+ send_recvdone_event(sock, &dev);
+ break;
+ }
+
+ if (have_lock)
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc__socket_recvv(isc_socket_t *sock0, isc_bufferlist_t *buflist,
+ unsigned int minimum, isc_task_t *task,
+ isc_taskaction_t action, void *arg)
+{
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ isc_socketevent_t *dev;
+ isc__socketmgr_t *manager;
+ unsigned int iocount;
+ isc_buffer_t *buffer;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(buflist != NULL);
+ REQUIRE(!ISC_LIST_EMPTY(*buflist));
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ iocount = isc_bufferlist_availablecount(buflist);
+ REQUIRE(iocount > 0);
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(manager->mctx, sock,
+ ISC_SOCKEVENT_RECVDONE, action, arg);
+ if (dev == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * UDP sockets are always partial read
+ */
+ if (sock->type == isc_sockettype_udp)
+ dev->minimum = 1;
+ else {
+ if (minimum == 0)
+ dev->minimum = iocount;
+ else
+ dev->minimum = minimum;
+ }
+
+ /*
+ * Move each buffer from the passed in list to our internal one.
+ */
+ buffer = ISC_LIST_HEAD(*buflist);
+ while (buffer != NULL) {
+ ISC_LIST_DEQUEUE(*buflist, buffer, link);
+ ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
+ buffer = ISC_LIST_HEAD(*buflist);
+ }
+
+ return (socket_recv(sock, dev, task, 0));
+}
+
+isc_result_t
+isc__socket_recv(isc_socket_t *sock0, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_taskaction_t action, void *arg)
+{
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ isc_socketevent_t *dev;
+ isc__socketmgr_t *manager;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(manager->mctx, sock,
+ ISC_SOCKEVENT_RECVDONE, action, arg);
+ if (dev == NULL)
+ return (ISC_R_NOMEMORY);
+
+ return (isc__socket_recv2(sock0, region, minimum, task, dev, 0));
+}
+
+isc_result_t
+isc__socket_recv2(isc_socket_t *sock0, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_socketevent_t *event, unsigned int flags)
+{
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+
+ event->ev_sender = sock;
+ event->result = ISC_R_UNSET;
+ ISC_LIST_INIT(event->bufferlist);
+ event->region = *region;
+ event->n = 0;
+ event->offset = 0;
+ event->attributes = 0;
+
+ /*
+ * UDP sockets are always partial read.
+ */
+ if (sock->type == isc_sockettype_udp)
+ event->minimum = 1;
+ else {
+ if (minimum == 0)
+ event->minimum = region->length;
+ else
+ event->minimum = minimum;
+ }
+
+ return (socket_recv(sock, event, task, flags));
+}
+
+static isc_result_t
+socket_send(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ unsigned int flags)
+{
+ int io_state;
+ bool have_lock = false;
+ isc_task_t *ntask = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ dev->ev_sender = task;
+
+ set_dev_address(address, sock, dev);
+ if (pktinfo != NULL) {
+ dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
+ dev->pktinfo = *pktinfo;
+
+ if (!isc_sockaddr_issitelocal(&dev->address) &&
+ !isc_sockaddr_islinklocal(&dev->address)) {
+ socket_log(sock, NULL, TRACE, isc_msgcat,
+ ISC_MSGSET_SOCKET, ISC_MSG_PKTINFOPROVIDED,
+ "pktinfo structure provided, ifindex %u "
+ "(set to 0)", pktinfo->ipi6_ifindex);
+
+ /*
+ * Set the pktinfo index to 0 here, to let the
+ * kernel decide what interface it should send on.
+ */
+ dev->pktinfo.ipi6_ifindex = 0;
+ }
+ }
+
+ if (sock->type == isc_sockettype_udp)
+ io_state = doio_send(sock, dev);
+ else {
+ LOCK(&sock->lock);
+ have_lock = true;
+
+ if (ISC_LIST_EMPTY(sock->send_list))
+ io_state = doio_send(sock, dev);
+ else
+ io_state = DOIO_SOFT;
+ }
+
+ switch (io_state) {
+ case DOIO_SOFT:
+ /*
+ * We couldn't send all or part of the request right now, so
+ * queue it unless ISC_SOCKFLAG_NORETRY is set.
+ */
+ if ((flags & ISC_SOCKFLAG_NORETRY) == 0) {
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ if (!have_lock) {
+ LOCK(&sock->lock);
+ have_lock = true;
+ }
+
+ /*
+ * Enqueue the request. If the socket was previously
+ * not being watched, poke the watcher to start
+ * paying attention to it.
+ */
+ if (ISC_LIST_EMPTY(sock->send_list) &&
+ !sock->pending_send)
+ select_poke(sock->manager, sock->fd,
+ SELECT_POKE_WRITE);
+ ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
+
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "socket_send: event %p -> task %p",
+ dev, ntask);
+
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
+ result = ISC_R_INPROGRESS;
+ break;
+ }
+
+ /* FALLTHROUGH */
+
+ case DOIO_HARD:
+ case DOIO_SUCCESS:
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
+ send_senddone_event(sock, &dev);
+ break;
+ }
+
+ if (have_lock)
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc__socket_send(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ /*
+ * REQUIRE() checking is performed in isc_socket_sendto().
+ */
+ return (isc__socket_sendto(sock, region, task, action, arg, NULL,
+ NULL));
+}
+
+isc_result_t
+isc__socket_sendto(isc_socket_t *sock0, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ isc_socketevent_t *dev;
+ isc__socketmgr_t *manager;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(region != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(manager->mctx, sock,
+ ISC_SOCKEVENT_SENDDONE, action, arg);
+ if (dev == NULL)
+ return (ISC_R_NOMEMORY);
+
+ dev->region = *region;
+
+ return (socket_send(sock, dev, task, address, pktinfo, 0));
+}
+
+isc_result_t
+isc__socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ return (isc__socket_sendtov2(sock, buflist, task, action, arg, NULL,
+ NULL, 0));
+}
+
+isc_result_t
+isc__socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+ return (isc__socket_sendtov2(sock, buflist, task, action, arg, address,
+ pktinfo, 0));
+}
+
+isc_result_t
+isc__socket_sendtov2(isc_socket_t *sock0, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ unsigned int flags)
+{
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ isc_socketevent_t *dev;
+ isc__socketmgr_t *manager;
+ unsigned int iocount;
+ isc_buffer_t *buffer;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(buflist != NULL);
+ REQUIRE(!ISC_LIST_EMPTY(*buflist));
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ iocount = isc_bufferlist_usedcount(buflist);
+ REQUIRE(iocount > 0);
+
+ dev = allocate_socketevent(manager->mctx, sock,
+ ISC_SOCKEVENT_SENDDONE, action, arg);
+ if (dev == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * Move each buffer from the passed in list to our internal one.
+ */
+ buffer = ISC_LIST_HEAD(*buflist);
+ while (buffer != NULL) {
+ ISC_LIST_DEQUEUE(*buflist, buffer, link);
+ ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
+ buffer = ISC_LIST_HEAD(*buflist);
+ }
+
+ return (socket_send(sock, dev, task, address, pktinfo, flags));
+}
+
+isc_result_t
+isc__socket_sendto2(isc_socket_t *sock0, isc_region_t *region,
+ isc_task_t *task,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ isc_socketevent_t *event, unsigned int flags)
+{
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0);
+ if ((flags & ISC_SOCKFLAG_NORETRY) != 0)
+ REQUIRE(sock->type == isc_sockettype_udp);
+ event->ev_sender = sock;
+ event->result = ISC_R_UNSET;
+ ISC_LIST_INIT(event->bufferlist);
+ event->region = *region;
+ event->n = 0;
+ event->offset = 0;
+ event->attributes &= ~ISC_SOCKEVENTATTR_ATTACHED;
+
+ return (socket_send(sock, event, task, address, pktinfo, flags));
+}
+
+void
+isc__socket_cleanunix(isc_sockaddr_t *sockaddr, bool active) {
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ int s;
+ struct stat sb;
+ char strbuf[ISC_STRERRORSIZE];
+
+ if (sockaddr->type.sa.sa_family != AF_UNIX)
+ return;
+
+#ifndef S_ISSOCK
+#if defined(S_IFMT) && defined(S_IFSOCK)
+#define S_ISSOCK(mode) ((mode & S_IFMT)==S_IFSOCK)
+#elif defined(_S_IFMT) && defined(S_IFSOCK)
+#define S_ISSOCK(mode) ((mode & _S_IFMT)==S_IFSOCK)
+#endif
+#endif
+
+#ifndef S_ISFIFO
+#if defined(S_IFMT) && defined(S_IFIFO)
+#define S_ISFIFO(mode) ((mode & S_IFMT)==S_IFIFO)
+#elif defined(_S_IFMT) && defined(S_IFIFO)
+#define S_ISFIFO(mode) ((mode & _S_IFMT)==S_IFIFO)
+#endif
+#endif
+
+#if !defined(S_ISFIFO) && !defined(S_ISSOCK)
+#error You need to define S_ISFIFO and S_ISSOCK as appropriate for your platform. See <sys/stat.h>.
+#endif
+
+#ifndef S_ISFIFO
+#define S_ISFIFO(mode) 0
+#endif
+
+#ifndef S_ISSOCK
+#define S_ISSOCK(mode) 0
+#endif
+
+ if (active) {
+ if (stat(sockaddr->type.sunix.sun_path, &sb) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "isc_socket_cleanunix: stat(%s): %s",
+ sockaddr->type.sunix.sun_path, strbuf);
+ return;
+ }
+ if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "isc_socket_cleanunix: %s: not a socket",
+ sockaddr->type.sunix.sun_path);
+ return;
+ }
+ if (unlink(sockaddr->type.sunix.sun_path) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "isc_socket_cleanunix: unlink(%s): %s",
+ sockaddr->type.sunix.sun_path, strbuf);
+ }
+ return;
+ }
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+ "isc_socket_cleanunix: socket(%s): %s",
+ sockaddr->type.sunix.sun_path, strbuf);
+ return;
+ }
+
+ if (stat(sockaddr->type.sunix.sun_path, &sb) < 0) {
+ switch (errno) {
+ case ENOENT: /* We exited cleanly last time */
+ break;
+ default:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+ "isc_socket_cleanunix: stat(%s): %s",
+ sockaddr->type.sunix.sun_path, strbuf);
+ break;
+ }
+ goto cleanup;
+ }
+
+ if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+ "isc_socket_cleanunix: %s: not a socket",
+ sockaddr->type.sunix.sun_path);
+ goto cleanup;
+ }
+
+ if (connect(s, (struct sockaddr *)&sockaddr->type.sunix,
+ sizeof(sockaddr->type.sunix)) < 0) {
+ switch (errno) {
+ case ECONNREFUSED:
+ case ECONNRESET:
+ if (unlink(sockaddr->type.sunix.sun_path) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET,
+ ISC_LOG_WARNING,
+ "isc_socket_cleanunix: "
+ "unlink(%s): %s",
+ sockaddr->type.sunix.sun_path,
+ strbuf);
+ }
+ break;
+ default:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+ "isc_socket_cleanunix: connect(%s): %s",
+ sockaddr->type.sunix.sun_path, strbuf);
+ break;
+ }
+ }
+ cleanup:
+ close(s);
+#else
+ UNUSED(sockaddr);
+ UNUSED(active);
+#endif
+}
+
+isc_result_t
+isc__socket_permunix(isc_sockaddr_t *sockaddr, uint32_t perm,
+ uint32_t owner, uint32_t group)
+{
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ isc_result_t result = ISC_R_SUCCESS;
+ char strbuf[ISC_STRERRORSIZE];
+ char path[sizeof(sockaddr->type.sunix.sun_path)];
+#ifdef NEED_SECURE_DIRECTORY
+ char *slash;
+#endif
+
+ REQUIRE(sockaddr->type.sa.sa_family == AF_UNIX);
+ INSIST(strlen(sockaddr->type.sunix.sun_path) < sizeof(path));
+ strlcpy(path, sockaddr->type.sunix.sun_path, sizeof(path));
+
+#ifdef NEED_SECURE_DIRECTORY
+ slash = strrchr(path, '/');
+ if (slash != NULL) {
+ if (slash != path) {
+ *slash = '\0';
+ } else {
+ strlcpy(path, "/", sizeof(path));
+ }
+ } else {
+ strlcpy(path, ".", sizeof(path));
+ }
+#endif
+
+ if (chmod(path, perm) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "isc_socket_permunix: chmod(%s, %d): %s",
+ path, perm, strbuf);
+ result = ISC_R_FAILURE;
+ }
+ if (chown(path, owner, group) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "isc_socket_permunix: chown(%s, %d, %d): %s",
+ path, owner, group,
+ strbuf);
+ result = ISC_R_FAILURE;
+ }
+ return (result);
+#else
+ UNUSED(sockaddr);
+ UNUSED(perm);
+ UNUSED(owner);
+ UNUSED(group);
+ return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+isc_result_t
+isc__socket_bind(isc_socket_t *sock0, isc_sockaddr_t *sockaddr,
+ unsigned int options) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ char strbuf[ISC_STRERRORSIZE];
+ int on = 1;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+
+ INSIST(!sock->bound);
+ INSIST(!sock->dupped);
+
+ if (sock->pf != sockaddr->type.sa.sa_family) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_FAMILYMISMATCH);
+ }
+
+ /*
+ * Only set SO_REUSEADDR when we want a specific port.
+ */
+#ifdef AF_UNIX
+ if (sock->pf == AF_UNIX)
+ goto bind_socket;
+#endif
+ if ((options & ISC_SOCKET_REUSEADDRESS) != 0 &&
+ isc_sockaddr_getport(sockaddr) != (in_port_t)0 &&
+ setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
+ sizeof(on)) < 0) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d) %s", sock->fd,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ /* Press on... */
+ }
+#ifdef AF_UNIX
+ bind_socket:
+#endif
+ if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) {
+ inc_stats(sock->manager->stats,
+ sock->statsindex[STATID_BINDFAIL]);
+
+ UNLOCK(&sock->lock);
+ switch (errno) {
+ case EACCES:
+ return (ISC_R_NOPERM);
+ case EADDRNOTAVAIL:
+ return (ISC_R_ADDRNOTAVAIL);
+ case EADDRINUSE:
+ return (ISC_R_ADDRINUSE);
+ case EINVAL:
+ return (ISC_R_BOUND);
+ default:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ socket_log(sock, sockaddr, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "bound");
+ sock->bound = 1;
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Enable this only for specific OS versions, and only when they have repaired
+ * their problems with it. Until then, this is is broken and needs to be
+ * diabled by default. See RT22589 for details.
+ */
+#undef ENABLE_ACCEPTFILTER
+
+isc_result_t
+isc__socket_filter(isc_socket_t *sock0, const char *filter) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+#if defined(SO_ACCEPTFILTER) && defined(ENABLE_ACCEPTFILTER)
+ char strbuf[ISC_STRERRORSIZE];
+ struct accept_filter_arg afa;
+#else
+ UNUSED(sock);
+ UNUSED(filter);
+#endif
+
+ REQUIRE(VALID_SOCKET(sock));
+
+#if defined(SO_ACCEPTFILTER) && defined(ENABLE_ACCEPTFILTER)
+ bzero(&afa, sizeof(afa));
+ strlcpy(afa.af_name, filter, sizeof(afa.af_name));
+ if (setsockopt(sock->fd, SOL_SOCKET, SO_ACCEPTFILTER,
+ &afa, sizeof(afa)) == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FILTER, "setsockopt(SO_ACCEPTFILTER): %s",
+ strbuf);
+ return (ISC_R_FAILURE);
+ }
+ return (ISC_R_SUCCESS);
+#else
+ return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+/*
+ * Try enabling TCP Fast Open for a given socket if the OS supports it.
+ */
+static void
+set_tcp_fastopen(isc__socket_t *sock, unsigned int backlog) {
+#if defined(ISC_PLATFORM_HAVETFO) && defined(TCP_FASTOPEN)
+ char strbuf[ISC_STRERRORSIZE];
+
+/*
+ * FreeBSD, as of versions 10.3 and 11.0, defines TCP_FASTOPEN while also
+ * shipping a default kernel without TFO support, so we special-case it by
+ * performing an additional runtime check for TFO support using sysctl to
+ * prevent setsockopt() errors from being logged.
+ */
+#if defined(__FreeBSD__) && defined(HAVE_SYSCTLBYNAME)
+#define SYSCTL_TFO "net.inet.tcp.fastopen.enabled"
+ unsigned int enabled;
+ size_t enabledlen = sizeof(enabled);
+ static bool tfo_notice_logged = false;
+
+ if (sysctlbyname(SYSCTL_TFO, &enabled, &enabledlen, NULL, 0) < 0) {
+ /*
+ * This kernel does not support TCP Fast Open. There is
+ * nothing more we can do.
+ */
+ return;
+ } else if (enabled == 0) {
+ /*
+ * This kernel does support TCP Fast Open, but it is disabled
+ * by sysctl. Notify the user, but do not nag.
+ */
+ if (!tfo_notice_logged) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_NOTICE,
+ "TCP_FASTOPEN support is disabled by "
+ "sysctl (" SYSCTL_TFO " = 0)");
+ tfo_notice_logged = true;
+ }
+ return;
+ }
+#endif
+
+#ifdef __APPLE__
+ backlog = 1;
+#else
+ backlog = backlog / 2;
+ if (backlog == 0)
+ backlog = 1;
+#endif
+ if (setsockopt(sock->fd, IPPROTO_TCP, TCP_FASTOPEN,
+ (void *)&backlog, sizeof(backlog)) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, TCP_FASTOPEN) failed with %s",
+ sock->fd, strbuf);
+ /* TCP_FASTOPEN is experimental so ignore failures */
+ }
+#else
+ UNUSED(sock);
+ UNUSED(backlog);
+#endif
+}
+
+/*
+ * Set up to listen on a given socket. We do this by creating an internal
+ * event that will be dispatched when the socket has read activity. The
+ * watcher will send the internal event to the task when there is a new
+ * connection.
+ *
+ * Unlike in read, we don't preallocate a done event here. Every time there
+ * is a new connection we'll have to allocate a new one anyway, so we might
+ * as well keep things simple rather than having to track them.
+ */
+isc_result_t
+isc__socket_listen(isc_socket_t *sock0, unsigned int backlog) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+
+ REQUIRE(!sock->listener);
+ REQUIRE(sock->bound);
+ REQUIRE(sock->type == isc_sockettype_tcp ||
+ sock->type == isc_sockettype_unix);
+
+ if (backlog == 0)
+ backlog = SOMAXCONN;
+
+ if (listen(sock->fd, (int)backlog) < 0) {
+ UNLOCK(&sock->lock);
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+ set_tcp_fastopen(sock, backlog);
+
+ sock->listener = 1;
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This should try to do aggressive accept() XXXMLG
+ */
+isc_result_t
+isc__socket_accept(isc_socket_t *sock0,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ isc_socket_newconnev_t *dev;
+ isc__socketmgr_t *manager;
+ isc_task_t *ntask = NULL;
+ isc__socket_t *nsock;
+ isc_result_t result;
+ bool do_poke = false;
+
+ REQUIRE(VALID_SOCKET(sock));
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ LOCK(&sock->lock);
+
+ REQUIRE(sock->listener);
+
+ /*
+ * Sender field is overloaded here with the task we will be sending
+ * this event to. Just before the actual event is delivered the
+ * actual ev_sender will be touched up to be the socket.
+ */
+ dev = (isc_socket_newconnev_t *)
+ isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN,
+ action, arg, sizeof(*dev));
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+ ISC_LINK_INIT(dev, ev_link);
+
+ result = allocate_socket(manager, sock->type, &nsock);
+ if (result != ISC_R_SUCCESS) {
+ isc_event_free(ISC_EVENT_PTR(&dev));
+ UNLOCK(&sock->lock);
+ return (result);
+ }
+
+ /*
+ * Attach to socket and to task.
+ */
+ isc_task_attach(task, &ntask);
+ if (isc_task_exiting(ntask)) {
+ free_socket(&nsock);
+ isc_task_detach(&ntask);
+ isc_event_free(ISC_EVENT_PTR(&dev));
+ UNLOCK(&sock->lock);
+ return (ISC_R_SHUTTINGDOWN);
+ }
+ nsock->references++;
+ nsock->statsindex = sock->statsindex;
+
+ dev->ev_sender = ntask;
+ dev->newsocket = (isc_socket_t *)nsock;
+
+ /*
+ * Poke watcher here. We still have the socket locked, so there
+ * is no race condition. We will keep the lock for such a short
+ * bit of time waking it up now or later won't matter all that much.
+ */
+ if (ISC_LIST_EMPTY(sock->accept_list))
+ do_poke = true;
+
+ ISC_LIST_ENQUEUE(sock->accept_list, dev, ev_link);
+
+ if (do_poke)
+ select_poke(manager, sock->fd, SELECT_POKE_ACCEPT);
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__socket_connect(isc_socket_t *sock0, isc_sockaddr_t *addr,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ isc_socket_connev_t *dev;
+ isc_task_t *ntask = NULL;
+ isc__socketmgr_t *manager;
+ int cc;
+ char strbuf[ISC_STRERRORSIZE];
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addr != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(addr != NULL);
+
+ if (isc_sockaddr_ismulticast(addr))
+ return (ISC_R_MULTICAST);
+
+ LOCK(&sock->lock);
+
+ dev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
+ ISC_SOCKEVENT_CONNECT,
+ action, arg,
+ sizeof(*dev));
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+ ISC_LINK_INIT(dev, ev_link);
+
+ if (sock->connecting) {
+ INSIST(isc_sockaddr_equal(&sock->peer_address, addr));
+ goto queue;
+ }
+
+ if (sock->connected) {
+ INSIST(isc_sockaddr_equal(&sock->peer_address, addr));
+ dev->result = ISC_R_SUCCESS;
+ isc_task_send(task, ISC_EVENT_PTR(&dev));
+
+ UNLOCK(&sock->lock);
+
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * Try to do the connect right away, as there can be only one
+ * outstanding, and it might happen to complete.
+ */
+ sock->peer_address = *addr;
+ cc = connect(sock->fd, &addr->type.sa, addr->length);
+ if (cc < 0) {
+ /*
+ * HP-UX "fails" to connect a UDP socket and sets errno to
+ * EINPROGRESS if it's non-blocking. We'd rather regard this as
+ * a success and let the user detect it if it's really an error
+ * at the time of sending a packet on the socket.
+ */
+ if (sock->type == isc_sockettype_udp && errno == EINPROGRESS) {
+ cc = 0;
+ goto success;
+ }
+ if (SOFT_ERROR(errno) || errno == EINPROGRESS)
+ goto queue;
+
+ switch (errno) {
+#define ERROR_MATCH(a, b) case a: dev->result = b; goto err_exit;
+ ERROR_MATCH(EACCES, ISC_R_NOPERM);
+ ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(ECONNREFUSED, ISC_R_CONNREFUSED);
+ ERROR_MATCH(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+#ifdef EHOSTDOWN
+ ERROR_MATCH(EHOSTDOWN, ISC_R_HOSTUNREACH);
+#endif
+ ERROR_MATCH(ENETUNREACH, ISC_R_NETUNREACH);
+ ERROR_MATCH(ENOBUFS, ISC_R_NORESOURCES);
+ ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);
+ ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);
+ ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET);
+#undef ERROR_MATCH
+ }
+
+ sock->connected = 0;
+
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "connect(%s) %d/%s",
+ addrbuf, errno, strbuf);
+
+ UNLOCK(&sock->lock);
+ inc_stats(sock->manager->stats,
+ sock->statsindex[STATID_CONNECTFAIL]);
+ isc_event_free(ISC_EVENT_PTR(&dev));
+ return (ISC_R_UNEXPECTED);
+
+ err_exit:
+ sock->connected = 0;
+ isc_task_send(task, ISC_EVENT_PTR(&dev));
+
+ UNLOCK(&sock->lock);
+ inc_stats(sock->manager->stats,
+ sock->statsindex[STATID_CONNECTFAIL]);
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * If connect completed, fire off the done event.
+ */
+ success:
+ if (cc == 0) {
+ sock->connected = 1;
+ sock->bound = 1;
+ dev->result = ISC_R_SUCCESS;
+ isc_task_send(task, ISC_EVENT_PTR(&dev));
+
+ UNLOCK(&sock->lock);
+
+ inc_stats(sock->manager->stats,
+ sock->statsindex[STATID_CONNECT]);
+
+ return (ISC_R_SUCCESS);
+ }
+
+ queue:
+
+ /*
+ * Attach to task.
+ */
+ isc_task_attach(task, &ntask);
+
+ dev->ev_sender = ntask;
+
+ /*
+ * Poke watcher here. We still have the socket locked, so there
+ * is no race condition. We will keep the lock for such a short
+ * bit of time waking it up now or later won't matter all that much.
+ */
+ if (ISC_LIST_EMPTY(sock->connect_list) && !sock->connecting)
+ select_poke(manager, sock->fd, SELECT_POKE_CONNECT);
+
+ sock->connecting = 1;
+
+ ISC_LIST_ENQUEUE(sock->connect_list, dev, ev_link);
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Called when a socket with a pending connect() finishes.
+ */
+static void
+internal_connect(isc_task_t *me, isc_event_t *ev) {
+ isc__socket_t *sock;
+ isc_socket_connev_t *dev;
+ int cc;
+ isc_result_t result;
+ ISC_SOCKADDR_LEN_T optlen;
+ char strbuf[ISC_STRERRORSIZE];
+ char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+
+ UNUSED(me);
+ INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
+
+ sock = ev->ev_sender;
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+
+ /*
+ * When the internal event was sent the reference count was bumped
+ * to keep the socket around for us. Decrement the count here.
+ */
+ INSIST(sock->references > 0);
+ sock->references--;
+ if (sock->references == 0) {
+ UNLOCK(&sock->lock);
+ destroy(&sock);
+ return;
+ }
+
+ /*
+ * Get the first item off the connect list.
+ * If it is empty, unlock the socket and return.
+ */
+ dev = ISC_LIST_HEAD(sock->connect_list);
+ if (dev == NULL) {
+ INSIST(!sock->connecting);
+ UNLOCK(&sock->lock);
+ return;
+ }
+
+ INSIST(sock->connecting);
+ sock->connecting = 0;
+
+ /*
+ * Get any possible error status here.
+ */
+ optlen = sizeof(cc);
+ if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR,
+ (void *)&cc, (void *)&optlen) != 0)
+ cc = errno;
+ else
+ errno = cc;
+
+ if (errno != 0) {
+ /*
+ * If the error is EAGAIN, just re-select on this
+ * fd and pretend nothing strange happened.
+ */
+ if (SOFT_ERROR(errno) || errno == EINPROGRESS) {
+ sock->connecting = 1;
+ select_poke(sock->manager, sock->fd,
+ SELECT_POKE_CONNECT);
+ UNLOCK(&sock->lock);
+
+ return;
+ }
+
+ inc_stats(sock->manager->stats,
+ sock->statsindex[STATID_CONNECTFAIL]);
+
+ /*
+ * Translate other errors into ISC_R_* flavors.
+ */
+ switch (errno) {
+#define ERROR_MATCH(a, b) case a: result = b; break;
+ ERROR_MATCH(EACCES, ISC_R_NOPERM);
+ ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(ECONNREFUSED, ISC_R_CONNREFUSED);
+ ERROR_MATCH(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+#ifdef EHOSTDOWN
+ ERROR_MATCH(EHOSTDOWN, ISC_R_HOSTUNREACH);
+#endif
+ ERROR_MATCH(ENETUNREACH, ISC_R_NETUNREACH);
+ ERROR_MATCH(ENOBUFS, ISC_R_NORESOURCES);
+ ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);
+ ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);
+ ERROR_MATCH(ETIMEDOUT, ISC_R_TIMEDOUT);
+ ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET);
+#undef ERROR_MATCH
+ default:
+ result = ISC_R_UNEXPECTED;
+ isc_sockaddr_format(&sock->peer_address, peerbuf,
+ sizeof(peerbuf));
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_connect: connect(%s) %s",
+ peerbuf, strbuf);
+ }
+ } else {
+ inc_stats(sock->manager->stats,
+ sock->statsindex[STATID_CONNECT]);
+ result = ISC_R_SUCCESS;
+ sock->connected = 1;
+ sock->bound = 1;
+ }
+
+ do {
+ dev->result = result;
+ send_connectdone_event(sock, &dev);
+ dev = ISC_LIST_HEAD(sock->connect_list);
+ } while (dev != NULL);
+
+ UNLOCK(&sock->lock);
+}
+
+isc_result_t
+isc__socket_getpeername(isc_socket_t *sock0, isc_sockaddr_t *addressp) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ isc_result_t result;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addressp != NULL);
+
+ LOCK(&sock->lock);
+
+ if (sock->connected) {
+ *addressp = sock->peer_address;
+ result = ISC_R_SUCCESS;
+ } else {
+ result = ISC_R_NOTCONNECTED;
+ }
+
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc__socket_getsockname(isc_socket_t *sock0, isc_sockaddr_t *addressp) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ ISC_SOCKADDR_LEN_T len;
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addressp != NULL);
+
+ LOCK(&sock->lock);
+
+ if (!sock->bound) {
+ result = ISC_R_NOTBOUND;
+ goto out;
+ }
+
+ result = ISC_R_SUCCESS;
+
+ len = sizeof(addressp->type);
+ if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto out;
+ }
+ addressp->length = (unsigned int)len;
+
+ out:
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+/*
+ * Run through the list of events on this socket, and cancel the ones
+ * queued for task "task" of type "how". "how" is a bitmask.
+ */
+void
+isc__socket_cancel(isc_socket_t *sock0, isc_task_t *task, unsigned int how) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ /*
+ * Quick exit if there is nothing to do. Don't even bother locking
+ * in this case.
+ */
+ if (how == 0)
+ return;
+
+ LOCK(&sock->lock);
+
+ /*
+ * All of these do the same thing, more or less.
+ * Each will:
+ * o If the internal event is marked as "posted" try to
+ * remove it from the task's queue. If this fails, mark it
+ * as canceled instead, and let the task clean it up later.
+ * o For each I/O request for that task of that type, post
+ * its done event with status of "ISC_R_CANCELED".
+ * o Reset any state needed.
+ */
+ if (((how & ISC_SOCKCANCEL_RECV) == ISC_SOCKCANCEL_RECV)
+ && !ISC_LIST_EMPTY(sock->recv_list)) {
+ isc_socketevent_t *dev;
+ isc_socketevent_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->recv_list);
+
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_recvdone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ }
+
+ if (((how & ISC_SOCKCANCEL_SEND) == ISC_SOCKCANCEL_SEND)
+ && !ISC_LIST_EMPTY(sock->send_list)) {
+ isc_socketevent_t *dev;
+ isc_socketevent_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->send_list);
+
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_senddone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ }
+
+ if (((how & ISC_SOCKCANCEL_ACCEPT) == ISC_SOCKCANCEL_ACCEPT)
+ && !ISC_LIST_EMPTY(sock->accept_list)) {
+ isc_socket_newconnev_t *dev;
+ isc_socket_newconnev_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->accept_list);
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+
+ if ((task == NULL) || (task == current_task)) {
+
+ ISC_LIST_UNLINK(sock->accept_list, dev,
+ ev_link);
+
+ NEWCONNSOCK(dev)->references--;
+ free_socket((isc__socket_t **)&dev->newsocket);
+
+ dev->result = ISC_R_CANCELED;
+ dev->ev_sender = sock;
+ isc_task_sendanddetach(&current_task,
+ ISC_EVENT_PTR(&dev));
+ }
+
+ dev = next;
+ }
+ }
+
+ if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT)
+ && !ISC_LIST_EMPTY(sock->connect_list)) {
+ isc_socket_connev_t *dev;
+ isc_socket_connev_t *next;
+ isc_task_t *current_task;
+
+ INSIST(sock->connecting);
+ sock->connecting = 0;
+
+ dev = ISC_LIST_HEAD(sock->connect_list);
+
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_connectdone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ }
+
+ UNLOCK(&sock->lock);
+}
+
+isc_sockettype_t
+isc__socket_gettype(isc_socket_t *sock0) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ return (sock->type);
+}
+
+bool
+isc__socket_isbound(isc_socket_t *sock0) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+ bool val;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ val = ((sock->bound) ? true : false);
+ UNLOCK(&sock->lock);
+
+ return (val);
+}
+
+void
+isc__socket_ipv6only(isc_socket_t *sock0, bool yes) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+#if defined(IPV6_V6ONLY)
+ int onoff = yes ? 1 : 0;
+#else
+ UNUSED(yes);
+ UNUSED(sock);
+#endif
+
+ REQUIRE(VALID_SOCKET(sock));
+ INSIST(!sock->dupped);
+
+#ifdef IPV6_V6ONLY
+ if (sock->pf == AF_INET6) {
+ if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (void *)&onoff, sizeof(int)) < 0) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_V6ONLY) "
+ "%s: %s", sock->fd,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+ }
+ FIX_IPV6_RECVPKTINFO(sock); /* AIX */
+#endif
+}
+
+static void
+setdscp(isc__socket_t *sock, isc_dscp_t dscp) {
+#if defined(IP_TOS) || defined(IPV6_TCLASS)
+ int value = dscp << 2;
+#endif
+
+ sock->dscp = dscp;
+
+#ifdef IP_TOS
+ if (sock->pf == AF_INET) {
+ if (setsockopt(sock->fd, IPPROTO_IP, IP_TOS,
+ (void *)&value, sizeof(value)) < 0) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IP_TOS, %.02x) "
+ "%s: %s", sock->fd, value >> 2,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+ }
+#endif
+#ifdef IPV6_TCLASS
+ if (sock->pf == AF_INET6) {
+ if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_TCLASS,
+ (void *)&value, sizeof(value)) < 0) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_TCLASS, %.02x) "
+ "%s: %s", sock->fd, dscp >> 2,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+ }
+#endif
+}
+
+void
+isc__socket_dscp(isc_socket_t *sock0, isc_dscp_t dscp) {
+ isc__socket_t *sock = (isc__socket_t *)sock0;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(dscp < 0x40);
+
+#if !defined(IP_TOS) && !defined(IPV6_TCLASS)
+ UNUSED(dscp);
+#else
+ if (dscp < 0)
+ return;
+
+ /* The DSCP value must not be changed once it has been set. */
+ if (isc_dscp_check_value != -1)
+ INSIST(dscp == isc_dscp_check_value);
+#endif
+
+
+#ifdef notyet
+ REQUIRE(!sock->dupped);
+#endif
+
+ setdscp(sock, dscp);
+}
+
+isc_socketevent_t *
+isc_socket_socketevent(isc_mem_t *mctx, void *sender,
+ isc_eventtype_t eventtype, isc_taskaction_t action,
+ void *arg)
+{
+ return (allocate_socketevent(mctx, sender, eventtype, action, arg));
+}
+
+#ifndef USE_WATCHER_THREAD
+/*
+ * In our assumed scenario, we can simply use a single static object.
+ * XXX: this is not true if the application uses multiple threads with
+ * 'multi-context' mode. Fixing this is a future TODO item.
+ */
+static isc_socketwait_t swait_private;
+
+int
+isc__socketmgr_waitevents(isc_socketmgr_t *manager0, struct timeval *tvp,
+ isc_socketwait_t **swaitp)
+{
+ isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0;
+ int n;
+#ifdef USE_KQUEUE
+ struct timespec ts, *tsp;
+#endif
+#ifdef USE_EPOLL
+ int timeout;
+#endif
+#ifdef USE_DEVPOLL
+ isc_result_t result;
+ int pass;
+ struct dvpoll dvp;
+#endif
+
+ REQUIRE(swaitp != NULL && *swaitp == NULL);
+
+#ifdef USE_SHARED_MANAGER
+ if (manager == NULL)
+ manager = socketmgr;
+#endif
+ if (manager == NULL)
+ return (0);
+
+#ifdef USE_KQUEUE
+ if (tvp != NULL) {
+ ts.tv_sec = tvp->tv_sec;
+ ts.tv_nsec = tvp->tv_usec * 1000;
+ tsp = &ts;
+ } else
+ tsp = NULL;
+ swait_private.nevents = kevent(manager->kqueue_fd, NULL, 0,
+ manager->events, manager->nevents,
+ tsp);
+ n = swait_private.nevents;
+#elif defined(USE_EPOLL)
+ if (tvp != NULL)
+ timeout = tvp->tv_sec * 1000 + (tvp->tv_usec + 999) / 1000;
+ else
+ timeout = -1;
+ swait_private.nevents = epoll_wait(manager->epoll_fd,
+ manager->events,
+ manager->nevents, timeout);
+ n = swait_private.nevents;
+#elif defined(USE_DEVPOLL)
+ /*
+ * Re-probe every thousand calls.
+ */
+ if (manager->calls++ > 1000U) {
+ result = isc_resource_getcurlimit(isc_resource_openfiles,
+ &manager->open_max);
+ if (result != ISC_R_SUCCESS)
+ manager->open_max = 64;
+ manager->calls = 0;
+ }
+ for (pass = 0; pass < 2; pass++) {
+ dvp.dp_fds = manager->events;
+ dvp.dp_nfds = manager->nevents;
+ if (dvp.dp_nfds >= manager->open_max)
+ dvp.dp_nfds = manager->open_max - 1;
+ if (tvp != NULL) {
+ dvp.dp_timeout = tvp->tv_sec * 1000 +
+ (tvp->tv_usec + 999) / 1000;
+ } else
+ dvp.dp_timeout = -1;
+ n = ioctl(manager->devpoll_fd, DP_POLL, &dvp);
+ if (n == -1 && errno == EINVAL) {
+ /*
+ * {OPEN_MAX} may have dropped. Look
+ * up the current value and try again.
+ */
+ result = isc_resource_getcurlimit(
+ isc_resource_openfiles,
+ &manager->open_max);
+ if (result != ISC_R_SUCCESS)
+ manager->open_max = 64;
+ } else
+ break;
+ }
+ swait_private.nevents = n;
+#elif defined(USE_SELECT)
+ memmove(manager->read_fds_copy, manager->read_fds, manager->fd_bufsize);
+ memmove(manager->write_fds_copy, manager->write_fds,
+ manager->fd_bufsize);
+
+ swait_private.readset = manager->read_fds_copy;
+ swait_private.writeset = manager->write_fds_copy;
+ swait_private.maxfd = manager->maxfd + 1;
+
+ n = select(swait_private.maxfd, swait_private.readset,
+ swait_private.writeset, NULL, tvp);
+#endif
+
+ *swaitp = &swait_private;
+ return (n);
+}
+
+isc_result_t
+isc__socketmgr_dispatch(isc_socketmgr_t *manager0, isc_socketwait_t *swait) {
+ isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0;
+
+ REQUIRE(swait == &swait_private);
+
+#ifdef USE_SHARED_MANAGER
+ if (manager == NULL)
+ manager = socketmgr;
+#endif
+ if (manager == NULL)
+ return (ISC_R_NOTFOUND);
+
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
+ (void)process_fds(manager, manager->events, swait->nevents);
+ return (ISC_R_SUCCESS);
+#elif defined(USE_SELECT)
+ process_fds(manager, swait->maxfd, swait->readset, swait->writeset);
+ return (ISC_R_SUCCESS);
+#endif
+}
+#endif /* USE_WATCHER_THREAD */
+
+void
+isc__socket_setname(isc_socket_t *socket0, const char *name, void *tag) {
+ isc__socket_t *sock = (isc__socket_t *)socket0;
+
+ /*
+ * Name 'sock'.
+ */
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ strlcpy(sock->name, name, sizeof(sock->name));
+ sock->tag = tag;
+ UNLOCK(&sock->lock);
+}
+
+const char *
+isc__socket_getname(isc_socket_t *socket0) {
+ isc__socket_t *sock = (isc__socket_t *)socket0;
+
+ return (sock->name);
+}
+
+void *
+isc__socket_gettag(isc_socket_t *socket0) {
+ isc__socket_t *sock = (isc__socket_t *)socket0;
+
+ return (sock->tag);
+}
+
+isc_result_t
+isc__socket_register(void) {
+ return (isc_socket_register(isc__socketmgr_create));
+}
+
+int
+isc__socket_getfd(isc_socket_t *socket0) {
+ isc__socket_t *sock = (isc__socket_t *)socket0;
+
+ return ((short) sock->fd);
+}
+
+#if defined(HAVE_LIBXML2) || defined(HAVE_JSON)
+static const char *
+_socktype(isc_sockettype_t type)
+{
+ if (type == isc_sockettype_udp)
+ return ("udp");
+ else if (type == isc_sockettype_tcp)
+ return ("tcp");
+ else if (type == isc_sockettype_unix)
+ return ("unix");
+ else if (type == isc_sockettype_fdwatch)
+ return ("fdwatch");
+ else
+ return ("not-initialized");
+}
+#endif
+
+#ifdef HAVE_LIBXML2
+#define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
+int
+isc_socketmgr_renderxml(isc_socketmgr_t *mgr0, xmlTextWriterPtr writer) {
+ isc__socketmgr_t *mgr = (isc__socketmgr_t *)mgr0;
+ isc__socket_t *sock = NULL;
+ char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_t addr;
+ ISC_SOCKADDR_LEN_T len;
+ int xmlrc;
+
+ LOCK(&mgr->lock);
+
+#ifdef USE_SHARED_MANAGER
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->refs));
+ TRY0(xmlTextWriterEndElement(writer));
+#endif /* USE_SHARED_MANAGER */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "sockets"));
+ sock = ISC_LIST_HEAD(mgr->socklist);
+ while (sock != NULL) {
+ LOCK(&sock->lock);
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socket"));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%p", sock));
+ TRY0(xmlTextWriterEndElement(writer));
+
+ if (sock->name[0] != 0) {
+ TRY0(xmlTextWriterStartElement(writer,
+ ISC_XMLCHAR "name"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%s",
+ sock->name));
+ TRY0(xmlTextWriterEndElement(writer)); /* name */
+ }
+
+ TRY0(xmlTextWriterStartElement(writer,
+ ISC_XMLCHAR "references"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d",
+ sock->references));
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterWriteElement(writer, ISC_XMLCHAR "type",
+ ISC_XMLCHAR _socktype(sock->type)));
+
+ if (sock->connected) {
+ isc_sockaddr_format(&sock->peer_address, peerbuf,
+ sizeof(peerbuf));
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "peer-address",
+ ISC_XMLCHAR peerbuf));
+ }
+
+ len = sizeof(addr);
+ if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) {
+ isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf));
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "local-address",
+ ISC_XMLCHAR peerbuf));
+ }
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "states"));
+ if (sock->pending_recv)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "pending-receive"));
+ if (sock->pending_send)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "pending-send"));
+ if (sock->pending_accept)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "pending_accept"));
+ if (sock->listener)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "listener"));
+ if (sock->connected)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "connected"));
+ if (sock->connecting)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "connecting"));
+ if (sock->bound)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "bound"));
+
+ TRY0(xmlTextWriterEndElement(writer)); /* states */
+
+ TRY0(xmlTextWriterEndElement(writer)); /* socket */
+
+ UNLOCK(&sock->lock);
+ sock = ISC_LIST_NEXT(sock, link);
+ }
+ TRY0(xmlTextWriterEndElement(writer)); /* sockets */
+
+ error:
+ if (sock != NULL)
+ UNLOCK(&sock->lock);
+
+ UNLOCK(&mgr->lock);
+
+ return (xmlrc);
+}
+#endif /* HAVE_LIBXML2 */
+
+#ifdef HAVE_JSON
+#define CHECKMEM(m) do { \
+ if (m == NULL) { \
+ result = ISC_R_NOMEMORY;\
+ goto error;\
+ } \
+} while(0)
+
+isc_result_t
+isc_socketmgr_renderjson(isc_socketmgr_t *mgr0, json_object *stats) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc__socketmgr_t *mgr = (isc__socketmgr_t *)mgr0;
+ isc__socket_t *sock = NULL;
+ char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_t addr;
+ ISC_SOCKADDR_LEN_T len;
+ json_object *obj, *array = json_object_new_array();
+
+ CHECKMEM(array);
+
+ LOCK(&mgr->lock);
+
+#ifdef USE_SHARED_MANAGER
+ obj = json_object_new_int(mgr->refs);
+ CHECKMEM(obj);
+ json_object_object_add(stats, "references", obj);
+#endif /* USE_SHARED_MANAGER */
+
+ sock = ISC_LIST_HEAD(mgr->socklist);
+ while (sock != NULL) {
+ json_object *states, *entry = json_object_new_object();
+ char buf[255];
+
+ CHECKMEM(entry);
+ json_object_array_add(array, entry);
+
+ LOCK(&sock->lock);
+
+ snprintf(buf, sizeof(buf), "%p", sock);
+ obj = json_object_new_string(buf);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "id", obj);
+
+ if (sock->name[0] != 0) {
+ obj = json_object_new_string(sock->name);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "name", obj);
+ }
+
+ obj = json_object_new_int(sock->references);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "references", obj);
+
+ obj = json_object_new_string(_socktype(sock->type));
+ CHECKMEM(obj);
+ json_object_object_add(entry, "type", obj);
+
+ if (sock->connected) {
+ isc_sockaddr_format(&sock->peer_address, peerbuf,
+ sizeof(peerbuf));
+ obj = json_object_new_string(peerbuf);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "peer-address", obj);
+ }
+
+ len = sizeof(addr);
+ if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) {
+ isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf));
+ obj = json_object_new_string(peerbuf);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "local-address", obj);
+ }
+
+ states = json_object_new_array();
+ CHECKMEM(states);
+ json_object_object_add(entry, "states", states);
+
+ if (sock->pending_recv) {
+ obj = json_object_new_string("pending-receive");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->pending_send) {
+ obj = json_object_new_string("pending-send");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->pending_accept) {
+ obj = json_object_new_string("pending-accept");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->listener) {
+ obj = json_object_new_string("listener");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->connected) {
+ obj = json_object_new_string("connected");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->connecting) {
+ obj = json_object_new_string("connecting");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->bound) {
+ obj = json_object_new_string("bound");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ UNLOCK(&sock->lock);
+ sock = ISC_LIST_NEXT(sock, link);
+ }
+
+ json_object_object_add(stats, "sockets", array);
+ array = NULL;
+ result = ISC_R_SUCCESS;
+
+ error:
+ if (array != NULL)
+ json_object_put(array);
+
+ if (sock != NULL)
+ UNLOCK(&sock->lock);
+
+ UNLOCK(&mgr->lock);
+
+ return (result);
+}
+#endif /* HAVE_JSON */
+
+#include "../socket_api.c"
diff --git a/lib/isc/unix/socket_p.h b/lib/isc/unix/socket_p.h
new file mode 100644
index 0000000..fb4fdb8
--- /dev/null
+++ b/lib/isc/unix/socket_p.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_SOCKET_P_H
+#define ISC_SOCKET_P_H
+
+/*! \file */
+
+#ifdef ISC_PLATFORM_NEEDSYSSELECTH
+#include <sys/select.h>
+#endif
+
+typedef struct isc_socketwait isc_socketwait_t;
+int isc__socketmgr_waitevents(isc_socketmgr_t *, struct timeval *,
+ isc_socketwait_t **);
+isc_result_t isc__socketmgr_dispatch(isc_socketmgr_t *, isc_socketwait_t *);
+#endif /* ISC_SOCKET_P_H */
diff --git a/lib/isc/unix/stdio.c b/lib/isc/unix/stdio.c
new file mode 100644
index 0000000..e60fa65
--- /dev/null
+++ b/lib/isc/unix/stdio.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <isc/stdio.h>
+#include <isc/stat.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+isc_result_t
+isc_stdio_open(const char *filename, const char *mode, FILE **fp) {
+ FILE *f;
+
+ f = fopen(filename, mode);
+ if (f == NULL)
+ return (isc__errno2result(errno));
+ *fp = f;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_stdio_close(FILE *f) {
+ int r;
+
+ r = fclose(f);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_seek(FILE *f, off_t offset, int whence) {
+ int r;
+
+#ifdef HAVE_FSEEKO
+ r = fseeko(f, offset, whence);
+#else
+ r = fseek(f, offset, whence);
+#endif
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_tell(FILE *f, off_t *offsetp) {
+ off_t r;
+
+ REQUIRE(offsetp != NULL);
+
+#ifdef HAVE_FTELLO
+ r = ftello(f);
+#else
+ r = ftell(f);
+#endif
+ if (r >= 0) {
+ *offsetp = r;
+ return (ISC_R_SUCCESS);
+ } else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f, size_t *nret) {
+ isc_result_t result = ISC_R_SUCCESS;
+ size_t r;
+
+ clearerr(f);
+ r = fread(ptr, size, nmemb, f);
+ if (r != nmemb) {
+ if (feof(f))
+ result = ISC_R_EOF;
+ else
+ result = isc__errno2result(errno);
+ }
+ if (nret != NULL)
+ *nret = r;
+ return (result);
+}
+
+isc_result_t
+isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f,
+ size_t *nret)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ size_t r;
+
+ clearerr(f);
+ r = fwrite(ptr, size, nmemb, f);
+ if (r != nmemb)
+ result = isc__errno2result(errno);
+ if (nret != NULL)
+ *nret = r;
+ return (result);
+}
+
+isc_result_t
+isc_stdio_flush(FILE *f) {
+ int r;
+
+ r = fflush(f);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+/*
+ * OpenBSD has deprecated ENOTSUP in favor of EOPNOTSUPP.
+ */
+#if defined(EOPNOTSUPP) && !defined(ENOTSUP)
+#define ENOTSUP EOPNOTSUPP
+#endif
+
+isc_result_t
+isc_stdio_sync(FILE *f) {
+ struct stat buf;
+ int r;
+
+ if (fstat(fileno(f), &buf) != 0)
+ return (isc__errno2result(errno));
+
+ /*
+ * Only call fsync() on regular files.
+ */
+ if ((buf.st_mode & S_IFMT) != S_IFREG)
+ return (ISC_R_SUCCESS);
+
+ r = fsync(fileno(f));
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
diff --git a/lib/isc/unix/stdtime.c b/lib/isc/unix/stdtime.c
new file mode 100644
index 0000000..989bde4
--- /dev/null
+++ b/lib/isc/unix/stdtime.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stddef.h> /* NULL */
+#include <stdlib.h> /* NULL */
+#include <syslog.h>
+
+#include <sys/time.h>
+
+#include <isc/stdtime.h>
+#include <isc/util.h>
+
+#ifndef ISC_FIX_TV_USEC
+#define ISC_FIX_TV_USEC 1
+#endif
+
+#define US_PER_S 1000000
+
+#if ISC_FIX_TV_USEC
+static inline void
+fix_tv_usec(struct timeval *tv) {
+ bool fixed = false;
+
+ if (tv->tv_usec < 0) {
+ fixed = true;
+ do {
+ tv->tv_sec -= 1;
+ tv->tv_usec += US_PER_S;
+ } while (tv->tv_usec < 0);
+ } else if (tv->tv_usec >= US_PER_S) {
+ fixed = true;
+ do {
+ tv->tv_sec += 1;
+ tv->tv_usec -= US_PER_S;
+ } while (tv->tv_usec >=US_PER_S);
+ }
+ /*
+ * Call syslog directly as we are called from the logging functions.
+ */
+ if (fixed)
+ (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
+}
+#endif
+
+void
+isc_stdtime_get(isc_stdtime_t *t) {
+ struct timeval tv;
+
+ /*
+ * Set 't' to the number of seconds since 00:00:00 UTC, January 1,
+ * 1970.
+ */
+
+ REQUIRE(t != NULL);
+
+ RUNTIME_CHECK(gettimeofday(&tv, NULL) != -1);
+
+#if ISC_FIX_TV_USEC
+ fix_tv_usec(&tv);
+ INSIST(tv.tv_usec >= 0);
+#else
+ INSIST(tv.tv_usec >= 0 && tv.tv_usec < US_PER_S);
+#endif
+
+ *t = (unsigned int)tv.tv_sec;
+}
diff --git a/lib/isc/unix/strerror.c b/lib/isc/unix/strerror.c
new file mode 100644
index 0000000..e4fb793
--- /dev/null
+++ b/lib/isc/unix/strerror.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/strerror.h>
+#include <isc/util.h>
+
+#ifdef HAVE_STRERROR
+/*%
+ * We need to do this this way for profiled locks.
+ */
+static isc_mutex_t isc_strerror_lock;
+static void init_lock(void) {
+ RUNTIME_CHECK(isc_mutex_init(&isc_strerror_lock) == ISC_R_SUCCESS);
+}
+#else
+extern const char * const sys_errlist[];
+extern const int sys_nerr;
+#endif
+
+void
+isc__strerror(int num, char *buf, size_t size) {
+#ifdef HAVE_STRERROR
+ char *msg;
+ unsigned int unum = (unsigned int)num;
+ static isc_once_t once = ISC_ONCE_INIT;
+
+ REQUIRE(buf != NULL);
+
+ RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS);
+
+ LOCK(&isc_strerror_lock);
+ msg = strerror(num);
+ if (msg != NULL)
+ snprintf(buf, size, "%s", msg);
+ else
+ snprintf(buf, size, "Unknown error: %u", unum);
+ UNLOCK(&isc_strerror_lock);
+#else
+ unsigned int unum = (unsigned int)num;
+
+ REQUIRE(buf != NULL);
+
+ if (num >= 0 && num < sys_nerr)
+ snprintf(buf, size, "%s", sys_errlist[num]);
+ else
+ snprintf(buf, size, "Unknown error: %u", unum);
+#endif
+}
diff --git a/lib/isc/unix/syslog.c b/lib/isc/unix/syslog.c
new file mode 100644
index 0000000..4ce3272
--- /dev/null
+++ b/lib/isc/unix/syslog.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/syslog.h>
+#include <isc/util.h>
+
+static struct dsn_c_pvt_sfnt {
+ int val;
+ const char *strval;
+} facilities[] = {
+ { LOG_KERN, "kern" },
+ { LOG_USER, "user" },
+ { LOG_MAIL, "mail" },
+ { LOG_DAEMON, "daemon" },
+ { LOG_AUTH, "auth" },
+ { LOG_SYSLOG, "syslog" },
+ { LOG_LPR, "lpr" },
+#ifdef LOG_NEWS
+ { LOG_NEWS, "news" },
+#endif
+#ifdef LOG_UUCP
+ { LOG_UUCP, "uucp" },
+#endif
+#ifdef LOG_CRON
+ { LOG_CRON, "cron" },
+#endif
+#ifdef LOG_AUTHPRIV
+ { LOG_AUTHPRIV, "authpriv" },
+#endif
+#ifdef LOG_FTP
+ { LOG_FTP, "ftp" },
+#endif
+ { LOG_LOCAL0, "local0"},
+ { LOG_LOCAL1, "local1"},
+ { LOG_LOCAL2, "local2"},
+ { LOG_LOCAL3, "local3"},
+ { LOG_LOCAL4, "local4"},
+ { LOG_LOCAL5, "local5"},
+ { LOG_LOCAL6, "local6"},
+ { LOG_LOCAL7, "local7"},
+ { 0, NULL }
+};
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp) {
+ int i;
+
+ REQUIRE(str != NULL);
+ REQUIRE(facilityp != NULL);
+
+ for (i = 0; facilities[i].strval != NULL; i++) {
+ if (strcasecmp(facilities[i].strval, str) == 0) {
+ *facilityp = facilities[i].val;
+ return (ISC_R_SUCCESS);
+ }
+ }
+ return (ISC_R_NOTFOUND);
+
+}
diff --git a/lib/isc/unix/time.c b/lib/isc/unix/time.c
new file mode 100644
index 0000000..8edc9df
--- /dev/null
+++ b/lib/isc/unix/time.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <sys/time.h> /* Required for struct timeval on some platforms. */
+
+#include <isc/log.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/tm.h>
+#include <isc/util.h>
+
+#define NS_PER_S 1000000000 /*%< Nanoseconds per second. */
+#define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */
+#define NS_PER_MS 1000000 /*%< Nanoseconds per millisecond. */
+#define US_PER_S 1000000 /*%< Microseconds per second. */
+
+/*
+ * All of the INSIST()s checks of nanoseconds < NS_PER_S are for
+ * consistency checking of the type. In lieu of magic numbers, it
+ * is the best we've got. The check is only performed on functions which
+ * need an initialized type.
+ */
+
+#ifndef ISC_FIX_TV_USEC
+#define ISC_FIX_TV_USEC 1
+#endif
+
+/*%
+ *** Intervals
+ ***/
+
+static const isc_interval_t zero_interval = { 0, 0 };
+const isc_interval_t * const isc_interval_zero = &zero_interval;
+
+#if ISC_FIX_TV_USEC
+static inline void
+fix_tv_usec(struct timeval *tv) {
+ bool fixed = false;
+
+ if (tv->tv_usec < 0) {
+ fixed = true;
+ do {
+ tv->tv_sec -= 1;
+ tv->tv_usec += US_PER_S;
+ } while (tv->tv_usec < 0);
+ } else if (tv->tv_usec >= US_PER_S) {
+ fixed = true;
+ do {
+ tv->tv_sec += 1;
+ tv->tv_usec -= US_PER_S;
+ } while (tv->tv_usec >=US_PER_S);
+ }
+ /*
+ * Call syslog directly as was are called from the logging functions.
+ */
+ if (fixed)
+ (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
+}
+#endif
+
+void
+isc_interval_set(isc_interval_t *i,
+ unsigned int seconds, unsigned int nanoseconds)
+{
+ REQUIRE(i != NULL);
+ REQUIRE(nanoseconds < NS_PER_S);
+
+ i->seconds = seconds;
+ i->nanoseconds = nanoseconds;
+}
+
+bool
+isc_interval_iszero(const isc_interval_t *i) {
+ REQUIRE(i != NULL);
+ INSIST(i->nanoseconds < NS_PER_S);
+
+ if (i->seconds == 0 && i->nanoseconds == 0)
+ return (true);
+
+ return (false);
+}
+
+
+/***
+ *** Absolute Times
+ ***/
+
+static const isc_time_t epoch = { 0, 0 };
+const isc_time_t * const isc_time_epoch = &epoch;
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
+ REQUIRE(t != NULL);
+ REQUIRE(nanoseconds < NS_PER_S);
+
+ t->seconds = seconds;
+ t->nanoseconds = nanoseconds;
+}
+
+void
+isc_time_settoepoch(isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ t->seconds = 0;
+ t->nanoseconds = 0;
+}
+
+bool
+isc_time_isepoch(const isc_time_t *t) {
+ REQUIRE(t != NULL);
+ INSIST(t->nanoseconds < NS_PER_S);
+
+ if (t->seconds == 0 && t->nanoseconds == 0)
+ return (true);
+
+ return (false);
+}
+
+
+isc_result_t
+isc_time_now(isc_time_t *t) {
+ struct timeval tv;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(t != NULL);
+
+ if (gettimeofday(&tv, NULL) == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ /*
+ * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not,
+ * then this test will generate warnings for platforms on which it is
+ * unsigned. In any event, the chances of any of these problems
+ * happening are pretty much zero, but since the libisc library ensures
+ * certain things to be true ...
+ */
+#if ISC_FIX_TV_USEC
+ fix_tv_usec(&tv);
+ if (tv.tv_sec < 0)
+ return (ISC_R_UNEXPECTED);
+#else
+ if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
+ return (ISC_R_UNEXPECTED);
+#endif
+
+ /*
+ * Ensure the tv_sec value fits in t->seconds.
+ */
+ if (sizeof(tv.tv_sec) > sizeof(t->seconds) &&
+ ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U)
+ return (ISC_R_RANGE);
+
+ t->seconds = tv.tv_sec;
+ t->nanoseconds = tv.tv_usec * NS_PER_US;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
+ struct timeval tv;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(t != NULL);
+ REQUIRE(i != NULL);
+ INSIST(i->nanoseconds < NS_PER_S);
+
+ if (gettimeofday(&tv, NULL) == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ /*
+ * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not,
+ * then this test will generate warnings for platforms on which it is
+ * unsigned. In any event, the chances of any of these problems
+ * happening are pretty much zero, but since the libisc library ensures
+ * certain things to be true ...
+ */
+#if ISC_FIX_TV_USEC
+ fix_tv_usec(&tv);
+ if (tv.tv_sec < 0)
+ return (ISC_R_UNEXPECTED);
+#else
+ if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
+ return (ISC_R_UNEXPECTED);
+#endif
+
+ /*
+ * Ensure the resulting seconds value fits in the size of an
+ * unsigned int. (It is written this way as a slight optimization;
+ * note that even if both values == INT_MAX, then when added
+ * and getting another 1 added below the result is UINT_MAX.)
+ */
+ if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
+ ((long long)tv.tv_sec + i->seconds > UINT_MAX))
+ return (ISC_R_RANGE);
+
+ t->seconds = tv.tv_sec + i->seconds;
+ t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds;
+ if (t->nanoseconds >= NS_PER_S) {
+ t->seconds++;
+ t->nanoseconds -= NS_PER_S;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
+ REQUIRE(t1 != NULL && t2 != NULL);
+ INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
+
+ if (t1->seconds < t2->seconds)
+ return (-1);
+ if (t1->seconds > t2->seconds)
+ return (1);
+ if (t1->nanoseconds < t2->nanoseconds)
+ return (-1);
+ if (t1->nanoseconds > t2->nanoseconds)
+ return (1);
+ return (0);
+}
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
+{
+ REQUIRE(t != NULL && i != NULL && result != NULL);
+ INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
+
+ /*
+ * Ensure the resulting seconds value fits in the size of an
+ * unsigned int. (It is written this way as a slight optimization;
+ * note that even if both values == INT_MAX, then when added
+ * and getting another 1 added below the result is UINT_MAX.)
+ */
+ if ((t->seconds > INT_MAX || i->seconds > INT_MAX) &&
+ ((long long)t->seconds + i->seconds > UINT_MAX))
+ return (ISC_R_RANGE);
+
+ result->seconds = t->seconds + i->seconds;
+ result->nanoseconds = t->nanoseconds + i->nanoseconds;
+ if (result->nanoseconds >= NS_PER_S) {
+ result->seconds++;
+ result->nanoseconds -= NS_PER_S;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+ isc_time_t *result)
+{
+ REQUIRE(t != NULL && i != NULL && result != NULL);
+ INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
+
+ if ((unsigned int)t->seconds < i->seconds ||
+ ((unsigned int)t->seconds == i->seconds &&
+ t->nanoseconds < i->nanoseconds))
+ return (ISC_R_RANGE);
+
+ result->seconds = t->seconds - i->seconds;
+ if (t->nanoseconds >= i->nanoseconds)
+ result->nanoseconds = t->nanoseconds - i->nanoseconds;
+ else {
+ result->nanoseconds = NS_PER_S - i->nanoseconds +
+ t->nanoseconds;
+ result->seconds--;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
+ uint64_t i1, i2, i3;
+
+ REQUIRE(t1 != NULL && t2 != NULL);
+ INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
+
+ i1 = (uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds;
+ i2 = (uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds;
+
+ if (i1 <= i2)
+ return (0);
+
+ i3 = i1 - i2;
+
+ /*
+ * Convert to microseconds.
+ */
+ i3 /= NS_PER_US;
+
+ return (i3);
+}
+
+uint32_t
+isc_time_seconds(const isc_time_t *t) {
+ REQUIRE(t != NULL);
+ INSIST(t->nanoseconds < NS_PER_S);
+
+ return ((uint32_t)t->seconds);
+}
+
+isc_result_t
+isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
+ time_t seconds;
+
+ REQUIRE(t != NULL);
+ INSIST(t->nanoseconds < NS_PER_S);
+
+ /*
+ * Ensure that the number of seconds represented by t->seconds
+ * can be represented by a time_t. Since t->seconds is an unsigned
+ * int and since time_t is mostly opaque, this is trickier than
+ * it seems. (This standardized opaqueness of time_t is *very*
+ * frustrating; time_t is not even limited to being an integral
+ * type.)
+ *
+ * The mission, then, is to avoid generating any kind of warning
+ * about "signed versus unsigned" while trying to determine if the
+ * the unsigned int t->seconds is out range for tv_sec, which is
+ * pretty much only true if time_t is a signed integer of the same
+ * size as the return value of isc_time_seconds.
+ *
+ * If the paradox in the if clause below is true, t->seconds is out
+ * of range for time_t.
+ */
+ seconds = (time_t)t->seconds;
+
+ INSIST(sizeof(unsigned int) == sizeof(uint32_t));
+ INSIST(sizeof(time_t) >= sizeof(uint32_t));
+
+ if (t->seconds > (~0U>>1) && seconds <= (time_t)(~0U>>1))
+ return (ISC_R_RANGE);
+
+ *secondsp = seconds;
+
+ return (ISC_R_SUCCESS);
+}
+
+uint32_t
+isc_time_nanoseconds(const isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ ENSURE(t->nanoseconds < NS_PER_S);
+
+ return ((uint32_t)t->nanoseconds);
+}
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+ time_t now;
+ unsigned int flen;
+#ifdef ISC_PLATFORM_USETHREADS
+ struct tm tm;
+#endif
+
+ REQUIRE(t != NULL);
+ INSIST(t->nanoseconds < NS_PER_S);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ now = (time_t) t->seconds;
+#ifdef ISC_PLATFORM_USETHREADS
+ flen = strftime(buf, len, "%d-%b-%Y %X", localtime_r(&now, &tm));
+#else
+ flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now));
+#endif
+ INSIST(flen < len);
+ if (flen != 0)
+ snprintf(buf + flen, len - flen,
+ ".%03u", t->nanoseconds / NS_PER_MS);
+ else {
+ strlcpy(buf, "99-Bad-9999 99:99:99.999", len);
+ }
+}
+
+void
+isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+ time_t now;
+ unsigned int flen;
+#ifdef ISC_PLATFORM_USETHREADS
+ struct tm tm;
+#endif
+
+ REQUIRE(t != NULL);
+ INSIST(t->nanoseconds < NS_PER_S);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ /*
+ * 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+ %b (29+)
+ */
+ now = (time_t)t->seconds;
+#ifdef ISC_PLATFORM_USETHREADS
+ flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT",
+ gmtime_r(&now, &tm));
+#else
+ flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
+#endif
+ INSIST(flen < len);
+}
+
+isc_result_t
+isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
+ struct tm t_tm;
+ time_t when;
+ char *p;
+
+ REQUIRE(buf != NULL);
+ REQUIRE(t != NULL);
+
+ p = isc_tm_strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
+ if (p == NULL)
+ return (ISC_R_UNEXPECTED);
+ when = isc_tm_timegm(&t_tm);
+ if (when == -1)
+ return (ISC_R_UNEXPECTED);
+ isc_time_set(t, when, 0);
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
+ time_t now;
+ unsigned int flen;
+#ifdef ISC_PLATFORM_USETHREADS
+ struct tm tm;
+#endif
+
+ REQUIRE(t != NULL);
+ INSIST(t->nanoseconds < NS_PER_S);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ now = (time_t)t->seconds;
+#ifdef ISC_PLATFORM_USETHREADS
+ flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm));
+#else
+ flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
+#endif
+ INSIST(flen < len);
+}
+
+void
+isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) {
+ time_t now;
+ unsigned int flen;
+#ifdef ISC_PLATFORM_USETHREADS
+ struct tm tm;
+#endif
+
+ REQUIRE(t != NULL);
+ INSIST(t->nanoseconds < NS_PER_S);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ now = (time_t)t->seconds;
+#ifdef ISC_PLATFORM_USETHREADS
+ flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm));
+#else
+ flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
+#endif
+ INSIST(flen < len);
+ if (flen > 0U && len - flen >= 5) {
+ flen -= 1; /* rewind one character (Z) */
+ snprintf(buf + flen, len - flen, ".%03uZ",
+ t->nanoseconds / NS_PER_MS);
+ }
+}
diff --git a/lib/isc/version.c b/lib/isc/version.c
new file mode 100644
index 0000000..3a83a39
--- /dev/null
+++ b/lib/isc/version.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <isc/version.h>
+
+const char isc_version[] = VERSION;
+
+const unsigned int isc_libinterface = LIBINTERFACE;
+const unsigned int isc_librevision = LIBREVISION;
+const unsigned int isc_libage = LIBAGE;
diff --git a/lib/isc/win32/DLLMain.c b/lib/isc/win32/DLLMain.c
new file mode 100644
index 0000000..f14260e
--- /dev/null
+++ b/lib/isc/win32/DLLMain.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <windows.h>
+#include <stdio.h>
+
+/*
+ * Called when we enter the DLL
+ */
+__declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL,
+ DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ /*
+ * The DLL is loading due to process
+ * initialization or a call to LoadLibrary.
+ */
+ case DLL_PROCESS_ATTACH:
+ break;
+
+ /* The attached process creates a new thread. */
+ case DLL_THREAD_ATTACH:
+ break;
+
+ /* The thread of the attached process terminates. */
+ case DLL_THREAD_DETACH:
+ break;
+
+ /*
+ * The DLL is unloading from a process due to
+ * process termination or a call to FreeLibrary.
+ */
+ case DLL_PROCESS_DETACH:
+ break;
+
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
diff --git a/lib/isc/win32/Makefile.in b/lib/isc/win32/Makefile.in
new file mode 100644
index 0000000..19b46bd
--- /dev/null
+++ b/lib/isc/win32/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+CINCLUDES = -I${srcdir}/.. \
+ -I./include \
+ -I${srcdir}/include \
+ -I${srcdir}/../include
+CDEFINES =
+CWARNINGS =
+
+# Alphabetically
+OBJS = condition.@O@ dir.@O@ errno.@O@ file.@O@ \
+ meminfo.@O@ fsaccess.@O@ \
+ once.@O@ stdtime.@O@ thread.@O@ time.@O@ @ISC_PK11_API_O@
+
+# Alphabetically
+SRCS = condition.c dir.c errno.c file.c \
+ meminfo.c once.c fsaccess.c \
+ stdtime.c thread.c time.c @ISC_PK11_API_C@
+
+SUBDIRS = include
+TARGETS = ${OBJS}
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/win32/app.c b/lib/isc/win32/app.c
new file mode 100644
index 0000000..35274a2
--- /dev/null
+++ b/lib/isc/win32/app.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <process.h>
+
+#include <isc/app.h>
+#include <isc/condition.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/event.h>
+#include <isc/platform.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/util.h>
+#include <isc/thread.h>
+
+/*%
+ * For BIND9 internal applications built with threads, we use a single app
+ * context and let multiple worker, I/O, timer threads do actual jobs.
+ */
+
+static isc_thread_t blockedthread;
+
+/*%
+ * The following are intended for internal use (indicated by "isc__"
+ * prefix) but are not declared as static, allowing direct access from
+ * unit tests etc.
+ */
+isc_result_t isc__app_start(void);
+isc_result_t isc__app_ctxstart(isc_appctx_t *ctx);
+isc_result_t isc__app_onrun(isc_mem_t *mctx, isc_task_t *task,
+ isc_taskaction_t action, void *arg);
+isc_result_t isc__app_ctxrun(isc_appctx_t *ctx);
+isc_result_t isc__app_run(void);
+isc_result_t isc__app_ctxshutdown(isc_appctx_t *ctx);
+isc_result_t isc__app_shutdown(void);
+isc_result_t isc__app_reload(void);
+isc_result_t isc__app_ctxsuspend(isc_appctx_t *ctx);
+void isc__app_ctxfinish(isc_appctx_t *ctx);
+void isc__app_finish(void);
+void isc__app_block(void);
+void isc__app_unblock(void);
+isc_result_t isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp);
+void isc__appctx_destroy(isc_appctx_t **ctxp);
+void isc__appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr);
+void isc__appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr);
+void isc__appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr);
+isc_result_t isc__app_ctxonrun(isc_appctx_t *ctx, isc_mem_t *mctx,
+ isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+
+/*
+ * The application context of this module. This implementation actually
+ * doesn't use it. (This may change in the future).
+ */
+#define APPCTX_MAGIC ISC_MAGIC('A', 'p', 'c', 'x')
+#define VALID_APPCTX(c) ISC_MAGIC_VALID(c, APPCTX_MAGIC)
+
+/* Events to wait for */
+
+#define NUM_EVENTS 2
+
+enum {
+ RELOAD_EVENT,
+ SHUTDOWN_EVENT
+};
+
+typedef struct isc__appctx {
+ isc_appctx_t common;
+ isc_mem_t *mctx;
+ isc_eventlist_t on_run;
+ isc_mutex_t lock;
+ bool shutdown_requested;
+ bool running;
+ /*
+ * We assume that 'want_shutdown' can be read and written atomically.
+ */
+ bool want_shutdown;
+ /*
+ * We assume that 'want_reload' can be read and written atomically.
+ */
+ bool want_reload;
+
+ bool blocked;
+
+ HANDLE hEvents[NUM_EVENTS];
+
+ isc_taskmgr_t *taskmgr;
+ isc_socketmgr_t *socketmgr;
+ isc_timermgr_t *timermgr;
+} isc__appctx_t;
+
+static isc__appctx_t isc_g_appctx;
+
+static struct {
+ isc_appmethods_t methods;
+
+ /*%
+ * The following are defined just for avoiding unused static functions.
+ */
+ void *run, *shutdown, *start, *reload, *finish, *block, *unblock;
+} appmethods = {
+ {
+ isc__appctx_destroy,
+ isc__app_ctxstart,
+ isc__app_ctxrun,
+ isc__app_ctxsuspend,
+ isc__app_ctxshutdown,
+ isc__app_ctxfinish,
+ isc__appctx_settaskmgr,
+ isc__appctx_setsocketmgr,
+ isc__appctx_settimermgr,
+ isc__app_ctxonrun
+ },
+ (void *)isc__app_run,
+ (void *)isc__app_shutdown,
+ (void *)isc__app_start,
+ (void *)isc__app_reload,
+ (void *)isc__app_finish,
+ (void *)isc__app_block,
+ (void *)isc__app_unblock
+};
+
+/*
+ * We need to remember which thread is the main thread...
+ */
+static isc_thread_t main_thread;
+
+isc_result_t
+isc__app_ctxstart(isc_appctx_t *ctx0) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+ isc_result_t result;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ /*
+ * Start an ISC library application.
+ */
+
+ main_thread = GetCurrentThread();
+
+ result = isc_mutex_init(&ctx->lock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ ctx->shutdown_requested = false;
+ ctx->running = false;
+ ctx->want_shutdown = false;
+ ctx->want_reload = false;
+ ctx->blocked = false;
+
+ /* Create the reload event in a non-signaled state */
+ ctx->hEvents[RELOAD_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ /* Create the shutdown event in a non-signaled state */
+ ctx->hEvents[SHUTDOWN_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ ISC_LIST_INIT(ctx->on_run);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__app_start(void) {
+ isc_g_appctx.common.impmagic = APPCTX_MAGIC;
+ isc_g_appctx.common.magic = ISCAPI_APPCTX_MAGIC;
+ isc_g_appctx.common.methods = &appmethods.methods;
+ isc_g_appctx.mctx = NULL;
+ /* The remaining members will be initialized in ctxstart() */
+
+ return (isc__app_ctxstart((isc_appctx_t *)&isc_g_appctx));
+}
+
+isc_result_t
+isc__app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
+ void *arg)
+{
+ return (isc__app_ctxonrun((isc_appctx_t *)&isc_g_appctx, mctx,
+ task, action, arg));
+}
+
+isc_result_t
+isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task,
+ isc_taskaction_t action, void *arg)
+{
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+ isc_event_t *event;
+ isc_task_t *cloned_task = NULL;
+ isc_result_t result;
+
+ LOCK(&ctx->lock);
+
+ if (ctx->running) {
+ result = ISC_R_ALREADYRUNNING;
+ goto unlock;
+ }
+
+ /*
+ * Note that we store the task to which we're going to send the event
+ * in the event's "sender" field.
+ */
+ isc_task_attach(task, &cloned_task);
+ event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN,
+ action, arg, sizeof(*event));
+ if (event == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto unlock;
+ }
+
+ ISC_LINK_INIT(event, ev_link);
+ ISC_LIST_APPEND(ctx->on_run, event, ev_link);
+
+ result = ISC_R_SUCCESS;
+
+ unlock:
+ UNLOCK(&ctx->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc__app_ctxrun(isc_appctx_t *ctx0) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+ isc_event_t *event, *next_event;
+ isc_task_t *task;
+ HANDLE *pHandles = NULL;
+ DWORD dwWaitResult;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ REQUIRE(main_thread == GetCurrentThread());
+
+ LOCK(&ctx->lock);
+
+ if (!ctx->running) {
+ ctx->running = true;
+
+ /*
+ * Post any on-run events (in FIFO order).
+ */
+ for (event = ISC_LIST_HEAD(ctx->on_run);
+ event != NULL;
+ event = next_event) {
+ next_event = ISC_LIST_NEXT(event, ev_link);
+ ISC_LIST_UNLINK(ctx->on_run, event, ev_link);
+ task = event->ev_sender;
+ event->ev_sender = NULL;
+ isc_task_sendanddetach(&task, &event);
+ }
+
+ }
+
+ UNLOCK(&ctx->lock);
+
+ /*
+ * There is no danger if isc_app_shutdown() is called before we wait
+ * for events.
+ */
+
+ while (!ctx->want_shutdown) {
+ dwWaitResult = WaitForMultipleObjects(NUM_EVENTS, ctx->hEvents,
+ FALSE, INFINITE);
+
+ /* See why we returned */
+
+ if (WaitSucceeded(dwWaitResult, NUM_EVENTS)) {
+ /*
+ * The return was due to one of the events
+ * being signaled
+ */
+ switch (WaitSucceededIndex(dwWaitResult)) {
+ case RELOAD_EVENT:
+ ctx->want_reload = true;
+ break;
+
+ case SHUTDOWN_EVENT:
+ ctx->want_shutdown = true;
+ break;
+ }
+ }
+
+ if (ctx->want_reload) {
+ ctx->want_reload = false;
+ return (ISC_R_RELOAD);
+ }
+
+ if (ctx->want_shutdown && ctx->blocked)
+ exit(-1);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__app_run(void) {
+ return (isc__app_ctxrun((isc_appctx_t *)&isc_g_appctx));
+}
+
+isc_result_t
+isc__app_ctxshutdown(isc_appctx_t *ctx0) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+ bool want_kill = true;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ LOCK(&ctx->lock);
+
+ REQUIRE(ctx->running);
+
+ if (ctx->shutdown_requested)
+ want_kill = false; /* We're only signaling once */
+ else
+ ctx->shutdown_requested = true;
+
+ UNLOCK(&ctx->lock);
+
+ if (want_kill)
+ SetEvent(ctx->hEvents[SHUTDOWN_EVENT]);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__app_shutdown(void) {
+ return (isc__app_ctxshutdown((isc_appctx_t *)&isc_g_appctx));
+}
+
+isc_result_t
+isc__app_ctxsuspend(isc_appctx_t *ctx0) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+ bool want_kill = true;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ LOCK(&ctx->lock);
+
+ REQUIRE(ctx->running);
+
+ /*
+ * Don't send the reload signal if we're shutting down.
+ */
+ if (ctx->shutdown_requested)
+ want_kill = false;
+
+ UNLOCK(&ctx->lock);
+
+ if (want_kill)
+ SetEvent(ctx->hEvents[RELOAD_EVENT]);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__app_reload(void) {
+ return (isc__app_ctxsuspend((isc_appctx_t *)&isc_g_appctx));
+}
+
+void
+isc__app_ctxfinish(isc_appctx_t *ctx0) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ DESTROYLOCK(&ctx->lock);
+}
+
+void
+isc__app_finish(void) {
+ isc__app_ctxfinish((isc_appctx_t *)&isc_g_appctx);
+}
+
+void
+isc__app_block(void) {
+ REQUIRE(isc_g_appctx.running);
+ REQUIRE(!isc_g_appctx.blocked);
+
+ isc_g_appctx.blocked = true;
+ blockedthread = GetCurrentThread();
+}
+
+void
+isc__app_unblock(void) {
+ REQUIRE(isc_g_appctx.running);
+ REQUIRE(isc_g_appctx.blocked);
+
+ isc_g_appctx.blocked = false;
+ REQUIRE(blockedthread == GetCurrentThread());
+}
+
+isc_result_t
+isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) {
+ isc__appctx_t *ctx;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(ctxp != NULL && *ctxp == NULL);
+
+ ctx = isc_mem_get(mctx, sizeof(*ctx));
+ if (ctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ ctx->common.impmagic = APPCTX_MAGIC;
+ ctx->common.magic = ISCAPI_APPCTX_MAGIC;
+ ctx->common.methods = &appmethods.methods;
+
+ ctx->mctx = NULL;
+ isc_mem_attach(mctx, &ctx->mctx);
+
+ ctx->taskmgr = NULL;
+ ctx->socketmgr = NULL;
+ ctx->timermgr = NULL;
+
+ *ctxp = (isc_appctx_t *)ctx;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc__appctx_destroy(isc_appctx_t **ctxp) {
+ isc__appctx_t *ctx;
+
+ REQUIRE(ctxp != NULL);
+ ctx = (isc__appctx_t *)*ctxp;
+ REQUIRE(VALID_APPCTX(ctx));
+
+ isc_mem_putanddetach(&ctx->mctx, ctx, sizeof(*ctx));
+
+ *ctxp = NULL;
+}
+
+void
+isc__appctx_settaskmgr(isc_appctx_t *ctx0, isc_taskmgr_t *taskmgr) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ ctx->taskmgr = taskmgr;
+}
+
+void
+isc__appctx_setsocketmgr(isc_appctx_t *ctx0, isc_socketmgr_t *socketmgr) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ ctx->socketmgr = socketmgr;
+}
+
+void
+isc__appctx_settimermgr(isc_appctx_t *ctx0, isc_timermgr_t *timermgr) {
+ isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
+
+ REQUIRE(VALID_APPCTX(ctx));
+
+ ctx->timermgr = timermgr;
+}
+
+isc_result_t
+isc__app_register(void) {
+ return (isc_app_register(isc__appctx_create));
+}
+
+#include "../app_api.c"
diff --git a/lib/isc/win32/condition.c b/lib/isc/win32/condition.c
new file mode 100644
index 0000000..7887508
--- /dev/null
+++ b/lib/isc/win32/condition.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/condition.h>
+#include <isc/assertions.h>
+#include <isc/util.h>
+#include <isc/thread.h>
+#include <isc/time.h>
+
+#define LSIGNAL 0
+#define LBROADCAST 1
+
+isc_result_t
+isc_condition_init(isc_condition_t *cond) {
+ HANDLE h;
+
+ REQUIRE(cond != NULL);
+
+ cond->waiters = 0;
+ /*
+ * This handle is shared across all threads
+ */
+ h = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (h == NULL) {
+ /* XXX */
+ return (ISC_R_UNEXPECTED);
+ }
+ cond->events[LSIGNAL] = h;
+
+ /*
+ * The threadlist will hold the actual events needed
+ * for the wait condition
+ */
+ ISC_LIST_INIT(cond->threadlist);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Add the thread to the threadlist along with the required events
+ */
+static isc_result_t
+register_thread(unsigned long thrd, isc_condition_t *gblcond,
+ isc_condition_thread_t **localcond)
+{
+ HANDLE hc;
+ isc_condition_thread_t *newthread;
+
+ REQUIRE(localcond != NULL && *localcond == NULL);
+
+ newthread = malloc(sizeof(isc_condition_thread_t));
+ if (newthread == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * Create the thread-specific handle
+ */
+ hc = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (hc == NULL) {
+ free(newthread);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ /*
+ * Add the thread ID and handles to list of threads for broadcast
+ */
+ newthread->handle[LSIGNAL] = gblcond->events[LSIGNAL];
+ newthread->handle[LBROADCAST] = hc;
+ newthread->th = thrd;
+
+ /*
+ * The thread is holding the manager lock so this is safe
+ */
+ ISC_LINK_INIT(newthread, link);
+ ISC_LIST_APPEND(gblcond->threadlist, newthread, link);
+ *localcond = newthread;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+find_thread_condition(unsigned long thrd, isc_condition_t *cond,
+ isc_condition_thread_t **threadcondp)
+{
+ isc_condition_thread_t *threadcond;
+
+ REQUIRE(threadcondp != NULL && *threadcondp == NULL);
+
+ /*
+ * Look for the thread ID.
+ */
+ for (threadcond = ISC_LIST_HEAD(cond->threadlist);
+ threadcond != NULL;
+ threadcond = ISC_LIST_NEXT(threadcond, link)) {
+
+ if (threadcond->th == thrd) {
+ *threadcondp = threadcond;
+ return (ISC_R_SUCCESS);
+ }
+ }
+
+ /*
+ * Not found, so add it.
+ */
+ return (register_thread(thrd, cond, threadcondp));
+}
+
+isc_result_t
+isc_condition_signal(isc_condition_t *cond) {
+
+ /*
+ * Unlike pthreads, the caller MUST hold the lock associated with
+ * the condition variable when calling us.
+ */
+ REQUIRE(cond != NULL);
+
+ if (!SetEvent(cond->events[LSIGNAL])) {
+ /* XXX */
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_condition_broadcast(isc_condition_t *cond) {
+
+ isc_condition_thread_t *threadcond;
+ bool failed = false;
+
+ /*
+ * Unlike pthreads, the caller MUST hold the lock associated with
+ * the condition variable when calling us.
+ */
+ REQUIRE(cond != NULL);
+
+ /*
+ * Notify every thread registered for this
+ */
+ for (threadcond = ISC_LIST_HEAD(cond->threadlist);
+ threadcond != NULL;
+ threadcond = ISC_LIST_NEXT(threadcond, link)) {
+
+ if (!SetEvent(threadcond->handle[LBROADCAST]))
+ failed = true;
+ }
+
+ if (failed)
+ return (ISC_R_UNEXPECTED);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_condition_destroy(isc_condition_t *cond) {
+
+ isc_condition_thread_t *next, *threadcond;
+
+ REQUIRE(cond != NULL);
+ REQUIRE(cond->waiters == 0);
+
+ (void)CloseHandle(cond->events[LSIGNAL]);
+
+ /*
+ * Delete the threadlist
+ */
+ threadcond = ISC_LIST_HEAD(cond->threadlist);
+
+ while (threadcond != NULL) {
+ next = ISC_LIST_NEXT(threadcond, link);
+ DEQUEUE(cond->threadlist, threadcond, link);
+ (void) CloseHandle(threadcond->handle[LBROADCAST]);
+ free(threadcond);
+ threadcond = next;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This is always called when the mutex (lock) is held, but because
+ * we are waiting we need to release it and reacquire it as soon as the wait
+ * is over. This allows other threads to make use of the object guarded
+ * by the mutex but it should never try to delete it as long as the
+ * number of waiters > 0. Always reacquire the mutex regardless of the
+ * result of the wait. Note that EnterCriticalSection will wait to acquire
+ * the mutex.
+ */
+static isc_result_t
+wait(isc_condition_t *cond, isc_mutex_t *mutex, DWORD milliseconds) {
+ DWORD result;
+ isc_result_t tresult;
+ isc_condition_thread_t *threadcond = NULL;
+
+ /*
+ * Get the thread events needed for the wait
+ */
+ tresult = find_thread_condition(isc_thread_self(), cond, &threadcond);
+ if (tresult != ISC_R_SUCCESS)
+ return (tresult);
+
+ cond->waiters++;
+ LeaveCriticalSection(mutex);
+ result = WaitForMultipleObjects(2, threadcond->handle, FALSE,
+ milliseconds);
+ EnterCriticalSection(mutex);
+ cond->waiters--;
+ if (result == WAIT_FAILED) {
+ /* XXX */
+ return (ISC_R_UNEXPECTED);
+ }
+ if (result == WAIT_TIMEOUT)
+ return (ISC_R_TIMEDOUT);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_condition_wait(isc_condition_t *cond, isc_mutex_t *mutex) {
+ return (wait(cond, mutex, INFINITE));
+}
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *cond, isc_mutex_t *mutex,
+ isc_time_t *t) {
+ DWORD milliseconds;
+ uint64_t microseconds;
+ isc_time_t now;
+
+ if (isc_time_now(&now) != ISC_R_SUCCESS) {
+ /* XXX */
+ return (ISC_R_UNEXPECTED);
+ }
+
+ microseconds = isc_time_microdiff(t, &now);
+ if (microseconds > 0xFFFFFFFFi64 * 1000)
+ milliseconds = 0xFFFFFFFF;
+ else
+ milliseconds = (DWORD)(microseconds / 1000);
+
+ return (wait(cond, mutex, milliseconds));
+}
diff --git a/lib/isc/win32/dir.c b/lib/isc/win32/dir.c
new file mode 100644
index 0000000..5db2c23
--- /dev/null
+++ b/lib/isc/win32/dir.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <direct.h>
+#include <process.h>
+#include <io.h>
+
+#include <sys/stat.h>
+
+#include <isc/assertions.h>
+#include <isc/dir.h>
+#include <isc/magic.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+#define ISC_DIR_MAGIC ISC_MAGIC('D', 'I', 'R', '*')
+#define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC)
+
+static isc_result_t
+start_directory(isc_dir_t *p);
+
+void
+isc_dir_init(isc_dir_t *dir) {
+ REQUIRE(dir != NULL);
+
+ dir->dirname[0] = '\0';
+
+ dir->entry.name[0] = '\0';
+ dir->entry.length = 0;
+ memset(&(dir->entry.find_data), 0, sizeof(dir->entry.find_data));
+
+ dir->entry_filled = false;
+ dir->search_handle = INVALID_HANDLE_VALUE;
+
+ dir->magic = ISC_DIR_MAGIC;
+}
+
+/*
+ * Allocate workspace and open directory stream. If either one fails,
+ * NULL will be returned.
+ */
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname) {
+ char *p;
+ isc_result_t result;
+
+ REQUIRE(dirname != NULL);
+ REQUIRE(VALID_DIR(dir) && dir->search_handle == INVALID_HANDLE_VALUE);
+
+ /*
+ * Copy directory name. Need to have enough space for the name,
+ * a possible path separator, the wildcard, and the final NUL.
+ */
+ if (strlen(dirname) + 3 > sizeof(dir->dirname))
+ /* XXXDCL ? */
+ return (ISC_R_NOSPACE);
+ strlcpy(dir->dirname, dirname, sizeof(dir->dirname));
+
+ /*
+ * Append path separator, if needed, and "*".
+ */
+ p = dir->dirname + strlen(dir->dirname);
+ if (dir->dirname < p && *(p - 1) != '\\' && *(p - 1) != ':')
+ *p++ = '\\';
+ *p++ = '*';
+ *p = '\0';
+
+ /*
+ * Open stream.
+ */
+ result = start_directory(dir);
+
+ return (result);
+}
+
+/*
+ * Return previously retrieved file or get next one. Unix's dirent has
+ * separate open and read functions, but the Win32 and DOS interfaces open
+ * the dir stream and reads the first file in one operation.
+ */
+isc_result_t
+isc_dir_read(isc_dir_t *dir) {
+ REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE);
+
+ if (dir->entry_filled)
+ /*
+ * start_directory() already filled in the first entry.
+ */
+ dir->entry_filled = false;
+
+ else {
+ /*
+ * Fetch next file in directory.
+ */
+ if (FindNextFile(dir->search_handle,
+ &dir->entry.find_data) == FALSE)
+ /*
+ * Either the last file has been processed or
+ * an error has occurred. The former is not
+ * really an error, but the latter is.
+ */
+ if (GetLastError() == ERROR_NO_MORE_FILES)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_UNEXPECTED);
+ }
+
+ /*
+ * Make sure that the space for the name is long enough.
+ */
+ strlcpy(dir->entry.name, dir->entry.find_data.cFileName,
+ sizeof(dir->entry.name));
+ dir->entry.length = strlen(dir->entry.name);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Close directory stream.
+ */
+void
+isc_dir_close(isc_dir_t *dir) {
+ REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE);
+
+ FindClose(dir->search_handle);
+ dir->search_handle = INVALID_HANDLE_VALUE;
+}
+
+/*
+ * Reposition directory stream at start.
+ */
+isc_result_t
+isc_dir_reset(isc_dir_t *dir) {
+ isc_result_t result;
+
+ REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE);
+ REQUIRE(dir->dirname != NULL);
+
+ /*
+ * NT cannot reposition the seek pointer to the beginning of the
+ * the directory stream, but rather the directory needs to be
+ * closed and reopened. The latter might fail.
+ */
+
+ isc_dir_close(dir);
+
+ result = start_directory(dir);
+
+ return (result);
+}
+
+/*
+ * Initialize isc_dir_t structure with new directory. The function
+ * returns 0 on failure and nonzero on success.
+ *
+ * Note:
+ * - Be sure to close previous stream before opening new one
+ */
+static isc_result_t
+start_directory(isc_dir_t *dir)
+{
+ REQUIRE(VALID_DIR(dir));
+ REQUIRE(dir->search_handle == INVALID_HANDLE_VALUE);
+
+ dir->entry_filled = false;
+
+ /*
+ * Open stream and retrieve first file.
+ */
+ dir->search_handle = FindFirstFile(dir->dirname,
+ &dir->entry.find_data);
+
+ if (dir->search_handle == INVALID_HANDLE_VALUE) {
+ /*
+ * Something went wrong but we don't know what. GetLastError()
+ * could give us more information about the error, but the
+ * MSDN documentation is frustratingly thin about what
+ * possible errors could have resulted. (Score one for
+ * the Unix manual pages.) So there is just this lame error
+ * instead of being able to differentiate ISC_R_NOTFOUND
+ * from ISC_R_UNEXPECTED.
+ */
+ return (ISC_R_FAILURE);
+ }
+
+ /*
+ * Make sure that the space for the name is long enough.
+ */
+ INSIST(sizeof(dir->entry.name) >
+ strlen(dir->entry.find_data.cFileName));
+
+ /*
+ * Fill in the data for the first entry of the directory.
+ */
+ strlcpy(dir->entry.name, dir->entry.find_data.cFileName,
+ sizeof(dir->entry.name));
+ dir->entry.length = strlen(dir->entry.name);
+
+ dir->entry_filled = true;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chdir(const char *dirname) {
+ /*
+ * Change the current directory to 'dirname'.
+ */
+
+ REQUIRE(dirname != NULL);
+
+ if (chdir(dirname) < 0)
+ return (isc__errno2result(errno));
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chroot(const char *dirname) {
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+isc_result_t
+isc_dir_createunique(char *templet) {
+ isc_result_t result;
+ char *x;
+ char *p;
+ int i;
+ int pid;
+
+ REQUIRE(templet != NULL);
+
+ /*
+ * mkdtemp is not portable, so this emulates it.
+ */
+
+ pid = getpid();
+
+ /*
+ * Replace trailing Xs with the process-id, zero-filled.
+ */
+ for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet;
+ x--, pid /= 10)
+ *x = pid % 10 + '0';
+
+ x++; /* Set x to start of ex-Xs. */
+
+ do {
+ i = mkdir(templet);
+ if (i == 0)
+ i = chmod(templet, 0700);
+
+ if (i == 0 || errno != EEXIST)
+ break;
+
+ /*
+ * The BSD algorithm.
+ */
+ p = x;
+ while (*p != '\0') {
+ if (isdigit(*p & 0xff))
+ *p = 'a';
+ else if (*p != 'z')
+ ++*p;
+ else {
+ /*
+ * Reset character and move to next.
+ */
+ *p++ = 'a';
+ continue;
+ }
+
+ break;
+ }
+
+ if (*p == '\0') {
+ /*
+ * Tried all combinations. errno should already
+ * be EEXIST, but ensure it is anyway for
+ * isc__errno2result().
+ */
+ errno = EEXIST;
+ break;
+ }
+ } while (1);
+
+ if (i == -1)
+ result = isc__errno2result(errno);
+ else
+ result = ISC_R_SUCCESS;
+
+ return (result);
+}
diff --git a/lib/isc/win32/entropy.c b/lib/isc/win32/entropy.c
new file mode 100644
index 0000000..2480c02
--- /dev/null
+++ b/lib/isc/win32/entropy.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * This is the system dependent part of the ISC entropy API.
+ */
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <windows.h>
+#include <wincrypt.h>
+
+#include <process.h>
+#include <io.h>
+#include <share.h>
+
+/*
+ * There is only one variable in the entropy data structures that is not
+ * system independent, but pulling the structure that uses it into this file
+ * ultimately means pulling several other independent structures here also to
+ * resolve their interdependencies. Thus only the problem variable's type
+ * is defined here.
+ */
+#define FILESOURCE_HANDLE_TYPE HCRYPTPROV
+
+typedef struct {
+ int dummy;
+} isc_entropyusocketsource_t;
+
+#include "../entropy.c"
+
+static unsigned int
+get_from_filesource(isc_entropysource_t *source, uint32_t desired) {
+ isc_entropy_t *ent = source->ent;
+ unsigned char buf[128];
+ HCRYPTPROV hcryptprov = source->sources.file.handle;
+ ssize_t ndesired;
+ unsigned int added;
+
+ if (source->bad)
+ return (0);
+
+ desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
+
+ added = 0;
+ while (desired > 0) {
+ ndesired = ISC_MIN(desired, sizeof(buf));
+ if (!CryptGenRandom(hcryptprov, (DWORD)ndesired, buf)) {
+ CryptReleaseContext(hcryptprov, 0);
+ source->bad = true;
+ goto out;
+ }
+
+ entropypool_adddata(ent, buf,
+ (unsigned int)ndesired,
+ (unsigned int)ndesired * 8);
+ added += (unsigned int)ndesired * 8;
+ desired -= (uint32_t)ndesired;
+ }
+
+ out:
+ return (added);
+}
+
+/*
+ * Poll each source, trying to get data from it to stuff into the entropy
+ * pool.
+ */
+static void
+fillpool(isc_entropy_t *ent, unsigned int desired, bool blocking) {
+ unsigned int added;
+ unsigned int remaining;
+ unsigned int needed;
+ unsigned int nsource;
+ isc_entropysource_t *source;
+ isc_entropysource_t *firstsource;
+
+ REQUIRE(VALID_ENTROPY(ent));
+
+ needed = desired;
+
+ /*
+ * This logic is a little strange, so an explanation is in order.
+ *
+ * If needed is 0, it means we are being asked to "fill to whatever
+ * we think is best." This means that if we have at least a
+ * partially full pool (say, > 1/4th of the pool) we probably don't
+ * need to add anything.
+ *
+ * Also, we will check to see if the "pseudo" count is too high.
+ * If it is, try to mix in better data. Too high is currently
+ * defined as 1/4th of the pool.
+ *
+ * Next, if we are asked to add a specific bit of entropy, make
+ * certain that we will do so. Clamp how much we try to add to
+ * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
+ *
+ * Note that if we are in a blocking mode, we will only try to
+ * get as much data as we need, not as much as we might want
+ * to build up.
+ */
+ if (needed == 0) {
+ REQUIRE(!blocking);
+
+ if ((ent->pool.entropy >= RND_POOLBITS / 4)
+ && (ent->pool.pseudo <= RND_POOLBITS / 4))
+ return;
+
+ needed = THRESHOLD_BITS * 4;
+ } else {
+ needed = ISC_MAX(needed, THRESHOLD_BITS);
+ needed = ISC_MIN(needed, RND_POOLBITS);
+ }
+
+ /*
+ * In any case, clamp how much we need to how much we can add.
+ */
+ needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
+
+ /*
+ * But wait! If we're not yet initialized, we need at least
+ * THRESHOLD_BITS
+ * of randomness.
+ */
+ if (ent->initialized < THRESHOLD_BITS)
+ needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
+
+ /*
+ * Poll each file source to see if we can read anything useful from
+ * it. XXXMLG When where are multiple sources, we should keep a
+ * record of which one we last used so we can start from it (or the
+ * next one) to avoid letting some sources build up entropy while
+ * others are always drained.
+ */
+
+ added = 0;
+ remaining = needed;
+ if (ent->nextsource == NULL) {
+ ent->nextsource = ISC_LIST_HEAD(ent->sources);
+ if (ent->nextsource == NULL)
+ return;
+ }
+ source = ent->nextsource;
+ /*
+ * Remember the first source so we can break if we have looped back to
+ * the beginning and still have nothing
+ */
+ firstsource = source;
+ again_file:
+ for (nsource = 0; nsource < ent->nsources; nsource++) {
+ unsigned int got;
+
+ if (remaining == 0)
+ break;
+
+ got = 0;
+
+ if (source->type == ENTROPY_SOURCETYPE_FILE)
+ got = get_from_filesource(source, remaining);
+
+ added += got;
+
+ remaining -= ISC_MIN(remaining, got);
+
+ source = ISC_LIST_NEXT(source, link);
+ if (source == NULL)
+ source = ISC_LIST_HEAD(ent->sources);
+ }
+ ent->nextsource = source;
+
+ /*
+ * Go again only if there's been progress and we've not
+ * gone back to the beginning
+ */
+ if (!(ent->nextsource == firstsource && added == 0)) {
+ if (blocking && remaining != 0) {
+ goto again_file;
+ }
+ }
+
+ /*
+ * Here, if there are bits remaining to be had and we can block,
+ * check to see if we have a callback source. If so, call them.
+ */
+ source = ISC_LIST_HEAD(ent->sources);
+ while ((remaining != 0) && (source != NULL)) {
+ unsigned int got;
+
+ got = 0;
+
+ if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
+ got = get_from_callback(source, remaining, blocking);
+
+ added += got;
+ remaining -= ISC_MIN(remaining, got);
+
+ if (added >= needed)
+ break;
+
+ source = ISC_LIST_NEXT(source, link);
+ }
+
+ /*
+ * Mark as initialized if we've added enough data.
+ */
+ if (ent->initialized < THRESHOLD_BITS)
+ ent->initialized += added;
+}
+
+
+
+/*
+ * Requires "ent" be locked.
+ */
+static void
+destroyfilesource(isc_entropyfilesource_t *source) {
+ CryptReleaseContext(source->handle, 0);
+}
+
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source) {
+ UNUSED(source);
+}
+
+
+isc_result_t
+isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
+ isc_result_t ret;
+ isc_entropysource_t *source;
+ HCRYPTPROV hcryptprov;
+ BOOL err;
+
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(fname != NULL);
+
+ LOCK(&ent->lock);
+
+ source = NULL;
+
+ /*
+ * The first time we just try to acquire the context
+ */
+ err = CryptAcquireContext(&hcryptprov, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT);
+ if (!err){
+ (void)GetLastError();
+ ret = ISC_R_IOERROR;
+ goto errout;
+ }
+
+ source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+ if (source == NULL) {
+ ret = ISC_R_NOMEMORY;
+ goto closecontext;
+ }
+
+ /*
+ * From here down, no failures can occur.
+ */
+ source->magic = SOURCE_MAGIC;
+ source->type = ENTROPY_SOURCETYPE_FILE;
+ source->ent = ent;
+ source->total = 0;
+ source->bad = false;
+ memset(source->name, 0, sizeof(source->name));
+ ISC_LINK_INIT(source, link);
+ source->sources.file.handle = hcryptprov;
+
+ /*
+ * Hook it into the entropy system.
+ */
+ ISC_LIST_APPEND(ent->sources, source, link);
+ ent->nsources++;
+
+ UNLOCK(&ent->lock);
+ return (ISC_R_SUCCESS);
+
+ closecontext:
+ CryptReleaseContext(hcryptprov, 0);
+
+ errout:
+ if (source != NULL)
+ isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
+
+ UNLOCK(&ent->lock);
+
+ return (ret);
+}
diff --git a/lib/isc/win32/errno.c b/lib/isc/win32/errno.c
new file mode 100644
index 0000000..74ebf0c
--- /dev/null
+++ b/lib/isc/win32/errno.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include "errno2result.h"
+
+isc_result_t
+isc_errno_toresult(int err) {
+ return (isc__errno2resultx(err, false, 0, 0));
+}
diff --git a/lib/isc/win32/errno2result.c b/lib/isc/win32/errno2result.c
new file mode 100644
index 0000000..83dbb4e
--- /dev/null
+++ b/lib/isc/win32/errno2result.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <winsock2.h>
+#include "errno2result.h"
+#include <isc/result.h>
+#include <isc/strerror.h>
+#include <isc/util.h>
+
+/*
+ * Convert a POSIX errno value into an isc_result_t. The
+ * list of supported errno values is not complete; new users
+ * of this function should add any expected errors that are
+ * not already there.
+ */
+isc_result_t
+isc__errno2resultx(int posixerrno, bool dolog,
+ const char *file, int line)
+{
+ char strbuf[ISC_STRERRORSIZE];
+
+ switch (posixerrno) {
+ case ENOTDIR:
+ case WSAELOOP:
+ case WSAEINVAL:
+ case EINVAL: /* XXX sometimes this is not for files */
+ case ENAMETOOLONG:
+ case WSAENAMETOOLONG:
+ case EBADF:
+ case WSAEBADF:
+ return (ISC_R_INVALIDFILE);
+ case ENOENT:
+ return (ISC_R_FILENOTFOUND);
+ case EACCES:
+ case WSAEACCES:
+ case EPERM:
+ return (ISC_R_NOPERM);
+ case EEXIST:
+ return (ISC_R_FILEEXISTS);
+ case EIO:
+ return (ISC_R_IOERROR);
+ case ENOMEM:
+ return (ISC_R_NOMEMORY);
+#ifdef EOVERFLOW
+ case EOVERFLOW:
+ return (ISC_R_RANGE);
+#endif
+ case ENFILE:
+ case EMFILE:
+ case WSAEMFILE:
+ return (ISC_R_TOOMANYOPENFILES);
+ case ERROR_CANCELLED:
+ return (ISC_R_CANCELED);
+ case ERROR_CONNECTION_REFUSED:
+ case WSAECONNREFUSED:
+ return (ISC_R_CONNREFUSED);
+ case WSAENOTCONN:
+ case ERROR_CONNECTION_INVALID:
+ return (ISC_R_NOTCONNECTED);
+ case ERROR_HOST_UNREACHABLE:
+ case WSAEHOSTUNREACH:
+ return (ISC_R_HOSTUNREACH);
+ case ERROR_NETWORK_UNREACHABLE:
+ case WSAENETUNREACH:
+ return (ISC_R_NETUNREACH);
+ case ERROR_NO_NETWORK:
+ return (ISC_R_NETUNREACH);
+ case ERROR_PORT_UNREACHABLE:
+ return (ISC_R_HOSTUNREACH);
+ case ERROR_SEM_TIMEOUT:
+ return (ISC_R_TIMEDOUT);
+ case WSAECONNRESET:
+ case WSAENETRESET:
+ case WSAECONNABORTED:
+ case WSAEDISCON:
+ case ERROR_OPERATION_ABORTED:
+ case ERROR_CONNECTION_ABORTED:
+ case ERROR_REQUEST_ABORTED:
+ return (ISC_R_CONNECTIONRESET);
+ case WSAEADDRNOTAVAIL:
+ return (ISC_R_ADDRNOTAVAIL);
+ case ERROR_NETNAME_DELETED:
+ case WSAENETDOWN:
+ return (ISC_R_NETUNREACH);
+ case WSAEHOSTDOWN:
+ return (ISC_R_HOSTUNREACH);
+ case WSAENOBUFS:
+ return (ISC_R_NORESOURCES);
+ default:
+ if (dolog) {
+ isc__strerror(posixerrno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(file, line,
+ "unable to convert errno "
+ "to isc_result: %d: %s",
+ posixerrno, strbuf);
+ }
+ /*
+ * XXXDCL would be nice if perhaps this function could
+ * return the system's error string, so the caller
+ * might have something more descriptive than "unexpected
+ * error" to log with.
+ */
+ return (ISC_R_UNEXPECTED);
+ }
+}
diff --git a/lib/isc/win32/errno2result.h b/lib/isc/win32/errno2result.h
new file mode 100644
index 0000000..99752ae
--- /dev/null
+++ b/lib/isc/win32/errno2result.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef UNIX_ERRNO2RESULT_H
+#define UNIX_ERRNO2RESULT_H 1
+
+/* XXXDCL this should be moved to lib/isc/include/isc/errno2result.h. */
+
+#include <errno.h> /* Provides errno. */
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define isc__errno2result(posixerrno) \
+ isc__errno2resultx(posixerrno, true, __FILE__, __LINE__)
+
+isc_result_t
+isc__errno2resultx(int posixerrno, bool dolog,
+ const char *file, int line);
+
+ISC_LANG_ENDDECLS
+
+#endif /* UNIX_ERRNO2RESULT_H */
diff --git a/lib/isc/win32/file.c b/lib/isc/win32/file.c
new file mode 100644
index 0000000..d281ba1
--- /dev/null
+++ b/lib/isc/win32/file.c
@@ -0,0 +1,928 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#undef rename
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <io.h>
+#include <process.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/utime.h>
+
+#include <isc/file.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/result.h>
+#include <isc/sha2.h>
+#include <isc/stat.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+static const char alphnum[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+/*
+ * Emulate UNIX mkstemp, which returns an open FD to the new file
+ *
+ */
+static int
+gettemp(char *path, bool binary, int *doopen) {
+ char *start, *trv;
+ struct stat sbuf;
+ int flags = O_CREAT|O_EXCL|O_RDWR;
+
+ if (binary)
+ flags |= _O_BINARY;
+
+ trv = strrchr(path, 'X');
+ trv++;
+ /* extra X's get set to 0's */
+ while (*--trv == 'X') {
+ uint32_t which;
+
+ isc_random_get(&which);
+ *trv = alphnum[which % (sizeof(alphnum) - 1)];
+ }
+ /*
+ * check the target directory; if you have six X's and it
+ * doesn't exist this runs for a *very* long time.
+ */
+ for (start = trv + 1;; --trv) {
+ if (trv <= path)
+ break;
+ if (*trv == '\\') {
+ *trv = '\0';
+ if (stat(path, &sbuf))
+ return (0);
+ if (!S_ISDIR(sbuf.st_mode)) {
+ errno = ENOTDIR;
+ return (0);
+ }
+ *trv = '\\';
+ break;
+ }
+ }
+
+ for (;;) {
+ if (doopen) {
+ if ((*doopen =
+ open(path, flags, _S_IREAD | _S_IWRITE)) >= 0)
+ return (1);
+ if (errno != EEXIST)
+ return (0);
+ } else if (stat(path, &sbuf))
+ return (errno == ENOENT ? 1 : 0);
+
+ /* tricky little algorithm for backward compatibility */
+ for (trv = start;;) {
+ if (!*trv)
+ return (0);
+ if (*trv == 'z')
+ *trv++ = 'a';
+ else {
+ if (isdigit(*trv))
+ *trv = 'a';
+ else
+ ++*trv;
+ break;
+ }
+ }
+ }
+ /*NOTREACHED*/
+}
+
+static int
+mkstemp(char *path, bool binary) {
+ int fd;
+
+ return (gettemp(path, binary, &fd) ? fd : -1);
+}
+
+/*
+ * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
+ * it might be good to provide a mechanism that allows for the results
+ * of a previous stat() to be used again without having to do another stat,
+ * such as perl's mechanism of using "_" in place of a file name to indicate
+ * that the results of the last stat should be used. But then you get into
+ * annoying MP issues. BTW, Win32 has stat().
+ */
+static isc_result_t
+file_stats(const char *file, struct stat *stats) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(file != NULL);
+ REQUIRE(stats != NULL);
+
+ if (stat(file, stats) != 0)
+ result = isc__errno2result(errno);
+
+ return (result);
+}
+
+static isc_result_t
+fd_stats(int fd, struct stat *stats) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(stats != NULL);
+
+ if (fstat(fd, stats) != 0)
+ result = isc__errno2result(errno);
+
+ return (result);
+}
+
+isc_result_t
+isc_file_getsizefd(int fd, off_t *size) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(size != NULL);
+
+ result = fd_stats(fd, &stats);
+
+ if (result == ISC_R_SUCCESS)
+ *size = stats.st_size;
+ return (result);
+}
+
+isc_result_t
+isc_file_mode(const char *file, mode_t *modep) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(modep != NULL);
+
+ result = file_stats(file, &stats);
+ if (result == ISC_R_SUCCESS)
+ *modep = (stats.st_mode & 07777);
+ return (result);
+}
+
+/*
+ * isc_file_safemovefile is needed to be defined here to ensure that
+ * any file with the new name is renamed to a backup name and then the
+ * rename is done. If all goes well then the backup can be deleted,
+ * otherwise it gets renamed back.
+ */
+
+int
+isc_file_safemovefile(const char *oldname, const char *newname) {
+ BOOL filestatus;
+ char buf[512];
+ struct stat sbuf;
+ BOOL exists = FALSE;
+ int tmpfd;
+
+ /*
+ * Make sure we have something to do
+ */
+ if (stat(oldname, &sbuf) != 0) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /*
+ * Rename to a backup the new file if it still exists
+ */
+ if (stat(newname, &sbuf) == 0) {
+ exists = TRUE;
+ strlcpy(buf, newname, sizeof(buf));
+ strlcat(buf, ".XXXXX", sizeof(buf));
+ tmpfd = mkstemp(buf, true);
+ if (tmpfd > 0)
+ _close(tmpfd);
+ (void)DeleteFile(buf);
+ _chmod(newname, _S_IREAD | _S_IWRITE);
+
+ filestatus = MoveFile(newname, buf);
+ }
+ /* Now rename the file to the new name
+ */
+ _chmod(oldname, _S_IREAD | _S_IWRITE);
+
+ filestatus = MoveFile(oldname, newname);
+ if (filestatus == 0) {
+ /*
+ * Try to rename the backup back to the original name
+ * if the backup got created
+ */
+ if (exists == TRUE) {
+ filestatus = MoveFile(buf, newname);
+ if (filestatus == 0)
+ errno = EACCES;
+ }
+ return (-1);
+ }
+
+ /*
+ * Delete the backup file if it got created
+ */
+ if (exists == TRUE)
+ (void)DeleteFile(buf);
+ return (0);
+}
+
+isc_result_t
+isc_file_getmodtime(const char *file, isc_time_t *time) {
+ int fh;
+
+ REQUIRE(file != NULL);
+ REQUIRE(time != NULL);
+
+ if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0)
+ return (isc__errno2result(errno));
+
+ if (!GetFileTime((HANDLE) _get_osfhandle(fh),
+ NULL,
+ NULL,
+ &time->absolute))
+ {
+ close(fh);
+ errno = EINVAL;
+ return (isc__errno2result(errno));
+ }
+ close(fh);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_getsize(const char *file, off_t *size) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(file != NULL);
+ REQUIRE(size != NULL);
+
+ result = file_stats(file, &stats);
+
+ if (result == ISC_R_SUCCESS)
+ *size = stats.st_size;
+
+ return (result);
+}
+
+isc_result_t
+isc_file_settime(const char *file, isc_time_t *time) {
+ int fh;
+
+ REQUIRE(file != NULL && time != NULL);
+
+ if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0)
+ return (isc__errno2result(errno));
+
+ /*
+ * Set the date via the filedate system call and return. Failing
+ * this call implies the new file times are not supported by the
+ * underlying file system.
+ */
+ if (!SetFileTime((HANDLE) _get_osfhandle(fh),
+ NULL,
+ &time->absolute,
+ &time->absolute))
+ {
+ close(fh);
+ errno = EINVAL;
+ return (isc__errno2result(errno));
+ }
+
+ close(fh);
+ return (ISC_R_SUCCESS);
+
+}
+
+#undef TEMPLATE
+#define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */
+
+isc_result_t
+isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
+ return (isc_file_template(path, TEMPLATE, buf, buflen));
+}
+
+isc_result_t
+isc_file_template(const char *path, const char *templet, char *buf,
+ size_t buflen)
+{
+ char *s;
+
+ REQUIRE(templet != NULL);
+ REQUIRE(buf != NULL);
+
+ if (path == NULL)
+ path = "";
+
+ s = strrchr(templet, '\\');
+ if (s != NULL)
+ templet = s + 1;
+
+ s = strrchr(path, '\\');
+
+ if (s != NULL) {
+ size_t prefixlen = s - path + 1;
+ if ((prefixlen + strlen(templet) + 1) > buflen)
+ return (ISC_R_NOSPACE);
+
+ /* Copy 'prefixlen' bytes and NUL terminate. */
+ strlcpy(buf, path, ISC_MIN(prefixlen + 1, buflen));
+ strlcat(buf, templet, buflen);
+ } else {
+ if ((strlen(templet) + 1) > buflen)
+ return (ISC_R_NOSPACE);
+
+ strlcpy(buf, templet, buflen);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_renameunique(const char *file, char *templet) {
+ int fd;
+ int res = 0;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(file != NULL);
+ REQUIRE(templet != NULL);
+
+ fd = mkstemp(templet, true);
+ if (fd == -1)
+ result = isc__errno2result(errno);
+ else
+ close(fd);
+
+ if (result == ISC_R_SUCCESS) {
+ res = isc_file_safemovefile(file, templet);
+ if (res != 0) {
+ result = isc__errno2result(errno);
+ (void)unlink(templet);
+ }
+ }
+ return (result);
+}
+
+static isc_result_t
+openuniquemode(char *templet, int mode, bool binary, FILE **fp) {
+ int fd;
+ FILE *f;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(templet != NULL);
+ REQUIRE(fp != NULL && *fp == NULL);
+
+ /*
+ * Win32 does not have mkstemp. Using emulation above.
+ */
+ fd = mkstemp(templet, binary);
+
+ if (fd == -1)
+ result = isc__errno2result(errno);
+ if (result == ISC_R_SUCCESS) {
+#if 1
+ UNUSED(mode);
+#else
+ (void)fchmod(fd, mode);
+#endif
+ f = fdopen(fd, binary ? "wb+" : "w+");
+ if (f == NULL) {
+ result = isc__errno2result(errno);
+ (void)remove(templet);
+ (void)close(fd);
+ } else
+ *fp = f;
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_file_openuniqueprivate(char *templet, FILE **fp) {
+ int mode = _S_IREAD | _S_IWRITE;
+ return (openuniquemode(templet, mode, false, fp));
+}
+
+isc_result_t
+isc_file_openunique(char *templet, FILE **fp) {
+ int mode = _S_IREAD | _S_IWRITE;
+ return (openuniquemode(templet, mode, false, fp));
+}
+
+isc_result_t
+isc_file_openuniquemode(char *templet, int mode, FILE **fp) {
+ return (openuniquemode(templet, mode, false, fp));
+}
+
+isc_result_t
+isc_file_bopenuniqueprivate(char *templet, FILE **fp) {
+ int mode = _S_IREAD | _S_IWRITE;
+ return (openuniquemode(templet, mode, true, fp));
+}
+
+isc_result_t
+isc_file_bopenunique(char *templet, FILE **fp) {
+ int mode = _S_IREAD | _S_IWRITE;
+ return (openuniquemode(templet, mode, true, fp));
+}
+
+isc_result_t
+isc_file_bopenuniquemode(char *templet, int mode, FILE **fp) {
+ return (openuniquemode(templet, mode, true, fp));
+}
+
+isc_result_t
+isc_file_remove(const char *filename) {
+ int r;
+
+ REQUIRE(filename != NULL);
+
+ r = unlink(filename);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_file_rename(const char *oldname, const char *newname) {
+ int r;
+
+ REQUIRE(oldname != NULL);
+ REQUIRE(newname != NULL);
+
+ r = isc_file_safemovefile(oldname, newname);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+bool
+isc_file_exists(const char *pathname) {
+ struct stat stats;
+
+ REQUIRE(pathname != NULL);
+
+ return (file_stats(pathname, &stats) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_isplainfile(const char *filename) {
+ /*
+ * This function returns success if filename is a plain file.
+ */
+ struct stat filestat;
+ memset(&filestat,0,sizeof(struct stat));
+
+ if ((stat(filename, &filestat)) == -1)
+ return(isc__errno2result(errno));
+
+ if(! S_ISREG(filestat.st_mode))
+ return(ISC_R_INVALIDFILE);
+
+ return(ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_isplainfilefd(int fd) {
+ /*
+ * This function returns success if filename is a plain file.
+ */
+ struct stat filestat;
+ memset(&filestat,0,sizeof(struct stat));
+
+ if ((fstat(fd, &filestat)) == -1)
+ return(isc__errno2result(errno));
+
+ if(! S_ISREG(filestat.st_mode))
+ return(ISC_R_INVALIDFILE);
+
+ return(ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_isdirectory(const char *filename) {
+ /*
+ * This function returns success if filename is a directory.
+ */
+ struct stat filestat;
+ memset(&filestat,0,sizeof(struct stat));
+
+ if ((stat(filename, &filestat)) == -1)
+ return(isc__errno2result(errno));
+
+ if(! S_ISDIR(filestat.st_mode))
+ return(ISC_R_INVALIDFILE);
+
+ return(ISC_R_SUCCESS);
+}
+
+
+bool
+isc_file_isabsolute(const char *filename) {
+ REQUIRE(filename != NULL);
+ /*
+ * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
+ * the UNC style file specs
+ */
+ if ((filename[0] == '\\') && (filename[1] == '\\'))
+ return (true);
+ if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\')
+ return (true);
+ if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/')
+ return (true);
+ return (false);
+}
+
+bool
+isc_file_iscurrentdir(const char *filename) {
+ REQUIRE(filename != NULL);
+ return (filename[0] == '.' && filename[1] == '\0');
+}
+
+bool
+isc_file_ischdiridempotent(const char *filename) {
+ REQUIRE(filename != NULL);
+
+ if (isc_file_isabsolute(filename))
+ return (true);
+ if (filename[0] == '\\')
+ return (true);
+ if (filename[0] == '/')
+ return (true);
+ if (isc_file_iscurrentdir(filename))
+ return (true);
+ return (false);
+}
+
+const char *
+isc_file_basename(const char *filename) {
+ char *s;
+
+ REQUIRE(filename != NULL);
+
+ s = strrchr(filename, '\\');
+ if (s == NULL)
+ return (filename);
+ return (s + 1);
+}
+
+isc_result_t
+isc_file_progname(const char *filename, char *progname, size_t namelen) {
+ const char *s;
+ const char *p;
+ size_t len;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(progname != NULL);
+
+ /*
+ * Strip the path from the name
+ */
+ s = isc_file_basename(filename);
+ if (s == NULL) {
+ return (ISC_R_NOSPACE);
+ }
+
+ /*
+ * Strip any and all suffixes
+ */
+ p = strchr(s, '.');
+ if (p == NULL) {
+ if (namelen <= strlen(s))
+ return (ISC_R_NOSPACE);
+
+ strlcpy(progname, s, namelen);
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * Copy the result to the buffer
+ */
+ len = p - s;
+ if (len >= namelen)
+ return (ISC_R_NOSPACE);
+
+ /* Copy up to 'len' bytes and NUL terminate. */
+ strlcpy(progname, s, ISC_MIN(len + 1, namelen));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
+ char *ptrname;
+ DWORD retval;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(path != NULL);
+
+ retval = GetFullPathName(filename, (DWORD) pathlen, path, &ptrname);
+
+ /* Something went wrong in getting the path */
+ if (retval == 0)
+ return (ISC_R_NOTFOUND);
+ /* Caller needs to provide a larger buffer to contain the string */
+ if (retval >= pathlen)
+ return (ISC_R_NOSPACE);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_truncate(const char *filename, isc_offset_t size) {
+ int fh;
+
+ REQUIRE(filename != NULL && size >= 0);
+
+ if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0)
+ return (isc__errno2result(errno));
+
+ if(_chsize(fh, size) != 0) {
+ close(fh);
+ return (isc__errno2result(errno));
+ }
+ close(fh);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_safecreate(const char *filename, FILE **fp) {
+ isc_result_t result;
+ int flags;
+ struct stat sb;
+ FILE *f;
+ int fd;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(fp != NULL && *fp == NULL);
+
+ result = file_stats(filename, &sb);
+ if (result == ISC_R_SUCCESS) {
+ if ((sb.st_mode & S_IFREG) == 0)
+ return (ISC_R_INVALIDFILE);
+ flags = O_WRONLY | O_TRUNC;
+ } else if (result == ISC_R_FILENOTFOUND) {
+ flags = O_WRONLY | O_CREAT | O_EXCL;
+ } else
+ return (result);
+
+ fd = open(filename, flags, S_IRUSR | S_IWUSR);
+ if (fd == -1)
+ return (isc__errno2result(errno));
+
+ f = fdopen(fd, "w");
+ if (f == NULL) {
+ result = isc__errno2result(errno);
+ close(fd);
+ return (result);
+ }
+
+ *fp = f;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_splitpath(isc_mem_t *mctx, const char *path, char **dirname,
+ char const ** basename)
+{
+ char *dir;
+ const char *file, *slash;
+ char *backslash;
+
+ slash = strrchr(path, '/');
+
+ backslash = strrchr(path, '\\');
+ if ((slash != NULL && backslash != NULL && backslash > slash) ||
+ (slash == NULL && backslash != NULL))
+ slash = backslash;
+
+ if (slash == path) {
+ file = ++slash;
+ dir = isc_mem_strdup(mctx, "/");
+ } else if (slash != NULL) {
+ file = ++slash;
+ dir = isc_mem_allocate(mctx, slash - path);
+ if (dir != NULL)
+ strlcpy(dir, path, slash - path);
+ } else {
+ file = path;
+ dir = isc_mem_strdup(mctx, ".");
+ }
+
+ if (dir == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if (*file == '\0') {
+ isc_mem_free(mctx, dir);
+ return (ISC_R_INVALIDFILE);
+ }
+
+ *dirname = dir;
+ *basename = file;
+
+ return (ISC_R_SUCCESS);
+}
+
+void *
+isc_file_mmap(void *addr, size_t len, int prot,
+ int flags, int fd, off_t offset)
+{
+ void *buf;
+ ssize_t ret;
+ off_t end;
+
+ UNUSED(addr);
+ UNUSED(prot);
+ UNUSED(flags);
+
+ end = lseek(fd, 0, SEEK_END);
+ lseek(fd, offset, SEEK_SET);
+ if (end - offset < (off_t) len)
+ len = end - offset;
+
+ buf = malloc(len);
+ if (buf == NULL)
+ return (NULL);
+
+ ret = read(fd, buf, (unsigned int) len);
+ if (ret != (ssize_t) len) {
+ free(buf);
+ buf = NULL;
+ }
+
+ return (buf);
+}
+
+int
+isc_file_munmap(void *addr, size_t len) {
+ UNUSED(len);
+ free(addr);
+ return (0);
+}
+
+#define DISALLOW "\\/:ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+isc_result_t
+isc_file_sanitize(const char *dir, const char *base, const char *ext,
+ char *path, size_t length)
+{
+ char buf[PATH_MAX], hash[ISC_SHA256_DIGESTSTRINGLENGTH];
+ size_t l = 0;
+
+ REQUIRE(base != NULL);
+ REQUIRE(path != NULL);
+
+ l = strlen(base) + 1;
+
+ /*
+ * allow room for a full sha256 hash (64 chars
+ * plus null terminator)
+ */
+ if (l < 65)
+ l = 65;
+
+ if (dir != NULL)
+ l += strlen(dir) + 1;
+ if (ext != NULL)
+ l += strlen(ext) + 1;
+
+ if (l > length || l > PATH_MAX)
+ return (ISC_R_NOSPACE);
+
+ /* Check whether the full-length SHA256 hash filename exists */
+ isc_sha256_data((const void *) base, strlen(base), hash);
+ snprintf(buf, sizeof(buf), "%s%s%s%s%s",
+ dir != NULL ? dir : "", dir != NULL ? "/" : "",
+ hash, ext != NULL ? "." : "", ext != NULL ? ext : "");
+ if (isc_file_exists(buf)) {
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+ }
+
+ /* Check for a truncated SHA256 hash filename */
+ hash[16] = '\0';
+ snprintf(buf, sizeof(buf), "%s%s%s%s%s",
+ dir != NULL ? dir : "", dir != NULL ? "/" : "",
+ hash, ext != NULL ? "." : "", ext != NULL ? ext : "");
+ if (isc_file_exists(buf)) {
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * If neither hash filename already exists, then we'll use
+ * the original base name if it has no disallowed characters,
+ * or the truncated hash name if it does.
+ */
+ if (strpbrk(base, DISALLOW) != NULL) {
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+ }
+
+ snprintf(buf, sizeof(buf), "%s%s%s%s%s",
+ dir != NULL ? dir : "", dir != NULL ? "/" : "",
+ base, ext != NULL ? "." : "", ext != NULL ? ext : "");
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Based on http://blog.aaronballman.com/2011/08/how-to-check-access-rights/
+ */
+bool
+isc_file_isdirwritable(const char *path) {
+ DWORD length = 0;
+ HANDLE hToken = NULL;
+ PSECURITY_DESCRIPTOR security = NULL;
+ bool answer = false;
+
+ if (isc_file_isdirectory(path) != ISC_R_SUCCESS) {
+ return (answer);
+ }
+
+ /*
+ * Figure out buffer size. GetFileSecurity() should not succeed.
+ */
+ if (GetFileSecurity(path, OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION,
+ NULL, 0, &length))
+ {
+ return (answer);
+ }
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ return (answer);
+ }
+
+ security = malloc(length);
+ if (security == NULL) {
+ return (answer);
+ }
+
+ /*
+ * GetFileSecurity() should succeed.
+ */
+ if (!GetFileSecurity(path, OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION,
+ security, length, &length))
+ {
+ return (answer);
+ }
+
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_IMPERSONATE |
+ TOKEN_QUERY | TOKEN_DUPLICATE |
+ STANDARD_RIGHTS_READ, &hToken))
+ {
+ HANDLE hImpersonatedToken = NULL;
+
+ if (DuplicateToken(hToken, SecurityImpersonation,
+ &hImpersonatedToken))
+ {
+ GENERIC_MAPPING mapping;
+ PRIVILEGE_SET privileges = { 0 };
+ DWORD grantedAccess = 0;
+ DWORD privilegesLength = sizeof(privileges);
+ BOOL result = FALSE;
+ DWORD genericAccessRights = GENERIC_WRITE;
+
+ mapping.GenericRead = FILE_GENERIC_READ;
+ mapping.GenericWrite = FILE_GENERIC_WRITE;
+ mapping.GenericExecute = FILE_GENERIC_EXECUTE;
+ mapping.GenericAll = FILE_ALL_ACCESS;
+
+ MapGenericMask(&genericAccessRights, &mapping);
+ if (AccessCheck(security, hImpersonatedToken,
+ genericAccessRights, &mapping,
+ &privileges, &privilegesLength,
+ &grantedAccess, &result))
+ {
+ answer = result;
+ }
+ CloseHandle(hImpersonatedToken);
+ }
+ CloseHandle(hToken);
+ }
+ free(security);
+ return (answer);
+}
diff --git a/lib/isc/win32/fsaccess.c b/lib/isc/win32/fsaccess.c
new file mode 100644
index 0000000..164985d
--- /dev/null
+++ b/lib/isc/win32/fsaccess.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * Note that Win32 does not have the concept of files having access
+ * and ownership bits. The FAT File system only has a readonly flag
+ * for everyone and that's all. NTFS uses ACL's which is a totally
+ * different concept of controlling access.
+ *
+ * This code needs to be revisited to set up proper access control for
+ * NTFS file systems. Nothing can be done for FAT file systems.
+ */
+
+#include <config.h>
+
+#include <aclapi.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <isc/file.h>
+#include <isc/stat.h>
+#include <isc/string.h>
+
+#include "errno2result.h"
+
+/*
+ * The OS-independent part of the API is in lib/isc.
+ */
+#include "../fsaccess.c"
+
+/* Store the user account name locally */
+static char username[255] = "\0";
+static DWORD namelen = 0;
+
+/*
+ * In order to set or retrieve access information, we need to obtain
+ * the File System type. These could be UNC-type shares.
+ */
+
+BOOL
+is_ntfs(const char * file) {
+
+ char drive[255];
+ char FSType[20];
+ char tmpbuf[256];
+ char *machinename;
+ char *sharename;
+ char filename[1024];
+
+ REQUIRE(filename != NULL);
+
+ if (isc_file_absolutepath(file, filename,
+ sizeof(filename)) != ISC_R_SUCCESS) {
+ return (FALSE);
+ }
+
+ /*
+ * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
+ * the UNC style file specs
+ */
+ if (isalpha(filename[0]) && filename[1] == ':' &&
+ (filename[2] == '\\' || filename[2] == '/')) {
+ /* Copy 'c:\' or 'c:/' and NUL terminate. */
+ strlcpy(drive, filename, ISC_MIN(3 + 1, sizeof(drive)));
+ } else if ((filename[0] == '\\') && (filename[1] == '\\')) {
+ /* Find the machine and share name and rebuild the UNC */
+ strlcpy(tmpbuf, filename, sizeof(tmpbuf));
+ machinename = strtok(tmpbuf, "\\");
+ sharename = strtok(NULL, "\\");
+ strlcpy(drive, "\\\\", sizeof(drive));
+ strlcat(drive, machinename, sizeof(drive));
+ strlcat(drive, "\\", sizeof(drive));
+ strlcat(drive, sharename, sizeof(drive));
+ strlcat(drive, "\\", sizeof(drive));
+
+ } else /* Not determinable */
+ return (FALSE);
+
+ GetVolumeInformation(drive, NULL, 0, NULL, 0, NULL, FSType,
+ sizeof(FSType));
+ if (strcmp(FSType, "NTFS") == 0)
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
+/*
+ * If it's not NTFS, we assume that it is FAT and proceed
+ * with almost nothing to do. Only the write flag can be set or
+ * cleared.
+ */
+isc_result_t
+FAT_fsaccess_set(const char *path, isc_fsaccess_t access) {
+ int mode;
+ isc_fsaccess_t bits;
+
+ /*
+ * Done with checking bad bits. Set mode_t.
+ */
+ mode = 0;
+
+#define SET_AND_CLEAR1(modebit) \
+ if ((access & bits) != 0) { \
+ mode |= modebit; \
+ access &= ~bits; \
+ }
+#define SET_AND_CLEAR(user, group, other) \
+ SET_AND_CLEAR1(user); \
+ bits <<= STEP; \
+ SET_AND_CLEAR1(group); \
+ bits <<= STEP; \
+ SET_AND_CLEAR1(other);
+
+ bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY;
+
+ SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH);
+
+ bits = ISC_FSACCESS_WRITE |
+ ISC_FSACCESS_CREATECHILD |
+ ISC_FSACCESS_DELETECHILD;
+
+ SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH);
+
+ INSIST(access == 0);
+
+ if (_chmod(path, mode) < 0)
+ return (isc__errno2result(errno));
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+NTFS_Access_Control(const char *filename, const char *user, int access,
+ bool isdir) {
+ SECURITY_DESCRIPTOR sd;
+ BYTE aclBuffer[1024];
+ PACL pacl=(PACL)&aclBuffer;
+ BYTE sidBuffer[100];
+ PSID psid=(PSID) &sidBuffer;
+ DWORD sidBufferSize = sizeof(sidBuffer);
+ BYTE adminSidBuffer[100];
+ PSID padminsid=(PSID) &adminSidBuffer;
+ DWORD adminSidBufferSize = sizeof(adminSidBuffer);
+ BYTE otherSidBuffer[100];
+ PSID pothersid=(PSID) &otherSidBuffer;
+ DWORD otherSidBufferSize = sizeof(otherSidBuffer);
+ char domainBuffer[100];
+ DWORD domainBufferSize = sizeof(domainBuffer);
+ SID_NAME_USE snu;
+ DWORD NTFSbits;
+ int caccess;
+
+
+ /* Initialize an ACL */
+ if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
+ return (ISC_R_NOPERM);
+ if (!InitializeAcl(pacl, sizeof(aclBuffer), ACL_REVISION))
+ return (ISC_R_NOPERM);
+ if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer,
+ &domainBufferSize, &snu))
+ return (ISC_R_NOPERM);
+ domainBufferSize = sizeof(domainBuffer);
+ if (!LookupAccountName(0, "Administrators", padminsid,
+ &adminSidBufferSize, domainBuffer, &domainBufferSize, &snu)) {
+ (void)GetLastError();
+ return (ISC_R_NOPERM);
+ }
+ domainBufferSize = sizeof(domainBuffer);
+ if (!LookupAccountName(0, "Everyone", pothersid,
+ &otherSidBufferSize, domainBuffer, &domainBufferSize, &snu)) {
+ (void)GetLastError();
+ return (ISC_R_NOPERM);
+ }
+
+ caccess = access;
+ /* Owner check */
+
+ NTFSbits = 0;
+ if (caccess & ISC_FSACCESS_READ)
+ NTFSbits |= FILE_GENERIC_READ;
+ if (caccess & ISC_FSACCESS_WRITE)
+ NTFSbits |= FILE_GENERIC_WRITE;
+ if (caccess & ISC_FSACCESS_EXECUTE)
+ NTFSbits |= FILE_GENERIC_EXECUTE;
+
+ /* For directories check the directory-specific bits */
+ if (isdir == true) {
+ if (caccess & ISC_FSACCESS_CREATECHILD)
+ NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE;
+ if (caccess & ISC_FSACCESS_DELETECHILD)
+ NTFSbits |= FILE_DELETE_CHILD;
+ if (caccess & ISC_FSACCESS_LISTDIRECTORY)
+ NTFSbits |= FILE_LIST_DIRECTORY;
+ if (caccess & ISC_FSACCESS_ACCESSCHILD)
+ NTFSbits |= FILE_TRAVERSE;
+ }
+
+ if (NTFSbits == (FILE_GENERIC_READ | FILE_GENERIC_WRITE
+ | FILE_GENERIC_EXECUTE))
+ NTFSbits |= FILE_ALL_ACCESS;
+ /*
+ * Owner and Administrator also get STANDARD_RIGHTS_ALL
+ * to ensure that they have full control
+ */
+
+ NTFSbits |= STANDARD_RIGHTS_ALL;
+
+ /* Add the ACE to the ACL */
+ if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, psid))
+ return (ISC_R_NOPERM);
+ if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, padminsid))
+ return (ISC_R_NOPERM);
+
+ /*
+ * Group is ignored since we can be in multiple groups or no group
+ * and its meaning is not clear on Win32
+ */
+
+ caccess = caccess >> STEP;
+
+ /*
+ * Other check. We translate this to be the same as Everyone
+ */
+
+ caccess = caccess >> STEP;
+
+ NTFSbits = 0;
+ if (caccess & ISC_FSACCESS_READ)
+ NTFSbits |= FILE_GENERIC_READ;
+ if (caccess & ISC_FSACCESS_WRITE)
+ NTFSbits |= FILE_GENERIC_WRITE;
+ if (caccess & ISC_FSACCESS_EXECUTE)
+ NTFSbits |= FILE_GENERIC_EXECUTE;
+
+ /* For directories check the directory-specific bits */
+ if (isdir == TRUE) {
+ if (caccess & ISC_FSACCESS_CREATECHILD)
+ NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE;
+ if (caccess & ISC_FSACCESS_DELETECHILD)
+ NTFSbits |= FILE_DELETE_CHILD;
+ if (caccess & ISC_FSACCESS_LISTDIRECTORY)
+ NTFSbits |= FILE_LIST_DIRECTORY;
+ if (caccess & ISC_FSACCESS_ACCESSCHILD)
+ NTFSbits |= FILE_TRAVERSE;
+ }
+ /* Add the ACE to the ACL */
+ if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits,
+ pothersid))
+ return (ISC_R_NOPERM);
+
+ if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE))
+ return (ISC_R_NOPERM);
+ if (!SetFileSecurity(filename, DACL_SECURITY_INFORMATION, &sd)) {
+ return (ISC_R_NOPERM);
+ }
+
+ return(ISC_R_SUCCESS);
+}
+
+isc_result_t
+NTFS_fsaccess_set(const char *path, isc_fsaccess_t access,
+ bool isdir){
+
+ /*
+ * For NTFS we first need to get the name of the account under
+ * which BIND is running
+ */
+ if (namelen == 0) {
+ namelen = sizeof(username);
+ if (GetUserName(username, &namelen) == 0)
+ return (ISC_R_FAILURE);
+ }
+ return (NTFS_Access_Control(path, username, access, isdir));
+}
+
+isc_result_t
+isc_fsaccess_set(const char *path, isc_fsaccess_t access) {
+ struct stat statb;
+ bool is_dir = false;
+ isc_result_t result;
+
+ if (stat(path, &statb) != 0)
+ return (isc__errno2result(errno));
+
+ if ((statb.st_mode & S_IFDIR) != 0)
+ is_dir = true;
+ else if ((statb.st_mode & S_IFREG) == 0)
+ return (ISC_R_INVALIDFILE);
+
+ result = check_bad_bits(access, is_dir);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Determine if this is a FAT or NTFS disk and
+ * call the appropriate function to set the permissions
+ */
+ if (is_ntfs(path))
+ return (NTFS_fsaccess_set(path, access, is_dir));
+ else
+ return (FAT_fsaccess_set(path, access));
+}
+
+isc_result_t
+isc_fsaccess_changeowner(const char *filename, const char *user) {
+ SECURITY_DESCRIPTOR psd;
+ BYTE sidBuffer[500];
+ BYTE groupBuffer[500];
+ PSID psid=(PSID) &sidBuffer;
+ DWORD sidBufferSize = sizeof(sidBuffer);
+ char domainBuffer[100];
+ DWORD domainBufferSize = sizeof(domainBuffer);
+ SID_NAME_USE snu;
+ PSID pSidGroup = (PSID) &groupBuffer;
+ DWORD groupBufferSize = sizeof(groupBuffer);
+
+
+ /*
+ * Determine if this is a FAT or NTFS disk and
+ * call the appropriate function to set the ownership
+ * FAT disks do not have ownership attributes so it's
+ * a noop.
+ */
+ if (is_ntfs(filename) == FALSE)
+ return (ISC_R_SUCCESS);
+
+ if (!InitializeSecurityDescriptor(&psd, SECURITY_DESCRIPTOR_REVISION))
+ return (ISC_R_NOPERM);
+
+ if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer,
+ &domainBufferSize, &snu))
+ return (ISC_R_NOPERM);
+
+ /* Make sure administrators can get to it */
+ domainBufferSize = sizeof(domainBuffer);
+ if (!LookupAccountName(0, "Administrators", pSidGroup,
+ &groupBufferSize, domainBuffer, &domainBufferSize, &snu))
+ return (ISC_R_NOPERM);
+
+ if (!SetSecurityDescriptorOwner(&psd, psid, FALSE))
+ return (ISC_R_NOPERM);
+
+ if (!SetSecurityDescriptorGroup(&psd, pSidGroup, FALSE))
+ return (ISC_R_NOPERM);
+
+ if (!SetFileSecurity(filename,
+ OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
+ &psd))
+ return (ISC_R_NOPERM);
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/win32/include/Makefile.in b/lib/isc/win32/include/Makefile.in
new file mode 100644
index 0000000..2cbf021
--- /dev/null
+++ b/lib/isc/win32/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc pkcs11
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/win32/include/isc/Makefile.in b/lib/isc/win32/include/isc/Makefile.in
new file mode 100644
index 0000000..a7c0243
--- /dev/null
+++ b/lib/isc/win32/include/isc/Makefile.in
@@ -0,0 +1,30 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = dir.h keyboard.h mutex.h net.h netdb.h once.h \
+ stat.h stdtime.h thread.h time.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}\isc
+
+install:: installdirs
+ for i in $(HEADERS); do \
+ $(INSTALL_DATA) $(srcdir)\$$i $(includedir)\isc || exit 1; \
+ done
diff --git a/lib/isc/win32/include/isc/atomic.h b/lib/isc/win32/include/isc/atomic.h
new file mode 100644
index 0000000..4b3d92d
--- /dev/null
+++ b/lib/isc/win32/include/isc/atomic.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <inttypes.h>
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+#ifdef ISC_PLATFORM_HAVEXADD
+static __inline int32_t
+isc_atomic_xadd(int32_t *p, int32_t val) {
+ return (int32_t) _InterlockedExchangeAdd((long *)p, (long)val);
+}
+#endif
+
+#ifdef ISC_PLATFORM_HAVEXADDQ
+static __inline int64_t
+isc_atomic_xaddq(int64_t *p, int64_t val) {
+ return (int64_t) _InterlockedExchangeAdd64((__int64 *)p,
+ (__int64) val);
+}
+#endif
+
+/*
+ * This routine atomically stores the value 'val' in 'p' (32-bit version).
+ */
+#ifdef ISC_PLATFORM_HAVEATOMICSTORE
+static __inline void
+isc_atomic_store(int32_t *p, int32_t val) {
+ (void) _InterlockedExchange((long *)p, (long)val);
+}
+#endif
+
+/*
+ * This routine atomically stores the value 'val' in 'p' (64-bit version).
+ */
+#ifdef ISC_PLATFORM_HAVEATOMICSTOREQ
+static __inline void
+isc_atomic_storeq(int64_t *p, int64_t val) {
+ (void) _InterlockedExchange64((__int64 *)p, (__int64)val);
+}
+#endif
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+#ifdef ISC_PLATFORM_HAVECMPXCHG
+static __inline int32_t
+isc_atomic_cmpxchg(int32_t *p, int32_t cmpval, int32_t val) {
+ /* beware: swap arguments */
+ return (int32_t) _InterlockedCompareExchange((long *)p,
+ (long)val,
+ (long)cmpval);
+}
+#endif
+
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/win32/include/isc/bind_registry.h b/lib/isc/win32/include/isc/bind_registry.h
new file mode 100644
index 0000000..57970be
--- /dev/null
+++ b/lib/isc/win32/include/isc/bind_registry.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_BINDREGISTRY_H
+#define ISC_BINDREGISTRY_H
+
+/*
+ * BIND makes use of the following Registry keys in various places, especially
+ * during startup and installation
+ */
+
+#define BIND_SUBKEY "Software\\ISC\\BIND"
+#define BIND_SESSION "CurrentSession"
+#define BIND_SESSION_SUBKEY "Software\\ISC\\BIND\\CurrentSession"
+#define BIND_UNINSTALL_SUBKEY \
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ISC BIND"
+
+#define EVENTLOG_APP_SUBKEY \
+ "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"
+#define BIND_MESSAGE_SUBKEY \
+ "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\named"
+#define BIND_MESSAGE_NAME "named"
+
+#define BIND_SERVICE_SUBKEY \
+ "SYSTEM\\CurrentControlSet\\Services\\named"
+
+
+#define BIND_CONFIGFILE 0
+#define BIND_DEBUGLEVEL 1
+#define BIND_QUERYLOG 2
+#define BIND_FOREGROUND 3
+#define BIND_PORT 4
+
+#endif /* ISC_BINDREGISTRY_H */
diff --git a/lib/isc/win32/include/isc/bindevt.h b/lib/isc/win32/include/isc/bindevt.h
new file mode 100644
index 0000000..d4088e8
--- /dev/null
+++ b/lib/isc/win32/include/isc/bindevt.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_BINDEVT_H
+#define ISC_BINDEVT_H 1
+
+/*
+ * This is used for the event log for both logging the messages and
+ * later on by the event viewer when looking at the events
+ */
+
+/*
+ * Values are 32 bit values layed out as follows:
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---+-+-+-----------------------+-------------------------------+
+ * |Sev|C|R| Facility | Code |
+ * +---+-+-+-----------------------+-------------------------------+
+ *
+ * where
+ *
+ * Sev - is the severity code
+ *
+ * 00 - Success
+ * 01 - Informational
+ * 10 - Warning
+ * 11 - Error
+ *
+ * C - is the Customer code flag
+ *
+ * R - is a reserved bit
+ *
+ * Facility - is the facility code
+ *
+ * Code - is the facility's status code
+ *
+ *
+ * Define the facility codes
+ */
+
+
+/*
+ * Define the severity codes
+ */
+
+
+/*
+ * MessageId: BIND_ERR_MSG
+ *
+ * MessageText:
+ *
+ * %1
+ */
+#define BIND_ERR_MSG ((DWORD)0xC0000001L)
+
+/*
+ * MessageId: BIND_WARN_MSG
+ *
+ * MessageText:
+ *
+ * %1
+ */
+#define BIND_WARN_MSG ((DWORD)0x80000002L)
+
+/*
+ * MessageId: BIND_INFO_MSG
+ *
+ * MessageText:
+ *
+ * %1
+ */
+#define BIND_INFO_MSG ((DWORD)0x40000003L)
+
+#endif /* ISC_BINDEVT_H */
diff --git a/lib/isc/win32/include/isc/condition.h b/lib/isc/win32/include/isc/condition.h
new file mode 100644
index 0000000..1f5b2d6
--- /dev/null
+++ b/lib/isc/win32/include/isc/condition.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_CONDITION_H
+#define ISC_CONDITION_H 1
+
+#include <windows.h>
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/thread.h>
+#include <isc/types.h>
+
+typedef struct isc_condition_thread isc_condition_thread_t;
+
+struct isc_condition_thread {
+ unsigned long th;
+ HANDLE handle[2];
+ ISC_LINK(isc_condition_thread_t) link;
+
+};
+
+typedef struct isc_condition {
+ HANDLE events[2];
+ unsigned int waiters;
+ ISC_LIST(isc_condition_thread_t) threadlist;
+} isc_condition_t;
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_condition_init(isc_condition_t *);
+
+isc_result_t
+isc_condition_wait(isc_condition_t *, isc_mutex_t *);
+
+isc_result_t
+isc_condition_signal(isc_condition_t *);
+
+isc_result_t
+isc_condition_broadcast(isc_condition_t *);
+
+isc_result_t
+isc_condition_destroy(isc_condition_t *);
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_CONDITION_H */
diff --git a/lib/isc/win32/include/isc/dir.h b/lib/isc/win32/include/isc/dir.h
new file mode 100644
index 0000000..7370fa6
--- /dev/null
+++ b/lib/isc/win32/include/isc/dir.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_DIR_H
+#define ISC_DIR_H 1
+
+#include <windows.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+#define ISC_DIR_NAMEMAX _MAX_FNAME
+#define ISC_DIR_PATHMAX _MAX_PATH
+
+typedef struct {
+ char name[ISC_DIR_NAMEMAX];
+ unsigned int length;
+ WIN32_FIND_DATA find_data;
+} isc_direntry_t;
+
+typedef struct {
+ unsigned int magic;
+ char dirname[ISC_DIR_PATHMAX];
+ isc_direntry_t entry;
+ bool entry_filled;
+ HANDLE search_handle;
+} isc_dir_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_dir_init(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname);
+
+isc_result_t
+isc_dir_read(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_reset(isc_dir_t *dir);
+
+void
+isc_dir_close(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_chdir(const char *dirname);
+
+isc_result_t
+isc_dir_chroot(const char *dirname);
+
+isc_result_t
+isc_dir_createunique(char *templet);
+/*
+ * Use a templet (such as from isc_file_mktemplate()) to create a uniquely
+ * named, empty directory. The templet string is modified in place.
+ * If result == ISC_R_SUCCESS, it is the name of the directory that was
+ * created.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_DIR_H */
diff --git a/lib/isc/win32/include/isc/ipv6.h b/lib/isc/win32/include/isc/ipv6.h
new file mode 100644
index 0000000..bee1bd0
--- /dev/null
+++ b/lib/isc/win32/include/isc/ipv6.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_IPV6_H
+#define ISC_IPV6_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * IPv6 definitions for systems which do not support IPv6.
+ *
+ * MP:
+ * No impact.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * N/A.
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ * Standards:
+ * RFC2553.
+ */
+
+#if _MSC_VER < 1300
+#define in6_addr in_addr6
+#endif
+
+#ifndef IN6ADDR_ANY_INIT
+#define IN6ADDR_ANY_INIT {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#define IN6ADDR_LOOPBACK_INIT {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}
+#endif
+#ifndef IN6ADDR_V4MAPPED_INIT
+#define IN6ADDR_V4MAPPED_INIT {{ 0,0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0 }}
+#endif
+
+LIBISC_EXTERNAL_DATA extern const struct in6_addr isc_in6addr_any;
+LIBISC_EXTERNAL_DATA extern const struct in6_addr isc_in6addr_loopback;
+
+/*
+ * Unspecified
+ */
+#ifndef IN6_IS_ADDR_UNSPECIFIED
+#define IN6_IS_ADDR_UNSPECIFIED(a) (\
+*((u_long *)((a)->s6_addr) ) == 0 && \
+*((u_long *)((a)->s6_addr) + 1) == 0 && \
+*((u_long *)((a)->s6_addr) + 2) == 0 && \
+*((u_long *)((a)->s6_addr) + 3) == 0 \
+)
+#endif
+
+/*
+ * Loopback
+ */
+#ifndef IN6_IS_ADDR_LOOPBACK
+#define IN6_IS_ADDR_LOOPBACK(a) (\
+*((u_long *)((a)->s6_addr) ) == 0 && \
+*((u_long *)((a)->s6_addr) + 1) == 0 && \
+*((u_long *)((a)->s6_addr) + 2) == 0 && \
+*((u_long *)((a)->s6_addr) + 3) == htonl(1) \
+)
+#endif
+
+/*
+ * IPv4 compatible
+ */
+#define IN6_IS_ADDR_V4COMPAT(a) (\
+*((u_long *)((a)->s6_addr) ) == 0 && \
+*((u_long *)((a)->s6_addr) + 1) == 0 && \
+*((u_long *)((a)->s6_addr) + 2) == 0 && \
+*((u_long *)((a)->s6_addr) + 3) != 0 && \
+*((u_long *)((a)->s6_addr) + 3) != htonl(1) \
+)
+
+/*
+ * Mapped
+ */
+#define IN6_IS_ADDR_V4MAPPED(a) (\
+*((u_long *)((a)->s6_addr) ) == 0 && \
+*((u_long *)((a)->s6_addr) + 1) == 0 && \
+*((u_long *)((a)->s6_addr) + 2) == htonl(0x0000ffff))
+
+/*
+ * Multicast
+ */
+#define IN6_IS_ADDR_MULTICAST(a) \
+ ((a)->s6_addr[0] == 0xffU)
+
+/*
+ * Unicast link / site local.
+ */
+#ifndef IN6_IS_ADDR_LINKLOCAL
+#define IN6_IS_ADDR_LINKLOCAL(a) (\
+ ((a)->s6_addr[0] == 0xfe) && \
+ (((a)->s6_addr[1] & 0xc0) == 0x80))
+#endif
+
+#ifndef IN6_IS_ADDR_SITELOCAL
+#define IN6_IS_ADDR_SITELOCAL(a) (\
+ ((a)->s6_addr[0] == 0xfe) && \
+ (((a)->s6_addr[1] & 0xc0) == 0xc0))
+#endif
+
+#endif /* ISC_IPV6_H */
diff --git a/lib/isc/win32/include/isc/keyboard.h b/lib/isc/win32/include/isc/keyboard.h
new file mode 100644
index 0000000..009523a
--- /dev/null
+++ b/lib/isc/win32/include/isc/keyboard.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_KEYBOARD_H
+#define ISC_KEYBOARD_H 1
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef struct {
+ int fd;
+ isc_result_t result;
+} isc_keyboard_t;
+
+isc_result_t
+isc_keyboard_open(isc_keyboard_t *keyboard);
+
+isc_result_t
+isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleepseconds);
+
+isc_result_t
+isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp);
+
+bool
+isc_keyboard_canceled(isc_keyboard_t *keyboard);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_KEYBOARD_H */
diff --git a/lib/isc/win32/include/isc/mutex.h b/lib/isc/win32/include/isc/mutex.h
new file mode 100644
index 0000000..6815741
--- /dev/null
+++ b/lib/isc/win32/include/isc/mutex.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_MUTEX_H
+#define ISC_MUTEX_H 1
+
+#include <isc/net.h>
+#include <windows.h>
+
+#include <isc/result.h>
+
+typedef CRITICAL_SECTION isc_mutex_t;
+
+/*
+ * This definition is here since some versions of WINBASE.H
+ * omits it for some reason.
+ */
+#if (_WIN32_WINNT < 0x0400)
+WINBASEAPI BOOL WINAPI
+TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+#endif /* _WIN32_WINNT < 0x0400 */
+
+#define isc_mutex_init(mp) \
+ (InitializeCriticalSection((mp)), ISC_R_SUCCESS)
+#define isc_mutex_lock(mp) \
+ (EnterCriticalSection((mp)), ISC_R_SUCCESS)
+#define isc_mutex_unlock(mp) \
+ (LeaveCriticalSection((mp)), ISC_R_SUCCESS)
+#define isc_mutex_trylock(mp) \
+ (TryEnterCriticalSection((mp)) ? ISC_R_SUCCESS : ISC_R_LOCKBUSY)
+#define isc_mutex_destroy(mp) \
+ (DeleteCriticalSection((mp)), ISC_R_SUCCESS)
+
+/*
+ * This is a placeholder for now since we are not keeping any mutex stats
+ */
+#define isc_mutex_stats(fp) do {} while (0)
+
+#endif /* ISC_MUTEX_H */
diff --git a/lib/isc/win32/include/isc/net.h b/lib/isc/win32/include/isc/net.h
new file mode 100644
index 0000000..9712a6a
--- /dev/null
+++ b/lib/isc/win32/include/isc/net.h
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* $Id$ */
+
+#ifndef ISC_NET_H
+#define ISC_NET_H 1
+
+/*
+ * Also define LWRES_IPV6_H to keep it from being included if liblwres is
+ * being used, or redefinition errors will occur.
+ */
+#define LWRES_IPV6_H 1
+
+
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * Basic Networking Types
+ *
+ * This module is responsible for defining the following basic networking
+ * types:
+ *
+ * struct in_addr
+ * struct in6_addr
+ * struct in6_pktinfo
+ * struct sockaddr
+ * struct sockaddr_in
+ * struct sockaddr_in6
+ * in_port_t
+ *
+ * It ensures that the AF_ and PF_ macros are defined.
+ *
+ * It declares ntoh[sl]() and hton[sl]().
+ *
+ * It declares inet_aton(), inet_ntop(), and inet_pton().
+ *
+ * It ensures that INADDR_ANY, IN6ADDR_ANY_INIT, in6addr_any, and
+ * in6addr_loopback are available.
+ *
+ * It ensures that IN_MULTICAST() is available to check for multicast
+ * addresses.
+ *
+ * MP:
+ * No impact.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * N/A.
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ * Standards:
+ * BSD Socket API
+ * RFC2553
+ */
+
+/***
+ *** Imports.
+ ***/
+#include <inttypes.h>
+
+#include <isc/platform.h>
+
+/*
+ * Because of some sort of problem in the MS header files, this cannot
+ * be simple "#include <winsock2.h>", because winsock2.h tries to include
+ * windows.h, which then generates an error out of mswsock.h. _You_
+ * figure it out.
+ */
+#ifndef _WINSOCKAPI_
+#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */
+#endif
+
+#include <winsock2.h>
+
+#include <sys/types.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#include <ws2tcpip.h>
+#include <isc/ipv6.h>
+
+/*
+ * This is here because named client, interfacemgr.c, etc. use the name as
+ * a variable
+ */
+#undef interface
+
+#ifndef INADDR_ANY
+#define INADDR_ANY 0x00000000UL
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001UL
+#endif
+
+#ifndef ISC_PLATFORM_HAVEIN6PKTINFO
+struct in6_pktinfo {
+ struct in6_addr ipi6_addr; /* src/dst IPv6 address */
+ unsigned int ipi6_ifindex; /* send/recv interface index */
+};
+#endif
+
+#if _MSC_VER < 1300
+#define in6addr_any isc_in6addr_any
+#define in6addr_loopback isc_in6addr_loopback
+#endif
+
+/*
+ * Ensure type in_port_t is defined.
+ */
+#ifdef ISC_PLATFORM_NEEDPORTT
+typedef uint16_t in_port_t;
+#endif
+
+/*
+ * If this system does not have MSG_TRUNC (as returned from recvmsg())
+ * ISC_PLATFORM_RECVOVERFLOW will be defined. This will enable the MSG_TRUNC
+ * faking code in socket.c.
+ */
+#ifndef MSG_TRUNC
+#define ISC_PLATFORM_RECVOVERFLOW
+#endif
+
+#define ISC__IPADDR(x) ((uint32_t)htonl((uint32_t)(x)))
+
+#define ISC_IPADDR_ISMULTICAST(i) \
+ (((uint32_t)(i) & ISC__IPADDR(0xf0000000)) \
+ == ISC__IPADDR(0xe0000000))
+
+#define ISC_IPADDR_ISEXPERIMENTAL(i) \
+ (((uint32_t)(i) & ISC__IPADDR(0xf0000000)) \
+ == ISC__IPADDR(0xf0000000))
+
+/*
+ * Fix the FD_SET and FD_CLR Macros to properly cast
+ */
+#undef FD_CLR
+#define FD_CLR(fd, set) do { \
+ u_int __i; \
+ for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count; __i++) { \
+ if (((fd_set FAR *)(set))->fd_array[__i] == (SOCKET) fd) { \
+ while (__i < ((fd_set FAR *)(set))->fd_count-1) { \
+ ((fd_set FAR *)(set))->fd_array[__i] = \
+ ((fd_set FAR *)(set))->fd_array[__i+1]; \
+ __i++; \
+ } \
+ ((fd_set FAR *)(set))->fd_count--; \
+ break; \
+ } \
+ } \
+} while (0)
+
+#undef FD_SET
+#define FD_SET(fd, set) do { \
+ u_int __i; \
+ for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count; __i++) { \
+ if (((fd_set FAR *)(set))->fd_array[__i] == (SOCKET)(fd)) { \
+ break; \
+ } \
+ } \
+ if (__i == ((fd_set FAR *)(set))->fd_count) { \
+ if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) { \
+ ((fd_set FAR *)(set))->fd_array[__i] = (SOCKET)(fd); \
+ ((fd_set FAR *)(set))->fd_count++; \
+ } \
+ } \
+} while (0)
+
+/*
+ * Windows Sockets errors redefined as regular Berkeley error constants.
+ * These are usually commented out in Windows NT to avoid conflicts with errno.h.
+ * Use the WSA constants instead.
+ */
+
+#include <errno.h>
+
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+#ifndef EINPROGRESS
+#define EINPROGRESS WSAEINPROGRESS
+#endif
+#ifndef EALREADY
+#define EALREADY WSAEALREADY
+#endif
+#ifndef ENOTSOCK
+#define ENOTSOCK WSAENOTSOCK
+#endif
+#ifndef EDESTADDRREQ
+#define EDESTADDRREQ WSAEDESTADDRREQ
+#endif
+#ifndef EMSGSIZE
+#define EMSGSIZE WSAEMSGSIZE
+#endif
+#ifndef EPROTOTYPE
+#define EPROTOTYPE WSAEPROTOTYPE
+#endif
+#ifndef ENOPROTOOPT
+#define ENOPROTOOPT WSAENOPROTOOPT
+#endif
+#ifndef EPROTONOSUPPORT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#endif
+#ifndef ESOCKTNOSUPPORT
+#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#endif
+#ifndef EOPNOTSUPP
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#endif
+#ifndef EPFNOSUPPORT
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#endif
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif
+#ifndef EADDRINUSE
+#define EADDRINUSE WSAEADDRINUSE
+#endif
+#ifndef EADDRNOTAVAIL
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#endif
+#ifndef ENETDOWN
+#define ENETDOWN WSAENETDOWN
+#endif
+#ifndef ENETUNREACH
+#define ENETUNREACH WSAENETUNREACH
+#endif
+#ifndef ENETRESET
+#define ENETRESET WSAENETRESET
+#endif
+#ifndef ECONNABORTED
+#define ECONNABORTED WSAECONNABORTED
+#endif
+#ifndef ECONNRESET
+#define ECONNRESET WSAECONNRESET
+#endif
+#ifndef ENOBUFS
+#define ENOBUFS WSAENOBUFS
+#endif
+#ifndef EISCONN
+#define EISCONN WSAEISCONN
+#endif
+#ifndef ENOTCONN
+#define ENOTCONN WSAENOTCONN
+#endif
+#ifndef ESHUTDOWN
+#define ESHUTDOWN WSAESHUTDOWN
+#endif
+#ifndef ETOOMANYREFS
+#define ETOOMANYREFS WSAETOOMANYREFS
+#endif
+#ifndef ETIMEDOUT
+#define ETIMEDOUT WSAETIMEDOUT
+#endif
+#ifndef ECONNREFUSED
+#define ECONNREFUSED WSAECONNREFUSED
+#endif
+#ifndef ELOOP
+#define ELOOP WSAELOOP
+#endif
+#ifndef EHOSTDOWN
+#define EHOSTDOWN WSAEHOSTDOWN
+#endif
+#ifndef EHOSTUNREACH
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#endif
+#ifndef EPROCLIM
+#define EPROCLIM WSAEPROCLIM
+#endif
+#ifndef EUSERS
+#define EUSERS WSAEUSERS
+#endif
+#ifndef EDQUOT
+#define EDQUOT WSAEDQUOT
+#endif
+#ifndef ESTALE
+#define ESTALE WSAESTALE
+#endif
+#ifndef EREMOTE
+#define EREMOTE WSAEREMOTE
+#endif
+
+
+/***
+ *** Functions.
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_net_probeipv4(void);
+/*
+ * Check if the system's kernel supports IPv4.
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS IPv4 is supported.
+ * ISC_R_NOTFOUND IPv4 is not supported.
+ * ISC_R_DISABLED IPv4 is disabled.
+ * ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probeipv6(void);
+/*
+ * Check if the system's kernel supports IPv6.
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS IPv6 is supported.
+ * ISC_R_NOTFOUND IPv6 is not supported.
+ * ISC_R_DISABLED IPv6 is disabled.
+ * ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probeunix(void);
+/*
+ * Check if UNIX domain sockets are supported.
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS
+ * ISC_R_NOTFOUND
+ */
+
+#define ISC_NET_DSCPRECVV4 0x01 /* Can receive sent DSCP value IPv4 */
+#define ISC_NET_DSCPRECVV6 0x02 /* Can receive sent DSCP value IPv6 */
+#define ISC_NET_DSCPSETV4 0x04 /* Can set DSCP on socket IPv4 */
+#define ISC_NET_DSCPSETV6 0x08 /* Can set DSCP on socket IPv6 */
+#define ISC_NET_DSCPPKTV4 0x10 /* Can set DSCP on per packet IPv4 */
+#define ISC_NET_DSCPPKTV6 0x20 /* Can set DSCP on per packet IPv6 */
+#define ISC_NET_DSCPALL 0x3f /* All valid flags */
+
+unsigned int
+isc_net_probedscp(void);
+/*%<
+ * Probe the level of DSCP support.
+ */
+
+isc_result_t
+isc_net_probe_ipv6only(void);
+/*
+ * Check if the system's kernel supports the IPV6_V6ONLY socket option.
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS the option is supported for both TCP and UDP.
+ * ISC_R_NOTFOUND IPv6 itself or the option is not supported.
+ * ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probe_ipv6pktinfo(void);
+/*
+ * Check if the system's kernel supports the IPV6_(RECV)PKTINFO socket option
+ * for UDP sockets.
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS the option is supported.
+ * ISC_R_NOTFOUND IPv6 itself or the option is not supported.
+ * ISC_R_UNEXPECTED
+ */
+
+void
+isc_net_disableipv4(void);
+
+void
+isc_net_disableipv6(void);
+
+void
+isc_net_enableipv4(void);
+
+void
+isc_net_enableipv6(void);
+
+isc_result_t
+isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high);
+/*%<
+ * Returns system's default range of ephemeral UDP ports, if defined.
+ * If the range is not available or unknown, ISC_NET_PORTRANGELOW and
+ * ISC_NET_PORTRANGEHIGH will be returned.
+ *
+ * Requires:
+ *
+ *\li 'low' and 'high' must be non NULL.
+ *
+ * Returns:
+ *
+ *\li *low and *high will be the ports specifying the low and high ends of
+ * the range.
+ */
+
+#ifdef ISC_PLATFORM_NEEDNTOP
+const char *
+isc_net_ntop(int af, const void *src, char *dst, size_t size);
+#undef inet_ntop
+#define inet_ntop isc_net_ntop
+#endif
+
+#ifdef ISC_PLATFORM_NEEDPTON
+int
+isc_net_pton(int af, const char *src, void *dst);
+#define inet_pton isc_net_pton
+#endif
+
+int
+isc_net_aton(const char *cp, struct in_addr *addr);
+#define inet_aton isc_net_aton
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NET_H */
diff --git a/lib/isc/win32/include/isc/netdb.h b/lib/isc/win32/include/isc/netdb.h
new file mode 100644
index 0000000..c07194d
--- /dev/null
+++ b/lib/isc/win32/include/isc/netdb.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_NETDB_H
+#define ISC_NETDB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * Portable netdb.h support.
+ *
+ * This module is responsible for defining the get<x>by<y> APIs.
+ *
+ * MP:
+ * No impact.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * N/A.
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ * Standards:
+ * BSD API
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/net.h>
+
+#endif /* ISC_NETDB_H */
diff --git a/lib/isc/win32/include/isc/ntgroups.h b/lib/isc/win32/include/isc/ntgroups.h
new file mode 100644
index 0000000..e8352fc
--- /dev/null
+++ b/lib/isc/win32/include/isc/ntgroups.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_NTGROUPS_H
+#define ISC_NTGROUPS_H 1
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+
+isc_result_t
+isc_ntsecurity_getaccountgroups(char *name, char **Groups, unsigned int maxgroups,
+ unsigned int *total);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NTGROUPS_H */
diff --git a/lib/isc/win32/include/isc/ntpaths.h b/lib/isc/win32/include/isc/ntpaths.h
new file mode 100644
index 0000000..c0010fc
--- /dev/null
+++ b/lib/isc/win32/include/isc/ntpaths.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * Windows-specific path definitions
+ * These routines are used to set up and return system-specific path
+ * information about the files enumerated in NtPaths
+ */
+
+#ifndef ISC_NTPATHS_H
+#define ISC_NTPATHS_H
+
+#include <isc/lang.h>
+
+/*
+ * Index of paths needed
+ */
+enum NtPaths {
+ NAMED_CONF_PATH,
+ LWRES_CONF_PATH,
+ RESOLV_CONF_PATH,
+ RNDC_CONF_PATH,
+ NAMED_PID_PATH,
+ LWRESD_PID_PATH,
+ NAMED_LOCK_PATH,
+ LOCAL_STATE_DIR,
+ SYS_CONF_DIR,
+ RNDC_KEY_PATH,
+ SESSION_KEY_PATH
+};
+
+/*
+ * Define macros to get the path of the config files
+ */
+#define NAMED_CONFFILE isc_ntpaths_get(NAMED_CONF_PATH)
+#define RNDC_CONFFILE isc_ntpaths_get(RNDC_CONF_PATH)
+#define RNDC_KEYFILE isc_ntpaths_get(RNDC_KEY_PATH)
+#define SESSION_KEYFILE isc_ntpaths_get(SESSION_KEY_PATH)
+#define RESOLV_CONF isc_ntpaths_get(RESOLV_CONF_PATH)
+
+/*
+ * Information about where the files are on disk
+ */
+#define NS_LOCALSTATEDIR "/dns/bin"
+#define NS_SYSCONFDIR "/dns/etc"
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_ntpaths_init(void);
+
+char *
+isc_ntpaths_get(int);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NTPATHS_H */
diff --git a/lib/isc/win32/include/isc/offset.h b/lib/isc/win32/include/isc/offset.h
new file mode 100644
index 0000000..14ef06f
--- /dev/null
+++ b/lib/isc/win32/include/isc/offset.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_OFFSET_H
+#define ISC_OFFSET_H 1
+
+/*
+ * File offsets are operating-system dependent.
+ */
+#include <limits.h> /* Required for CHAR_BIT. */
+#include <sys/types.h>
+
+typedef _off_t isc_offset_t;
+
+#endif /* ISC_OFFSET_H */
diff --git a/lib/isc/win32/include/isc/once.h b/lib/isc/win32/include/isc/once.h
new file mode 100644
index 0000000..c005b0b
--- /dev/null
+++ b/lib/isc/win32/include/isc/once.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ONCE_H
+#define ISC_ONCE_H 1
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef struct {
+ int status;
+ int counter;
+} isc_once_t;
+
+#define ISC_ONCE_INIT_NEEDED 0
+#define ISC_ONCE_INIT_DONE 1
+
+#define ISC_ONCE_INIT { ISC_ONCE_INIT_NEEDED, 1 }
+
+isc_result_t
+isc_once_do(isc_once_t *controller, void(*function)(void));
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ONCE_H */
diff --git a/lib/isc/win32/include/isc/platform.h.in b/lib/isc/win32/include/isc/platform.h.in
new file mode 100644
index 0000000..5b8a2c9
--- /dev/null
+++ b/lib/isc/win32/include/isc/platform.h.in
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_PLATFORM_H
+#define ISC_PLATFORM_H 1
+
+/*****
+ ***** Platform-dependent defines.
+ *****/
+
+#define ISC_PLATFORM_USETHREADS 1
+
+/***
+ *** Network.
+ ***/
+
+#ifndef PATH_MAX
+#define PATH_MAX _MAX_PATH
+#endif
+
+#define ISC_PLATFORM_HAVEIPV6
+#if _MSC_VER > 1200
+#define ISC_PLATFORM_HAVEIN6PKTINFO
+#endif
+#define ISC_PLATFORM_HAVESCOPEID
+#define ISC_PLATFORM_NEEDPORTT
+#undef MSG_TRUNC
+#define ISC_PLATFORM_NEEDNTOP
+#define ISC_PLATFORM_NEEDPTON
+#define ISC_PLATFORM_HAVESOCKADDRSTORAGE
+
+#define ISC_PLATFORM_NEEDSTRSEP
+#define ISC_PLATFORM_NEEDSTRLCPY
+#define ISC_PLATFORM_NEEDSTRLCAT
+#define ISC_PLATFORM_NEEDSTRLCPY
+
+/*
+ * Used to control how extern data is linked; needed for Win32 platforms.
+ */
+#define ISC_PLATFORM_USEDECLSPEC 1
+
+/*
+ * Define this here for now as winsock2.h defines h_errno
+ * and we don't want to redeclare it.
+ */
+#define ISC_PLATFORM_NONSTDHERRNO
+
+/*
+ * Define if the platform has <sys/un.h>.
+ */
+#undef ISC_PLATFORM_HAVESYSUNH
+
+/*
+ * Define if we want to log backtrace
+ */
+@ISC_PLATFORM_USEBACKTRACE@
+
+/*
+ * Defines for the noreturn attribute.
+ */
+#define ISC_PLATFORM_NORETURN_PRE __declspec(noreturn)
+#define ISC_PLATFORM_NORETURN_POST
+
+/*
+ * Define if the hash functions must be provided by OpenSSL.
+ */
+@ISC_PLATFORM_OPENSSLHASH@
+
+/*
+ * Define if AES support is wanted
+ */
+@ISC_PLATFORM_WANTAES@
+
+/*
+ * If the "xadd" operation is available on this architecture,
+ * ISC_PLATFORM_HAVEXADD will be defined.
+ */
+@ISC_PLATFORM_HAVEXADD@
+
+/*
+ * If the "xaddq" operation (64bit xadd) is available on this architecture,
+ * ISC_PLATFORM_HAVEXADDQ will be defined.
+ */
+@ISC_PLATFORM_HAVEXADDQ@
+
+/*
+ * If the "atomic swap" operation is available on this architecture,
+ * ISC_PLATFORM_HAVEATOMICSTORE" will be defined.
+ */
+@ISC_PLATFORM_HAVEATOMICSTORE@
+
+/*
+ * If the "compare-and-exchange" operation is available on this architecture,
+ * ISC_PLATFORM_HAVECMPXCHG will be defined.
+ */
+@ISC_PLATFORM_HAVECMPXCHG@
+
+/*
+ * Define with the busy wait nop asm or function call.
+ */
+@ISC_PLATFORM_BUSYWAITNOP@
+
+/*
+ * If the strcasestr() operation is not available on this platform,
+ * ISC_PLATFORM_NEEDSTRCASESTR will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRCASESTR@
+
+/*
+ * Set up a macro for importing and exporting from the DLL
+ */
+
+#ifdef LIBISC_EXPORTS
+#define LIBISC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBDNS_EXPORTS
+#define LIBDNS_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBDNS_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBISCCC_EXPORTS
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBISCCFG_EXPORTS
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBBIND9_EXPORTS
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBTESTS_EXPORTS
+#define LIBTESTS_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBTESTS_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#endif /* ISC_PLATFORM_H */
diff --git a/lib/isc/win32/include/isc/stat.h b/lib/isc/win32/include/isc/stat.h
new file mode 100644
index 0000000..8b7d685
--- /dev/null
+++ b/lib/isc/win32/include/isc/stat.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_STAT_H
+#define ISC_STAT_H 1
+
+#include <sys/stat.h>
+
+/*
+ * Windows doesn't typedef this.
+ */
+typedef unsigned short mode_t;
+
+/* open() under unix allows setting of read/write permissions
+ * at the owner, group and other levels. These don't exist in NT
+ * We'll just map them all to the NT equivalent
+ */
+
+#define S_IREAD _S_IREAD /* read permission, owner */
+#define S_IWRITE _S_IWRITE /* write permission, owner */
+#define S_IRUSR _S_IREAD /* Owner read permission */
+#define S_IWUSR _S_IWRITE /* Owner write permission */
+#define S_IRGRP _S_IREAD /* Group read permission */
+#define S_IWGRP _S_IWRITE /* Group write permission */
+#define S_IROTH _S_IREAD /* Other read permission */
+#define S_IWOTH _S_IWRITE /* Other write permission */
+
+#ifndef S_IFMT
+# define S_IFMT _S_IFMT
+#endif
+#ifndef S_IFDIR
+# define S_IFDIR _S_IFDIR
+#endif
+#ifndef S_IFCHR
+# define S_IFCHR _S_IFCHR
+#endif
+#ifndef S_IFREG
+# define S_IFREG _S_IFREG
+#endif
+
+#ifndef S_ISDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#ifndef S_ISREG
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+#endif /* ISC_STAT_H */
diff --git a/lib/isc/win32/include/isc/stdtime.h b/lib/isc/win32/include/isc/stdtime.h
new file mode 100644
index 0000000..e11647f
--- /dev/null
+++ b/lib/isc/win32/include/isc/stdtime.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_STDTIME_H
+#define ISC_STDTIME_H 1
+
+#include <isc/lang.h>
+#include <inttypes.h>
+
+/*
+ * It's public information that 'isc_stdtime_t' is an unsigned integral type.
+ * Applications that want maximum portability should not assume anything
+ * about its size.
+ */
+typedef uint32_t isc_stdtime_t;
+
+/* but this flag helps... */
+#define STDTIME_ON_32BITS 1
+
+/*
+ * isc_stdtime32_t is a 32-bit version of isc_stdtime_t. A variable of this
+ * type should only be used as an opaque integer (e.g.,) to compare two
+ * time values.
+ */
+typedef uint32_t isc_stdtime32_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_stdtime_get(isc_stdtime_t *t);
+/*
+ * Set 't' to the number of seconds since 00:00:00 UTC, January 1, 1970.
+ *
+ * Requires:
+ *
+ * 't' is a valid pointer.
+ */
+
+#define isc_stdtime_convert32(t, t32p) (*(t32p) = t)
+/*
+ * Convert the standard time to its 32-bit version.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STDTIME_H */
diff --git a/lib/isc/win32/include/isc/strerror.h b/lib/isc/win32/include/isc/strerror.h
new file mode 100644
index 0000000..ae040a4
--- /dev/null
+++ b/lib/isc/win32/include/isc/strerror.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_STRERROR_H
+#define ISC_STRERROR_H
+
+#include <sys/types.h>
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+#define ISC_STRERRORSIZE 128
+
+/*
+ * Provide a thread safe wrapper to strerrror().
+ *
+ * Requires:
+ * 'buf' to be non NULL.
+ */
+void
+isc__strerror(int num, char *buf, size_t bufsize);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STRERROR_H */
diff --git a/lib/isc/win32/include/isc/syslog.h b/lib/isc/win32/include/isc/syslog.h
new file mode 100644
index 0000000..66431e5
--- /dev/null
+++ b/lib/isc/win32/include/isc/syslog.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_SYSLOG_H
+#define ISC_SYSLOG_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp);
+/*
+ * Convert 'str' to the appropriate syslog facility constant.
+ *
+ * Requires:
+ *
+ * 'str' is not NULL
+ * 'facilityp' is not NULL
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_NOTFOUND
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SYSLOG_H */
diff --git a/lib/isc/win32/include/isc/thread.h b/lib/isc/win32/include/isc/thread.h
new file mode 100644
index 0000000..be1343a
--- /dev/null
+++ b/lib/isc/win32/include/isc/thread.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_THREAD_H
+#define ISC_THREAD_H 1
+
+#include <windows.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+/*
+ * Inlines to help with wait return checking
+ */
+
+/* check handle for NULL and INVALID_HANDLE */
+inline BOOL IsValidHandle( HANDLE hHandle) {
+ return ((hHandle != NULL) && (hHandle != INVALID_HANDLE_VALUE));
+}
+
+/* validate wait return codes... */
+inline BOOL WaitSucceeded( DWORD dwWaitResult, DWORD dwHandleCount) {
+ return ((dwWaitResult >= WAIT_OBJECT_0) &&
+ (dwWaitResult < WAIT_OBJECT_0 + dwHandleCount));
+}
+
+inline BOOL WaitAbandoned( DWORD dwWaitResult, DWORD dwHandleCount) {
+ return ((dwWaitResult >= WAIT_ABANDONED_0) &&
+ (dwWaitResult < WAIT_ABANDONED_0 + dwHandleCount));
+}
+
+inline BOOL WaitTimeout( DWORD dwWaitResult) {
+ return (dwWaitResult == WAIT_TIMEOUT);
+}
+
+inline BOOL WaitFailed( DWORD dwWaitResult) {
+ return (dwWaitResult == WAIT_FAILED);
+}
+
+/* compute object indices for waits... */
+inline DWORD WaitSucceededIndex( DWORD dwWaitResult) {
+ return (dwWaitResult - WAIT_OBJECT_0);
+}
+
+inline DWORD WaitAbandonedIndex( DWORD dwWaitResult) {
+ return (dwWaitResult - WAIT_ABANDONED_0);
+}
+
+
+
+typedef HANDLE isc_thread_t;
+typedef DWORD isc_threadresult_t;
+typedef void * isc_threadarg_t;
+typedef isc_threadresult_t (WINAPI *isc_threadfunc_t)(isc_threadarg_t);
+typedef DWORD isc_thread_key_t;
+
+#define isc_thread_self (unsigned long)GetCurrentThreadId
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_thread_create(isc_threadfunc_t, isc_threadarg_t, isc_thread_t *);
+
+isc_result_t
+isc_thread_join(isc_thread_t, isc_threadresult_t *);
+
+void
+isc_thread_setconcurrency(unsigned int level);
+
+void
+isc_thread_setname(isc_thread_t, const char *);
+
+int
+isc_thread_key_create(isc_thread_key_t *key, void (*func)(void *));
+
+int
+isc_thread_key_delete(isc_thread_key_t key);
+
+void *
+isc_thread_key_getspecific(isc_thread_key_t);
+
+int
+isc_thread_key_setspecific(isc_thread_key_t key, void *value);
+
+#define isc_thread_yield() Sleep(0)
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_THREAD_H */
diff --git a/lib/isc/win32/include/isc/time.h b/lib/isc/win32/include/isc/time.h
new file mode 100644
index 0000000..486f527
--- /dev/null
+++ b/lib/isc/win32/include/isc/time.h
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_TIME_H
+#define ISC_TIME_H 1
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <windows.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/***
+ *** Intervals
+ ***/
+
+/*
+ * The contents of this structure are private, and MUST NOT be accessed
+ * directly by callers.
+ *
+ * The contents are exposed only to allow callers to avoid dynamic allocation.
+ */
+struct isc_interval {
+ int64_t interval;
+};
+
+LIBISC_EXTERNAL_DATA extern const isc_interval_t * const isc_interval_zero;
+
+/*
+ * ISC_FORMATHTTPTIMESTAMP_SIZE needs to be 30 in C locale and potentially
+ * more for other locales to handle longer national abbreviations when
+ * expanding strftime's %a and %b.
+ */
+#define ISC_FORMATHTTPTIMESTAMP_SIZE 50
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_interval_set(isc_interval_t *i,
+ unsigned int seconds, unsigned int nanoseconds);
+/*
+ * Set 'i' to a value representing an interval of 'seconds' seconds and
+ * 'nanoseconds' nanoseconds, suitable for use in isc_time_add() and
+ * isc_time_subtract().
+ *
+ * Requires:
+ *
+ * 't' is a valid pointer.
+ * nanoseconds < 1000000000.
+ */
+
+bool
+isc_interval_iszero(const isc_interval_t *i);
+/*
+ * Returns true iff. 'i' is the zero interval.
+ *
+ * Requires:
+ *
+ * 'i' is a valid pointer.
+ */
+
+/***
+ *** Absolute Times
+ ***/
+
+/*
+ * The contents of this structure are private, and MUST NOT be accessed
+ * directly by callers.
+ *
+ * The contents are exposed only to allow callers to avoid dynamic allocation.
+ */
+
+struct isc_time {
+ FILETIME absolute;
+};
+
+LIBISC_EXTERNAL_DATA extern const isc_time_t * const isc_time_epoch;
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds);
+/*%<
+ * Set 't' to a value which represents the given number of seconds and
+ * nanoseconds since 00:00:00 January 1, 1970, UTC.
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *\li nanoseconds < 1000000000.
+ */
+
+void
+isc_time_settoepoch(isc_time_t *t);
+/*
+ * Set 't' to the time of the epoch.
+ *
+ * Notes:
+ * The date of the epoch is platform-dependent.
+ *
+ * Requires:
+ *
+ * 't' is a valid pointer.
+ */
+
+bool
+isc_time_isepoch(const isc_time_t *t);
+/*
+ * Returns true iff. 't' is the epoch ("time zero").
+ *
+ * Requires:
+ *
+ * 't' is a valid pointer.
+ */
+
+isc_result_t
+isc_time_now(isc_time_t *t);
+/*
+ * Set 't' to the current absolute time.
+ *
+ * Requires:
+ *
+ * 't' is a valid pointer.
+ *
+ * Returns:
+ *
+ * Success
+ * Unexpected error
+ * Getting the time from the system failed.
+ * Out of range
+ * The time from the system is too large to be represented
+ * in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i);
+/*
+ * Set *t to the current absolute time + i.
+ *
+ * Note:
+ * This call is equivalent to:
+ *
+ * isc_time_now(t);
+ * isc_time_add(t, i, t);
+ *
+ * Requires:
+ *
+ * 't' and 'i' are valid pointers.
+ *
+ * Returns:
+ *
+ * Success
+ * Unexpected error
+ * Getting the time from the system failed.
+ * Out of range
+ * The interval added to the time from the system is too large to
+ * be represented in the current definition of isc_time_t.
+ */
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2);
+/*
+ * Compare the times referenced by 't1' and 't2'
+ *
+ * Requires:
+ *
+ * 't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ *
+ * -1 t1 < t2 (comparing times, not pointers)
+ * 0 t1 = t2
+ * 1 t1 > t2
+ */
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result);
+/*
+ * Add 'i' to 't', storing the result in 'result'.
+ *
+ * Requires:
+ *
+ * 't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ * Success
+ * Out of range
+ * The interval added to the time is too large to
+ * be represented in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+ isc_time_t *result);
+/*
+ * Subtract 'i' from 't', storing the result in 'result'.
+ *
+ * Requires:
+ *
+ * 't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ * Success
+ * Out of range
+ * The interval is larger than the time since the epoch.
+ */
+
+uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2);
+/*
+ * Find the difference in milliseconds between time t1 and time t2.
+ * t2 is the subtrahend of t1; ie, difference = t1 - t2.
+ *
+ * Requires:
+ *
+ * 't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ * The difference of t1 - t2, or 0 if t1 <= t2.
+ */
+
+isc_result_t
+isc_time_parsehttptimestamp(char *input, isc_time_t *t);
+/*%<
+ * Parse the time in 'input' into the isc_time_t pointed to by 't',
+ * expecting a format like "Mon, 30 Aug 2000 04:06:47 GMT"
+ *
+ * Requires:
+ *\li 'buf' and 't' are not NULL.
+ */
+
+uint32_t
+isc_time_nanoseconds(const isc_time_t *t);
+/*
+ * Return the number of nanoseconds stored in a time structure.
+ *
+ * Notes:
+ * This is the number of nanoseconds in excess of the number
+ * of seconds since the epoch; it will always be less than one
+ * full second.
+ *
+ * Requires:
+ * 't' is a valid pointer.
+ *
+ * Ensures:
+ * The returned value is less than 1*10^9.
+ */
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using a format like "30-Aug-2000 04:06:47.997" and the local time zone.
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ * 'len' > 0
+ * 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using a format like "Mon, 30 Aug 2000 04:06:47 GMT"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ * 'len' > 0
+ * 'buf' points to an array of at least len chars
+ *
+ */
+
+isc_result_t
+isc_time_parsehttptimestamp(char *input, isc_time_t *t);
+/*%<
+ * Parse the time in 'input' into the isc_time_t pointed to by 't',
+ * expecting a format like "Mon, 30 Aug 2000 04:06:47 GMT"
+ *
+ * Requires:
+ *\li 'buf' and 't' are not NULL.
+ */
+
+void
+isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ssZ"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sssZ"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+uint32_t
+isc_time_seconds(const isc_time_t *t);
+/*%<
+ * Return the number of seconds since the epoch stored in a time structure.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+isc_result_t
+isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp);
+/*%<
+ * Ensure the number of seconds in an isc_time_t is representable by a time_t.
+ *
+ * Notes:
+ *\li The number of seconds stored in an isc_time_t might be larger
+ * than the number of seconds a time_t is able to handle. Since
+ * time_t is mostly opaque according to the ANSI/ISO standard
+ * (essentially, all you can be sure of is that it is an arithmetic type,
+ * not even necessarily integral), it can be tricky to ensure that
+ * the isc_time_t is in the range a time_t can handle. Use this
+ * function in place of isc_time_seconds() any time you need to set a
+ * time_t from an isc_time_t.
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *
+ * Returns:
+ *\li Success
+ *\li Out of range
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TIME_H */
diff --git a/lib/isc/win32/include/isc/win32os.h b/lib/isc/win32/include/isc/win32os.h
new file mode 100644
index 0000000..bc18c40
--- /dev/null
+++ b/lib/isc/win32/include/isc/win32os.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_WIN32OS_H
+#define ISC_WIN32OS_H 1
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/*
+ * Return the number of CPUs available on the system, or 1 if this cannot
+ * be determined.
+ */
+
+int
+isc_win32os_versioncheck(unsigned int major, unsigned int minor,
+ unsigned int updatemajor, unsigned int updateminor);
+
+/*
+ * Checks the current version of the operating system with the
+ * supplied version information.
+ * Returns:
+ * -1 if less than the version information supplied
+ * 0 if equal to all of the version information supplied
+ * +1 if greater than the version information supplied
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_WIN32OS_H */
diff --git a/lib/isc/win32/include/pkcs11/Makefile.in b/lib/isc/win32/include/pkcs11/Makefile.in
new file mode 100644
index 0000000..e9a85d4
--- /dev/null
+++ b/lib/isc/win32/include/pkcs11/Makefile.in
@@ -0,0 +1,26 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+HEADERS = cryptoki.h
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/pkcs11
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/pkcs11 || exit 1; \
+ done
diff --git a/lib/isc/win32/include/pkcs11/cryptoki.h b/lib/isc/win32/include/pkcs11/cryptoki.h
new file mode 100644
index 0000000..2a681c4
--- /dev/null
+++ b/lib/isc/win32/include/pkcs11/cryptoki.h
@@ -0,0 +1,66 @@
+/* cryptoki.h include file for PKCS #11. */
+/* $Revision: 1.2 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* This is a sample file containing the top level include directives
+ * for building Win32 Cryptoki libraries and applications.
+ */
+
+#ifndef ___CRYPTOKI_H_INC___
+#define ___CRYPTOKI_H_INC___
+
+#pragma pack(push, cryptoki, 1)
+
+/* Specifies that the function is a DLL entry point. */
+#define CK_IMPORT_SPEC __declspec(dllimport)
+
+/* Define CRYPTOKI_EXPORTS during the build of cryptoki libraries. Do
+ * not define it in applications.
+ */
+#ifdef CRYPTOKI_EXPORTS
+/* Specified that the function is an exported DLL entry point. */
+#define CK_EXPORT_SPEC __declspec(dllexport)
+#else
+#define CK_EXPORT_SPEC CK_IMPORT_SPEC
+#endif
+
+/* Ensures the calling convention for Win32 builds */
+#define CK_CALL_SPEC __cdecl
+
+#define CK_PTR *
+
+#define CK_DEFINE_FUNCTION(returnType, name) \
+ returnType CK_EXPORT_SPEC CK_CALL_SPEC name
+
+#define CK_DECLARE_FUNCTION(returnType, name) \
+ returnType CK_EXPORT_SPEC CK_CALL_SPEC name
+
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ returnType CK_IMPORT_SPEC (CK_CALL_SPEC CK_PTR name)
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+ returnType (CK_CALL_SPEC CK_PTR name)
+
+#ifndef NULL_PTR
+#define NULL_PTR 0
+#endif
+
+#include <pkcs11/pkcs11.h>
+
+#pragma pack(pop, cryptoki)
+
+#endif /* ___CRYPTOKI_H_INC___ */
diff --git a/lib/isc/win32/interfaceiter.c b/lib/isc/win32/interfaceiter.c
new file mode 100644
index 0000000..1bbd0f8
--- /dev/null
+++ b/lib/isc/win32/interfaceiter.c
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * Note that this code will need to be revisited to support IPv6 Interfaces.
+ * For now we just iterate through IPv4 interfaces.
+ */
+
+#include <config.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <sys/types.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <isc/interfaceiter.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/strerror.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+void InitSockets(void);
+
+/* Common utility functions */
+
+/*
+ * Extract the network address part from a "struct sockaddr".
+ *
+ * The address family is given explicitly
+ * instead of using src->sa_family, because the latter does not work
+ * for copying a network mask obtained by SIOCGIFNETMASK (it does
+ * not have a valid address family).
+ */
+
+
+#define IFITER_MAGIC 0x49464954U /* IFIT. */
+#define VALID_IFITER(t) ((t) != NULL && (t)->magic == IFITER_MAGIC)
+
+struct isc_interfaceiter {
+ unsigned int magic; /* Magic number. */
+ isc_mem_t *mctx;
+ SOCKET socket;
+ INTERFACE_INFO IFData; /* Current Interface Info. */
+ int numIF; /* Current Interface count. */
+ int v4IF; /* Number of IPv4 Interfaces */
+ INTERFACE_INFO *buf4; /* Buffer for WSAIoctl data. */
+ unsigned int buf4size; /* Bytes allocated. */
+ INTERFACE_INFO *pos4; /* Current offset in IF List */
+ SOCKET_ADDRESS_LIST *buf6; /* Buffer for WSAIoctl data. */
+ unsigned int buf6size; /* Bytes allocated. */
+ unsigned int pos6; /* Which entry to process. */
+ bool v6loop; /* See IPv6 loop address. */
+ bool pos6zero; /* Done pos6 == 0. */
+ isc_interface_t current; /* Current interface data. */
+ isc_result_t result; /* Last result code. */
+};
+
+
+/*
+ * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
+ * We assume no sane system will have more than than 1K of IP addresses on
+ * all of its adapters.
+ */
+#define IFCONF_SIZE_INITIAL 16
+#define IFCONF_SIZE_INCREMENT 64
+#define IFCONF_SIZE_MAX 1040
+
+static void
+get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
+ dst->family = family;
+ switch (family) {
+ case AF_INET:
+ memmove(&dst->type.in,
+ &((struct sockaddr_in *) src)->sin_addr,
+ sizeof(struct in_addr));
+ break;
+ case AF_INET6:
+ memmove(&dst->type.in6,
+ &((struct sockaddr_in6 *) src)->sin6_addr,
+ sizeof(struct in6_addr));
+ dst->zone = ((struct sockaddr_in6 *) src)->sin6_scope_id;
+ break;
+ default:
+ INSIST(0);
+ break;
+ }
+}
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc_interfaceiter_t *iter;
+ isc_result_t result;
+ int error;
+ unsigned long bytesReturned = 0;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(iterp != NULL);
+ REQUIRE(*iterp == NULL);
+
+ iter = isc_mem_get(mctx, sizeof(*iter));
+ if (iter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ InitSockets();
+
+ iter->mctx = mctx;
+ iter->buf4 = NULL;
+ iter->buf6 = NULL;
+ iter->pos4 = NULL;
+ iter->pos6 = 0;
+ iter->v6loop = true;
+ iter->pos6zero = true;
+ iter->buf6size = 0;
+ iter->buf4size = 0;
+ iter->result = ISC_R_FAILURE;
+ iter->numIF = 0;
+ iter->v4IF = 0;
+
+ /*
+ * Create an unbound datagram socket to do the
+ * SIO_GET_INTERFACE_LIST WSAIoctl on.
+ */
+ iter->socket = socket(AF_INET, SOCK_DGRAM, 0);
+ if (iter->socket == INVALID_SOCKET) {
+ error = WSAGetLastError();
+ if (error == WSAEAFNOSUPPORT)
+ goto inet6_only;
+ isc__strerror(error, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "making interface scan socket: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto socket_failure;
+ }
+
+ /*
+ * Get the interface configuration, allocating more memory if
+ * necessary.
+ */
+ iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO);
+
+ for (;;) {
+ iter->buf4 = isc_mem_get(mctx, iter->buf4size);
+ if (iter->buf4 == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto alloc_failure;
+ }
+
+ if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST,
+ 0, 0, iter->buf4, iter->buf4size,
+ &bytesReturned, 0, 0) == SOCKET_ERROR)
+ {
+ error = WSAGetLastError();
+ if (error != WSAEFAULT && error != WSAENOBUFS) {
+ errno = error;
+ isc__strerror(error, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "get interface configuration: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto ioctl_failure;
+ }
+ /*
+ * EINVAL. Retry with a bigger buffer.
+ */
+ } else {
+ /*
+ * The WSAIoctl succeeded.
+ * If the number of the returned bytes is the same
+ * as the buffer size, we will grow it just in
+ * case and retry.
+ */
+ if (bytesReturned > 0 &&
+ (bytesReturned < iter->buf4size))
+ break;
+ }
+ if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "get interface configuration: "
+ "maximum buffer size exceeded");
+ result = ISC_R_UNEXPECTED;
+ goto ioctl_failure;
+ }
+ isc_mem_put(mctx, iter->buf4, iter->buf4size);
+
+ iter->buf4size += IFCONF_SIZE_INCREMENT *
+ sizeof(INTERFACE_INFO);
+ }
+
+ /*
+ * A newly created iterator has an undefined position
+ * until isc_interfaceiter_first() is called.
+ */
+ iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO);
+
+ /* We don't need the socket any more, so close it */
+ closesocket(iter->socket);
+
+ inet6_only:
+ /*
+ * Create an unbound datagram socket to do the
+ * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
+ */
+ iter->socket = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (iter->socket == INVALID_SOCKET) {
+ error = WSAGetLastError();
+ if (error == WSAEAFNOSUPPORT)
+ goto inet_only;
+ isc__strerror(error, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "making interface scan socket: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto ioctl_failure;
+ }
+
+ /*
+ * Get the interface configuration, allocating more memory if
+ * necessary.
+ */
+ iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) +
+ IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS);
+
+ for (;;) {
+ iter->buf6 = isc_mem_get(mctx, iter->buf6size);
+ if (iter->buf6 == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto ioctl_failure;
+ }
+
+ if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY,
+ 0, 0, iter->buf6, iter->buf6size,
+ &bytesReturned, 0, 0) == SOCKET_ERROR)
+ {
+ error = WSAGetLastError();
+ if (error != WSAEFAULT && error != WSAENOBUFS) {
+ errno = error;
+ isc__strerror(error, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "sio address list query: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto ioctl6_failure;
+ }
+ /*
+ * EINVAL. Retry with a bigger buffer.
+ */
+ } else
+ break;
+
+ if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "get interface configuration: "
+ "maximum buffer size exceeded");
+ result = ISC_R_UNEXPECTED;
+ goto ioctl6_failure;
+ }
+ isc_mem_put(mctx, iter->buf6, iter->buf6size);
+
+ iter->buf6size += IFCONF_SIZE_INCREMENT *
+ sizeof(SOCKET_ADDRESS);
+ }
+
+ closesocket(iter->socket);
+
+ inet_only:
+ iter->magic = IFITER_MAGIC;
+ *iterp = iter;
+ return (ISC_R_SUCCESS);
+
+ ioctl6_failure:
+ isc_mem_put(mctx, iter->buf6, iter->buf6size);
+
+ ioctl_failure:
+ if (iter->buf4 != NULL)
+ isc_mem_put(mctx, iter->buf4, iter->buf4size);
+
+ alloc_failure:
+ if (iter->socket != INVALID_SOCKET)
+ (void) closesocket(iter->socket);
+
+ socket_failure:
+ isc_mem_put(mctx, iter, sizeof(*iter));
+ return (result);
+}
+
+/*
+ * Get information about the current interface to iter->current.
+ * If successful, return ISC_R_SUCCESS.
+ * If the interface has an unsupported address family, or if
+ * some operation on it fails, return ISC_R_IGNORE to make
+ * the higher-level iterator code ignore it.
+ */
+
+static isc_result_t
+internal_current(isc_interfaceiter_t *iter) {
+ BOOL ifNamed = FALSE;
+ unsigned long flags;
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE(iter->numIF >= 0);
+
+ memset(&iter->current, 0, sizeof(iter->current));
+ iter->current.af = AF_INET;
+
+ get_addr(AF_INET, &iter->current.address,
+ (struct sockaddr *)&(iter->IFData.iiAddress));
+
+ /*
+ * Get interface flags.
+ */
+
+ iter->current.flags = 0;
+ flags = iter->IFData.iiFlags;
+
+ if ((flags & IFF_UP) != 0)
+ iter->current.flags |= INTERFACE_F_UP;
+
+ if ((flags & IFF_POINTTOPOINT) != 0) {
+ iter->current.flags |= INTERFACE_F_POINTTOPOINT;
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "PPP Interface %d", iter->numIF);
+ ifNamed = TRUE;
+ }
+
+ if ((flags & IFF_LOOPBACK) != 0) {
+ iter->current.flags |= INTERFACE_F_LOOPBACK;
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "Loopback Interface %d", iter->numIF);
+ ifNamed = TRUE;
+ }
+
+ /*
+ * If the interface is point-to-point, get the destination address.
+ */
+ if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
+ get_addr(AF_INET, &iter->current.dstaddress,
+ (struct sockaddr *)&(iter->IFData.iiBroadcastAddress));
+ }
+
+ if (ifNamed == FALSE)
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "TCP/IP Interface %d", iter->numIF);
+
+ /*
+ * Get the network mask.
+ */
+ get_addr(AF_INET, &iter->current.netmask,
+ (struct sockaddr *)&(iter->IFData.iiNetmask));
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+internal_current6(isc_interfaceiter_t *iter) {
+ SOCKET fd;
+ int i;
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE(iter->buf6 != NULL);
+
+ memset(&iter->current, 0, sizeof(iter->current));
+ iter->current.af = AF_INET6;
+
+ if (!iter->pos6zero) {
+ if (iter->pos6 == 0U)
+ iter->pos6zero = true;
+ get_addr(AF_INET6, &iter->current.address,
+ iter->buf6->Address[iter->pos6].lpSockaddr);
+
+ /*
+ * Set interface flags.
+ */
+
+ iter->current.flags = INTERFACE_F_UP;
+
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "TCP/IPv6 Interface %u", iter->pos6 + 1);
+
+ for (i = 0; i < 16; i++)
+ iter->current.netmask.type.in6.s6_addr[i] = 0xff;
+ iter->current.netmask.family = AF_INET6;
+ if (IN6_IS_ADDR_LOOPBACK(&iter->current.address.type.in6))
+ iter->v6loop = true;
+ } else {
+ /*
+ * See if we can bind to the ::1 and if so return ::1.
+ */
+ struct sockaddr_in6 sin6;
+
+ iter->v6loop = true; /* So we don't loop forever. */
+
+ fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fd == INVALID_SOCKET)
+ return (ISC_R_IGNORE);
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr.s6_addr[15] = 1;
+ if (bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
+ closesocket(fd);
+ return (ISC_R_IGNORE);
+ }
+ closesocket(fd);
+
+ iter->current.flags = INTERFACE_F_UP | INTERFACE_F_LOOPBACK;
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "TCP/IPv6 Loopback Interface");
+ for (i = 0; i < 16; i++) {
+ if (i != 15)
+ iter->current.address.type.in6.s6_addr[i] = 0;
+ else
+ iter->current.address.type.in6.s6_addr[i] = 1;
+ iter->current.netmask.type.in6.s6_addr[i] = 0xff;
+ }
+ iter->current.address.family = AF_INET6;
+ iter->current.netmask.family = AF_INET6;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Step the iterator to the next interface. Unlike
+ * isc_interfaceiter_next(), this may leave the iterator
+ * positioned on an interface that will ultimately
+ * be ignored. Return ISC_R_NOMORE if there are no more
+ * interfaces, otherwise ISC_R_SUCCESS.
+ */
+static isc_result_t
+internal_next(isc_interfaceiter_t *iter) {
+ if (iter->numIF >= iter->v4IF)
+ return (ISC_R_NOMORE);
+
+ /*
+ * The first one needs to be set up to point to the last
+ * Element of the array. Go to the end and back up
+ * Microsoft's implementation is peculiar for returning
+ * the list in reverse order
+ */
+
+ if (iter->numIF == 0)
+ iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF));
+
+ iter->pos4--;
+ if (&(iter->pos4) < &(iter->buf4))
+ return (ISC_R_NOMORE);
+
+ memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO));
+ memmove(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO));
+ iter->numIF++;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+internal_next6(isc_interfaceiter_t *iter) {
+ if (iter->pos6 == 0U && iter->v6loop)
+ return (ISC_R_NOMORE);
+ if (iter->pos6 != 0U)
+ iter->pos6--;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_interfaceiter_current(isc_interfaceiter_t *iter,
+ isc_interface_t *ifdata) {
+ REQUIRE(iter->result == ISC_R_SUCCESS);
+ memmove(ifdata, &iter->current, sizeof(*ifdata));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_interfaceiter_first(isc_interfaceiter_t *iter) {
+
+ REQUIRE(VALID_IFITER(iter));
+
+ if (iter->buf6 != NULL) {
+ iter->pos6 = iter->buf6->iAddressCount;
+ iter->v6loop = false;
+ iter->pos6zero = (iter->pos6 == 0U);
+ }
+ iter->result = ISC_R_SUCCESS;
+ return (isc_interfaceiter_next(iter));
+}
+
+isc_result_t
+isc_interfaceiter_next(isc_interfaceiter_t *iter) {
+ isc_result_t result;
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE(iter->result == ISC_R_SUCCESS);
+
+ for (;;) {
+ result = internal_next(iter);
+ if (result == ISC_R_NOMORE) {
+ result = internal_next6(iter);
+ if (result != ISC_R_SUCCESS)
+ break;
+ result = internal_current6(iter);
+ if (result == ISC_R_IGNORE)
+ continue;
+ break;
+ } else if (result != ISC_R_SUCCESS)
+ break;
+ result = internal_current(iter);
+ if (result != ISC_R_IGNORE)
+ break;
+ }
+ iter->result = result;
+ return (result);
+}
+
+void
+isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) {
+ isc_interfaceiter_t *iter;
+ REQUIRE(iterp != NULL);
+ iter = *iterp;
+ REQUIRE(VALID_IFITER(iter));
+
+ if (iter->buf4 != NULL)
+ isc_mem_put(iter->mctx, iter->buf4, iter->buf4size);
+ if (iter->buf6 != NULL)
+ isc_mem_put(iter->mctx, iter->buf6, iter->buf6size);
+
+ iter->magic = 0;
+ isc_mem_put(iter->mctx, iter, sizeof(*iter));
+ *iterp = NULL;
+}
diff --git a/lib/isc/win32/ipv6.c b/lib/isc/win32/ipv6.c
new file mode 100644
index 0000000..c2a4ac5
--- /dev/null
+++ b/lib/isc/win32/ipv6.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <isc/net.h>
+#include <isc/platform.h>
+
+LIBISC_EXTERNAL_DATA const struct in6_addr isc_in6addr_any =
+ IN6ADDR_ANY_INIT;
+
+LIBISC_EXTERNAL_DATA const struct in6_addr isc_in6addr_loopback =
+ IN6ADDR_LOOPBACK_INIT;
diff --git a/lib/isc/win32/keyboard.c b/lib/isc/win32/keyboard.c
new file mode 100644
index 0000000..6e6f800
--- /dev/null
+++ b/lib/isc/win32/keyboard.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#include <windows.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <io.h>
+
+#include <isc/keyboard.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_keyboard_open(isc_keyboard_t *keyboard) {
+ int fd;
+
+ REQUIRE(keyboard != NULL);
+
+ fd = _fileno(stdin);
+ if (fd < 0)
+ return (ISC_R_IOERROR);
+
+ keyboard->fd = fd;
+
+ keyboard->result = ISC_R_SUCCESS;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleeptime) {
+ REQUIRE(keyboard != NULL);
+
+ if (sleeptime > 0 && keyboard->result != ISC_R_CANCELED)
+ (void)Sleep(sleeptime*1000);
+
+ keyboard->fd = -1;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp) {
+ ssize_t cc;
+ unsigned char c;
+
+ REQUIRE(keyboard != NULL);
+ REQUIRE(cp != NULL);
+
+ cc = read(keyboard->fd, &c, 1);
+ if (cc < 0) {
+ keyboard->result = ISC_R_IOERROR;
+ return (keyboard->result);
+ }
+
+ *cp = c;
+
+ return (ISC_R_SUCCESS);
+}
+
+bool
+isc_keyboard_canceled(isc_keyboard_t *keyboard) {
+ return (keyboard->result == ISC_R_CANCELED);
+}
diff --git a/lib/isc/win32/libgen.h b/lib/isc/win32/libgen.h
new file mode 100644
index 0000000..e74740f
--- /dev/null
+++ b/lib/isc/win32/libgen.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef LIBGEN_H
+#define LIBGEN_H 1
+
+char *basename(const char *);
+char *dirname(const char *);
+
+#endif
diff --git a/lib/isc/win32/libisc.def.exclude b/lib/isc/win32/libisc.def.exclude
new file mode 100644
index 0000000..41e8562
--- /dev/null
+++ b/lib/isc/win32/libisc.def.exclude
@@ -0,0 +1,42 @@
+; These symbols are not needed by the WIN32 build, but build-tarballs
+; will complain if they aren't present here.
+isc_print_fprintf
+isc_print_printf
+isc_print_snprintf
+isc_print_sprintf
+isc_print_vsnprintf
+isc_socket_accept
+isc_socket_attach
+isc_socket_bind
+isc_socket_cancel
+isc_socket_cleanunix
+isc_socket_close
+isc_socket_connect
+isc_socket_create
+isc_socket_detach
+isc_socket_dscp
+isc_socket_dup
+isc_socket_fdwatchcreate
+isc_socket_fdwatchpoke
+isc_socket_filter
+isc_socket_getpeername
+isc_socket_getsockname
+isc_socket_gettype
+isc_socket_ipv6only
+isc_socket_listen
+isc_socket_open
+isc_socket_permunix
+isc_socket_recv
+isc_socket_recv2
+isc_socket_recvv
+isc_socket_register
+isc_socket_send
+isc_socket_sendto
+isc_socket_sendto2
+isc_socket_sendtov
+isc_socket_sendtov2
+isc_socket_sendv
+isc_socketmgr_create
+isc_socketmgr_create2
+isc_socketmgr_destroy
+isc_socketmgr_setstats
diff --git a/lib/isc/win32/libisc.def.in b/lib/isc/win32/libisc.def.in
new file mode 100644
index 0000000..a82face
--- /dev/null
+++ b/lib/isc/win32/libisc.def.in
@@ -0,0 +1,836 @@
+LIBRARY libisc
+
+; Exported Functions
+EXPORTS
+
+NTReportError
+closelog
+@IF PKCS11
+getpassphrase
+@END PKCS11
+isc___socketmgr_maxudp
+isc__app_block
+isc__app_ctxfinish
+isc__app_ctxonrun
+isc__app_ctxrun
+isc__app_ctxshutdown
+isc__app_ctxstart
+isc__app_ctxsuspend
+isc__app_finish
+isc__app_onrun
+isc__app_reload
+isc__app_run
+isc__app_shutdown
+isc__app_start
+isc__app_unblock
+isc__appctx_create
+isc__appctx_destroy
+isc__appctx_setsocketmgr
+isc__appctx_settaskmgr
+isc__appctx_settimermgr
+isc__buffer_activeregion
+isc__buffer_add
+isc__buffer_availableregion
+isc__buffer_back
+isc__buffer_clear
+isc__buffer_consumedregion
+isc__buffer_first
+isc__buffer_forward
+isc__buffer_init
+isc__buffer_initnull
+isc__buffer_invalidate
+isc__buffer_putmem
+isc__buffer_putstr
+isc__buffer_putuint16
+isc__buffer_putuint24
+isc__buffer_putuint32
+isc__buffer_putuint48
+isc__buffer_putuint8
+isc__buffer_region
+isc__buffer_remainingregion
+isc__buffer_setactive
+isc__buffer_subtract
+isc__buffer_usedregion
+isc__hash_setvec
+isc__mem_allocate
+isc__mem_free
+isc__mem_get
+isc__mem_put
+isc__mem_putanddetach
+isc__mem_reallocate
+isc__mem_strdup
+isc__mempool_get
+isc__mempool_put
+isc__socket_accept
+isc__socket_attach
+isc__socket_bind
+isc__socket_cancel
+isc__socket_cleanunix
+isc__socket_close
+isc__socket_connect
+isc__socket_create
+isc__socket_detach
+isc__socket_dscp
+isc__socket_dup
+isc__socket_filter
+isc__socket_getfd
+isc__socket_getname
+isc__socket_getpeername
+isc__socket_getsockname
+isc__socket_gettag
+isc__socket_gettype
+isc__socket_ipv6only
+isc__socket_isbound
+isc__socket_listen
+isc__socket_open
+isc__socket_permunix
+isc__socket_recv
+isc__socket_recv2
+isc__socket_recvv
+isc__socket_register
+isc__socket_send
+isc__socket_sendto
+isc__socket_sendto2
+isc__socket_sendtov
+isc__socket_sendtov2
+isc__socket_sendv
+isc__socket_setname
+isc__socketmgr_create
+isc__socketmgr_create2
+isc__socketmgr_destroy
+isc__socketmgr_getmaxsockets
+isc__socketmgr_setreserved
+isc__socketmgr_setstats
+isc__strerror
+isc__task_getname
+isc__task_gettag
+isc__task_unsendrange
+isc__taskmgr_mode
+@IF AES
+isc_aes128_crypt
+isc_aes192_crypt
+isc_aes256_crypt
+@END AES
+isc_app_block
+isc_app_ctxfinish
+isc_app_ctxonrun
+isc_app_ctxrun
+isc_app_ctxshutdown
+isc_app_ctxstart
+isc_app_ctxsuspend
+isc_app_finish
+isc_app_isrunning
+isc_app_onrun
+isc_app_register
+isc_app_reload
+isc_app_run
+isc_app_shutdown
+isc_app_start
+isc_app_unblock
+isc_appctx_create
+isc_appctx_destroy
+isc_appctx_setsocketmgr
+isc_appctx_settaskmgr
+isc_appctx_settimermgr
+isc_assertion_failed
+isc_assertion_setcallback
+isc_assertion_typetotext
+isc_backtrace_getsymbol
+isc_backtrace_getsymbolfromindex
+isc_backtrace_gettrace
+isc_base32_decoderegion
+isc_base32_decodestring
+isc_base32_tobuffer
+isc_base32_totext
+isc_base32hex_decoderegion
+isc_base32hex_decodestring
+isc_base32hex_tobuffer
+isc_base32hex_totext
+isc_base32hexnp_decoderegion
+isc_base32hexnp_decodestring
+isc_base32hexnp_tobuffer
+isc_base32hexnp_totext
+isc_base64_decodestring
+isc_base64_tobuffer
+isc_base64_totext
+isc_buffer_allocate
+isc_buffer_compact
+isc_buffer_copyregion
+isc_buffer_dup
+isc_buffer_free
+isc_buffer_getuint16
+isc_buffer_getuint32
+isc_buffer_getuint48
+isc_buffer_getuint8
+isc_buffer_putdecint
+isc_buffer_reallocate
+isc_buffer_reinit
+isc_buffer_reserve
+isc_buffer_setautorealloc
+isc_bufferlist_availablecount
+isc_bufferlist_usedcount
+isc_commandline_parse
+isc_commandline_strtoargv
+isc_condition_broadcast
+isc_condition_destroy
+isc_condition_init
+isc_condition_signal
+isc_condition_wait
+isc_condition_waituntil
+isc_counter_attach
+isc_counter_create
+isc_counter_detach
+isc_counter_increment
+isc_counter_setlimit
+isc_counter_used
+isc_crc64_final
+isc_crc64_init
+isc_crc64_update
+isc_dir_chdir
+isc_dir_chroot
+isc_dir_close
+isc_dir_createunique
+isc_dir_init
+isc_dir_open
+isc_dir_read
+isc_dir_reset
+isc_entropy_addcallbacksample
+isc_entropy_addsample
+isc_entropy_attach
+isc_entropy_create
+isc_entropy_createcallbacksource
+isc_entropy_createfilesource
+isc_entropy_createsamplesource
+isc_entropy_destroysource
+isc_entropy_detach
+isc_entropy_getdata
+isc_entropy_putdata
+isc_entropy_stats
+isc_entropy_status
+isc_entropy_stopcallbacksources
+isc_entropy_usebestsource
+isc_errno_toresult
+isc_error_fatal
+isc_error_runtimecheck
+isc_error_setfatal
+isc_error_setunexpected
+isc_error_unexpected
+isc_event_allocate
+isc_event_constallocate
+isc_event_free
+isc_file_absolutepath
+isc_file_basename
+isc_file_bopenunique
+isc_file_bopenuniquemode
+isc_file_bopenuniqueprivate
+isc_file_exists
+isc_file_getmodtime
+isc_file_getsize
+isc_file_getsizefd
+isc_file_isabsolute
+isc_file_ischdiridempotent
+isc_file_iscurrentdir
+isc_file_isdirectory
+isc_file_isdirwritable
+isc_file_isplainfile
+isc_file_isplainfilefd
+isc_file_mktemplate
+isc_file_mmap
+isc_file_mode
+isc_file_munmap
+isc_file_openunique
+isc_file_openuniquemode
+isc_file_openuniqueprivate
+isc_file_progname
+isc_file_remove
+isc_file_rename
+isc_file_renameunique
+isc_file_safecreate
+isc_file_safemovefile
+isc_file_sanitize
+isc_file_settime
+isc_file_splitpath
+isc_file_template
+isc_file_truncate
+isc_fsaccess_add
+isc_fsaccess_changeowner
+isc_fsaccess_remove
+isc_fsaccess_set
+isc_hash_calc
+isc_hash_create
+isc_hash_ctxattach
+isc_hash_ctxcalc
+isc_hash_ctxcreate
+isc_hash_ctxdetach
+isc_hash_ctxinit
+isc_hash_destroy
+isc_hash_function
+isc_hash_function_reverse
+isc_hash_get_initializer
+isc_hash_init
+isc_hash_set_initializer
+isc_heap_create
+isc_heap_decreased
+isc_heap_delete
+isc_heap_destroy
+isc_heap_foreach
+isc_heap_element
+isc_heap_increased
+isc_heap_insert
+isc_hex_decodestring
+isc_hex_tobuffer
+isc_hex_totext
+isc_hmacmd5_check
+isc_hmacmd5_init
+isc_hmacmd5_invalidate
+isc_hmacmd5_sign
+isc_hmacmd5_update
+isc_hmacmd5_verify
+isc_hmacmd5_verify2
+isc_hmacsha1_check
+isc_hmacsha1_init
+isc_hmacsha1_invalidate
+isc_hmacsha1_sign
+isc_hmacsha1_update
+isc_hmacsha1_verify
+isc_hmacsha224_init
+isc_hmacsha224_invalidate
+isc_hmacsha224_sign
+isc_hmacsha224_update
+isc_hmacsha224_verify
+isc_hmacsha256_init
+isc_hmacsha256_invalidate
+isc_hmacsha256_sign
+isc_hmacsha256_update
+isc_hmacsha256_verify
+isc_hmacsha384_init
+isc_hmacsha384_invalidate
+isc_hmacsha384_sign
+isc_hmacsha384_update
+isc_hmacsha384_verify
+isc_hmacsha512_init
+isc_hmacsha512_invalidate
+isc_hmacsha512_sign
+isc_hmacsha512_update
+isc_hmacsha512_verify
+isc_ht_add
+isc_ht_count
+isc_ht_delete
+isc_ht_destroy
+isc_ht_find
+isc_ht_init
+isc_ht_iter_create
+isc_ht_iter_current
+isc_ht_iter_currentkey
+isc_ht_iter_delcurrent_next
+isc_ht_iter_destroy
+isc_ht_iter_first
+isc_ht_iter_next
+isc_httpd_addheader
+isc_httpd_addheaderuint
+isc_httpd_response
+isc_httpd_setfinishhook
+isc_httpdmgr_addurl
+isc_httpdmgr_addurl2
+isc_httpdmgr_create
+isc_httpdmgr_shutdown
+isc_interfaceiter_create
+isc_interfaceiter_current
+isc_interfaceiter_destroy
+isc_interfaceiter_first
+isc_interfaceiter_next
+isc_interval_iszero
+isc_interval_set
+isc_iterated_hash
+isc_keyboard_canceled
+isc_keyboard_close
+isc_keyboard_getchar
+isc_keyboard_open
+isc_lex_close
+isc_lex_create
+isc_lex_destroy
+isc_lex_getcomments
+isc_lex_getlasttokentext
+isc_lex_getmastertoken
+isc_lex_getoctaltoken
+isc_lex_getsourceline
+isc_lex_getsourcename
+isc_lex_getspecials
+isc_lex_gettoken
+isc_lex_isfile
+isc_lex_openbuffer
+isc_lex_openfile
+isc_lex_openstream
+isc_lex_setcomments
+isc_lex_setsourceline
+isc_lex_setsourcename
+isc_lex_setspecials
+isc_lex_ungettoken
+isc_lfsr_generate
+isc_lfsr_generate32
+isc_lfsr_init
+isc_lfsr_skip
+isc_lib_initmsgcat
+isc_lib_register
+isc_log_categorybyname
+isc_log_closefilelogs
+isc_log_create
+isc_log_createchannel
+isc_log_destroy
+isc_log_getdebuglevel
+isc_log_getduplicateinterval
+isc_log_gettag
+isc_log_ivwrite
+isc_log_ivwrite1
+isc_log_iwrite
+isc_log_iwrite1
+isc_log_modulebyname
+isc_log_opensyslog
+isc_log_registercategories
+isc_log_registermodules
+isc_log_setcontext
+isc_log_setdebuglevel
+isc_log_setduplicateinterval
+isc_log_settag
+isc_log_usechannel
+isc_log_vwrite
+isc_log_vwrite1
+isc_log_wouldlog
+isc_log_write
+isc_log_write1
+isc_logconfig_create
+isc_logconfig_destroy
+isc_logconfig_get
+isc_logconfig_use
+isc_logfile_roll
+isc_md5_check
+isc_md5_final
+isc_md5_init
+isc_md5_invalidate
+isc_md5_update
+isc_mem_attach
+isc_mem_checkdestroyed
+isc_mem_create
+isc_mem_create2
+isc_mem_createx
+isc_mem_createx2
+isc_mem_destroy
+isc_mem_detach
+isc_mem_getname
+isc_mem_getquota
+isc_mem_gettag
+isc_mem_inuse
+isc_mem_isovermem
+isc_mem_maxinuse
+isc_mem_ondestroy
+isc_mem_printallactive
+isc_mem_references
+isc_mem_register
+@IF NOTYET
+isc_mem_renderjson
+@END NOTYET
+@IF LIBXML2
+isc_mem_renderxml
+@END LIBXML2
+isc_mem_setdestroycheck
+isc_mem_setname
+isc_mem_setquota
+isc_mem_setwater
+isc_mem_stats
+isc_mem_total
+isc_mem_waterack
+isc_meminfo_totalphys
+isc_mempool_associatelock
+isc_mempool_create
+isc_mempool_destroy
+isc_mempool_getallocated
+isc_mempool_getfillcount
+isc_mempool_getfreecount
+isc_mempool_getfreemax
+isc_mempool_getmaxalloc
+isc_mempool_setfillcount
+isc_mempool_setfreemax
+isc_mempool_setmaxalloc
+isc_mempool_setname
+isc_msgcat_close
+isc_msgcat_get
+isc_msgcat_open
+isc_mutexblock_destroy
+isc_mutexblock_init
+isc_net_aton
+isc_net_disableipv4
+isc_net_disableipv6
+isc_net_enableipv4
+isc_net_enableipv6
+isc_net_getudpportrange
+isc_net_ntop
+isc_net_probe_ipv6only
+isc_net_probe_ipv6pktinfo
+isc_net_probedscp
+isc_net_probeipv4
+isc_net_probeipv6
+isc_net_probeunix
+isc_net_pton
+isc_netaddr_any
+isc_netaddr_any6
+isc_netaddr_eqprefix
+isc_netaddr_equal
+isc_netaddr_format
+isc_netaddr_fromin
+isc_netaddr_fromin6
+isc_netaddr_frompath
+isc_netaddr_fromsockaddr
+isc_netaddr_fromv4mapped
+isc_netaddr_getzone
+isc_netaddr_isexperimental
+isc_netaddr_islinklocal
+isc_netaddr_isloopback
+isc_netaddr_ismulticast
+isc_netaddr_isnetzero
+isc_netaddr_issitelocal
+isc_netaddr_masktoprefixlen
+isc_netaddr_prefixok
+isc_netaddr_setzone
+isc_netaddr_totext
+isc_netscope_pton
+isc_ntpaths_get
+isc_ntpaths_init
+isc_once_do
+isc_ondestroy_init
+isc_ondestroy_notify
+isc_ondestroy_register
+isc_os_ncpus
+isc_parse_uint16
+isc_parse_uint32
+isc_parse_uint8
+isc_pool_count
+isc_pool_create
+isc_pool_destroy
+isc_pool_expand
+isc_pool_get
+isc_portset_add
+isc_portset_addrange
+isc_portset_create
+isc_portset_destroy
+isc_portset_isset
+isc_portset_nports
+isc_portset_remove
+isc_portset_removerange
+isc_quota_attach
+isc_quota_destroy
+isc_quota_detach
+isc_quota_init
+isc_quota_max
+isc_quota_release
+isc_quota_reserve
+isc_quota_soft
+isc_radix_create
+isc_radix_destroy
+isc_radix_insert
+isc_radix_process
+isc_radix_remove
+isc_radix_search
+isc_random_get
+isc_random_jitter
+isc_random_seed
+isc_ratelimiter_attach
+isc_ratelimiter_create
+isc_ratelimiter_dequeue
+isc_ratelimiter_detach
+isc_ratelimiter_enqueue
+isc_ratelimiter_release
+isc_ratelimiter_setinterval
+isc_ratelimiter_setpertic
+isc_ratelimiter_setpushpop
+isc_ratelimiter_shutdown
+isc_ratelimiter_stall
+isc_refcount_init
+isc_regex_validate
+isc_region_compare
+isc_resource_getcurlimit
+isc_resource_getlimit
+isc_resource_setlimit
+isc_result_register
+isc_result_registerids
+isc_result_toid
+isc_result_totext
+isc_rng_attach
+isc_rng_create
+isc_rng_detach
+isc_rng_random
+isc_rng_uniformrandom
+isc_rwlock_destroy
+isc_rwlock_downgrade
+isc_rwlock_init
+isc_rwlock_lock
+isc_rwlock_trylock
+isc_rwlock_tryupgrade
+isc_rwlock_unlock
+isc_safe_memcompare
+isc_safe_memequal
+isc_safe_memwipe
+isc_serial_eq
+isc_serial_ge
+isc_serial_gt
+isc_serial_le
+isc_serial_lt
+isc_serial_ne
+isc_sha1_check
+isc_sha1_final
+isc_sha1_init
+isc_sha1_invalidate
+isc_sha1_update
+isc_sha224_data
+isc_sha224_end
+isc_sha224_final
+isc_sha224_init
+isc_sha224_invalidate
+isc_sha224_update
+isc_sha256_data
+isc_sha256_end
+isc_sha256_final
+isc_sha256_init
+isc_sha256_invalidate
+isc_sha256_update
+isc_sha384_data
+isc_sha384_end
+isc_sha384_final
+isc_sha384_init
+isc_sha384_invalidate
+isc_sha384_update
+isc_sha512_data
+isc_sha512_end
+isc_sha512_final
+isc_sha512_init
+isc_sha512_invalidate
+isc_sha512_update
+isc_sockaddr_any
+isc_sockaddr_any6
+isc_sockaddr_anyofpf
+isc_sockaddr_compare
+isc_sockaddr_eqaddr
+isc_sockaddr_eqaddrprefix
+isc_sockaddr_equal
+isc_sockaddr_format
+isc_sockaddr_fromin
+isc_sockaddr_fromin6
+isc_sockaddr_fromnetaddr
+isc_sockaddr_frompath
+isc_sockaddr_getport
+isc_sockaddr_hash
+isc_sockaddr_isexperimental
+isc_sockaddr_islinklocal
+isc_sockaddr_ismulticast
+isc_sockaddr_isnetzero
+isc_sockaddr_issitelocal
+isc_sockaddr_pf
+isc_sockaddr_setport
+isc_sockaddr_totext
+isc_sockaddr_v6fromin
+isc_socket_socketevent
+isc_socketmgr_createinctx
+@IF NOTYET
+isc_socketmgr_renderjson
+@END NOTYET
+@IF LIBXML2
+isc_socketmgr_renderxml
+@END LIBXML2
+isc_stats_attach
+isc_stats_create
+isc_stats_decrement
+isc_stats_detach
+isc_stats_dump
+isc_stats_increment
+isc_stats_ncounters
+isc_stats_set
+isc_stdio_close
+isc_stdio_flush
+isc_stdio_open
+isc_stdio_read
+isc_stdio_seek
+isc_stdio_sync
+isc_stdio_tell
+isc_stdio_write
+isc_stdtime_get
+isc_string_append
+isc_string_append_truncate
+isc_string_copy
+isc_string_copy_truncate
+isc_string_printf
+isc_string_printf_truncate
+isc_string_regiondup
+isc_string_separate
+isc_string_strcasestr
+isc_string_strlcat
+isc_string_strlcpy
+isc_string_touint64
+isc_symtab_count
+isc_symtab_create
+isc_symtab_define
+isc_symtab_destroy
+isc_symtab_lookup
+isc_symtab_undefine
+isc_syslog_facilityfromstring
+isc_task_attach
+isc_task_beginexclusive
+isc_task_create
+isc_task_destroy
+isc_task_detach
+isc_task_endexclusive
+isc_task_exiting
+isc_task_getcurrenttime
+isc_task_getcurrenttimex
+isc_task_onshutdown
+isc_task_privilege
+isc_task_purge
+isc_task_purgeevent
+isc_task_purgerange
+isc_task_register
+isc_task_send
+isc_task_sendanddetach
+isc_task_setname
+isc_task_setprivilege
+isc_task_shutdown
+isc_task_unsend
+isc_taskmgr_create
+isc_taskmgr_createinctx
+isc_taskmgr_destroy
+isc_taskmgr_excltask
+isc_taskmgr_mode
+@IF NOTYET
+isc_taskmgr_renderjson
+@END NOTYET
+@IF LIBXML2
+isc_taskmgr_renderxml
+@END LIBXML2
+isc_taskmgr_setexcltask
+isc_taskmgr_setmode
+isc_taskpool_create
+isc_taskpool_destroy
+isc_taskpool_expand
+isc_taskpool_gettask
+isc_taskpool_setprivilege
+isc_taskpool_size
+isc_thread_create
+isc_thread_join
+isc_thread_key_create
+isc_thread_key_delete
+isc_thread_key_getspecific
+isc_thread_key_setspecific
+isc_thread_setconcurrency
+isc_thread_setname
+isc_time_add
+isc_time_compare
+isc_time_formatISO8601
+isc_time_formatISO8601ms
+isc_time_formathttptimestamp
+isc_time_formattimestamp
+isc_time_isepoch
+isc_time_microdiff
+isc_time_nanoseconds
+isc_time_now
+isc_time_nowplusinterval
+isc_time_parsehttptimestamp
+isc_time_secondsastimet
+isc_time_seconds
+isc_time_set
+isc_time_settoepoch
+isc_time_subtract
+isc_timer_attach
+isc_timer_create
+isc_timer_detach
+isc_timer_gettype
+isc_timer_register
+isc_timer_reset
+isc_timer_touch
+isc_timermgr_create
+isc_timermgr_createinctx
+isc_timermgr_destroy
+isc_timermgr_poke
+isc_tm_timegm
+isc_tm_strptime
+isc_win32os_versioncheck
+openlog
+@IF PKCS11
+pk11_attribute_bytype
+pk11_attribute_first
+pk11_attribute_next
+pk11_dump_tokens
+pk11_error_fatalcheck
+pk11_finalize
+pk11_get_best_token
+pk11_get_lib_name
+pk11_get_load_error_message
+pk11_get_session
+pk11_initialize
+pk11_initmsgcat
+pk11_mem_get
+pk11_mem_put
+pk11_numbits
+pk11_parse_uri
+pk11_rand_bytes
+pk11_rand_seed_fromfile
+pk11_result_register
+pk11_result_totext
+pk11_return_session
+pk11_set_lib_name
+pkcs_C_CloseSession
+pkcs_C_CreateObject
+pkcs_C_DeriveKey
+pkcs_C_DestroyObject
+pkcs_C_DigestFinal
+pkcs_C_DigestInit
+pkcs_C_DigestUpdate
+pkcs_C_Encrypt
+pkcs_C_EncryptInit
+pkcs_C_Finalize
+pkcs_C_FindObjects
+pkcs_C_FindObjectsFinal
+pkcs_C_FindObjectsInit
+pkcs_C_GenerateKey
+pkcs_C_GenerateKeyPair
+pkcs_C_GenerateRandom
+pkcs_C_GetAttributeValue
+pkcs_C_GetMechanismInfo
+pkcs_C_GetSlotList
+pkcs_C_GetTokenInfo
+pkcs_C_Initialize
+pkcs_C_Login
+pkcs_C_Logout
+pkcs_C_OpenSession
+pkcs_C_SeedRandom
+pkcs_C_SetAttributeValue
+pkcs_C_Sign
+pkcs_C_SignFinal
+pkcs_C_SignInit
+pkcs_C_SignUpdate
+pkcs_C_Verify
+pkcs_C_VerifyFinal
+pkcs_C_VerifyInit
+pkcs_C_VerifyUpdate
+@END PKCS11
+syslog
+
+@IF NOLONGER
+; Exported Data
+
+EXPORTS
+
+isc__backtrace_nsymbols DATA
+isc__backtrace_symtable DATA
+isc_bind9 DATA
+isc_commandline_argument DATA
+isc_commandline_errprint DATA
+isc_commandline_index DATA
+isc_commandline_option DATA
+isc_commandline_progname DATA
+isc_commandline_reset DATA
+isc_dscp_check_value DATA
+isc_hashctx DATA
+isc_mem_debugging DATA
+isc_msgcat DATA
+@IF PKCS11
+pk11_msgcat DATA
+pk11_verbose_init DATA
+@END PKCS11
+@END NOLONGER
diff --git a/lib/isc/win32/libisc.dsp.in b/lib/isc/win32/libisc.dsp.in
new file mode 100644
index 0000000..d21edb8
--- /dev/null
+++ b/lib/isc/win32/libisc.dsp.in
@@ -0,0 +1,949 @@
+# Microsoft Developer Studio Project File - Name="libisc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "@PLATFORM@ (x86) Dynamic-Link Library" 0x0102
+
+CFG=libisc - @PLATFORM@ Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libisc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libisc.mak" CFG="libisc - @PLATFORM@ Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libisc - @PLATFORM@ Release" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE "libisc - @PLATFORM@ Debug" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 @COPTX@ @COPTI@ /O2 /D "BIND9" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" @COPTY@ /FD /c
+@IF PKCS11
+# ADD CPP /nologo /MD /W3 @COPTX@ @COPTI@ /O2 /I "./" /I "../../../" @LIBXML2_INC@ @OPENSSL_INC@ @ZLIB_INC@ /I "include" /I "../include" /I "win32" /I "../../isccfg/include" /I "../../../lib/dns/win32/include" /I "../../../lib/dns/include" /D "BIND9" @CRYPTO@ @PK11_LIB_LOCATION@ /D "WIN32" /D "NDEBUG" /D "__STDC__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" @COPTY@ /FD /c
+@ELSE PKCS11
+# ADD CPP /nologo /MD /W3 @COPTX@ @COPTI@ /O2 /I "./" /I "../../../" @LIBXML2_INC@ @OPENSSL_INC@ @ZLIB_INC@ /I "include" /I "../include" /I "win32" /I "../../isccfg/include" /D "BIND9" /D "WIN32" /D "NDEBUG" /D "__STDC__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" @COPTY@ /FD /c
+@END PKCS11
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll @MACHINE@
+# ADD LINK32 @LIBXML2_LIB@ @OPENSSL_LIB@ @ZLIB_LIB@ user32.lib advapi32.lib ws2_32.lib /nologo /dll @MACHINE@ /out:"../../../Build/Release/libisc.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /D "BIND9" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" @COPTY@ /FD /GZ /c
+@IF PKCS11
+# ADD CPP /nologo /MDd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /I "./" /I "../../../" @LIBXML2_INC@ @OPENSSL_INC@ @ZLIB_INC@ /I "include" /I "../include" /I "win32" /I "../../isccfg/include" /I "../../../lib/dns/win32/include" /I "../../../lib/dns/include" /D "BIND9" @CRYPTO@ @PK11_LIB_LOCATION@ /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /FR @COPTY@ /FD /GZ /c
+@ELSE PKCS11
+# ADD CPP /nologo /MDd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /I "./" /I "../../../" @LIBXML2_INC@ @OPENSSL_INC@ @ZLIB_INC@ /I "include" /I "../include" /I "win32" /I "../../isccfg/include" /D "BIND9" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /FR @COPTY@ /FD /GZ /c
+@END PKCS11
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug @MACHINE@ /pdbtype:sept
+# ADD LINK32 @LIBXML2_LIB@ @OPENSSL_LIB@ @ZLIB_LIB@ user32.lib advapi32.lib ws2_32.lib /nologo /dll /map /debug @MACHINE@ /out:"../../../Build/Debug/libisc.dll" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "libisc - @PLATFORM@ Release"
+# Name "libisc - @PLATFORM@ Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\app.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\condition.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\DLLMain.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\entropy.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\errno.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\errno2result.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\file.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fsaccess.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\interfaceiter.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ipv6.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\keyboard.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\meminfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\net.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ntpaths.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\once.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os.c
+# End Source File
+@IF PKCS11
+# Begin Source File
+
+SOURCE=.\pk11_api.c
+# End Source File
+@END PKCS11
+# Begin Source File
+
+SOURCE=.\resource.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\socket.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\stdio.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\stdtime.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strerror.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\syslog.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\thread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\time.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\version.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32os.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+@IF AES
+# Begin Source File
+
+SOURCE=..\include\isc\aes.h
+# End Source File
+@END AES
+# Begin Source File
+
+SOURCE=..\include\isc\app.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\assertions.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\backtrace.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\base32.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\base64.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\bind9.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\bind_registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\bindevt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\boolean.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\buffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\bufferlist.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\commandline.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\counter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\condition.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\config.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\crc64.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\dir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\entropy.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\errno.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\errno2result.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\error.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\event.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\eventclass.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\file.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\formatcheck.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\fsaccess.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\hash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\heap.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\hex.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\hmacmd5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\hmacsha.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\ht.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\httpd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\int.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\interfaceiter.h
+# End Source File
+@IF PKCS11
+# Begin Source File
+
+SOURCE=..\include\pk11\internal.h
+# End Source File
+@END PKCS11
+# Begin Source File
+
+SOURCE=.\include\isc\ipv6.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\iterated_hash.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\keyboard.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\json.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\lang.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\lex.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\lfsr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\lib.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\list.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\log.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\magic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\mem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\meminfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\msgcat.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\mutex.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\mutexblock.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\net.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\netaddr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\netscope.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\netdb.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\ntgroups.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\ntpaths.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\offset.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\once.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\ondestroy.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\os.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\parseint.h
+# End Source File
+@IF PKCS11
+# Begin Source File
+
+SOURCE=..\include\pk11\pk11.h
+# End Source File
+@END PKCS11
+# Begin Source File
+
+SOURCE=..\include\isc\pool.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\portset.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\platform.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\print.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\queue.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\quota.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\radix.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\random.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\ratelimiter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\refcount.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\regex.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\region.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\result.h
+# End Source File
+@IF PKCS11
+# Begin Source File
+
+SOURCE=..\include\pk11\result.h
+# End Source File
+@END PKCS11
+# Begin Source File
+
+SOURCE=..\include\isc\resultclass.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\rwlock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\safe.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\serial.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\sha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\sha2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\sockaddr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\socket.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\stat.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\stats.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\stdio.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\stdlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\stdtime.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\strerror.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\string.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\symtab.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\syslog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\syslog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\task.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\taskpool.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\thread.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\time.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\timer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\tm.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\win32os.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\types.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\unistd.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\util.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\versions.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\xml.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Group "Main Isc Lib"
+
+# PROP Default_Filter "c"
+@IF AES
+# Begin Source File
+
+SOURCE=..\aes.c
+# End Source File
+@END AES
+# Begin Source File
+
+SOURCE=..\assertions.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\backtrace.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\backtrace-emptytbl.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\base32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\base64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\bind9.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\buffer.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\bufferlist.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\commandline.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\counter.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\crc64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\error.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\event.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\hash.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\heap.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\hex.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\hmacmd5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\hmacsha.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ht.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\httpd.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\inet_aton.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\inet_ntop.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\inet_pton.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\iterated_hash.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\lex.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\lfsr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\log.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mem.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\nls\msgcat.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mutexblock.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\netaddr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\netscope.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ondestroy.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\parseint.c
+# End Source File
+@IF PKCS11
+# Begin Source File
+
+SOURCE=..\pk11.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\pk11_result.c
+# End Source File
+@END PKCS11
+# Begin Source File
+
+SOURCE=..\pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\portset.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\quota.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\radix.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\random.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ratelimiter.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\refcount.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\regex.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\region.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\result.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\rwlock.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\safe.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\serial.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\sha1.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\sha2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\sockaddr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\stats.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\string.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\symtab.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\task.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\taskpool.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\timer.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\tm.c
+# End Source File
+# End Group
+@IF ATOMIC
+# Begin Source File
+
+SOURCE=.\include\atomic.h
+# End Source File
+@ELSE ATOMIC
+# Begin Source File
+
+SOURCE=..\noatomic\include\atomic.h
+# End Source File
+@END ATOMIC
+# Begin Source File
+
+SOURCE=.\libisc.def
+# End Source File
+# End Target
+# End Project
diff --git a/lib/isc/win32/libisc.dsw b/lib/isc/win32/libisc.dsw
new file mode 100644
index 0000000..49c089c
--- /dev/null
+++ b/lib/isc/win32/libisc.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "libisc"=".\libisc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lib/isc/win32/libisc.mak.in b/lib/isc/win32/libisc.mak.in
new file mode 100644
index 0000000..9a6acd5
--- /dev/null
+++ b/lib/isc/win32/libisc.mak.in
@@ -0,0 +1,2398 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on libisc.dsp
+!IF "$(CFG)" == ""
+CFG=libisc - @PLATFORM@ Debug
+!MESSAGE No configuration specified. Defaulting to libisc - @PLATFORM@ Debug.
+!ENDIF
+
+!IF "$(CFG)" != "libisc - @PLATFORM@ Release" && "$(CFG)" != "libisc - @PLATFORM@ Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libisc.mak" CFG="libisc - @PLATFORM@ Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libisc - @PLATFORM@ Release" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE "libisc - @PLATFORM@ Debug" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+LIBXML=@LIBXML2_LIB@
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+_VC_MANIFEST_INC=0
+_VC_MANIFEST_BASENAME=__VC80
+!ELSE
+_VC_MANIFEST_INC=1
+_VC_MANIFEST_BASENAME=__VC80.Debug
+!ENDIF
+
+####################################################
+# Specifying name of temporary resource file used only in incremental builds:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res
+!else
+_VC_MANIFEST_AUTO_RES=
+!endif
+
+####################################################
+# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+#MT_SPECIAL_RETURN=1090650113
+#MT_SPECIAL_SWITCH=-notify_resource_update
+MT_SPECIAL_RETURN=0
+MT_SPECIAL_SWITCH=
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
+if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
+rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
+link $** /out:$@ $(LFLAGS)
+
+!else
+
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1
+
+!endif
+
+####################################################
+# _VC_MANIFEST_EMBED_DLL - command to embed manifest in DLL:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+#MT_SPECIAL_RETURN=1090650113
+#MT_SPECIAL_SWITCH=-notify_resource_update
+MT_SPECIAL_RETURN=0
+MT_SPECIAL_SWITCH=
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
+if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
+rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
+link $** /out:$@ $(LFLAGS)
+
+!else
+
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;2
+
+!endif
+####################################################
+# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \
+ $(_VC_MANIFEST_BASENAME).auto.rc \
+ $(_VC_MANIFEST_BASENAME).auto.manifest
+
+!else
+
+_VC_MANIFEST_CLEAN=
+
+!endif
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "..\..\..\Build\Release\libisc.dll"
+
+
+CLEAN :
+@IF AES
+ -@erase "$(INTDIR)\aes.obj"
+@END AES
+ -@erase "$(INTDIR)\app.obj"
+ -@erase "$(INTDIR)\assertions.obj"
+ -@erase "$(INTDIR)\backtrace.obj"
+ -@erase "$(INTDIR)\backtrace-emptytbl.obj"
+ -@erase "$(INTDIR)\base32.obj"
+ -@erase "$(INTDIR)\base64.obj"
+ -@erase "$(INTDIR)\bind9.obj"
+ -@erase "$(INTDIR)\buffer.obj"
+ -@erase "$(INTDIR)\bufferlist.obj"
+ -@erase "$(INTDIR)\commandline.obj"
+ -@erase "$(INTDIR)\counter.obj"
+ -@erase "$(INTDIR)\condition.obj"
+ -@erase "$(INTDIR)\crc64.obj"
+ -@erase "$(INTDIR)\dir.obj"
+ -@erase "$(INTDIR)\DLLMain.obj"
+ -@erase "$(INTDIR)\entropy.obj"
+ -@erase "$(INTDIR)\errno.obj"
+ -@erase "$(INTDIR)\errno2result.obj"
+ -@erase "$(INTDIR)\error.obj"
+ -@erase "$(INTDIR)\event.obj"
+ -@erase "$(INTDIR)\file.obj"
+ -@erase "$(INTDIR)\fsaccess.obj"
+ -@erase "$(INTDIR)\hash.obj"
+ -@erase "$(INTDIR)\heap.obj"
+ -@erase "$(INTDIR)\hex.obj"
+ -@erase "$(INTDIR)\hmacmd5.obj"
+ -@erase "$(INTDIR)\hmacsha.obj"
+ -@erase "$(INTDIR)\ht.obj"
+ -@erase "$(INTDIR)\httpd.obj"
+ -@erase "$(INTDIR)\inet_aton.obj"
+ -@erase "$(INTDIR)\inet_ntop.obj"
+ -@erase "$(INTDIR)\inet_pton.obj"
+ -@erase "$(INTDIR)\interfaceiter.obj"
+ -@erase "$(INTDIR)\ipv6.obj"
+ -@erase "$(INTDIR)\iterated_hash.obj"
+ -@erase "$(INTDIR)\keyboard.obj"
+ -@erase "$(INTDIR)\lex.obj"
+ -@erase "$(INTDIR)\lfsr.obj"
+ -@erase "$(INTDIR)\lib.obj"
+ -@erase "$(INTDIR)\log.obj"
+ -@erase "$(INTDIR)\md5.obj"
+ -@erase "$(INTDIR)\mem.obj"
+ -@erase "$(INTDIR)\msgcat.obj"
+ -@erase "$(INTDIR)\mutexblock.obj"
+ -@erase "$(INTDIR)\meminfo.obj"
+ -@erase "$(INTDIR)\net.obj"
+ -@erase "$(INTDIR)\netaddr.obj"
+ -@erase "$(INTDIR)\netscope.obj"
+ -@erase "$(INTDIR)\ntpaths.obj"
+ -@erase "$(INTDIR)\once.obj"
+ -@erase "$(INTDIR)\ondestroy.obj"
+ -@erase "$(INTDIR)\os.obj"
+ -@erase "$(INTDIR)\parseint.obj"
+@IF PKCS11
+ -@erase "$(INTDIR)\pk11.obj"
+ -@erase "$(INTDIR)\pk11_api.obj"
+ -@erase "$(INTDIR)\pk11_result.obj"
+@END PKCS11
+ -@erase "$(INTDIR)\pool.obj"
+ -@erase "$(INTDIR)\portset.obj"
+ -@erase "$(INTDIR)\quota.obj"
+ -@erase "$(INTDIR)\radix.obj"
+ -@erase "$(INTDIR)\random.obj"
+ -@erase "$(INTDIR)\ratelimiter.obj"
+ -@erase "$(INTDIR)\refcount.obj"
+ -@erase "$(INTDIR)\regex.obj"
+ -@erase "$(INTDIR)\region.obj"
+ -@erase "$(INTDIR)\resource.obj"
+ -@erase "$(INTDIR)\result.obj"
+ -@erase "$(INTDIR)\rwlock.obj"
+ -@erase "$(INTDIR)\safe.obj"
+ -@erase "$(INTDIR)\serial.obj"
+ -@erase "$(INTDIR)\sha1.obj"
+ -@erase "$(INTDIR)\sha2.obj"
+ -@erase "$(INTDIR)\sockaddr.obj"
+ -@erase "$(INTDIR)\socket.obj"
+ -@erase "$(INTDIR)\stats.obj"
+ -@erase "$(INTDIR)\stdio.obj"
+ -@erase "$(INTDIR)\stdtime.obj"
+ -@erase "$(INTDIR)\strerror.obj"
+ -@erase "$(INTDIR)\string.obj"
+ -@erase "$(INTDIR)\symtab.obj"
+ -@erase "$(INTDIR)\syslog.obj"
+ -@erase "$(INTDIR)\task.obj"
+ -@erase "$(INTDIR)\taskpool.obj"
+ -@erase "$(INTDIR)\thread.obj"
+ -@erase "$(INTDIR)\time.obj"
+ -@erase "$(INTDIR)\timer.obj"
+ -@erase "$(INTDIR)\tm.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\version.obj"
+ -@erase "$(INTDIR)\win32os.obj"
+ -@erase "$(OUTDIR)\libisc.exp"
+ -@erase "$(OUTDIR)\libisc.lib"
+ -@erase "..\..\..\Build\Release\libisc.dll"
+ -@$(_VC_MANIFEST_CLEAN)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+@IF PKCS11
+CPP_PROJ=/nologo /MD /W3 @COPTX@ @COPTI@ /O2 /I "./" /I "../../../" /I "include" /I "../include" /I "win32" /I "../../isccfg/include" /I "../../dns/win32/include" /I "../../dns/include" @LIBXML2_INC@ @OPENSSL_INC@ @ZLIB_INC@ /D "BIND9" @CRYPTO@ @PK11_LIB_LOCATION@ /D "WIN32" /D "NDEBUG" /D "__STDC__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /Fp"$(INTDIR)\libisc.pch" @COPTY@ /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+@ELSE PKCS11
+CPP_PROJ=/nologo /MD /W3 @COPTX@ @COPTI@ /O2 /I "./" /I "../../../" /I "include" /I "../include" /I "win32" /I "../../isccfg/include" @LIBXML2_INC@ @OPENSSL_INC@ @ZLIB_INC@ /D "BIND9" /D "WIN32" /D "NDEBUG" /D "__STDC__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /Fp"$(INTDIR)\libisc.pch" @COPTY@ /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+@END PKCS11
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libisc.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=user32.lib advapi32.lib ws2_32.lib $(LIBXML) @OPENSSL_LIB@ @ZLIB_LIB@ /nologo /dll /incremental:no /pdb:"$(OUTDIR)\libisc.pdb" @MACHINE@ /def:".\libisc.def" /out:"../../../Build/Release/libisc.dll" /implib:"$(OUTDIR)\libisc.lib"
+DEF_FILE= \
+ ".\libisc.def"
+LINK32_OBJS= \
+ "$(INTDIR)\app.obj" \
+ "$(INTDIR)\condition.obj" \
+ "$(INTDIR)\dir.obj" \
+ "$(INTDIR)\DLLMain.obj" \
+ "$(INTDIR)\entropy.obj" \
+ "$(INTDIR)\errno.obj" \
+ "$(INTDIR)\errno2result.obj" \
+ "$(INTDIR)\file.obj" \
+ "$(INTDIR)\fsaccess.obj" \
+ "$(INTDIR)\interfaceiter.obj" \
+ "$(INTDIR)\ipv6.obj" \
+ "$(INTDIR)\iterated_hash.obj" \
+ "$(INTDIR)\keyboard.obj" \
+ "$(INTDIR)\meminfo.obj" \
+ "$(INTDIR)\net.obj" \
+ "$(INTDIR)\ntpaths.obj" \
+ "$(INTDIR)\once.obj" \
+ "$(INTDIR)\os.obj" \
+@IF PKCS11
+ "$(INTDIR)\pk11_api.obj" \
+@END PKCS11
+ "$(INTDIR)\resource.obj" \
+ "$(INTDIR)\socket.obj" \
+ "$(INTDIR)\stdio.obj" \
+ "$(INTDIR)\stdtime.obj" \
+ "$(INTDIR)\strerror.obj" \
+ "$(INTDIR)\syslog.obj" \
+ "$(INTDIR)\thread.obj" \
+ "$(INTDIR)\time.obj" \
+ "$(INTDIR)\version.obj" \
+ "$(INTDIR)\win32os.obj" \
+@IF AES
+ "$(INTDIR)\aes.obj" \
+@END AES
+ "$(INTDIR)\assertions.obj" \
+ "$(INTDIR)\backtrace.obj" \
+ "$(INTDIR)\backtrace-emptytbl.obj" \
+ "$(INTDIR)\base32.obj" \
+ "$(INTDIR)\base64.obj" \
+ "$(INTDIR)\bind9.obj" \
+ "$(INTDIR)\buffer.obj" \
+ "$(INTDIR)\bufferlist.obj" \
+ "$(INTDIR)\commandline.obj" \
+ "$(INTDIR)\counter.obj" \
+ "$(INTDIR)\crc64.obj" \
+ "$(INTDIR)\error.obj" \
+ "$(INTDIR)\event.obj" \
+ "$(INTDIR)\hash.obj" \
+ "$(INTDIR)\heap.obj" \
+ "$(INTDIR)\hex.obj" \
+ "$(INTDIR)\hmacmd5.obj" \
+ "$(INTDIR)\hmacsha.obj" \
+ "$(INTDIR)\ht.obj" \
+ "$(INTDIR)\httpd.obj" \
+ "$(INTDIR)\inet_aton.obj" \
+ "$(INTDIR)\inet_ntop.obj" \
+ "$(INTDIR)\inet_pton.obj" \
+ "$(INTDIR)\lex.obj" \
+ "$(INTDIR)\lfsr.obj" \
+ "$(INTDIR)\lib.obj" \
+ "$(INTDIR)\log.obj" \
+ "$(INTDIR)\md5.obj" \
+ "$(INTDIR)\mem.obj" \
+ "$(INTDIR)\msgcat.obj" \
+ "$(INTDIR)\mutexblock.obj" \
+ "$(INTDIR)\netaddr.obj" \
+ "$(INTDIR)\netscope.obj" \
+ "$(INTDIR)\ondestroy.obj" \
+@IF PKCS11
+ "$(INTDIR)\pk11.obj" \
+ "$(INTDIR)\pk11_result.obj" \
+@END PKCS11
+ "$(INTDIR)\quota.obj" \
+ "$(INTDIR)\radix.obj" \
+ "$(INTDIR)\random.obj" \
+ "$(INTDIR)\ratelimiter.obj" \
+ "$(INTDIR)\refcount.obj" \
+ "$(INTDIR)\result.obj" \
+ "$(INTDIR)\rwlock.obj" \
+ "$(INTDIR)\safe.obj" \
+ "$(INTDIR)\serial.obj" \
+ "$(INTDIR)\sha1.obj" \
+ "$(INTDIR)\sha2.obj" \
+ "$(INTDIR)\sockaddr.obj" \
+ "$(INTDIR)\stats.obj" \
+ "$(INTDIR)\string.obj" \
+ "$(INTDIR)\symtab.obj" \
+ "$(INTDIR)\task.obj" \
+ "$(INTDIR)\taskpool.obj" \
+ "$(INTDIR)\timer.obj" \
+ "$(INTDIR)\tm.obj" \
+ "$(INTDIR)\parseint.obj" \
+ "$(INTDIR)\pool.obj" \
+ "$(INTDIR)\portset.obj" \
+ "$(INTDIR)\regex.obj" \
+ "$(INTDIR)\region.obj"
+
+"..\..\..\Build\Release\libisc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+ $(_VC_MANIFEST_EMBED_DLL)
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+ALL : "..\..\..\Build\Debug\libisc.dll" "$(OUTDIR)\libisc.bsc"
+
+
+CLEAN :
+@IF AES
+ -@erase "$(INTDIR)\aes.obj"
+ -@erase "$(INTDIR)\aes.sbr"
+@END AES
+ -@erase "$(INTDIR)\app.obj"
+ -@erase "$(INTDIR)\app.sbr"
+ -@erase "$(INTDIR)\assertions.obj"
+ -@erase "$(INTDIR)\assertions.sbr"
+ -@erase "$(INTDIR)\backtrace.obj"
+ -@erase "$(INTDIR)\backtrace-emptytbl.obj"
+ -@erase "$(INTDIR)\backtrace.sbr"
+ -@erase "$(INTDIR)\backtrace-emptytbl.sbr"
+ -@erase "$(INTDIR)\base32.obj"
+ -@erase "$(INTDIR)\base32.sbr"
+ -@erase "$(INTDIR)\base64.obj"
+ -@erase "$(INTDIR)\base64.sbr"
+ -@erase "$(INTDIR)\bind9.obj"
+ -@erase "$(INTDIR)\bind9.sbr"
+ -@erase "$(INTDIR)\buffer.obj"
+ -@erase "$(INTDIR)\buffer.sbr"
+ -@erase "$(INTDIR)\bufferlist.obj"
+ -@erase "$(INTDIR)\bufferlist.sbr"
+ -@erase "$(INTDIR)\commandline.obj"
+ -@erase "$(INTDIR)\commandline.sbr"
+ -@erase "$(INTDIR)\counter.obj"
+ -@erase "$(INTDIR)\counter.sbr"
+ -@erase "$(INTDIR)\condition.obj"
+ -@erase "$(INTDIR)\condition.sbr"
+ -@erase "$(INTDIR)\crc64.obj"
+ -@erase "$(INTDIR)\crc64.sbr"
+ -@erase "$(INTDIR)\dir.obj"
+ -@erase "$(INTDIR)\dir.sbr"
+ -@erase "$(INTDIR)\DLLMain.obj"
+ -@erase "$(INTDIR)\DLLMain.sbr"
+ -@erase "$(INTDIR)\entropy.obj"
+ -@erase "$(INTDIR)\entropy.sbr"
+ -@erase "$(INTDIR)\errno.obj"
+ -@erase "$(INTDIR)\errno.sbr"
+ -@erase "$(INTDIR)\errno2result.obj"
+ -@erase "$(INTDIR)\errno2result.sbr"
+ -@erase "$(INTDIR)\error.obj"
+ -@erase "$(INTDIR)\error.sbr"
+ -@erase "$(INTDIR)\event.obj"
+ -@erase "$(INTDIR)\event.sbr"
+ -@erase "$(INTDIR)\file.obj"
+ -@erase "$(INTDIR)\file.sbr"
+ -@erase "$(INTDIR)\fsaccess.obj"
+ -@erase "$(INTDIR)\fsaccess.sbr"
+ -@erase "$(INTDIR)\hash.obj"
+ -@erase "$(INTDIR)\hash.sbr"
+ -@erase "$(INTDIR)\heap.obj"
+ -@erase "$(INTDIR)\heap.sbr"
+ -@erase "$(INTDIR)\hex.obj"
+ -@erase "$(INTDIR)\hex.sbr"
+ -@erase "$(INTDIR)\hmacmd5.obj"
+ -@erase "$(INTDIR)\hmacmd5.sbr"
+ -@erase "$(INTDIR)\hmacsha.obj"
+ -@erase "$(INTDIR)\hmacsha.sbr"
+ -@erase "$(INTDIR)\ht.obj"
+ -@erase "$(INTDIR)\ht.sbr"
+ -@erase "$(INTDIR)\httpd.obj"
+ -@erase "$(INTDIR)\httpd.sbr"
+ -@erase "$(INTDIR)\inet_aton.obj"
+ -@erase "$(INTDIR)\inet_aton.sbr"
+ -@erase "$(INTDIR)\inet_ntop.obj"
+ -@erase "$(INTDIR)\inet_ntop.sbr"
+ -@erase "$(INTDIR)\inet_pton.obj"
+ -@erase "$(INTDIR)\inet_pton.sbr"
+ -@erase "$(INTDIR)\interfaceiter.obj"
+ -@erase "$(INTDIR)\interfaceiter.sbr"
+ -@erase "$(INTDIR)\ipv6.obj"
+ -@erase "$(INTDIR)\ipv6.sbr"
+ -@erase "$(INTDIR)\iterated_hash.obj"
+ -@erase "$(INTDIR)\iterated_hash.sbr"
+ -@erase "$(INTDIR)\keyboard.obj"
+ -@erase "$(INTDIR)\keyboard.sbr"
+ -@erase "$(INTDIR)\lex.obj"
+ -@erase "$(INTDIR)\lex.sbr"
+ -@erase "$(INTDIR)\lfsr.obj"
+ -@erase "$(INTDIR)\lfsr.sbr"
+ -@erase "$(INTDIR)\lib.obj"
+ -@erase "$(INTDIR)\lib.sbr"
+ -@erase "$(INTDIR)\log.obj"
+ -@erase "$(INTDIR)\log.sbr"
+ -@erase "$(INTDIR)\md5.obj"
+ -@erase "$(INTDIR)\md5.sbr"
+ -@erase "$(INTDIR)\mem.obj"
+ -@erase "$(INTDIR)\mem.sbr"
+ -@erase "$(INTDIR)\msgcat.obj"
+ -@erase "$(INTDIR)\msgcat.sbr"
+ -@erase "$(INTDIR)\mutexblock.obj"
+ -@erase "$(INTDIR)\mutexblock.sbr"
+ -@erase "$(INTDIR)\meminfo.obj"
+ -@erase "$(INTDIR)\meminfo.sbr"
+ -@erase "$(INTDIR)\net.obj"
+ -@erase "$(INTDIR)\net.sbr"
+ -@erase "$(INTDIR)\netaddr.obj"
+ -@erase "$(INTDIR)\netaddr.sbr"
+ -@erase "$(INTDIR)\netscope.obj"
+ -@erase "$(INTDIR)\netscope.sbr"
+ -@erase "$(INTDIR)\ntpaths.obj"
+ -@erase "$(INTDIR)\ntpaths.sbr"
+ -@erase "$(INTDIR)\once.obj"
+ -@erase "$(INTDIR)\once.sbr"
+ -@erase "$(INTDIR)\ondestroy.obj"
+ -@erase "$(INTDIR)\ondestroy.sbr"
+ -@erase "$(INTDIR)\os.obj"
+ -@erase "$(INTDIR)\os.sbr"
+ -@erase "$(INTDIR)\parseint.obj"
+ -@erase "$(INTDIR)\parseint.sbr"
+@IF PKCS11
+ -@erase "$(INTDIR)\pk11.obj"
+ -@erase "$(INTDIR)\pk11_api.obj"
+ -@erase "$(INTDIR)\pk11_result.obj"
+@END PKCS11
+ -@erase "$(INTDIR)\pool.obj"
+ -@erase "$(INTDIR)\pool.sbr"
+ -@erase "$(INTDIR)\portset.obj"
+ -@erase "$(INTDIR)\portset.sbr"
+ -@erase "$(INTDIR)\quota.obj"
+ -@erase "$(INTDIR)\quota.sbr"
+ -@erase "$(INTDIR)\radix.obj"
+ -@erase "$(INTDIR)\radix.sbr"
+ -@erase "$(INTDIR)\random.obj"
+ -@erase "$(INTDIR)\random.sbr"
+ -@erase "$(INTDIR)\ratelimiter.obj"
+ -@erase "$(INTDIR)\ratelimiter.sbr"
+ -@erase "$(INTDIR)\refcount.obj"
+ -@erase "$(INTDIR)\refcount.sbr"
+ -@erase "$(INTDIR)\regex.obj"
+ -@erase "$(INTDIR)\regex.sbr"
+ -@erase "$(INTDIR)\region.obj"
+ -@erase "$(INTDIR)\region.sbr"
+ -@erase "$(INTDIR)\resource.obj"
+ -@erase "$(INTDIR)\resource.sbr"
+ -@erase "$(INTDIR)\result.obj"
+ -@erase "$(INTDIR)\result.sbr"
+ -@erase "$(INTDIR)\rwlock.obj"
+ -@erase "$(INTDIR)\rwlock.sbr"
+ -@erase "$(INTDIR)\safe.obj"
+ -@erase "$(INTDIR)\safe.sbr"
+ -@erase "$(INTDIR)\serial.obj"
+ -@erase "$(INTDIR)\serial.sbr"
+ -@erase "$(INTDIR)\sha1.obj"
+ -@erase "$(INTDIR)\sha1.sbr"
+ -@erase "$(INTDIR)\sha2.obj"
+ -@erase "$(INTDIR)\sha2.sbr"
+ -@erase "$(INTDIR)\sockaddr.obj"
+ -@erase "$(INTDIR)\sockaddr.sbr"
+ -@erase "$(INTDIR)\socket.obj"
+ -@erase "$(INTDIR)\socket.sbr"
+ -@erase "$(INTDIR)\stats.obj"
+ -@erase "$(INTDIR)\stats.sbr"
+ -@erase "$(INTDIR)\stdio.obj"
+ -@erase "$(INTDIR)\stdio.sbr"
+ -@erase "$(INTDIR)\stdtime.obj"
+ -@erase "$(INTDIR)\stdtime.sbr"
+ -@erase "$(INTDIR)\strerror.obj"
+ -@erase "$(INTDIR)\strerror.sbr"
+ -@erase "$(INTDIR)\string.obj"
+ -@erase "$(INTDIR)\string.sbr"
+ -@erase "$(INTDIR)\symtab.obj"
+ -@erase "$(INTDIR)\symtab.sbr"
+ -@erase "$(INTDIR)\syslog.obj"
+ -@erase "$(INTDIR)\syslog.sbr"
+ -@erase "$(INTDIR)\task.obj"
+ -@erase "$(INTDIR)\task.sbr"
+ -@erase "$(INTDIR)\taskpool.obj"
+ -@erase "$(INTDIR)\taskpool.sbr"
+ -@erase "$(INTDIR)\thread.obj"
+ -@erase "$(INTDIR)\thread.sbr"
+ -@erase "$(INTDIR)\time.obj"
+ -@erase "$(INTDIR)\time.sbr"
+ -@erase "$(INTDIR)\timer.obj"
+ -@erase "$(INTDIR)\timer.sbr"
+ -@erase "$(INTDIR)\tm.obj"
+ -@erase "$(INTDIR)\tm.sbr"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\version.obj"
+ -@erase "$(INTDIR)\version.sbr"
+ -@erase "$(INTDIR)\win32os.obj"
+ -@erase "$(INTDIR)\win32os.sbr"
+ -@erase "$(OUTDIR)\libisc.bsc"
+ -@erase "$(OUTDIR)\libisc.exp"
+ -@erase "$(OUTDIR)\libisc.lib"
+ -@erase "$(OUTDIR)\libisc.map"
+ -@erase "$(OUTDIR)\libisc.pdb"
+ -@erase "..\..\..\Build\Debug\libisc.dll"
+ -@erase "..\..\..\Build\Debug\libisc.ilk"
+ -@$(_VC_MANIFEST_CLEAN)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+@IF PKCS11
+CPP_PROJ=/nologo /MDd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /I "./" /I "../../../" /I "include" /I "../include" /I "win32" /I "../../isccfg/include" /I "../../dns/win32/include" /I "../../dns/include" @LIBXML2_INC@ @OPENSSL_INC@ @ZLIB_INC@ /D "BIND9" @CRYPTO@ @PK11_LIB_LOCATION@ /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\libisc.pch" @COPTY@ /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+@ELSE PKCS11
+CPP_PROJ=/nologo /MDd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /I "./" /I "../../../" /I "include" /I "../include" /I "win32" /I "../../isccfg/include" @LIBXML2_INC@ @OPENSSL_INC@ @ZLIB_INC@ /D "BIND9" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\libisc.pch" @COPTY@ /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+@END PKCS11
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libisc.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\app.sbr" \
+ "$(INTDIR)\condition.sbr" \
+ "$(INTDIR)\dir.sbr" \
+ "$(INTDIR)\DLLMain.sbr" \
+ "$(INTDIR)\entropy.sbr" \
+ "$(INTDIR)\errno.sbr" \
+ "$(INTDIR)\errno2result.sbr" \
+ "$(INTDIR)\file.sbr" \
+ "$(INTDIR)\fsaccess.sbr" \
+ "$(INTDIR)\interfaceiter.sbr" \
+ "$(INTDIR)\ipv6.sbr" \
+ "$(INTDIR)\iterated_hash.sbr" \
+ "$(INTDIR)\keyboard.sbr" \
+ "$(INTDIR)\meminfo.sbr" \
+ "$(INTDIR)\net.sbr" \
+ "$(INTDIR)\ntpaths.sbr" \
+ "$(INTDIR)\once.sbr" \
+ "$(INTDIR)\os.sbr" \
+@IF PKCS11
+ "$(INTDIR)\pk11_api.sbr" \
+@END PKCS11
+ "$(INTDIR)\resource.sbr" \
+ "$(INTDIR)\socket.sbr" \
+ "$(INTDIR)\stdio.sbr" \
+ "$(INTDIR)\stdtime.sbr" \
+ "$(INTDIR)\strerror.sbr" \
+ "$(INTDIR)\syslog.sbr" \
+ "$(INTDIR)\thread.sbr" \
+ "$(INTDIR)\time.sbr" \
+ "$(INTDIR)\version.sbr" \
+ "$(INTDIR)\win32os.sbr" \
+@IF AES
+ "$(INTDIR)\aes.sbr" \
+@END AES
+ "$(INTDIR)\assertions.sbr" \
+ "$(INTDIR)\backtrace.sbr" \
+ "$(INTDIR)\backtrace-emptytbl.sbr" \
+ "$(INTDIR)\base32.sbr" \
+ "$(INTDIR)\base64.sbr" \
+ "$(INTDIR)\bind9.sbr" \
+ "$(INTDIR)\buffer.sbr" \
+ "$(INTDIR)\bufferlist.sbr" \
+ "$(INTDIR)\commandline.sbr" \
+ "$(INTDIR)\counter.sbr" \
+ "$(INTDIR)\crc64.sbr" \
+ "$(INTDIR)\error.sbr" \
+ "$(INTDIR)\event.sbr" \
+ "$(INTDIR)\hash.sbr" \
+ "$(INTDIR)\heap.sbr" \
+ "$(INTDIR)\hex.sbr" \
+ "$(INTDIR)\hmacmd5.sbr" \
+ "$(INTDIR)\hmacsha.sbr" \
+ "$(INTDIR)\ht.sbr" \
+ "$(INTDIR)\httpd.sbr" \
+ "$(INTDIR)\inet_aton.sbr" \
+ "$(INTDIR)\inet_ntop.sbr" \
+ "$(INTDIR)\inet_pton.sbr" \
+ "$(INTDIR)\lex.sbr" \
+ "$(INTDIR)\lfsr.sbr" \
+ "$(INTDIR)\lib.sbr" \
+ "$(INTDIR)\log.sbr" \
+ "$(INTDIR)\md5.sbr" \
+ "$(INTDIR)\mem.sbr" \
+ "$(INTDIR)\msgcat.sbr" \
+ "$(INTDIR)\mutexblock.sbr" \
+ "$(INTDIR)\netaddr.sbr" \
+ "$(INTDIR)\netscope.sbr" \
+ "$(INTDIR)\ondestroy.sbr" \
+@IF PKCS11
+ "$(INTDIR)\pk11.sbr" \
+ "$(INTDIR)\pk11_result.sbr" \
+@END PKCS11
+ "$(INTDIR)\quota.sbr" \
+ "$(INTDIR)\radix.sbr" \
+ "$(INTDIR)\random.sbr" \
+ "$(INTDIR)\ratelimiter.sbr" \
+ "$(INTDIR)\refcount.sbr" \
+ "$(INTDIR)\result.sbr" \
+ "$(INTDIR)\rwlock.sbr" \
+ "$(INTDIR)\safe.sbr" \
+ "$(INTDIR)\serial.sbr" \
+ "$(INTDIR)\sha1.sbr" \
+ "$(INTDIR)\sha2.sbr" \
+ "$(INTDIR)\sockaddr.sbr" \
+ "$(INTDIR)\stats.sbr" \
+ "$(INTDIR)\string.sbr" \
+ "$(INTDIR)\symtab.sbr" \
+ "$(INTDIR)\task.sbr" \
+ "$(INTDIR)\taskpool.sbr" \
+ "$(INTDIR)\timer.sbr" \
+ "$(INTDIR)\tm.sbr" \
+ "$(INTDIR)\parseint.sbr" \
+ "$(INTDIR)\pool.sbr" \
+ "$(INTDIR)\portset.sbr" \
+ "$(INTDIR)\regex.sbr" \
+ "$(INTDIR)\region.sbr"
+
+"$(OUTDIR)\libisc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=user32.lib advapi32.lib ws2_32.lib $(LIBXML) @OPENSSL_LIB@ @ZLIB_LIB@ /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\libisc.pdb" /map:"$(INTDIR)\libisc.map" /debug @MACHINE@ /def:".\libisc.def" /out:"../../../Build/Debug/libisc.dll" /implib:"$(OUTDIR)\libisc.lib" /pdbtype:sept
+DEF_FILE= \
+ ".\libisc.def"
+LINK32_OBJS= \
+ "$(INTDIR)\app.obj" \
+ "$(INTDIR)\condition.obj" \
+ "$(INTDIR)\dir.obj" \
+ "$(INTDIR)\DLLMain.obj" \
+ "$(INTDIR)\entropy.obj" \
+ "$(INTDIR)\errno.obj" \
+ "$(INTDIR)\errno2result.obj" \
+ "$(INTDIR)\file.obj" \
+ "$(INTDIR)\fsaccess.obj" \
+ "$(INTDIR)\interfaceiter.obj" \
+ "$(INTDIR)\ipv6.obj" \
+ "$(INTDIR)\iterated_hash.obj" \
+ "$(INTDIR)\keyboard.obj" \
+ "$(INTDIR)\meminfo.obj" \
+ "$(INTDIR)\net.obj" \
+ "$(INTDIR)\ntpaths.obj" \
+ "$(INTDIR)\once.obj" \
+ "$(INTDIR)\os.obj" \
+@IF PKCS11
+ "$(INTDIR)\pk11_api.obj" \
+@END PKCS11
+ "$(INTDIR)\resource.obj" \
+ "$(INTDIR)\socket.obj" \
+ "$(INTDIR)\stdio.obj" \
+ "$(INTDIR)\stdtime.obj" \
+ "$(INTDIR)\strerror.obj" \
+ "$(INTDIR)\syslog.obj" \
+ "$(INTDIR)\thread.obj" \
+ "$(INTDIR)\time.obj" \
+ "$(INTDIR)\version.obj" \
+ "$(INTDIR)\win32os.obj" \
+@IF AES
+ "$(INTDIR)\aes.obj" \
+@END AES
+ "$(INTDIR)\assertions.obj" \
+ "$(INTDIR)\backtrace.obj" \
+ "$(INTDIR)\backtrace-emptytbl.obj" \
+ "$(INTDIR)\base32.obj" \
+ "$(INTDIR)\base64.obj" \
+ "$(INTDIR)\bind9.obj" \
+ "$(INTDIR)\buffer.obj" \
+ "$(INTDIR)\bufferlist.obj" \
+ "$(INTDIR)\commandline.obj" \
+ "$(INTDIR)\counter.obj" \
+ "$(INTDIR)\crc64.obj" \
+ "$(INTDIR)\error.obj" \
+ "$(INTDIR)\event.obj" \
+ "$(INTDIR)\hash.obj" \
+ "$(INTDIR)\heap.obj" \
+ "$(INTDIR)\hex.obj" \
+ "$(INTDIR)\hmacmd5.obj" \
+ "$(INTDIR)\hmacsha.obj" \
+ "$(INTDIR)\ht.obj" \
+ "$(INTDIR)\httpd.obj" \
+ "$(INTDIR)\inet_aton.obj" \
+ "$(INTDIR)\inet_ntop.obj" \
+ "$(INTDIR)\inet_pton.obj" \
+ "$(INTDIR)\lex.obj" \
+ "$(INTDIR)\lfsr.obj" \
+ "$(INTDIR)\lib.obj" \
+ "$(INTDIR)\log.obj" \
+ "$(INTDIR)\md5.obj" \
+ "$(INTDIR)\mem.obj" \
+ "$(INTDIR)\msgcat.obj" \
+ "$(INTDIR)\mutexblock.obj" \
+ "$(INTDIR)\netaddr.obj" \
+ "$(INTDIR)\netscope.obj" \
+ "$(INTDIR)\ondestroy.obj" \
+@IF PKCS11
+ "$(INTDIR)\pk11.obj" \
+ "$(INTDIR)\pk11_result.obj" \
+@END PKCS11
+ "$(INTDIR)\quota.obj" \
+ "$(INTDIR)\radix.obj" \
+ "$(INTDIR)\random.obj" \
+ "$(INTDIR)\ratelimiter.obj" \
+ "$(INTDIR)\refcount.obj" \
+ "$(INTDIR)\result.obj" \
+ "$(INTDIR)\rwlock.obj" \
+ "$(INTDIR)\safe.obj" \
+ "$(INTDIR)\serial.obj" \
+ "$(INTDIR)\sha1.obj" \
+ "$(INTDIR)\sha2.obj" \
+ "$(INTDIR)\sockaddr.obj" \
+ "$(INTDIR)\stats.obj" \
+ "$(INTDIR)\string.obj" \
+ "$(INTDIR)\symtab.obj" \
+ "$(INTDIR)\task.obj" \
+ "$(INTDIR)\taskpool.obj" \
+ "$(INTDIR)\timer.obj" \
+ "$(INTDIR)\tm.obj" \
+ "$(INTDIR)\parseint.obj" \
+ "$(INTDIR)\pool.obj" \
+ "$(INTDIR)\portset.obj" \
+ "$(INTDIR)\regex.obj" \
+ "$(INTDIR)\region.obj"
+
+"..\..\..\Build\Debug\libisc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+ $(_VC_MANIFEST_EMBED_DLL)
+
+!ENDIF
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("libisc.dep")
+!INCLUDE "libisc.dep"
+!ELSE
+!MESSAGE Warning: cannot find "libisc.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release" || "$(CFG)" == "libisc - @PLATFORM@ Debug"
+SOURCE=.\app.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\app.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\app.obj" "$(INTDIR)\app.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\condition.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\condition.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\condition.obj" "$(INTDIR)\condition.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\dir.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\dir.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\dir.obj" "$(INTDIR)\dir.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\DLLMain.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\DLLMain.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\DLLMain.obj" "$(INTDIR)\DLLMain.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\entropy.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\entropy.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\entropy.obj" "$(INTDIR)\entropy.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\errno.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\errno.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\errno.obj" "$(INTDIR)\errno.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+
+SOURCE=.\errno2result.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\errno2result.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\errno2result.obj" "$(INTDIR)\errno2result.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\file.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\file.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\file.obj" "$(INTDIR)\file.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\fsaccess.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\fsaccess.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\fsaccess.obj" "$(INTDIR)\fsaccess.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\interfaceiter.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\interfaceiter.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\interfaceiter.obj" "$(INTDIR)\interfaceiter.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\ipv6.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\ipv6.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\ipv6.obj" "$(INTDIR)\ipv6.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+
+SOURCE=.\keyboard.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\keyboard.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\keyboard.obj" "$(INTDIR)\keyboard.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\meminfo.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\meminfo.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\meminfo.obj" "$(INTDIR)\meminfo.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\net.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\net.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\net.obj" "$(INTDIR)\net.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\ntpaths.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\ntpaths.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\ntpaths.obj" "$(INTDIR)\ntpaths.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\once.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\once.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\once.obj" "$(INTDIR)\once.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\os.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\os.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\os.obj" "$(INTDIR)\os.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\pk11_api.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\pk11_api.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\pk11_api.obj" "$(INTDIR)\pk11_api.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\resource.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\resource.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\resource.obj" "$(INTDIR)\resource.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\socket.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\socket.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\socket.obj" "$(INTDIR)\socket.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\stdio.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\stdio.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\stdio.obj" "$(INTDIR)\stdio.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\stdtime.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\stdtime.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\stdtime.obj" "$(INTDIR)\stdtime.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\strerror.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\strerror.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\strerror.obj" "$(INTDIR)\strerror.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\syslog.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\syslog.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\syslog.obj" "$(INTDIR)\syslog.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\thread.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\thread.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\thread.obj" "$(INTDIR)\thread.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\time.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\time.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\time.obj" "$(INTDIR)\time.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\version.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\version.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\version.obj" "$(INTDIR)\version.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\win32os.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\win32os.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\win32os.obj" "$(INTDIR)\win32os.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+@IF AES
+SOURCE=..\aes.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\aes.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\aes.obj" "$(INTDIR)\aes.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+@END AES
+
+SOURCE=..\assertions.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\assertions.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\assertions.obj" "$(INTDIR)\assertions.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\backtrace.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\backtrace.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\backtrace.obj" "$(INTDIR)\backtrace.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\backtrace-emptytbl.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\backtrace-emptytbl.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\backtrace-emptytbl.obj" "$(INTDIR)\backtrace-emptytbl.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\base32.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\base32.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\base32.obj" "$(INTDIR)\base32.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\base64.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\base64.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\base64.obj" "$(INTDIR)\base64.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\bind9.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\bind9.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\bind9.obj" "$(INTDIR)\bind9.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\buffer.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\buffer.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\buffer.obj" "$(INTDIR)\buffer.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\bufferlist.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\bufferlist.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\bufferlist.obj" "$(INTDIR)\bufferlist.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\commandline.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\commandline.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\commandline.obj" "$(INTDIR)\commandline.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\counter.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\counter.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\counter.obj" "$(INTDIR)\counter.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\crc64.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\crc64.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\crc64.obj" "$(INTDIR)\crc64.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\error.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\error.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\error.obj" "$(INTDIR)\error.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\event.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\event.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\event.obj" "$(INTDIR)\event.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\hash.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\hash.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\hash.obj" "$(INTDIR)\hash.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\heap.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\heap.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\heap.obj" "$(INTDIR)\heap.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\hex.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\hex.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\hex.obj" "$(INTDIR)\hex.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\hmacmd5.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\hmacmd5.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\hmacmd5.obj" "$(INTDIR)\hmacmd5.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\hmacsha.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\hmacsha.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\hmacsha.obj" "$(INTDIR)\hmacsha.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\ht.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\ht.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\ht.obj" "$(INTDIR)\ht.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\httpd.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\httpd.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\httpd.obj" "$(INTDIR)\httpd.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\inet_aton.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\inet_aton.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\inet_aton.obj" "$(INTDIR)\inet_aton.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\inet_ntop.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\inet_ntop.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\inet_ntop.obj" "$(INTDIR)\inet_ntop.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\inet_pton.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\inet_pton.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\inet_pton.obj" "$(INTDIR)\inet_pton.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\iterated_hash.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\iterated_hash.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\iterated_hash.obj" "$(INTDIR)\iterated_hash.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\lex.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\lex.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\lex.obj" "$(INTDIR)\lex.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\lfsr.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\lfsr.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\lfsr.obj" "$(INTDIR)\lfsr.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\lib.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\lib.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\lib.obj" "$(INTDIR)\lib.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\log.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\log.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\log.obj" "$(INTDIR)\log.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\md5.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\md5.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\md5.obj" "$(INTDIR)\md5.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\mem.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\mem.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\mem.obj" "$(INTDIR)\mem.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\nls\msgcat.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\msgcat.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\msgcat.obj" "$(INTDIR)\msgcat.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\mutexblock.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\mutexblock.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\mutexblock.obj" "$(INTDIR)\mutexblock.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\netaddr.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\netaddr.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\netaddr.obj" "$(INTDIR)\netaddr.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\netscope.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\netscope.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\netscope.obj" "$(INTDIR)\netscope.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\ondestroy.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\ondestroy.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\ondestroy.obj" "$(INTDIR)\ondestroy.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\parseint.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\parseint.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\parseint.obj" "$(INTDIR)\parseint.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\pk11.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\pk11.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\pk11.obj" "$(INTDIR)\pk11.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\pk11_result.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\pk11_result.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\pk11_result.obj" "$(INTDIR)\pk11_result.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\pool.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\pool.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\pool.obj" "$(INTDIR)\pool.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\portset.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\portset.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\portset.obj" "$(INTDIR)\portset.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\quota.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\quota.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\quota.obj" "$(INTDIR)\quota.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\radix.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\radix.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\radix.obj" "$(INTDIR)\radix.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\random.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\random.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\random.obj" "$(INTDIR)\random.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\ratelimiter.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\ratelimiter.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\ratelimiter.obj" "$(INTDIR)\ratelimiter.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\refcount.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\refcount.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\refcount.obj" "$(INTDIR)\refcount.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\regex.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\regex.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\regex.obj" "$(INTDIR)\regex.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+
+SOURCE=..\region.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\region.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\region.obj" "$(INTDIR)\region.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\result.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\result.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\result.obj" "$(INTDIR)\result.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\rwlock.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\rwlock.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\rwlock.obj" "$(INTDIR)\rwlock.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\safe.c
+
+!IF "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\safe.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\safe.obj" "$(INTDIR)\safe.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\serial.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\serial.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\serial.obj" "$(INTDIR)\serial.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\sha1.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\sha1.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\sha1.obj" "$(INTDIR)\sha1.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\sha2.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\sha2.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\sha2.obj" "$(INTDIR)\sha2.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\sockaddr.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\sockaddr.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\sockaddr.obj" "$(INTDIR)\sockaddr.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\stats.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\stats.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\stats.obj" "$(INTDIR)\stats.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\string.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\string.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\string.obj" "$(INTDIR)\string.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\symtab.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\symtab.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\symtab.obj" "$(INTDIR)\symtab.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\task.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\task.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\task.obj" "$(INTDIR)\task.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\taskpool.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\taskpool.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\taskpool.obj" "$(INTDIR)\taskpool.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\timer.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\timer.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\timer.obj" "$(INTDIR)\timer.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\tm.c
+
+!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\tm.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\tm.obj" "$(INTDIR)\tm.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+
+!ENDIF
+
+####################################################
+# Commands to generate initial empty manifest file and the RC file
+# that references it, and for generating the .res file:
+
+$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc
+
+$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest
+ type <<$@
+#include <winuser.h>
+1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest"
+<< KEEP
+
+$(_VC_MANIFEST_BASENAME).auto.manifest :
+ type <<$@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+</assembly>
+<< KEEP
diff --git a/lib/isc/win32/libisc.vcxproj.filters.in b/lib/isc/win32/libisc.vcxproj.filters.in
new file mode 100644
index 0000000..d6a5234
--- /dev/null
+++ b/lib/isc/win32/libisc.vcxproj.filters.in
@@ -0,0 +1,675 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Library Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Win32 Source Files">
+ <UniqueIdentifier>{289562c2-1bdd-4582-b6bd-3f598ee23cbd}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Win32 Header Files">
+ <UniqueIdentifier>{d03c3e6a-e78e-4a01-bd77-64c839b1adfe}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Library Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="libisc.def" />
+ </ItemGroup>
+ <ItemGroup>
+@IF AES
+ <ClInclude Include="..\include\isc\aes.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+@END AES
+ <ClInclude Include="..\include\isc\app.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\assertions.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\backtrace.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\base32.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\base64.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\bind9.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\boolean.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\buffer.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\bufferlist.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\commandline.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\counter.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\crc64.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\entropy.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\errno.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\error.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\event.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\eventclass.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\file.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\formatcheck.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\fsaccess.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\hash.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\heap.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\hex.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\hmacmd5.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\hmacsha.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\ht.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\httpd.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\int.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\interfaceiter.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\iterated_hash.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\json.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\lang.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\lex.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\lfsr.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\lib.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\list.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\log.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\magic.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\md5.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\mem.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\meminfo.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\msgcat.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\msgs.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\mutexblock.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\netaddr.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\netscope.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\ondestroy.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\os.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\parseint.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\pool.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\portset.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\print.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\queue.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\quota.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\radix.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\random.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\ratelimiter.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\refcount.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\regex.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\region.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\resource.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\result.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\resultclass.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\rwlock.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\safe.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\serial.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\sha1.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\sha2.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\sockaddr.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\socket.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\stats.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\stdio.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\stdlib.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\string.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\symtab.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\task.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\taskpool.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\timer.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\tm.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\types.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\util.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\version.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\xml.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+@IF PKCS11
+ <ClInclude Include="..\include\pk11\constants.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\pk11\internal.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\pk11\pk11.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\pk11\result.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\pkcs11\pkcs11.h">
+ <Filter>Pkcs11 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\pkcs11\pkcs11f.h">
+ <Filter>Pkcs11 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\pkcs11\pkcs11t.h">
+ <Filter>Pkcs11 Header Files</Filter>
+ </ClInclude>
+@END PKCS11
+ <ClInclude Include="include\isc\bind_registry.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\bindevt.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\condition.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\dir.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\ipv6.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\keyboard.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\mutex.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\net.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\netdb.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\ntgroups.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\ntpaths.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\offset.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\once.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\platform.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\stat.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\stdtime.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\strerror.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\syslog.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\thread.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\time.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\win32os.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="errno2result.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="syslog.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="unistd.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+@IF PKCS11
+ <ClInclude Include="include\pkcs11\cryptoki.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+@END PKCS11
+@IF ATOMIC
+ <ClInclude Include="include\isc\atomic.h">
+@ELSE ATOMIC
+ <ClInclude Include="..\noatomic\include\isc\atomic.h">
+@END ATOMIC
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\config.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\versions.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="app.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="condition.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dir.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DLLMain.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="entropy.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="errno.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="errno2result.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="file.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="fsaccess.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="interfaceiter.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ipv6.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="keyboard.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="meminfo.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="net.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ntpaths.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="once.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="os.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="resource.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="socket.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stdio.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stdtime.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="strerror.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="syslog.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="thread.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="time.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="version.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="win32os.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+@IF PKCS11
+ <ClCompile Include="pk11_api.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+@END PKCS11
+@IF AES
+ <ClCompile Include="..\aes.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+@END AES
+ <ClCompile Include="..\assertions.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\backtrace.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\backtrace-emptytbl.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\base32.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\base64.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\bind9.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\buffer.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\bufferlist.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\commandline.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\counter.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\crc64.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\error.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\event.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\hash.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\heap.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\hex.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\hmacmd5.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\hmacsha.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ht.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\httpd.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\inet_aton.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\inet_ntop.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\inet_pton.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\iterated_hash.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\lex.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\lfsr.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\lib.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\log.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\md5.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\mem.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nls\msgcat.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\mutexblock.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\netaddr.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\netscope.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ondestroy.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\parseint.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\pool.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\portset.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\quota.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\radix.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\random.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ratelimiter.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\refcount.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\regex.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\region.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\result.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\rwlock.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\safe.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\serial.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\sha1.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\sha2.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\sockaddr.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\stats.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\string.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\symtab.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\task.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\taskpool.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\timer.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\tm.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+@IF PKCS11
+ <ClCompile Include="..\pk11.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\pk11_result.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+@END PKCS11
+ </ItemGroup>
+</Project>
diff --git a/lib/isc/win32/libisc.vcxproj.in b/lib/isc/win32/libisc.vcxproj.in
new file mode 100644
index 0000000..fb9222a
--- /dev/null
+++ b/lib/isc/win32/libisc.vcxproj.in
@@ -0,0 +1,530 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|@PLATFORM@">
+ <Configuration>Debug</Configuration>
+ <Platform>@PLATFORM@</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|@PLATFORM@">
+ <Configuration>Release</Configuration>
+ <Platform>@PLATFORM@</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{3840E563-D180-4761-AA9C-E6155F02EAFF}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>libisc</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>..\..\..\Build\$(Configuration)\</OutDir>
+ <IntDir>.\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>..\..\..\Build\$(Configuration)\</OutDir>
+ <IntDir>.\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+@IF PKCS11
+ <PreprocessorDefinitions>BIND9;@CRYPTO@@PK11_LIB_LOCATION@WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+@ELSE PKCS11
+ <PreprocessorDefinitions>BIND9;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+@END PKCS11
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeaderOutputFile>.\$(Configuration)\$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\$(Configuration)\</AssemblerListingLocation>
+ <ObjectFileName>.\$(Configuration)\</ObjectFileName>
+ <ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <BrowseInformation>true</BrowseInformation>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
+ <AdditionalDependencies>@LIBXML2_LIB@@OPENSSL_LIB@@ZLIB_LIB@ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
+ <ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
+ </Link>
+ <PreBuildEvent>
+ <Command>cd ..\..\..\win32utils
+
+if NOT Exist ..\Build mkdir ..\Build
+if NOT Exist ..\Build\Debug mkdir ..\Build\Debug
+
+echo Copying COPYRIGHT notice.
+
+copy ..\COPYRIGHT ..\Build\Debug
+
+@IF OPENSSL
+echo Copying the OpenSSL DLL and LICENSE.
+
+copy @OPENSSL_DLL@ ..\Build\Debug\
+copy @OPENSSL_PATH@\LICENSE ..\Build\Debug\OpenSSL-LICENSE
+@END OPENSSL
+
+@IF LIBXML2
+echo Copying the libxml DLL.
+
+copy @LIBXML2_DLL@ ..\Build\Debug\
+@END LIBXML2
+
+@IF GSSAPI
+echo Copying the GSSAPI and KRB5 DLLs.
+
+copy @GSSAPI_DLL@ ..\Build\Debug\
+copy @KRB5_DLL@ ..\Build\Debug\
+copy @COMERR_DLL@ ..\Build\Debug\
+copy @K5SPRT_DLL@ ..\Build\Debug\
+copy @WSHELP_DLL@ ..\Build\Debug\
+@END GSSAPI
+
+@IF GEOIP
+echo Copying the GeoIP DLL.
+
+copy @GEOIP_DLL@ ..\Build\Debug\
+@END GEOIP
+
+@IF IDNKIT
+echo Copying the IDN kit DLL.
+
+copy @IDN_DLL@ ..\Build\Debug\
+copy @ICONV_DLL@ ..\Build\Debug\
+@END IDNKIT
+
+@IF ZLIB
+echo Copying the zlib DLL.
+
+copy @ZLIB_DLL@ ..\Build\Debug\
+@END ZLIB
+
+echo Copying Visual C x86 Redistributable Installer.
+
+copy /Y @VCREDIST_PATH@ ..\Build\Debug\
+
+echo Copying install files (flags and file list).
+
+copy InstallFlags ..\Build\Debug\
+copy InstallFiles ..\Build\Debug\
+
+</Command>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>@INTRINSIC@</IntrinsicFunctions>
+@IF PKCS11
+ <PreprocessorDefinitions>BIND9;@CRYPTO@@PK11_LIB_LOCATION@WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+@ELSE PKCS11
+ <PreprocessorDefinitions>BIND9;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+@END PKCS11
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <StringPooling>true</StringPooling>
+ <PrecompiledHeaderOutputFile>.\$(Configuration)\$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\$(Configuration)\</AssemblerListingLocation>
+ <ObjectFileName>.\$(Configuration)\</ObjectFileName>
+ <ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
+ <AdditionalDependencies>@LIBXML2_LIB@@OPENSSL_LIB@@ZLIB_LIB@ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
+ <ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
+ <LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
+ </Link>
+ <PreBuildEvent>
+ <Command>cd ..\..\..\win32utils
+
+if NOT Exist ..\Build mkdir ..\Build
+if NOT Exist ..\Build\Release mkdir ..\Build\Release
+
+echo Copying the ARM and the Installation Notes.
+
+copy ..\COPYRIGHT ..\Build\Release
+copy ..\README ..\Build\Release
+copy ..\HISTORY ..\Build\Release
+copy readme1st.txt ..\Build\Release
+copy index.html ..\Build\Release
+copy ..\doc\arm\*.html ..\Build\Release
+copy ..\doc\arm\notes.pdf ..\Build\Release
+copy ..\doc\arm\Bv9ARM.pdf ..\Build\Release
+copy ..\CHANGES ..\Build\Release
+if Exist ..\CHANGES.SE copy ..\CHANGES.SE ..\Build\Release
+copy ..\FAQ ..\Build\Release
+
+echo Copying the standalone manual pages.
+
+copy ..\bin\named\named.html ..\Build\Release
+copy ..\bin\named\named.conf.html ..\Build\Release
+copy ..\bin\named\lwresd.html ..\Build\Release
+copy ..\bin\rndc\*.html ..\Build\Release
+copy ..\bin\confgen\*.html ..\Build\Release
+copy ..\bin\dig\*.html ..\Build\Release
+copy ..\bin\delv\*.html ..\Build\Release
+copy ..\bin\nsupdate\*.html ..\Build\Release
+copy ..\bin\check\*.html ..\Build\Release
+copy ..\bin\dnssec\dnssec-keygen.html ..\Build\Release
+copy ..\bin\dnssec\dnssec-signzone.html ..\Build\Release
+copy ..\bin\dnssec\dnssec-dsfromkey.html ..\Build\Release
+copy ..\bin\dnssec\dnssec-keyfromlabel.html ..\Build\Release
+copy ..\bin\dnssec\dnssec-settime.html ..\Build\Release
+copy ..\bin\dnssec\dnssec-revoke.html ..\Build\Release
+copy ..\bin\dnssec\dnssec-verify.html ..\Build\Release
+copy ..\bin\dnssec\dnssec-importkey.html ..\Build\Release
+@IF PYTHON
+copy ..\bin\python\dnssec-checkds.html ..\Build\Release
+copy ..\bin\python\dnssec-coverage.html ..\Build\Release
+copy ..\bin\python\dnssec-keymgr.html ..\Build\Release
+@END PYTHON
+@IF PKCS11
+copy ..\bin\pkcs11\pkcs11-keygen.html ..\Build\Release
+copy ..\bin\pkcs11\pkcs11-list.html ..\Build\Release
+copy ..\bin\pkcs11\pkcs11-destroy.html ..\Build\Release
+copy ..\bin\pkcs11\pkcs11-tokens.html ..\Build\Release
+@END PKCS11
+copy ..\bin\tools\arpaname.html ..\Build\Release
+copy ..\bin\tools\genrandom.html ..\Build\Release
+copy ..\bin\tools\isc-hmac-fixup.html ..\Build\Release
+copy ..\bin\tools\named-journalprint.html ..\Build\Release
+copy ..\bin\tools\named-rrchecker.html ..\Build\Release
+copy ..\bin\tools\nsec3hash.html ..\Build\Release
+copy ..\bin\tools\mdig.html ..\Build\Release
+
+echo Copying the migration notes.
+
+copy ..\doc\misc\migration ..\Build\Release
+copy ..\doc\misc\migration-4to9 ..\Build\Release
+
+@IF OPENSSL
+echo Copying the OpenSSL DLL and LICENSE.
+
+copy @OPENSSL_DLL@ ..\Build\Release\
+copy @OPENSSL_PATH@\LICENSE ..\Build\Release\OpenSSL-LICENSE
+@END OPENSSL
+
+@IF LIBXML2
+echo Copying the libxml DLL.
+
+copy @LIBXML2_DLL@ ..\Build\Release\
+@END LIBXML2
+
+@IF GSSAPI
+echo Copying the GSSAPI and KRB5 DLLs.
+
+copy @GSSAPI_DLL@ ..\Build\Release\
+copy @KRB5_DLL@ ..\Build\Release\
+copy @COMERR_DLL@ ..\Build\Release\
+copy @K5SPRT_DLL@ ..\Build\Release\
+copy @WSHELP_DLL@ ..\Build\Release\
+@END GSSAPI
+
+@IF GEOIP
+echo Copying the GeoIP DLL.
+
+copy @GEOIP_DLL@ ..\Build\Release\
+@END GEOIP
+
+@IF IDNKIT
+echo Copying the IDN kit DLL.
+
+copy @IDN_DLL@ ..\Build\Release\
+copy @ICONV_DLL@ ..\Build\Release\
+@END IDNKIT
+
+@IF ZLIB
+echo Copying the zlib DLL.
+
+copy @ZLIB_DLL@ ..\Build\Release\
+@END ZLIB
+
+echo Copying Visual C x86 Redistributable Installer.
+
+copy /Y @VCREDIST_PATH@ ..\Build\Release\
+
+echo Copying install files (flags and file list).
+
+copy InstallFlags ..\Build\Release\
+copy InstallFiles ..\Build\Release\
+
+</Command>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <None Include="libisc.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\config.h" />
+@IF AES
+ <ClInclude Include="..\include\isc\aes.h" />
+@END AES
+ <ClInclude Include="..\include\isc\app.h" />
+ <ClInclude Include="..\include\isc\assertions.h" />
+ <ClInclude Include="..\include\isc\backtrace.h" />
+ <ClInclude Include="..\include\isc\base32.h" />
+ <ClInclude Include="..\include\isc\base64.h" />
+ <ClInclude Include="..\include\isc\bind9.h" />
+ <ClInclude Include="..\include\isc\boolean.h" />
+ <ClInclude Include="..\include\isc\buffer.h" />
+ <ClInclude Include="..\include\isc\bufferlist.h" />
+ <ClInclude Include="..\include\isc\commandline.h" />
+ <ClInclude Include="..\include\isc\counter.h" />
+ <ClInclude Include="..\include\isc\crc64.h" />
+ <ClInclude Include="..\include\isc\entropy.h" />
+ <ClInclude Include="..\include\isc\errno.h" />
+ <ClInclude Include="..\include\isc\error.h" />
+ <ClInclude Include="..\include\isc\event.h" />
+ <ClInclude Include="..\include\isc\eventclass.h" />
+ <ClInclude Include="..\include\isc\file.h" />
+ <ClInclude Include="..\include\isc\formatcheck.h" />
+ <ClInclude Include="..\include\isc\fsaccess.h" />
+ <ClInclude Include="..\include\isc\hash.h" />
+ <ClInclude Include="..\include\isc\heap.h" />
+ <ClInclude Include="..\include\isc\hex.h" />
+ <ClInclude Include="..\include\isc\hmacmd5.h" />
+ <ClInclude Include="..\include\isc\hmacsha.h" />
+ <ClInclude Include="..\include\isc\ht.h" />
+ <ClInclude Include="..\include\isc\httpd.h" />
+ <ClInclude Include="..\include\isc\int.h" />
+ <ClInclude Include="..\include\isc\interfaceiter.h" />
+ <ClInclude Include="..\include\isc\iterated_hash.h" />
+ <ClInclude Include="..\include\isc\json.h" />
+ <ClInclude Include="..\include\isc\lang.h" />
+ <ClInclude Include="..\include\isc\lex.h" />
+ <ClInclude Include="..\include\isc\lfsr.h" />
+ <ClInclude Include="..\include\isc\lib.h" />
+ <ClInclude Include="..\include\isc\list.h" />
+ <ClInclude Include="..\include\isc\log.h" />
+ <ClInclude Include="..\include\isc\magic.h" />
+ <ClInclude Include="..\include\isc\md5.h" />
+ <ClInclude Include="..\include\isc\mem.h" />
+ <ClInclude Include="..\include\isc\meminfo.h" />
+ <ClInclude Include="..\include\isc\msgcat.h" />
+ <ClInclude Include="..\include\isc\msgs.h" />
+ <ClInclude Include="..\include\isc\mutexblock.h" />
+ <ClInclude Include="..\include\isc\netaddr.h" />
+ <ClInclude Include="..\include\isc\netscope.h" />
+ <ClInclude Include="..\include\isc\ondestroy.h" />
+ <ClInclude Include="..\include\isc\os.h" />
+ <ClInclude Include="..\include\isc\parseint.h" />
+ <ClInclude Include="..\include\isc\pool.h" />
+ <ClInclude Include="..\include\isc\portset.h" />
+ <ClInclude Include="..\include\isc\print.h" />
+ <ClInclude Include="..\include\isc\queue.h" />
+ <ClInclude Include="..\include\isc\quota.h" />
+ <ClInclude Include="..\include\isc\radix.h" />
+ <ClInclude Include="..\include\isc\random.h" />
+ <ClInclude Include="..\include\isc\ratelimiter.h" />
+ <ClInclude Include="..\include\isc\refcount.h" />
+ <ClInclude Include="..\include\isc\regex.h" />
+ <ClInclude Include="..\include\isc\region.h" />
+ <ClInclude Include="..\include\isc\resource.h" />
+ <ClInclude Include="..\include\isc\result.h" />
+ <ClInclude Include="..\include\isc\resultclass.h" />
+ <ClInclude Include="..\include\isc\rwlock.h" />
+ <ClInclude Include="..\include\isc\safe.h" />
+ <ClInclude Include="..\include\isc\serial.h" />
+ <ClInclude Include="..\include\isc\sha1.h" />
+ <ClInclude Include="..\include\isc\sha2.h" />
+ <ClInclude Include="..\include\isc\sockaddr.h" />
+ <ClInclude Include="..\include\isc\socket.h" />
+ <ClInclude Include="..\include\isc\stats.h" />
+ <ClInclude Include="..\include\isc\stdio.h" />
+ <ClInclude Include="..\include\isc\stdlib.h" />
+ <ClInclude Include="..\include\isc\string.h" />
+ <ClInclude Include="..\include\isc\symtab.h" />
+ <ClInclude Include="..\include\isc\task.h" />
+ <ClInclude Include="..\include\isc\taskpool.h" />
+ <ClInclude Include="..\include\isc\timer.h" />
+ <ClInclude Include="..\include\isc\tm.h" />
+ <ClInclude Include="..\include\isc\types.h" />
+ <ClInclude Include="..\include\isc\util.h" />
+ <ClInclude Include="..\include\isc\version.h" />
+ <ClInclude Include="..\include\isc\xml.h" />
+@IF PKCS11
+ <ClInclude Include="..\include\pk11\constants.h" />
+ <ClInclude Include="..\include\pk11\internal.h" />
+ <ClInclude Include="..\include\pk11\pk11.h" />
+ <ClInclude Include="..\include\pk11\result.h" />
+ <ClInclude Include="..\include\pkcs11\pkcs11.h" />
+ <ClInclude Include="..\include\pkcs11\pkcs11f.h" />
+ <ClInclude Include="..\include\pkcs11\pkcs11t.h" />
+@END PKCS11
+@IF ATOMIC
+ <ClInclude Include="include\isc\atomic.h" />
+@ELSE ATOMIC
+ <ClInclude Include="..\noatomic\include\isc\atomic.h" />
+@END ATOMIC
+ <ClInclude Include="errno2result.h" />
+ <ClInclude Include="include\isc\bindevt.h" />
+ <ClInclude Include="include\isc\bind_registry.h" />
+ <ClInclude Include="include\isc\condition.h" />
+ <ClInclude Include="include\isc\dir.h" />
+ <ClInclude Include="include\isc\ipv6.h" />
+ <ClInclude Include="include\isc\keyboard.h" />
+ <ClInclude Include="include\isc\mutex.h" />
+ <ClInclude Include="include\isc\net.h" />
+ <ClInclude Include="include\isc\netdb.h" />
+ <ClInclude Include="include\isc\ntgroups.h" />
+ <ClInclude Include="include\isc\ntpaths.h" />
+ <ClInclude Include="include\isc\offset.h" />
+ <ClInclude Include="include\isc\once.h" />
+ <ClInclude Include="include\isc\platform.h" />
+ <ClInclude Include="include\isc\stat.h" />
+ <ClInclude Include="include\isc\stdtime.h" />
+ <ClInclude Include="include\isc\strerror.h" />
+ <ClInclude Include="include\isc\syslog.h" />
+ <ClInclude Include="include\isc\thread.h" />
+ <ClInclude Include="include\isc\time.h" />
+ <ClInclude Include="include\isc\win32os.h" />
+ <ClInclude Include="syslog.h" />
+ <ClInclude Include="unistd.h" />
+@IF PKCS11
+ <ClInclude Include="include\pkcs11\cryptoki.h" />
+@END PKCS11
+ <ClInclude Include="..\..\versions.h" />
+ </ItemGroup>
+ <ItemGroup>
+@IF AES
+ <ClCompile Include="..\aes.c" />
+@END AES
+ <ClCompile Include="..\assertions.c" />
+ <ClCompile Include="..\backtrace-emptytbl.c" />
+ <ClCompile Include="..\backtrace.c" />
+ <ClCompile Include="..\base32.c" />
+ <ClCompile Include="..\base64.c" />
+ <ClCompile Include="..\bind9.c" />
+ <ClCompile Include="..\buffer.c" />
+ <ClCompile Include="..\bufferlist.c" />
+ <ClCompile Include="..\commandline.c" />
+ <ClCompile Include="..\counter.c" />
+ <ClCompile Include="..\crc64.c" />
+ <ClCompile Include="..\error.c" />
+ <ClCompile Include="..\event.c" />
+ <ClCompile Include="..\hash.c" />
+ <ClCompile Include="..\heap.c" />
+ <ClCompile Include="..\hex.c" />
+ <ClCompile Include="..\hmacmd5.c" />
+ <ClCompile Include="..\hmacsha.c" />
+ <ClCompile Include="..\ht.c" />
+ <ClCompile Include="..\httpd.c" />
+ <ClCompile Include="..\inet_aton.c" />
+ <ClCompile Include="..\inet_ntop.c" />
+ <ClCompile Include="..\inet_pton.c" />
+ <ClCompile Include="..\iterated_hash.c" />
+ <ClCompile Include="..\lex.c" />
+ <ClCompile Include="..\lfsr.c" />
+ <ClCompile Include="..\lib.c" />
+ <ClCompile Include="..\log.c" />
+ <ClCompile Include="..\md5.c" />
+ <ClCompile Include="..\mem.c" />
+ <ClCompile Include="..\mutexblock.c" />
+ <ClCompile Include="..\netaddr.c" />
+ <ClCompile Include="..\netscope.c" />
+ <ClCompile Include="..\nls\msgcat.c" />
+ <ClCompile Include="..\ondestroy.c" />
+ <ClCompile Include="..\parseint.c" />
+ <ClCompile Include="..\pool.c" />
+ <ClCompile Include="..\portset.c" />
+ <ClCompile Include="..\quota.c" />
+ <ClCompile Include="..\radix.c" />
+ <ClCompile Include="..\random.c" />
+ <ClCompile Include="..\ratelimiter.c" />
+ <ClCompile Include="..\refcount.c" />
+ <ClCompile Include="..\regex.c" />
+ <ClCompile Include="..\region.c" />
+ <ClCompile Include="..\result.c" />
+ <ClCompile Include="..\rwlock.c" />
+ <ClCompile Include="..\safe.c" />
+ <ClCompile Include="..\serial.c" />
+ <ClCompile Include="..\sha1.c" />
+ <ClCompile Include="..\sha2.c" />
+ <ClCompile Include="..\sockaddr.c" />
+ <ClCompile Include="..\stats.c" />
+ <ClCompile Include="..\string.c" />
+ <ClCompile Include="..\symtab.c" />
+ <ClCompile Include="..\task.c" />
+ <ClCompile Include="..\taskpool.c" />
+ <ClCompile Include="..\timer.c" />
+ <ClCompile Include="..\tm.c" />
+@IF PKCS11
+ <ClCompile Include="..\pk11.c" />
+ <ClCompile Include="..\pk11_result.c" />
+@END PKCS11
+ <ClCompile Include="app.c" />
+ <ClCompile Include="condition.c" />
+ <ClCompile Include="dir.c" />
+ <ClCompile Include="DLLMain.c" />
+ <ClCompile Include="entropy.c" />
+ <ClCompile Include="errno.c" />
+ <ClCompile Include="errno2result.c" />
+ <ClCompile Include="file.c" />
+ <ClCompile Include="fsaccess.c" />
+ <ClCompile Include="interfaceiter.c" />
+ <ClCompile Include="ipv6.c" />
+ <ClCompile Include="keyboard.c" />
+ <ClCompile Include="meminfo.c" />
+ <ClCompile Include="net.c" />
+ <ClCompile Include="ntpaths.c" />
+ <ClCompile Include="once.c" />
+ <ClCompile Include="os.c" />
+ <ClCompile Include="resource.c" />
+ <ClCompile Include="socket.c" />
+ <ClCompile Include="stdio.c" />
+ <ClCompile Include="stdtime.c" />
+ <ClCompile Include="strerror.c" />
+ <ClCompile Include="syslog.c" />
+ <ClCompile Include="thread.c" />
+ <ClCompile Include="time.c" />
+ <ClCompile Include="version.c" />
+ <ClCompile Include="win32os.c" />
+@IF PKCS11
+ <ClCompile Include="pk11_api.c" />
+@END PKCS11
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/lib/isc/win32/libisc.vcxproj.user b/lib/isc/win32/libisc.vcxproj.user
new file mode 100644
index 0000000..695b5c7
--- /dev/null
+++ b/lib/isc/win32/libisc.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project> \ No newline at end of file
diff --git a/lib/isc/win32/meminfo.c b/lib/isc/win32/meminfo.c
new file mode 100644
index 0000000..51077f6
--- /dev/null
+++ b/lib/isc/win32/meminfo.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <windows.h>
+
+#include <isc/meminfo.h>
+
+uint64_t
+isc_meminfo_totalphys(void) {
+ MEMORYSTATUSEX statex;
+
+ statex.dwLength = sizeof(statex);
+ GlobalMemoryStatusEx(&statex);
+ return ((uint64_t)statex.ullTotalPhys);
+}
diff --git a/lib/isc/win32/net.c b/lib/isc/win32/net.c
new file mode 100644
index 0000000..c49bb6b
--- /dev/null
+++ b/lib/isc/win32/net.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <isc/log.h>
+#include <isc/msgs.h>
+#include <isc/net.h>
+#include <isc/once.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/*%
+ * Definitions about UDP port range specification. This is a total mess of
+ * portability variants: some use sysctl (but the sysctl names vary), some use
+ * system-specific interfaces, some have the same interface for IPv4 and IPv6,
+ * some separate them, etc...
+ */
+
+/*%
+ * The last resort defaults: use all non well known port space
+ */
+#ifndef ISC_NET_PORTRANGELOW
+#define ISC_NET_PORTRANGELOW 1024
+#endif /* ISC_NET_PORTRANGELOW */
+#ifndef ISC_NET_PORTRANGEHIGH
+#define ISC_NET_PORTRANGEHIGH 65535
+#endif /* ISC_NET_PORTRANGEHIGH */
+
+#if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRANY)
+const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
+#endif
+
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_once_t once_ipv6only = ISC_ONCE_INIT;
+static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
+static isc_result_t ipv4_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
+
+void InitSockets(void);
+
+static isc_result_t
+try_proto(int domain) {
+ SOCKET s;
+ char strbuf[ISC_STRERRORSIZE];
+ int errval;
+
+ s = socket(domain, SOCK_STREAM, IPPROTO_TCP);
+ if (s == INVALID_SOCKET) {
+ errval = WSAGetLastError();
+ switch (errval) {
+ case WSAEAFNOSUPPORT:
+ case WSAEPROTONOSUPPORT:
+ case WSAEINVAL:
+ return (ISC_R_NOTFOUND);
+ default:
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ closesocket(s);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+initialize_action(void) {
+ InitSockets();
+ ipv4_result = try_proto(PF_INET);
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ ipv6_result = try_proto(PF_INET6);
+#endif
+#endif
+#endif
+}
+
+static void
+initialize(void) {
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_net_probeipv4(void) {
+ initialize();
+ return (ipv4_result);
+}
+
+isc_result_t
+isc_net_probeipv6(void) {
+ initialize();
+ return (ipv6_result);
+}
+
+isc_result_t
+isc_net_probeunix(void) {
+ return (ISC_R_NOTFOUND);
+}
+
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+static void
+try_ipv6only(void) {
+#ifdef IPV6_V6ONLY
+ SOCKET s;
+ int on;
+ char strbuf[ISC_STRERRORSIZE];
+#endif
+ isc_result_t result;
+
+ result = isc_net_probeipv6();
+ if (result != ISC_R_SUCCESS) {
+ ipv6only_result = result;
+ return;
+ }
+
+#ifndef IPV6_V6ONLY
+ ipv6only_result = ISC_R_NOTFOUND;
+ return;
+#else
+ /* check for TCP sockets */
+ s = socket(PF_INET6, SOCK_STREAM, 0);
+ if (s == INVALID_SOCKET) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ ipv6only_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on,
+ sizeof(on)) < 0) {
+ ipv6only_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ closesocket(s);
+
+ /* check for UDP sockets */
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s == INVALID_SOCKET) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ ipv6only_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on,
+ sizeof(on)) < 0) {
+ ipv6only_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ ipv6only_result = ISC_R_SUCCESS;
+
+close:
+ closesocket(s);
+ return;
+#endif /* IPV6_V6ONLY */
+}
+
+static void
+initialize_ipv6only(void) {
+ RUNTIME_CHECK(isc_once_do(&once_ipv6only,
+ try_ipv6only) == ISC_R_SUCCESS);
+}
+
+#ifdef __notyet__
+/*
+ * XXXMPA requires win32/socket.c to be updated to support
+ * WSASendMsg and WSARecvMsg which are themselves Winsock
+ * and compiler version dependent.
+ */
+static void
+try_ipv6pktinfo(void) {
+ SOCKET s;
+ int on;
+ char strbuf[ISC_STRERRORSIZE];
+ isc_result_t result;
+ int optname;
+
+ result = isc_net_probeipv6();
+ if (result != ISC_R_SUCCESS) {
+ ipv6pktinfo_result = result;
+ return;
+ }
+
+ /* we only use this for UDP sockets */
+ s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == INVALID_SOCKET) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ ipv6pktinfo_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+#ifdef IPV6_RECVPKTINFO
+ optname = IPV6_RECVPKTINFO;
+#else
+ optname = IPV6_PKTINFO;
+#endif
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, optname, (const char *) &on,
+ sizeof(on)) < 0) {
+ ipv6pktinfo_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ ipv6pktinfo_result = ISC_R_SUCCESS;
+
+close:
+ closesocket(s);
+ return;
+}
+
+static void
+initialize_ipv6pktinfo(void) {
+ RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
+ try_ipv6pktinfo) == ISC_R_SUCCESS);
+}
+#endif /* __notyet__ */
+#endif /* WANT_IPV6 */
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+
+isc_result_t
+isc_net_probe_ipv6only(void) {
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+ initialize_ipv6only();
+#else
+ ipv6only_result = ISC_R_NOTFOUND;
+#endif
+#endif
+ return (ipv6only_result);
+}
+
+isc_result_t
+isc_net_probe_ipv6pktinfo(void) {
+#ifdef __notyet__
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+ initialize_ipv6pktinfo();
+#else
+ ipv6pktinfo_result = ISC_R_NOTFOUND;
+#endif
+#endif
+#endif /* __notyet__ */
+ return (ipv6pktinfo_result);
+}
+
+isc_result_t
+isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
+ int result = ISC_R_FAILURE;
+
+ REQUIRE(low != NULL && high != NULL);
+
+ UNUSED(af);
+
+ if (result != ISC_R_SUCCESS) {
+ *low = ISC_NET_PORTRANGELOW;
+ *high = ISC_NET_PORTRANGEHIGH;
+ }
+
+ return (ISC_R_SUCCESS); /* we currently never fail in this function */
+}
+
+void
+isc_net_disableipv4(void) {
+ initialize();
+ if (ipv4_result == ISC_R_SUCCESS)
+ ipv4_result = ISC_R_DISABLED;
+}
+
+void
+isc_net_disableipv6(void) {
+ initialize();
+ if (ipv6_result == ISC_R_SUCCESS)
+ ipv6_result = ISC_R_DISABLED;
+}
+
+void
+isc_net_enableipv4(void) {
+ initialize();
+ if (ipv4_result == ISC_R_DISABLED)
+ ipv4_result = ISC_R_SUCCESS;
+}
+
+void
+isc_net_enableipv6(void) {
+ initialize();
+ if (ipv6_result == ISC_R_DISABLED)
+ ipv6_result = ISC_R_SUCCESS;
+}
+
+unsigned int
+isc_net_probedscp(void) {
+ return (0);
+}
diff --git a/lib/isc/win32/netdb.h b/lib/isc/win32/netdb.h
new file mode 100644
index 0000000..a9398c8
--- /dev/null
+++ b/lib/isc/win32/netdb.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef NETDB_H
+#define NETDB_H 1
+
+#include <stddef.h>
+#include <winsock2.h>
+
+/*
+ * Define if <netdb.h> does not declare struct addrinfo.
+ */
+
+#if _MSC_VER < 1600
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* Length of ai_addr */
+ char *ai_canonname; /* Canonical name for hostname */
+ struct sockaddr *ai_addr; /* Binary address */
+ struct addrinfo *ai_next; /* Next structure in linked list */
+};
+#endif
+
+
+/*
+ * Undefine all \#defines we are interested in as <netdb.h> may or may not have
+ * defined them.
+ */
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (left in extern int h_errno).
+ */
+
+#undef NETDB_INTERNAL
+#undef NETDB_SUCCESS
+#undef HOST_NOT_FOUND
+#undef TRY_AGAIN
+#undef NO_RECOVERY
+#undef NO_DATA
+#undef NO_ADDRESS
+
+#define NETDB_INTERNAL -1 /* see errno */
+#define NETDB_SUCCESS 0 /* no problem */
+#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */
+#define TRY_AGAIN 2 /* Non-Authoritative Host not found, or SERVERFAIL */
+#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define NO_DATA 4 /* Valid name, no data record of requested type */
+#define NO_ADDRESS NO_DATA /* no address, look for MX record */
+
+/*
+ * Error return codes from getaddrinfo()
+ */
+
+#undef EAI_ADDRFAMILY
+#undef EAI_AGAIN
+#undef EAI_BADFLAGS
+#undef EAI_FAIL
+#undef EAI_FAMILY
+#undef EAI_MEMORY
+#undef EAI_NODATA
+#undef EAI_NONAME
+#undef EAI_SERVICE
+#undef EAI_SOCKTYPE
+#undef EAI_SYSTEM
+#undef EAI_BADHINTS
+#undef EAI_PROTOCOL
+#undef EAI_MAX
+
+#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */
+#define EAI_AGAIN 2 /* temporary failure in name resolution */
+#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
+#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
+#define EAI_FAMILY 5 /* ai_family not supported */
+#define EAI_MEMORY 6 /* memory allocation failure */
+#define EAI_NODATA 7 /* no address associated with hostname */
+#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
+#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
+#define EAI_SYSTEM 11 /* system error returned in errno */
+#define EAI_BADHINTS 12
+#define EAI_PROTOCOL 13
+#define EAI_MAX 14
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#undef AI_PASSIVE
+#undef AI_CANONNAME
+#undef AI_NUMERICHOST
+
+#define AI_PASSIVE 0x00000001
+#define AI_CANONNAME 0x00000002
+#define AI_NUMERICHOST 0x00000004
+
+/*
+ * Flag values for getipnodebyname()
+ */
+#undef AI_V4MAPPED
+#undef AI_ALL
+#undef AI_ADDRCONFIG
+#undef AI_DEFAULT
+
+#define AI_V4MAPPED 0x00000008
+#define AI_ALL 0x00000010
+#define AI_ADDRCONFIG 0x00000020
+#define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG)
+
+/*
+ * Constants for getnameinfo()
+ */
+#undef NI_MAXHOST
+#undef NI_MAXSERV
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+/*
+ * Flag values for getnameinfo()
+ */
+#undef NI_NOFQDN
+#undef NI_NUMERICHOST
+#undef NI_NAMEREQD
+#undef NI_NUMERICSERV
+#undef NI_DGRAM
+#undef NI_NUMERICSCOPE
+
+#define NI_NOFQDN 0x00000001
+#define NI_NUMERICHOST 0x00000002
+#define NI_NAMEREQD 0x00000004
+#define NI_NUMERICSERV 0x00000008
+#define NI_DGRAM 0x00000010
+#define NI_NUMERICSCOPE 0x00000020 /*2553bis-00*/
+
+/*
+ * Structures for getrrsetbyname()
+ */
+struct rdatainfo {
+ unsigned int rdi_length;
+ unsigned char *rdi_data;
+};
+
+struct rrsetinfo {
+ unsigned int rri_flags;
+ int rri_rdclass;
+ int rri_rdtype;
+ unsigned int rri_ttl;
+ unsigned int rri_nrdatas;
+ unsigned int rri_nsigs;
+ char *rri_name;
+ struct rdatainfo *rri_rdatas;
+ struct rdatainfo *rri_sigs;
+};
+
+/*
+ * Flags for getrrsetbyname()
+ */
+#define RRSET_VALIDATED 0x00000001
+ /* Set was dnssec validated */
+
+/*
+ * Return codes for getrrsetbyname()
+ */
+#define ERRSET_SUCCESS 0
+#define ERRSET_NOMEMORY 1
+#define ERRSET_FAIL 2
+#define ERRSET_INVAL 3
+
+
+#endif /* NETDB_H */
diff --git a/lib/isc/win32/ntgroups.c b/lib/isc/win32/ntgroups.c
new file mode 100644
index 0000000..e3a45ca
--- /dev/null
+++ b/lib/isc/win32/ntgroups.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * The NT Groups have two groups that are not well documented and are
+ * not normally seen: None and Everyone. A user account belongs to
+ * any number of groups, but if it is not a member of any group then
+ * it is a member of the None Group. The None group is not listed
+ * anywhere. You cannot remove an account from the none group except
+ * by making it a member of some other group, The second group is the
+ * Everyone group. All accounts, no matter how many groups that they
+ * belong to, also belong to the Everyone group. You cannot remove an
+ * account from the Everyone group.
+ */
+
+#ifndef UNICODE
+#define UNICODE
+#endif /* UNICODE */
+
+/*
+ * Silence warnings.
+ */
+#define _CRT_SECURE_NO_DEPRECATE 1
+
+#include <windows.h>
+#include <assert.h>
+#include <lm.h>
+
+#include <isc/ntgroups.h>
+#include <isc/result.h>
+
+#define MAX_NAME_LENGTH 256
+
+isc_result_t
+isc_ntsecurity_getaccountgroups(char *username, char **GroupList,
+ unsigned int maxgroups,
+ unsigned int *totalGroups) {
+ LPGROUP_USERS_INFO_0 pTmpBuf;
+ LPLOCALGROUP_USERS_INFO_0 pTmpLBuf;
+ DWORD i;
+ LPLOCALGROUP_USERS_INFO_0 pBuf = NULL;
+ LPGROUP_USERS_INFO_0 pgrpBuf = NULL;
+ DWORD dwLevel = 0;
+ DWORD dwFlags = LG_INCLUDE_INDIRECT;
+ DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
+ DWORD dwEntriesRead = 0;
+ DWORD dwTotalEntries = 0;
+ NET_API_STATUS nStatus;
+ size_t retlen;
+ wchar_t user[MAX_NAME_LENGTH];
+
+ retlen = mbstowcs(user, username, MAX_NAME_LENGTH);
+
+ *totalGroups = 0;
+ /*
+ * Call the NetUserGetLocalGroups function
+ * specifying information level 0.
+ *
+ * The LG_INCLUDE_INDIRECT flag specifies that the
+ * function should also return the names of the local
+ * groups in which the user is indirectly a member.
+ */
+ nStatus = NetUserGetLocalGroups(NULL,
+ user,
+ dwLevel,
+ dwFlags,
+ (LPBYTE *) &pBuf,
+ dwPrefMaxLen,
+ &dwEntriesRead,
+ &dwTotalEntries);
+ /*
+ * See if the call succeeds,
+ */
+ if (nStatus != NERR_Success) {
+ if (nStatus == ERROR_ACCESS_DENIED)
+ return (ISC_R_NOPERM);
+ if (nStatus == ERROR_MORE_DATA)
+ return (ISC_R_NOSPACE);
+ if (nStatus == NERR_UserNotFound)
+ dwEntriesRead = 0;
+ }
+
+ if (pBuf != NULL) {
+ pTmpLBuf = pBuf;
+ /*
+ * Loop through the entries
+ */
+ for (i = 0;
+ (i < dwEntriesRead && *totalGroups < maxgroups); i++) {
+ assert(pTmpLBuf != NULL);
+ if (pTmpLBuf == NULL)
+ break;
+ retlen = wcslen(pTmpLBuf->lgrui0_name);
+ GroupList[*totalGroups] = (char *) malloc(retlen +1);
+ if (GroupList[*totalGroups] == NULL)
+ return (ISC_R_NOMEMORY);
+
+ retlen = wcstombs(GroupList[*totalGroups],
+ pTmpLBuf->lgrui0_name, retlen);
+ GroupList[*totalGroups][retlen] = '\0';
+ if (strcmp(GroupList[*totalGroups], "None") == 0)
+ free(GroupList[*totalGroups]);
+ else
+ (*totalGroups)++;
+ pTmpLBuf++;
+ }
+ }
+ /* Free the allocated memory. */
+ if (pBuf != NULL)
+ NetApiBufferFree(pBuf);
+
+
+ /*
+ * Call the NetUserGetGroups function, specifying level 0.
+ */
+ nStatus = NetUserGetGroups(NULL,
+ user,
+ dwLevel,
+ (LPBYTE*)&pgrpBuf,
+ dwPrefMaxLen,
+ &dwEntriesRead,
+ &dwTotalEntries);
+ /*
+ * See if the call succeeds,
+ */
+ if (nStatus != NERR_Success) {
+ if (nStatus == ERROR_ACCESS_DENIED)
+ return (ISC_R_NOPERM);
+ if (nStatus == ERROR_MORE_DATA)
+ return (ISC_R_NOSPACE);
+ if (nStatus == NERR_UserNotFound)
+ dwEntriesRead = 0;
+ }
+
+ if (pgrpBuf != NULL) {
+ pTmpBuf = pgrpBuf;
+ /*
+ * Loop through the entries
+ */
+ for (i = 0;
+ (i < dwEntriesRead && *totalGroups < maxgroups); i++) {
+ assert(pTmpBuf != NULL);
+
+ if (pTmpBuf == NULL)
+ break;
+ retlen = wcslen(pTmpBuf->grui0_name);
+ GroupList[*totalGroups] = (char *) malloc(retlen +1);
+ if (GroupList[*totalGroups] == NULL)
+ return (ISC_R_NOMEMORY);
+
+ retlen = wcstombs(GroupList[*totalGroups],
+ pTmpBuf->grui0_name, retlen);
+ GroupList[*totalGroups][retlen] = '\0';
+ if (strcmp(GroupList[*totalGroups], "None") == 0)
+ free(GroupList[*totalGroups]);
+ else
+ (*totalGroups)++;
+ pTmpBuf++;
+ }
+ }
+ /*
+ * Free the allocated memory.
+ */
+ if (pgrpBuf != NULL)
+ NetApiBufferFree(pgrpBuf);
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/win32/ntpaths.c b/lib/isc/win32/ntpaths.c
new file mode 100644
index 0000000..df71bfa
--- /dev/null
+++ b/lib/isc/win32/ntpaths.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*
+ * This module fetches the required path information that is specific
+ * to NT systems which can have its configuration and system files
+ * almost anywhere. It can be used to override whatever the application
+ * had previously assigned to the pointer. Basic information about the
+ * file locations are stored in the registry.
+ */
+
+#include <config.h>
+
+#include <isc/bind_registry.h>
+#include <isc/ntpaths.h>
+#include <isc/string.h>
+
+/*
+ * Module Variables
+ */
+
+static char systemDir[MAX_PATH];
+static char namedBase[MAX_PATH];
+static char ns_confFile[MAX_PATH];
+static char lwresd_confFile[MAX_PATH];
+static char lwresd_resolvconfFile[MAX_PATH];
+static char rndc_confFile[MAX_PATH];
+static char ns_defaultpidfile[MAX_PATH];
+static char lwresd_defaultpidfile[MAX_PATH];
+static char ns_lockfile[MAX_PATH];
+static char local_state_dir[MAX_PATH];
+static char sys_conf_dir[MAX_PATH];
+static char rndc_keyFile[MAX_PATH];
+static char session_keyFile[MAX_PATH];
+
+static DWORD baseLen = MAX_PATH;
+static BOOL Initialized = FALSE;
+
+void
+isc_ntpaths_init(void) {
+ HKEY hKey;
+ BOOL keyFound = TRUE;
+
+ memset(namedBase, 0, sizeof(namedBase));
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SUBKEY, 0, KEY_READ, &hKey)
+ != ERROR_SUCCESS)
+ keyFound = FALSE;
+
+ if (keyFound == TRUE) {
+ /* Get the named directory */
+ if (RegQueryValueEx(hKey, "InstallDir", NULL, NULL,
+ (LPBYTE)namedBase, &baseLen) != ERROR_SUCCESS)
+ keyFound = FALSE;
+ RegCloseKey(hKey);
+ }
+
+ GetSystemDirectory(systemDir, MAX_PATH);
+
+ if (keyFound == FALSE) {
+ /* Use the System Directory as a default */
+ strlcpy(namedBase, systemDir, sizeof(namedBase));
+ }
+
+ strlcpy(lwresd_confFile, namedBase, sizeof(lwresd_confFile)) ;
+ strlcat(lwresd_confFile, "\\etc\\lwresd.conf",
+ sizeof(lwresd_confFile));
+
+ strlcpy(lwresd_defaultpidfile, namedBase,
+ sizeof(lwresd_defaultpidfile));
+ strlcat(lwresd_defaultpidfile, "\\etc\\lwresd.pid",
+ sizeof(lwresd_defaultpidfile));
+
+ strlcpy(lwresd_resolvconfFile, systemDir,
+ sizeof(lwresd_resolvconfFile));
+ strlcat(lwresd_resolvconfFile, "\\Drivers\\etc\\resolv.conf",
+ sizeof(lwresd_resolvconfFile));
+
+ strlcpy(ns_confFile, namedBase, sizeof(ns_confFile));
+ strlcat(ns_confFile, "\\etc\\named.conf", sizeof(ns_confFile));
+
+ strlcpy(rndc_keyFile, namedBase, sizeof(rndc_keyFile));
+ strlcat(rndc_keyFile, "\\etc\\rndc.key", sizeof(rndc_keyFile));
+
+ strlcpy(session_keyFile, namedBase, sizeof(session_keyFile));
+ strlcat(session_keyFile, "\\etc\\session.key", sizeof(session_keyFile));
+
+ strlcpy(rndc_confFile, namedBase, sizeof(rndc_confFile));
+ strlcat(rndc_confFile, "\\etc\\rndc.conf", sizeof(rndc_confFile));
+
+ strlcpy(ns_defaultpidfile, namedBase, sizeof(ns_defaultpidfile));
+ strlcat(ns_defaultpidfile, "\\etc\\named.pid",
+ sizeof(ns_defaultpidfile));
+
+ strlcpy(ns_lockfile, namedBase, sizeof(ns_lockfile));
+ strlcat(ns_lockfile, "\\etc\\named.lock", sizeof(ns_lockfile));
+
+ strlcpy(local_state_dir, namedBase, sizeof(local_state_dir));
+ strlcat(local_state_dir, "\\bin", sizeof(local_state_dir));
+
+ strlcpy(sys_conf_dir, namedBase, sizeof(sys_conf_dir));
+ strlcat(sys_conf_dir, "\\etc", sizeof(sys_conf_dir));
+
+ Initialized = TRUE;
+}
+
+char *
+isc_ntpaths_get(int ind) {
+ if (!Initialized)
+ isc_ntpaths_init();
+
+ switch (ind) {
+ case NAMED_CONF_PATH:
+ return (ns_confFile);
+ break;
+ case LWRES_CONF_PATH:
+ return (lwresd_confFile);
+ break;
+ case RESOLV_CONF_PATH:
+ return (lwresd_resolvconfFile);
+ break;
+ case RNDC_CONF_PATH:
+ return (rndc_confFile);
+ break;
+ case NAMED_PID_PATH:
+ return (ns_defaultpidfile);
+ break;
+ case LWRESD_PID_PATH:
+ return (lwresd_defaultpidfile);
+ break;
+ case NAMED_LOCK_PATH:
+ return (ns_lockfile);
+ break;
+ case LOCAL_STATE_DIR:
+ return (local_state_dir);
+ break;
+ case SYS_CONF_DIR:
+ return (sys_conf_dir);
+ break;
+ case RNDC_KEY_PATH:
+ return (rndc_keyFile);
+ break;
+ case SESSION_KEY_PATH:
+ return (session_keyFile);
+ break;
+ default:
+ return (NULL);
+ }
+}
diff --git a/lib/isc/win32/once.c b/lib/isc/win32/once.c
new file mode 100644
index 0000000..baf178d
--- /dev/null
+++ b/lib/isc/win32/once.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <windows.h>
+
+#include <isc/once.h>
+#include <isc/assertions.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_once_do(isc_once_t *controller, void(*function)(void)) {
+ REQUIRE(controller != NULL && function != NULL);
+
+ if (controller->status == ISC_ONCE_INIT_NEEDED) {
+
+ if (InterlockedDecrement(&controller->counter) == 0) {
+ if (controller->status == ISC_ONCE_INIT_NEEDED) {
+ function();
+ controller->status = ISC_ONCE_INIT_DONE;
+ }
+ } else {
+ while (controller->status == ISC_ONCE_INIT_NEEDED) {
+ /*
+ * Sleep(0) indicates that this thread
+ * should be suspended to allow other
+ * waiting threads to execute.
+ */
+ Sleep(0);
+ }
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/win32/os.c b/lib/isc/win32/os.c
new file mode 100644
index 0000000..0f4023f
--- /dev/null
+++ b/lib/isc/win32/os.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <windows.h>
+
+#include <isc/os.h>
+
+static BOOL bInit = FALSE;
+static SYSTEM_INFO SystemInfo;
+
+static void
+initialize_action(void) {
+ if (bInit)
+ return;
+
+ GetSystemInfo(&SystemInfo);
+ bInit = TRUE;
+}
+
+unsigned int
+isc_os_ncpus(void) {
+ long ncpus;
+ initialize_action();
+ ncpus = SystemInfo.dwNumberOfProcessors;
+ if (ncpus <= 0)
+ ncpus = 1;
+
+ return ((unsigned int)ncpus);
+}
diff --git a/lib/isc/win32/pk11_api.c b/lib/isc/win32/pk11_api.c
new file mode 100644
index 0000000..76e4abb
--- /dev/null
+++ b/lib/isc/win32/pk11_api.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+/* missing code for WIN32 */
+
+#include <config.h>
+
+#include <string.h>
+#include <windows.h>
+
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/stdio.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include <pk11/pk11.h>
+#include <pk11/internal.h>
+
+#define HAVE_GETPASSPHRASE
+
+char *
+getpassphrase(const char *prompt) {
+ static char buf[128];
+ HANDLE h;
+ DWORD cc, mode;
+ int cnt;
+
+ h = GetStdHandle(STD_INPUT_HANDLE);
+ fputs(prompt, stderr);
+ fflush(stderr);
+ fflush(stdout);
+ FlushConsoleInputBuffer(h);
+ GetConsoleMode(h, &mode);
+ SetConsoleMode(h, ENABLE_PROCESSED_INPUT);
+
+ for (cnt = 0; cnt < sizeof(buf) - 1; cnt++)
+ {
+ ReadFile(h, buf + cnt, 1, &cc, NULL);
+ if (buf[cnt] == '\r')
+ break;
+ fputc('*', stdout);
+ fflush(stderr);
+ fflush(stdout);
+ }
+
+ SetConsoleMode(h, mode);
+ buf[cnt] = '\0';
+ fputs("\n", stderr);
+ return (buf);
+}
+
+/* load PKCS11 DLL */
+
+static HINSTANCE hPK11 = NULL;
+static char loaderrmsg[1024];
+
+CK_RV
+pkcs_C_Initialize(CK_VOID_PTR pReserved) {
+ CK_C_Initialize sym;
+ const char *lib_name = pk11_get_lib_name();
+
+ if (hPK11 != NULL)
+ return (CKR_LIBRARY_ALREADY_INITIALIZED);
+
+ if (lib_name == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ /* Visual Studio convertion issue... */
+ if (*lib_name == ' ')
+ lib_name++;
+
+ hPK11 = LoadLibraryA(lib_name);
+
+ if (hPK11 == NULL) {
+ const DWORD err = GetLastError();
+ snprintf(loaderrmsg, sizeof(loaderrmsg),
+ "LoadLibraryA(\"%s\") failed with 0x%X\n",
+ lib_name, err);
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ sym = (CK_C_Initialize)GetProcAddress(hPK11, "C_Initialize");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(pReserved);
+}
+
+char *pk11_get_load_error_message(void) {
+ return (loaderrmsg);
+}
+
+CK_RV
+pkcs_C_Finalize(CK_VOID_PTR pReserved) {
+ CK_C_Finalize sym;
+ CK_RV rv;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ sym = (CK_C_Finalize)GetProcAddress(hPK11, "C_Finalize");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ rv = (*sym)(pReserved);
+ if ((rv == CKR_OK) && (FreeLibrary(hPK11) == 0))
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ hPK11 = NULL;
+ return (rv);
+}
+
+CK_RV
+pkcs_C_GetSlotList(CK_BBOOL tokenPresent,
+ CK_SLOT_ID_PTR pSlotList,
+ CK_ULONG_PTR pulCount)
+{
+ static CK_C_GetSlotList sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_GetSlotList)GetProcAddress(hPK11, "C_GetSlotList");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(tokenPresent, pSlotList, pulCount);
+}
+
+CK_RV
+pkcs_C_GetTokenInfo(CK_SLOT_ID slotID,
+ CK_TOKEN_INFO_PTR pInfo)
+{
+ static CK_C_GetTokenInfo sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_GetTokenInfo)GetProcAddress(hPK11,
+ "C_GetTokenInfo");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(slotID, pInfo);
+}
+
+CK_RV
+pkcs_C_GetMechanismInfo(CK_SLOT_ID slotID,
+ CK_MECHANISM_TYPE type,
+ CK_MECHANISM_INFO_PTR pInfo)
+{
+ static CK_C_GetMechanismInfo sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_GetMechanismInfo)GetProcAddress(hPK11,
+ "C_GetMechanismInfo");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(slotID, type, pInfo);
+}
+
+CK_RV
+pkcs_C_OpenSession(CK_SLOT_ID slotID,
+ CK_FLAGS flags,
+ CK_VOID_PTR pApplication,
+ CK_RV (*Notify) (CK_SESSION_HANDLE hSession,
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication),
+ CK_SESSION_HANDLE_PTR phSession)
+{
+ static CK_C_OpenSession sym = NULL;
+
+ if (hPK11 == NULL)
+ hPK11 = LoadLibraryA(pk11_get_lib_name());
+ if (hPK11 == NULL) {
+ const DWORD err = GetLastError();
+ snprintf(loaderrmsg, sizeof(loaderrmsg),
+ "LoadLibraryA(\"%s\") failed with 0x%X\n",
+ pk11_get_lib_name(), err);
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL)
+ sym = (CK_C_OpenSession)GetProcAddress(hPK11, "C_OpenSession");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(slotID, flags, pApplication, Notify, phSession);
+}
+
+CK_RV
+pkcs_C_CloseSession(CK_SESSION_HANDLE hSession) {
+ static CK_C_CloseSession sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_CloseSession)GetProcAddress(hPK11,
+ "C_CloseSession");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession);
+}
+
+CK_RV
+pkcs_C_Login(CK_SESSION_HANDLE hSession,
+ CK_USER_TYPE userType,
+ CK_CHAR_PTR pPin,
+ CK_ULONG usPinLen)
+{
+ static CK_C_Login sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_Login)GetProcAddress(hPK11, "C_Login");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, userType, pPin, usPinLen);
+}
+
+CK_RV
+pkcs_C_Logout(CK_SESSION_HANDLE hSession) {
+ static CK_C_Logout sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_Logout)GetProcAddress(hPK11, "C_Logout");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession);
+}
+
+CK_RV
+pkcs_C_CreateObject(CK_SESSION_HANDLE hSession,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG usCount,
+ CK_OBJECT_HANDLE_PTR phObject)
+{
+ static CK_C_CreateObject sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_CreateObject)GetProcAddress(hPK11,
+ "C_CreateObject");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pTemplate, usCount, phObject);
+}
+
+CK_RV
+pkcs_C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) {
+ static CK_C_DestroyObject sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_DestroyObject)GetProcAddress(hPK11,
+ "C_DestroyObject");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, hObject);
+}
+
+CK_RV
+pkcs_C_GetAttributeValue(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG usCount)
+{
+ static CK_C_GetAttributeValue sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_GetAttributeValue)GetProcAddress(hPK11,
+ "C_GetAttributeValue");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, hObject, pTemplate, usCount);
+}
+
+CK_RV
+pkcs_C_SetAttributeValue(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG usCount)
+{
+ static CK_C_SetAttributeValue sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_SetAttributeValue)GetProcAddress(hPK11,
+ "C_SetAttributeValue");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, hObject, pTemplate, usCount);
+}
+
+CK_RV
+pkcs_C_FindObjectsInit(CK_SESSION_HANDLE hSession,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG usCount)
+{
+ static CK_C_FindObjectsInit sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_FindObjectsInit)GetProcAddress(hPK11,
+ "C_FindObjectsInit");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pTemplate, usCount);
+}
+
+CK_RV
+pkcs_C_FindObjects(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE_PTR phObject,
+ CK_ULONG usMaxObjectCount,
+ CK_ULONG_PTR pusObjectCount)
+{
+ static CK_C_FindObjects sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_FindObjects)GetProcAddress(hPK11, "C_FindObjects");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, phObject, usMaxObjectCount, pusObjectCount);
+}
+
+CK_RV
+pkcs_C_FindObjectsFinal(CK_SESSION_HANDLE hSession) {
+ static CK_C_FindObjectsFinal sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_FindObjectsFinal)GetProcAddress(hPK11,
+ "C_FindObjectsFinal");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession);
+}
+
+CK_RV
+pkcs_C_EncryptInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{
+ static CK_C_EncryptInit sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_EncryptInit)GetProcAddress(hPK11, "C_EncryptInit");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pMechanism, hKey);
+}
+
+CK_RV
+pkcs_C_Encrypt(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen,
+ CK_BYTE_PTR pEncryptedData,
+ CK_ULONG_PTR pulEncryptedDataLen)
+{
+ static CK_C_Encrypt sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_Encrypt)GetProcAddress(hPK11, "C_Encrypt");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pData, ulDataLen,
+ pEncryptedData, pulEncryptedDataLen);
+}
+
+CK_RV
+pkcs_C_DigestInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism)
+{
+ static CK_C_DigestInit sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_DigestInit)GetProcAddress(hPK11, "C_DigestInit");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pMechanism);
+}
+
+CK_RV
+pkcs_C_DigestUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen)
+{
+ static CK_C_DigestUpdate sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_DigestUpdate)GetProcAddress(hPK11,
+ "C_DigestUpdate");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pPart, ulPartLen);
+}
+
+CK_RV
+pkcs_C_DigestFinal(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pDigest,
+ CK_ULONG_PTR pulDigestLen)
+{
+ static CK_C_DigestFinal sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_DigestFinal)GetProcAddress(hPK11, "C_DigestFinal");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pDigest, pulDigestLen);
+}
+
+CK_RV
+pkcs_C_SignInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{
+ static CK_C_SignInit sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_SignInit)GetProcAddress(hPK11, "C_SignInit");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pMechanism, hKey);
+}
+
+CK_RV
+pkcs_C_Sign(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen,
+ CK_BYTE_PTR pSignature,
+ CK_ULONG_PTR pulSignatureLen)
+{
+ static CK_C_Sign sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_Sign)GetProcAddress(hPK11, "C_Sign");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pData, ulDataLen, pSignature, pulSignatureLen);
+}
+
+CK_RV
+pkcs_C_SignUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen)
+{
+ static CK_C_SignUpdate sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_SignUpdate)GetProcAddress(hPK11, "C_SignUpdate");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pPart, ulPartLen);
+}
+
+CK_RV
+pkcs_C_SignFinal(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pSignature,
+ CK_ULONG_PTR pulSignatureLen)
+{
+ static CK_C_SignFinal sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_SignFinal)GetProcAddress(hPK11, "C_SignFinal");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pSignature, pulSignatureLen);
+}
+
+CK_RV
+pkcs_C_VerifyInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{
+ static CK_C_VerifyInit sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_VerifyInit)GetProcAddress(hPK11, "C_VerifyInit");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pMechanism, hKey);
+}
+
+CK_RV
+pkcs_C_Verify(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen,
+ CK_BYTE_PTR pSignature,
+ CK_ULONG ulSignatureLen)
+{
+ static CK_C_Verify sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_Verify)GetProcAddress(hPK11, "C_Verify");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pData, ulDataLen, pSignature, ulSignatureLen);
+}
+
+CK_RV
+pkcs_C_VerifyUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen)
+{
+ static CK_C_VerifyUpdate sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_VerifyUpdate)GetProcAddress(hPK11,
+ "C_VerifyUpdate");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pPart, ulPartLen);
+}
+
+CK_RV
+pkcs_C_VerifyFinal(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pSignature,
+ CK_ULONG ulSignatureLen)
+{
+ static CK_C_VerifyFinal sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_VerifyFinal)GetProcAddress(hPK11, "C_VerifyFinal");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pSignature, ulSignatureLen);
+}
+
+CK_RV
+pkcs_C_GenerateKey(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulCount,
+ CK_OBJECT_HANDLE_PTR phKey)
+{
+ static CK_C_GenerateKey sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_GenerateKey)GetProcAddress(hPK11, "C_GenerateKey");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pMechanism, pTemplate, ulCount, phKey);
+}
+
+CK_RV
+pkcs_C_GenerateKeyPair(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+ CK_ULONG usPublicKeyAttributeCount,
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+ CK_ULONG usPrivateKeyAttributeCount,
+ CK_OBJECT_HANDLE_PTR phPrivateKey,
+ CK_OBJECT_HANDLE_PTR phPublicKey)
+{
+ static CK_C_GenerateKeyPair sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_GenerateKeyPair)GetProcAddress(hPK11,
+ "C_GenerateKeyPair");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession,
+ pMechanism,
+ pPublicKeyTemplate,
+ usPublicKeyAttributeCount,
+ pPrivateKeyTemplate,
+ usPrivateKeyAttributeCount,
+ phPrivateKey,
+ phPublicKey);
+}
+
+CK_RV
+pkcs_C_DeriveKey(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hBaseKey,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_OBJECT_HANDLE_PTR phKey)
+{
+ static CK_C_DeriveKey sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_DeriveKey)GetProcAddress(hPK11, "C_DeriveKey");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession,
+ pMechanism,
+ hBaseKey,
+ pTemplate,
+ ulAttributeCount,
+ phKey);
+}
+
+CK_RV
+pkcs_C_SeedRandom(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pSeed,
+ CK_ULONG ulSeedLen)
+{
+ static CK_C_SeedRandom sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_SeedRandom)GetProcAddress(hPK11, "C_SeedRandom");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, pSeed, ulSeedLen);
+}
+
+CK_RV
+pkcs_C_GenerateRandom(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR RandomData,
+ CK_ULONG ulRandomLen)
+{
+ static CK_C_GenerateRandom sym = NULL;
+
+ if (hPK11 == NULL)
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ if (sym == NULL)
+ sym = (CK_C_GenerateRandom)GetProcAddress(hPK11,
+ "C_GenerateRandom");
+ if (sym == NULL)
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ return (*sym)(hSession, RandomData, ulRandomLen);
+}
diff --git a/lib/isc/win32/resource.c b/lib/isc/win32/resource.c
new file mode 100644
index 0000000..0fbc9a4
--- /dev/null
+++ b/lib/isc/win32/resource.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <isc/platform.h>
+#include <isc/resource.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+/*
+ * Windows limits the maximum number of open files to 2048
+ */
+
+#define WIN32_MAX_OPEN_FILES 2048
+
+isc_result_t
+isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
+ isc_resourcevalue_t rlim_value;
+ int wresult;
+
+ if (resource != isc_resource_openfiles)
+ return (ISC_R_NOTIMPLEMENTED);
+
+
+ if (value == ISC_RESOURCE_UNLIMITED)
+ rlim_value = WIN32_MAX_OPEN_FILES;
+ else
+ rlim_value = min(value, WIN32_MAX_OPEN_FILES);
+
+ wresult = _setmaxstdio((int) rlim_value);
+
+ if (wresult > 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+
+ if (resource != isc_resource_openfiles)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ *value = WIN32_MAX_OPEN_FILES;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+ return (isc_resource_getlimit(resource, value));
+}
diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c
new file mode 100644
index 0000000..75b1c26
--- /dev/null
+++ b/lib/isc/win32/socket.c
@@ -0,0 +1,4277 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/* This code uses functions which are only available on Server 2003 and
+ * higher, and Windows XP and higher.
+ *
+ * This code is by nature multithreaded and takes advantage of various
+ * features to pass on information through the completion port for
+ * when I/O is completed. All sends, receives, accepts, and connects are
+ * completed through the completion port.
+ *
+ * The number of Completion Port Worker threads used is the total number
+ * of CPU's + 1. This increases the likelihood that a Worker Thread is
+ * available for processing a completed request.
+ *
+ * XXXPDM 5 August, 2002
+ */
+
+#include <config.h>
+
+#define MAKE_EXTERNAL 1
+
+#include <sys/types.h>
+
+#ifndef _WINSOCKAPI_
+#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */
+#endif
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <io.h>
+#include <fcntl.h>
+#include <process.h>
+
+#include <isc/app.h>
+#include <isc/buffer.h>
+#include <isc/bufferlist.h>
+#include <isc/condition.h>
+#include <isc/list.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/once.h>
+#include <isc/os.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/socket.h>
+#include <isc/stats.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/syslog.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+#include <isc/win32os.h>
+
+#include <mswsock.h>
+
+#include "errno2result.h"
+
+/*
+ * Set by the -T dscp option on the command line. If set to a value
+ * other than -1, we check to make sure DSCP values match it, and
+ * assert if not.
+ */
+LIBISC_EXTERNAL_DATA int isc_dscp_check_value = -1;
+
+/*
+ * How in the world can Microsoft exist with APIs like this?
+ * We can't actually call this directly, because it turns out
+ * no library exports this function. Instead, we need to
+ * issue a runtime call to get the address.
+ */
+LPFN_CONNECTEX ISCConnectEx;
+LPFN_ACCEPTEX ISCAcceptEx;
+LPFN_GETACCEPTEXSOCKADDRS ISCGetAcceptExSockaddrs;
+
+/*
+ * Run expensive internal consistency checks.
+ */
+#ifdef ISC_SOCKET_CONSISTENCY_CHECKS
+#define CONSISTENT(sock) consistent(sock)
+#else
+#define CONSISTENT(sock) do {} while (0)
+#endif
+static void consistent(isc_socket_t *sock);
+
+/*
+ * Define this macro to control the behavior of connection
+ * resets on UDP sockets. See Microsoft KnowledgeBase Article Q263823
+ * for details.
+ * NOTE: This requires that Windows 2000 systems install Service Pack 2
+ * or later.
+ */
+#ifndef SIO_UDP_CONNRESET
+#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
+#endif
+
+/*
+ * Some systems define the socket length argument as an int, some as size_t,
+ * some as socklen_t. This is here so it can be easily changed if needed.
+ */
+#ifndef ISC_SOCKADDR_LEN_T
+#define ISC_SOCKADDR_LEN_T unsigned int
+#endif
+
+/*
+ * Define what the possible "soft" errors can be. These are non-fatal returns
+ * of various network related functions, like recv() and so on.
+ */
+#define SOFT_ERROR(e) ((e) == WSAEINTR || \
+ (e) == WSAEWOULDBLOCK || \
+ (e) == EWOULDBLOCK || \
+ (e) == EINTR || \
+ (e) == EAGAIN || \
+ (e) == 0)
+
+/*
+ * Pending errors are not really errors and should be
+ * kept separate
+ */
+#define PENDING_ERROR(e) ((e) == WSA_IO_PENDING || (e) == 0)
+
+#define DOIO_SUCCESS 0 /* i/o ok, event sent */
+#define DOIO_SOFT 1 /* i/o ok, soft error, no event sent */
+#define DOIO_HARD 2 /* i/o error, event sent */
+#define DOIO_EOF 3 /* EOF, no event sent */
+#define DOIO_PENDING 4 /* status when i/o is in process */
+#define DOIO_NEEDMORE 5 /* IO was processed, but we need more due to minimum */
+
+#define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x)
+
+/*
+ * DLVL(90) -- Function entry/exit and other tracing.
+ * DLVL(70) -- Socket "correctness" -- including returning of events, etc.
+ * DLVL(60) -- Socket data send/receive
+ * DLVL(50) -- Event tracing, including receiving/sending completion events.
+ * DLVL(20) -- Socket creation/destruction.
+ */
+#define TRACE_LEVEL 90
+#define CORRECTNESS_LEVEL 70
+#define IOEVENT_LEVEL 60
+#define EVENT_LEVEL 50
+#define CREATION_LEVEL 20
+
+#define TRACE DLVL(TRACE_LEVEL)
+#define CORRECTNESS DLVL(CORRECTNESS_LEVEL)
+#define IOEVENT DLVL(IOEVENT_LEVEL)
+#define EVENT DLVL(EVENT_LEVEL)
+#define CREATION DLVL(CREATION_LEVEL)
+
+typedef isc_event_t intev_t;
+
+/*
+ * Socket State
+ */
+enum {
+ SOCK_INITIALIZED, /* Socket Initialized */
+ SOCK_OPEN, /* Socket opened but nothing yet to do */
+ SOCK_DATA, /* Socket sending or receiving data */
+ SOCK_LISTEN, /* TCP Socket listening for connects */
+ SOCK_ACCEPT, /* TCP socket is waiting to accept */
+ SOCK_CONNECT, /* TCP Socket connecting */
+ SOCK_CLOSED, /* Socket has been closed */
+};
+
+#define SOCKET_MAGIC ISC_MAGIC('I', 'O', 'i', 'o')
+#define VALID_SOCKET(t) ISC_MAGIC_VALID(t, SOCKET_MAGIC)
+
+/*
+ * IPv6 control information. If the socket is an IPv6 socket we want
+ * to collect the destination address and interface so the client can
+ * set them on outgoing packets.
+ */
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifndef USE_CMSG
+#define USE_CMSG 1
+#endif
+#endif
+
+/*
+ * We really don't want to try and use these control messages. Win32
+ * doesn't have this mechanism before XP.
+ */
+#undef USE_CMSG
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ * Used value-result for recvmsg, value only for sendmsg.
+ */
+struct msghdr {
+ SOCKADDR_STORAGE to_addr; /* UDP send/recv address */
+ int to_addr_len; /* length of the address */
+ WSABUF *msg_iov; /* scatter/gather array */
+ u_int msg_iovlen; /* # elements in msg_iov */
+ void *msg_control; /* ancillary data, see below */
+ u_int msg_controllen; /* ancillary data buffer len */
+ u_int msg_totallen; /* total length of this message */
+} msghdr;
+
+/*
+ * The size to raise the receive buffer to.
+ */
+#define RCVBUFSIZE (32*1024)
+
+/*
+ * The number of times a send operation is repeated if the result
+ * is WSAEINTR.
+ */
+#define NRETRIES 10
+
+struct isc_socket {
+ /* Not locked. */
+ unsigned int magic;
+ isc_socketmgr_t *manager;
+ isc_mutex_t lock;
+ isc_sockettype_t type;
+
+ /* Pointers to scatter/gather buffers */
+ WSABUF iov[ISC_SOCKET_MAXSCATTERGATHER];
+
+ /* Locked by socket lock. */
+ ISC_LINK(isc_socket_t) link;
+ unsigned int references; /* EXTERNAL references */
+ SOCKET fd; /* file handle */
+ int pf; /* protocol family */
+ char name[16];
+ void * tag;
+
+ /*
+ * Each recv() call uses this buffer. It is a per-socket receive
+ * buffer that allows us to decouple the system recv() from the
+ * recv_list done events. This means the items on the recv_list
+ * can be removed without having to cancel pending system recv()
+ * calls. It also allows us to read-ahead in some cases.
+ */
+ struct {
+ SOCKADDR_STORAGE from_addr; // UDP send/recv address
+ int from_addr_len; // length of the address
+ char *base; // the base of the buffer
+ char *consume_position; // where to start copying data from next
+ unsigned int len; // the actual size of this buffer
+ unsigned int remaining; // the number of bytes remaining
+ } recvbuf;
+
+ ISC_LIST(isc_socketevent_t) send_list;
+ ISC_LIST(isc_socketevent_t) recv_list;
+ ISC_LIST(isc_socket_newconnev_t) accept_list;
+ ISC_LIST(isc_socket_connev_t) connect_list;
+
+ isc_sockaddr_t address; /* remote address */
+
+ unsigned int listener : 1, /* listener socket */
+ connected : 1,
+ pending_connect : 1, /* connect pending */
+ bound : 1, /* bound to local addr */
+ dupped : 1; /* created by isc_socket_dup() */
+ unsigned int pending_iocp; /* Should equal the counters below. Debug. */
+ unsigned int pending_recv; /* Number of outstanding recv() calls. */
+ unsigned int pending_send; /* Number of outstanding send() calls. */
+ unsigned int pending_accept; /* Number of outstanding accept() calls. */
+ unsigned int state; /* Socket state. Debugging and consistency checking. */
+ int state_lineno; /* line which last touched state */
+};
+
+#define _set_state(sock, _state) do { (sock)->state = (_state); (sock)->state_lineno = __LINE__; } while (0)
+
+/*
+ * Buffer structure
+ */
+typedef struct buflist buflist_t;
+
+struct buflist {
+ void *buf;
+ unsigned int buflen;
+ ISC_LINK(buflist_t) link;
+};
+
+/*
+ * I/O Completion ports Info structures
+ */
+
+static HANDLE hHeapHandle = NULL;
+typedef struct IoCompletionInfo {
+ OVERLAPPED overlapped;
+ isc_socketevent_t *dev; /* send()/recv() done event */
+ isc_socket_connev_t *cdev; /* connect() done event */
+ isc_socket_newconnev_t *adev; /* accept() done event */
+ void *acceptbuffer;
+ DWORD received_bytes;
+ int request_type;
+ struct msghdr messagehdr;
+ ISC_LIST(buflist_t) bufferlist; /*%< list of buffers */
+} IoCompletionInfo;
+
+/*
+ * Define a maximum number of I/O Completion Port worker threads
+ * to handle the load on the Completion Port. The actual number
+ * used is the number of CPU's + 1.
+ */
+#define MAX_IOCPTHREADS 20
+
+#define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g')
+#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC)
+
+struct isc_socketmgr {
+ /* Not locked. */
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ isc_stats_t *stats;
+
+ /* Locked by manager lock. */
+ ISC_LIST(isc_socket_t) socklist;
+ bool bShutdown;
+ isc_condition_t shutdown_ok;
+ HANDLE hIoCompletionPort;
+ int maxIOCPThreads;
+ HANDLE hIOCPThreads[MAX_IOCPTHREADS];
+ DWORD dwIOCPThreadIds[MAX_IOCPTHREADS];
+
+ /*
+ * Debugging.
+ * Modified by InterlockedIncrement() and InterlockedDecrement()
+ */
+ LONG totalSockets;
+ LONG iocp_total;
+};
+
+enum {
+ SOCKET_RECV,
+ SOCKET_SEND,
+ SOCKET_ACCEPT,
+ SOCKET_CONNECT
+};
+
+/*
+ * send() and recv() iovec counts
+ */
+#define MAXSCATTERGATHER_SEND (ISC_SOCKET_MAXSCATTERGATHER)
+#define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER)
+
+static isc_result_t socket_create(isc_socketmgr_t *manager0, int pf,
+ isc_sockettype_t type,
+ isc_socket_t **socketp,
+ isc_socket_t *dup_socket);
+static isc_threadresult_t WINAPI SocketIoThread(LPVOID ThreadContext);
+static void maybe_free_socket(isc_socket_t **, int);
+static void free_socket(isc_socket_t **, int);
+static bool senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev);
+static bool acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev);
+static bool connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev);
+static void send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev);
+static void send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev);
+static void send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev);
+static void send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev);
+static void send_recvdone_abort(isc_socket_t *sock, isc_result_t result);
+static void send_connectdone_abort(isc_socket_t *sock, isc_result_t result);
+static void queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev);
+static void queue_receive_request(isc_socket_t *sock);
+
+/*
+ * This is used to dump the contents of the sock structure
+ * You should make sure that the sock is locked before
+ * dumping it. Since the code uses simple printf() statements
+ * it should only be used interactively.
+ */
+void
+sock_dump(isc_socket_t *sock) {
+ isc_socketevent_t *ldev;
+ isc_socket_newconnev_t *ndev;
+ isc_socket_connev_t *cdev;
+
+#if 0
+ isc_sockaddr_t addr;
+ char socktext[ISC_SOCKADDR_FORMATSIZE];
+ isc_result_t result;
+
+ result = isc_socket_getpeername(sock, &addr);
+ if (result == ISC_R_SUCCESS) {
+ isc_sockaddr_format(&addr, socktext, sizeof(socktext));
+ printf("Remote Socket: %s\n", socktext);
+ }
+ result = isc_socket_getsockname(sock, &addr);
+ if (result == ISC_R_SUCCESS) {
+ isc_sockaddr_format(&addr, socktext, sizeof(socktext));
+ printf("This Socket: %s\n", socktext);
+ }
+#endif
+
+ printf("\n\t\tSock Dump\n");
+ printf("\t\tfd: %Iu\n", sock->fd);
+ printf("\t\treferences: %u\n", sock->references);
+ printf("\t\tpending_accept: %u\n", sock->pending_accept);
+ printf("\t\tconnecting: %u\n", sock->pending_connect);
+ printf("\t\tconnected: %u\n", sock->connected);
+ printf("\t\tbound: %u\n", sock->bound);
+ printf("\t\tpending_iocp: %u\n", sock->pending_iocp);
+ printf("\t\tsocket type: %d\n", sock->type);
+
+ printf("\n\t\tSock Recv List\n");
+ ldev = ISC_LIST_HEAD(sock->recv_list);
+ while (ldev != NULL) {
+ printf("\t\tdev: %p\n", ldev);
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+ }
+
+ printf("\n\t\tSock Send List\n");
+ ldev = ISC_LIST_HEAD(sock->send_list);
+ while (ldev != NULL) {
+ printf("\t\tdev: %p\n", ldev);
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+ }
+
+ printf("\n\t\tSock Accept List\n");
+ ndev = ISC_LIST_HEAD(sock->accept_list);
+ while (ndev != NULL) {
+ printf("\t\tdev: %p\n", ldev);
+ ndev = ISC_LIST_NEXT(ndev, ev_link);
+ }
+
+ printf("\n\t\tSock Connect List\n");
+ cdev = ISC_LIST_HEAD(sock->connect_list);
+ while (cdev != NULL) {
+ printf("\t\tdev: %p\n", cdev);
+ cdev = ISC_LIST_NEXT(cdev, ev_link);
+ }
+}
+
+static void
+socket_log(int lineno, isc_socket_t *sock, isc_sockaddr_t *address,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10);
+
+/* This function will add an entry to the I/O completion port
+ * that will signal the I/O thread to exit (gracefully)
+ */
+static void
+signal_iocompletionport_exit(isc_socketmgr_t *manager) {
+ int i;
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_MANAGER(manager));
+ for (i = 0; i < manager->maxIOCPThreads; i++) {
+ if (!PostQueuedCompletionStatus(manager->hIoCompletionPort,
+ 0, 0, 0)) {
+ errval = GetLastError();
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FAILED,
+ "Can't request service thread to exit: %s"),
+ strbuf);
+ }
+ }
+}
+
+/*
+ * Create the worker threads for the I/O Completion Port
+ */
+void
+iocompletionport_createthreads(int total_threads, isc_socketmgr_t *manager) {
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+ int i;
+
+ INSIST(total_threads > 0);
+ REQUIRE(VALID_MANAGER(manager));
+ /*
+ * We need at least one
+ */
+ for (i = 0; i < total_threads; i++) {
+ manager->hIOCPThreads[i] = CreateThread(NULL, 0, SocketIoThread,
+ manager, 0,
+ &manager->dwIOCPThreadIds[i]);
+ if (manager->hIOCPThreads[i] == NULL) {
+ errval = GetLastError();
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FAILED,
+ "Can't create IOCP thread: %s"),
+ strbuf);
+ }
+ }
+}
+
+/*
+ * Create/initialise the I/O completion port
+ */
+void
+iocompletionport_init(isc_socketmgr_t *manager) {
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_MANAGER(manager));
+ /*
+ * Create a private heap to handle the socket overlapped structure
+ * The minimum number of structures is 10, there is no maximum
+ */
+ hHeapHandle = HeapCreate(0, 10 * sizeof(IoCompletionInfo), 0);
+ if (hHeapHandle == NULL) {
+ errval = GetLastError();
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FAILED,
+ "HeapCreate() failed during "
+ "initialization: %s"),
+ strbuf);
+ }
+
+ manager->maxIOCPThreads = min(isc_os_ncpus() + 1, MAX_IOCPTHREADS);
+
+ /* Now Create the Completion Port */
+ manager->hIoCompletionPort = CreateIoCompletionPort(
+ INVALID_HANDLE_VALUE, NULL,
+ 0, manager->maxIOCPThreads);
+ if (manager->hIoCompletionPort == NULL) {
+ errval = GetLastError();
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FAILED,
+ "CreateIoCompletionPort() failed "
+ "during initialization: %s"),
+ strbuf);
+ }
+
+ /*
+ * Worker threads for servicing the I/O
+ */
+ iocompletionport_createthreads(manager->maxIOCPThreads, manager);
+}
+
+/*
+ * Associate a socket with an IO Completion Port. This allows us to queue events for it
+ * and have our worker pool of threads process them.
+ */
+void
+iocompletionport_update(isc_socket_t *sock) {
+ HANDLE hiocp;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ hiocp = CreateIoCompletionPort((HANDLE)sock->fd,
+ sock->manager->hIoCompletionPort, (ULONG_PTR)sock, 0);
+
+ if (hiocp == NULL) {
+ DWORD errval = GetLastError();
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ isc_log_iwrite(isc_lctx,
+ ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_TOOMANYHANDLES,
+ "iocompletionport_update: failed to open"
+ " io completion port: %s",
+ strbuf);
+
+ /* XXXMLG temporary hack to make failures detected.
+ * This function should return errors to the caller, not
+ * exit here.
+ */
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FAILED,
+ "CreateIoCompletionPort() failed "
+ "during initialization: %s"),
+ strbuf);
+ }
+
+ InterlockedIncrement(&sock->manager->iocp_total);
+}
+
+/*
+ * Routine to cleanup and then close the socket.
+ * Only close the socket here if it is NOT associated
+ * with an event, otherwise the WSAWaitForMultipleEvents
+ * may fail due to the fact that the Wait should not
+ * be running while closing an event or a socket.
+ * The socket is locked before calling this function
+ */
+void
+socket_close(isc_socket_t *sock) {
+
+ REQUIRE(sock != NULL);
+
+ if (sock->fd != INVALID_SOCKET) {
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ _set_state(sock, SOCK_CLOSED);
+ InterlockedDecrement(&sock->manager->totalSockets);
+ }
+}
+
+static isc_once_t initialise_once = ISC_ONCE_INIT;
+static bool initialised = false;
+
+static void
+initialise(void) {
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+ SOCKET sock;
+ GUID GUIDConnectEx = WSAID_CONNECTEX;
+ GUID GUIDAcceptEx = WSAID_ACCEPTEX;
+ GUID GUIDGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
+ DWORD dwBytes;
+
+ /* Need Winsock 2.2 or better */
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+ if (err != 0) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc__strerror(err, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__, "WSAStartup() %s: %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+ }
+ /*
+ * The following APIs do not exist as functions in a library, but
+ * we must ask winsock for them. They are "extensions" -- but why
+ * they cannot be actual functions is beyond me. So, ask winsock
+ * for the pointers to the functions we need.
+ */
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ INSIST(sock != INVALID_SOCKET);
+ err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &GUIDConnectEx, sizeof(GUIDConnectEx),
+ &ISCConnectEx, sizeof(ISCConnectEx),
+ &dwBytes, NULL, NULL);
+ INSIST(err == 0);
+
+ err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &GUIDAcceptEx, sizeof(GUIDAcceptEx),
+ &ISCAcceptEx, sizeof(ISCAcceptEx),
+ &dwBytes, NULL, NULL);
+ INSIST(err == 0);
+
+ err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &GUIDGetAcceptExSockaddrs, sizeof(GUIDGetAcceptExSockaddrs),
+ &ISCGetAcceptExSockaddrs, sizeof(ISCGetAcceptExSockaddrs),
+ &dwBytes, NULL, NULL);
+ INSIST(err == 0);
+
+ closesocket(sock);
+
+ initialised = true;
+}
+
+/*
+ * Initialize socket services
+ */
+void
+InitSockets(void) {
+ RUNTIME_CHECK(isc_once_do(&initialise_once,
+ initialise) == ISC_R_SUCCESS);
+ if (!initialised)
+ exit(1);
+}
+
+int
+internal_sendmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
+ struct msghdr *messagehdr, int flags, int *Error)
+{
+ int Result;
+ DWORD BytesSent;
+ DWORD Flags = flags;
+ int total_sent;
+
+ *Error = 0;
+ Result = WSASendTo(sock->fd, messagehdr->msg_iov,
+ messagehdr->msg_iovlen, &BytesSent,
+ Flags, (SOCKADDR *)&messagehdr->to_addr,
+ messagehdr->to_addr_len, (LPWSAOVERLAPPED)lpo,
+ NULL);
+
+ total_sent = (int)BytesSent;
+
+ /* Check for errors.*/
+ if (Result == SOCKET_ERROR) {
+ *Error = WSAGetLastError();
+
+ switch (*Error) {
+ case WSA_IO_INCOMPLETE:
+ case WSA_WAIT_IO_COMPLETION:
+ case WSA_IO_PENDING:
+ case NO_ERROR: /* Strange, but okay */
+ sock->pending_iocp++;
+ sock->pending_send++;
+ break;
+
+ default:
+ return (-1);
+ break;
+ }
+ } else {
+ sock->pending_iocp++;
+ sock->pending_send++;
+ }
+
+ if (lpo != NULL)
+ return (0);
+ else
+ return (total_sent);
+}
+
+static void
+queue_receive_request(isc_socket_t *sock) {
+ DWORD Flags = 0;
+ DWORD NumBytes = 0;
+ int Result;
+ int Error;
+ int need_retry;
+ WSABUF iov[1];
+ IoCompletionInfo *lpo = NULL;
+ isc_result_t isc_result;
+
+ retry:
+ need_retry = false;
+
+ /*
+ * If we already have a receive pending, do nothing.
+ */
+ if (sock->pending_recv > 0) {
+ if (lpo != NULL)
+ HeapFree(hHeapHandle, 0, lpo);
+ return;
+ }
+
+ /*
+ * If no one is waiting, do nothing.
+ */
+ if (ISC_LIST_EMPTY(sock->recv_list)) {
+ if (lpo != NULL)
+ HeapFree(hHeapHandle, 0, lpo);
+ return;
+ }
+
+ INSIST(sock->recvbuf.remaining == 0);
+ INSIST(sock->fd != INVALID_SOCKET);
+
+ iov[0].len = sock->recvbuf.len;
+ iov[0].buf = sock->recvbuf.base;
+
+ if (lpo == NULL) {
+ lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
+ HEAP_ZERO_MEMORY,
+ sizeof(IoCompletionInfo));
+ RUNTIME_CHECK(lpo != NULL);
+ } else
+ ZeroMemory(lpo, sizeof(IoCompletionInfo));
+ lpo->request_type = SOCKET_RECV;
+
+ sock->recvbuf.from_addr_len = sizeof(sock->recvbuf.from_addr);
+
+ Error = 0;
+ Result = WSARecvFrom((SOCKET)sock->fd, iov, 1,
+ &NumBytes, &Flags,
+ (SOCKADDR *)&sock->recvbuf.from_addr,
+ &sock->recvbuf.from_addr_len,
+ (LPWSAOVERLAPPED)lpo, NULL);
+
+ /* Check for errors. */
+ if (Result == SOCKET_ERROR) {
+ Error = WSAGetLastError();
+
+ switch (Error) {
+ case WSA_IO_PENDING:
+ sock->pending_iocp++;
+ sock->pending_recv++;
+ break;
+
+ /* direct error: no completion event */
+ case ERROR_HOST_UNREACHABLE:
+ case WSAENETRESET:
+ case WSAECONNRESET:
+ if (!sock->connected) {
+ /* soft error */
+ need_retry = true;
+ break;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ isc_result = isc__errno2result(Error);
+ if (isc_result == ISC_R_UNEXPECTED)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "WSARecvFrom: Windows error code: %d, isc result %d",
+ Error, isc_result);
+ send_recvdone_abort(sock, isc_result);
+ HeapFree(hHeapHandle, 0, lpo);
+ lpo = NULL;
+ break;
+ }
+ } else {
+ /*
+ * The recv() finished immediately, but we will still get
+ * a completion event. Rather than duplicate code, let
+ * that thread handle sending the data along its way.
+ */
+ sock->pending_iocp++;
+ sock->pending_recv++;
+ }
+
+ socket_log(__LINE__, sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_DOIORECV,
+ "queue_io_request: fd %d result %d error %d",
+ sock->fd, Result, Error);
+
+ CONSISTENT(sock);
+
+ if (need_retry)
+ goto retry;
+}
+
+static void
+manager_log(isc_socketmgr_t *sockmgr, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *fmt, ...)
+{
+ char msgbuf[2048];
+ va_list ap;
+
+ if (!isc_log_wouldlog(isc_lctx, level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ isc_log_write(isc_lctx, category, module, level,
+ "sockmgr %p: %s", sockmgr, msgbuf);
+}
+
+static void
+socket_log(int lineno, isc_socket_t *sock, isc_sockaddr_t *address,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *fmt, ...)
+{
+ char msgbuf[2048];
+ char peerbuf[256];
+ va_list ap;
+
+
+ if (!isc_log_wouldlog(isc_lctx, level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ if (address == NULL) {
+ isc_log_iwrite(isc_lctx, category, module, level,
+ msgcat, msgset, message,
+ "socket %p line %d: %s", sock, lineno, msgbuf);
+ } else {
+ isc_sockaddr_format(address, peerbuf, sizeof(peerbuf));
+ isc_log_iwrite(isc_lctx, category, module, level,
+ msgcat, msgset, message,
+ "socket %p line %d %s: %s", sock, lineno,
+ peerbuf, msgbuf);
+ }
+
+}
+
+/*
+ * Make an fd SOCKET non-blocking.
+ */
+static isc_result_t
+make_nonblock(SOCKET fd) {
+ int ret;
+ unsigned long flags = 1;
+ char strbuf[ISC_STRERRORSIZE];
+
+ /* Set the socket to non-blocking */
+ ret = ioctlsocket(fd, FIONBIO, &flags);
+
+ if (ret == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "ioctlsocket(%d, FIOBIO, %d): %s",
+ fd, flags, strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Windows 2000 systems incorrectly cause UDP sockets using WSARecvFrom
+ * to not work correctly, returning a WSACONNRESET error when a WSASendTo
+ * fails with an "ICMP port unreachable" response and preventing the
+ * socket from using the WSARecvFrom in subsequent operations.
+ * The function below fixes this, but requires that Windows 2000
+ * Service Pack 2 or later be installed on the system. NT 4.0
+ * systems are not affected by this and work correctly.
+ * See Microsoft Knowledge Base Article Q263823 for details of this.
+ */
+isc_result_t
+connection_reset_fix(SOCKET fd) {
+ DWORD dwBytesReturned = 0;
+ BOOL bNewBehavior = FALSE;
+ DWORD status;
+
+ if (isc_win32os_versioncheck(5, 0, 0, 0) < 0)
+ return (ISC_R_SUCCESS); /* NT 4.0 has no problem */
+
+ /* disable bad behavior using IOCTL: SIO_UDP_CONNRESET */
+ status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior,
+ sizeof(bNewBehavior), NULL, 0,
+ &dwBytesReturned, NULL, NULL);
+ if (status != SOCKET_ERROR)
+ return (ISC_R_SUCCESS);
+ else {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "WSAIoctl(SIO_UDP_CONNRESET, oldBehaviour) %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ return (ISC_R_UNEXPECTED);
+ }
+}
+
+/*
+ * Construct an iov array and attach it to the msghdr passed in. This is
+ * the SEND constructor, which will use the used region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
+ *
+ * Nothing can be NULL, and the done event must list at least one buffer
+ * on the buffer linked list for this function to be meaningful.
+ */
+static void
+build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
+ struct msghdr *msg, char *cmsg, WSABUF *iov,
+ IoCompletionInfo *lpo)
+{
+ unsigned int iovcount;
+ isc_buffer_t *buffer;
+ buflist_t *cpbuffer;
+ isc_region_t used;
+ size_t write_count;
+ size_t skip_count;
+
+ memset(msg, 0, sizeof(*msg));
+
+ memmove(&msg->to_addr, &dev->address.type, dev->address.length);
+ msg->to_addr_len = dev->address.length;
+
+ buffer = ISC_LIST_HEAD(dev->bufferlist);
+ write_count = 0;
+ iovcount = 0;
+
+ /*
+ * Single buffer I/O? Skip what we've done so far in this region.
+ */
+ if (buffer == NULL) {
+ write_count = dev->region.length - dev->n;
+ cpbuffer = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(buflist_t));
+ RUNTIME_CHECK(cpbuffer != NULL);
+ cpbuffer->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, write_count);
+ RUNTIME_CHECK(cpbuffer->buf != NULL);
+
+ socket_log(__LINE__, sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+ "alloc_buffer %p %d %p %d", cpbuffer, sizeof(buflist_t),
+ cpbuffer->buf, write_count);
+
+ memmove(cpbuffer->buf,(dev->region.base + dev->n), write_count);
+ cpbuffer->buflen = (unsigned int)write_count;
+ ISC_LINK_INIT(cpbuffer, link);
+ ISC_LIST_ENQUEUE(lpo->bufferlist, cpbuffer, link);
+ iov[0].buf = cpbuffer->buf;
+ iov[0].len = (u_long)write_count;
+ iovcount = 1;
+
+ goto config;
+ }
+
+ /*
+ * Multibuffer I/O.
+ * Skip the data in the buffer list that we have already written.
+ */
+ skip_count = dev->n;
+ while (buffer != NULL) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ if (skip_count < isc_buffer_usedlength(buffer))
+ break;
+ skip_count -= isc_buffer_usedlength(buffer);
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ while (buffer != NULL) {
+ INSIST(iovcount < MAXSCATTERGATHER_SEND);
+
+ isc_buffer_usedregion(buffer, &used);
+
+ if (used.length > 0) {
+ int uselen = (int)(used.length - skip_count);
+ cpbuffer = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(buflist_t));
+ RUNTIME_CHECK(cpbuffer != NULL);
+ cpbuffer->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, uselen);
+ RUNTIME_CHECK(cpbuffer->buf != NULL);
+
+ socket_log(__LINE__, sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+ "alloc_buffer %p %d %p %d", cpbuffer, sizeof(buflist_t),
+ cpbuffer->buf, write_count);
+
+ memmove(cpbuffer->buf,(used.base + skip_count), uselen);
+ cpbuffer->buflen = uselen;
+ iov[iovcount].buf = cpbuffer->buf;
+ iov[iovcount].len = (u_long)(used.length - skip_count);
+ write_count += uselen;
+ skip_count = 0;
+ iovcount++;
+ }
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ INSIST(skip_count == 0);
+
+ config:
+ msg->msg_iov = iov;
+ msg->msg_iovlen = iovcount;
+ msg->msg_totallen = (u_int)write_count;
+}
+
+static void
+set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock,
+ isc_socketevent_t *dev)
+{
+ if (sock->type == isc_sockettype_udp) {
+ if (address != NULL)
+ dev->address = *address;
+ else
+ dev->address = sock->address;
+ } else if (sock->type == isc_sockettype_tcp) {
+ INSIST(address == NULL);
+ dev->address = sock->address;
+ }
+}
+
+static void
+destroy_socketevent(isc_event_t *event) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)event;
+
+ INSIST(ISC_LIST_EMPTY(ev->bufferlist));
+
+ (ev->destroy)(event);
+}
+
+static isc_socketevent_t *
+allocate_socketevent(isc_mem_t *mctx, isc_socket_t *sock,
+ isc_eventtype_t eventtype, isc_taskaction_t action,
+ void *arg)
+{
+ isc_socketevent_t *ev;
+
+ ev = (isc_socketevent_t *)isc_event_allocate(mctx, sock, eventtype,
+ action, arg,
+ sizeof(*ev));
+ if (ev == NULL)
+ return (NULL);
+
+ ev->result = ISC_R_IOERROR; // XXXMLG temporary change to detect failure to set
+ ISC_LINK_INIT(ev, ev_link);
+ ISC_LIST_INIT(ev->bufferlist);
+ ev->region.base = NULL;
+ ev->n = 0;
+ ev->offset = 0;
+ ev->attributes = 0;
+ ev->destroy = ev->ev_destroy;
+ ev->ev_destroy = destroy_socketevent;
+ ev->dscp = 0;
+
+ return (ev);
+}
+
+#if defined(ISC_SOCKET_DEBUG)
+static void
+dump_msg(struct msghdr *msg, isc_socket_t *sock) {
+ unsigned int i;
+
+ printf("MSGHDR %p, Socket #: %Iu\n", msg, sock->fd);
+ printf("\tname %p, namelen %d\n", msg->msg_name, msg->msg_namelen);
+ printf("\tiov %p, iovlen %d\n", msg->msg_iov, msg->msg_iovlen);
+ for (i = 0; i < (unsigned int)msg->msg_iovlen; i++)
+ printf("\t\t%u\tbase %p, len %u\n", i,
+ msg->msg_iov[i].buf, msg->msg_iov[i].len);
+}
+#endif
+
+/*
+ * map the error code
+ */
+int
+map_socket_error(isc_socket_t *sock, int windows_errno, int *isc_errno,
+ char *errorstring, size_t bufsize) {
+
+ int doreturn;
+ switch (windows_errno) {
+ case WSAECONNREFUSED:
+ *isc_errno = ISC_R_CONNREFUSED;
+ if (sock->connected)
+ doreturn = DOIO_HARD;
+ else
+ doreturn = DOIO_SOFT;
+ break;
+ case WSAENETUNREACH:
+ case ERROR_NETWORK_UNREACHABLE:
+ *isc_errno = ISC_R_NETUNREACH;
+ if (sock->connected)
+ doreturn = DOIO_HARD;
+ else
+ doreturn = DOIO_SOFT;
+ break;
+ case ERROR_PORT_UNREACHABLE:
+ case ERROR_HOST_UNREACHABLE:
+ case WSAEHOSTUNREACH:
+ *isc_errno = ISC_R_HOSTUNREACH;
+ if (sock->connected)
+ doreturn = DOIO_HARD;
+ else
+ doreturn = DOIO_SOFT;
+ break;
+ case WSAENETDOWN:
+ *isc_errno = ISC_R_NETDOWN;
+ if (sock->connected)
+ doreturn = DOIO_HARD;
+ else
+ doreturn = DOIO_SOFT;
+ break;
+ case WSAEHOSTDOWN:
+ *isc_errno = ISC_R_HOSTDOWN;
+ if (sock->connected)
+ doreturn = DOIO_HARD;
+ else
+ doreturn = DOIO_SOFT;
+ break;
+ case WSAEACCES:
+ *isc_errno = ISC_R_NOPERM;
+ if (sock->connected)
+ doreturn = DOIO_HARD;
+ else
+ doreturn = DOIO_SOFT;
+ break;
+ case WSAECONNRESET:
+ case WSAENETRESET:
+ case WSAECONNABORTED:
+ case WSAEDISCON:
+ *isc_errno = ISC_R_CONNECTIONRESET;
+ if (sock->connected)
+ doreturn = DOIO_HARD;
+ else
+ doreturn = DOIO_SOFT;
+ break;
+ case WSAENOTCONN:
+ *isc_errno = ISC_R_NOTCONNECTED;
+ if (sock->connected)
+ doreturn = DOIO_HARD;
+ else
+ doreturn = DOIO_SOFT;
+ break;
+ case ERROR_OPERATION_ABORTED:
+ case ERROR_CONNECTION_ABORTED:
+ case ERROR_REQUEST_ABORTED:
+ *isc_errno = ISC_R_CONNECTIONRESET;
+ doreturn = DOIO_HARD;
+ break;
+ case WSAENOBUFS:
+ *isc_errno = ISC_R_NORESOURCES;
+ doreturn = DOIO_HARD;
+ break;
+ case WSAEAFNOSUPPORT:
+ *isc_errno = ISC_R_FAMILYNOSUPPORT;
+ doreturn = DOIO_HARD;
+ break;
+ case WSAEADDRNOTAVAIL:
+ *isc_errno = ISC_R_ADDRNOTAVAIL;
+ doreturn = DOIO_HARD;
+ break;
+ case WSAEDESTADDRREQ:
+ *isc_errno = ISC_R_BADADDRESSFORM;
+ doreturn = DOIO_HARD;
+ break;
+ case ERROR_NETNAME_DELETED:
+ *isc_errno = ISC_R_NETDOWN;
+ doreturn = DOIO_HARD;
+ break;
+ default:
+ *isc_errno = ISC_R_IOERROR;
+ doreturn = DOIO_HARD;
+ break;
+ }
+ if (doreturn == DOIO_HARD) {
+ isc__strerror(windows_errno, errorstring, bufsize);
+ }
+ return (doreturn);
+}
+
+static void
+fill_recv(isc_socket_t *sock, isc_socketevent_t *dev) {
+ isc_region_t r;
+ int copylen;
+ isc_buffer_t *buffer;
+
+ INSIST(dev->n < dev->minimum);
+ INSIST(sock->recvbuf.remaining > 0);
+ INSIST(sock->pending_recv == 0);
+
+ if (sock->type == isc_sockettype_udp) {
+ dev->address.length = sock->recvbuf.from_addr_len;
+ memmove(&dev->address.type, &sock->recvbuf.from_addr,
+ sock->recvbuf.from_addr_len);
+ if (isc_sockaddr_getport(&dev->address) == 0) {
+ if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+ socket_log(__LINE__, sock, &dev->address, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_ZEROPORT,
+ "dropping source port zero packet");
+ }
+ sock->recvbuf.remaining = 0;
+ return;
+ }
+ } else if (sock->type == isc_sockettype_tcp) {
+ dev->address = sock->address;
+ }
+
+ /*
+ * Run through the list of buffers we were given, and find the
+ * first one with space. Once it is found, loop through, filling
+ * the buffers as much as possible.
+ */
+ buffer = ISC_LIST_HEAD(dev->bufferlist);
+ if (buffer != NULL) { // Multi-buffer receive
+ while (buffer != NULL && sock->recvbuf.remaining > 0) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ if (isc_buffer_availablelength(buffer) > 0) {
+ isc_buffer_availableregion(buffer, &r);
+ copylen = min(r.length,
+ sock->recvbuf.remaining);
+ memmove(r.base, sock->recvbuf.consume_position,
+ copylen);
+ sock->recvbuf.consume_position += copylen;
+ sock->recvbuf.remaining -= copylen;
+ isc_buffer_add(buffer, copylen);
+ dev->n += copylen;
+ }
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+ } else { // Single-buffer receive
+ copylen = min(dev->region.length - dev->n, sock->recvbuf.remaining);
+ memmove(dev->region.base + dev->n,
+ sock->recvbuf.consume_position, copylen);
+ sock->recvbuf.consume_position += copylen;
+ sock->recvbuf.remaining -= copylen;
+ dev->n += copylen;
+ }
+
+ /*
+ * UDP receives are all-consuming. That is, if we have 4k worth of
+ * data in our receive buffer, and the caller only gave us
+ * 1k of space, we will toss the remaining 3k of data. TCP
+ * will keep the extra data around and use it for later requests.
+ */
+ if (sock->type == isc_sockettype_udp)
+ sock->recvbuf.remaining = 0;
+}
+
+/*
+ * Copy out as much data from the internal buffer to done events.
+ * As each done event is filled, send it along its way.
+ */
+static void
+completeio_recv(isc_socket_t *sock)
+{
+ isc_socketevent_t *dev;
+
+ /*
+ * If we are in the process of filling our buffer, we cannot
+ * touch it yet, so don't.
+ */
+ if (sock->pending_recv > 0)
+ return;
+
+ while (sock->recvbuf.remaining > 0 && !ISC_LIST_EMPTY(sock->recv_list)) {
+ dev = ISC_LIST_HEAD(sock->recv_list);
+
+ /*
+ * See if we have sufficient data in our receive buffer
+ * to handle this. If we do, copy out the data.
+ */
+ fill_recv(sock, dev);
+
+ /*
+ * Did we satisfy it?
+ */
+ if (dev->n >= dev->minimum) {
+ dev->result = ISC_R_SUCCESS;
+ send_recvdone_event(sock, &dev);
+ }
+ }
+}
+
+/*
+ * Returns:
+ * DOIO_SUCCESS The operation succeeded. dev->result contains
+ * ISC_R_SUCCESS.
+ *
+ * DOIO_HARD A hard or unexpected I/O error was encountered.
+ * dev->result contains the appropriate error.
+ *
+ * DOIO_SOFT A soft I/O error was encountered. No senddone
+ * event was sent. The operation should be retried.
+ *
+ * No other return values are possible.
+ */
+static int
+completeio_send(isc_socket_t *sock, isc_socketevent_t *dev,
+ struct msghdr *messagehdr, int cc, int send_errno)
+{
+ char strbuf[ISC_STRERRORSIZE];
+
+ if (send_errno != 0) {
+ if (SOFT_ERROR(send_errno))
+ return (DOIO_SOFT);
+
+ return (map_socket_error(sock, send_errno, &dev->result,
+ strbuf, sizeof(strbuf)));
+ }
+
+ /*
+ * If we write less than we expected, update counters, poke.
+ */
+ dev->n += cc;
+ if (cc != messagehdr->msg_totallen)
+ return (DOIO_SOFT);
+
+ /*
+ * Exactly what we wanted to write. We're done with this
+ * entry. Post its completion event.
+ */
+ dev->result = ISC_R_SUCCESS;
+ return (DOIO_SUCCESS);
+}
+
+static int
+startio_send(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
+ int *send_errno)
+{
+ char *cmsg = NULL;
+ char strbuf[ISC_STRERRORSIZE];
+ IoCompletionInfo *lpo;
+ int status;
+ struct msghdr *mh;
+
+ lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
+ HEAP_ZERO_MEMORY,
+ sizeof(IoCompletionInfo));
+ RUNTIME_CHECK(lpo != NULL);
+ lpo->request_type = SOCKET_SEND;
+ lpo->dev = dev;
+ mh = &lpo->messagehdr;
+ memset(mh, 0, sizeof(struct msghdr));
+ ISC_LIST_INIT(lpo->bufferlist);
+
+ build_msghdr_send(sock, dev, mh, cmsg, sock->iov, lpo);
+
+ *nbytes = internal_sendmsg(sock, lpo, mh, 0, send_errno);
+
+ if (*nbytes <= 0) {
+ /*
+ * I/O has been initiated
+ * completion will be through the completion port
+ */
+ if (PENDING_ERROR(*send_errno)) {
+ status = DOIO_PENDING;
+ goto done;
+ }
+
+ if (SOFT_ERROR(*send_errno)) {
+ status = DOIO_SOFT;
+ goto done;
+ }
+
+ /*
+ * If we got this far then something is wrong
+ */
+ if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+ isc__strerror(*send_errno, strbuf, sizeof(strbuf));
+ socket_log(__LINE__, sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_INTERNALSEND,
+ "startio_send: internal_sendmsg(%d) %d "
+ "bytes, err %d/%s",
+ sock->fd, *nbytes, *send_errno, strbuf);
+ }
+ status = DOIO_HARD;
+ goto done;
+ }
+ dev->result = ISC_R_SUCCESS;
+ status = DOIO_SOFT;
+ done:
+ _set_state(sock, SOCK_DATA);
+ return (status);
+}
+
+static void
+use_min_mtu(isc_socket_t *sock) {
+#ifdef IPV6_USE_MIN_MTU
+ /* use minimum MTU */
+ if (sock->pf == AF_INET6) {
+ int on = 1;
+ (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
+ (void *)&on, sizeof(on));
+ }
+#else
+ UNUSED(sock);
+#endif
+}
+
+static isc_result_t
+allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
+ isc_socket_t **socketp) {
+ isc_socket_t *sock;
+ isc_result_t result;
+
+ sock = isc_mem_get(manager->mctx, sizeof(*sock));
+
+ if (sock == NULL)
+ return (ISC_R_NOMEMORY);
+
+ sock->magic = 0;
+ sock->references = 0;
+
+ sock->manager = manager;
+ sock->type = type;
+ sock->fd = INVALID_SOCKET;
+
+ ISC_LINK_INIT(sock, link);
+
+ /*
+ * Set up list of readers and writers to be initially empty.
+ */
+ ISC_LIST_INIT(sock->recv_list);
+ ISC_LIST_INIT(sock->send_list);
+ ISC_LIST_INIT(sock->accept_list);
+ ISC_LIST_INIT(sock->connect_list);
+ sock->pending_accept = 0;
+ sock->pending_recv = 0;
+ sock->pending_send = 0;
+ sock->pending_iocp = 0;
+ sock->listener = 0;
+ sock->connected = 0;
+ sock->pending_connect = 0;
+ sock->bound = 0;
+ sock->dupped = 0;
+ memset(sock->name, 0, sizeof(sock->name)); // zero the name field
+ _set_state(sock, SOCK_INITIALIZED);
+
+ sock->recvbuf.len = 65536;
+ sock->recvbuf.consume_position = sock->recvbuf.base;
+ sock->recvbuf.remaining = 0;
+ sock->recvbuf.base = isc_mem_get(manager->mctx, sock->recvbuf.len); // max buffer size
+ if (sock->recvbuf.base == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto error;
+ }
+
+ /*
+ * Initialize the lock.
+ */
+ result = isc_mutex_init(&sock->lock);
+ if (result != ISC_R_SUCCESS)
+ goto error;
+
+ socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+ "allocated");
+
+ sock->magic = SOCKET_MAGIC;
+ *socketp = sock;
+
+ return (ISC_R_SUCCESS);
+
+ error:
+ if (sock->recvbuf.base != NULL)
+ isc_mem_put(manager->mctx, sock->recvbuf.base, sock->recvbuf.len);
+ isc_mem_put(manager->mctx, sock, sizeof(*sock));
+
+ return (result);
+}
+
+/*
+ * Verify that the socket state is consistent.
+ */
+static void
+consistent(isc_socket_t *sock) {
+
+ isc_socketevent_t *dev;
+ isc_socket_newconnev_t *nev;
+ unsigned int count;
+ char *crash_reason;
+ bool crash = false;
+
+ REQUIRE(sock->pending_iocp == sock->pending_recv + sock->pending_send
+ + sock->pending_accept + sock->pending_connect);
+
+ dev = ISC_LIST_HEAD(sock->send_list);
+ count = 0;
+ while (dev != NULL) {
+ count++;
+ dev = ISC_LIST_NEXT(dev, ev_link);
+ }
+ if (count > sock->pending_send) {
+ crash = true;
+ crash_reason = "send_list > sock->pending_send";
+ }
+
+ nev = ISC_LIST_HEAD(sock->accept_list);
+ count = 0;
+ while (nev != NULL) {
+ count++;
+ nev = ISC_LIST_NEXT(nev, ev_link);
+ }
+ if (count > sock->pending_accept) {
+ crash = true;
+ crash_reason = "accept_list > sock->pending_accept";
+ }
+
+ if (crash) {
+ socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_DESTROYING, "SOCKET INCONSISTENT: %s",
+ crash_reason);
+ sock_dump(sock);
+ INSIST(crash == false);
+ }
+}
+
+/*
+ * Maybe free the socket.
+ *
+ * This function will verify tht the socket is no longer in use in any way,
+ * either internally or externally. This is the only place where this
+ * check is to be made; if some bit of code believes that IT is done with
+ * the socket (e.g., some reference counter reaches zero), it should call
+ * this function.
+ *
+ * When calling this function, the socket must be locked, and the manager
+ * must be unlocked.
+ *
+ * When this function returns, *socketp will be NULL. No tricks to try
+ * to hold on to this pointer are allowed.
+ */
+static void
+maybe_free_socket(isc_socket_t **socketp, int lineno) {
+ isc_socket_t *sock = *socketp;
+ *socketp = NULL;
+
+ INSIST(VALID_SOCKET(sock));
+ CONSISTENT(sock);
+
+ if (sock->pending_iocp > 0
+ || sock->pending_recv > 0
+ || sock->pending_send > 0
+ || sock->pending_accept > 0
+ || sock->references > 0
+ || sock->pending_connect == 1
+ || !ISC_LIST_EMPTY(sock->recv_list)
+ || !ISC_LIST_EMPTY(sock->send_list)
+ || !ISC_LIST_EMPTY(sock->accept_list)
+ || !ISC_LIST_EMPTY(sock->connect_list)
+ || sock->fd != INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return;
+ }
+ UNLOCK(&sock->lock);
+
+ free_socket(&sock, lineno);
+}
+
+void
+free_socket(isc_socket_t **sockp, int lineno) {
+ isc_socketmgr_t *manager;
+ isc_socket_t *sock = *sockp;
+ *sockp = NULL;
+
+ /*
+ * Seems we can free the socket after all.
+ */
+ manager = sock->manager;
+ socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat,
+ ISC_MSGSET_SOCKET, ISC_MSG_DESTROYING,
+ "freeing socket line %d fd %d lock %p semaphore %p",
+ lineno, sock->fd, &sock->lock, sock->lock.LockSemaphore);
+
+ sock->magic = 0;
+ DESTROYLOCK(&sock->lock);
+
+ if (sock->recvbuf.base != NULL)
+ isc_mem_put(manager->mctx, sock->recvbuf.base,
+ sock->recvbuf.len);
+
+ LOCK(&manager->lock);
+ if (ISC_LINK_LINKED(sock, link))
+ ISC_LIST_UNLINK(manager->socklist, sock, link);
+ isc_mem_put(manager->mctx, sock, sizeof(*sock));
+
+ if (ISC_LIST_EMPTY(manager->socklist))
+ SIGNAL(&manager->shutdown_ok);
+ UNLOCK(&manager->lock);
+}
+
+/*
+ * Create a new 'type' socket managed by 'manager'. Events
+ * will be posted to 'task' and when dispatched 'action' will be
+ * called with 'arg' as the arg value. The new socket is returned
+ * in 'socketp'.
+ */
+static isc_result_t
+socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
+ isc_socket_t **socketp, isc_socket_t *dup_socket)
+{
+ isc_socket_t *sock = NULL;
+ isc_result_t result;
+#if defined(USE_CMSG)
+ int on = 1;
+#endif
+#if defined(SO_RCVBUF)
+ ISC_SOCKADDR_LEN_T optlen;
+ int size;
+#endif
+ int socket_errno;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+ REQUIRE(type != isc_sockettype_fdwatch);
+
+#ifndef SOCK_RAW
+ if (type == isc_sockettype_raw)
+ return (ISC_R_NOTIMPLEMENTED);
+#endif
+
+ result = allocate_socket(manager, type, &sock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ sock->pf = pf;
+ switch (type) {
+ case isc_sockettype_udp:
+ sock->fd = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock->fd != INVALID_SOCKET) {
+ result = connection_reset_fix(sock->fd);
+ if (result != ISC_R_SUCCESS) {
+ socket_log(__LINE__, sock,
+ NULL, EVENT, NULL, 0, 0,
+ "closed %d %d %d "
+ "con_reset_fix_failed",
+ sock->pending_recv,
+ sock->pending_send,
+ sock->references);
+ closesocket(sock->fd);
+ _set_state(sock, SOCK_CLOSED);
+ sock->fd = INVALID_SOCKET;
+ free_socket(&sock, __LINE__);
+ return (result);
+ }
+ }
+ break;
+ case isc_sockettype_tcp:
+ sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP);
+ break;
+#ifdef SOCK_RAW
+ case isc_sockettype_raw:
+ sock->fd = socket(pf, SOCK_RAW, 0);
+#ifdef PF_ROUTE
+ if (pf == PF_ROUTE)
+ sock->bound = 1;
+#endif
+ break;
+#endif
+ }
+
+ if (sock->fd == INVALID_SOCKET) {
+ socket_errno = WSAGetLastError();
+ free_socket(&sock, __LINE__);
+
+ switch (socket_errno) {
+ case WSAEMFILE:
+ case WSAENOBUFS:
+ return (ISC_R_NORESOURCES);
+
+ case WSAEPROTONOSUPPORT:
+ case WSAEPFNOSUPPORT:
+ case WSAEAFNOSUPPORT:
+ return (ISC_R_FAMILYNOSUPPORT);
+
+ default:
+ isc__strerror(socket_errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ result = make_nonblock(sock->fd);
+ if (result != ISC_R_SUCCESS) {
+ socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+ "closed %d %d %d make_nonblock_failed",
+ sock->pending_recv, sock->pending_send,
+ sock->references);
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ free_socket(&sock, __LINE__);
+ return (result);
+ }
+
+ /*
+ * Use minimum mtu if possible.
+ */
+ use_min_mtu(sock);
+
+#if defined(USE_CMSG) || defined(SO_RCVBUF)
+ if (type == isc_sockettype_udp) {
+
+#if defined(USE_CMSG)
+#if defined(ISC_PLATFORM_HAVEIPV6)
+#ifdef IPV6_RECVPKTINFO
+ /* 2292bis */
+ if ((pf == AF_INET6)
+ && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ (char *)&on, sizeof(on)) < 0)) {
+ isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_RECVPKTINFO) "
+ "%s: %s", sock->fd,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+#else
+ /* 2292 */
+ if ((pf == AF_INET6)
+ && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO,
+ (char *)&on, sizeof(on)) < 0)) {
+ isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_PKTINFO) %s: %s",
+ sock->fd,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+#endif /* IPV6_RECVPKTINFO */
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+#endif /* defined(USE_CMSG) */
+
+#if defined(SO_RCVBUF)
+ optlen = sizeof(size);
+ if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+ (char *)&size, &optlen) >= 0 &&
+ size < RCVBUFSIZE) {
+ size = RCVBUFSIZE;
+ (void)setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+ (char *)&size, sizeof(size));
+ }
+#endif
+
+ }
+#endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */
+
+ _set_state(sock, SOCK_OPEN);
+ sock->references = 1;
+ *socketp = sock;
+
+ iocompletionport_update(sock);
+
+ if (dup_socket) {
+#ifndef ISC_ALLOW_MAPPED
+ isc__socket_ipv6only(sock, true);
+#endif
+
+ if (dup_socket->bound) {
+ isc_sockaddr_t local;
+
+ result = isc__socket_getsockname(dup_socket, &local);
+ if (result != ISC_R_SUCCESS) {
+ isc_socket_close(sock);
+ return (result);
+ }
+ result = isc__socket_bind(sock, &local,
+ ISC_SOCKET_REUSEADDRESS);
+ if (result != ISC_R_SUCCESS) {
+ isc_socket_close(sock);
+ return (result);
+ }
+ }
+ sock->dupped = 1;
+ }
+
+ /*
+ * Note we don't have to lock the socket like we normally would because
+ * there are no external references to it yet.
+ */
+ LOCK(&manager->lock);
+ ISC_LIST_APPEND(manager->socklist, sock, link);
+ InterlockedIncrement(&manager->totalSockets);
+ UNLOCK(&manager->lock);
+
+ socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat,
+ ISC_MSGSET_SOCKET, ISC_MSG_CREATED,
+ "created %u type %u", sock->fd, type);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
+ isc_socket_t **socketp)
+{
+ return (socket_create(manager, pf, type, socketp, NULL));
+}
+
+isc_result_t
+isc__socket_dup(isc_socket_t *sock, isc_socket_t **socketp) {
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ return (socket_create(sock->manager, sock->pf, sock->type,
+ socketp, sock));
+}
+
+isc_result_t
+isc_socket_open(isc_socket_t *sock) {
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(sock->type != isc_sockettype_fdwatch);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+/*
+ * Attach to a socket. Caller must explicitly detach when it is done.
+ */
+void
+isc__socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+ sock->references++;
+ UNLOCK(&sock->lock);
+
+ *socketp = sock;
+}
+
+/*
+ * Dereference a socket. If this is the last reference to it, clean things
+ * up by destroying the socket.
+ */
+void
+isc__socket_detach(isc_socket_t **socketp) {
+ isc_socket_t *sock;
+
+ REQUIRE(socketp != NULL);
+ sock = *socketp;
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(sock->type != isc_sockettype_fdwatch);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+ REQUIRE(sock->references > 0);
+ sock->references--;
+
+ socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+ "detach_socket %d %d %d",
+ sock->pending_recv, sock->pending_send,
+ sock->references);
+
+ if (sock->references == 0 && sock->fd != INVALID_SOCKET) {
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ _set_state(sock, SOCK_CLOSED);
+ }
+
+ maybe_free_socket(&sock, __LINE__);
+
+ *socketp = NULL;
+}
+
+isc_result_t
+isc_socket_close(isc_socket_t *sock) {
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(sock->type != isc_sockettype_fdwatch);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+/*
+ * Dequeue an item off the given socket's read queue, set the result code
+ * in the done event to the one provided, and send it to the task it was
+ * destined for.
+ *
+ * If the event to be sent is on a list, remove it before sending. If
+ * asked to, send and detach from the task as well.
+ *
+ * Caller must have the socket locked if the event is attached to the socket.
+ */
+static void
+send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
+ isc_task_t *task;
+
+ task = (*dev)->ev_sender;
+ (*dev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*dev, ev_link))
+ ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
+
+ if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
+ == ISC_SOCKEVENTATTR_ATTACHED)
+ isc_task_sendanddetach(&task, (isc_event_t **)dev);
+ else
+ isc_task_send(task, (isc_event_t **)dev);
+
+ CONSISTENT(sock);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ */
+static void
+send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
+ isc_task_t *task;
+
+ INSIST(dev != NULL && *dev != NULL);
+
+ task = (*dev)->ev_sender;
+ (*dev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*dev, ev_link))
+ ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);
+
+ if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
+ == ISC_SOCKEVENTATTR_ATTACHED)
+ isc_task_sendanddetach(&task, (isc_event_t **)dev);
+ else
+ isc_task_send(task, (isc_event_t **)dev);
+
+ CONSISTENT(sock);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ */
+static void
+send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev) {
+ isc_task_t *task;
+
+ INSIST(adev != NULL && *adev != NULL);
+
+ task = (*adev)->ev_sender;
+ (*adev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*adev, ev_link))
+ ISC_LIST_DEQUEUE(sock->accept_list, *adev, ev_link);
+
+ isc_task_sendanddetach(&task, (isc_event_t **)adev);
+
+ CONSISTENT(sock);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ */
+static void
+send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev) {
+ isc_task_t *task;
+
+ INSIST(cdev != NULL && *cdev != NULL);
+
+ task = (*cdev)->ev_sender;
+ (*cdev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*cdev, ev_link))
+ ISC_LIST_DEQUEUE(sock->connect_list, *cdev, ev_link);
+
+ isc_task_sendanddetach(&task, (isc_event_t **)cdev);
+
+ CONSISTENT(sock);
+}
+
+/*
+ * On entry to this function, the event delivered is the internal
+ * readable event, and the first item on the accept_list should be
+ * the done event we want to send. If the list is empty, this is a no-op,
+ * so just close the new connection, unlock, and return.
+ *
+ * Note the socket is locked before entering here
+ */
+static void
+internal_accept(isc_socket_t *sock, IoCompletionInfo *lpo, int accept_errno) {
+ isc_socket_newconnev_t *adev;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_socket_t *nsock;
+ struct sockaddr *localaddr;
+ int localaddr_len = sizeof(*localaddr);
+ struct sockaddr *remoteaddr;
+ int remoteaddr_len = sizeof(*remoteaddr);
+
+ INSIST(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ socket_log(__LINE__, sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+ "internal_accept called");
+
+ INSIST(sock->listener);
+
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_accept > 0);
+ sock->pending_accept--;
+
+ adev = lpo->adev;
+
+ /*
+ * If the event is no longer in the list we can just return.
+ */
+ if (!acceptdone_is_active(sock, adev))
+ goto done;
+
+ nsock = adev->newsocket;
+
+ /*
+ * Pull off the done event.
+ */
+ ISC_LIST_UNLINK(sock->accept_list, adev, ev_link);
+
+ /*
+ * Extract the addresses from the socket, copy them into the structure,
+ * and return the new socket.
+ */
+ ISCGetAcceptExSockaddrs(lpo->acceptbuffer, 0,
+ sizeof(SOCKADDR_STORAGE) + 16, sizeof(SOCKADDR_STORAGE) + 16,
+ (LPSOCKADDR *)&localaddr, &localaddr_len,
+ (LPSOCKADDR *)&remoteaddr, &remoteaddr_len);
+ memmove(&adev->address.type, remoteaddr, remoteaddr_len);
+ adev->address.length = remoteaddr_len;
+ nsock->address = adev->address;
+ nsock->pf = adev->address.type.sa.sa_family;
+
+ socket_log(__LINE__, nsock, &nsock->address, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+ "internal_accept parent %p", sock);
+
+ result = make_nonblock(adev->newsocket->fd);
+ INSIST(result == ISC_R_SUCCESS);
+
+ /*
+ * Use minimum mtu if possible.
+ */
+ use_min_mtu(adev->newsocket);
+
+ INSIST(setsockopt(nsock->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ (char *)&sock->fd, sizeof(sock->fd)) == 0);
+
+ /*
+ * Hook it up into the manager.
+ */
+ nsock->bound = 1;
+ nsock->connected = 1;
+ _set_state(nsock, SOCK_OPEN);
+
+ LOCK(&nsock->manager->lock);
+ ISC_LIST_APPEND(nsock->manager->socklist, nsock, link);
+ InterlockedIncrement(&nsock->manager->totalSockets);
+ UNLOCK(&nsock->manager->lock);
+
+ socket_log(__LINE__, sock, &nsock->address, CREATION,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
+ "accepted_connection new_socket %p fd %d",
+ nsock, nsock->fd);
+
+ adev->result = result;
+ send_acceptdone_event(sock, &adev);
+
+done:
+ CONSISTENT(sock);
+ UNLOCK(&sock->lock);
+
+ HeapFree(hHeapHandle, 0, lpo->acceptbuffer);
+ lpo->acceptbuffer = NULL;
+}
+
+/*
+ * Called when a socket with a pending connect() finishes.
+ * Note that the socket is locked before entering.
+ */
+static void
+internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) {
+ isc_socket_connev_t *cdev;
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_connect == 1);
+ sock->pending_connect = 0;
+
+ /*
+ * If the event is no longer in the list we can just close and return.
+ */
+ cdev = lpo->cdev;
+ if (!connectdone_is_active(sock, cdev)) {
+ sock->pending_connect = 0;
+ if (sock->fd != INVALID_SOCKET) {
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ _set_state(sock, SOCK_CLOSED);
+ }
+ CONSISTENT(sock);
+ UNLOCK(&sock->lock);
+ return;
+ }
+
+ /*
+ * Check possible Windows network event error status here.
+ */
+ if (connect_errno != 0) {
+ /*
+ * If the error is SOFT, just try again on this
+ * fd and pretend nothing strange happened.
+ */
+ if (SOFT_ERROR(connect_errno) ||
+ connect_errno == WSAEINPROGRESS) {
+ sock->pending_connect = 1;
+ CONSISTENT(sock);
+ UNLOCK(&sock->lock);
+ return;
+ }
+
+ /*
+ * Translate other errors into ISC_R_* flavors.
+ */
+ switch (connect_errno) {
+#define ERROR_MATCH(a, b) case a: result = b; break;
+ ERROR_MATCH(WSAEACCES, ISC_R_NOPERM);
+ ERROR_MATCH(WSAEADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(WSAEAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(WSAECONNREFUSED, ISC_R_CONNREFUSED);
+ ERROR_MATCH(WSAEHOSTUNREACH, ISC_R_HOSTUNREACH);
+ ERROR_MATCH(WSAEHOSTDOWN, ISC_R_HOSTDOWN);
+ ERROR_MATCH(WSAENETUNREACH, ISC_R_NETUNREACH);
+ ERROR_MATCH(WSAENETDOWN, ISC_R_NETDOWN);
+ ERROR_MATCH(WSAENOBUFS, ISC_R_NORESOURCES);
+ ERROR_MATCH(WSAECONNRESET, ISC_R_CONNECTIONRESET);
+ ERROR_MATCH(WSAECONNABORTED, ISC_R_CONNECTIONRESET);
+ ERROR_MATCH(WSAETIMEDOUT, ISC_R_TIMEDOUT);
+#undef ERROR_MATCH
+ default:
+ result = ISC_R_UNEXPECTED;
+ isc__strerror(connect_errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_connect: connect() %s",
+ strbuf);
+ }
+ } else {
+ INSIST(setsockopt(sock->fd, SOL_SOCKET,
+ SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == 0);
+ result = ISC_R_SUCCESS;
+ sock->connected = 1;
+ socket_log(__LINE__, sock, &sock->address, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
+ "internal_connect: success");
+ }
+
+ do {
+ cdev->result = result;
+ send_connectdone_event(sock, &cdev);
+ cdev = ISC_LIST_HEAD(sock->connect_list);
+ } while (cdev != NULL);
+
+ UNLOCK(&sock->lock);
+}
+
+/*
+ * Loop through the socket, returning ISC_R_EOF for each done event pending.
+ */
+static void
+send_recvdone_abort(isc_socket_t *sock, isc_result_t result) {
+ isc_socketevent_t *dev;
+
+ while (!ISC_LIST_EMPTY(sock->recv_list)) {
+ dev = ISC_LIST_HEAD(sock->recv_list);
+ dev->result = result;
+ send_recvdone_event(sock, &dev);
+ }
+}
+
+/*
+ * Loop through the socket, returning result for each done event pending.
+ */
+static void
+send_connectdone_abort(isc_socket_t *sock, isc_result_t result) {
+ isc_socket_connev_t *dev;
+
+ while (!ISC_LIST_EMPTY(sock->connect_list)) {
+ dev = ISC_LIST_HEAD(sock->connect_list);
+ dev->result = result;
+ send_connectdone_event(sock, &dev);
+ }
+}
+
+/*
+ * Take the data we received in our private buffer, and if any recv() calls on
+ * our list are satisfied, send the corresponding done event.
+ *
+ * If we need more data (there are still items on the recv_list after we consume all
+ * our data) then arrange for another system recv() call to fill our buffers.
+ */
+static void
+internal_recv(isc_socket_t *sock, int nbytes)
+{
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ socket_log(__LINE__, sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
+ "internal_recv: %d bytes received", nbytes);
+
+ /*
+ * If we got here, the I/O operation succeeded. However, we might still have removed this
+ * event from our notification list (or never placed it on it due to immediate completion.)
+ * Handle the reference counting here, and handle the cancellation event just after.
+ */
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_recv > 0);
+ sock->pending_recv--;
+
+ /*
+ * The only way we could have gotten here is that our I/O has successfully completed.
+ * Update our pointers, and move on. The only odd case here is that we might not
+ * have received enough data on a TCP stream to satisfy the minimum requirements. If
+ * this is the case, we will re-issue the recv() call for what we need.
+ *
+ * We do check for a recv() of 0 bytes on a TCP stream. This means the remote end
+ * has closed.
+ */
+ if (nbytes == 0 && sock->type == isc_sockettype_tcp) {
+ send_recvdone_abort(sock, ISC_R_EOF);
+ maybe_free_socket(&sock, __LINE__);
+ return;
+ }
+ sock->recvbuf.remaining = nbytes;
+ sock->recvbuf.consume_position = sock->recvbuf.base;
+ completeio_recv(sock);
+
+ /*
+ * If there are more receivers waiting for data, queue another receive
+ * here.
+ */
+ queue_receive_request(sock);
+
+ /*
+ * Unlock and/or destroy if we are the last thing this socket has left to do.
+ */
+ maybe_free_socket(&sock, __LINE__);
+}
+
+static void
+internal_send(isc_socket_t *sock, isc_socketevent_t *dev,
+ struct msghdr *messagehdr, int nbytes, int send_errno, IoCompletionInfo *lpo)
+{
+ buflist_t *buffer;
+
+ /*
+ * Find out what socket this is and lock it.
+ */
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ socket_log(__LINE__, sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
+ "internal_send: task got socket event %p", dev);
+
+ buffer = ISC_LIST_HEAD(lpo->bufferlist);
+ while (buffer != NULL) {
+ ISC_LIST_DEQUEUE(lpo->bufferlist, buffer, link);
+
+ socket_log(__LINE__, sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+ "free_buffer %p %p", buffer, buffer->buf);
+
+ HeapFree(hHeapHandle, 0, buffer->buf);
+ HeapFree(hHeapHandle, 0, buffer);
+ buffer = ISC_LIST_HEAD(lpo->bufferlist);
+ }
+
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_send > 0);
+ sock->pending_send--;
+
+ /* If the event is no longer in the list we can just return */
+ if (!senddone_is_active(sock, dev))
+ goto done;
+
+ /*
+ * Set the error code and send things on its way.
+ */
+ switch (completeio_send(sock, dev, messagehdr, nbytes, send_errno)) {
+ case DOIO_SOFT:
+ break;
+ case DOIO_HARD:
+ case DOIO_SUCCESS:
+ send_senddone_event(sock, &dev);
+ break;
+ }
+
+ done:
+ maybe_free_socket(&sock, __LINE__);
+}
+
+/*
+ * These return if the done event passed in is on the list.
+ * Using these ensures we will not double-send an event.
+ */
+static bool
+senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev)
+{
+ isc_socketevent_t *ldev;
+
+ ldev = ISC_LIST_HEAD(sock->send_list);
+ while (ldev != NULL && ldev != dev)
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+
+ return (ldev == NULL ? false : true);
+}
+
+static bool
+acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev)
+{
+ isc_socket_newconnev_t *ldev;
+
+ ldev = ISC_LIST_HEAD(sock->accept_list);
+ while (ldev != NULL && ldev != dev)
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+
+ return (ldev == NULL ? false : true);
+}
+
+static bool
+connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev)
+{
+ isc_socket_connev_t *cdev;
+
+ cdev = ISC_LIST_HEAD(sock->connect_list);
+ while (cdev != NULL && cdev != dev)
+ cdev = ISC_LIST_NEXT(cdev, ev_link);
+
+ return (cdev == NULL ? false : true);
+}
+
+//
+// The Windows network stack seems to have two very distinct paths depending
+// on what is installed. Specifically, if something is looking at network
+// connections (like an anti-virus or anti-malware application, such as
+// McAfee products) Windows may return additional error conditions which
+// were not previously returned.
+//
+// One specific one is when a TCP SYN scan is used. In this situation,
+// Windows responds with the SYN-ACK, but the scanner never responds with
+// the 3rd packet, the ACK. Windows consiers this a partially open connection.
+// Most Unix networking stacks, and Windows without McAfee installed, will
+// not return this to the caller. However, with this product installed,
+// Windows returns this as a failed status on the Accept() call. Here, we
+// will just re-issue the ISCAcceptEx() call as if nothing had happened.
+//
+// This code should only be called when the listening socket has received
+// such an error. Additionally, the "parent" socket must be locked.
+// Additionally, the lpo argument is re-used here, and must not be freed
+// by the caller.
+//
+static isc_result_t
+restart_accept(isc_socket_t *parent, IoCompletionInfo *lpo)
+{
+ isc_socket_t *nsock = lpo->adev->newsocket;
+ SOCKET new_fd;
+
+ /*
+ * AcceptEx() requires we pass in a socket. Note that we carefully
+ * do not close the previous socket in case of an error message returned by
+ * our new socket() call. If we return an error here, our caller will
+ * clean up.
+ */
+ new_fd = socket(parent->pf, SOCK_STREAM, IPPROTO_TCP);
+ if (nsock->fd == INVALID_SOCKET) {
+ return (ISC_R_FAILURE); // parent will ask windows for error message
+ }
+ closesocket(nsock->fd);
+ nsock->fd = new_fd;
+
+ memset(&lpo->overlapped, 0, sizeof(lpo->overlapped));
+
+ ISCAcceptEx(parent->fd,
+ nsock->fd, /* Accepted Socket */
+ lpo->acceptbuffer, /* Buffer for initial Recv */
+ 0, /* Length of Buffer */
+ sizeof(SOCKADDR_STORAGE) + 16, /* Local address length + 16 */
+ sizeof(SOCKADDR_STORAGE) + 16, /* Remote address lengh + 16 */
+ (LPDWORD)&lpo->received_bytes, /* Bytes Recved */
+ (LPOVERLAPPED)lpo /* Overlapped structure */
+ );
+
+ InterlockedDecrement(&nsock->manager->iocp_total);
+ iocompletionport_update(nsock);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This is the I/O Completion Port Worker Function. It loops forever
+ * waiting for I/O to complete and then forwards them for further
+ * processing. There are a number of these in separate threads.
+ */
+static isc_threadresult_t WINAPI
+SocketIoThread(LPVOID ThreadContext) {
+ isc_socketmgr_t *manager = ThreadContext;
+ BOOL bSuccess = FALSE;
+ DWORD nbytes;
+ IoCompletionInfo *lpo = NULL;
+ isc_socket_t *sock = NULL;
+ int request;
+ struct msghdr *messagehdr = NULL;
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+ int errstatus;
+
+ REQUIRE(VALID_MANAGER(manager));
+
+ /*
+ * Set the thread priority high enough so I/O will
+ * preempt normal recv packet processing, but not
+ * higher than the timer sync thread.
+ */
+ if (!SetThreadPriority(GetCurrentThread(),
+ THREAD_PRIORITY_ABOVE_NORMAL)) {
+ errval = GetLastError();
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FAILED,
+ "Can't set thread priority: %s"),
+ strbuf);
+ }
+
+ /*
+ * Loop forever waiting on I/O Completions and then processing them
+ */
+ while (TRUE) {
+ wait_again:
+ bSuccess = GetQueuedCompletionStatus(manager->hIoCompletionPort,
+ &nbytes,
+ (PULONG_PTR)&sock,
+ (LPWSAOVERLAPPED *)&lpo,
+ INFINITE);
+ if (lpo == NULL) /* Received request to exit */
+ break;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ request = lpo->request_type;
+
+ if (!bSuccess)
+ errstatus = GetLastError();
+ else
+ errstatus = 0;
+ if (!bSuccess && errstatus != ERROR_MORE_DATA) {
+ isc_result_t isc_result;
+
+ /*
+ * Did the I/O operation complete?
+ */
+ isc_result = isc__errno2result(errstatus);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+ switch (request) {
+ case SOCKET_RECV:
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_recv > 0);
+ sock->pending_recv--;
+ if (!sock->connected &&
+ ((errstatus == ERROR_HOST_UNREACHABLE) ||
+ (errstatus == WSAENETRESET) ||
+ (errstatus == WSAECONNRESET))) {
+ /* ignore soft errors */
+ queue_receive_request(sock);
+ break;
+ }
+ send_recvdone_abort(sock, isc_result);
+ if (isc_result == ISC_R_UNEXPECTED) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "SOCKET_RECV: Windows error code: %d, returning ISC error %d",
+ errstatus, isc_result);
+ }
+ break;
+
+ case SOCKET_SEND:
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_send > 0);
+ sock->pending_send--;
+ if (senddone_is_active(sock, lpo->dev)) {
+ lpo->dev->result = isc_result;
+ socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+ "canceled_send");
+ send_senddone_event(sock, &lpo->dev);
+ }
+ break;
+
+ case SOCKET_ACCEPT:
+ INSIST(sock->pending_iocp > 0);
+ INSIST(sock->pending_accept > 0);
+
+ socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+ "Accept: errstatus=%d isc_result=%d", errstatus, isc_result);
+
+ if (acceptdone_is_active(sock, lpo->adev)) {
+ if (restart_accept(sock, lpo) == ISC_R_SUCCESS) {
+ UNLOCK(&sock->lock);
+ goto wait_again;
+ } else {
+ errstatus = GetLastError();
+ isc_result = isc__errno2result(errstatus);
+ socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+ "restart_accept() failed: errstatus=%d isc_result=%d",
+ errstatus, isc_result);
+ }
+ }
+
+ sock->pending_iocp--;
+ sock->pending_accept--;
+ if (acceptdone_is_active(sock, lpo->adev)) {
+ closesocket(lpo->adev->newsocket->fd);
+ lpo->adev->newsocket->fd = INVALID_SOCKET;
+ lpo->adev->newsocket->references--;
+ free_socket(&lpo->adev->newsocket, __LINE__);
+ lpo->adev->result = isc_result;
+ socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+ "canceled_accept");
+ send_acceptdone_event(sock, &lpo->adev);
+ }
+ break;
+
+ case SOCKET_CONNECT:
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_connect == 1);
+ sock->pending_connect = 0;
+ if (connectdone_is_active(sock, lpo->cdev)) {
+ socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+ "canceled_connect");
+ send_connectdone_abort(sock, isc_result);
+ }
+ break;
+ }
+ maybe_free_socket(&sock, __LINE__);
+
+ if (lpo != NULL)
+ HeapFree(hHeapHandle, 0, lpo);
+ continue;
+ }
+
+ messagehdr = &lpo->messagehdr;
+
+ switch (request) {
+ case SOCKET_RECV:
+ internal_recv(sock, nbytes);
+ break;
+ case SOCKET_SEND:
+ internal_send(sock, lpo->dev, messagehdr, nbytes, errstatus, lpo);
+ break;
+ case SOCKET_ACCEPT:
+ internal_accept(sock, lpo, errstatus);
+ break;
+ case SOCKET_CONNECT:
+ internal_connect(sock, lpo, errstatus);
+ break;
+ }
+
+ if (lpo != NULL)
+ HeapFree(hHeapHandle, 0, lpo);
+ }
+
+ /*
+ * Exit Completion Port Thread
+ */
+ manager_log(manager, TRACE,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_EXITING, "SocketIoThread exiting"));
+ return ((isc_threadresult_t)0);
+}
+
+/*
+ * Create a new socket manager.
+ */
+isc_result_t
+isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
+ return (isc_socketmgr_create2(mctx, managerp, 0));
+}
+
+isc_result_t
+isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
+ unsigned int maxsocks)
+{
+ isc_socketmgr_t *manager;
+ isc_result_t result;
+
+ REQUIRE(managerp != NULL && *managerp == NULL);
+
+ if (maxsocks != 0)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ manager = isc_mem_get(mctx, sizeof(*manager));
+ if (manager == NULL)
+ return (ISC_R_NOMEMORY);
+
+ InitSockets();
+
+ manager->magic = SOCKET_MANAGER_MAGIC;
+ manager->mctx = NULL;
+ manager->stats = NULL;
+ ISC_LIST_INIT(manager->socklist);
+ result = isc_mutex_init(&manager->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ return (result);
+ }
+ if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) {
+ DESTROYLOCK(&manager->lock);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ isc_mem_attach(mctx, &manager->mctx);
+
+ iocompletionport_init(manager); /* Create the Completion Ports */
+
+ manager->bShutdown = false;
+ manager->totalSockets = 0;
+ manager->iocp_total = 0;
+
+ *managerp = manager;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp) {
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(nsockp != NULL);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+void
+isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) {
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(ISC_LIST_EMPTY(manager->socklist));
+ REQUIRE(manager->stats == NULL);
+ REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max);
+
+ isc_stats_attach(stats, &manager->stats);
+}
+
+void
+isc__socketmgr_destroy(isc_socketmgr_t **managerp) {
+ isc_socketmgr_t *manager;
+ int i;
+ isc_mem_t *mctx;
+
+ /*
+ * Destroy a socket manager.
+ */
+
+ REQUIRE(managerp != NULL);
+ manager = *managerp;
+ REQUIRE(VALID_MANAGER(manager));
+
+ LOCK(&manager->lock);
+
+ /*
+ * Wait for all sockets to be destroyed.
+ */
+ while (!ISC_LIST_EMPTY(manager->socklist)) {
+ manager_log(manager, CREATION,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_SOCKETSREMAIN,
+ "sockets exist"));
+ WAIT(&manager->shutdown_ok, &manager->lock);
+ }
+
+ UNLOCK(&manager->lock);
+
+ /*
+ * Here, we need to had some wait code for the completion port
+ * thread.
+ */
+ signal_iocompletionport_exit(manager);
+ manager->bShutdown = true;
+
+ /*
+ * Wait for threads to exit.
+ */
+ for (i = 0; i < manager->maxIOCPThreads; i++) {
+ if (isc_thread_join((isc_thread_t) manager->hIOCPThreads[i],
+ NULL) != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_thread_join() for Completion Port %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ }
+ /*
+ * Clean up.
+ */
+
+ CloseHandle(manager->hIoCompletionPort);
+
+ (void)isc_condition_destroy(&manager->shutdown_ok);
+
+ DESTROYLOCK(&manager->lock);
+ if (manager->stats != NULL)
+ isc_stats_detach(&manager->stats);
+ manager->magic = 0;
+ mctx= manager->mctx;
+ isc_mem_put(mctx, manager, sizeof(*manager));
+
+ isc_mem_detach(&mctx);
+
+ *managerp = NULL;
+}
+
+static void
+queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev)
+{
+ isc_task_t *ntask = NULL;
+
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ /*
+ * Enqueue the request.
+ */
+ INSIST(!ISC_LINK_LINKED(dev, ev_link));
+ ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
+
+ socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+ "queue_receive_event: event %p -> task %p",
+ dev, ntask);
+}
+
+/*
+ * Check the pending receive queue, and if we have data pending, give it to this
+ * caller. If we have none, queue an I/O request. If this caller is not the first
+ * on the list, then we will just queue this event and return.
+ *
+ * Caller must have the socket locked.
+ */
+static isc_result_t
+socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+ unsigned int flags)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+
+ dev->ev_sender = task;
+
+ if (sock->fd == INVALID_SOCKET)
+ return (ISC_R_EOF);
+
+ /*
+ * Queue our event on the list of things to do. Call our function to
+ * attempt to fill buffers as much as possible, and return done events.
+ * We are going to lie about our handling of the ISC_SOCKFLAG_IMMEDIATE
+ * here and tell our caller that we could not satisfy it immediately.
+ */
+ queue_receive_event(sock, task, dev);
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
+ result = ISC_R_INPROGRESS;
+
+ completeio_recv(sock);
+
+ /*
+ * If there are more receivers waiting for data, queue another receive
+ * here. If the
+ */
+ queue_receive_request(sock);
+
+ return (result);
+}
+
+isc_result_t
+isc__socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ unsigned int minimum, isc_task_t *task,
+ isc_taskaction_t action, void *arg)
+{
+ isc_socketevent_t *dev;
+ isc_socketmgr_t *manager;
+ unsigned int iocount;
+ isc_buffer_t *buffer;
+ isc_result_t ret;
+
+ REQUIRE(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * Make sure that the socket is not closed. XXXMLG change error here?
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ REQUIRE(buflist != NULL);
+ REQUIRE(!ISC_LIST_EMPTY(*buflist));
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ iocount = isc_bufferlist_availablecount(buflist);
+ REQUIRE(iocount > 0);
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(manager->mctx, sock,
+ ISC_SOCKEVENT_RECVDONE, action, arg);
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+
+ /*
+ * UDP sockets are always partial read
+ */
+ if (sock->type == isc_sockettype_udp)
+ dev->minimum = 1;
+ else {
+ if (minimum == 0)
+ dev->minimum = iocount;
+ else
+ dev->minimum = minimum;
+ }
+
+ /*
+ * Move each buffer from the passed in list to our internal one.
+ */
+ buffer = ISC_LIST_HEAD(*buflist);
+ while (buffer != NULL) {
+ ISC_LIST_DEQUEUE(*buflist, buffer, link);
+ ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
+ buffer = ISC_LIST_HEAD(*buflist);
+ }
+
+ ret = socket_recv(sock, dev, task, 0);
+
+ UNLOCK(&sock->lock);
+ return (ret);
+}
+
+isc_result_t
+isc__socket_recv(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_taskaction_t action, void *arg)
+{
+ isc_socketevent_t *dev;
+ isc_socketmgr_t *manager;
+ isc_result_t ret;
+
+ REQUIRE(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(manager->mctx, sock,
+ ISC_SOCKEVENT_RECVDONE, action, arg);
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+
+ ret = isc_socket_recv2(sock, region, minimum, task, dev, 0);
+ UNLOCK(&sock->lock);
+ return (ret);
+}
+
+isc_result_t
+isc__socket_recv2(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_socketevent_t *event, unsigned int flags)
+{
+ isc_result_t ret;
+
+ REQUIRE(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ event->result = ISC_R_UNEXPECTED;
+ event->ev_sender = sock;
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ ISC_LIST_INIT(event->bufferlist);
+ event->region = *region;
+ event->n = 0;
+ event->offset = 0;
+ event->attributes = 0;
+
+ /*
+ * UDP sockets are always partial read.
+ */
+ if (sock->type == isc_sockettype_udp)
+ event->minimum = 1;
+ else {
+ if (minimum == 0)
+ event->minimum = region->length;
+ else
+ event->minimum = minimum;
+ }
+
+ ret = socket_recv(sock, event, task, flags);
+ UNLOCK(&sock->lock);
+ return (ret);
+}
+
+/*
+ * Caller must have the socket locked.
+ */
+static isc_result_t
+socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ unsigned int flags)
+{
+ int io_state;
+ int send_errno = 0;
+ int cc = 0;
+ isc_task_t *ntask = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ dev->ev_sender = task;
+
+ set_dev_address(address, sock, dev);
+ if (pktinfo != NULL) {
+ socket_log(__LINE__, sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_PKTINFOPROVIDED,
+ "pktinfo structure provided, ifindex %u (set to 0)",
+ pktinfo->ipi6_ifindex);
+
+ dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
+ dev->pktinfo = *pktinfo;
+ /*
+ * Set the pktinfo index to 0 here, to let the kernel decide
+ * what interface it should send on.
+ */
+ dev->pktinfo.ipi6_ifindex = 0;
+ }
+
+ io_state = startio_send(sock, dev, &cc, &send_errno);
+ switch (io_state) {
+ case DOIO_PENDING: /* I/O started. Enqueue completion event. */
+ case DOIO_SOFT:
+ /*
+ * We couldn't send all or part of the request right now, so
+ * queue it unless ISC_SOCKFLAG_NORETRY is set.
+ */
+ if ((flags & ISC_SOCKFLAG_NORETRY) == 0 ||
+ io_state == DOIO_PENDING) {
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ /*
+ * Enqueue the request.
+ */
+ INSIST(!ISC_LINK_LINKED(dev, ev_link));
+ ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
+
+ socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+ "socket_send: event %p -> task %p",
+ dev, ntask);
+
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
+ result = ISC_R_INPROGRESS;
+ break;
+ }
+
+ case DOIO_SUCCESS:
+ break;
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc__socket_send(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ /*
+ * REQUIRE() checking is performed in isc_socket_sendto().
+ */
+ return (isc_socket_sendto(sock, region, task, action, arg, NULL,
+ NULL));
+}
+
+isc_result_t
+isc__socket_sendto(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+ isc_socketevent_t *dev;
+ isc_socketmgr_t *manager;
+ isc_result_t ret;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(sock->type != isc_sockettype_fdwatch);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+ REQUIRE(region != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(manager->mctx, sock,
+ ISC_SOCKEVENT_SENDDONE, action, arg);
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+ dev->region = *region;
+
+ ret = socket_send(sock, dev, task, address, pktinfo, 0);
+ UNLOCK(&sock->lock);
+ return (ret);
+}
+
+isc_result_t
+isc__socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ return (isc_socket_sendtov2(sock, buflist, task, action, arg, NULL,
+ NULL, 0));
+}
+
+isc_result_t
+isc__socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+ return (isc_socket_sendtov2(sock, buflist, task, action, arg, address,
+ pktinfo, 0));
+}
+
+isc_result_t
+isc__socket_sendtov2(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ unsigned int flags)
+{
+ isc_socketevent_t *dev;
+ isc_socketmgr_t *manager;
+ unsigned int iocount;
+ isc_buffer_t *buffer;
+ isc_result_t ret;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+ REQUIRE(buflist != NULL);
+ REQUIRE(!ISC_LIST_EMPTY(*buflist));
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ iocount = isc_bufferlist_usedcount(buflist);
+ REQUIRE(iocount > 0);
+
+ dev = allocate_socketevent(manager->mctx, sock,
+ ISC_SOCKEVENT_SENDDONE, action, arg);
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+
+ /*
+ * Move each buffer from the passed in list to our internal one.
+ */
+ buffer = ISC_LIST_HEAD(*buflist);
+ while (buffer != NULL) {
+ ISC_LIST_DEQUEUE(*buflist, buffer, link);
+ ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
+ buffer = ISC_LIST_HEAD(*buflist);
+ }
+
+ ret = socket_send(sock, dev, task, address, pktinfo, flags);
+ UNLOCK(&sock->lock);
+ return (ret);
+}
+
+isc_result_t
+isc__socket_sendto2(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ isc_socketevent_t *event, unsigned int flags)
+{
+ isc_result_t ret;
+
+ REQUIRE(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0);
+ if ((flags & ISC_SOCKFLAG_NORETRY) != 0)
+ REQUIRE(sock->type == isc_sockettype_udp);
+ event->ev_sender = sock;
+ event->result = ISC_R_UNEXPECTED;
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+ ISC_LIST_INIT(event->bufferlist);
+ event->region = *region;
+ event->n = 0;
+ event->offset = 0;
+ event->attributes = 0;
+
+ ret = socket_send(sock, event, task, address, pktinfo, flags);
+ UNLOCK(&sock->lock);
+ return (ret);
+}
+
+isc_result_t
+isc__socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr,
+ unsigned int options) {
+ int bind_errno;
+ char strbuf[ISC_STRERRORSIZE];
+ int on = 1;
+
+ REQUIRE(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ INSIST(!sock->bound);
+ INSIST(!sock->dupped);
+
+ if (sock->pf != sockaddr->type.sa.sa_family) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_FAMILYMISMATCH);
+ }
+ /*
+ * Only set SO_REUSEADDR when we want a specific port.
+ */
+ if ((options & ISC_SOCKET_REUSEADDRESS) != 0 &&
+ isc_sockaddr_getport(sockaddr) != (in_port_t)0 &&
+ setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+ sizeof(on)) < 0) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d) %s", sock->fd,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ /* Press on... */
+ }
+ if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) {
+ bind_errno = WSAGetLastError();
+ UNLOCK(&sock->lock);
+ switch (bind_errno) {
+ case WSAEACCES:
+ return (ISC_R_NOPERM);
+ case WSAEADDRNOTAVAIL:
+ return (ISC_R_ADDRNOTAVAIL);
+ case WSAEADDRINUSE:
+ return (ISC_R_ADDRINUSE);
+ case WSAEINVAL:
+ return (ISC_R_BOUND);
+ default:
+ isc__strerror(bind_errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ socket_log(__LINE__, sock, sockaddr, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "bound");
+ sock->bound = 1;
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__socket_filter(isc_socket_t *sock, const char *filter) {
+ UNUSED(sock);
+ UNUSED(filter);
+
+ REQUIRE(VALID_SOCKET(sock));
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+/*
+ * Set up to listen on a given socket. We do this by creating an internal
+ * event that will be dispatched when the socket has read activity. The
+ * watcher will send the internal event to the task when there is a new
+ * connection.
+ *
+ * Unlike in read, we don't preallocate a done event here. Every time there
+ * is a new connection we'll have to allocate a new one anyway, so we might
+ * as well keep things simple rather than having to track them.
+ */
+isc_result_t
+isc__socket_listen(isc_socket_t *sock, unsigned int backlog) {
+ char strbuf[ISC_STRERRORSIZE];
+#if defined(ISC_PLATFORM_HAVETFO) && defined(TCP_FASTOPEN)
+ char on = 1;
+#endif
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ REQUIRE(!sock->listener);
+ REQUIRE(sock->bound);
+ REQUIRE(sock->type == isc_sockettype_tcp);
+
+ if (backlog == 0)
+ backlog = SOMAXCONN;
+
+ if (listen(sock->fd, (int)backlog) < 0) {
+ UNLOCK(&sock->lock);
+ isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
+
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+#if defined(ISC_PLATFORM_HAVETFO) && defined(TCP_FASTOPEN)
+ if (setsockopt(sock->fd, IPPROTO_TCP, TCP_FASTOPEN,
+ &on, sizeof(on)) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, TCP_FASTOPEN) failed with %s",
+ sock->fd, strbuf);
+ /* TCP_FASTOPEN is experimental so ignore failures */
+ }
+#endif
+
+ socket_log(__LINE__, sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "listening");
+ sock->listener = 1;
+ _set_state(sock, SOCK_LISTEN);
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This should try to do aggressive accept() XXXMLG
+ */
+isc_result_t
+isc__socket_accept(isc_socket_t *sock,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ isc_socket_newconnev_t *adev;
+ isc_socketmgr_t *manager;
+ isc_task_t *ntask = NULL;
+ isc_socket_t *nsock;
+ isc_result_t result;
+ IoCompletionInfo *lpo;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ REQUIRE(sock->listener);
+
+ /*
+ * Sender field is overloaded here with the task we will be sending
+ * this event to. Just before the actual event is delivered the
+ * actual ev_sender will be touched up to be the socket.
+ */
+ adev = (isc_socket_newconnev_t *)
+ isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN,
+ action, arg, sizeof(*adev));
+ if (adev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+ ISC_LINK_INIT(adev, ev_link);
+
+ result = allocate_socket(manager, sock->type, &nsock);
+ if (result != ISC_R_SUCCESS) {
+ isc_event_free((isc_event_t **)&adev);
+ UNLOCK(&sock->lock);
+ return (result);
+ }
+
+ /*
+ * AcceptEx() requires we pass in a socket.
+ */
+ nsock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP);
+ if (nsock->fd == INVALID_SOCKET) {
+ free_socket(&nsock, __LINE__);
+ isc_event_free((isc_event_t **)&adev);
+ UNLOCK(&sock->lock);
+ return (ISC_R_FAILURE); // XXXMLG need real error message
+ }
+
+ /*
+ * Attach to socket and to task.
+ */
+ isc_task_attach(task, &ntask);
+ if (isc_task_exiting(ntask)) {
+ free_socket(&nsock, __LINE__);
+ isc_task_detach(&ntask);
+ isc_event_free(ISC_EVENT_PTR(&adev));
+ UNLOCK(&sock->lock);
+ return (ISC_R_SHUTTINGDOWN);
+ }
+ nsock->references++;
+
+ adev->ev_sender = ntask;
+ adev->newsocket = nsock;
+ _set_state(nsock, SOCK_ACCEPT);
+
+ /*
+ * Queue io completion for an accept().
+ */
+ lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
+ HEAP_ZERO_MEMORY,
+ sizeof(IoCompletionInfo));
+ RUNTIME_CHECK(lpo != NULL);
+ lpo->acceptbuffer = (void *)HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY,
+ (sizeof(SOCKADDR_STORAGE) + 16) * 2);
+ RUNTIME_CHECK(lpo->acceptbuffer != NULL);
+
+ lpo->adev = adev;
+ lpo->request_type = SOCKET_ACCEPT;
+
+ ISCAcceptEx(sock->fd,
+ nsock->fd, /* Accepted Socket */
+ lpo->acceptbuffer, /* Buffer for initial Recv */
+ 0, /* Length of Buffer */
+ sizeof(SOCKADDR_STORAGE) + 16, /* Local address length + 16 */
+ sizeof(SOCKADDR_STORAGE) + 16, /* Remote address lengh + 16 */
+ (LPDWORD)&lpo->received_bytes, /* Bytes Recved */
+ (LPOVERLAPPED)lpo /* Overlapped structure */
+ );
+ iocompletionport_update(nsock);
+
+ socket_log(__LINE__, sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND,
+ "accepting for nsock %p fd %d", nsock, nsock->fd);
+
+ /*
+ * Enqueue the event
+ */
+ ISC_LIST_ENQUEUE(sock->accept_list, adev, ev_link);
+ sock->pending_accept++;
+ sock->pending_iocp++;
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ char strbuf[ISC_STRERRORSIZE];
+ isc_socket_connev_t *cdev;
+ isc_task_t *ntask = NULL;
+ isc_socketmgr_t *manager;
+ IoCompletionInfo *lpo;
+ int bind_errno;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addr != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(addr != NULL);
+
+ if (isc_sockaddr_ismulticast(addr))
+ return (ISC_R_MULTICAST);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ /*
+ * Windows sockets won't connect unless the socket is bound.
+ */
+ if (!sock->bound) {
+ isc_sockaddr_t any;
+
+ isc_sockaddr_anyofpf(&any, isc_sockaddr_pf(addr));
+ if (bind(sock->fd, &any.type.sa, any.length) < 0) {
+ bind_errno = WSAGetLastError();
+ UNLOCK(&sock->lock);
+ switch (bind_errno) {
+ case WSAEACCES:
+ return (ISC_R_NOPERM);
+ case WSAEADDRNOTAVAIL:
+ return (ISC_R_ADDRNOTAVAIL);
+ case WSAEADDRINUSE:
+ return (ISC_R_ADDRINUSE);
+ case WSAEINVAL:
+ return (ISC_R_BOUND);
+ default:
+ isc__strerror(bind_errno, strbuf,
+ sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "bind: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+ sock->bound = 1;
+ }
+
+ cdev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
+ ISC_SOCKEVENT_CONNECT,
+ action, arg,
+ sizeof(*cdev));
+ if (cdev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+ ISC_LINK_INIT(cdev, ev_link);
+
+ if (sock->connected) {
+ INSIST(isc_sockaddr_equal(&sock->address, addr));
+ cdev->result = ISC_R_SUCCESS;
+ isc_task_send(task, ISC_EVENT_PTR(&cdev));
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+ }
+
+ if ((sock->type == isc_sockettype_tcp) && !sock->pending_connect) {
+ /*
+ * Queue io completion for an accept().
+ */
+ lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
+ HEAP_ZERO_MEMORY,
+ sizeof(IoCompletionInfo));
+ lpo->cdev = cdev;
+ lpo->request_type = SOCKET_CONNECT;
+
+ sock->address = *addr;
+ ISCConnectEx(sock->fd, &addr->type.sa, addr->length,
+ NULL, 0, NULL, (LPOVERLAPPED)lpo);
+
+ /*
+ * Attach to task.
+ */
+ isc_task_attach(task, &ntask);
+ cdev->ev_sender = ntask;
+
+ sock->pending_connect = 1;
+ _set_state(sock, SOCK_CONNECT);
+
+ /*
+ * Enqueue the request.
+ */
+ INSIST(!ISC_LINK_LINKED(cdev, ev_link));
+ ISC_LIST_ENQUEUE(sock->connect_list, cdev, ev_link);
+ sock->pending_iocp++;
+ } else if (sock->type == isc_sockettype_tcp) {
+ INSIST(sock->pending_connect);
+ INSIST(isc_sockaddr_equal(&sock->address, addr));
+ isc_task_attach(task, &ntask);
+ cdev->ev_sender = ntask;
+ INSIST(!ISC_LINK_LINKED(cdev, ev_link));
+ ISC_LIST_ENQUEUE(sock->connect_list, cdev, ev_link);
+ } else {
+ REQUIRE(!sock->pending_connect);
+ WSAConnect(sock->fd, &addr->type.sa, addr->length, NULL, NULL, NULL, NULL);
+ cdev->result = ISC_R_SUCCESS;
+ isc_task_send(task, (isc_event_t **)&cdev);
+ }
+ CONSISTENT(sock);
+ UNLOCK(&sock->lock);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+ isc_result_t result;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addressp != NULL);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ if (sock->connected) {
+ *addressp = sock->address;
+ result = ISC_R_SUCCESS;
+ } else {
+ result = ISC_R_NOTCONNECTED;
+ }
+
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc__socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+ ISC_SOCKADDR_LEN_T len;
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addressp != NULL);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ if (!sock->bound) {
+ result = ISC_R_NOTBOUND;
+ goto out;
+ }
+
+ result = ISC_R_SUCCESS;
+
+ len = sizeof(addressp->type);
+ if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) {
+ isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto out;
+ }
+ addressp->length = (unsigned int)len;
+
+ out:
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+/*
+ * Run through the list of events on this socket, and cancel the ones
+ * queued for task "task" of type "how". "how" is a bitmask.
+ */
+void
+isc__socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ /*
+ * Quick exit if there is nothing to do. Don't even bother locking
+ * in this case.
+ */
+ if (how == 0)
+ return;
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return;
+ }
+
+ /*
+ * All of these do the same thing, more or less.
+ * Each will:
+ * o If the internal event is marked as "posted" try to
+ * remove it from the task's queue. If this fails, mark it
+ * as canceled instead, and let the task clean it up later.
+ * o For each I/O request for that task of that type, post
+ * its done event with status of "ISC_R_CANCELED".
+ * o Reset any state needed.
+ */
+
+ if ((how & ISC_SOCKCANCEL_RECV) == ISC_SOCKCANCEL_RECV) {
+ isc_socketevent_t *dev;
+ isc_socketevent_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->recv_list);
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_recvdone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ }
+ how &= ~ISC_SOCKCANCEL_RECV;
+
+ if ((how & ISC_SOCKCANCEL_SEND) == ISC_SOCKCANCEL_SEND) {
+ isc_socketevent_t *dev;
+ isc_socketevent_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->send_list);
+
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_senddone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ }
+ how &= ~ISC_SOCKCANCEL_SEND;
+
+ if (((how & ISC_SOCKCANCEL_ACCEPT) == ISC_SOCKCANCEL_ACCEPT)
+ && !ISC_LIST_EMPTY(sock->accept_list)) {
+ isc_socket_newconnev_t *dev;
+ isc_socket_newconnev_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->accept_list);
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+
+ if ((task == NULL) || (task == current_task)) {
+
+ dev->newsocket->references--;
+ closesocket(dev->newsocket->fd);
+ dev->newsocket->fd = INVALID_SOCKET;
+ free_socket(&dev->newsocket, __LINE__);
+
+ dev->result = ISC_R_CANCELED;
+ send_acceptdone_event(sock, &dev);
+ }
+
+ dev = next;
+ }
+ }
+ how &= ~ISC_SOCKCANCEL_ACCEPT;
+
+ if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT)
+ && !ISC_LIST_EMPTY(sock->connect_list)) {
+ isc_socket_connev_t *dev;
+ isc_socket_connev_t *next;
+ isc_task_t *current_task;
+
+ INSIST(sock->pending_connect);
+
+ dev = ISC_LIST_HEAD(sock->connect_list);
+
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_connectdone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ _set_state(sock, SOCK_CLOSED);
+ }
+ how &= ~ISC_SOCKCANCEL_CONNECT;
+
+ maybe_free_socket(&sock, __LINE__);
+}
+
+isc_sockettype_t
+isc__socket_gettype(isc_socket_t *sock) {
+ isc_sockettype_t type;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ type = sock->type;
+ UNLOCK(&sock->lock);
+ return (type);
+}
+
+bool
+isc__socket_isbound(isc_socket_t *sock) {
+ bool val;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (false);
+ }
+
+ val = ((sock->bound) ? true : false);
+ UNLOCK(&sock->lock);
+
+ return (val);
+}
+
+void
+isc__socket_ipv6only(isc_socket_t *sock, bool yes) {
+#if defined(IPV6_V6ONLY)
+ int onoff = yes ? 1 : 0;
+#else
+ UNUSED(yes);
+#endif
+
+ REQUIRE(VALID_SOCKET(sock));
+
+#ifdef IPV6_V6ONLY
+ if (sock->pf == AF_INET6) {
+ (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *)&onoff, sizeof(onoff));
+ }
+#endif
+}
+
+void
+isc__socket_dscp(isc_socket_t *sock, isc_dscp_t dscp) {
+#if !defined(IP_TOS) && !defined(IPV6_TCLASS)
+ UNUSED(dscp);
+#else
+ if (dscp < 0)
+ return;
+
+ dscp <<= 2;
+ dscp &= 0xff;
+#endif
+
+ REQUIRE(VALID_SOCKET(sock));
+
+#ifdef IP_TOS
+ if (sock->pf == AF_INET) {
+ (void)setsockopt(sock->fd, IPPROTO_IP, IP_TOS,
+ (char *)&dscp, sizeof(dscp));
+ }
+#endif
+#ifdef IPV6_TCLASS
+ if (sock->pf == AF_INET6) {
+ (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_TCLASS,
+ (char *)&dscp, sizeof(dscp));
+ }
+#endif
+}
+
+void
+isc__socket_cleanunix(isc_sockaddr_t *addr, bool active) {
+ UNUSED(addr);
+ UNUSED(active);
+}
+
+isc_result_t
+isc__socket_permunix(isc_sockaddr_t *addr, uint32_t perm,
+ uint32_t owner, uint32_t group)
+{
+ UNUSED(addr);
+ UNUSED(perm);
+ UNUSED(owner);
+ UNUSED(group);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+void
+isc__socket_setname(isc_socket_t *socket, const char *name, void *tag) {
+
+ /*
+ * Name 'socket'.
+ */
+
+ REQUIRE(VALID_SOCKET(socket));
+
+ LOCK(&socket->lock);
+ strlcpy(socket->name, name, sizeof(socket->name));
+ socket->tag = tag;
+ UNLOCK(&socket->lock);
+}
+
+const char *
+isc__socket_getname(isc_socket_t *socket) {
+ return (socket->name);
+}
+
+void *
+isc__socket_gettag(isc_socket_t *socket) {
+ return (socket->tag);
+}
+
+int
+isc__socket_getfd(isc_socket_t *socket) {
+ return ((short) socket->fd);
+}
+
+void
+isc__socketmgr_setreserved(isc_socketmgr_t *manager, uint32_t reserved) {
+ UNUSED(manager);
+ UNUSED(reserved);
+}
+
+void
+isc___socketmgr_maxudp(isc_socketmgr_t *manager, int maxudp) {
+
+ UNUSED(manager);
+ UNUSED(maxudp);
+}
+
+isc_socketevent_t *
+isc_socket_socketevent(isc_mem_t *mctx, void *sender,
+ isc_eventtype_t eventtype, isc_taskaction_t action,
+ void *arg)
+{
+ return (allocate_socketevent(mctx, sender, eventtype, action, arg));
+}
+
+#ifdef HAVE_LIBXML2
+
+static const char *
+_socktype(isc_sockettype_t type) {
+ if (type == isc_sockettype_udp)
+ return ("udp");
+ else if (type == isc_sockettype_tcp)
+ return ("tcp");
+ else if (type == isc_sockettype_unix)
+ return ("unix");
+ else if (type == isc_sockettype_fdwatch)
+ return ("fdwatch");
+ else
+ return ("not-initialized");
+}
+
+#define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
+int
+isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer)
+{
+ isc_socket_t *sock = NULL;
+ char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_t addr;
+ ISC_SOCKADDR_LEN_T len;
+ int xmlrc;
+
+ LOCK(&mgr->lock);
+
+#ifndef ISC_PLATFORM_USETHREADS
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->refs));
+ TRY0(xmlTextWriterEndElement(writer));
+#endif
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "sockets"));
+ sock = ISC_LIST_HEAD(mgr->socklist);
+ while (sock != NULL) {
+ LOCK(&sock->lock);
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socket"));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%p", sock));
+ TRY0(xmlTextWriterEndElement(writer));
+
+ if (sock->name[0] != 0) {
+ TRY0(xmlTextWriterStartElement(writer,
+ ISC_XMLCHAR "name"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%s",
+ sock->name));
+ TRY0(xmlTextWriterEndElement(writer)); /* name */
+ }
+
+ TRY0(xmlTextWriterStartElement(writer,
+ ISC_XMLCHAR "references"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%d",
+ sock->references));
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterWriteElement(writer, ISC_XMLCHAR "type",
+ ISC_XMLCHAR _socktype(sock->type)));
+
+ if (sock->connected) {
+ isc_sockaddr_format(&sock->address, peerbuf,
+ sizeof(peerbuf));
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "peer-address",
+ ISC_XMLCHAR peerbuf));
+ }
+
+ len = sizeof(addr);
+ if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) {
+ isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf));
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "local-address",
+ ISC_XMLCHAR peerbuf));
+ }
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "states"));
+ if (sock->pending_recv)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "pending-receive"));
+ if (sock->pending_send)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "pending-send"));
+ if (sock->pending_accept)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "pending_accept"));
+ if (sock->listener)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "listener"));
+ if (sock->connected)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "connected"));
+ if (sock->pending_connect)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "connecting"));
+ if (sock->bound)
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "bound"));
+
+ TRY0(xmlTextWriterEndElement(writer)); /* states */
+
+ TRY0(xmlTextWriterEndElement(writer)); /* socket */
+
+ UNLOCK(&sock->lock);
+ sock = ISC_LIST_NEXT(sock, link);
+ }
+ TRY0(xmlTextWriterEndElement(writer)); /* sockets */
+
+error:
+ if (sock != NULL)
+ UNLOCK(&sock->lock);
+
+ UNLOCK(&mgr->lock);
+
+ return (xmlrc);
+}
+#endif /* HAVE_LIBXML2 */
+
+#ifdef HAVE_JSON
+#define CHECKMEM(m) do { \
+ if (m == NULL) { \
+ result = ISC_R_NOMEMORY;\
+ goto error;\
+ } \
+} while(0)
+
+isc_result_t
+isc_socketmgr_renderjson(isc_socketmgr_t *mgr, json_object *stats) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_socket_t *sock = NULL;
+ char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_t addr;
+ ISC_SOCKADDR_LEN_T len;
+ json_object *obj, *array = json_object_new_array();
+
+ CHECKMEM(array);
+
+ LOCK(&mgr->lock);
+
+#ifdef USE_SHARED_MANAGER
+ obj = json_object_new_int(mgr->refs);
+ CHECKMEM(obj);
+ json_object_object_add(stats, "references", obj);
+#endif /* USE_SHARED_MANAGER */
+
+ sock = ISC_LIST_HEAD(mgr->socklist);
+ while (sock != NULL) {
+ json_object *states, *entry = json_object_new_object();
+ char buf[255];
+
+ CHECKMEM(entry);
+ json_object_array_add(array, entry);
+
+ LOCK(&sock->lock);
+
+ snprintf(buf, sizeof(buf), "%p", sock);
+ obj = json_object_new_string(buf);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "id", obj);
+
+ if (sock->name[0] != 0) {
+ obj = json_object_new_string(sock->name);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "name", obj);
+ }
+
+ obj = json_object_new_int(sock->references);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "references", obj);
+
+ obj = json_object_new_string(_socktype(sock->type));
+ CHECKMEM(obj);
+ json_object_object_add(entry, "type", obj);
+
+ if (sock->connected) {
+ isc_sockaddr_format(&sock->address, peerbuf,
+ sizeof(peerbuf));
+ obj = json_object_new_string(peerbuf);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "peer-address", obj);
+ }
+
+ len = sizeof(addr);
+ if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) {
+ isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf));
+ obj = json_object_new_string(peerbuf);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "local-address", obj);
+ }
+
+ states = json_object_new_array();
+ CHECKMEM(states);
+ json_object_object_add(entry, "states", states);
+
+ if (sock->pending_recv) {
+ obj = json_object_new_string("pending-receive");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->pending_send) {
+ obj = json_object_new_string("pending-send");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->pending_accept) {
+ obj = json_object_new_string("pending-accept");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->listener) {
+ obj = json_object_new_string("listener");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->connected) {
+ obj = json_object_new_string("connected");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->pending_connect) {
+ obj = json_object_new_string("connecting");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->bound) {
+ obj = json_object_new_string("bound");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ UNLOCK(&sock->lock);
+ sock = ISC_LIST_NEXT(sock, link);
+ }
+
+ json_object_object_add(stats, "sockets", array);
+ array = NULL;
+ result = ISC_R_SUCCESS;
+
+ error:
+ if (array != NULL)
+ json_object_put(array);
+
+ if (sock != NULL)
+ UNLOCK(&sock->lock);
+
+ UNLOCK(&mgr->lock);
+
+ return (result);
+}
+#endif /* HAVE_JSON */
+
+/*
+ * Replace ../socket_api.c
+ */
+
+isc_result_t
+isc__socket_register(void) {
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socketmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
+ isc_socketmgr_t **managerp)
+{
+ isc_result_t result;
+
+ result = isc_socketmgr_create(mctx, managerp);
+
+ if (result == ISC_R_SUCCESS)
+ isc_appctx_setsocketmgr(actx, *managerp);
+
+ return (result);
+}
diff --git a/lib/isc/win32/stdio.c b/lib/isc/win32/stdio.c
new file mode 100644
index 0000000..a4c8134
--- /dev/null
+++ b/lib/isc/win32/stdio.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <io.h>
+#include <errno.h>
+
+#include <isc/stdio.h>
+#include <isc/util.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "errno2result.h"
+
+isc_result_t
+isc_stdio_open(const char *filename, const char *mode, FILE **fp) {
+ FILE *f;
+
+ f = fopen(filename, mode);
+ if (f == NULL)
+ return (isc__errno2result(errno));
+ *fp = f;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_stdio_close(FILE *f) {
+ int r;
+
+ r = fclose(f);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_seek(FILE *f, off_t offset, int whence) {
+ int r;
+
+#ifndef _WIN64
+ r = fseek(f, offset, whence);
+#else
+ r = _fseeki64(f, offset, whence);
+#endif
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_tell(FILE *f, off_t *offsetp) {
+#ifndef _WIN64
+ long r;
+#else
+ __int64 r;
+#endif
+
+ REQUIRE(offsetp != NULL);
+
+#ifndef _WIN64
+ r = ftell(f);
+#else
+ r = _ftelli64(f);
+#endif
+ if (r >= 0) {
+ *offsetp = r;
+ return (ISC_R_SUCCESS);
+ } else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f, size_t *nret) {
+ isc_result_t result = ISC_R_SUCCESS;
+ size_t r;
+
+ clearerr(f);
+ r = fread(ptr, size, nmemb, f);
+ if (r != nmemb) {
+ if (feof(f))
+ result = ISC_R_EOF;
+ else
+ result = isc__errno2result(errno);
+ }
+ if (nret != NULL)
+ *nret = r;
+ return (result);
+}
+
+isc_result_t
+isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f,
+ size_t *nret)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ size_t r;
+
+ clearerr(f);
+ r = fwrite(ptr, size, nmemb, f);
+ if (r != nmemb)
+ result = isc__errno2result(errno);
+ if (nret != NULL)
+ *nret = r;
+ return (result);
+}
+
+isc_result_t
+isc_stdio_flush(FILE *f) {
+ int r;
+
+ r = fflush(f);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_sync(FILE *f) {
+ struct _stat buf;
+ int r;
+
+ if (_fstat(_fileno(f), &buf) != 0)
+ return (isc__errno2result(errno));
+
+ /*
+ * Only call _commit() on regular files.
+ */
+ if ((buf.st_mode & S_IFMT) != S_IFREG)
+ return (ISC_R_SUCCESS);
+
+ r = _commit(_fileno(f));
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
diff --git a/lib/isc/win32/stdtime.c b/lib/isc/win32/stdtime.c
new file mode 100644
index 0000000..bff6fd1
--- /dev/null
+++ b/lib/isc/win32/stdtime.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <time.h>
+
+#include <isc/assertions.h>
+#include <isc/stdtime.h>
+#include <isc/util.h>
+
+void
+isc_stdtime_get(isc_stdtime_t *t) {
+ /*
+ * Set 't' to the number of seconds past 00:00:00 UTC, January 1, 1970.
+ */
+
+ REQUIRE(t != NULL);
+
+ (void)_time32(t);
+}
diff --git a/lib/isc/win32/strerror.c b/lib/isc/win32/strerror.c
new file mode 100644
index 0000000..36c9b79
--- /dev/null
+++ b/lib/isc/win32/strerror.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <winsock2.h>
+
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/strerror.h>
+#include <isc/util.h>
+
+/*
+ * Forward declarations
+ */
+
+char *
+FormatError(int error);
+
+char *
+GetWSAErrorMessage(int errval);
+
+char *
+NTstrerror(int err, BOOL *bfreebuf);
+
+/*
+ * We need to do this this way for profiled locks.
+ */
+
+static isc_mutex_t isc_strerror_lock;
+static void init_lock(void) {
+ RUNTIME_CHECK(isc_mutex_init(&isc_strerror_lock) == ISC_R_SUCCESS);
+}
+
+/*
+ * This routine needs to free up any buffer allocated by FormatMessage
+ * if that routine gets used.
+ */
+
+void
+isc__strerror(int num, char *buf, size_t size) {
+ char *msg;
+ BOOL freebuf;
+ unsigned int unum = num;
+ static isc_once_t once = ISC_ONCE_INIT;
+
+ REQUIRE(buf != NULL);
+
+ RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS);
+
+ LOCK(&isc_strerror_lock);
+ freebuf = FALSE;
+ msg = NTstrerror(num, &freebuf);
+ if (msg != NULL)
+ snprintf(buf, size, "%s", msg);
+ else
+ snprintf(buf, size, "Unknown error: %u", unum);
+ if(freebuf && msg != NULL) {
+ LocalFree(msg);
+ }
+ UNLOCK(&isc_strerror_lock);
+}
+
+/*
+ * Note this will cause a memory leak unless the memory allocated here
+ * is freed by calling LocalFree. isc__strerror does this before unlocking.
+ * This only gets called if there is a system type of error and will likely
+ * be an unusual event.
+ */
+char *
+FormatError(int error) {
+ LPVOID lpMsgBuf = NULL;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error,
+ /* Default language */
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL);
+
+ return (lpMsgBuf);
+}
+
+/*
+ * This routine checks the error value and calls the WSA Windows Sockets
+ * Error message function GetWSAErrorMessage below if it's within that range
+ * since those messages are not available in the system error messages.
+ */
+char *
+NTstrerror(int err, BOOL *bfreebuf) {
+ char *retmsg = NULL;
+
+ /* Copy the error value first in case of other errors */
+ DWORD errval = err;
+
+ *bfreebuf = FALSE;
+
+ /* Get the Winsock2 error messages */
+ if (errval >= WSABASEERR && errval <= (WSABASEERR + 1015)) {
+ retmsg = GetWSAErrorMessage(errval);
+ if (retmsg != NULL)
+ return (retmsg);
+ }
+ /*
+ * If it's not one of the standard Unix error codes,
+ * try a system error message
+ */
+ if (errval > (DWORD) _sys_nerr) {
+ *bfreebuf = TRUE;
+ return (FormatError(errval));
+ } else {
+ return (strerror(errval));
+ }
+}
+
+/*
+ * This is a replacement for perror
+ */
+void __cdecl
+NTperror(char *errmsg) {
+ /* Copy the error value first in case of other errors */
+ int errval = errno;
+ BOOL bfreebuf = FALSE;
+ char *msg;
+
+ msg = NTstrerror(errval, &bfreebuf);
+ fprintf(stderr, "%s: %s\n", errmsg, msg);
+ if(bfreebuf == TRUE) {
+ LocalFree(msg);
+ }
+
+}
+
+/*
+ * Return the error string related to Winsock2 errors.
+ * This function is necessary since FormatMessage knows nothing about them
+ * and there is no function to get them.
+ */
+char *
+GetWSAErrorMessage(int errval) {
+ char *msg;
+
+ switch (errval) {
+
+ case WSAEINTR:
+ msg = "Interrupted system call";
+ break;
+
+ case WSAEBADF:
+ msg = "Bad file number";
+ break;
+
+ case WSAEACCES:
+ msg = "Permission denied";
+ break;
+
+ case WSAEFAULT:
+ msg = "Bad address";
+ break;
+
+ case WSAEINVAL:
+ msg = "Invalid argument";
+ break;
+
+ case WSAEMFILE:
+ msg = "Too many open sockets";
+ break;
+
+ case WSAEWOULDBLOCK:
+ msg = "Operation would block";
+ break;
+
+ case WSAEINPROGRESS:
+ msg = "Operation now in progress";
+ break;
+
+ case WSAEALREADY:
+ msg = "Operation already in progress";
+ break;
+
+ case WSAENOTSOCK:
+ msg = "Socket operation on non-socket";
+ break;
+
+ case WSAEDESTADDRREQ:
+ msg = "Destination address required";
+ break;
+
+ case WSAEMSGSIZE:
+ msg = "Message too long";
+ break;
+
+ case WSAEPROTOTYPE:
+ msg = "Protocol wrong type for socket";
+ break;
+
+ case WSAENOPROTOOPT:
+ msg = "Bad protocol option";
+ break;
+
+ case WSAEPROTONOSUPPORT:
+ msg = "Protocol not supported";
+ break;
+
+ case WSAESOCKTNOSUPPORT:
+ msg = "Socket type not supported";
+ break;
+
+ case WSAEOPNOTSUPP:
+ msg = "Operation not supported on socket";
+ break;
+
+ case WSAEPFNOSUPPORT:
+ msg = "Protocol family not supported";
+ break;
+
+ case WSAEAFNOSUPPORT:
+ msg = "Address family not supported";
+ break;
+
+ case WSAEADDRINUSE:
+ msg = "Address already in use";
+ break;
+
+ case WSAEADDRNOTAVAIL:
+ msg = "Can't assign requested address";
+ break;
+
+ case WSAENETDOWN:
+ msg = "Network is down";
+ break;
+
+ case WSAENETUNREACH:
+ msg = "Network is unreachable";
+ break;
+
+ case WSAENETRESET:
+ msg = "Net connection reset";
+ break;
+
+ case WSAECONNABORTED:
+ msg = "Software caused connection abort";
+ break;
+
+ case WSAECONNRESET:
+ msg = "Connection reset by peer";
+ break;
+
+ case WSAENOBUFS:
+ msg = "No buffer space available";
+ break;
+
+ case WSAEISCONN:
+ msg = "Socket is already connected";
+ break;
+
+ case WSAENOTCONN:
+ msg = "Socket is not connected";
+ break;
+
+ case WSAESHUTDOWN:
+ msg = "Can't send after socket shutdown";
+ break;
+
+ case WSAETOOMANYREFS:
+ msg = "Too many references: can't splice";
+ break;
+
+ case WSAETIMEDOUT:
+ msg = "Connection timed out";
+ break;
+
+ case WSAECONNREFUSED:
+ msg = "Connection refused";
+ break;
+
+ case WSAELOOP:
+ msg = "Too many levels of symbolic links";
+ break;
+
+ case WSAENAMETOOLONG:
+ msg = "File name too long";
+ break;
+
+ case WSAEHOSTDOWN:
+ msg = "Host is down";
+ break;
+
+ case WSAEHOSTUNREACH:
+ msg = "No route to host";
+ break;
+
+ case WSAENOTEMPTY:
+ msg = "Directory not empty";
+ break;
+
+ case WSAEPROCLIM:
+ msg = "Too many processes";
+ break;
+
+ case WSAEUSERS:
+ msg = "Too many users";
+ break;
+
+ case WSAEDQUOT:
+ msg = "Disc quota exceeded";
+ break;
+
+ case WSAESTALE:
+ msg = "Stale NFS file handle";
+ break;
+
+ case WSAEREMOTE:
+ msg = "Too many levels of remote in path";
+ break;
+
+ case WSASYSNOTREADY:
+ msg = "Network system is unavailable";
+ break;
+
+ case WSAVERNOTSUPPORTED:
+ msg = "Winsock version out of range";
+ break;
+
+ case WSANOTINITIALISED:
+ msg = "WSAStartup not yet called";
+ break;
+
+ case WSAEDISCON:
+ msg = "Graceful shutdown in progress";
+ break;
+/*
+ case WSAHOST_NOT_FOUND:
+ msg = "Host not found";
+ break;
+
+ case WSANO_DATA:
+ msg = "No host data of that type was found";
+ break;
+*/
+ default:
+ msg = NULL;
+ break;
+ }
+ return (msg);
+}
+
+/*
+ * These error messages are more informative about CryptAPI Errors than the
+ * standard error messages
+ */
+
+char *
+GetCryptErrorMessage(int errval) {
+ char *msg;
+
+ switch (errval) {
+
+ case NTE_BAD_FLAGS:
+ msg = "The dwFlags parameter has an illegal value.";
+ break;
+ case NTE_BAD_KEYSET:
+ msg = "The Registry entry for the key container "
+ "could not be opened and may not exist.";
+ break;
+ case NTE_BAD_KEYSET_PARAM:
+ msg = "The pszContainer or pszProvider parameter "
+ "is set to an illegal value.";
+ break;
+ case NTE_BAD_PROV_TYPE:
+ msg = "The value of the dwProvType parameter is out "
+ "of range. All provider types must be from "
+ "1 to 999, inclusive.";
+ break;
+ case NTE_BAD_SIGNATURE:
+ msg = "The provider DLL signature did not verify "
+ "correctly. Either the DLL or the digital "
+ "signature has been tampered with.";
+ break;
+ case NTE_EXISTS:
+ msg = "The dwFlags parameter is CRYPT_NEWKEYSET, but the key"
+ " container already exists.";
+ break;
+ case NTE_KEYSET_ENTRY_BAD:
+ msg = "The Registry entry for the pszContainer key container "
+ "was found (in the HKEY_CURRENT_USER window), but is "
+ "corrupt. See the section System Administration for "
+ " etails about CryptoAPI's Registry usage.";
+ break;
+ case NTE_KEYSET_NOT_DEF:
+ msg = "No Registry entry exists in the HKEY_CURRENT_USER "
+ "window for the key container specified by "
+ "pszContainer.";
+ break;
+ case NTE_NO_MEMORY:
+ msg = "The CSP ran out of memory during the operation.";
+ break;
+ case NTE_PROV_DLL_NOT_FOUND:
+ msg = "The provider DLL file does not exist or is not on the "
+ "current path.";
+ break;
+ case NTE_PROV_TYPE_ENTRY_BAD:
+ msg = "The Registry entry for the provider type specified by "
+ "dwProvType is corrupt. This error may relate to "
+ "either the user default CSP list or the machine "
+ "default CSP list. See the section System "
+ "Administration for details about CryptoAPI's "
+ "Registry usage.";
+ break;
+ case NTE_PROV_TYPE_NO_MATCH:
+ msg = "The provider type specified by dwProvType does not "
+ "match the provider type found in the Registry. Note "
+ "that this error can only occur when pszProvider "
+ "specifies an actual CSP name.";
+ break;
+ case NTE_PROV_TYPE_NOT_DEF:
+ msg = "No Registry entry exists for the provider type "
+ "specified by dwProvType.";
+ break;
+ case NTE_PROVIDER_DLL_FAIL:
+ msg = "The provider DLL file could not be loaded, and "
+ "may not exist. If it exists, then the file is "
+ "not a valid DLL.";
+ break;
+ case NTE_SIGNATURE_FILE_BAD:
+ msg = "An error occurred while loading the DLL file image, "
+ "prior to verifying its signature.";
+ break;
+
+ default:
+ msg = NULL;
+ break;
+ }
+ return msg;
+}
+
diff --git a/lib/isc/win32/syslog.c b/lib/isc/win32/syslog.c
new file mode 100644
index 0000000..071e187
--- /dev/null
+++ b/lib/isc/win32/syslog.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <stdio.h>
+#include <windows.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <isc/bindevt.h>
+#include <isc/result.h>
+#include <isc/syslog.h>
+#include <isc/util.h>
+
+static HANDLE hAppLog = NULL;
+static FILE *log_stream;
+static int debug_level = 0;
+
+static struct dsn_c_pvt_sfnt {
+ int val;
+ const char *strval;
+} facilities[] = {
+ { LOG_KERN, "kern" },
+ { LOG_USER, "user" },
+ { LOG_MAIL, "mail" },
+ { LOG_DAEMON, "daemon" },
+ { LOG_AUTH, "auth" },
+ { LOG_SYSLOG, "syslog" },
+ { LOG_LPR, "lpr" },
+#ifdef LOG_NEWS
+ { LOG_NEWS, "news" },
+#endif
+#ifdef LOG_UUCP
+ { LOG_UUCP, "uucp" },
+#endif
+#ifdef LOG_CRON
+ { LOG_CRON, "cron" },
+#endif
+#ifdef LOG_AUTHPRIV
+ { LOG_AUTHPRIV, "authpriv" },
+#endif
+#ifdef LOG_FTP
+ { LOG_FTP, "ftp" },
+#endif
+ { LOG_LOCAL0, "local0"},
+ { LOG_LOCAL1, "local1"},
+ { LOG_LOCAL2, "local2"},
+ { LOG_LOCAL3, "local3"},
+ { LOG_LOCAL4, "local4"},
+ { LOG_LOCAL5, "local5"},
+ { LOG_LOCAL6, "local6"},
+ { LOG_LOCAL7, "local7"},
+ { 0, NULL }
+};
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp) {
+ int i;
+
+ REQUIRE(str != NULL);
+ REQUIRE(facilityp != NULL);
+
+ for (i = 0; facilities[i].strval != NULL; i++) {
+ if (strcasecmp(facilities[i].strval, str) == 0) {
+ *facilityp = facilities[i].val;
+ return (ISC_R_SUCCESS);
+ }
+ }
+ return (ISC_R_NOTFOUND);
+}
+
+/*
+ * Log to the NT Event Log
+ */
+void
+syslog(int level, const char *fmt, ...) {
+ va_list ap;
+ char buf[1024];
+ char *str[1];
+
+ str[0] = buf;
+
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ /* Make sure that the channel is open to write the event */
+ if (hAppLog != NULL) {
+ switch (level) {
+ case LOG_INFO:
+ case LOG_NOTICE:
+ case LOG_DEBUG:
+ ReportEvent(hAppLog, EVENTLOG_INFORMATION_TYPE, 0,
+ BIND_INFO_MSG, NULL, 1, 0, str, NULL);
+ break;
+ case LOG_WARNING:
+ ReportEvent(hAppLog, EVENTLOG_WARNING_TYPE, 0,
+ BIND_WARN_MSG, NULL, 1, 0, str, NULL);
+ break;
+ default:
+ ReportEvent(hAppLog, EVENTLOG_ERROR_TYPE, 0,
+ BIND_ERR_MSG, NULL, 1, 0, str, NULL);
+ break;
+ }
+ }
+}
+
+/*
+ * Initialize event logging
+ */
+void
+openlog(const char *name, int flags, ...) {
+ /* Get a handle to the Application event log */
+ hAppLog = RegisterEventSource(NULL, name);
+}
+
+/*
+ * Close the Handle to the application Event Log
+ * We don't care whether or not we succeeded so ignore return values
+ * In fact if we failed then we would have nowhere to put the message
+ */
+void
+closelog(void) {
+ DeregisterEventSource(hAppLog);
+}
+
+/*
+ * Keep event logging synced with the current debug level
+ */
+void
+ModifyLogLevel(int level) {
+ debug_level = level;
+}
+
+/*
+ * Initialize logging for the port section of libbind.
+ * Piggyback onto stream given.
+ */
+void
+InitNTLogging(FILE *stream, int debug) {
+ log_stream = stream;
+ ModifyLogLevel(debug);
+}
+/*
+ * This function is for reporting errors to the application
+ * event log in case the regular syslog is not available
+ * mainly during startup. It should not be used under normal
+ * circumstances.
+ */
+void
+NTReportError(const char *name, const char *str) {
+ HANDLE hNTAppLog = NULL;
+ const char *buf[1];
+
+ buf[0] = str;
+
+ hNTAppLog = RegisterEventSource(NULL, name);
+
+ ReportEvent(hNTAppLog, EVENTLOG_ERROR_TYPE, 0,
+ BIND_ERR_MSG, NULL, 1, 0, buf, NULL);
+
+ DeregisterEventSource(hNTAppLog);
+}
diff --git a/lib/isc/win32/syslog.h b/lib/isc/win32/syslog.h
new file mode 100644
index 0000000..0197165
--- /dev/null
+++ b/lib/isc/win32/syslog.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef _SYSLOG_H
+#define _SYSLOG_H
+
+#include <stdio.h>
+
+/* Constant definitions for openlog() */
+#define LOG_PID 1
+#define LOG_CONS 2
+/* NT event log does not support facility level */
+#define LOG_KERN 0
+#define LOG_USER 0
+#define LOG_MAIL 0
+#define LOG_DAEMON 0
+#define LOG_AUTH 0
+#define LOG_SYSLOG 0
+#define LOG_LPR 0
+#define LOG_LOCAL0 0
+#define LOG_LOCAL1 0
+#define LOG_LOCAL2 0
+#define LOG_LOCAL3 0
+#define LOG_LOCAL4 0
+#define LOG_LOCAL5 0
+#define LOG_LOCAL6 0
+#define LOG_LOCAL7 0
+
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but signification condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+
+void
+syslog(int level, const char *fmt, ...);
+
+void
+openlog(const char *, int, ...);
+
+void
+closelog(void);
+
+void
+ModifyLogLevel(int level);
+
+void
+InitNTLogging(FILE *, int);
+
+void
+NTReportError(const char *, const char *);
+/*
+ * Include the event codes required for logging.
+ */
+#include <isc/bindevt.h>
+
+#endif
diff --git a/lib/isc/win32/thread.c b/lib/isc/win32/thread.c
new file mode 100644
index 0000000..ebc2f29
--- /dev/null
+++ b/lib/isc/win32/thread.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <process.h>
+
+#include <isc/thread.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_thread_create(isc_threadfunc_t start, isc_threadarg_t arg,
+ isc_thread_t *threadp)
+{
+ isc_thread_t thread;
+ unsigned int id;
+
+ thread = (isc_thread_t)_beginthreadex(NULL, 0, start, arg, 0, &id);
+ if (thread == NULL) {
+ /* XXX */
+ return (ISC_R_UNEXPECTED);
+ }
+
+ *threadp = thread;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_thread_join(isc_thread_t thread, isc_threadresult_t *rp) {
+ DWORD result;
+
+ result = WaitForSingleObject(thread, INFINITE);
+ if (result != WAIT_OBJECT_0) {
+ /* XXX */
+ return (ISC_R_UNEXPECTED);
+ }
+ if (rp != NULL && !GetExitCodeThread(thread, rp)) {
+ /* XXX */
+ return (ISC_R_UNEXPECTED);
+ }
+ (void)CloseHandle(thread);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_thread_setconcurrency(unsigned int level) {
+ /*
+ * This is unnecessary on Win32 systems, but is here so that the
+ * call exists
+ */
+}
+
+void
+isc_thread_setname(isc_thread_t thread, const char *name) {
+ UNUSED(thread);
+ UNUSED(name);
+}
+
+void *
+isc_thread_key_getspecific(isc_thread_key_t key) {
+ return(TlsGetValue(key));
+}
+
+int
+isc_thread_key_setspecific(isc_thread_key_t key, void *value) {
+ return (TlsSetValue(key, value) ? 0 : GetLastError());
+}
+
+int
+isc_thread_key_create(isc_thread_key_t *key, void (*func)(void *)) {
+ *key = TlsAlloc();
+
+ return ((*key != -1) ? 0 : GetLastError());
+}
+
+int
+isc_thread_key_delete(isc_thread_key_t key) {
+ return (TlsFree(key) ? 0 : GetLastError());
+}
diff --git a/lib/isc/win32/time.c b/lib/isc/win32/time.c
new file mode 100644
index 0000000..a1c8a84
--- /dev/null
+++ b/lib/isc/win32/time.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <config.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <windows.h>
+
+#include <isc/assertions.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/tm.h>
+#include <isc/util.h>
+
+/*
+ * struct FILETIME uses "100-nanoseconds intervals".
+ * NS / S = 1000000000 (10^9).
+ * While it is reasonably obvious that this makes the needed
+ * conversion factor 10^7, it is coded this way for additional clarity.
+ */
+#define NS_PER_S 1000000000
+#define NS_INTERVAL 100
+#define INTERVALS_PER_S (NS_PER_S / NS_INTERVAL)
+
+/***
+ *** Absolute Times
+ ***/
+
+static const isc_time_t epoch = { { 0, 0 } };
+LIBISC_EXTERNAL_DATA const isc_time_t * const isc_time_epoch = &epoch;
+
+/***
+ *** Intervals
+ ***/
+
+static const isc_interval_t zero_interval = { 0 };
+LIBISC_EXTERNAL_DATA const isc_interval_t * const isc_interval_zero = &zero_interval;
+
+void
+isc_interval_set(isc_interval_t *i, unsigned int seconds,
+ unsigned int nanoseconds)
+{
+ REQUIRE(i != NULL);
+ REQUIRE(nanoseconds < NS_PER_S);
+
+ /*
+ * This rounds nanoseconds up not down.
+ */
+ i->interval = (LONGLONG)seconds * INTERVALS_PER_S
+ + (nanoseconds + NS_INTERVAL - 1) / NS_INTERVAL;
+}
+
+bool
+isc_interval_iszero(const isc_interval_t *i) {
+ REQUIRE(i != NULL);
+ if (i->interval == 0)
+ return (true);
+
+ return (false);
+}
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
+ SYSTEMTIME epoch1970 = { 1970, 1, 4, 1, 0, 0, 0, 0 };
+ FILETIME temp;
+ ULARGE_INTEGER i1;
+
+ REQUIRE(t != NULL);
+ REQUIRE(nanoseconds < NS_PER_S);
+
+ SystemTimeToFileTime(&epoch1970, &temp);
+
+ i1.LowPart = temp.dwLowDateTime;
+ i1.HighPart = temp.dwHighDateTime;
+
+ i1.QuadPart += (unsigned __int64)nanoseconds/100;
+ i1.QuadPart += (unsigned __int64)seconds*10000000;
+
+ t->absolute.dwLowDateTime = i1.LowPart;
+ t->absolute.dwHighDateTime = i1.HighPart;
+}
+
+void
+isc_time_settoepoch(isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ t->absolute.dwLowDateTime = 0;
+ t->absolute.dwHighDateTime = 0;
+}
+
+bool
+isc_time_isepoch(const isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ if (t->absolute.dwLowDateTime == 0 &&
+ t->absolute.dwHighDateTime == 0)
+ return (true);
+
+ return (false);
+}
+
+isc_result_t
+isc_time_now(isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ GetSystemTimeAsFileTime(&t->absolute);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
+ ULARGE_INTEGER i1;
+
+ REQUIRE(t != NULL);
+ REQUIRE(i != NULL);
+
+ GetSystemTimeAsFileTime(&t->absolute);
+
+ i1.LowPart = t->absolute.dwLowDateTime;
+ i1.HighPart = t->absolute.dwHighDateTime;
+
+ if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval)
+ return (ISC_R_RANGE);
+
+ i1.QuadPart += i->interval;
+
+ t->absolute.dwLowDateTime = i1.LowPart;
+ t->absolute.dwHighDateTime = i1.HighPart;
+
+ return (ISC_R_SUCCESS);
+}
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
+ REQUIRE(t1 != NULL && t2 != NULL);
+
+ return ((int)CompareFileTime(&t1->absolute, &t2->absolute));
+}
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
+{
+ ULARGE_INTEGER i1;
+
+ REQUIRE(t != NULL && i != NULL && result != NULL);
+
+ i1.LowPart = t->absolute.dwLowDateTime;
+ i1.HighPart = t->absolute.dwHighDateTime;
+
+ if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval)
+ return (ISC_R_RANGE);
+
+ i1.QuadPart += i->interval;
+
+ result->absolute.dwLowDateTime = i1.LowPart;
+ result->absolute.dwHighDateTime = i1.HighPart;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+ isc_time_t *result) {
+ ULARGE_INTEGER i1;
+
+ REQUIRE(t != NULL && i != NULL && result != NULL);
+
+ i1.LowPart = t->absolute.dwLowDateTime;
+ i1.HighPart = t->absolute.dwHighDateTime;
+
+ if (i1.QuadPart < (unsigned __int64) i->interval)
+ return (ISC_R_RANGE);
+
+ i1.QuadPart -= i->interval;
+
+ result->absolute.dwLowDateTime = i1.LowPart;
+ result->absolute.dwHighDateTime = i1.HighPart;
+
+ return (ISC_R_SUCCESS);
+}
+
+uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
+ ULARGE_INTEGER i1, i2;
+ LONGLONG i3;
+
+ REQUIRE(t1 != NULL && t2 != NULL);
+
+ i1.LowPart = t1->absolute.dwLowDateTime;
+ i1.HighPart = t1->absolute.dwHighDateTime;
+ i2.LowPart = t2->absolute.dwLowDateTime;
+ i2.HighPart = t2->absolute.dwHighDateTime;
+
+ if (i1.QuadPart <= i2.QuadPart)
+ return (0);
+
+ /*
+ * Convert to microseconds.
+ */
+ i3 = (i1.QuadPart - i2.QuadPart) / 10;
+
+ return (i3);
+}
+
+uint32_t
+isc_time_seconds(const isc_time_t *t) {
+ SYSTEMTIME epoch1970 = { 1970, 1, 4, 1, 0, 0, 0, 0 };
+ FILETIME temp;
+ ULARGE_INTEGER i1, i2;
+ LONGLONG i3;
+
+ SystemTimeToFileTime(&epoch1970, &temp);
+
+ i1.LowPart = t->absolute.dwLowDateTime;
+ i1.HighPart = t->absolute.dwHighDateTime;
+ i2.LowPart = temp.dwLowDateTime;
+ i2.HighPart = temp.dwHighDateTime;
+
+ i3 = (i1.QuadPart - i2.QuadPart) / 10000000;
+
+ return ((uint32_t)i3);
+}
+
+isc_result_t
+isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
+ time_t seconds;
+
+ REQUIRE(t != NULL);
+
+ seconds = (time_t)isc_time_seconds(t);
+
+ INSIST(sizeof(unsigned int) == sizeof(uint32_t));
+ INSIST(sizeof(time_t) >= sizeof(uint32_t));
+
+ if (isc_time_seconds(t) > (~0U>>1) && seconds <= (time_t)(~0U>>1))
+ return (ISC_R_RANGE);
+
+ *secondsp = seconds;
+
+ return (ISC_R_SUCCESS);
+}
+
+
+uint32_t
+isc_time_nanoseconds(const isc_time_t *t) {
+ ULARGE_INTEGER i;
+
+ i.LowPart = t->absolute.dwLowDateTime;
+ i.HighPart = t->absolute.dwHighDateTime;
+ return ((uint32_t)(i.QuadPart % 10000000) * 100);
+}
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+ FILETIME localft;
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToLocalFileTime(&t->absolute, &localft) &&
+ FileTimeToSystemTime(&localft, &st)) {
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "dd-MMM-yyyy",
+ DateBuf, 50);
+ GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER|
+ TIME_FORCE24HOURFORMAT, &st, NULL, TimeBuf, 50);
+
+ snprintf(buf, len, "%s %s.%03u", DateBuf, TimeBuf,
+ st.wMilliseconds);
+
+ } else {
+ strlcpy(buf, "99-Bad-9999 99:99:99.999", len);
+ }
+}
+
+void
+isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+/* strftime() format: "%a, %d %b %Y %H:%M:%S GMT" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st,
+ "ddd',' dd MMM yyyy", DateBuf, 50);
+ GetTimeFormat(LOCALE_USER_DEFAULT,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
+ &st, "hh':'mm':'ss", TimeBuf, 50);
+
+ snprintf(buf, len, "%s %s GMT", DateBuf, TimeBuf);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+isc_result_t
+isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
+ struct tm t_tm;
+ time_t when;
+ char *p;
+
+ REQUIRE(buf != NULL);
+ REQUIRE(t != NULL);
+
+ p = isc_tm_strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
+ if (p == NULL)
+ return (ISC_R_UNEXPECTED);
+ when = isc_tm_timegm(&t_tm);
+ if (when == -1)
+ return (ISC_R_UNEXPECTED);
+ isc_time_set(t, (unsigned int)when, 0);
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y-%m-%dT%H:%M:%SZ" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd",
+ DateBuf, 50);
+ GetTimeFormat(LOCALE_NEUTRAL,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
+ &st, "hh':'mm':'ss", TimeBuf, 50);
+ snprintf(buf, len, "%sT%sZ", DateBuf, TimeBuf);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+void
+isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y-%m-%dT%H:%M:%S.SSSZ" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd",
+ DateBuf, 50);
+ GetTimeFormat(LOCALE_NEUTRAL,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
+ &st, "hh':'mm':'ss", TimeBuf, 50);
+ snprintf(buf, len, "%sT%s.%03uZ", DateBuf, TimeBuf,
+ st.wMilliseconds);
+ } else {
+ buf[0] = 0;
+ }
+}
diff --git a/lib/isc/win32/unistd.h b/lib/isc/win32/unistd.h
new file mode 100644
index 0000000..170577e
--- /dev/null
+++ b/lib/isc/win32/unistd.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/* None of these are defined in NT, so define them for our use */
+#define O_NONBLOCK 1
+#define PORT_NONBLOCK O_NONBLOCK
+
+/*
+ * fcntl() commands
+ */
+#define F_SETFL 0
+#define F_GETFL 1
+#define F_SETFD 2
+#define F_GETFD 3
+/*
+ * Enough problems not having full fcntl() without worrying about this!
+ */
+#undef F_DUPFD
+
+int fcntl(int, int, ...);
+
+/*
+ * access() related definitions for winXP
+ */
+#include <io.h>
+#ifndef F_OK
+#define F_OK 0
+#endif
+
+#ifndef X_OK
+#define X_OK 1
+#endif
+
+#ifndef W_OK
+#define W_OK 2
+#endif
+
+#ifndef R_OK
+#define R_OK 4
+#endif
+
+#define access _access
+
+#include <process.h>
diff --git a/lib/isc/win32/version.c b/lib/isc/win32/version.c
new file mode 100644
index 0000000..d86c781
--- /dev/null
+++ b/lib/isc/win32/version.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <versions.h>
+
+#include <isc/version.h>
+
+LIBISC_EXTERNAL_DATA const char isc_version[] = VERSION;
+
+LIBISC_EXTERNAL_DATA const unsigned int isc_libinterface = LIBINTERFACE;
+LIBISC_EXTERNAL_DATA const unsigned int isc_librevision = LIBREVISION;
+LIBISC_EXTERNAL_DATA const unsigned int isc_libage = LIBAGE;
diff --git a/lib/isc/win32/win32os.c b/lib/isc/win32/win32os.c
new file mode 100644
index 0000000..9af95c8
--- /dev/null
+++ b/lib/isc/win32/win32os.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <windows.h>
+
+#ifndef TESTVERSION
+#include <isc/win32os.h>
+#else
+#include <stdio.h>
+#include <isc/util.h>
+#endif
+#include <isc/print.h>
+
+int
+isc_win32os_versioncheck(unsigned int major, unsigned int minor,
+ unsigned int spmajor, unsigned int spminor)
+{
+ OSVERSIONINFOEX osVer;
+ DWORD typeMask;
+ ULONGLONG conditionMask;
+
+ memset(&osVer, 0, sizeof(OSVERSIONINFOEX));
+ osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ typeMask = 0;
+ conditionMask = 0;
+
+ /* Optimistic: likely greater */
+ osVer.dwMajorVersion = major;
+ typeMask |= VER_MAJORVERSION;
+ conditionMask = VerSetConditionMask(conditionMask,
+ VER_MAJORVERSION,
+ VER_GREATER);
+ osVer.dwMinorVersion = minor;
+ typeMask |= VER_MINORVERSION;
+ conditionMask = VerSetConditionMask(conditionMask,
+ VER_MINORVERSION,
+ VER_GREATER);
+ osVer.wServicePackMajor = spmajor;
+ typeMask |= VER_SERVICEPACKMAJOR;
+ conditionMask = VerSetConditionMask(conditionMask,
+ VER_SERVICEPACKMAJOR,
+ VER_GREATER);
+ osVer.wServicePackMinor = spminor;
+ typeMask |= VER_SERVICEPACKMINOR;
+ conditionMask = VerSetConditionMask(conditionMask,
+ VER_SERVICEPACKMINOR,
+ VER_GREATER);
+ if (VerifyVersionInfo(&osVer, typeMask, conditionMask))
+ return (1);
+
+ /* Failed: retry with equal */
+ conditionMask = 0;
+ conditionMask = VerSetConditionMask(conditionMask,
+ VER_MAJORVERSION,
+ VER_EQUAL);
+ conditionMask = VerSetConditionMask(conditionMask,
+ VER_MINORVERSION,
+ VER_EQUAL);
+ conditionMask = VerSetConditionMask(conditionMask,
+ VER_SERVICEPACKMAJOR,
+ VER_EQUAL);
+ conditionMask = VerSetConditionMask(conditionMask,
+ VER_SERVICEPACKMINOR,
+ VER_EQUAL);
+ if (VerifyVersionInfo(&osVer, typeMask, conditionMask))
+ return (0);
+ else
+ return (-1);
+}
+
+#ifdef TESTVERSION
+int
+main(int argc, char **argv) {
+ unsigned int major = 0;
+ unsigned int minor = 0;
+ unsigned int spmajor = 0;
+ unsigned int spminor = 0;
+ int ret;
+
+ if (argc > 1) {
+ --argc;
+ ++argv;
+ major = (unsigned int) atoi(argv[0]);
+ }
+ if (argc > 1) {
+ --argc;
+ ++argv;
+ minor = (unsigned int) atoi(argv[0]);
+ }
+ if (argc > 1) {
+ --argc;
+ ++argv;
+ spmajor = (unsigned int) atoi(argv[0]);
+ }
+ if (argc > 1) {
+ --argc;
+ POST(argc);
+ ++argv;
+ spminor = (unsigned int) atoi(argv[0]);
+ }
+
+ ret = isc_win32os_versioncheck(major, minor, spmajor, spminor);
+
+ printf("%s major %u minor %u SP major %u SP minor %u\n",
+ ret > 0 ? "greater" : (ret == 0 ? "equal" : "less"),
+ major, minor, spmajor, spminor);
+ return (ret);
+}
+#endif
diff --git a/lib/isc/x86_32/Makefile.in b/lib/isc/x86_32/Makefile.in
new file mode 100644
index 0000000..419cf9f
--- /dev/null
+++ b/lib/isc/x86_32/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/x86_32/include/Makefile.in b/lib/isc/x86_32/include/Makefile.in
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/lib/isc/x86_32/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/x86_32/include/isc/Makefile.in b/lib/isc/x86_32/include/isc/Makefile.in
new file mode 100644
index 0000000..97b6b41
--- /dev/null
+++ b/lib/isc/x86_32/include/isc/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
diff --git a/lib/isc/x86_32/include/isc/atomic.h b/lib/isc/x86_32/include/isc/atomic.h
new file mode 100644
index 0000000..8bcc8b0
--- /dev/null
+++ b/lib/isc/x86_32/include/isc/atomic.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <inttypes.h>
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+static __inline__ int32_t
+isc_atomic_xadd(int32_t *p, int32_t val) {
+ int32_t prev = val;
+
+ __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xadd %0, %1"
+ :"=q"(prev)
+ :"m"(*p), "0"(prev)
+ :"memory", "cc");
+
+ return (prev);
+}
+
+#ifdef ISC_PLATFORM_HAVEXADDQ
+static __inline__ int64_t
+isc_atomic_xaddq(int64_t *p, int64_t val) {
+ int64_t prev = val;
+
+ __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xaddq %0, %1"
+ :"=q"(prev)
+ :"m"(*p), "0"(prev)
+ :"memory", "cc");
+
+ return (prev);
+}
+#endif /* ISC_PLATFORM_HAVEXADDQ */
+
+/*
+ * This routine atomically stores the value 'val' in 'p' (32-bit version).
+ */
+static __inline__ void
+isc_atomic_store(int32_t *p, int32_t val) {
+ __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * xchg should automatically lock memory, but we add it
+ * explicitly just in case (it at least doesn't harm)
+ */
+ "lock;"
+#endif
+
+ "xchgl %1, %0"
+ :
+ : "r"(val), "m"(*p)
+ : "memory");
+}
+
+#ifdef ISC_PLATFORM_HAVEATOMICSTOREQ
+/*
+ * This routine atomically stores the value 'val' in 'p' (64-bit version).
+ */
+static __inline__ void
+isc_atomic_storeq(int64_t *p, int64_t val) {
+ __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * xchg should automatically lock memory, but we add it
+ * explicitly just in case (it at least doesn't harm)
+ */
+ "lock;"
+#endif
+
+ "xchgq %1, %0"
+ :
+ : "r"(val), "m"(*p)
+ : "memory");
+}
+#endif /* ISC_PLATFORM_HAVEATOMICSTOREQ */
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+static __inline__ int32_t
+isc_atomic_cmpxchg(int32_t *p, int32_t cmpval, int32_t val) {
+ __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "cmpxchgl %1, %2"
+ : "=a"(cmpval)
+ : "r"(val), "m"(*p), "a"(cmpval)
+ : "memory");
+
+ return (cmpval);
+}
+
+#elif defined(ISC_PLATFORM_USESTDASM)
+/*
+ * The followings are "generic" assembly code which implements the same
+ * functionality in case the gcc extension cannot be used. It should be
+ * better to avoid inlining below, since we directly refer to specific
+ * positions of the stack frame, which would not actually point to the
+ * intended address in the embedded mnemonic.
+ */
+static int32_t
+isc_atomic_xadd(int32_t *p, int32_t val) {
+ (void)(p);
+ (void)(val);
+
+ __asm (
+ "movl 8(%ebp), %ecx\n"
+ "movl 12(%ebp), %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xadd %edx, (%ecx)\n"
+
+ /*
+ * set the return value directly in the register so that we
+ * can avoid guessing the correct position in the stack for a
+ * local variable.
+ */
+ "movl %edx, %eax"
+ );
+}
+
+static void
+isc_atomic_store(int32_t *p, int32_t val) {
+ (void)(p);
+ (void)(val);
+
+ __asm (
+ "movl 8(%ebp), %ecx\n"
+ "movl 12(%ebp), %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xchgl (%ecx), %edx\n"
+ );
+}
+
+static int32_t
+isc_atomic_cmpxchg(int32_t *p, int32_t cmpval, int32_t val) {
+ (void)(p);
+ (void)(cmpval);
+ (void)(val);
+
+ __asm (
+ "movl 8(%ebp), %ecx\n"
+ "movl 12(%ebp), %eax\n" /* must be %eax for cmpxchgl */
+ "movl 16(%ebp), %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+
+ /*
+ * If (%ecx) == %eax then (%ecx) := %edx.
+ % %eax is set to old (%ecx), which will be the return value.
+ */
+ "cmpxchgl %edx, (%ecx)"
+ );
+}
+#else /* !ISC_PLATFORM_USEGCCASM && !ISC_PLATFORM_USESTDASM */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/x86_64/Makefile.in b/lib/isc/x86_64/Makefile.in
new file mode 100644
index 0000000..419cf9f
--- /dev/null
+++ b/lib/isc/x86_64/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/x86_64/include/Makefile.in b/lib/isc/x86_64/include/Makefile.in
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/lib/isc/x86_64/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/x86_64/include/isc/Makefile.in b/lib/isc/x86_64/include/isc/Makefile.in
new file mode 100644
index 0000000..97b6b41
--- /dev/null
+++ b/lib/isc/x86_64/include/isc/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \
+ done
diff --git a/lib/isc/x86_64/include/isc/atomic.h b/lib/isc/x86_64/include/isc/atomic.h
new file mode 100644
index 0000000..b2d7880
--- /dev/null
+++ b/lib/isc/x86_64/include/isc/atomic.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <inttypes.h>
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+
+/* We share the gcc-version with x86_32 */
+#error "impossible case. check build configuration"
+
+#elif defined(ISC_PLATFORM_USESTDASM)
+/*
+ * The followings are "generic" assembly code which implements the same
+ * functionality in case the gcc extension cannot be used. It should be
+ * better to avoid inlining below, since we directly refer to specific
+ * registers for arguments, which would not actually correspond to the
+ * intended address or value in the embedded mnemonic.
+ */
+
+static int32_t
+isc_atomic_xadd(int32_t *p, int32_t val) {
+ (void)(p);
+ (void)(val);
+
+ __asm (
+ "movq %rdi, %rdx\n"
+ "movl %esi, %eax\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xadd %eax, (%rdx)\n"
+ /*
+ * XXX: assume %eax will be used as the return value.
+ */
+ );
+}
+
+#ifdef ISC_PLATFORM_HAVEXADDQ
+static int64_t
+isc_atomic_xaddq(int64_t *p, int64_t val) {
+ (void)(p);
+ (void)(val);
+
+ __asm (
+ "movq %rdi, %rdx\n"
+ "movq %rsi, %rax\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xaddq %rax, (%rdx)\n"
+ /*
+ * XXX: assume %rax will be used as the return value.
+ */
+ );
+}
+#endif
+
+static void
+isc_atomic_store(int32_t *p, int32_t val) {
+ (void)(p);
+ (void)(val);
+
+ __asm (
+ "movq %rdi, %rax\n"
+ "movl %esi, %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xchgl (%rax), %edx\n"
+ );
+}
+
+#ifdef ISC_PLATFORM_HAVEATOMICSTOREQ
+static void
+isc_atomic_storeq(int64_t *p, int64_t val) {
+ (void)(p);
+ (void)(val);
+
+ __asm (
+ "movq %rdi, %rax\n"
+ "movq %rsi, %rdx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xchgq (%rax), %rdx\n"
+ );
+}
+#endif
+
+static int32_t
+isc_atomic_cmpxchg(int32_t *p, int32_t cmpval, int32_t val) {
+ (void)(p);
+ (void)(cmpval);
+ (void)(val);
+
+ __asm (
+ /*
+ * p is %rdi, cmpval is %esi, val is %edx.
+ */
+ "movl %edx, %ecx\n"
+ "movl %esi, %eax\n"
+ "movq %rdi, %rdx\n"
+
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ /*
+ * If [%rdi] == %eax then [%rdi] := %ecx (equal to %edx
+ * from above), and %eax is untouched (equal to %esi)
+ * from above.
+ *
+ * Else if [%rdi] != %eax then [%rdi] := [%rdi]
+ * (rewritten in write cycle) and %eax := [%rdi].
+ */
+ "cmpxchgl %ecx, (%rdx)"
+ );
+}
+
+#else /* !ISC_PLATFORM_USEGCCASM && !ISC_PLATFORM_USESTDASM */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isccc/Makefile.in b/lib/isccc/Makefile.in
new file mode 100644
index 0000000..ca88e98
--- /dev/null
+++ b/lib/isccc/Makefile.in
@@ -0,0 +1,84 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# $Id$
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+@LIBISCCC_API@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = -I. ${DNS_INCLUDES} ${ISC_INCLUDES} \
+ ${ISCCC_INCLUDES} @ISC_OPENSSL_INC@
+
+CDEFINES = @CRYPTO@
+CWARNINGS =
+
+ISCLIBS = ../../lib/isc/libisc.@A@
+ISCCCLIBS = ../../lib/isccc/libisccc.@A@
+
+ISCDEPLIBS = ../../lib/isc/libisc.@A@
+ISCCCDEPLIBS = libisccc.@A@
+
+LIBS = @LIBS@
+
+SUBDIRS = include
+
+# Alphabetically
+OBJS = alist.@O@ base64.@O@ cc.@O@ ccmsg.@O@ \
+ lib.@O@ \
+ result.@O@ sexpr.@O@ symtab.@O@ version.@O@
+
+# Alphabetically
+SRCS = alist.c base64.c cc.c ccmsg.c \
+ lib.c \
+ result.c sexpr.c symtab.c version.c
+
+
+TARGETS = timestamp
+
+@BIND9_MAKE_RULES@
+
+version.@O@: version.c
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \
+ -DVERSION=\"${VERSION}\" \
+ -DLIBINTERFACE=${LIBINTERFACE} \
+ -DLIBREVISION=${LIBREVISION} \
+ -DLIBAGE=${LIBAGE} \
+ -c ${srcdir}/version.c
+
+libisccc.@SA@: ${OBJS}
+ ${AR} ${ARFLAGS} $@ ${OBJS}
+ ${RANLIB} $@
+
+libisccc.la: ${OBJS}
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisccc.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} ${ISCLIBS} ${LIBS}
+
+timestamp: libisccc.@A@
+ touch timestamp
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+
+install:: timestamp installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_LIBRARY} libisccc.@A@ ${DESTDIR}${libdir}
+
+uninstall::
+ ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${libdir}/libisccc.@A@
+
+clean distclean::
+ rm -f libisccc.@A@ timestamp
diff --git a/lib/isccc/alist.c b/lib/isccc/alist.c
new file mode 100644
index 0000000..22992d6
--- /dev/null
+++ b/lib/isccc/alist.c
@@ -0,0 +1,307 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isccc/alist.h>
+#include <isc/assertions.h>
+#include <isc/print.h>
+#include <isccc/result.h>
+#include <isccc/sexpr.h>
+#include <isccc/util.h>
+
+#define CAR(s) (s)->value.as_dottedpair.car
+#define CDR(s) (s)->value.as_dottedpair.cdr
+
+#define ALIST_TAG "*alist*"
+#define MAX_INDENT 64
+
+static char spaces[MAX_INDENT + 1] =
+ " ";
+
+isccc_sexpr_t *
+isccc_alist_create(void)
+{
+ isccc_sexpr_t *alist, *tag;
+
+ tag = isccc_sexpr_fromstring(ALIST_TAG);
+ if (tag == NULL)
+ return (NULL);
+ alist = isccc_sexpr_cons(tag, NULL);
+ if (alist == NULL) {
+ isccc_sexpr_free(&tag);
+ return (NULL);
+ }
+
+ return (alist);
+}
+
+bool
+isccc_alist_alistp(isccc_sexpr_t *alist)
+{
+ isccc_sexpr_t *car;
+
+ if (alist == NULL || alist->type != ISCCC_SEXPRTYPE_DOTTEDPAIR)
+ return (false);
+ car = CAR(alist);
+ if (car == NULL || car->type != ISCCC_SEXPRTYPE_STRING)
+ return (false);
+ if (strcmp(car->value.as_string, ALIST_TAG) != 0)
+ return (false);
+ return (true);
+}
+
+bool
+isccc_alist_emptyp(isccc_sexpr_t *alist)
+{
+ REQUIRE(isccc_alist_alistp(alist));
+
+ if (CDR(alist) == NULL)
+ return (true);
+ return (false);
+}
+
+isccc_sexpr_t *
+isccc_alist_first(isccc_sexpr_t *alist)
+{
+ REQUIRE(isccc_alist_alistp(alist));
+
+ return (CDR(alist));
+}
+
+isccc_sexpr_t *
+isccc_alist_assq(isccc_sexpr_t *alist, const char *key)
+{
+ isccc_sexpr_t *car, *caar;
+
+ REQUIRE(isccc_alist_alistp(alist));
+
+ /*
+ * Skip alist type tag.
+ */
+ alist = CDR(alist);
+
+ while (alist != NULL) {
+ INSIST(alist->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+ car = CAR(alist);
+ INSIST(car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+ caar = CAR(car);
+ if (caar->type == ISCCC_SEXPRTYPE_STRING &&
+ strcmp(caar->value.as_string, key) == 0)
+ return (car);
+ alist = CDR(alist);
+ }
+
+ return (NULL);
+}
+
+void
+isccc_alist_delete(isccc_sexpr_t *alist, const char *key)
+{
+ isccc_sexpr_t *car, *caar, *rest, *prev;
+
+ REQUIRE(isccc_alist_alistp(alist));
+
+ prev = alist;
+ rest = CDR(alist);
+ while (rest != NULL) {
+ INSIST(rest->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+ car = CAR(rest);
+ INSIST(car != NULL && car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+ caar = CAR(car);
+ if (caar->type == ISCCC_SEXPRTYPE_STRING &&
+ strcmp(caar->value.as_string, key) == 0) {
+ CDR(prev) = CDR(rest);
+ CDR(rest) = NULL;
+ isccc_sexpr_free(&rest);
+ break;
+ }
+ prev = rest;
+ rest = CDR(rest);
+ }
+}
+
+isccc_sexpr_t *
+isccc_alist_define(isccc_sexpr_t *alist, const char *key, isccc_sexpr_t *value)
+{
+ isccc_sexpr_t *kv, *k, *elt;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv == NULL) {
+ /*
+ * New association.
+ */
+ k = isccc_sexpr_fromstring(key);
+ if (k == NULL)
+ return (NULL);
+ kv = isccc_sexpr_cons(k, value);
+ if (kv == NULL) {
+ isccc_sexpr_free(&kv);
+ return (NULL);
+ }
+ elt = isccc_sexpr_addtolist(&alist, kv);
+ if (elt == NULL) {
+ isccc_sexpr_free(&kv);
+ return (NULL);
+ }
+ } else {
+ /*
+ * We've already got an entry for this key. Replace it.
+ */
+ isccc_sexpr_free(&CDR(kv));
+ CDR(kv) = value;
+ }
+
+ return (kv);
+}
+
+isccc_sexpr_t *
+isccc_alist_definestring(isccc_sexpr_t *alist, const char *key, const char *str)
+{
+ isccc_sexpr_t *v, *kv;
+
+ v = isccc_sexpr_fromstring(str);
+ if (v == NULL)
+ return (NULL);
+ kv = isccc_alist_define(alist, key, v);
+ if (kv == NULL)
+ isccc_sexpr_free(&v);
+
+ return (kv);
+}
+
+isccc_sexpr_t *
+isccc_alist_definebinary(isccc_sexpr_t *alist, const char *key, isccc_region_t *r)
+{
+ isccc_sexpr_t *v, *kv;
+
+ v = isccc_sexpr_frombinary(r);
+ if (v == NULL)
+ return (NULL);
+ kv = isccc_alist_define(alist, key, v);
+ if (kv == NULL)
+ isccc_sexpr_free(&v);
+
+ return (kv);
+}
+
+isccc_sexpr_t *
+isccc_alist_lookup(isccc_sexpr_t *alist, const char *key)
+{
+ isccc_sexpr_t *kv;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv != NULL)
+ return (CDR(kv));
+ return (NULL);
+}
+
+isc_result_t
+isccc_alist_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp)
+{
+ isccc_sexpr_t *kv, *v;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv != NULL) {
+ v = CDR(kv);
+ if (isccc_sexpr_stringp(v)) {
+ if (strp != NULL)
+ *strp = isccc_sexpr_tostring(v);
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_EXISTS);
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+isc_result_t
+isccc_alist_lookupbinary(isccc_sexpr_t *alist, const char *key, isccc_region_t **r)
+{
+ isccc_sexpr_t *kv, *v;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv != NULL) {
+ v = CDR(kv);
+ if (isccc_sexpr_binaryp(v)) {
+ if (r != NULL)
+ *r = isccc_sexpr_tobinary(v);
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_EXISTS);
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+void
+isccc_alist_prettyprint(isccc_sexpr_t *sexpr, unsigned int indent, FILE *stream)
+{
+ isccc_sexpr_t *elt, *kv, *k, *v;
+
+ if (isccc_alist_alistp(sexpr)) {
+ fprintf(stream, "{\n");
+ indent += 4;
+ for (elt = isccc_alist_first(sexpr);
+ elt != NULL;
+ elt = CDR(elt)) {
+ kv = CAR(elt);
+ INSIST(isccc_sexpr_listp(kv));
+ k = CAR(kv);
+ v = CDR(kv);
+ INSIST(isccc_sexpr_stringp(k));
+ fprintf(stream, "%.*s%s => ", (int)indent, spaces,
+ isccc_sexpr_tostring(k));
+ isccc_alist_prettyprint(v, indent, stream);
+ if (CDR(elt) != NULL)
+ fprintf(stream, ",");
+ fprintf(stream, "\n");
+ }
+ indent -= 4;
+ fprintf(stream, "%.*s}", (int)indent, spaces);
+ } else if (isccc_sexpr_listp(sexpr)) {
+ fprintf(stream, "(\n");
+ indent += 4;
+ for (elt = sexpr;
+ elt != NULL;
+ elt = CDR(elt)) {
+ fprintf(stream, "%.*s", (int)indent, spaces);
+ isccc_alist_prettyprint(CAR(elt), indent, stream);
+ if (CDR(elt) != NULL)
+ fprintf(stream, ",");
+ fprintf(stream, "\n");
+ }
+ indent -= 4;
+ fprintf(stream, "%.*s)", (int)indent, spaces);
+ } else
+ isccc_sexpr_print(sexpr, stream);
+}
diff --git a/lib/isccc/api b/lib/isccc/api
new file mode 100644
index 0000000..79bb9eb
--- /dev/null
+++ b/lib/isccc/api
@@ -0,0 +1,13 @@
+# LIBINTERFACE ranges
+# 9.6: 50-59, 110-119
+# 9.7: 60-79
+# 9.8: 80-89, 120-129
+# 9.9: 90-109, 170-179
+# 9.9-sub: 130-139, 150-159, 200-209
+# 9.10: 140-149, 190-199
+# 9.10-sub: 180-189
+# 9.11: 160-169,1100-1199
+# 9.12: 1200-1299
+LIBINTERFACE = 161
+LIBREVISION = 0
+LIBAGE = 0
diff --git a/lib/isccc/base64.c b/lib/isccc/base64.c
new file mode 100644
index 0000000..54e8bd0
--- /dev/null
+++ b/lib/isccc/base64.c
@@ -0,0 +1,73 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/base64.h>
+#include <isc/buffer.h>
+#include <isc/region.h>
+#include <isc/result.h>
+
+#include <isccc/base64.h>
+#include <isccc/result.h>
+#include <isccc/util.h>
+
+isc_result_t
+isccc_base64_encode(isccc_region_t *source, int wordlength,
+ const char *wordbreak, isccc_region_t *target)
+{
+ isc_region_t sr;
+ isc_buffer_t tb;
+ isc_result_t result;
+
+ sr.base = source->rstart;
+ sr.length = (unsigned int)(source->rend - source->rstart);
+ isc_buffer_init(&tb, target->rstart,
+ (unsigned int)(target->rend - target->rstart));
+
+ result = isc_base64_totext(&sr, wordlength, wordbreak, &tb);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ source->rstart = source->rend;
+ target->rstart = isc_buffer_used(&tb);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isccc_base64_decode(const char *cstr, isccc_region_t *target) {
+ isc_buffer_t b;
+ isc_result_t result;
+
+ isc_buffer_init(&b, target->rstart,
+ (unsigned int)(target->rend - target->rstart));
+ result = isc_base64_decodestring(cstr, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ target->rstart = isc_buffer_used(&b);
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isccc/cc.c b/lib/isccc/cc.c
new file mode 100644
index 0000000..c2740cb
--- /dev/null
+++ b/lib/isccc/cc.c
@@ -0,0 +1,1084 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+
+#include <isc/assertions.h>
+#include <isc/hmacmd5.h>
+#include <isc/hmacsha.h>
+#include <isc/print.h>
+#include <isc/safe.h>
+#include <isc/stdlib.h>
+
+#include <pk11/site.h>
+
+#include <isccc/alist.h>
+#include <isccc/base64.h>
+#include <isccc/cc.h>
+#include <isccc/result.h>
+#include <isccc/sexpr.h>
+#include <isccc/symtab.h>
+#include <isccc/symtype.h>
+#include <isccc/util.h>
+
+#define MAX_TAGS 256
+#define DUP_LIFETIME 900
+
+typedef isccc_sexpr_t *sexpr_ptr;
+
+#ifndef PK11_MD5_DISABLE
+static unsigned char auth_hmd5[] = {
+ 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
+ ISCCC_CCMSGTYPE_TABLE, /*%< message type */
+ 0x00, 0x00, 0x00, 0x20, /*%< length == 32 */
+ 0x04, 0x68, 0x6d, 0x64, 0x35, /*%< len + hmd5 */
+ ISCCC_CCMSGTYPE_BINARYDATA, /*%< message type */
+ 0x00, 0x00, 0x00, 0x16, /*%< length == 22 */
+ /*
+ * The base64 encoding of one of our HMAC-MD5 signatures is
+ * 22 bytes.
+ */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#define HMD5_OFFSET 21 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 */
+#define HMD5_LENGTH 22
+#endif
+
+static unsigned char auth_hsha[] = {
+ 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
+ ISCCC_CCMSGTYPE_TABLE, /*%< message type */
+ 0x00, 0x00, 0x00, 0x63, /*%< length == 99 */
+ 0x04, 0x68, 0x73, 0x68, 0x61, /*%< len + hsha */
+ ISCCC_CCMSGTYPE_BINARYDATA, /*%< message type */
+ 0x00, 0x00, 0x00, 0x59, /*%< length == 89 */
+ 0x00, /*%< algorithm */
+ /*
+ * The base64 encoding of one of our HMAC-SHA* signatures is
+ * 88 bytes.
+ */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#define HSHA_OFFSET 22 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 + 1 */
+#define HSHA_LENGTH 88
+
+static isc_result_t
+table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
+
+static isc_result_t
+list_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
+
+static isc_result_t
+value_towire(isccc_sexpr_t *elt, isc_buffer_t **buffer) {
+ unsigned int len;
+ isccc_region_t *vr;
+ isc_result_t result;
+
+ if (isccc_sexpr_binaryp(elt)) {
+ vr = isccc_sexpr_tobinary(elt);
+ len = REGION_SIZE(*vr);
+ result = isc_buffer_reserve(buffer, 1 + 4);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_BINARYDATA);
+ isc_buffer_putuint32(*buffer, len);
+
+ result = isc_buffer_reserve(buffer, len);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putmem(*buffer, vr->rstart, len);
+ } else if (isccc_alist_alistp(elt)) {
+ unsigned int used;
+ isc_buffer_t b;
+
+ result = isc_buffer_reserve(buffer, 1 + 4);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_TABLE);
+ /*
+ * Emit a placeholder length.
+ */
+ used = (*buffer)->used;
+ isc_buffer_putuint32(*buffer, 0);
+
+ /*
+ * Emit the table.
+ */
+ result = table_towire(elt, buffer);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ len = (*buffer)->used - used;
+ /*
+ * 'len' is 4 bytes too big, since it counts
+ * the placeholder length too. Adjust and
+ * emit.
+ */
+ INSIST(len >= 4U);
+ len -= 4;
+
+ isc_buffer_init(&b, (unsigned char *) (*buffer)->base + used, 4);
+ isc_buffer_putuint32(&b, len);
+ } else if (isccc_sexpr_listp(elt)) {
+ unsigned int used;
+ isc_buffer_t b;
+
+ result = isc_buffer_reserve(buffer, 1 + 4);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_LIST);
+ /*
+ * Emit a placeholder length.
+ */
+ used = (*buffer)->used;
+ isc_buffer_putuint32(*buffer, 0);
+
+ /*
+ * Emit the list.
+ */
+ result = list_towire(elt, buffer);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ len = (*buffer)->used - used;
+ /*
+ * 'len' is 4 bytes too big, since it counts
+ * the placeholder length too. Adjust and
+ * emit.
+ */
+ INSIST(len >= 4U);
+ len -= 4;
+
+ isc_buffer_init(&b, (unsigned char *) (*buffer)->base + used, 4);
+ isc_buffer_putuint32(&b, len);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer) {
+ isccc_sexpr_t *kv, *elt, *k, *v;
+ char *ks;
+ isc_result_t result;
+ unsigned int len;
+
+ for (elt = isccc_alist_first(alist);
+ elt != NULL;
+ elt = ISCCC_SEXPR_CDR(elt)) {
+ kv = ISCCC_SEXPR_CAR(elt);
+ k = ISCCC_SEXPR_CAR(kv);
+ ks = isccc_sexpr_tostring(k);
+ v = ISCCC_SEXPR_CDR(kv);
+ len = (unsigned int)strlen(ks);
+ INSIST(len <= 255U);
+ /*
+ * Emit the key name.
+ */
+ result = isc_buffer_reserve(buffer, 1 + len);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint8(*buffer, (uint8_t)len);
+ isc_buffer_putmem(*buffer, (const unsigned char *) ks, len);
+ /*
+ * Emit the value.
+ */
+ result = value_towire(v, buffer);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+list_towire(isccc_sexpr_t *list, isc_buffer_t **buffer) {
+ isc_result_t result;
+
+ while (list != NULL) {
+ result = value_towire(ISCCC_SEXPR_CAR(list), buffer);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ list = ISCCC_SEXPR_CDR(list);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+sign(unsigned char *data, unsigned int length, unsigned char *hmac,
+ uint32_t algorithm, isccc_region_t *secret)
+{
+ union {
+#ifndef PK11_MD5_DISABLE
+ isc_hmacmd5_t hmd5;
+#endif
+ isc_hmacsha1_t hsha;
+ isc_hmacsha224_t h224;
+ isc_hmacsha256_t h256;
+ isc_hmacsha384_t h384;
+ isc_hmacsha512_t h512;
+ } ctx;
+ isc_result_t result;
+ isccc_region_t source, target;
+ unsigned char digest[ISC_SHA512_DIGESTLENGTH];
+ unsigned char digestb64[HSHA_LENGTH + 4];
+
+ source.rstart = digest;
+
+ switch (algorithm) {
+#ifndef PK11_MD5_DISABLE
+ case ISCCC_ALG_HMACMD5:
+ isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacmd5_update(&ctx.hmd5, data, length);
+ isc_hmacmd5_sign(&ctx.hmd5, digest);
+ source.rend = digest + ISC_MD5_DIGESTLENGTH;
+ break;
+#endif
+
+ case ISCCC_ALG_HMACSHA1:
+ isc_hmacsha1_init(&ctx.hsha, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacsha1_update(&ctx.hsha, data, length);
+ isc_hmacsha1_sign(&ctx.hsha, digest,
+ ISC_SHA1_DIGESTLENGTH);
+ source.rend = digest + ISC_SHA1_DIGESTLENGTH;
+ break;
+
+ case ISCCC_ALG_HMACSHA224:
+ isc_hmacsha224_init(&ctx.h224, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacsha224_update(&ctx.h224, data, length);
+ isc_hmacsha224_sign(&ctx.h224, digest,
+ ISC_SHA224_DIGESTLENGTH);
+ source.rend = digest + ISC_SHA224_DIGESTLENGTH;
+ break;
+
+ case ISCCC_ALG_HMACSHA256:
+ isc_hmacsha256_init(&ctx.h256, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacsha256_update(&ctx.h256, data, length);
+ isc_hmacsha256_sign(&ctx.h256, digest,
+ ISC_SHA256_DIGESTLENGTH);
+ source.rend = digest + ISC_SHA256_DIGESTLENGTH;
+ break;
+
+ case ISCCC_ALG_HMACSHA384:
+ isc_hmacsha384_init(&ctx.h384, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacsha384_update(&ctx.h384, data, length);
+ isc_hmacsha384_sign(&ctx.h384, digest,
+ ISC_SHA384_DIGESTLENGTH);
+ source.rend = digest + ISC_SHA384_DIGESTLENGTH;
+ break;
+
+ case ISCCC_ALG_HMACSHA512:
+ isc_hmacsha512_init(&ctx.h512, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacsha512_update(&ctx.h512, data, length);
+ isc_hmacsha512_sign(&ctx.h512, digest,
+ ISC_SHA512_DIGESTLENGTH);
+ source.rend = digest + ISC_SHA512_DIGESTLENGTH;
+ break;
+
+ default:
+ return (ISC_R_FAILURE);
+ }
+
+ memset(digestb64, 0, sizeof(digestb64));
+ target.rstart = digestb64;
+ target.rend = digestb64 + sizeof(digestb64);
+ result = isccc_base64_encode(&source, 64, "", &target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#ifndef PK11_MD5_DISABLE
+ if (algorithm == ISCCC_ALG_HMACMD5)
+ PUT_MEM(digestb64, HMD5_LENGTH, hmac);
+ else
+#endif
+ PUT_MEM(digestb64, HSHA_LENGTH, hmac);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer,
+ uint32_t algorithm, isccc_region_t *secret)
+{
+ unsigned int hmac_base, signed_base;
+ isc_result_t result;
+
+#ifndef PK11_MD5_DISABLE
+ result = isc_buffer_reserve(buffer,
+ 4 + ((algorithm == ISCCC_ALG_HMACMD5) ?
+ sizeof(auth_hmd5) :
+ sizeof(auth_hsha)));
+#else
+ if (algorithm == ISCCC_ALG_HMACMD5)
+ return (ISC_R_NOTIMPLEMENTED);
+ result = isc_buffer_reserve(buffer, 4 + sizeof(auth_hsha));
+#endif
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOSPACE);
+
+ /*
+ * Emit protocol version.
+ */
+ isc_buffer_putuint32(*buffer, 1);
+
+ if (secret != NULL) {
+ /*
+ * Emit _auth section with zeroed HMAC signature.
+ * We'll replace the zeros with the real signature once
+ * we know what it is.
+ */
+#ifndef PK11_MD5_DISABLE
+ if (algorithm == ISCCC_ALG_HMACMD5) {
+ hmac_base = (*buffer)->used + HMD5_OFFSET;
+ isc_buffer_putmem(*buffer,
+ auth_hmd5, sizeof(auth_hmd5));
+ } else
+#endif
+ {
+ unsigned char *hmac_alg;
+
+ hmac_base = (*buffer)->used + HSHA_OFFSET;
+ hmac_alg = (unsigned char *) isc_buffer_used(*buffer) +
+ HSHA_OFFSET - 1;
+ isc_buffer_putmem(*buffer,
+ auth_hsha, sizeof(auth_hsha));
+ *hmac_alg = algorithm;
+ }
+ } else
+ hmac_base = 0;
+ signed_base = (*buffer)->used;
+ /*
+ * Delete any existing _auth section so that we don't try
+ * to encode it.
+ */
+ isccc_alist_delete(alist, "_auth");
+ /*
+ * Emit the message.
+ */
+ result = table_towire(alist, buffer);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (secret != NULL)
+ return (sign((unsigned char *) (*buffer)->base + signed_base,
+ (*buffer)->used - signed_base,
+ (unsigned char *) (*buffer)->base + hmac_base,
+ algorithm, secret));
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
+ uint32_t algorithm, isccc_region_t *secret)
+{
+ union {
+#ifndef PK11_MD5_DISABLE
+ isc_hmacmd5_t hmd5;
+#endif
+ isc_hmacsha1_t hsha;
+ isc_hmacsha224_t h224;
+ isc_hmacsha256_t h256;
+ isc_hmacsha384_t h384;
+ isc_hmacsha512_t h512;
+ } ctx;
+ isccc_region_t source;
+ isccc_region_t target;
+ isc_result_t result;
+ isccc_sexpr_t *_auth, *hmac;
+ unsigned char digest[ISC_SHA512_DIGESTLENGTH];
+ unsigned char digestb64[HSHA_LENGTH * 4];
+
+ /*
+ * Extract digest.
+ */
+ _auth = isccc_alist_lookup(alist, "_auth");
+ if (!isccc_alist_alistp(_auth))
+ return (ISC_R_FAILURE);
+#ifndef PK11_MD5_DISABLE
+ if (algorithm == ISCCC_ALG_HMACMD5)
+ hmac = isccc_alist_lookup(_auth, "hmd5");
+ else
+#endif
+ hmac = isccc_alist_lookup(_auth, "hsha");
+ if (!isccc_sexpr_binaryp(hmac))
+ return (ISC_R_FAILURE);
+ /*
+ * Compute digest.
+ */
+ source.rstart = digest;
+ target.rstart = digestb64;
+ switch (algorithm) {
+#ifndef PK11_MD5_DISABLE
+ case ISCCC_ALG_HMACMD5:
+ isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacmd5_update(&ctx.hmd5, data, length);
+ isc_hmacmd5_sign(&ctx.hmd5, digest);
+ source.rend = digest + ISC_MD5_DIGESTLENGTH;
+ break;
+#endif
+
+ case ISCCC_ALG_HMACSHA1:
+ isc_hmacsha1_init(&ctx.hsha, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacsha1_update(&ctx.hsha, data, length);
+ isc_hmacsha1_sign(&ctx.hsha, digest,
+ ISC_SHA1_DIGESTLENGTH);
+ source.rend = digest + ISC_SHA1_DIGESTLENGTH;
+ break;
+
+ case ISCCC_ALG_HMACSHA224:
+ isc_hmacsha224_init(&ctx.h224, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacsha224_update(&ctx.h224, data, length);
+ isc_hmacsha224_sign(&ctx.h224, digest,
+ ISC_SHA224_DIGESTLENGTH);
+ source.rend = digest + ISC_SHA224_DIGESTLENGTH;
+ break;
+
+ case ISCCC_ALG_HMACSHA256:
+ isc_hmacsha256_init(&ctx.h256, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacsha256_update(&ctx.h256, data, length);
+ isc_hmacsha256_sign(&ctx.h256, digest,
+ ISC_SHA256_DIGESTLENGTH);
+ source.rend = digest + ISC_SHA256_DIGESTLENGTH;
+ break;
+
+ case ISCCC_ALG_HMACSHA384:
+ isc_hmacsha384_init(&ctx.h384, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacsha384_update(&ctx.h384, data, length);
+ isc_hmacsha384_sign(&ctx.h384, digest,
+ ISC_SHA384_DIGESTLENGTH);
+ source.rend = digest + ISC_SHA384_DIGESTLENGTH;
+ break;
+
+ case ISCCC_ALG_HMACSHA512:
+ isc_hmacsha512_init(&ctx.h512, secret->rstart,
+ REGION_SIZE(*secret));
+ isc_hmacsha512_update(&ctx.h512, data, length);
+ isc_hmacsha512_sign(&ctx.h512, digest,
+ ISC_SHA512_DIGESTLENGTH);
+ source.rend = digest + ISC_SHA512_DIGESTLENGTH;
+ break;
+
+ default:
+ return (ISC_R_FAILURE);
+ }
+ target.rstart = digestb64;
+ target.rend = digestb64 + sizeof(digestb64);
+ memset(digestb64, 0, sizeof(digestb64));
+ result = isccc_base64_encode(&source, 64, "", &target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Verify.
+ */
+#ifndef PK11_MD5_DISABLE
+ if (algorithm == ISCCC_ALG_HMACMD5) {
+ isccc_region_t *region;
+ unsigned char *value;
+
+ region = isccc_sexpr_tobinary(hmac);
+ if ((region->rend - region->rstart) != HMD5_LENGTH)
+ return (ISCCC_R_BADAUTH);
+ value = region->rstart;
+ if (!isc_safe_memequal(value, digestb64, HMD5_LENGTH))
+ return (ISCCC_R_BADAUTH);
+ } else
+#endif
+ {
+ isccc_region_t *region;
+ unsigned char *value;
+ uint32_t valalg;
+
+ region = isccc_sexpr_tobinary(hmac);
+
+ /*
+ * Note: with non-MD5 algorithms, there's an extra octet
+ * to identify which algorithm is in use.
+ */
+ if ((region->rend - region->rstart) != HSHA_LENGTH + 1)
+ return (ISCCC_R_BADAUTH);
+ value = region->rstart;
+ GET8(valalg, value);
+ if ((valalg != algorithm) ||
+ !isc_safe_memequal(value, digestb64, HSHA_LENGTH))
+ return (ISCCC_R_BADAUTH);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+table_fromwire(isccc_region_t *source, isccc_region_t *secret,
+ uint32_t algorithm, isccc_sexpr_t **alistp);
+
+static isc_result_t
+list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp);
+
+static isc_result_t
+value_fromwire(isccc_region_t *source, isccc_sexpr_t **valuep) {
+ unsigned int msgtype;
+ uint32_t len;
+ isccc_sexpr_t *value;
+ isccc_region_t active;
+ isc_result_t result;
+
+ if (REGION_SIZE(*source) < 1 + 4)
+ return (ISC_R_UNEXPECTEDEND);
+ GET8(msgtype, source->rstart);
+ GET32(len, source->rstart);
+ if (REGION_SIZE(*source) < len)
+ return (ISC_R_UNEXPECTEDEND);
+ active.rstart = source->rstart;
+ active.rend = active.rstart + len;
+ source->rstart = active.rend;
+ if (msgtype == ISCCC_CCMSGTYPE_BINARYDATA) {
+ value = isccc_sexpr_frombinary(&active);
+ if (value != NULL) {
+ *valuep = value;
+ result = ISC_R_SUCCESS;
+ } else
+ result = ISC_R_NOMEMORY;
+ } else if (msgtype == ISCCC_CCMSGTYPE_TABLE)
+ result = table_fromwire(&active, NULL, 0, valuep);
+ else if (msgtype == ISCCC_CCMSGTYPE_LIST)
+ result = list_fromwire(&active, valuep);
+ else
+ result = ISCCC_R_SYNTAX;
+
+ return (result);
+}
+
+static isc_result_t
+table_fromwire(isccc_region_t *source, isccc_region_t *secret,
+ uint32_t algorithm, isccc_sexpr_t **alistp)
+{
+ char key[256];
+ uint32_t len;
+ isc_result_t result;
+ isccc_sexpr_t *alist, *value;
+ bool first_tag;
+ unsigned char *checksum_rstart;
+
+ REQUIRE(alistp != NULL && *alistp == NULL);
+
+ checksum_rstart = NULL;
+ first_tag = true;
+ alist = isccc_alist_create();
+ if (alist == NULL)
+ return (ISC_R_NOMEMORY);
+
+ while (!REGION_EMPTY(*source)) {
+ GET8(len, source->rstart);
+ if (REGION_SIZE(*source) < len) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto bad;
+ }
+ GET_MEM(key, len, source->rstart);
+ key[len] = '\0'; /* Ensure NUL termination. */
+ value = NULL;
+ result = value_fromwire(source, &value);
+ if (result != ISC_R_SUCCESS)
+ goto bad;
+ if (isccc_alist_define(alist, key, value) == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto bad;
+ }
+ if (first_tag && secret != NULL && strcmp(key, "_auth") == 0)
+ checksum_rstart = source->rstart;
+ first_tag = false;
+ }
+
+ if (secret != NULL) {
+ if (checksum_rstart != NULL)
+ result = verify(alist, checksum_rstart,
+ (unsigned int)
+ (source->rend - checksum_rstart),
+ algorithm, secret);
+ else
+ result = ISCCC_R_BADAUTH;
+ } else
+ result = ISC_R_SUCCESS;
+
+ bad:
+ if (result == ISC_R_SUCCESS)
+ *alistp = alist;
+ else
+ isccc_sexpr_free(&alist);
+
+ return (result);
+}
+
+static isc_result_t
+list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp) {
+ isccc_sexpr_t *list, *value;
+ isc_result_t result;
+
+ list = NULL;
+ while (!REGION_EMPTY(*source)) {
+ value = NULL;
+ result = value_fromwire(source, &value);
+ if (result != ISC_R_SUCCESS) {
+ isccc_sexpr_free(&list);
+ return (result);
+ }
+ if (isccc_sexpr_addtolist(&list, value) == NULL) {
+ isccc_sexpr_free(&value);
+ isccc_sexpr_free(&list);
+ return (ISC_R_NOMEMORY);
+ }
+ }
+
+ *listp = list;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
+ uint32_t algorithm, isccc_region_t *secret)
+{
+ unsigned int size;
+ uint32_t version;
+
+ size = REGION_SIZE(*source);
+ if (size < 4)
+ return (ISC_R_UNEXPECTEDEND);
+ GET32(version, source->rstart);
+ if (version != 1)
+ return (ISCCC_R_UNKNOWNVERSION);
+
+ return (table_fromwire(source, secret, algorithm, alistp));
+}
+
+static isc_result_t
+createmessage(uint32_t version, const char *from, const char *to,
+ uint32_t serial, isccc_time_t now,
+ isccc_time_t expires, isccc_sexpr_t **alistp,
+ bool want_expires)
+{
+ isccc_sexpr_t *alist, *_ctrl, *_data;
+ isc_result_t result;
+
+ REQUIRE(alistp != NULL && *alistp == NULL);
+
+ if (version != 1)
+ return (ISCCC_R_UNKNOWNVERSION);
+
+ alist = isccc_alist_create();
+ if (alist == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = ISC_R_NOMEMORY;
+
+ _ctrl = isccc_alist_create();
+ if (_ctrl == NULL)
+ goto bad;
+ if (isccc_alist_define(alist, "_ctrl", _ctrl) == NULL) {
+ isccc_sexpr_free(&_ctrl);
+ goto bad;
+ }
+
+ _data = isccc_alist_create();
+ if (_data == NULL)
+ goto bad;
+ if (isccc_alist_define(alist, "_data", _data) == NULL) {
+ isccc_sexpr_free(&_data);
+ goto bad;
+ }
+
+ if (isccc_cc_defineuint32(_ctrl, "_ser", serial) == NULL ||
+ isccc_cc_defineuint32(_ctrl, "_tim", now) == NULL ||
+ (want_expires &&
+ isccc_cc_defineuint32(_ctrl, "_exp", expires) == NULL))
+ goto bad;
+ if (from != NULL &&
+ isccc_cc_definestring(_ctrl, "_frm", from) == NULL)
+ goto bad;
+ if (to != NULL &&
+ isccc_cc_definestring(_ctrl, "_to", to) == NULL)
+ goto bad;
+
+ *alistp = alist;
+
+ return (ISC_R_SUCCESS);
+
+ bad:
+ isccc_sexpr_free(&alist);
+
+ return (result);
+}
+
+isc_result_t
+isccc_cc_createmessage(uint32_t version, const char *from, const char *to,
+ uint32_t serial, isccc_time_t now,
+ isccc_time_t expires, isccc_sexpr_t **alistp)
+{
+ return (createmessage(version, from, to, serial, now, expires,
+ alistp, true));
+}
+
+isc_result_t
+isccc_cc_createack(isccc_sexpr_t *message, bool ok,
+ isccc_sexpr_t **ackp)
+{
+ char *_frm, *_to;
+ uint32_t serial;
+ isccc_sexpr_t *ack, *_ctrl;
+ isc_result_t result;
+ isccc_time_t t;
+
+ REQUIRE(ackp != NULL && *ackp == NULL);
+
+ _ctrl = isccc_alist_lookup(message, "_ctrl");
+ if (!isccc_alist_alistp(_ctrl) ||
+ isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
+ isccc_cc_lookupuint32(_ctrl, "_tim", &t) != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+ /*
+ * _frm and _to are optional.
+ */
+ _frm = NULL;
+ (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
+ _to = NULL;
+ (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
+ /*
+ * Create the ack.
+ */
+ ack = NULL;
+ result = createmessage(1, _to, _frm, serial, t, 0, &ack, false);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ _ctrl = isccc_alist_lookup(ack, "_ctrl");
+ if (_ctrl == NULL) {
+ result = ISC_R_FAILURE;
+ goto bad;
+ }
+ if (isccc_cc_definestring(ack, "_ack", (ok) ? "1" : "0") == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto bad;
+ }
+
+ *ackp = ack;
+
+ return (ISC_R_SUCCESS);
+
+ bad:
+ isccc_sexpr_free(&ack);
+
+ return (result);
+}
+
+bool
+isccc_cc_isack(isccc_sexpr_t *message) {
+ isccc_sexpr_t *_ctrl;
+
+ _ctrl = isccc_alist_lookup(message, "_ctrl");
+ if (!isccc_alist_alistp(_ctrl))
+ return (false);
+ if (isccc_cc_lookupstring(_ctrl, "_ack", NULL) == ISC_R_SUCCESS)
+ return (true);
+ return (false);
+}
+
+bool
+isccc_cc_isreply(isccc_sexpr_t *message) {
+ isccc_sexpr_t *_ctrl;
+
+ _ctrl = isccc_alist_lookup(message, "_ctrl");
+ if (!isccc_alist_alistp(_ctrl))
+ return (false);
+ if (isccc_cc_lookupstring(_ctrl, "_rpl", NULL) == ISC_R_SUCCESS)
+ return (true);
+ return (false);
+}
+
+isc_result_t
+isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
+ isccc_time_t expires, isccc_sexpr_t **alistp)
+{
+ char *_frm, *_to, *type = NULL;
+ uint32_t serial;
+ isccc_sexpr_t *alist, *_ctrl, *_data;
+ isc_result_t result;
+
+ REQUIRE(alistp != NULL && *alistp == NULL);
+
+ _ctrl = isccc_alist_lookup(message, "_ctrl");
+ _data = isccc_alist_lookup(message, "_data");
+ if (!isccc_alist_alistp(_ctrl) || !isccc_alist_alistp(_data) ||
+ isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
+ isccc_cc_lookupstring(_data, "type", &type) != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+ /*
+ * _frm and _to are optional.
+ */
+ _frm = NULL;
+ (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
+ _to = NULL;
+ (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
+ /*
+ * Create the response.
+ */
+ alist = NULL;
+ result = isccc_cc_createmessage(1, _to, _frm, serial, now, expires,
+ &alist);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ _ctrl = isccc_alist_lookup(alist, "_ctrl");
+ if (_ctrl == NULL) {
+ result = ISC_R_FAILURE;
+ goto bad;
+ }
+
+ _data = isccc_alist_lookup(alist, "_data");
+ if (_data == NULL) {
+ result = ISC_R_FAILURE;
+ goto bad;
+ }
+
+ if (isccc_cc_definestring(_ctrl, "_rpl", "1") == NULL ||
+ isccc_cc_definestring(_data, "type", type) == NULL)
+ {
+ result = ISC_R_NOMEMORY;
+ goto bad;
+ }
+
+ *alistp = alist;
+
+ return (ISC_R_SUCCESS);
+
+ bad:
+ isccc_sexpr_free(&alist);
+ return (result);
+}
+
+isccc_sexpr_t *
+isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str) {
+ size_t len;
+ isccc_region_t r;
+
+ len = strlen(str);
+ DE_CONST(str, r.rstart);
+ r.rend = r.rstart + len;
+
+ return (isccc_alist_definebinary(alist, key, &r));
+}
+
+isccc_sexpr_t *
+isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, uint32_t i) {
+ char b[100];
+ size_t len;
+ isccc_region_t r;
+
+ snprintf(b, sizeof(b), "%u", i);
+ len = strlen(b);
+ r.rstart = (unsigned char *)b;
+ r.rend = (unsigned char *)b + len;
+
+ return (isccc_alist_definebinary(alist, key, &r));
+}
+
+isc_result_t
+isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp) {
+ isccc_sexpr_t *kv, *v;
+
+ REQUIRE(strp == NULL || *strp == NULL);
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv != NULL) {
+ v = ISCCC_SEXPR_CDR(kv);
+ if (isccc_sexpr_binaryp(v)) {
+ if (strp != NULL)
+ *strp = isccc_sexpr_tostring(v);
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_EXISTS);
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+isc_result_t
+isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key,
+ uint32_t *uintp)
+{
+ isccc_sexpr_t *kv, *v;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv != NULL) {
+ v = ISCCC_SEXPR_CDR(kv);
+ if (isccc_sexpr_binaryp(v)) {
+ if (uintp != NULL)
+ *uintp = (uint32_t)
+ strtoul(isccc_sexpr_tostring(v),
+ NULL, 10);
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_EXISTS);
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+static void
+symtab_undefine(char *key, unsigned int type, isccc_symvalue_t value,
+ void *arg)
+{
+ UNUSED(type);
+ UNUSED(value);
+ UNUSED(arg);
+
+ free(key);
+}
+
+static bool
+symtab_clean(char *key, unsigned int type, isccc_symvalue_t value, void *arg) {
+ isccc_time_t *now;
+
+ UNUSED(key);
+ UNUSED(type);
+
+ now = arg;
+
+ if (*now < value.as_uinteger)
+ return (false);
+ if ((*now - value.as_uinteger) < DUP_LIFETIME)
+ return (false);
+ return (true);
+}
+
+isc_result_t
+isccc_cc_createsymtab(isccc_symtab_t **symtabp) {
+ return (isccc_symtab_create(11897, symtab_undefine, NULL, false,
+ symtabp));
+}
+
+void
+isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now) {
+ isccc_symtab_foreach(symtab, symtab_clean, &now);
+}
+
+static bool
+has_whitespace(const char *str) {
+ char c;
+
+ if (str == NULL)
+ return (false);
+ while ((c = *str++) != '\0') {
+ if (c == ' ' || c == '\t' || c == '\n')
+ return (true);
+ }
+ return (false);
+}
+
+isc_result_t
+isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
+ isccc_time_t now)
+{
+ const char *_frm;
+ const char *_to;
+ char *_ser = NULL, *_tim = NULL, *tmp;
+ isc_result_t result;
+ char *key;
+ size_t len;
+ isccc_symvalue_t value;
+ isccc_sexpr_t *_ctrl;
+
+ _ctrl = isccc_alist_lookup(message, "_ctrl");
+ if (!isccc_alist_alistp(_ctrl) ||
+ isccc_cc_lookupstring(_ctrl, "_ser", &_ser) != ISC_R_SUCCESS ||
+ isccc_cc_lookupstring(_ctrl, "_tim", &_tim) != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+
+ INSIST(_ser != NULL);
+ INSIST(_tim != NULL);
+
+ /*
+ * _frm and _to are optional.
+ */
+ tmp = NULL;
+ if (isccc_cc_lookupstring(_ctrl, "_frm", &tmp) != ISC_R_SUCCESS)
+ _frm = "";
+ else
+ _frm = tmp;
+ tmp = NULL;
+ if (isccc_cc_lookupstring(_ctrl, "_to", &tmp) != ISC_R_SUCCESS)
+ _to = "";
+ else
+ _to = tmp;
+ /*
+ * Ensure there is no newline in any of the strings. This is so
+ * we can write them to a file later.
+ */
+ if (has_whitespace(_frm) || has_whitespace(_to) ||
+ has_whitespace(_ser) || has_whitespace(_tim))
+ return (ISC_R_FAILURE);
+ len = strlen(_frm) + strlen(_to) + strlen(_ser) + strlen(_tim) + 4;
+ key = malloc(len);
+ if (key == NULL)
+ return (ISC_R_NOMEMORY);
+ snprintf(key, len, "%s;%s;%s;%s", _frm, _to, _ser, _tim);
+ value.as_uinteger = now;
+ result = isccc_symtab_define(symtab, key, ISCCC_SYMTYPE_CCDUP, value,
+ isccc_symexists_reject);
+ if (result != ISC_R_SUCCESS) {
+ free(key);
+ return (result);
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isccc/ccmsg.c b/lib/isccc/ccmsg.c
new file mode 100644
index 0000000..4cfa528
--- /dev/null
+++ b/lib/isccc/ccmsg.c
@@ -0,0 +1,230 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include <isccc/events.h>
+#include <isccc/ccmsg.h>
+
+#define CCMSG_MAGIC ISC_MAGIC('C', 'C', 'm', 's')
+#define VALID_CCMSG(foo) ISC_MAGIC_VALID(foo, CCMSG_MAGIC)
+
+static void recv_length(isc_task_t *, isc_event_t *);
+static void recv_message(isc_task_t *, isc_event_t *);
+
+
+static void
+recv_length(isc_task_t *task, isc_event_t *ev_in) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
+ isc_event_t *dev;
+ isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
+ isc_region_t region;
+ isc_result_t result;
+
+ INSIST(VALID_CCMSG(ccmsg));
+
+ dev = &ccmsg->event;
+
+ if (ev->result != ISC_R_SUCCESS) {
+ ccmsg->result = ev->result;
+ goto send_and_free;
+ }
+
+ /*
+ * Success.
+ */
+ ccmsg->size = ntohl(ccmsg->size);
+ if (ccmsg->size == 0) {
+ ccmsg->result = ISC_R_UNEXPECTEDEND;
+ goto send_and_free;
+ }
+ if (ccmsg->size > ccmsg->maxsize) {
+ ccmsg->result = ISC_R_RANGE;
+ goto send_and_free;
+ }
+
+ region.base = isc_mem_get(ccmsg->mctx, ccmsg->size);
+ region.length = ccmsg->size;
+ if (region.base == NULL) {
+ ccmsg->result = ISC_R_NOMEMORY;
+ goto send_and_free;
+ }
+
+ isc_buffer_init(&ccmsg->buffer, region.base, region.length);
+ result = isc_socket_recv(ccmsg->sock, &region, 0,
+ task, recv_message, ccmsg);
+ if (result != ISC_R_SUCCESS) {
+ ccmsg->result = result;
+ goto send_and_free;
+ }
+
+ isc_event_free(&ev_in);
+ return;
+
+ send_and_free:
+ isc_task_send(ccmsg->task, &dev);
+ ccmsg->task = NULL;
+ isc_event_free(&ev_in);
+ return;
+}
+
+static void
+recv_message(isc_task_t *task, isc_event_t *ev_in) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
+ isc_event_t *dev;
+ isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
+
+ (void)task;
+
+ INSIST(VALID_CCMSG(ccmsg));
+
+ dev = &ccmsg->event;
+
+ if (ev->result != ISC_R_SUCCESS) {
+ ccmsg->result = ev->result;
+ goto send_and_free;
+ }
+
+ ccmsg->result = ISC_R_SUCCESS;
+ isc_buffer_add(&ccmsg->buffer, ev->n);
+ ccmsg->address = ev->address;
+
+ send_and_free:
+ isc_task_send(ccmsg->task, &dev);
+ ccmsg->task = NULL;
+ isc_event_free(&ev_in);
+}
+
+void
+isccc_ccmsg_init(isc_mem_t *mctx, isc_socket_t *sock, isccc_ccmsg_t *ccmsg) {
+ REQUIRE(mctx != NULL);
+ REQUIRE(sock != NULL);
+ REQUIRE(ccmsg != NULL);
+
+ ccmsg->magic = CCMSG_MAGIC;
+ ccmsg->size = 0;
+ ccmsg->buffer.base = NULL;
+ ccmsg->buffer.length = 0;
+ ccmsg->maxsize = 4294967295U; /* Largest message possible. */
+ ccmsg->mctx = mctx;
+ ccmsg->sock = sock;
+ ccmsg->task = NULL; /* None yet. */
+ ccmsg->result = ISC_R_UNEXPECTED; /* None yet. */
+ /*
+ * Should probably initialize the event here, but it can wait.
+ */
+}
+
+
+void
+isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize) {
+ REQUIRE(VALID_CCMSG(ccmsg));
+
+ ccmsg->maxsize = maxsize;
+}
+
+
+isc_result_t
+isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ isc_result_t result;
+ isc_region_t region;
+
+ REQUIRE(VALID_CCMSG(ccmsg));
+ REQUIRE(task != NULL);
+ REQUIRE(ccmsg->task == NULL); /* not currently in use */
+
+ if (ccmsg->buffer.base != NULL) {
+ isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
+ ccmsg->buffer.length);
+ ccmsg->buffer.base = NULL;
+ ccmsg->buffer.length = 0;
+ }
+
+ ccmsg->task = task;
+ ccmsg->action = action;
+ ccmsg->arg = arg;
+ ccmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
+
+ ISC_EVENT_INIT(&ccmsg->event, sizeof(isc_event_t), 0, 0,
+ ISCCC_EVENT_CCMSG, action, arg, ccmsg,
+ NULL, NULL);
+
+ region.base = (unsigned char *)&ccmsg->size;
+ region.length = 4; /* uint32_t */
+ result = isc_socket_recv(ccmsg->sock, &region, 0,
+ ccmsg->task, recv_length, ccmsg);
+
+ if (result != ISC_R_SUCCESS)
+ ccmsg->task = NULL;
+
+ return (result);
+}
+
+void
+isccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg) {
+ REQUIRE(VALID_CCMSG(ccmsg));
+
+ isc_socket_cancel(ccmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
+}
+
+#if 0
+void
+isccc_ccmsg_freebuffer(isccc_ccmsg_t *ccmsg) {
+ REQUIRE(VALID_CCMSG(ccmsg));
+
+ if (ccmsg->buffer.base == NULL)
+ return;
+
+ isc_mem_put(ccmsg->mctx, ccmsg->buffer.base, ccmsg->buffer.length);
+ ccmsg->buffer.base = NULL;
+ ccmsg->buffer.length = 0;
+}
+#endif
+
+void
+isccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg) {
+ REQUIRE(VALID_CCMSG(ccmsg));
+
+ ccmsg->magic = 0;
+
+ if (ccmsg->buffer.base != NULL) {
+ isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
+ ccmsg->buffer.length);
+ ccmsg->buffer.base = NULL;
+ ccmsg->buffer.length = 0;
+ }
+}
diff --git a/lib/isccc/include/Makefile.in b/lib/isccc/include/Makefile.in
new file mode 100644
index 0000000..aea49d7
--- /dev/null
+++ b/lib/isccc/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isccc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isccc/include/isccc/Makefile.in b/lib/isccc/include/isccc/Makefile.in
new file mode 100644
index 0000000..23903db
--- /dev/null
+++ b/lib/isccc/include/isccc/Makefile.in
@@ -0,0 +1,39 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+#
+# Only list headers that are to be installed and are not
+# machine generated. The latter are handled specially in the
+# install target below.
+#
+HEADERS = alist.h base64.h cc.h ccmsg.h events.h lib.h result.h \
+ sexpr.h symtab.h symtype.h types.h util.h version.h
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isccc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/isccc || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isccc/$$i || exit 1; \
+ done
diff --git a/lib/isccc/include/isccc/alist.h b/lib/isccc/include/isccc/alist.h
new file mode 100644
index 0000000..ea50a44
--- /dev/null
+++ b/lib/isccc/include/isccc/alist.h
@@ -0,0 +1,81 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_ALIST_H
+#define ISCCC_ALIST_H 1
+
+/*! \file isccc/alist.h */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isccc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isccc_sexpr_t *
+isccc_alist_create(void);
+
+bool
+isccc_alist_alistp(isccc_sexpr_t *alist);
+
+bool
+isccc_alist_emptyp(isccc_sexpr_t *alist);
+
+isccc_sexpr_t *
+isccc_alist_first(isccc_sexpr_t *alist);
+
+isccc_sexpr_t *
+isccc_alist_assq(isccc_sexpr_t *alist, const char *key);
+
+void
+isccc_alist_delete(isccc_sexpr_t *alist, const char *key);
+
+isccc_sexpr_t *
+isccc_alist_define(isccc_sexpr_t *alist, const char *key, isccc_sexpr_t *value);
+
+isccc_sexpr_t *
+isccc_alist_definestring(isccc_sexpr_t *alist, const char *key, const char *str);
+
+isccc_sexpr_t *
+isccc_alist_definebinary(isccc_sexpr_t *alist, const char *key, isccc_region_t *r);
+
+isccc_sexpr_t *
+isccc_alist_lookup(isccc_sexpr_t *alist, const char *key);
+
+isc_result_t
+isccc_alist_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp);
+
+isc_result_t
+isccc_alist_lookupbinary(isccc_sexpr_t *alist, const char *key, isccc_region_t **r);
+
+void
+isccc_alist_prettyprint(isccc_sexpr_t *sexpr, unsigned int indent, FILE *stream);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_ALIST_H */
diff --git a/lib/isccc/include/isccc/base64.h b/lib/isccc/include/isccc/base64.h
new file mode 100644
index 0000000..c9bf70a
--- /dev/null
+++ b/lib/isccc/include/isccc/base64.h
@@ -0,0 +1,78 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_BASE64_H
+#define ISCCC_BASE64_H 1
+
+/*! \file isccc/base64.h */
+
+#include <isc/lang.h>
+#include <isccc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isccc_base64_encode(isccc_region_t *source, int wordlength,
+ const char *wordbreak, isccc_region_t *target);
+/*%<
+ * Convert data into base64 encoded text.
+ *
+ * Notes:
+ *\li The base64 encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data.
+ *\li 'target' is a text region containing available space.
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters.
+ */
+
+isc_result_t
+isccc_base64_decode(const char *cstr, isccc_region_t *target);
+/*%<
+ * Decode a null-terminated base64 string.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid region.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE64 -- 'cstr' is not a valid base64 encoding.
+ *\li #ISC_R_NOSPACE -- 'target' is not big enough.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_BASE64_H */
diff --git a/lib/isccc/include/isccc/cc.h b/lib/isccc/include/isccc/cc.h
new file mode 100644
index 0000000..5da2a72
--- /dev/null
+++ b/lib/isccc/include/isccc/cc.h
@@ -0,0 +1,129 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_CC_H
+#define ISCCC_CC_H 1
+
+/*! \file isccc/cc.h */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/buffer.h>
+#include <isccc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% from lib/dns/include/dst/dst.h */
+
+#define ISCCC_ALG_UNKNOWN 0
+#define ISCCC_ALG_HMACMD5 157
+#define ISCCC_ALG_HMACSHA1 161
+#define ISCCC_ALG_HMACSHA224 162
+#define ISCCC_ALG_HMACSHA256 163
+#define ISCCC_ALG_HMACSHA384 164
+#define ISCCC_ALG_HMACSHA512 165
+
+/*% Maximum Datagram Package */
+#define ISCCC_CC_MAXDGRAMPACKET 4096
+
+/*% Message Type String */
+#define ISCCC_CCMSGTYPE_STRING 0x00
+/*% Message Type Binary Data */
+#define ISCCC_CCMSGTYPE_BINARYDATA 0x01
+/*% Message Type Table */
+#define ISCCC_CCMSGTYPE_TABLE 0x02
+/*% Message Type List */
+#define ISCCC_CCMSGTYPE_LIST 0x03
+
+/*% Send to Wire */
+isc_result_t
+isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer,
+ uint32_t algorithm, isccc_region_t *secret);
+
+/*% Get From Wire */
+isc_result_t
+isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
+ uint32_t algorithm, isccc_region_t *secret);
+
+/*% Create Message */
+isc_result_t
+isccc_cc_createmessage(uint32_t version, const char *from, const char *to,
+ uint32_t serial, isccc_time_t now,
+ isccc_time_t expires, isccc_sexpr_t **alistp);
+
+/*% Create Acknowledgment */
+isc_result_t
+isccc_cc_createack(isccc_sexpr_t *message, bool ok,
+ isccc_sexpr_t **ackp);
+
+/*% Is Ack? */
+bool
+isccc_cc_isack(isccc_sexpr_t *message);
+
+/*% Is Reply? */
+bool
+isccc_cc_isreply(isccc_sexpr_t *message);
+
+/*% Create Response */
+isc_result_t
+isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
+ isccc_time_t expires, isccc_sexpr_t **alistp);
+
+/*% Define String */
+isccc_sexpr_t *
+isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str);
+
+/*% Define uint 32 */
+isccc_sexpr_t *
+isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, uint32_t i);
+
+/*% Lookup String */
+isc_result_t
+isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp);
+
+/*% Lookup uint 32 */
+isc_result_t
+isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key,
+ uint32_t *uintp);
+
+/*% Create Symbol Table */
+isc_result_t
+isccc_cc_createsymtab(isccc_symtab_t **symtabp);
+
+/*% Clean up Symbol Table */
+void
+isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now);
+
+/*% Check for Duplicates */
+isc_result_t
+isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
+ isccc_time_t now);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_CC_H */
diff --git a/lib/isccc/include/isccc/ccmsg.h b/lib/isccc/include/isccc/ccmsg.h
new file mode 100644
index 0000000..230d985
--- /dev/null
+++ b/lib/isccc/include/isccc/ccmsg.h
@@ -0,0 +1,143 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_CCMSG_H
+#define ISCCC_CCMSG_H 1
+
+/*! \file isccc/ccmsg.h */
+
+#include <inttypes.h>
+
+#include <isc/buffer.h>
+#include <isc/lang.h>
+#include <isc/socket.h>
+
+/*% ISCCC Message Structure */
+typedef struct isccc_ccmsg {
+ /* private (don't touch!) */
+ unsigned int magic;
+ uint32_t size;
+ isc_buffer_t buffer;
+ unsigned int maxsize;
+ isc_mem_t *mctx;
+ isc_socket_t *sock;
+ isc_task_t *task;
+ isc_taskaction_t action;
+ void *arg;
+ isc_event_t event;
+ /* public (read-only) */
+ isc_result_t result;
+ isc_sockaddr_t address;
+} isccc_ccmsg_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isccc_ccmsg_init(isc_mem_t *mctx, isc_socket_t *sock, isccc_ccmsg_t *ccmsg);
+/*%
+ * Associate a cc message state with a given memory context and
+ * TCP socket.
+ *
+ * Requires:
+ *
+ *\li "mctx" and "sock" be non-NULL and valid types.
+ *
+ *\li "sock" be a read/write TCP socket.
+ *
+ *\li "ccmsg" be non-NULL and an uninitialized or invalidated structure.
+ *
+ * Ensures:
+ *
+ *\li "ccmsg" is a valid structure.
+ */
+
+void
+isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize);
+/*%
+ * Set the maximum packet size to "maxsize"
+ *
+ * Requires:
+ *
+ *\li "ccmsg" be valid.
+ *
+ *\li 512 <= "maxsize" <= 4294967296
+ */
+
+isc_result_t
+isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+/*%
+ * Schedule an event to be delivered when a command channel message is
+ * readable, or when an error occurs on the socket.
+ *
+ * Requires:
+ *
+ *\li "ccmsg" be valid.
+ *
+ *\li "task", "taskaction", and "arg" be valid.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS -- no error
+ *\li Anything that the isc_socket_recv() call can return. XXXMLG
+ *
+ * Notes:
+ *
+ *\li The event delivered is a fully generic event. It will contain no
+ * actual data. The sender will be a pointer to the isccc_ccmsg_t.
+ * The result code inside that structure should be checked to see
+ * what the final result was.
+ */
+
+void
+isccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg);
+/*%
+ * Cancel a readmessage() call. The event will still be posted with a
+ * CANCELED result code.
+ *
+ * Requires:
+ *
+ *\li "ccmsg" be valid.
+ */
+
+void
+isccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg);
+/*%
+ * Clean up all allocated state, and invalidate the structure.
+ *
+ * Requires:
+ *
+ *\li "ccmsg" be valid.
+ *
+ * Ensures:
+ *
+ *\li "ccmsg" is invalidated and disassociated with all memory contexts,
+ * sockets, etc.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_CCMSG_H */
diff --git a/lib/isccc/include/isccc/events.h b/lib/isccc/include/isccc/events.h
new file mode 100644
index 0000000..5b6d23f
--- /dev/null
+++ b/lib/isccc/include/isccc/events.h
@@ -0,0 +1,43 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_EVENTS_H
+#define ISCCC_EVENTS_H 1
+
+/*! \file isccc/events.h */
+
+#include <isc/eventclass.h>
+
+/*%
+ * Registry of ISCCC event numbers.
+ */
+
+#define ISCCC_EVENT_CCMSG (ISC_EVENTCLASS_ISCCC + 0)
+
+#define ISCCC_EVENT_FIRSTEVENT (ISC_EVENTCLASS_ISCCC + 0)
+#define ISCCC_EVENT_LASTEVENT (ISC_EVENTCLASS_ISCCC + 65535)
+
+#endif /* ISCCC_EVENTS_H */
diff --git a/lib/isccc/include/isccc/lib.h b/lib/isccc/include/isccc/lib.h
new file mode 100644
index 0000000..408dee4
--- /dev/null
+++ b/lib/isccc/include/isccc/lib.h
@@ -0,0 +1,48 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_LIB_H
+#define ISCCC_LIB_H 1
+
+/*! \file isccc/lib.h */
+
+#include <isc/types.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+LIBISCCC_EXTERNAL_DATA extern isc_msgcat_t *isccc_msgcat;
+
+void
+isccc_lib_initmsgcat(void);
+/*%
+ * Initialize the ISCCC library's message catalog, isccc_msgcat, if it
+ * has not already been initialized.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_LIB_H */
diff --git a/lib/isccc/include/isccc/result.h b/lib/isccc/include/isccc/result.h
new file mode 100644
index 0000000..6ff81ad
--- /dev/null
+++ b/lib/isccc/include/isccc/result.h
@@ -0,0 +1,66 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_RESULT_H
+#define ISCCC_RESULT_H 1
+
+/*! \file isccc/result.h */
+
+#include <isc/lang.h>
+#include <isc/resultclass.h>
+#include <isc/result.h>
+
+#include <isccc/types.h>
+
+/*% Unknown Version */
+#define ISCCC_R_UNKNOWNVERSION (ISC_RESULTCLASS_ISCCC + 0)
+/*% Syntax Error */
+#define ISCCC_R_SYNTAX (ISC_RESULTCLASS_ISCCC + 1)
+/*% Bad Authorization */
+#define ISCCC_R_BADAUTH (ISC_RESULTCLASS_ISCCC + 2)
+/*% Expired */
+#define ISCCC_R_EXPIRED (ISC_RESULTCLASS_ISCCC + 3)
+/*% Clock Skew */
+#define ISCCC_R_CLOCKSKEW (ISC_RESULTCLASS_ISCCC + 4)
+/*% Duplicate */
+#define ISCCC_R_DUPLICATE (ISC_RESULTCLASS_ISCCC + 5)
+
+#define ISCCC_R_NRESULTS 6 /*%< Number of results */
+
+ISC_LANG_BEGINDECLS
+
+const char *
+isccc_result_totext(isc_result_t result);
+/*%
+ * Convert a isccc_result_t into a string message describing the result.
+ */
+
+void
+isccc_result_register(void);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_RESULT_H */
diff --git a/lib/isccc/include/isccc/sexpr.h b/lib/isccc/include/isccc/sexpr.h
new file mode 100644
index 0000000..10f215c
--- /dev/null
+++ b/lib/isccc/include/isccc/sexpr.h
@@ -0,0 +1,118 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_SEXPR_H
+#define ISCCC_SEXPR_H 1
+
+/*! \file isccc/sexpr.h */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isccc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% dotted pair structure */
+struct isccc_dottedpair {
+ isccc_sexpr_t *car;
+ isccc_sexpr_t *cdr;
+};
+
+/*% iscc_sexpr structure */
+struct isccc_sexpr {
+ unsigned int type;
+ union {
+ char * as_string;
+ isccc_dottedpair_t as_dottedpair;
+ isccc_region_t as_region;
+ } value;
+};
+
+#define ISCCC_SEXPRTYPE_NONE 0x00 /*%< Illegal. */
+#define ISCCC_SEXPRTYPE_T 0x01
+#define ISCCC_SEXPRTYPE_STRING 0x02
+#define ISCCC_SEXPRTYPE_DOTTEDPAIR 0x03
+#define ISCCC_SEXPRTYPE_BINARY 0x04
+
+#define ISCCC_SEXPR_CAR(s) (s)->value.as_dottedpair.car
+#define ISCCC_SEXPR_CDR(s) (s)->value.as_dottedpair.cdr
+
+isccc_sexpr_t *
+isccc_sexpr_cons(isccc_sexpr_t *car, isccc_sexpr_t *cdr);
+
+isccc_sexpr_t *
+isccc_sexpr_tconst(void);
+
+isccc_sexpr_t *
+isccc_sexpr_fromstring(const char *str);
+
+isccc_sexpr_t *
+isccc_sexpr_frombinary(const isccc_region_t *region);
+
+void
+isccc_sexpr_free(isccc_sexpr_t **sexprp);
+
+void
+isccc_sexpr_print(isccc_sexpr_t *sexpr, FILE *stream);
+
+isccc_sexpr_t *
+isccc_sexpr_car(isccc_sexpr_t *list);
+
+isccc_sexpr_t *
+isccc_sexpr_cdr(isccc_sexpr_t *list);
+
+void
+isccc_sexpr_setcar(isccc_sexpr_t *pair, isccc_sexpr_t *car);
+
+void
+isccc_sexpr_setcdr(isccc_sexpr_t *pair, isccc_sexpr_t *cdr);
+
+isccc_sexpr_t *
+isccc_sexpr_addtolist(isccc_sexpr_t **l1p, isccc_sexpr_t *l2);
+
+bool
+isccc_sexpr_listp(isccc_sexpr_t *sexpr);
+
+bool
+isccc_sexpr_emptyp(isccc_sexpr_t *sexpr);
+
+bool
+isccc_sexpr_stringp(isccc_sexpr_t *sexpr);
+
+bool
+isccc_sexpr_binaryp(isccc_sexpr_t *sexpr);
+
+char *
+isccc_sexpr_tostring(isccc_sexpr_t *sexpr);
+
+isccc_region_t *
+isccc_sexpr_tobinary(isccc_sexpr_t *sexpr);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_SEXPR_H */
diff --git a/lib/isccc/include/isccc/symtab.h b/lib/isccc/include/isccc/symtab.h
new file mode 100644
index 0000000..cd595a1
--- /dev/null
+++ b/lib/isccc/include/isccc/symtab.h
@@ -0,0 +1,130 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_SYMTAB_H
+#define ISCCC_SYMTAB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isccc/symtab.h
+ * \brief
+ * Provides a simple memory-based symbol table.
+ *
+ * Keys are C strings. A type may be specified when looking up,
+ * defining, or undefining. A type value of 0 means "match any type";
+ * any other value will only match the given type.
+ *
+ * It's possible that a client will attempt to define a <key, type,
+ * value> tuple when a tuple with the given key and type already
+ * exists in the table. What to do in this case is specified by the
+ * client. Possible policies are:
+ *
+ *\li isccc_symexists_reject Disallow the define, returning #ISC_R_EXISTS
+ *\li isccc_symexists_replace Replace the old value with the new. The
+ * undefine action (if provided) will be called
+ * with the old <key, type, value> tuple.
+ *\li isccc_symexists_add Add the new tuple, leaving the old tuple in
+ * the table. Subsequent lookups will retrieve
+ * the most-recently-defined tuple.
+ *
+ * A lookup of a key using type 0 will return the most-recently
+ * defined symbol with that key. An undefine of a key using type 0
+ * will undefine the most-recently defined symbol with that key.
+ * Trying to define a key with type 0 is illegal.
+ *
+ * The symbol table library does not make a copy the key field, so the
+ * caller must ensure that any key it passes to isccc_symtab_define()
+ * will not change until it calls isccc_symtab_undefine() or
+ * isccc_symtab_destroy().
+ *
+ * A user-specified action will be called (if provided) when a symbol
+ * is undefined. It can be used to free memory associated with keys
+ * and/or values.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isccc/types.h>
+
+/***
+ *** Symbol Tables.
+ ***/
+
+typedef union isccc_symvalue {
+ void * as_pointer;
+ int as_integer;
+ unsigned int as_uinteger;
+} isccc_symvalue_t;
+
+typedef void (*isccc_symtabundefaction_t)(char *key, unsigned int type,
+ isccc_symvalue_t value, void *userarg);
+
+typedef bool (*isccc_symtabforeachaction_t)(char *key,
+ unsigned int type,
+ isccc_symvalue_t value,
+ void *userarg);
+
+typedef enum {
+ isccc_symexists_reject = 0,
+ isccc_symexists_replace = 1,
+ isccc_symexists_add = 2
+} isccc_symexists_t;
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isccc_symtab_create(unsigned int size,
+ isccc_symtabundefaction_t undefine_action, void *undefine_arg,
+ bool case_sensitive, isccc_symtab_t **symtabp);
+
+void
+isccc_symtab_destroy(isccc_symtab_t **symtabp);
+
+isc_result_t
+isccc_symtab_lookup(isccc_symtab_t *symtab, const char *key, unsigned int type,
+ isccc_symvalue_t *value);
+
+isc_result_t
+isccc_symtab_define(isccc_symtab_t *symtab, char *key, unsigned int type,
+ isccc_symvalue_t value, isccc_symexists_t exists_policy);
+
+isc_result_t
+isccc_symtab_undefine(isccc_symtab_t *symtab, const char *key, unsigned int type);
+
+void
+isccc_symtab_foreach(isccc_symtab_t *symtab, isccc_symtabforeachaction_t action,
+ void *arg);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_SYMTAB_H */
diff --git a/lib/isccc/include/isccc/symtype.h b/lib/isccc/include/isccc/symtype.h
new file mode 100644
index 0000000..dbd9ad7
--- /dev/null
+++ b/lib/isccc/include/isccc/symtype.h
@@ -0,0 +1,37 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_SYMTYPE_H
+#define ISCCC_SYMTYPE_H 1
+
+/*! \file isccc/symtype.h */
+
+#define ISCCC_SYMTYPE_ZONESTATS 0x0001
+#define ISCCC_SYMTYPE_CCDUP 0x0002
+#define ISCCC_SYMTYPE_TELLSERVICE 0x0003
+#define ISCCC_SYMTYPE_TELLRESPONSE 0x0004
+
+#endif /* ISCCC_SYMTYPE_H */
diff --git a/lib/isccc/include/isccc/types.h b/lib/isccc/include/isccc/types.h
new file mode 100644
index 0000000..bea22c9
--- /dev/null
+++ b/lib/isccc/include/isccc/types.h
@@ -0,0 +1,52 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_TYPES_H
+#define ISCCC_TYPES_H 1
+
+/*! \file isccc/types.h */
+
+#include <inttypes.h>
+
+#include <isc/result.h>
+
+/*% isccc_time_t typedef */
+typedef uint32_t isccc_time_t;
+
+/*% isccc_sexpr_t typedef */
+typedef struct isccc_sexpr isccc_sexpr_t;
+/*% isccc_dottedpair_t typedef */
+typedef struct isccc_dottedpair isccc_dottedpair_t;
+/*% isccc_symtab_t typedef */
+typedef struct isccc_symtab isccc_symtab_t;
+
+/*% iscc region structure */
+typedef struct isccc_region {
+ unsigned char * rstart;
+ unsigned char * rend;
+} isccc_region_t;
+
+#endif /* ISCCC_TYPES_H */
diff --git a/lib/isccc/include/isccc/util.h b/lib/isccc/include/isccc/util.h
new file mode 100644
index 0000000..58e69b3
--- /dev/null
+++ b/lib/isccc/include/isccc/util.h
@@ -0,0 +1,220 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef ISCCC_UTIL_H
+#define ISCCC_UTIL_H 1
+
+#include <inttypes.h>
+
+#include <isc/util.h>
+
+/*! \file isccc/util.h
+ * \brief
+ * Macros for dealing with unaligned numbers.
+ *
+ * \note no side effects are allowed when invoking these macros!
+ */
+
+#define GET8(v, w) \
+ do { \
+ v = *w; \
+ w++; \
+ } while (0)
+
+#define GET16(v, w) \
+ do { \
+ v = (unsigned int)w[0] << 8; \
+ v |= (unsigned int)w[1]; \
+ w += 2; \
+ } while (0)
+
+#define GET24(v, w) \
+ do { \
+ v = (unsigned int)w[0] << 16; \
+ v |= (unsigned int)w[1] << 8; \
+ v |= (unsigned int)w[2]; \
+ w += 3; \
+ } while (0)
+
+#define GET32(v, w) \
+ do { \
+ v = (unsigned int)w[0] << 24; \
+ v |= (unsigned int)w[1] << 16; \
+ v |= (unsigned int)w[2] << 8; \
+ v |= (unsigned int)w[3]; \
+ w += 4; \
+ } while (0)
+
+#define GET64(v, w) \
+ do { \
+ v = (uint64_t)w[0] << 56; \
+ v |= (uint64_t)w[1] << 48; \
+ v |= (uint64_t)w[2] << 40; \
+ v |= (uint64_t)w[3] << 32; \
+ v |= (uint64_t)w[4] << 24; \
+ v |= (uint64_t)w[5] << 16; \
+ v |= (uint64_t)w[6] << 8; \
+ v |= (uint64_t)w[7]; \
+ w += 8; \
+ } while (0)
+
+#define GETC16(v, w, d) \
+ do { \
+ GET8(v, w); \
+ if (v == 0) \
+ d = ISCCC_TRUE; \
+ else { \
+ d = ISCCC_FALSE; \
+ if (v == 255) \
+ GET16(v, w); \
+ } \
+ } while (0)
+
+#define GETC32(v, w) \
+ do { \
+ GET24(v, w); \
+ if (v == 0xffffffu) \
+ GET32(v, w); \
+ } while (0)
+
+#define GET_OFFSET(v, w) GET32(v, w)
+
+#define GET_MEM(v, c, w) \
+ do { \
+ memmove(v, w, c); \
+ w += c; \
+ } while (0)
+
+#define GET_TYPE(v, w) \
+ do { \
+ GET8(v, w); \
+ if (v > 127) { \
+ if (v < 255) \
+ v = ((v & 0x7f) << 16) | ISCCC_RDATATYPE_SIG; \
+ else \
+ GET32(v, w); \
+ } \
+ } while (0)
+
+#define PUT8(v, w) \
+ do { \
+ *w = (v & 0x000000ffU); \
+ w++; \
+ } while (0)
+
+#define PUT16(v, w) \
+ do { \
+ w[0] = (v & 0x0000ff00U) >> 8; \
+ w[1] = (v & 0x000000ffU); \
+ w += 2; \
+ } while (0)
+
+#define PUT24(v, w) \
+ do { \
+ w[0] = (v & 0x00ff0000U) >> 16; \
+ w[1] = (v & 0x0000ff00U) >> 8; \
+ w[2] = (v & 0x000000ffU); \
+ w += 3; \
+ } while (0)
+
+#define PUT32(v, w) \
+ do { \
+ w[0] = (v & 0xff000000U) >> 24; \
+ w[1] = (v & 0x00ff0000U) >> 16; \
+ w[2] = (v & 0x0000ff00U) >> 8; \
+ w[3] = (v & 0x000000ffU); \
+ w += 4; \
+ } while (0)
+
+#define PUT64(v, w) \
+ do { \
+ w[0] = (v & 0xff00000000000000ULL) >> 56; \
+ w[1] = (v & 0x00ff000000000000ULL) >> 48; \
+ w[2] = (v & 0x0000ff0000000000ULL) >> 40; \
+ w[3] = (v & 0x000000ff00000000ULL) >> 32; \
+ w[4] = (v & 0x00000000ff000000ULL) >> 24; \
+ w[5] = (v & 0x0000000000ff0000ULL) >> 16; \
+ w[6] = (v & 0x000000000000ff00ULL) >> 8; \
+ w[7] = (v & 0x00000000000000ffULL); \
+ w += 8; \
+ } while (0)
+
+#define PUTC16(v, w) \
+ do { \
+ if (v > 0 && v < 255) \
+ PUT8(v, w); \
+ else { \
+ PUT8(255, w); \
+ PUT16(v, w); \
+ } \
+ } while (0)
+
+#define PUTC32(v, w) \
+ do { \
+ if (v < 0xffffffU) \
+ PUT24(v, w); \
+ else { \
+ PUT24(0xffffffU, w); \
+ PUT32(v, w); \
+ } \
+ } while (0)
+
+#define PUT_OFFSET(v, w) PUT32(v, w)
+
+#include <string.h>
+
+#define PUT_MEM(s, c, w) \
+ do { \
+ memmove(w, s, c); \
+ w += c; \
+ } while (0)
+
+/*
+ * Regions.
+ */
+#define REGION_SIZE(r) ((unsigned int)((r).rend - (r).rstart))
+#define REGION_EMPTY(r) ((r).rstart == (r).rend)
+#define REGION_FROMSTRING(r, s) do { \
+ (r).rstart = (unsigned char *)s; \
+ (r).rend = (r).rstart + strlen(s); \
+} while (0)
+
+/*%
+ * Use this to remove the const qualifier of a variable to assign it to
+ * a non-const variable or pass it as a non-const function argument ...
+ * but only when you are sure it won't then be changed!
+ * This is necessary to sometimes shut up some compilers
+ * (as with gcc -Wcast-qual) when there is just no other good way to avoid the
+ * situation.
+ */
+#define DE_CONST(konst, var) \
+ do { \
+ union { const void *k; void *v; } _u; \
+ _u.k = konst; \
+ var = _u.v; \
+ } while (0)
+
+#endif /* ISCCC_UTIL_H */
diff --git a/lib/isccc/include/isccc/version.h b/lib/isccc/include/isccc/version.h
new file mode 100644
index 0000000..dcb352f
--- /dev/null
+++ b/lib/isccc/include/isccc/version.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file isccc/version.h */
+
+#include <isc/platform.h>
+
+LIBISCCC_EXTERNAL_DATA extern const char isccc_version[];
+
+LIBISCCC_EXTERNAL_DATA extern const unsigned int isccc_libinterface;
+LIBISCCC_EXTERNAL_DATA extern const unsigned int isccc_librevision;
+LIBISCCC_EXTERNAL_DATA extern const unsigned int isccc_libage;
diff --git a/lib/isccc/lib.c b/lib/isccc/lib.c
new file mode 100644
index 0000000..1222bbe
--- /dev/null
+++ b/lib/isccc/lib.c
@@ -0,0 +1,71 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/once.h>
+#include <isc/msgcat.h>
+#include <isc/util.h>
+
+#include <isccc/lib.h>
+
+/***
+ *** Globals
+ ***/
+
+LIBISCCC_EXTERNAL_DATA isc_msgcat_t * isccc_msgcat = NULL;
+
+
+/***
+ *** Private
+ ***/
+
+static isc_once_t msgcat_once = ISC_ONCE_INIT;
+
+
+/***
+ *** Functions
+ ***/
+
+static void
+open_msgcat(void) {
+ isc_msgcat_open("libisccc.cat", &isccc_msgcat);
+}
+
+void
+isccc_lib_initmsgcat(void) {
+
+ /*
+ * Initialize the DNS library's message catalog, isccc_msgcat, if it
+ * has not already been initialized.
+ */
+
+ RUNTIME_CHECK(isc_once_do(&msgcat_once, open_msgcat) == ISC_R_SUCCESS);
+}
diff --git a/lib/isccc/result.c b/lib/isccc/result.c
new file mode 100644
index 0000000..75f5ade
--- /dev/null
+++ b/lib/isccc/result.c
@@ -0,0 +1,94 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/once.h>
+#include <isc/util.h>
+
+#include <isccc/result.h>
+#include <isccc/lib.h>
+
+static const char *text[ISCCC_R_NRESULTS] = {
+ "unknown version", /* 1 */
+ "syntax error", /* 2 */
+ "bad auth", /* 3 */
+ "expired", /* 4 */
+ "clock skew", /* 5 */
+ "duplicate" /* 6 */
+};
+
+static const char *ids[ISCCC_R_NRESULTS] = {
+ "ISCCC_R_UNKNOWNVERSION",
+ "ISCCC_R_SYNTAX",
+ "ISCCC_R_BADAUTH",
+ "ISCCC_R_EXPIRED",
+ "ISCCC_R_CLOCKSKEW",
+ "ISCCC_R_DUPLICATE",
+};
+
+#define ISCCC_RESULT_RESULTSET 2
+
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+initialize_action(void) {
+ isc_result_t result;
+
+ result = isc_result_register(ISC_RESULTCLASS_ISCCC, ISCCC_R_NRESULTS,
+ text, isccc_msgcat,
+ ISCCC_RESULT_RESULTSET);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_result_register() failed: %u", result);
+
+ result = isc_result_registerids(ISC_RESULTCLASS_ISCCC, ISCCC_R_NRESULTS,
+ ids, isccc_msgcat,
+ ISCCC_RESULT_RESULTSET);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_result_registerids() failed: %u", result);
+}
+
+static void
+initialize(void) {
+ isccc_lib_initmsgcat();
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+const char *
+isccc_result_totext(isc_result_t result) {
+ initialize();
+
+ return (isc_result_totext(result));
+}
+
+void
+isccc_result_register(void) {
+ initialize();
+}
diff --git a/lib/isccc/sexpr.c b/lib/isccc/sexpr.c
new file mode 100644
index 0000000..68dbe44
--- /dev/null
+++ b/lib/isccc/sexpr.c
@@ -0,0 +1,301 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/assertions.h>
+#include <isc/print.h>
+#include <isccc/sexpr.h>
+#include <isccc/util.h>
+
+static isccc_sexpr_t sexpr_t = { ISCCC_SEXPRTYPE_T, { NULL } };
+
+#define CAR(s) (s)->value.as_dottedpair.car
+#define CDR(s) (s)->value.as_dottedpair.cdr
+
+isccc_sexpr_t *
+isccc_sexpr_cons(isccc_sexpr_t *car, isccc_sexpr_t *cdr) {
+ isccc_sexpr_t *sexpr;
+
+ sexpr = malloc(sizeof(*sexpr));
+ if (sexpr == NULL)
+ return (NULL);
+ sexpr->type = ISCCC_SEXPRTYPE_DOTTEDPAIR;
+ CAR(sexpr) = car;
+ CDR(sexpr) = cdr;
+
+ return (sexpr);
+}
+
+isccc_sexpr_t *
+isccc_sexpr_tconst(void) {
+ return (&sexpr_t);
+}
+
+isccc_sexpr_t *
+isccc_sexpr_fromstring(const char *str) {
+ isccc_sexpr_t *sexpr;
+
+ sexpr = malloc(sizeof(*sexpr));
+ if (sexpr == NULL)
+ return (NULL);
+ sexpr->type = ISCCC_SEXPRTYPE_STRING;
+ sexpr->value.as_string = strdup(str);
+ if (sexpr->value.as_string == NULL) {
+ free(sexpr);
+ return (NULL);
+ }
+
+ return (sexpr);
+}
+
+isccc_sexpr_t *
+isccc_sexpr_frombinary(const isccc_region_t *region) {
+ isccc_sexpr_t *sexpr;
+ unsigned int region_size;
+
+ sexpr = malloc(sizeof(*sexpr));
+ if (sexpr == NULL)
+ return (NULL);
+ sexpr->type = ISCCC_SEXPRTYPE_BINARY;
+ region_size = REGION_SIZE(*region);
+ /*
+ * We add an extra byte when we malloc so we can NUL terminate
+ * the binary data. This allows the caller to use it as a C
+ * string. It's up to the caller to ensure this is safe. We don't
+ * add 1 to the length of the binary region, because the NUL is
+ * not part of the binary data.
+ */
+ sexpr->value.as_region.rstart = malloc(region_size + 1);
+ if (sexpr->value.as_region.rstart == NULL) {
+ free(sexpr);
+ return (NULL);
+ }
+ sexpr->value.as_region.rend = sexpr->value.as_region.rstart +
+ region_size;
+ memmove(sexpr->value.as_region.rstart, region->rstart, region_size);
+ /*
+ * NUL terminate.
+ */
+ sexpr->value.as_region.rstart[region_size] = '\0';
+
+ return (sexpr);
+}
+
+void
+isccc_sexpr_free(isccc_sexpr_t **sexprp) {
+ isccc_sexpr_t *sexpr;
+ isccc_sexpr_t *item;
+
+ sexpr = *sexprp;
+ if (sexpr == NULL)
+ return;
+ switch (sexpr->type) {
+ case ISCCC_SEXPRTYPE_STRING:
+ free(sexpr->value.as_string);
+ break;
+ case ISCCC_SEXPRTYPE_DOTTEDPAIR:
+ item = CAR(sexpr);
+ if (item != NULL)
+ isccc_sexpr_free(&item);
+ item = CDR(sexpr);
+ if (item != NULL)
+ isccc_sexpr_free(&item);
+ break;
+ case ISCCC_SEXPRTYPE_BINARY:
+ free(sexpr->value.as_region.rstart);
+ break;
+ }
+ free(sexpr);
+
+ *sexprp = NULL;
+}
+
+static bool
+printable(isccc_region_t *r) {
+ unsigned char *curr;
+
+ curr = r->rstart;
+ while (curr != r->rend) {
+ if (!isprint(*curr))
+ return (false);
+ curr++;
+ }
+
+ return (true);
+}
+
+void
+isccc_sexpr_print(isccc_sexpr_t *sexpr, FILE *stream) {
+ isccc_sexpr_t *cdr;
+ unsigned int size, i;
+ unsigned char *curr;
+
+ if (sexpr == NULL) {
+ fprintf(stream, "nil");
+ return;
+ }
+
+ switch (sexpr->type) {
+ case ISCCC_SEXPRTYPE_T:
+ fprintf(stream, "t");
+ break;
+ case ISCCC_SEXPRTYPE_STRING:
+ fprintf(stream, "\"%s\"", sexpr->value.as_string);
+ break;
+ case ISCCC_SEXPRTYPE_DOTTEDPAIR:
+ fprintf(stream, "(");
+ do {
+ isccc_sexpr_print(CAR(sexpr), stream);
+ cdr = CDR(sexpr);
+ if (cdr != NULL) {
+ fprintf(stream, " ");
+ if (cdr->type != ISCCC_SEXPRTYPE_DOTTEDPAIR) {
+ fprintf(stream, ". ");
+ isccc_sexpr_print(cdr, stream);
+ cdr = NULL;
+ }
+ }
+ sexpr = cdr;
+ } while (sexpr != NULL);
+ fprintf(stream, ")");
+ break;
+ case ISCCC_SEXPRTYPE_BINARY:
+ size = REGION_SIZE(sexpr->value.as_region);
+ curr = sexpr->value.as_region.rstart;
+ if (printable(&sexpr->value.as_region)) {
+ fprintf(stream, "'%.*s'", (int)size, curr);
+ } else {
+ fprintf(stream, "0x");
+ for (i = 0; i < size; i++)
+ fprintf(stream, "%02x", *curr++);
+ }
+ break;
+ default:
+ INSIST(0);
+ }
+}
+
+isccc_sexpr_t *
+isccc_sexpr_car(isccc_sexpr_t *list) {
+ REQUIRE(list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+
+ return (CAR(list));
+}
+
+isccc_sexpr_t *
+isccc_sexpr_cdr(isccc_sexpr_t *list) {
+ REQUIRE(list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+
+ return (CDR(list));
+}
+
+void
+isccc_sexpr_setcar(isccc_sexpr_t *pair, isccc_sexpr_t *car) {
+ REQUIRE(pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+
+ CAR(pair) = car;
+}
+
+void
+isccc_sexpr_setcdr(isccc_sexpr_t *pair, isccc_sexpr_t *cdr) {
+ REQUIRE(pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+
+ CDR(pair) = cdr;
+}
+
+isccc_sexpr_t *
+isccc_sexpr_addtolist(isccc_sexpr_t **l1p, isccc_sexpr_t *l2) {
+ isccc_sexpr_t *last, *elt, *l1;
+
+ REQUIRE(l1p != NULL);
+ l1 = *l1p;
+ REQUIRE(l1 == NULL || l1->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+
+ elt = isccc_sexpr_cons(l2, NULL);
+ if (elt == NULL)
+ return (NULL);
+ if (l1 == NULL) {
+ *l1p = elt;
+ return (elt);
+ }
+ for (last = l1; CDR(last) != NULL; last = CDR(last))
+ /* Nothing */;
+ CDR(last) = elt;
+
+ return (elt);
+}
+
+bool
+isccc_sexpr_listp(isccc_sexpr_t *sexpr) {
+ if (sexpr == NULL || sexpr->type == ISCCC_SEXPRTYPE_DOTTEDPAIR)
+ return (true);
+ return (false);
+}
+
+bool
+isccc_sexpr_emptyp(isccc_sexpr_t *sexpr) {
+ if (sexpr == NULL)
+ return (true);
+ return (false);
+}
+
+bool
+isccc_sexpr_stringp(isccc_sexpr_t *sexpr) {
+ if (sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_STRING)
+ return (true);
+ return (false);
+}
+
+bool
+isccc_sexpr_binaryp(isccc_sexpr_t *sexpr) {
+ if (sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_BINARY)
+ return (true);
+ return (false);
+}
+
+char *
+isccc_sexpr_tostring(isccc_sexpr_t *sexpr) {
+ REQUIRE(sexpr != NULL &&
+ (sexpr->type == ISCCC_SEXPRTYPE_STRING ||
+ sexpr->type == ISCCC_SEXPRTYPE_BINARY));
+
+ if (sexpr->type == ISCCC_SEXPRTYPE_BINARY)
+ return ((char *)sexpr->value.as_region.rstart);
+ return (sexpr->value.as_string);
+}
+
+isccc_region_t *
+isccc_sexpr_tobinary(isccc_sexpr_t *sexpr) {
+ REQUIRE(sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_BINARY);
+ return (&sexpr->value.as_region);
+}
diff --git a/lib/isccc/symtab.c b/lib/isccc/symtab.c
new file mode 100644
index 0000000..da59a78
--- /dev/null
+++ b/lib/isccc/symtab.c
@@ -0,0 +1,287 @@
+/*
+ * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/assertions.h>
+#include <isc/magic.h>
+#include <isc/string.h>
+
+#include <isccc/result.h>
+#include <isccc/symtab.h>
+#include <isccc/util.h>
+
+typedef struct elt {
+ char * key;
+ unsigned int type;
+ isccc_symvalue_t value;
+ ISC_LINK(struct elt) link;
+} elt_t;
+
+typedef ISC_LIST(elt_t) eltlist_t;
+
+#define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
+#define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
+
+struct isccc_symtab {
+ unsigned int magic;
+ unsigned int size;
+ eltlist_t * table;
+ isccc_symtabundefaction_t undefine_action;
+ void * undefine_arg;
+ bool case_sensitive;
+};
+
+isc_result_t
+isccc_symtab_create(unsigned int size,
+ isccc_symtabundefaction_t undefine_action,
+ void *undefine_arg,
+ bool case_sensitive,
+ isccc_symtab_t **symtabp)
+{
+ isccc_symtab_t *symtab;
+ unsigned int i;
+
+ REQUIRE(symtabp != NULL && *symtabp == NULL);
+ REQUIRE(size > 0); /* Should be prime. */
+
+ symtab = malloc(sizeof(*symtab));
+ if (symtab == NULL)
+ return (ISC_R_NOMEMORY);
+ symtab->table = malloc(size * sizeof(eltlist_t));
+ if (symtab->table == NULL) {
+ free(symtab);
+ return (ISC_R_NOMEMORY);
+ }
+ for (i = 0; i < size; i++)
+ ISC_LIST_INIT(symtab->table[i]);
+ symtab->size = size;
+ symtab->undefine_action = undefine_action;
+ symtab->undefine_arg = undefine_arg;
+ symtab->case_sensitive = case_sensitive;
+ symtab->magic = SYMTAB_MAGIC;
+
+ *symtabp = symtab;
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+free_elt(isccc_symtab_t *symtab, unsigned int bucket, elt_t *elt) {
+ ISC_LIST_UNLINK(symtab->table[bucket], elt, link);
+ if (symtab->undefine_action != NULL)
+ (symtab->undefine_action)(elt->key, elt->type, elt->value,
+ symtab->undefine_arg);
+ free(elt);
+}
+
+void
+isccc_symtab_destroy(isccc_symtab_t **symtabp) {
+ isccc_symtab_t *symtab;
+ unsigned int i;
+ elt_t *elt, *nelt;
+
+ REQUIRE(symtabp != NULL);
+ symtab = *symtabp;
+ REQUIRE(VALID_SYMTAB(symtab));
+
+ for (i = 0; i < symtab->size; i++) {
+ for (elt = ISC_LIST_HEAD(symtab->table[i]);
+ elt != NULL;
+ elt = nelt) {
+ nelt = ISC_LIST_NEXT(elt, link);
+ free_elt(symtab, i, elt);
+ }
+ }
+ free(symtab->table);
+ symtab->magic = 0;
+ free(symtab);
+
+ *symtabp = NULL;
+}
+
+static inline unsigned int
+hash(const char *key, bool case_sensitive) {
+ const char *s;
+ unsigned int h = 0;
+ unsigned int g;
+ int c;
+
+ /*
+ * P. J. Weinberger's hash function, adapted from p. 436 of
+ * _Compilers: Principles, Techniques, and Tools_, Aho, Sethi
+ * and Ullman, Addison-Wesley, 1986, ISBN 0-201-10088-6.
+ */
+
+ if (case_sensitive) {
+ for (s = key; *s != '\0'; s++) {
+ h = ( h << 4 ) + *s;
+ if ((g = ( h & 0xf0000000 )) != 0) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ } else {
+ for (s = key; *s != '\0'; s++) {
+ c = *s;
+ c = tolower((unsigned char)c);
+ h = ( h << 4 ) + c;
+ if ((g = ( h & 0xf0000000 )) != 0) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ }
+
+ return (h);
+}
+
+#define FIND(s, k, t, b, e) \
+ b = hash((k), (s)->case_sensitive) % (s)->size; \
+ if ((s)->case_sensitive) { \
+ for (e = ISC_LIST_HEAD((s)->table[b]); \
+ e != NULL; \
+ e = ISC_LIST_NEXT(e, link)) { \
+ if (((t) == 0 || e->type == (t)) && \
+ strcmp(e->key, (k)) == 0) \
+ break; \
+ } \
+ } else { \
+ for (e = ISC_LIST_HEAD((s)->table[b]); \
+ e != NULL; \
+ e = ISC_LIST_NEXT(e, link)) { \
+ if (((t) == 0 || e->type == (t)) && \
+ strcasecmp(e->key, (k)) == 0) \
+ break; \
+ } \
+ }
+
+isc_result_t
+isccc_symtab_lookup(isccc_symtab_t *symtab, const char *key, unsigned int type,
+ isccc_symvalue_t *value)
+{
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (elt == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (value != NULL)
+ *value = elt->value;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isccc_symtab_define(isccc_symtab_t *symtab, char *key, unsigned int type,
+ isccc_symvalue_t value, isccc_symexists_t exists_policy)
+{
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+ REQUIRE(type != 0);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (exists_policy != isccc_symexists_add && elt != NULL) {
+ if (exists_policy == isccc_symexists_reject)
+ return (ISC_R_EXISTS);
+ INSIST(exists_policy == isccc_symexists_replace);
+ ISC_LIST_UNLINK(symtab->table[bucket], elt, link);
+ if (symtab->undefine_action != NULL)
+ (symtab->undefine_action)(elt->key, elt->type,
+ elt->value,
+ symtab->undefine_arg);
+ } else {
+ elt = malloc(sizeof(*elt));
+ if (elt == NULL)
+ return (ISC_R_NOMEMORY);
+ ISC_LINK_INIT(elt, link);
+ }
+
+ elt->key = key;
+ elt->type = type;
+ elt->value = value;
+
+ /*
+ * We prepend so that the most recent definition will be found.
+ */
+ ISC_LIST_PREPEND(symtab->table[bucket], elt, link);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isccc_symtab_undefine(isccc_symtab_t *symtab, const char *key, unsigned int type) {
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (elt == NULL)
+ return (ISC_R_NOTFOUND);
+
+ free_elt(symtab, bucket, elt);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isccc_symtab_foreach(isccc_symtab_t *symtab, isccc_symtabforeachaction_t action,
+ void *arg)
+{
+ unsigned int i;
+ elt_t *elt, *nelt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(action != NULL);
+
+ for (i = 0; i < symtab->size; i++) {
+ for (elt = ISC_LIST_HEAD(symtab->table[i]);
+ elt != NULL;
+ elt = nelt) {
+ nelt = ISC_LIST_NEXT(elt, link);
+ if ((action)(elt->key, elt->type, elt->value, arg))
+ free_elt(symtab, i, elt);
+ }
+ }
+}
diff --git a/lib/isccc/version.c b/lib/isccc/version.c
new file mode 100644
index 0000000..a3c1d9b
--- /dev/null
+++ b/lib/isccc/version.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <isccc/version.h>
+
+const char isccc_version[] = VERSION;
+
+const unsigned int isccc_libinterface = LIBINTERFACE;
+const unsigned int isccc_librevision = LIBREVISION;
+const unsigned int isccc_libage = LIBAGE;
diff --git a/lib/isccc/win32/DLLMain.c b/lib/isccc/win32/DLLMain.c
new file mode 100644
index 0000000..8ff1017
--- /dev/null
+++ b/lib/isccc/win32/DLLMain.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <windows.h>
+#include <signal.h>
+
+/*
+ * Called when we enter the DLL
+ */
+__declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL,
+ DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason) {
+ /*
+ * The DLL is loading due to process
+ * initialization or a call to LoadLibrary.
+ */
+ case DLL_PROCESS_ATTACH:
+ break;
+
+ /* The attached process creates a new thread. */
+ case DLL_THREAD_ATTACH:
+ break;
+
+ /* The thread of the attached process terminates. */
+ case DLL_THREAD_DETACH:
+ break;
+
+ /*
+ * The DLL is unloading from a process due to
+ * process termination or a call to FreeLibrary.
+ */
+ case DLL_PROCESS_DETACH:
+ break;
+
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
diff --git a/lib/isccc/win32/libisccc.def b/lib/isccc/win32/libisccc.def
new file mode 100644
index 0000000..7a06b9a
--- /dev/null
+++ b/lib/isccc/win32/libisccc.def
@@ -0,0 +1,70 @@
+LIBRARY libisccc
+
+; Exported Functions
+EXPORTS
+
+isccc_alist_create
+isccc_alist_alistp
+isccc_alist_emptyp
+isccc_alist_first
+isccc_alist_assq
+isccc_alist_delete
+isccc_alist_define
+isccc_alist_definestring
+isccc_alist_definebinary
+isccc_alist_lookup
+isccc_alist_lookupstring
+isccc_alist_lookupbinary
+isccc_alist_prettyprint
+isccc_base64_encode
+isccc_base64_decode
+isccc_cc_towire
+isccc_cc_fromwire
+isccc_cc_createmessage
+isccc_cc_createack
+isccc_cc_isack
+isccc_cc_isreply
+isccc_cc_createresponse
+isccc_cc_definestring
+isccc_cc_defineuint32
+isccc_cc_lookupstring
+isccc_cc_lookupuint32
+isccc_cc_createsymtab
+isccc_cc_cleansymtab
+isccc_cc_checkdup
+isccc_ccmsg_init
+isccc_ccmsg_setmaxsize
+isccc_ccmsg_readmessage
+isccc_ccmsg_cancelread
+isccc_ccmsg_invalidate
+isccc_lib_initmsgcat
+isccc_result_totext
+isccc_result_register
+isccc_sexpr_cons
+isccc_sexpr_tconst
+isccc_sexpr_fromstring
+isccc_sexpr_frombinary
+isccc_sexpr_free
+isccc_sexpr_print
+isccc_sexpr_car
+isccc_sexpr_cdr
+isccc_sexpr_setcar
+isccc_sexpr_setcdr
+isccc_sexpr_addtolist
+isccc_sexpr_listp
+isccc_sexpr_emptyp
+isccc_sexpr_stringp
+isccc_sexpr_binaryp
+isccc_sexpr_tostring
+isccc_sexpr_tobinary
+isccc_symtab_destroy
+isccc_symtab_create
+isccc_symtab_destroy
+isccc_symtab_lookup
+isccc_symtab_define
+isccc_symtab_undefine
+isccc_symtab_foreach
+
+; Exported Data
+
+;isccc_msgcat
diff --git a/lib/isccc/win32/libisccc.dsp.in b/lib/isccc/win32/libisccc.dsp.in
new file mode 100644
index 0000000..82c731e
--- /dev/null
+++ b/lib/isccc/win32/libisccc.dsp.in
@@ -0,0 +1,201 @@
+# Microsoft Developer Studio Project File - Name="libisccc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "@PLATFORM@ (x86) Dynamic-Link Library" 0x0102
+
+CFG=libisccc - @PLATFORM@ Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libisccc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libisccc.mak" CFG="libisccc - @PLATFORM@ Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libisccc - @PLATFORM@ Release" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE "libisccc - @PLATFORM@ Debug" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 @COPTX@ @COPTI@ /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "libisccc_EXPORTS" @COPTY@ /FD /c
+# ADD CPP /nologo /MD /W3 @COPTX@ @COPTI@ /O2 /I "./" /I "../../../" @LIBXML2_INC@ @OPENSSL_INC@ /I "include" /I "../include" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/dns/win32/include" /I "../../../lib/dns/include" /I "../../../lib/isc/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "USE_MD5" @CRYPTO@ /D "LIBISCCC_EXPORTS" @COPTY@ /FD /c
+# SUBTRACT CPP /X
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll @MACHINE@
+# ADD LINK32 user32.lib advapi32.lib ws2_32.lib ../../isc/win32/Release/libisc.lib /nologo /dll @MACHINE@ /out:"../../../Build/Release/libisccc.dll"
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "libisccc_EXPORTS" @COPTY@ /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /I "./" /I "../../../" @LIBXML2_INC@ @OPENSSL_INC@ /I "include" /I "../include" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/dns/win32/include" /I "../../../lib/dns/include" /I "../../../lib/isc/include" /D "_DEBUG" /D "WIN32" /D "__STDC__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "USE_MD5" @CRYPTO@ /D "LIBISCCC_EXPORTS" /FR @COPTY@ /FD /GZ /c
+# SUBTRACT CPP /X
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug @MACHINE@ /pdbtype:sept
+# ADD LINK32 user32.lib advapi32.lib ws2_32.lib ../../isc/win32/debug/libisc.lib /nologo /dll /debug @MACHINE@ /out:"../../../Build/Debug/libisccc.dll" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "libisccc - @PLATFORM@ Release"
+# Name "libisccc - @PLATFORM@ Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\alist.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\base64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\cc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ccmsg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\DLLMain.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\result.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\sexpr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\symtab.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\version.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\include\isccc\alist.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\base64.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\cc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\ccmsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\events.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\lib.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\result.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\sexpr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\symtab.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\symtype.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\types.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\util.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccc\version.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=.\libisccc.def
+# End Source File
+# End Target
+# End Project
diff --git a/lib/isccc/win32/libisccc.dsw b/lib/isccc/win32/libisccc.dsw
new file mode 100644
index 0000000..28eaa74
--- /dev/null
+++ b/lib/isccc/win32/libisccc.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "libisccc"=.\libisccc.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lib/isccc/win32/libisccc.mak.in b/lib/isccc/win32/libisccc.mak.in
new file mode 100644
index 0000000..d6512d3
--- /dev/null
+++ b/lib/isccc/win32/libisccc.mak.in
@@ -0,0 +1,540 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on libisccc.dsp
+!IF "$(CFG)" == ""
+CFG=libisccc - @PLATFORM@ Release
+!MESSAGE No configuration specified. Defaulting to libisccc - @PLATFORM@ Release.
+!ENDIF
+
+!IF "$(CFG)" != "libisccc - @PLATFORM@ Release" && "$(CFG)" != "libisccc - @PLATFORM@ Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libisccc.mak" CFG="libisccc - @PLATFORM@ Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libisccc - @PLATFORM@ Release" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE "libisccc - @PLATFORM@ Debug" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+_VC_MANIFEST_INC=0
+_VC_MANIFEST_BASENAME=__VC80
+!ELSE
+_VC_MANIFEST_INC=1
+_VC_MANIFEST_BASENAME=__VC80.Debug
+!ENDIF
+
+####################################################
+# Specifying name of temporary resource file used only in incremental builds:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res
+!else
+_VC_MANIFEST_AUTO_RES=
+!endif
+
+####################################################
+# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+#MT_SPECIAL_RETURN=1090650113
+#MT_SPECIAL_SWITCH=-notify_resource_update
+MT_SPECIAL_RETURN=0
+MT_SPECIAL_SWITCH=
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
+if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
+rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
+link $** /out:$@ $(LFLAGS)
+
+!else
+
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1
+
+!endif
+
+####################################################
+# _VC_MANIFEST_EMBED_DLL - command to embed manifest in DLL:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+#MT_SPECIAL_RETURN=1090650113
+#MT_SPECIAL_SWITCH=-notify_resource_update
+MT_SPECIAL_RETURN=0
+MT_SPECIAL_SWITCH=
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
+if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
+rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
+link $** /out:$@ $(LFLAGS)
+
+!else
+
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;2
+
+!endif
+####################################################
+# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \
+ $(_VC_MANIFEST_BASENAME).auto.rc \
+ $(_VC_MANIFEST_BASENAME).auto.manifest
+
+!else
+
+_VC_MANIFEST_CLEAN=
+
+!endif
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\..\..\Build\Release\libisccc.dll"
+
+!ELSE
+
+ALL : "libisc - @PLATFORM@ Release" "..\..\..\Build\Release\libisccc.dll"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libisc - @PLATFORM@ ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\alist.obj"
+ -@erase "$(INTDIR)\base64.obj"
+ -@erase "$(INTDIR)\cc.obj"
+ -@erase "$(INTDIR)\ccmsg.obj"
+ -@erase "$(INTDIR)\DLLMain.obj"
+ -@erase "$(INTDIR)\lib.obj"
+ -@erase "$(INTDIR)\result.obj"
+ -@erase "$(INTDIR)\sexpr.obj"
+ -@erase "$(INTDIR)\symtab.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\version.obj"
+ -@erase "$(OUTDIR)\libisccc.exp"
+ -@erase "$(OUTDIR)\libisccc.lib"
+ -@erase "..\..\..\Build\Release\libisccc.dll"
+ -@$(_VC_MANIFEST_CLEAN)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MD /W3 @COPTX@ @COPTI@ /O2 /I "./" /I "../../../" @LIBXML2_INC@ @OPENSSL_INC@ /I "include" /I "../include" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/dns/win32/include" /I "../../../lib/dns/include" /I "../../../lib/isc/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "USE_MD5" @CRYPTO@ /D "LIBISCCC_EXPORTS" /Fp"$(INTDIR)\libisccc.pch" @COPTY@ /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libisccc.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=user32.lib advapi32.lib ws2_32.lib ../../isc/win32/Release/libisc.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\libisccc.pdb" @MACHINE@ /def:".\libisccc.def" /out:"../../../Build/Release/libisccc.dll" /implib:"$(OUTDIR)\libisccc.lib"
+DEF_FILE= \
+ ".\libisccc.def"
+LINK32_OBJS= \
+ "$(INTDIR)\alist.obj" \
+ "$(INTDIR)\base64.obj" \
+ "$(INTDIR)\cc.obj" \
+ "$(INTDIR)\ccmsg.obj" \
+ "$(INTDIR)\DLLMain.obj" \
+ "$(INTDIR)\lib.obj" \
+ "$(INTDIR)\result.obj" \
+ "$(INTDIR)\sexpr.obj" \
+ "$(INTDIR)\symtab.obj" \
+ "$(INTDIR)\version.obj" \
+ "..\..\isc\win32\Release\libisc.lib"
+
+"..\..\..\Build\Release\libisccc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+ $(_VC_MANIFEST_EMBED_DLL)
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\..\..\Build\Debug\libisccc.dll" "$(OUTDIR)\libisccc.bsc"
+
+!ELSE
+
+ALL : "libisc - @PLATFORM@ Debug" "..\..\..\Build\Debug\libisccc.dll" "$(OUTDIR)\libisccc.bsc"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libisc - @PLATFORM@ DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\alist.obj"
+ -@erase "$(INTDIR)\alist.sbr"
+ -@erase "$(INTDIR)\base64.obj"
+ -@erase "$(INTDIR)\base64.sbr"
+ -@erase "$(INTDIR)\cc.obj"
+ -@erase "$(INTDIR)\cc.sbr"
+ -@erase "$(INTDIR)\ccmsg.obj"
+ -@erase "$(INTDIR)\ccmsg.sbr"
+ -@erase "$(INTDIR)\DLLMain.obj"
+ -@erase "$(INTDIR)\DLLMain.sbr"
+ -@erase "$(INTDIR)\lib.obj"
+ -@erase "$(INTDIR)\lib.sbr"
+ -@erase "$(INTDIR)\result.obj"
+ -@erase "$(INTDIR)\result.sbr"
+ -@erase "$(INTDIR)\sexpr.obj"
+ -@erase "$(INTDIR)\sexpr.sbr"
+ -@erase "$(INTDIR)\symtab.obj"
+ -@erase "$(INTDIR)\symtab.sbr"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\version.obj"
+ -@erase "$(INTDIR)\version.sbr"
+ -@erase "$(OUTDIR)\libisccc.bsc"
+ -@erase "$(OUTDIR)\libisccc.exp"
+ -@erase "$(OUTDIR)\libisccc.lib"
+ -@erase "$(OUTDIR)\libisccc.pdb"
+ -@erase "..\..\..\Build\Debug\libisccc.dll"
+ -@erase "..\..\..\Build\Debug\libisccc.ilk"
+ -@$(_VC_MANIFEST_CLEAN)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MDd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /I "./" /I "../../../" @LIBXML2_INC@ @OPENSSL_INC@ /I "include" /I "../include" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/dns/win32/include" /I "../../../lib/dns/include" /I "../../../lib/isc/include" /D "_DEBUG" /D "WIN32" /D "__STDC__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "USE_MD5" @CRYPTO@ /D "LIBISCCC_EXPORTS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\libisccc.pch" @COPTY@ /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libisccc.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\alist.sbr" \
+ "$(INTDIR)\base64.sbr" \
+ "$(INTDIR)\cc.sbr" \
+ "$(INTDIR)\ccmsg.sbr" \
+ "$(INTDIR)\DLLMain.sbr" \
+ "$(INTDIR)\lib.sbr" \
+ "$(INTDIR)\result.sbr" \
+ "$(INTDIR)\sexpr.sbr" \
+ "$(INTDIR)\symtab.sbr" \
+ "$(INTDIR)\version.sbr"
+
+"$(OUTDIR)\libisccc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=user32.lib advapi32.lib ws2_32.lib ../../isc/win32/debug/libisc.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\libisccc.pdb" /debug @MACHINE@ /def:".\libisccc.def" /out:"../../../Build/Debug/libisccc.dll" /implib:"$(OUTDIR)\libisccc.lib" /pdbtype:sept
+DEF_FILE= \
+ ".\libisccc.def"
+LINK32_OBJS= \
+ "$(INTDIR)\alist.obj" \
+ "$(INTDIR)\base64.obj" \
+ "$(INTDIR)\cc.obj" \
+ "$(INTDIR)\ccmsg.obj" \
+ "$(INTDIR)\DLLMain.obj" \
+ "$(INTDIR)\lib.obj" \
+ "$(INTDIR)\result.obj" \
+ "$(INTDIR)\sexpr.obj" \
+ "$(INTDIR)\symtab.obj" \
+ "$(INTDIR)\version.obj" \
+ "..\..\isc\win32\Debug\libisc.lib"
+
+"..\..\..\Build\Debug\libisccc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+ $(_VC_MANIFEST_EMBED_DLL)
+
+!ENDIF
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("libisccc.dep")
+!INCLUDE "libisccc.dep"
+!ELSE
+!MESSAGE Warning: cannot find "libisccc.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release" || "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+SOURCE=..\alist.c
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\alist.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\alist.obj" "$(INTDIR)\alist.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\base64.c
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\base64.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\base64.obj" "$(INTDIR)\base64.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\cc.c
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\cc.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\cc.obj" "$(INTDIR)\cc.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\ccmsg.c
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\ccmsg.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\ccmsg.obj" "$(INTDIR)\ccmsg.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\DLLMain.c
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\DLLMain.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\DLLMain.obj" "$(INTDIR)\DLLMain.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=..\lib.c
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\lib.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\lib.obj" "$(INTDIR)\lib.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\result.c
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\result.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\result.obj" "$(INTDIR)\result.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\sexpr.c
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\sexpr.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\sexpr.obj" "$(INTDIR)\sexpr.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\symtab.c
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\symtab.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\symtab.obj" "$(INTDIR)\symtab.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\version.c
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+
+"$(INTDIR)\version.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\version.obj" "$(INTDIR)\version.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+!IF "$(CFG)" == "libisccc - @PLATFORM@ Release"
+
+"libisc - @PLATFORM@ Release" :
+ cd "..\..\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - @PLATFORM@ Release"
+ cd "..\..\isccc\win32"
+
+"libisc - @PLATFORM@ ReleaseCLEAN" :
+ cd "..\..\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - @PLATFORM@ Release" RECURSE=1 CLEAN
+ cd "..\..\isccc\win32"
+
+!ELSEIF "$(CFG)" == "libisccc - @PLATFORM@ Debug"
+
+"libisc - @PLATFORM@ Debug" :
+ cd "..\..\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - @PLATFORM@ Debug"
+ cd "..\..\isccc\win32"
+
+"libisc - @PLATFORM@ DebugCLEAN" :
+ cd "..\..\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - @PLATFORM@ Debug" RECURSE=1 CLEAN
+ cd "..\..\isccc\win32"
+
+!ENDIF
+
+
+!ENDIF
+
+####################################################
+# Commands to generate initial empty manifest file and the RC file
+# that references it, and for generating the .res file:
+
+$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc
+
+$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest
+ type <<$@
+#include <winuser.h>
+1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest"
+<< KEEP
+
+$(_VC_MANIFEST_BASENAME).auto.manifest :
+ type <<$@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+</assembly>
+<< KEEP
diff --git a/lib/isccc/win32/libisccc.vcxproj.filters.in b/lib/isccc/win32/libisccc.vcxproj.filters.in
new file mode 100644
index 0000000..b17d13c
--- /dev/null
+++ b/lib/isccc/win32/libisccc.vcxproj.filters.in
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="libisccc.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="DLLMain.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="version.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\alist.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\base64.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\cc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ccmsg.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\lib.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\result.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\sexpr.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\symtab.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\include\isccc\alist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\base64.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\cc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\ccmsg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\events.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\lib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\result.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\sexpr.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\symtab.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\symtype.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\types.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\util.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccc\version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/lib/isccc/win32/libisccc.vcxproj.in b/lib/isccc/win32/libisccc.vcxproj.in
new file mode 100644
index 0000000..0ba2049
--- /dev/null
+++ b/lib/isccc/win32/libisccc.vcxproj.in
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|@PLATFORM@">
+ <Configuration>Debug</Configuration>
+ <Platform>@PLATFORM@</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|@PLATFORM@">
+ <Configuration>Release</Configuration>
+ <Platform>@PLATFORM@</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{B556705F-1920-4400-878A-B259D3556047}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>libisccc</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>..\..\..\Build\$(Configuration)\</OutDir>
+ <IntDir>.\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>..\..\..\Build\$(Configuration)\</OutDir>
+ <IntDir>.\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;USE_MD5;@CRYPTO@_DEBUG;_WINDOWS;_USRDLL;LIBISCCC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@include;..\include;..\..\isc\win32;..\..\isc\win32\include;..\..\isc\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeaderOutputFile>.\$(Configuration)\$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\$(Configuration)\</AssemblerListingLocation>
+ <ObjectFileName>.\$(Configuration)\</ObjectFileName>
+ <ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <BrowseInformation>true</BrowseInformation>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
+ <AdditionalLibraryDirectories>..\..\isc\win32\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libisc.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
+ <ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>@INTRINSIC@</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;USE_MD5;@CRYPTO@NDEBUG;_WINDOWS;_USRDLL;LIBISCCC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@include;..\include;..\..\isc\win32;..\..\isc\win32\include;..\..\isc\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <StringPooling>true</StringPooling>
+ <PrecompiledHeaderOutputFile>.\$(Configuration)\$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\$(Configuration)\</AssemblerListingLocation>
+ <ObjectFileName>.\$(Configuration)\</ObjectFileName>
+ <ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
+ <AdditionalLibraryDirectories>..\..\isc\win32\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libisc.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
+ <ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
+ <LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <None Include="libisccc.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\alist.c" />
+ <ClCompile Include="..\base64.c" />
+ <ClCompile Include="..\cc.c" />
+ <ClCompile Include="..\ccmsg.c" />
+ <ClCompile Include="..\lib.c" />
+ <ClCompile Include="..\result.c" />
+ <ClCompile Include="..\sexpr.c" />
+ <ClCompile Include="..\symtab.c" />
+ <ClCompile Include="DLLMain.c" />
+ <ClCompile Include="version.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\include\isccc\alist.h" />
+ <ClInclude Include="..\include\isccc\base64.h" />
+ <ClInclude Include="..\include\isccc\cc.h" />
+ <ClInclude Include="..\include\isccc\ccmsg.h" />
+ <ClInclude Include="..\include\isccc\events.h" />
+ <ClInclude Include="..\include\isccc\lib.h" />
+ <ClInclude Include="..\include\isccc\result.h" />
+ <ClInclude Include="..\include\isccc\sexpr.h" />
+ <ClInclude Include="..\include\isccc\symtab.h" />
+ <ClInclude Include="..\include\isccc\symtype.h" />
+ <ClInclude Include="..\include\isccc\types.h" />
+ <ClInclude Include="..\include\isccc\util.h" />
+ <ClInclude Include="..\include\isccc\version.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/lib/isccc/win32/libisccc.vcxproj.user b/lib/isccc/win32/libisccc.vcxproj.user
new file mode 100644
index 0000000..695b5c7
--- /dev/null
+++ b/lib/isccc/win32/libisccc.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project> \ No newline at end of file
diff --git a/lib/isccc/win32/version.c b/lib/isccc/win32/version.c
new file mode 100644
index 0000000..dfdd947
--- /dev/null
+++ b/lib/isccc/win32/version.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <versions.h>
+
+#include <isccc/version.h>
+
+LIBISCCC_EXTERNAL_DATA const char isccc_version[] = VERSION;
+
+LIBISCCC_EXTERNAL_DATA const unsigned int isccc_libinterface = LIBINTERFACE;
+LIBISCCC_EXTERNAL_DATA const unsigned int isccc_librevision = LIBREVISION;
+LIBISCCC_EXTERNAL_DATA const unsigned int isccc_libage = LIBAGE;
diff --git a/lib/isccfg/Atffile b/lib/isccfg/Atffile
new file mode 100644
index 0000000..1edb838
--- /dev/null
+++ b/lib/isccfg/Atffile
@@ -0,0 +1,5 @@
+Content-Type: application/X-atf-atffile; version="1"
+
+prop: test-suite = bind9
+
+tp: tests
diff --git a/lib/isccfg/Kyuafile b/lib/isccfg/Kyuafile
new file mode 100644
index 0000000..0739e3a
--- /dev/null
+++ b/lib/isccfg/Kyuafile
@@ -0,0 +1,4 @@
+syntax(2)
+test_suite('bind9')
+
+include('tests/Kyuafile')
diff --git a/lib/isccfg/Makefile.in b/lib/isccfg/Makefile.in
new file mode 100644
index 0000000..f459bd5
--- /dev/null
+++ b/lib/isccfg/Makefile.in
@@ -0,0 +1,83 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+@LIBISCCFG_API@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = -I. ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES}
+
+CDEFINES =
+CWARNINGS =
+
+ISCLIBS = ../../lib/isc/libisc.@A@
+DNSLIBS = ../../lib/dns/libdns.@A@
+ISCCFGLIBS = ../../lib/cfg/libisccfg.@A@
+
+ISCDEPLIBS = ../../lib/isc/libisc.@A@
+ISCCFGDEPLIBS = libisccfg.@A@
+
+LIBS = @LIBS@
+
+SUBDIRS = include
+TESTDIRS = @UNITTESTS@
+
+# Alphabetically
+OBJS = aclconf.@O@ dnsconf.@O@ log.@O@ namedconf.@O@ \
+ parser.@O@ version.@O@
+
+# Alphabetically
+SRCS = aclconf.c dnsconf.c log.c namedconf.c \
+ parser.c version.c
+
+TARGETS = timestamp
+
+@BIND9_MAKE_RULES@
+
+version.@O@: version.c
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \
+ -DVERSION=\"${VERSION}\" \
+ -DLIBINTERFACE=${LIBINTERFACE} \
+ -DLIBREVISION=${LIBREVISION} \
+ -DLIBAGE=${LIBAGE} \
+ -c ${srcdir}/version.c
+
+libisccfg.@SA@: ${OBJS}
+ ${AR} ${ARFLAGS} $@ ${OBJS}
+ ${RANLIB} $@
+
+libisccfg.la: ${OBJS}
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisccfg.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} ${DNSLIBS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ \
+ ${LIBS}
+
+timestamp: libisccfg.@A@
+ touch timestamp
+
+testdirs: libisccfg.@A@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+
+install:: timestamp installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_LIBRARY} libisccfg.@A@ ${DESTDIR}${libdir}
+
+uninstall::
+ ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${libdir}/libisccfg.@A@
+
+clean distclean::
+ rm -f libisccfg.@A@ timestamp
diff --git a/lib/isccfg/aclconf.c b/lib/isccfg/aclconf.c
new file mode 100644
index 0000000..3fa813e
--- /dev/null
+++ b/lib/isccfg/aclconf.c
@@ -0,0 +1,906 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/util.h>
+
+#include <isccfg/namedconf.h>
+#include <isccfg/aclconf.h>
+
+#include <dns/acl.h>
+#include <dns/iptable.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+
+#ifdef HAVE_GEOIP
+#include <stdlib.h>
+#include <math.h>
+#endif /* HAVE_GEOIP */
+
+#define LOOP_MAGIC ISC_MAGIC('L','O','O','P')
+
+isc_result_t
+cfg_aclconfctx_create(isc_mem_t *mctx, cfg_aclconfctx_t **ret) {
+ isc_result_t result;
+ cfg_aclconfctx_t *actx;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ actx = isc_mem_get(mctx, sizeof(*actx));
+ if (actx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = isc_refcount_init(&actx->references, 1);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ actx->mctx = NULL;
+ isc_mem_attach(mctx, &actx->mctx);
+ ISC_LIST_INIT(actx->named_acl_cache);
+
+#ifdef HAVE_GEOIP
+ actx->geoip = NULL;
+#endif
+
+ *ret = actx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ isc_mem_put(mctx, actx, sizeof(*actx));
+ return (result);
+}
+
+void
+cfg_aclconfctx_attach(cfg_aclconfctx_t *src, cfg_aclconfctx_t **dest) {
+ REQUIRE(src != NULL);
+ REQUIRE(dest != NULL && *dest == NULL);
+
+ isc_refcount_increment(&src->references, NULL);
+ *dest = src;
+}
+
+void
+cfg_aclconfctx_detach(cfg_aclconfctx_t **actxp) {
+ cfg_aclconfctx_t *actx;
+ dns_acl_t *dacl, *next;
+ unsigned int refs;
+
+ REQUIRE(actxp != NULL && *actxp != NULL);
+
+ actx = *actxp;
+
+ isc_refcount_decrement(&actx->references, &refs);
+ if (refs == 0) {
+ for (dacl = ISC_LIST_HEAD(actx->named_acl_cache);
+ dacl != NULL;
+ dacl = next)
+ {
+ next = ISC_LIST_NEXT(dacl, nextincache);
+ ISC_LIST_UNLINK(actx->named_acl_cache, dacl,
+ nextincache);
+ dns_acl_detach(&dacl);
+ }
+ isc_mem_putanddetach(&actx->mctx, actx, sizeof(*actx));
+ }
+
+ *actxp = NULL;
+}
+
+/*
+ * Find the definition of the named acl whose name is "name".
+ */
+static isc_result_t
+get_acl_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
+ isc_result_t result;
+ const cfg_obj_t *acls = NULL;
+ const cfg_listelt_t *elt;
+
+ result = cfg_map_get(cctx, "acl", &acls);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ for (elt = cfg_list_first(acls);
+ elt != NULL;
+ elt = cfg_list_next(elt)) {
+ const cfg_obj_t *acl = cfg_listelt_value(elt);
+ const char *aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
+ if (strcasecmp(aclname, name) == 0) {
+ if (ret != NULL) {
+ *ret = cfg_tuple_get(acl, "value");
+ }
+ return (ISC_R_SUCCESS);
+ }
+ }
+ return (ISC_R_NOTFOUND);
+}
+
+static isc_result_t
+convert_named_acl(const cfg_obj_t *nameobj, const cfg_obj_t *cctx,
+ isc_log_t *lctx, cfg_aclconfctx_t *ctx,
+ isc_mem_t *mctx, unsigned int nest_level,
+ dns_acl_t **target)
+{
+ isc_result_t result;
+ const cfg_obj_t *cacl = NULL;
+ dns_acl_t *dacl;
+ dns_acl_t loop;
+ const char *aclname = cfg_obj_asstring(nameobj);
+
+ /* Look for an already-converted version. */
+ for (dacl = ISC_LIST_HEAD(ctx->named_acl_cache);
+ dacl != NULL;
+ dacl = ISC_LIST_NEXT(dacl, nextincache))
+ {
+ if (strcasecmp(aclname, dacl->name) == 0) {
+ if (ISC_MAGIC_VALID(dacl, LOOP_MAGIC)) {
+ cfg_obj_log(nameobj, lctx, ISC_LOG_ERROR,
+ "acl loop detected: %s", aclname);
+ return (ISC_R_FAILURE);
+ }
+ dns_acl_attach(dacl, target);
+ return (ISC_R_SUCCESS);
+ }
+ }
+ /* Not yet converted. Convert now. */
+ result = get_acl_def(cctx, aclname, &cacl);
+ if (result != ISC_R_SUCCESS) {
+ cfg_obj_log(nameobj, lctx, ISC_LOG_WARNING,
+ "undefined ACL '%s'", aclname);
+ return (result);
+ }
+ /*
+ * Add a loop detection element.
+ */
+ memset(&loop, 0, sizeof(loop));
+ ISC_LINK_INIT(&loop, nextincache);
+ DE_CONST(aclname, loop.name);
+ loop.magic = LOOP_MAGIC;
+ ISC_LIST_APPEND(ctx->named_acl_cache, &loop, nextincache);
+ result = cfg_acl_fromconfig(cacl, cctx, lctx, ctx, mctx,
+ nest_level, &dacl);
+ ISC_LIST_UNLINK(ctx->named_acl_cache, &loop, nextincache);
+ loop.magic = 0;
+ loop.name = NULL;
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dacl->name = isc_mem_strdup(dacl->mctx, aclname);
+ if (dacl->name == NULL)
+ return (ISC_R_NOMEMORY);
+ ISC_LIST_APPEND(ctx->named_acl_cache, dacl, nextincache);
+ dns_acl_attach(dacl, target);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+convert_keyname(const cfg_obj_t *keyobj, isc_log_t *lctx, isc_mem_t *mctx,
+ dns_name_t *dnsname)
+{
+ isc_result_t result;
+ isc_buffer_t buf;
+ dns_fixedname_t fixname;
+ unsigned int keylen;
+ const char *txtname = cfg_obj_asstring(keyobj);
+
+ keylen = strlen(txtname);
+ isc_buffer_constinit(&buf, txtname, keylen);
+ isc_buffer_add(&buf, keylen);
+ dns_fixedname_init(&fixname);
+ result = dns_name_fromtext(dns_fixedname_name(&fixname), &buf,
+ dns_rootname, 0, NULL);
+ if (result != ISC_R_SUCCESS) {
+ cfg_obj_log(keyobj, lctx, ISC_LOG_WARNING,
+ "key name '%s' is not a valid domain name",
+ txtname);
+ return (result);
+ }
+ return (dns_name_dup(dns_fixedname_name(&fixname), mctx, dnsname));
+}
+
+/*
+ * Recursively pre-parse an ACL definition to find the total number
+ * of non-IP-prefix elements (localhost, localnets, key) in all nested
+ * ACLs, so that the parent will have enough space allocated for the
+ * elements table after all the nested ACLs have been merged in to the
+ * parent.
+ */
+static isc_result_t
+count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx,
+ isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx,
+ uint32_t *count, bool *has_negative)
+{
+ const cfg_listelt_t *elt;
+ isc_result_t result;
+ uint32_t n = 0;
+
+ REQUIRE(count != NULL);
+
+ if (has_negative != NULL)
+ *has_negative = false;
+
+ for (elt = cfg_list_first(caml);
+ elt != NULL;
+ elt = cfg_list_next(elt)) {
+ const cfg_obj_t *ce = cfg_listelt_value(elt);
+
+ /* might be a negated element, in which case get the value. */
+ if (cfg_obj_istuple(ce)) {
+ const cfg_obj_t *negated =
+ cfg_tuple_get(ce, "negated");
+ if (! cfg_obj_isvoid(negated)) {
+ ce = negated;
+ if (has_negative != NULL)
+ *has_negative = true;
+ }
+ }
+
+ if (cfg_obj_istype(ce, &cfg_type_keyref)) {
+ n++;
+ } else if (cfg_obj_islist(ce)) {
+ bool negative;
+ uint32_t sub;
+ result = count_acl_elements(ce, cctx, lctx, ctx, mctx,
+ &sub, &negative);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ n += sub;
+ if (negative)
+ n++;
+#ifdef HAVE_GEOIP
+ } else if (cfg_obj_istuple(ce) &&
+ cfg_obj_isvoid(cfg_tuple_get(ce, "negated")))
+ {
+ n++;
+#endif /* HAVE_GEOIP */
+ } else if (cfg_obj_isstring(ce)) {
+ const char *name = cfg_obj_asstring(ce);
+ if (strcasecmp(name, "localhost") == 0 ||
+ strcasecmp(name, "localnets") == 0 ||
+ strcasecmp(name, "none") == 0)
+ {
+ n++;
+ } else if (strcasecmp(name, "any") != 0) {
+ dns_acl_t *inneracl = NULL;
+ /*
+ * Convert any named acls we reference now if
+ * they have not already been converted.
+ */
+ result = convert_named_acl(ce, cctx, lctx, ctx,
+ mctx, 0, &inneracl);
+ if (result == ISC_R_SUCCESS) {
+ if (inneracl->has_negatives)
+ n++;
+ else
+ n += inneracl->length;
+ dns_acl_detach(&inneracl);
+ } else
+ return (result);
+ }
+ }
+ }
+
+ *count = n;
+ return (ISC_R_SUCCESS);
+}
+
+#ifdef HAVE_GEOIP
+static dns_geoip_subtype_t
+get_subtype(const cfg_obj_t *obj, isc_log_t *lctx,
+ dns_geoip_subtype_t subtype, const char *dbname)
+{
+ if (dbname == NULL)
+ return (subtype);
+
+ switch (subtype) {
+ case dns_geoip_countrycode:
+ if (strcasecmp(dbname, "city") == 0)
+ return (dns_geoip_city_countrycode);
+ else if (strcasecmp(dbname, "region") == 0)
+ return (dns_geoip_region_countrycode);
+ else if (strcasecmp(dbname, "country") == 0)
+ return (dns_geoip_country_code);
+ cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
+ "invalid GeoIP DB specified for "
+ "country search: ignored");
+ return (subtype);
+ case dns_geoip_countrycode3:
+ if (strcasecmp(dbname, "city") == 0)
+ return (dns_geoip_city_countrycode3);
+ else if (strcasecmp(dbname, "country") == 0)
+ return (dns_geoip_country_code3);
+ cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
+ "invalid GeoIP DB specified for "
+ "country search: ignored");
+ return (subtype);
+ case dns_geoip_countryname:
+ if (strcasecmp(dbname, "city") == 0)
+ return (dns_geoip_city_countryname);
+ else if (strcasecmp(dbname, "country") == 0)
+ return (dns_geoip_country_name);
+ cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
+ "invalid GeoIP DB specified for "
+ "country search: ignored");
+ return (subtype);
+ case dns_geoip_region:
+ if (strcasecmp(dbname, "city") == 0)
+ return (dns_geoip_city_region);
+ else if (strcasecmp(dbname, "region") == 0)
+ return (dns_geoip_region_code);
+ cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
+ "invalid GeoIP DB specified for "
+ "region search: ignored");
+ return (subtype);
+ case dns_geoip_regionname:
+ if (strcasecmp(dbname, "city") == 0)
+ return (dns_geoip_city_region);
+ else if (strcasecmp(dbname, "region") == 0)
+ return (dns_geoip_region_name);
+ cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
+ "invalid GeoIP DB specified for "
+ "region search: ignored");
+ return (subtype);
+
+ /*
+ * Log a warning if the wrong database was specified
+ * on an unambiguous query
+ */
+ case dns_geoip_city_name:
+ case dns_geoip_city_postalcode:
+ case dns_geoip_city_metrocode:
+ case dns_geoip_city_areacode:
+ case dns_geoip_city_continentcode:
+ case dns_geoip_city_timezonecode:
+ if (strcasecmp(dbname, "city") != 0)
+ cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
+ "invalid GeoIP DB specified for "
+ "a 'city'-only search type: ignoring");
+ return (subtype);
+ case dns_geoip_isp_name:
+ if (strcasecmp(dbname, "isp") != 0)
+ cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
+ "invalid GeoIP DB specified for "
+ "an 'isp' search: ignoring");
+ return (subtype);
+ case dns_geoip_org_name:
+ if (strcasecmp(dbname, "org") != 0)
+ cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
+ "invalid GeoIP DB specified for "
+ "an 'org' search: ignoring");
+ return (subtype);
+ case dns_geoip_as_asnum:
+ if (strcasecmp(dbname, "asnum") != 0)
+ cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
+ "invalid GeoIP DB specified for "
+ "an 'asnum' search: ignoring");
+ return (subtype);
+ case dns_geoip_domain_name:
+ if (strcasecmp(dbname, "domain") != 0)
+ cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
+ "invalid GeoIP DB specified for "
+ "a 'domain' search: ignoring");
+ return (subtype);
+ case dns_geoip_netspeed_id:
+ if (strcasecmp(dbname, "netspeed") != 0)
+ cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
+ "invalid GeoIP DB specified for "
+ "a 'netspeed' search: ignoring");
+ return (subtype);
+ default:
+ INSIST(0);
+ }
+}
+
+static bool
+geoip_can_answer(dns_aclelement_t *elt, cfg_aclconfctx_t *ctx) {
+ if (ctx->geoip == NULL)
+ return (true);
+
+ switch (elt->geoip_elem.subtype) {
+ case dns_geoip_countrycode:
+ case dns_geoip_countrycode3:
+ case dns_geoip_countryname:
+ if (ctx->geoip->city_v4 != NULL ||
+ ctx->geoip->city_v6 != NULL ||
+ ctx->geoip->country_v4 != NULL ||
+ ctx->geoip->country_v6 != NULL ||
+ ctx->geoip->region != NULL)
+ return (true);
+ /* FALLTHROUGH */
+ case dns_geoip_region:
+ case dns_geoip_regionname:
+ if (ctx->geoip->city_v4 != NULL ||
+ ctx->geoip->city_v6 != NULL ||
+ ctx->geoip->region != NULL)
+ return (true);
+ /* FALLTHROUGH */
+ case dns_geoip_country_code:
+ case dns_geoip_country_code3:
+ case dns_geoip_country_name:
+ if (ctx->geoip->country_v4 != NULL ||
+ ctx->geoip->country_v6 != NULL)
+ return (true);
+ /* FALLTHROUGH */
+ case dns_geoip_region_countrycode:
+ case dns_geoip_region_code:
+ case dns_geoip_region_name:
+ if (ctx->geoip->region != NULL)
+ return (true);
+ /* FALLTHROUGH */
+ case dns_geoip_city_countrycode:
+ case dns_geoip_city_countrycode3:
+ case dns_geoip_city_countryname:
+ case dns_geoip_city_region:
+ case dns_geoip_city_regionname:
+ case dns_geoip_city_name:
+ case dns_geoip_city_postalcode:
+ case dns_geoip_city_metrocode:
+ case dns_geoip_city_areacode:
+ case dns_geoip_city_continentcode:
+ case dns_geoip_city_timezonecode:
+ if (ctx->geoip->city_v4 != NULL ||
+ ctx->geoip->city_v6 != NULL)
+ return (true);
+ /* FALLTHROUGH */
+ case dns_geoip_isp_name:
+ if (ctx->geoip->isp != NULL)
+ return (true);
+ /* FALLTHROUGH */
+ case dns_geoip_org_name:
+ if (ctx->geoip->org != NULL)
+ return (true);
+ /* FALLTHROUGH */
+ case dns_geoip_as_asnum:
+ if (ctx->geoip->as != NULL)
+ return (true);
+ /* FALLTHROUGH */
+ case dns_geoip_domain_name:
+ if (ctx->geoip->domain != NULL)
+ return (true);
+ /* FALLTHROUGH */
+ case dns_geoip_netspeed_id:
+ if (ctx->geoip->netspeed != NULL)
+ return (true);
+ }
+
+ return (false);
+}
+
+static isc_result_t
+parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx,
+ cfg_aclconfctx_t *ctx, dns_aclelement_t *dep)
+{
+ const cfg_obj_t *ge;
+ const char *dbname = NULL;
+ const char *stype, *search;
+ dns_geoip_subtype_t subtype;
+ dns_aclelement_t de;
+ size_t len;
+
+ REQUIRE(dep != NULL);
+
+ de = *dep;
+
+ ge = cfg_tuple_get(obj, "db");
+ if (!cfg_obj_isvoid(ge))
+ dbname = cfg_obj_asstring(ge);
+
+ stype = cfg_obj_asstring(cfg_tuple_get(obj, "subtype"));
+ search = cfg_obj_asstring(cfg_tuple_get(obj, "search"));
+ len = strlen(search);
+
+ if (len == 0) {
+ cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
+ "zero-length geoip search field");
+ return (ISC_R_FAILURE);
+ }
+
+ if (strcasecmp(stype, "country") == 0 && len == 2) {
+ /* Two-letter country code */
+ subtype = dns_geoip_countrycode;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "country") == 0 && len == 3) {
+ /* Three-letter country code */
+ subtype = dns_geoip_countrycode3;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "country") == 0) {
+ /* Country name */
+ subtype = dns_geoip_countryname;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "region") == 0 && len == 2) {
+ /* Two-letter region code */
+ subtype = dns_geoip_region;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "region") == 0) {
+ /* Region name */
+ subtype = dns_geoip_regionname;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "city") == 0) {
+ /* City name */
+ subtype = dns_geoip_city_name;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "postal") == 0 ||
+ strcasecmp(stype, "postalcode") == 0)
+ {
+ if (len < 7) {
+ subtype = dns_geoip_city_postalcode;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else {
+ cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
+ "geoiop postal code (%s) too long",
+ search);
+ return (ISC_R_FAILURE);
+ }
+ } else if (strcasecmp(stype, "metro") == 0 ||
+ strcasecmp(stype, "metrocode") == 0)
+ {
+ subtype = dns_geoip_city_metrocode;
+ de.geoip_elem.as_int = atoi(search);
+ } else if (strcasecmp(stype, "area") == 0 ||
+ strcasecmp(stype, "areacode") == 0)
+ {
+ subtype = dns_geoip_city_areacode;
+ de.geoip_elem.as_int = atoi(search);
+ } else if (strcasecmp(stype, "tz") == 0 ||
+ strcasecmp(stype, "timezone") == 0)
+ {
+ subtype = dns_geoip_city_timezonecode;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "continent") == 0 && len == 2) {
+ /* Two-letter continent code */
+ subtype = dns_geoip_city_continentcode;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "continent") == 0) {
+ cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
+ "geoiop continent code (%s) too long", search);
+ return (ISC_R_FAILURE);
+ } else if (strcasecmp(stype, "isp") == 0) {
+ subtype = dns_geoip_isp_name;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "asnum") == 0) {
+ subtype = dns_geoip_as_asnum;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "org") == 0) {
+ subtype = dns_geoip_org_name;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "domain") == 0) {
+ subtype = dns_geoip_domain_name;
+ strlcpy(de.geoip_elem.as_string, search,
+ sizeof(de.geoip_elem.as_string));
+ } else if (strcasecmp(stype, "netspeed") == 0) {
+ subtype = dns_geoip_netspeed_id;
+ de.geoip_elem.as_int = atoi(search);
+ } else
+ INSIST(0);
+
+ de.geoip_elem.subtype = get_subtype(obj, lctx, subtype, dbname);
+
+ if (! geoip_can_answer(&de, ctx)) {
+ cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
+ "no GeoIP database installed which can answer "
+ "queries of type '%s'", stype);
+ return (ISC_R_FAILURE);
+ }
+
+ *dep = de;
+
+ return (ISC_R_SUCCESS);
+}
+#endif
+
+isc_result_t
+cfg_acl_fromconfig(const cfg_obj_t *caml, const cfg_obj_t *cctx,
+ isc_log_t *lctx, cfg_aclconfctx_t *ctx,
+ isc_mem_t *mctx, unsigned int nest_level,
+ dns_acl_t **target)
+{
+ return (cfg_acl_fromconfig2(caml, cctx, lctx, ctx, mctx,
+ nest_level, 0, target));
+}
+
+isc_result_t
+cfg_acl_fromconfig2(const cfg_obj_t *caml, const cfg_obj_t *cctx,
+ isc_log_t *lctx, cfg_aclconfctx_t *ctx,
+ isc_mem_t *mctx, unsigned int nest_level,
+ uint16_t family, dns_acl_t **target)
+{
+ isc_result_t result;
+ dns_acl_t *dacl = NULL, *inneracl = NULL;
+ dns_aclelement_t *de;
+ const cfg_listelt_t *elt;
+ dns_iptable_t *iptab;
+ int new_nest_level = 0;
+
+ if (nest_level != 0)
+ new_nest_level = nest_level - 1;
+
+ REQUIRE(target != NULL);
+ REQUIRE(*target == NULL || DNS_ACL_VALID(*target));
+
+ if (*target != NULL) {
+ /*
+ * If target already points to an ACL, then we're being
+ * called recursively to configure a nested ACL. The
+ * nested ACL's contents should just be absorbed into its
+ * parent ACL.
+ */
+ dns_acl_attach(*target, &dacl);
+ dns_acl_detach(target);
+ } else {
+ /*
+ * Need to allocate a new ACL structure. Count the items
+ * in the ACL definition that will require space in the
+ * elements table. (Note that if nest_level is nonzero,
+ * *everything* goes in the elements table.)
+ */
+ uint32_t nelem;
+
+ if (nest_level == 0) {
+ result = count_acl_elements(caml, cctx, lctx, ctx,
+ mctx, &nelem, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else
+ nelem = cfg_list_length(caml, false);
+
+ result = dns_acl_create(mctx, nelem, &dacl);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ de = dacl->elements;
+ for (elt = cfg_list_first(caml);
+ elt != NULL;
+ elt = cfg_list_next(elt)) {
+ const cfg_obj_t *ce = cfg_listelt_value(elt);
+ bool neg = false;
+
+ INSIST(dacl->length <= dacl->alloc);
+
+ if (cfg_obj_istuple(ce)) {
+ /* Might be a negated element */
+ const cfg_obj_t *negated =
+ cfg_tuple_get(ce, "negated");
+ if (! cfg_obj_isvoid(negated)) {
+ neg = true;
+ dacl->has_negatives = true;
+ ce = negated;
+ }
+ }
+
+ /*
+ * If nest_level is nonzero, then every element is
+ * to be stored as a separate, nested ACL rather than
+ * merged into the main iptable.
+ */
+ iptab = dacl->iptable;
+
+ if (nest_level != 0) {
+ result = dns_acl_create(mctx,
+ cfg_list_length(ce, false),
+ &de->nestedacl);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ iptab = de->nestedacl->iptable;
+ }
+
+ if (cfg_obj_isnetprefix(ce)) {
+ /* Network prefix */
+ isc_netaddr_t addr;
+ unsigned int bitlen;
+ bool setpos, setecs;
+
+ cfg_obj_asnetprefix(ce, &addr, &bitlen);
+ if (family != 0 && family != addr.family) {
+ char buf[ISC_NETADDR_FORMATSIZE + 1];
+ isc_netaddr_format(&addr, buf, sizeof(buf));
+ cfg_obj_log(ce, lctx, ISC_LOG_WARNING,
+ "'%s': incorrect address family; "
+ "ignoring", buf);
+ if (nest_level != 0)
+ dns_acl_detach(&de->nestedacl);
+ continue;
+ }
+ result = isc_netaddr_prefixok(&addr, bitlen);
+ if (result != ISC_R_SUCCESS) {
+ char buf[ISC_NETADDR_FORMATSIZE + 1];
+ isc_netaddr_format(&addr, buf, sizeof(buf));
+ cfg_obj_log(ce, lctx, ISC_LOG_WARNING,
+ "'%s/%u': address/prefix length "
+ "mismatch", buf, bitlen);
+ }
+
+ /*
+ * If nesting ACLs (nest_level != 0), we negate
+ * the nestedacl element, not the iptable entry.
+ */
+ setpos = (nest_level != 0 || !neg);
+ setecs = cfg_obj_istype(ce, &cfg_type_ecsprefix);
+ result = dns_iptable_addprefix2(iptab, &addr, bitlen,
+ setpos, setecs);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ if (nest_level > 0) {
+ INSIST(dacl->length < dacl->alloc);
+ de->type = dns_aclelementtype_nestedacl;
+ de->negative = neg;
+ } else
+ continue;
+ } else if (cfg_obj_islist(ce)) {
+ /*
+ * If we're nesting ACLs, put the nested
+ * ACL onto the elements list; otherwise
+ * merge it into *this* ACL. We nest ACLs
+ * in two cases: 1) sortlist, 2) if the
+ * nested ACL contains negated members.
+ */
+ if (inneracl != NULL)
+ dns_acl_detach(&inneracl);
+ result = cfg_acl_fromconfig(ce, cctx, lctx,
+ ctx, mctx, new_nest_level,
+ &inneracl);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+nested_acl:
+ if (nest_level > 0 || inneracl->has_negatives) {
+ INSIST(dacl->length < dacl->alloc);
+ de->type = dns_aclelementtype_nestedacl;
+ de->negative = neg;
+ if (de->nestedacl != NULL)
+ dns_acl_detach(&de->nestedacl);
+ dns_acl_attach(inneracl,
+ &de->nestedacl);
+ dns_acl_detach(&inneracl);
+ /* Fall through. */
+ } else {
+ INSIST(dacl->length + inneracl->length
+ <= dacl->alloc);
+ dns_acl_merge(dacl, inneracl,
+ !neg);
+ de += inneracl->length; /* elements added */
+ dns_acl_detach(&inneracl);
+ INSIST(dacl->length <= dacl->alloc);
+ continue;
+ }
+ } else if (cfg_obj_istype(ce, &cfg_type_keyref)) {
+ /* Key name. */
+ INSIST(dacl->length < dacl->alloc);
+ de->type = dns_aclelementtype_keyname;
+ de->negative = neg;
+ dns_name_init(&de->keyname, NULL);
+ result = convert_keyname(ce, lctx, mctx,
+ &de->keyname);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+#ifdef HAVE_GEOIP
+ } else if (cfg_obj_istuple(ce) &&
+ cfg_obj_isvoid(cfg_tuple_get(ce, "negated")))
+ {
+ INSIST(dacl->length < dacl->alloc);
+ result = parse_geoip_element(ce, lctx, ctx, de);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ de->type = dns_aclelementtype_geoip;
+ de->negative = neg;
+#endif /* HAVE_GEOIP */
+ } else if (cfg_obj_isstring(ce)) {
+ /* ACL name. */
+ const char *name = cfg_obj_asstring(ce);
+ if (strcasecmp(name, "any") == 0) {
+ /* Iptable entry with zero bit length. */
+ result = dns_iptable_addprefix(iptab, NULL, 0,
+ (nest_level != 0 || !neg));
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ if (nest_level != 0) {
+ INSIST(dacl->length < dacl->alloc);
+ de->type = dns_aclelementtype_nestedacl;
+ de->negative = neg;
+ } else
+ continue;
+ } else if (strcasecmp(name, "none") == 0) {
+ /* none == !any */
+ /*
+ * We don't unconditional set
+ * dacl->has_negatives and
+ * de->negative to true so we can handle
+ * "!none;".
+ */
+ result = dns_iptable_addprefix(iptab, NULL, 0,
+ (nest_level != 0 || neg));
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ if (!neg)
+ dacl->has_negatives = !neg;
+
+ if (nest_level != 0) {
+ INSIST(dacl->length < dacl->alloc);
+ de->type = dns_aclelementtype_nestedacl;
+ de->negative = !neg;
+ } else
+ continue;
+ } else if (strcasecmp(name, "localhost") == 0) {
+ INSIST(dacl->length < dacl->alloc);
+ de->type = dns_aclelementtype_localhost;
+ de->negative = neg;
+ } else if (strcasecmp(name, "localnets") == 0) {
+ INSIST(dacl->length < dacl->alloc);
+ de->type = dns_aclelementtype_localnets;
+ de->negative = neg;
+ } else {
+ if (inneracl != NULL)
+ dns_acl_detach(&inneracl);
+ /*
+ * This call should just find the cached
+ * of the named acl.
+ */
+ result = convert_named_acl(ce, cctx, lctx, ctx,
+ mctx, new_nest_level,
+ &inneracl);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ goto nested_acl;
+ }
+ } else {
+ cfg_obj_log(ce, lctx, ISC_LOG_WARNING,
+ "address match list contains "
+ "unsupported element type");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ /*
+ * This should only be reached for localhost, localnets
+ * and keyname elements, and nested ACLs if nest_level is
+ * nonzero (i.e., in sortlists).
+ */
+ if (de->nestedacl != NULL &&
+ de->type != dns_aclelementtype_nestedacl)
+ dns_acl_detach(&de->nestedacl);
+
+ dacl->node_count++;
+ de->node_num = dacl->node_count;
+
+ dacl->length++;
+ de++;
+ INSIST(dacl->length <= dacl->alloc);
+ }
+
+ dns_acl_attach(dacl, target);
+ result = ISC_R_SUCCESS;
+
+ cleanup:
+ if (inneracl != NULL)
+ dns_acl_detach(&inneracl);
+ dns_acl_detach(&dacl);
+ return (result);
+}
diff --git a/lib/isccfg/api b/lib/isccfg/api
new file mode 100644
index 0000000..4cbb63b
--- /dev/null
+++ b/lib/isccfg/api
@@ -0,0 +1,13 @@
+# LIBINTERFACE ranges
+# 9.6: 50-59, 110-119
+# 9.7: 60-79
+# 9.8: 80-89, 120-129
+# 9.9: 90-109, 170-179
+# 9.9-sub: 130-139, 150-159, 200-209
+# 9.10: 140-149, 190-199
+# 9.10-sub: 180-189
+# 9.11: 160-169,1100-1199
+# 9.12: 1200-1299
+LIBINTERFACE = 163
+LIBREVISION = 0
+LIBAGE = 0
diff --git a/lib/isccfg/dnsconf.c b/lib/isccfg/dnsconf.c
new file mode 100644
index 0000000..5d150c8
--- /dev/null
+++ b/lib/isccfg/dnsconf.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <isccfg/cfg.h>
+#include <isccfg/grammar.h>
+
+/*%
+ * A trusted key, as used in the "trusted-keys" statement.
+ */
+static cfg_tuplefielddef_t trustedkey_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "flags", &cfg_type_uint32, 0 },
+ { "protocol", &cfg_type_uint32, 0 },
+ { "algorithm", &cfg_type_uint32, 0 },
+ { "key", &cfg_type_qstring, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_trustedkey = {
+ "trustedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, trustedkey_fields
+};
+
+static cfg_type_t cfg_type_trustedkeys = {
+ "trusted-keys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_trustedkey
+};
+
+/*%
+ * Clauses that can be found within the top level of the dns.conf
+ * file only.
+ */
+static cfg_clausedef_t
+dnsconf_clauses[] = {
+ { "trusted-keys", &cfg_type_trustedkeys, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+
+/*% The top-level dns.conf syntax. */
+
+static cfg_clausedef_t *
+dnsconf_clausesets[] = {
+ dnsconf_clauses,
+ NULL
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_dnsconf = {
+ "dnsconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
+ &cfg_rep_map, dnsconf_clausesets
+};
diff --git a/lib/isccfg/include/Makefile.in b/lib/isccfg/include/Makefile.in
new file mode 100644
index 0000000..b2d2147
--- /dev/null
+++ b/lib/isccfg/include/Makefile.in
@@ -0,0 +1,17 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isccfg
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isccfg/include/isccfg/Makefile.in b/lib/isccfg/include/isccfg/Makefile.in
new file mode 100644
index 0000000..e0fde73
--- /dev/null
+++ b/lib/isccfg/include/isccfg/Makefile.in
@@ -0,0 +1,40 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+#
+# Only list headers that are to be installed and are not
+# machine generated. The latter are handled specially in the
+# install target below.
+#
+HEADERS = aclconf.h cfg.h dnsconf.h grammar.h log.h namedconf.h \
+ version.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isccfg
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/isccfg || exit 1; \
+ done
+
+uninstall::
+ for i in ${HEADERS}; do \
+ rm -f ${DESTDIR}${includedir}/isccfg/$$i || exit 1; \
+ done
diff --git a/lib/isccfg/include/isccfg/aclconf.h b/lib/isccfg/include/isccfg/aclconf.h
new file mode 100644
index 0000000..005827e
--- /dev/null
+++ b/lib/isccfg/include/isccfg/aclconf.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISCCFG_ACLCONF_H
+#define ISCCFG_ACLCONF_H 1
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/refcount.h>
+
+#include <isccfg/cfg.h>
+
+#ifdef HAVE_GEOIP
+#include <dns/geoip.h>
+#endif
+#include <dns/types.h>
+
+typedef struct cfg_aclconfctx {
+ ISC_LIST(dns_acl_t) named_acl_cache;
+ isc_mem_t *mctx;
+#ifdef HAVE_GEOIP
+ dns_geoip_databases_t *geoip;
+#endif
+ isc_refcount_t references;
+} cfg_aclconfctx_t;
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+cfg_aclconfctx_create(isc_mem_t *mctx, cfg_aclconfctx_t **ret);
+/*
+ * Creates and initializes an ACL configuration context.
+ */
+
+void
+cfg_aclconfctx_detach(cfg_aclconfctx_t **actxp);
+/*
+ * Removes a reference to an ACL configuration context; when references
+ * reaches zero, clears the contents and deallocate the structure.
+ */
+
+void
+cfg_aclconfctx_attach(cfg_aclconfctx_t *src, cfg_aclconfctx_t **dest);
+/*
+ * Attaches a pointer to an existing ACL configuration context.
+ */
+
+isc_result_t
+cfg_acl_fromconfig(const cfg_obj_t *caml, const cfg_obj_t *cctx,
+ isc_log_t *lctx, cfg_aclconfctx_t *ctx,
+ isc_mem_t *mctx, unsigned int nest_level,
+ dns_acl_t **target);
+
+isc_result_t
+cfg_acl_fromconfig2(const cfg_obj_t *caml, const cfg_obj_t *cctx,
+ isc_log_t *lctx, cfg_aclconfctx_t *ctx,
+ isc_mem_t *mctx, unsigned int nest_level,
+ uint16_t family, dns_acl_t **target);
+/*
+ * Construct a new dns_acl_t from configuration data in 'caml' and
+ * 'cctx'. Memory is allocated through 'mctx'.
+ *
+ * Any named ACLs referred to within 'caml' will be be converted
+ * into nested dns_acl_t objects. Multiple references to the same
+ * named ACLs will be converted into shared references to a single
+ * nested dns_acl_t object when the referring objects were created
+ * passing the same ACL configuration context 'ctx'.
+ *
+ * cfg_acl_fromconfig() is a backward-compatible version of
+ * cfg_acl_fromconfig2(), which allows an address family to be
+ * specified. If 'family' is not zero, then only addresses/prefixes
+ * of a matching family (AF_INET or AF_INET6) may be configured.
+ *
+ * On success, attach '*target' to the new dns_acl_t object.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCFG_ACLCONF_H */
diff --git a/lib/isccfg/include/isccfg/cfg.h b/lib/isccfg/include/isccfg/cfg.h
new file mode 100644
index 0000000..468ca29
--- /dev/null
+++ b/lib/isccfg/include/isccfg/cfg.h
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISCCFG_CFG_H
+#define ISCCFG_CFG_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isccfg/cfg.h
+ * \brief
+ * This is the new, table-driven, YACC-free configuration file parser.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+#include <isc/types.h>
+#include <isc/list.h>
+
+/***
+ *** Types
+ ***/
+
+/*%
+ * A configuration parser.
+ */
+typedef struct cfg_parser cfg_parser_t;
+
+/*%
+ * A configuration type definition object. There is a single
+ * static cfg_type_t object for each data type supported by
+ * the configuration parser.
+ */
+typedef struct cfg_type cfg_type_t;
+
+/*%
+ * A configuration object. This is the basic building block of the
+ * configuration parse tree. It contains a value (which may be
+ * of one of several types) and information identifying the file
+ * and line number the value came from, for printing error
+ * messages.
+ */
+typedef struct cfg_obj cfg_obj_t;
+
+/*%
+ * A configuration object list element.
+ */
+typedef struct cfg_listelt cfg_listelt_t;
+
+/*%
+ * A callback function to be called when parsing an option
+ * that needs to be interpreted at parsing time, like
+ * "directory".
+ */
+typedef isc_result_t
+(*cfg_parsecallback_t)(const char *clausename, const cfg_obj_t *obj, void *arg);
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+void
+cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest);
+/*%<
+ * Reference a parser object.
+ */
+
+isc_result_t
+cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret);
+/*%<
+ * Create a configuration file parser. Any warning and error
+ * messages will be logged to 'lctx'.
+ *
+ * The parser object returned can be used for a single call
+ * to cfg_parse_file() or cfg_parse_buffer(). It must not
+ * be reused for parsing multiple files or buffers.
+ */
+
+void
+cfg_parser_setcallback(cfg_parser_t *pctx,
+ cfg_parsecallback_t callback,
+ void *arg);
+/*%<
+ * Make the parser call 'callback' whenever it encounters
+ * a configuration clause with the callback attribute,
+ * passing it the clause name, the clause value,
+ * and 'arg' as arguments.
+ *
+ * To restore the default of not invoking callbacks, pass
+ * callback==NULL and arg==NULL.
+ */
+
+isc_result_t
+cfg_parse_file(cfg_parser_t *pctx, const char *file,
+ const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer,
+ const cfg_type_t *type, cfg_obj_t **ret);
+isc_result_t
+cfg_parse_buffer2(cfg_parser_t *pctx, isc_buffer_t *buffer,
+ const char *file, const cfg_type_t *type,
+ cfg_obj_t **ret);
+isc_result_t
+cfg_parse_buffer3(cfg_parser_t *pctx, isc_buffer_t *buffer,
+ const char *file, unsigned int line,
+ const cfg_type_t *type, cfg_obj_t **ret);
+isc_result_t
+cfg_parse_buffer4(cfg_parser_t *pctx, isc_buffer_t *buffer,
+ const char *file, unsigned int line,
+ const cfg_type_t *type, unsigned int flags,
+ cfg_obj_t **ret);
+/*%<
+ * Read a configuration containing data of type 'type'
+ * and make '*ret' point to its parse tree.
+ *
+ * The configuration is read from the file 'filename'
+ * (isc_parse_file()) or the buffer 'buffer'
+ * (isc_parse_buffer()).
+ *
+ * If 'file' is not NULL, it is the name of the file, or a name to use
+ * for the buffer in place of the filename, when logging errors.
+ *
+ * If 'line' is not 0, then it is the beginning line number to report
+ * when logging errors. This is useful when passing text that has been
+ * read from the middle of a file.
+ *
+ * Returns an error if the file or buffer does not parse correctly.
+ *
+ * Requires:
+ *\li "filename" is valid.
+ *\li "mem" is valid.
+ *\li "type" is valid.
+ *\li "cfg" is non-NULL and "*cfg" is NULL.
+ *\li "flags" be one or more of CFG_PCTX_NODEPRECATED or zero.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS - success
+ *\li #ISC_R_NOMEMORY - no memory available
+ *\li #ISC_R_INVALIDFILE - file doesn't exist or is unreadable
+ *\li others - file contains errors
+ */
+
+isc_result_t
+cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj,
+ cfg_obj_t *obj, const char *clause);
+/*%<
+ * Add the object 'obj' to the specified clause in mapbody 'mapobj'.
+ * Used for adding new zones.
+ *
+ * Require:
+ * \li 'obj' is a valid cfg_obj_t.
+ * \li 'mapobj' is a valid cfg_obj_t of type map.
+ * \li 'pctx' is a valid cfg_parser_t.
+ */
+
+void
+cfg_parser_reset(cfg_parser_t *pctx);
+/*%<
+ * Reset an existing parser so it can be re-used for a new file or
+ * buffer.
+ */
+
+void
+cfg_parser_destroy(cfg_parser_t **pctxp);
+/*%<
+ * Remove a reference to a configuration parser; destroy it if there are no
+ * more references.
+ */
+
+bool
+cfg_obj_isvoid(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of void type (e.g., an optional
+ * value not specified).
+ */
+
+bool
+cfg_obj_ismap(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of a map type.
+ */
+
+bool
+cfg_obj_isfixedpoint(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of a fixedpoint type.
+ */
+
+bool
+cfg_obj_ispercentage(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of a percentage type.
+ */
+
+isc_result_t
+cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj);
+/*%<
+ * Extract an element from a configuration object, which
+ * must be of a map type.
+ *
+ * Requires:
+ * \li 'mapobj' points to a valid configuration object of a map type.
+ * \li 'name' points to a null-terminated string.
+ * \li 'obj' is non-NULL and '*obj' is NULL.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS - success
+ * \li #ISC_R_NOTFOUND - name not found in map
+ */
+
+const cfg_obj_t *
+cfg_map_getname(const cfg_obj_t *mapobj);
+/*%<
+ * Get the name of a named map object, like a server "key" clause.
+ *
+ * Requires:
+ * \li 'mapobj' points to a valid configuration object of a map type.
+ *
+ * Returns:
+ * \li A pointer to a configuration object naming the map object,
+ * or NULL if the map object does not have a name.
+ */
+
+unsigned int
+cfg_map_count(const cfg_obj_t *mapobj);
+/*%<
+ * Get the number of elements defined in the symbol table of a map object.
+ *
+ * Requires:
+ * \li 'mapobj' points to a valid configuration object of a map type.
+ *
+ * Returns:
+ * \li The number of elements in the map object.
+ */
+
+bool
+cfg_obj_istuple(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of a map type.
+ */
+
+const cfg_obj_t *
+cfg_tuple_get(const cfg_obj_t *tupleobj, const char *name);
+/*%<
+ * Extract an element from a configuration object, which
+ * must be of a tuple type.
+ *
+ * Requires:
+ * \li 'tupleobj' points to a valid configuration object of a tuple type.
+ * \li 'name' points to a null-terminated string naming one of the
+ *\li fields of said tuple type.
+ */
+
+bool
+cfg_obj_isuint32(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of integer type.
+ */
+
+uint32_t
+cfg_obj_asuint32(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object of 32-bit integer type.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of 32-bit integer type.
+ *
+ * Returns:
+ * \li A 32-bit unsigned integer.
+ */
+
+bool
+cfg_obj_isuint64(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of integer type.
+ */
+
+uint64_t
+cfg_obj_asuint64(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object of 64-bit integer type.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of 64-bit integer type.
+ *
+ * Returns:
+ * \li A 64-bit unsigned integer.
+ */
+
+uint32_t
+cfg_obj_asfixedpoint(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object of fixed point number.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of fixed point type.
+ *
+ * Returns:
+ * \li A 32-bit unsigned integer.
+ */
+
+uint32_t
+cfg_obj_aspercentage(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object of percentage
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of percentage type.
+ *
+ * Returns:
+ * \li A 32-bit unsigned integer.
+ */
+
+bool
+cfg_obj_isstring(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of string type.
+ */
+
+const char *
+cfg_obj_asstring(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object of a string type
+ * as a null-terminated string.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of a string type.
+ *
+ * Returns:
+ * \li A pointer to a null terminated string.
+ */
+
+bool
+cfg_obj_isboolean(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of a boolean type.
+ */
+
+bool
+cfg_obj_asboolean(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object of a boolean type.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of a boolean type.
+ *
+ * Returns:
+ * \li A boolean value.
+ */
+
+bool
+cfg_obj_issockaddr(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is a socket address.
+ */
+
+const isc_sockaddr_t *
+cfg_obj_assockaddr(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object representing a socket address.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of a socket address type.
+ *
+ * Returns:
+ * \li A pointer to a sockaddr. The sockaddr must be copied by the caller
+ * if necessary.
+ */
+
+isc_dscp_t
+cfg_obj_getdscp(const cfg_obj_t *obj);
+/*%<
+ * Returns the DSCP value of a configuration object representing a
+ * socket address.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of a
+ * socket address type.
+ *
+ * Returns:
+ * \li DSCP value associated with a sockaddr, or -1.
+ */
+
+bool
+cfg_obj_isnetprefix(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is a network prefix.
+ */
+
+void
+cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
+ unsigned int *prefixlen);
+/*%<
+ * Gets the value of a configuration object representing a network
+ * prefix. The network address is returned through 'netaddr' and the
+ * prefix length in bits through 'prefixlen'.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of network prefix type.
+ *\li 'netaddr' and 'prefixlen' are non-NULL.
+ */
+
+bool
+cfg_obj_islist(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of list type.
+ */
+
+const cfg_listelt_t *
+cfg_list_first(const cfg_obj_t *obj);
+/*%<
+ * Returns the first list element in a configuration object of a list type.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of a list type or NULL.
+ *
+ * Returns:
+ * \li A pointer to a cfg_listelt_t representing the first list element,
+ * or NULL if the list is empty or nonexistent.
+ */
+
+const cfg_listelt_t *
+cfg_list_next(const cfg_listelt_t *elt);
+/*%<
+ * Returns the next element of a list of configuration objects.
+ *
+ * Requires:
+ * \li 'elt' points to cfg_listelt_t obtained from cfg_list_first() or
+ * a previous call to cfg_list_next().
+ *
+ * Returns:
+ * \li A pointer to a cfg_listelt_t representing the next element,
+ * or NULL if there are no more elements.
+ */
+
+unsigned int
+cfg_list_length(const cfg_obj_t *obj, bool recurse);
+/*%<
+ * Returns the length of a list of configure objects. If obj is
+ * not a list, returns 0. If recurse is true, add in the length of
+ * all contained lists.
+ */
+
+cfg_obj_t *
+cfg_listelt_value(const cfg_listelt_t *elt);
+/*%<
+ * Returns the configuration object associated with cfg_listelt_t.
+ *
+ * Requires:
+ * \li 'elt' points to cfg_listelt_t obtained from cfg_list_first() or
+ * cfg_list_next().
+ *
+ * Returns:
+ * \li A non-NULL pointer to a configuration object.
+ */
+
+void
+cfg_print(const cfg_obj_t *obj,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure);
+void
+cfg_printx(const cfg_obj_t *obj, unsigned int flags,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure);
+
+#define CFG_PRINTER_XKEY 0x1 /* '?' out shared keys. */
+#define CFG_PRINTER_ONELINE 0x2 /* print config as a single line */
+
+/*%<
+ * Print the configuration object 'obj' by repeatedly calling the
+ * function 'f', passing 'closure' and a region of text starting
+ * at 'text' and comprising 'textlen' characters.
+ *
+ * If CFG_PRINTER_XKEY the contents of shared keys will be obscured
+ * by replacing them with question marks ('?')
+ */
+
+void
+cfg_print_grammar(const cfg_type_t *type,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure);
+/*%<
+ * Print a summary of the grammar of the configuration type 'type'.
+ */
+
+bool
+cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type);
+/*%<
+ * Return true iff 'obj' is of type 'type'.
+ */
+
+void
+cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest);
+/*%<
+ * Reference a configuration object.
+ */
+
+void
+cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **obj);
+/*%<
+ * Delete a reference to a configuration object; destroy the object if
+ * there are no more references.
+ *
+ * Require:
+ * \li '*obj' is a valid cfg_obj_t.
+ * \li 'pctx' is a valid cfg_parser_t.
+ */
+
+void
+cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level,
+ const char *fmt, ...)
+ ISC_FORMAT_PRINTF(4, 5);
+/*%<
+ * Log a message concerning configuration object 'obj' to the logging
+ * channel of 'pctx', at log level 'level'. The message will be prefixed
+ * with the file name(s) and line number where 'obj' was defined.
+ */
+
+const char *
+cfg_obj_file(const cfg_obj_t *obj);
+/*%<
+ * Return the file that defined this object.
+ */
+
+unsigned int
+cfg_obj_line(const cfg_obj_t *obj);
+/*%<
+ * Return the line in file where this object was defined.
+ */
+
+const char *
+cfg_map_firstclause(const cfg_type_t *map, const void **clauses,
+ unsigned int *idx);
+const char *
+cfg_map_nextclause(const cfg_type_t *map, const void **clauses,
+ unsigned int *idx);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCFG_CFG_H */
diff --git a/lib/isccfg/include/isccfg/dnsconf.h b/lib/isccfg/include/isccfg/dnsconf.h
new file mode 100644
index 0000000..51221d3
--- /dev/null
+++ b/lib/isccfg/include/isccfg/dnsconf.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISCCFG_DNSCONF_H
+#define ISCCFG_DNSCONF_H 1
+
+
+/*! \file
+ * \brief
+ * This module defines the named.conf, rndc.conf, and rndc.key grammars.
+ */
+
+#include <isccfg/cfg.h>
+
+/*
+ * Configuration object types.
+ */
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_dnsconf;
+/*%< A complete dns.conf file. */
+
+#endif /* ISCCFG_DNSCONF_H */
diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h
new file mode 100644
index 0000000..9e0732a
--- /dev/null
+++ b/lib/isccfg/include/isccfg/grammar.h
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISCCFG_GRAMMAR_H
+#define ISCCFG_GRAMMAR_H 1
+
+/*! \file isccfg/grammar.h */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/lex.h>
+#include <isc/netaddr.h>
+#include <isc/refcount.h>
+#include <isc/sockaddr.h>
+#include <isc/region.h>
+#include <isc/types.h>
+
+#include <isccfg/cfg.h>
+
+/*
+ * Definitions shared between the configuration parser
+ * and the grammars; not visible to users of the parser.
+ */
+
+/*% Clause may occur multiple times (e.g., "zone") */
+#define CFG_CLAUSEFLAG_MULTI 0x00000001
+/*% Clause is obsolete */
+#define CFG_CLAUSEFLAG_OBSOLETE 0x00000002
+/*% Clause is not implemented, and may never be */
+#define CFG_CLAUSEFLAG_NOTIMP 0x00000004
+/*% Clause is not implemented yet */
+#define CFG_CLAUSEFLAG_NYI 0x00000008
+/*% Default value has changed since earlier release */
+#define CFG_CLAUSEFLAG_NEWDEFAULT 0x00000010
+/*%
+ * Clause needs to be interpreted during parsing
+ * by calling a callback function, like the
+ * "directory" option.
+ */
+#define CFG_CLAUSEFLAG_CALLBACK 0x00000020
+/*% A option that is only used in testing. */
+#define CFG_CLAUSEFLAG_TESTONLY 0x00000040
+/*% A configuration option that was not configured at compile time. */
+#define CFG_CLAUSEFLAG_NOTCONFIGURED 0x00000080
+/*% A option for a experimental feature. */
+#define CFG_CLAUSEFLAG_EXPERIMENTAL 0x00000100
+/*% A configuration option that is ineffective due to
+ * compile time options, but is harmless. */
+#define CFG_CLAUSEFLAG_NOOP 0x00000200
+/*% Clause is obsolete in a future release */
+#define CFG_CLAUSEFLAG_DEPRECATED 0x00000400
+
+/*%
+ * Zone types for which a clause is valid:
+ * These share space with CFG_CLAUSEFLAG values, but count
+ * down from the top.
+ */
+#define CFG_ZONE_MASTER 0x80000000
+#define CFG_ZONE_SLAVE 0x40000000
+#define CFG_ZONE_STUB 0x20000000
+#define CFG_ZONE_HINT 0x10000000
+#define CFG_ZONE_FORWARD 0x08000000
+#define CFG_ZONE_STATICSTUB 0x04000000
+#define CFG_ZONE_REDIRECT 0x02000000
+#define CFG_ZONE_DELEGATION 0x01000000
+#define CFG_ZONE_INVIEW 0x00800000
+
+typedef struct cfg_clausedef cfg_clausedef_t;
+typedef struct cfg_tuplefielddef cfg_tuplefielddef_t;
+typedef struct cfg_printer cfg_printer_t;
+typedef ISC_LIST(cfg_listelt_t) cfg_list_t;
+typedef struct cfg_map cfg_map_t;
+typedef struct cfg_rep cfg_rep_t;
+
+/*
+ * Function types for configuration object methods
+ */
+
+typedef isc_result_t (*cfg_parsefunc_t)(cfg_parser_t *, const cfg_type_t *type,
+ cfg_obj_t **);
+typedef void (*cfg_printfunc_t)(cfg_printer_t *, const cfg_obj_t *);
+typedef void (*cfg_docfunc_t)(cfg_printer_t *, const cfg_type_t *);
+typedef void (*cfg_freefunc_t)(cfg_parser_t *, cfg_obj_t *);
+
+/*
+ * Structure definitions
+ */
+
+/*%
+ * A configuration printer object. This is an abstract
+ * interface to a destination to which text can be printed
+ * by calling the function 'f'.
+ */
+struct cfg_printer {
+ void (*f)(void *closure, const char *text, int textlen);
+ void *closure;
+ int indent;
+ int flags;
+};
+
+/*% A clause definition. */
+struct cfg_clausedef {
+ const char *name;
+ cfg_type_t *type;
+ unsigned int flags;
+};
+
+/*% A tuple field definition. */
+struct cfg_tuplefielddef {
+ const char *name;
+ cfg_type_t *type;
+ unsigned int flags;
+};
+
+/*% A configuration object type definition. */
+struct cfg_type {
+ const char *name; /*%< For debugging purposes only */
+ cfg_parsefunc_t parse;
+ cfg_printfunc_t print;
+ cfg_docfunc_t doc; /*%< Print grammar description */
+ cfg_rep_t * rep; /*%< Data representation */
+ const void * of; /*%< Additional data for meta-types */
+};
+
+/*% A keyword-type definition, for things like "port <integer>". */
+typedef struct {
+ const char *name;
+ const cfg_type_t *type;
+} keyword_type_t;
+
+struct cfg_map {
+ cfg_obj_t *id; /*%< Used for 'named maps' like keys, zones, &c */
+ const cfg_clausedef_t * const *clausesets; /*%< The clauses that
+ can occur in this map;
+ used for printing */
+ isc_symtab_t *symtab;
+};
+
+typedef struct cfg_netprefix cfg_netprefix_t;
+
+struct cfg_netprefix {
+ isc_netaddr_t address; /* IP4/IP6 */
+ unsigned int prefixlen;
+};
+
+/*%
+ * A configuration data representation.
+ */
+struct cfg_rep {
+ const char * name; /*%< For debugging only */
+ cfg_freefunc_t free; /*%< How to free this kind of data. */
+};
+
+/*%
+ * A configuration object. This is the main building block
+ * of the configuration parse tree.
+ */
+
+struct cfg_obj {
+ const cfg_type_t *type;
+ union {
+ uint32_t uint32;
+ uint64_t uint64;
+ isc_textregion_t string; /*%< null terminated, too */
+ bool boolean;
+ cfg_map_t map;
+ cfg_list_t list;
+ cfg_obj_t ** tuple;
+ isc_sockaddr_t sockaddr;
+ struct {
+ isc_sockaddr_t sockaddr;
+ isc_dscp_t dscp;
+ } sockaddrdscp;
+ cfg_netprefix_t netprefix;
+ } value;
+ isc_refcount_t references; /*%< reference counter */
+ const char * file;
+ unsigned int line;
+ cfg_parser_t * pctx;
+};
+
+
+/*% A list element. */
+struct cfg_listelt {
+ cfg_obj_t *obj;
+ ISC_LINK(cfg_listelt_t) link;
+};
+
+/*% The parser object. */
+struct cfg_parser {
+ isc_mem_t * mctx;
+ isc_log_t * lctx;
+ isc_lex_t * lexer;
+ unsigned int errors;
+ unsigned int warnings;
+ isc_token_t token;
+
+ /*% We are at the end of all input. */
+ bool seen_eof;
+
+ /*% The current token has been pushed back. */
+ bool ungotten;
+
+ /*%
+ * The stack of currently active files, represented
+ * as a configuration list of configuration strings.
+ * The head is the top-level file, subsequent elements
+ * (if any) are the nested include files, and the
+ * last element is the file currently being parsed.
+ */
+ cfg_obj_t * open_files;
+
+ /*%
+ * Names of files that we have parsed and closed
+ * and were previously on the open_file list.
+ * We keep these objects around after closing
+ * the files because the file names may still be
+ * referenced from other configuration objects
+ * for use in reporting semantic errors after
+ * parsing is complete.
+ */
+ cfg_obj_t * closed_files;
+
+ /*%
+ * Name of a buffer being parsed; used only for
+ * logging.
+ */
+ char const * buf_name;
+
+ /*%
+ * Current line number. We maintain our own
+ * copy of this so that it is available even
+ * when a file has just been closed.
+ */
+ unsigned int line;
+
+ /*%
+ * Parser context flags, used for maintaining state
+ * from one token to the next.
+ */
+ unsigned int flags;
+
+ /*%< Reference counter */
+ isc_refcount_t references;
+
+ cfg_parsecallback_t callback;
+ void *callbackarg;
+};
+
+/* Parser context flags */
+#define CFG_PCTX_SKIP 0x1
+#define CFG_PCTX_NODEPRECATED 0x2
+
+/*@{*/
+/*%
+ * Flags defining whether to accept certain types of network addresses.
+ */
+#define CFG_ADDR_V4OK 0x00000001
+#define CFG_ADDR_V4PREFIXOK 0x00000002
+#define CFG_ADDR_V6OK 0x00000004
+#define CFG_ADDR_WILDOK 0x00000008
+#define CFG_ADDR_DSCPOK 0x00000010
+#define CFG_ADDR_MASK (CFG_ADDR_V6OK|CFG_ADDR_V4OK)
+/*@}*/
+
+/*@{*/
+/*%
+ * Predefined data representation types.
+ */
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_uint32;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_uint64;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_string;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_boolean;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_map;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_list;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_tuple;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_sockaddr;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_netprefix;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_void;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_fixedpoint;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_percentage;
+/*@}*/
+
+/*@{*/
+/*%
+ * Predefined configuration object types.
+ */
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_boolean;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_uint32;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_uint64;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_qstring;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_astring;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_ustring;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sstring;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_bracketed_text;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddr;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddrdscp;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr4;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr4wild;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr6;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr6wild;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netprefix;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_void;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_token;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_unsupported;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_fixedpoint;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_percentage;
+/*@}*/
+
+isc_result_t
+cfg_gettoken(cfg_parser_t *pctx, int options);
+
+isc_result_t
+cfg_peektoken(cfg_parser_t *pctx, int options);
+
+void
+cfg_ungettoken(cfg_parser_t *pctx);
+
+#define CFG_LEXOPT_QSTRING (ISC_LEXOPT_QSTRING | ISC_LEXOPT_QSTRINGMULTILINE)
+
+isc_result_t
+cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
+
+void
+cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u);
+
+isc_result_t
+cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+isc_result_t
+cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+isc_result_t
+cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na);
+
+void
+cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na);
+
+bool
+cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags);
+
+isc_result_t
+cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port);
+
+isc_result_t
+cfg_parse_dscp(cfg_parser_t *pctx, isc_dscp_t *dscp);
+
+isc_result_t
+cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_special(cfg_parser_t *pctx, int special);
+/*%< Parse a required special character 'special'. */
+
+isc_result_t
+cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
+
+isc_result_t
+cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
+
+isc_result_t
+cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
+ cfg_listelt_t **ret);
+
+isc_result_t
+cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+isc_result_t
+cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type);
+
+void
+cfg_print_chars(cfg_printer_t *pctx, const char *text, int len);
+/*%< Print 'len' characters at 'text' */
+
+void
+cfg_print_cstr(cfg_printer_t *pctx, const char *s);
+/*%< Print the null-terminated string 's' */
+
+isc_result_t
+cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **
+ret);
+
+void
+cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_parse_fixedpoint(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret);
+
+void
+cfg_print_fixedpoint(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+isc_result_t
+cfg_parse_percentage(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret);
+
+void
+cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+isc_result_t
+cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type);
+/*%<
+ * Print a description of the grammar of an arbitrary configuration
+ * type 'type'
+ */
+
+void
+cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type);
+/*%<
+ * Document the type 'type' as a terminal by printing its
+ * name in angle brackets, e.g., &lt;uint32>.
+ */
+
+void
+cfg_parser_error(cfg_parser_t *pctx, unsigned int flags,
+ const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4);
+/*!
+ * Pass one of these flags to cfg_parser_error() to include the
+ * token text in log message.
+ */
+#define CFG_LOG_NEAR 0x00000001 /*%< Say "near <token>" */
+#define CFG_LOG_BEFORE 0x00000002 /*%< Say "before <token>" */
+#define CFG_LOG_NOPREP 0x00000004 /*%< Say just "<token>" */
+
+void
+cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags,
+ const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4);
+
+bool
+cfg_is_enum(const char *s, const char *const *enums);
+/*%< Return true iff the string 's' is one of the strings in 'enums' */
+
+bool
+cfg_clause_validforzone(const char *name, unsigned int ztype);
+/*%<
+ * Check whether an option is legal for the specified zone type.
+ */
+
+void
+cfg_print_zonegrammar(const unsigned int zonetype,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure);
+/*%<
+ * Print a summary of the grammar of the zone type represented by
+ * 'zonetype'.
+ */
+
+void
+cfg_print_clauseflags(cfg_printer_t *pctx, unsigned int flags);
+/*%<
+ * Print clause flags (e.g. "obsolete", "not implemented", etc) in
+ * human readable form
+ */
+
+void
+cfg_print_indent(cfg_printer_t *pctx);
+/*%<
+ * Print the necessary indent required by the current settings of 'pctx'.
+ */
+
+#endif /* ISCCFG_GRAMMAR_H */
diff --git a/lib/isccfg/include/isccfg/log.h b/lib/isccfg/include/isccfg/log.h
new file mode 100644
index 0000000..5c7fe95
--- /dev/null
+++ b/lib/isccfg/include/isccfg/log.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISCCFG_LOG_H
+#define ISCCFG_LOG_H 1
+
+/*! \file isccfg/log.h */
+
+#include <isc/lang.h>
+#include <isc/log.h>
+
+LIBISCCFG_EXTERNAL_DATA extern isc_logcategory_t cfg_categories[];
+LIBISCCFG_EXTERNAL_DATA extern isc_logmodule_t cfg_modules[];
+
+#define CFG_LOGCATEGORY_CONFIG (&cfg_categories[0])
+
+#define CFG_LOGMODULE_PARSER (&cfg_modules[0])
+
+ISC_LANG_BEGINDECLS
+
+void
+cfg_log_init(isc_log_t *lctx);
+/*%<
+ * Make the libisccfg categories and modules available for use with the
+ * ISC logging library.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ *\li cfg_log_init() is called only once.
+ *
+ * Ensures:
+ * \li The categories and modules defined above are available for
+ * use by isc_log_usechannnel() and isc_log_write().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCFG_LOG_H */
diff --git a/lib/isccfg/include/isccfg/namedconf.h b/lib/isccfg/include/isccfg/namedconf.h
new file mode 100644
index 0000000..0a191c9
--- /dev/null
+++ b/lib/isccfg/include/isccfg/namedconf.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#ifndef ISCCFG_NAMEDCONF_H
+#define ISCCFG_NAMEDCONF_H 1
+
+/*! \file isccfg/namedconf.h
+ * \brief
+ * This module defines the named.conf, rndc.conf, and rndc.key grammars.
+ */
+
+#include <isccfg/cfg.h>
+
+/*
+ * Configuration object types.
+ */
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_namedconf;
+/*%< A complete named.conf file. */
+
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_bindkeys;
+/*%< A bind.keys file. */
+
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_newzones;
+/*%< A new-zones file (for zones added by 'rndc addzone'). */
+
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_addzoneconf;
+/*%< A single zone passed via the addzone rndc command. */
+
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_rndcconf;
+/*%< A complete rndc.conf file. */
+
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_rndckey;
+/*%< A complete rndc.key file. */
+
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sessionkey;
+/*%< A complete session.key file. */
+
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_keyref;
+/*%< A key reference, used as an ACL element */
+
+/*%< An EDNS client subnet address, used as an ACL element */
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_ecsprefix;
+
+/*%< Zone options */
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_zoneopts;
+
+#endif /* ISCCFG_NAMEDCONF_H */
diff --git a/lib/isccfg/include/isccfg/version.h b/lib/isccfg/include/isccfg/version.h
new file mode 100644
index 0000000..2e9a139
--- /dev/null
+++ b/lib/isccfg/include/isccfg/version.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file isccfg/version.h */
+
+#include <isc/platform.h>
+
+LIBISCCFG_EXTERNAL_DATA extern const char cfg_version[];
+
+LIBISCCFG_EXTERNAL_DATA extern const unsigned int cfg_libinterface;
+LIBISCCFG_EXTERNAL_DATA extern const unsigned int cfg_librevision;
+LIBISCCFG_EXTERNAL_DATA extern const unsigned int cfg_libage;
diff --git a/lib/isccfg/log.c b/lib/isccfg/log.c
new file mode 100644
index 0000000..4fd5e57
--- /dev/null
+++ b/lib/isccfg/log.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/util.h>
+
+#include <isccfg/log.h>
+
+/*%
+ * When adding a new category, be sure to add the appropriate
+ * \#define to <isccfg/log.h>.
+ */
+LIBISCCFG_EXTERNAL_DATA isc_logcategory_t cfg_categories[] = {
+ { "config", 0 },
+ { NULL, 0 }
+};
+
+/*%
+ * When adding a new module, be sure to add the appropriate
+ * \#define to <isccfg/log.h>.
+ */
+LIBISCCFG_EXTERNAL_DATA isc_logmodule_t cfg_modules[] = {
+ { "isccfg/parser", 0 },
+ { NULL, 0 }
+};
+
+void
+cfg_log_init(isc_log_t *lctx) {
+ REQUIRE(lctx != NULL);
+
+ isc_log_registercategories(lctx, cfg_categories);
+ isc_log_registermodules(lctx, cfg_modules);
+}
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
new file mode 100644
index 0000000..cd797a6
--- /dev/null
+++ b/lib/isccfg/namedconf.c
@@ -0,0 +1,4013 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/ttl.h>
+#include <dns/result.h>
+
+#include <isccfg/cfg.h>
+#include <isccfg/grammar.h>
+#include <isccfg/log.h>
+#include <isccfg/namedconf.h>
+
+#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
+
+/*% Check a return value. */
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto cleanup; \
+ } while (0)
+
+/*% Clean up a configuration object if non-NULL. */
+#define CLEANUP_OBJ(obj) \
+ do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
+
+
+/*%
+ * Forward declarations of static functions.
+ */
+
+static isc_result_t
+parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
+ const cfg_type_t *othertype, cfg_obj_t **ret);
+
+static void
+doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype,
+ const cfg_type_t *othertype);
+
+static isc_result_t
+parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+static isc_result_t
+parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret);
+
+static isc_result_t
+parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret);
+static void
+print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+static void
+doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type);
+
+static void
+print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+static void
+doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
+
+static void
+doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
+
+#ifdef HAVE_GEOIP
+static isc_result_t
+parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+static void
+print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+static void
+doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type);
+#endif /* HAVE_GEOIP */
+
+static cfg_type_t cfg_type_acl;
+static cfg_type_t cfg_type_addrmatchelt;
+static cfg_type_t cfg_type_bracketed_aml;
+static cfg_type_t cfg_type_bracketed_dscpsockaddrlist;
+static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
+static cfg_type_t cfg_type_bracketed_sockaddrlist;
+static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
+static cfg_type_t cfg_type_controls;
+static cfg_type_t cfg_type_controls_sockaddr;
+static cfg_type_t cfg_type_destinationlist;
+static cfg_type_t cfg_type_dialuptype;
+static cfg_type_t cfg_type_dlz;
+static cfg_type_t cfg_type_dnstap;
+static cfg_type_t cfg_type_dnstapoutput;
+static cfg_type_t cfg_type_dyndb;
+static cfg_type_t cfg_type_filter_aaaa;
+static cfg_type_t cfg_type_ixfrdifftype;
+static cfg_type_t cfg_type_key;
+static cfg_type_t cfg_type_logfile;
+static cfg_type_t cfg_type_logging;
+static cfg_type_t cfg_type_logseverity;
+static cfg_type_t cfg_type_lwres;
+static cfg_type_t cfg_type_masterselement;
+static cfg_type_t cfg_type_maxttl;
+static cfg_type_t cfg_type_minimal;
+static cfg_type_t cfg_type_nameportiplist;
+static cfg_type_t cfg_type_negated;
+static cfg_type_t cfg_type_notifytype;
+static cfg_type_t cfg_type_optional_allow;
+static cfg_type_t cfg_type_optional_class;
+static cfg_type_t cfg_type_optional_dscp;
+static cfg_type_t cfg_type_optional_facility;
+static cfg_type_t cfg_type_optional_keyref;
+static cfg_type_t cfg_type_optional_port;
+static cfg_type_t cfg_type_optional_uint32;
+static cfg_type_t cfg_type_options;
+static cfg_type_t cfg_type_portiplist;
+static cfg_type_t cfg_type_querysource4;
+static cfg_type_t cfg_type_querysource6;
+static cfg_type_t cfg_type_querysource;
+static cfg_type_t cfg_type_server;
+static cfg_type_t cfg_type_server_key_kludge;
+static cfg_type_t cfg_type_size;
+static cfg_type_t cfg_type_sizenodefault;
+static cfg_type_t cfg_type_sizeorpercent;
+static cfg_type_t cfg_type_sizeval;
+static cfg_type_t cfg_type_sockaddr4wild;
+static cfg_type_t cfg_type_sockaddr6wild;
+static cfg_type_t cfg_type_statschannels;
+static cfg_type_t cfg_type_ttlval;
+static cfg_type_t cfg_type_view;
+static cfg_type_t cfg_type_viewopts;
+static cfg_type_t cfg_type_zone;
+
+/*% tkey-dhkey */
+
+static cfg_tuplefielddef_t tkey_dhkey_fields[] = {
+ { "name", &cfg_type_qstring, 0 },
+ { "keyid", &cfg_type_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_tkey_dhkey = {
+ "tkey-dhkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, tkey_dhkey_fields
+};
+
+/*% listen-on */
+
+static cfg_tuplefielddef_t listenon_fields[] = {
+ { "port", &cfg_type_optional_port, 0 },
+ { "dscp", &cfg_type_optional_dscp, 0 },
+ { "acl", &cfg_type_bracketed_aml, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_listenon = {
+ "listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, listenon_fields
+};
+
+/*% acl */
+
+static cfg_tuplefielddef_t acl_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "value", &cfg_type_bracketed_aml, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_acl = {
+ "acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, acl_fields
+};
+
+/*% masters */
+static cfg_tuplefielddef_t masters_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "port", &cfg_type_optional_port, 0 },
+ { "dscp", &cfg_type_optional_dscp, 0 },
+ { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_masters = {
+ "masters", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, masters_fields
+};
+
+/*%
+ * "sockaddrkeylist", a list of socket addresses with optional keys
+ * and an optional default port, as used in the masters option.
+ * E.g.,
+ * "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
+ */
+
+static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
+ { "masterselement", &cfg_type_masterselement, 0 },
+ { "key", &cfg_type_optional_keyref, 0 },
+ { NULL, NULL, 0 },
+};
+
+static cfg_type_t cfg_type_namesockaddrkey = {
+ "namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, namesockaddrkey_fields
+};
+
+static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
+ "bracketed_namesockaddrkeylist", cfg_parse_bracketed_list,
+ cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
+ &cfg_type_namesockaddrkey
+};
+
+static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
+ { "port", &cfg_type_optional_port, 0 },
+ { "dscp", &cfg_type_optional_dscp, 0 },
+ { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_namesockaddrkeylist = {
+ "sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, namesockaddrkeylist_fields
+};
+
+/*%
+ * A list of socket addresses with an optional default port, as used
+ * in the lwresd 'listen-on' option. E.g., "{ 10.0.0.1; 1::2 port 69; }"
+ */
+static cfg_tuplefielddef_t portiplist_fields[] = {
+ { "port", &cfg_type_optional_port, 0 },
+ { "dscp", &cfg_type_optional_dscp, 0 },
+ { "addresses", &cfg_type_bracketed_dscpsockaddrlist, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_portiplist = {
+ "portiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, portiplist_fields
+};
+
+/*%
+ * A public key, as in the "pubkey" statement.
+ */
+static cfg_tuplefielddef_t pubkey_fields[] = {
+ { "flags", &cfg_type_uint32, 0 },
+ { "protocol", &cfg_type_uint32, 0 },
+ { "algorithm", &cfg_type_uint32, 0 },
+ { "key", &cfg_type_qstring, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_pubkey = {
+ "pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, pubkey_fields
+};
+
+/*%
+ * A list of RR types, used in grant statements.
+ * Note that the old parser allows quotes around the RR type names.
+ */
+static cfg_type_t cfg_type_rrtypelist = {
+ "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist,
+ cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring
+};
+
+static const char *mode_enums[] = { "deny", "grant", NULL };
+static cfg_type_t cfg_type_mode = {
+ "mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &mode_enums
+};
+
+static isc_result_t
+parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "zonesub") == 0) {
+ pctx->flags |= CFG_PCTX_SKIP;
+ }
+ return (cfg_parse_enum(pctx, type, ret));
+
+ cleanup:
+ return (result);
+}
+
+static isc_result_t
+parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+
+ if ((pctx->flags & CFG_PCTX_SKIP) != 0) {
+ pctx->flags &= ~CFG_PCTX_SKIP;
+ CHECK(cfg_parse_void(pctx, NULL, &obj));
+ } else
+ result = cfg_parse_astring(pctx, type, &obj);
+
+ *ret = obj;
+ cleanup:
+ return (result);
+}
+
+static void
+doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) {
+ cfg_print_cstr(pctx, "[ ");
+ cfg_doc_obj(pctx, type->of);
+ cfg_print_cstr(pctx, " ]");
+}
+
+static const char *matchtype_enums[] = {
+ "6to4-self", "external", "krb5-self", "krb5-selfsub",
+ "krb5-subdomain", "ms-self", "ms-selfsub", "ms-subdomain",
+ "name", "self", "selfsub", "selfwild", "subdomain", "tcp-self",
+ "wildcard", "zonesub", NULL
+};
+
+static cfg_type_t cfg_type_matchtype = {
+ "matchtype", parse_matchtype, cfg_print_ustring,
+ cfg_doc_enum, &cfg_rep_string, &matchtype_enums
+};
+
+static cfg_type_t cfg_type_matchname = {
+ "optional_matchname", parse_matchname, cfg_print_ustring,
+ &doc_matchname, &cfg_rep_tuple, &cfg_type_ustring
+};
+
+/*%
+ * A grant statement, used in the update policy.
+ */
+static cfg_tuplefielddef_t grant_fields[] = {
+ { "mode", &cfg_type_mode, 0 },
+ { "identity", &cfg_type_astring, 0 }, /* domain name */
+ { "matchtype", &cfg_type_matchtype, 0 },
+ { "name", &cfg_type_matchname, 0 }, /* domain name */
+ { "types", &cfg_type_rrtypelist, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_grant = {
+ "grant", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, grant_fields
+};
+
+static cfg_type_t cfg_type_updatepolicy = {
+ "update_policy", parse_updatepolicy, print_updatepolicy,
+ doc_updatepolicy, &cfg_rep_list, &cfg_type_grant
+};
+
+static isc_result_t
+parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == '{') {
+ cfg_ungettoken(pctx);
+ return (cfg_parse_bracketed_list(pctx, type, ret));
+ }
+
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "local") == 0) {
+ cfg_obj_t *obj = NULL;
+ CHECK(cfg_create_obj(pctx, &cfg_type_ustring, &obj));
+ obj->value.string.length = strlen("local");
+ obj->value.string.base = isc_mem_get(pctx->mctx,
+ obj->value.string.length + 1);
+ if (obj->value.string.base == NULL) {
+ isc_mem_put(pctx->mctx, obj, sizeof(*obj));
+ return (ISC_R_NOMEMORY);
+ }
+ memmove(obj->value.string.base, "local", 5);
+ obj->value.string.base[5] = '\0';
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+ }
+
+ cfg_ungettoken(pctx);
+ return (ISC_R_UNEXPECTEDTOKEN);
+
+ cleanup:
+ return (result);
+}
+
+static void
+print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ if (cfg_obj_isstring(obj))
+ cfg_print_ustring(pctx, obj);
+ else
+ cfg_print_bracketed_list(pctx, obj);
+}
+
+static void
+doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) {
+ cfg_print_cstr(pctx, "( local | { ");
+ cfg_doc_obj(pctx, type->of);
+ cfg_print_cstr(pctx, "; ... }");
+}
+
+/*%
+ * A view statement.
+ */
+static cfg_tuplefielddef_t view_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "class", &cfg_type_optional_class, 0 },
+ { "options", &cfg_type_viewopts, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_view = {
+ "view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, view_fields
+};
+
+/*%
+ * A zone statement.
+ */
+static cfg_tuplefielddef_t zone_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "class", &cfg_type_optional_class, 0 },
+ { "options", &cfg_type_zoneopts, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_zone = {
+ "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, zone_fields
+};
+
+/*%
+ * A "category" clause in the "logging" statement.
+ */
+static cfg_tuplefielddef_t category_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "destinations", &cfg_type_destinationlist,0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_category = {
+ "category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, category_fields
+};
+
+
+/*%
+ * A dnssec key, as used in the "trusted-keys" statement.
+ */
+static cfg_tuplefielddef_t dnsseckey_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "flags", &cfg_type_uint32, 0 },
+ { "protocol", &cfg_type_uint32, 0 },
+ { "algorithm", &cfg_type_uint32, 0 },
+ { "key", &cfg_type_qstring, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_dnsseckey = {
+ "dnsseckey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, dnsseckey_fields
+};
+
+/*%
+ * A managed key initialization specifier, as used in the
+ * "managed-keys" statement.
+ */
+static cfg_tuplefielddef_t managedkey_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "init", &cfg_type_ustring, 0 }, /* must be literal "initial-key" */
+ { "flags", &cfg_type_uint32, 0 },
+ { "protocol", &cfg_type_uint32, 0 },
+ { "algorithm", &cfg_type_uint32, 0 },
+ { "key", &cfg_type_qstring, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_managedkey = {
+ "managedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, managedkey_fields
+};
+
+static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };
+
+static cfg_type_t cfg_type_optional_wild_class = {
+ "optional_wild_class", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_string, &wild_class_kw
+};
+
+static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring };
+
+static cfg_type_t cfg_type_optional_wild_type = {
+ "optional_wild_type", parse_optional_keyvalue,
+ print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_type_kw
+};
+
+static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring };
+
+static cfg_type_t cfg_type_optional_wild_name = {
+ "optional_wild_name", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw
+};
+
+/*%
+ * An rrset ordering element.
+ */
+static cfg_tuplefielddef_t rrsetorderingelement_fields[] = {
+ { "class", &cfg_type_optional_wild_class, 0 },
+ { "type", &cfg_type_optional_wild_type, 0 },
+ { "name", &cfg_type_optional_wild_name, 0 },
+ { "order", &cfg_type_ustring, 0 }, /* must be literal "order" */
+ { "ordering", &cfg_type_ustring, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_rrsetorderingelement = {
+ "rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple,
+ cfg_doc_tuple, &cfg_rep_tuple, rrsetorderingelement_fields
+};
+
+/*%
+ * A global or view "check-names" option. Note that the zone
+ * "check-names" option has a different syntax.
+ */
+
+static const char *checktype_enums[] = { "master", "slave", "response", NULL };
+static cfg_type_t cfg_type_checktype = {
+ "checktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &checktype_enums
+};
+
+static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL };
+static cfg_type_t cfg_type_checkmode = {
+ "checkmode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &checkmode_enums
+};
+
+static const char *warn_enums[] = { "warn", "ignore", NULL };
+static cfg_type_t cfg_type_warn = {
+ "warn", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &warn_enums
+};
+
+static cfg_tuplefielddef_t checknames_fields[] = {
+ { "type", &cfg_type_checktype, 0 },
+ { "mode", &cfg_type_checkmode, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_checknames = {
+ "checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, checknames_fields
+};
+
+static cfg_type_t cfg_type_bracketed_dscpsockaddrlist = {
+ "bracketed_sockaddrlist", cfg_parse_bracketed_list,
+ cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
+ &cfg_type_sockaddrdscp
+};
+
+static cfg_type_t cfg_type_bracketed_sockaddrlist = {
+ "bracketed_sockaddrlist", cfg_parse_bracketed_list,
+ cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
+ &cfg_type_sockaddr
+};
+
+static const char *autodnssec_enums[] = {
+ "allow", "maintain", "off", NULL
+};
+static cfg_type_t cfg_type_autodnssec = {
+ "autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &autodnssec_enums
+};
+
+static const char *dnssecupdatemode_enums[] = {
+ "maintain", "no-resign", NULL
+};
+static cfg_type_t cfg_type_dnssecupdatemode = {
+ "dnssecupdatemode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &dnssecupdatemode_enums
+};
+
+static const char *updatemethods_enums[] = {
+ "date", "increment", "unixtime", NULL
+};
+static cfg_type_t cfg_type_updatemethod = {
+ "updatemethod", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &updatemethods_enums
+};
+
+/*
+ * zone-statistics: full, terse, or none.
+ *
+ * for backward compatibility, we also support boolean values.
+ * yes represents "full", no represents "terse". in the future we
+ * may change no to mean "none".
+ */
+static const char *zonestat_enums[] = { "full", "terse", "none", NULL };
+static isc_result_t
+parse_zonestat(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static void
+doc_zonestat(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_boolean);
+}
+static cfg_type_t cfg_type_zonestat = {
+ "zonestat", parse_zonestat, cfg_print_ustring, doc_zonestat,
+ &cfg_rep_string, zonestat_enums
+};
+
+static cfg_type_t cfg_type_rrsetorder = {
+ "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_rrsetorderingelement
+};
+
+static keyword_type_t dscp_kw = { "dscp", &cfg_type_uint32 };
+
+static cfg_type_t cfg_type_optional_dscp = {
+ "optional_dscp", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_uint32, &dscp_kw
+};
+
+static keyword_type_t port_kw = { "port", &cfg_type_uint32 };
+
+static cfg_type_t cfg_type_optional_port = {
+ "optional_port", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_uint32, &port_kw
+};
+
+/*% A list of keys, as in the "key" clause of the controls statement. */
+static cfg_type_t cfg_type_keylist = {
+ "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
+};
+
+/*% A list of dnssec keys, as in "trusted-keys" */
+static cfg_type_t cfg_type_dnsseckeys = {
+ "dnsseckeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_dnsseckey
+};
+
+/*%
+ * A list of managed key entries, as in "trusted-keys". Currently
+ * (9.7.0) this has a format similar to dnssec keys, except the keyname
+ * is followed by the keyword "initial-key". In future releases, this
+ * keyword may take other values indicating different methods for the
+ * key to be initialized.
+ */
+
+static cfg_type_t cfg_type_managedkeys = {
+ "managedkeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_managedkey
+};
+
+static const char *forwardtype_enums[] = { "first", "only", NULL };
+static cfg_type_t cfg_type_forwardtype = {
+ "forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &forwardtype_enums
+};
+
+static const char *zonetype_enums[] = {
+ "delegation-only", "forward", "hint", "master", "redirect",
+ "slave", "static-stub", "stub", NULL
+};
+static cfg_type_t cfg_type_zonetype = {
+ "zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &zonetype_enums
+};
+
+static const char *loglevel_enums[] = {
+ "critical", "error", "warning", "notice", "info", "dynamic", NULL
+};
+static cfg_type_t cfg_type_loglevel = {
+ "loglevel", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &loglevel_enums
+};
+
+static const char *transferformat_enums[] = {
+ "many-answers", "one-answer", NULL
+};
+static cfg_type_t cfg_type_transferformat = {
+ "transferformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &transferformat_enums
+};
+
+/*%
+ * The special keyword "none", as used in the pid-file option.
+ */
+
+static void
+print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ UNUSED(obj);
+ cfg_print_cstr(pctx, "none");
+}
+
+static cfg_type_t cfg_type_none = {
+ "none", NULL, print_none, NULL, &cfg_rep_void, NULL
+};
+
+/*%
+ * A quoted string or the special keyword "none". Used in the pid-file option.
+ */
+static isc_result_t
+parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+
+ CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "none") == 0)
+ return (cfg_create_obj(pctx, &cfg_type_none, ret));
+ cfg_ungettoken(pctx);
+ return (cfg_parse_qstring(pctx, type, ret));
+ cleanup:
+ return (result);
+}
+
+static void
+doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "( <quoted_string> | none )");
+}
+
+static cfg_type_t cfg_type_qstringornone = {
+ "qstringornone", parse_qstringornone, NULL, doc_qstringornone,
+ NULL, NULL
+};
+
+/*%
+ * A boolean ("yes" or "no"), or the special keyword "auto".
+ * Used in the dnssec-validation option.
+ */
+static void
+print_auto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ UNUSED(obj);
+ cfg_print_cstr(pctx, "auto");
+}
+
+static cfg_type_t cfg_type_auto = {
+ "auto", NULL, print_auto, NULL, &cfg_rep_void, NULL
+};
+
+static isc_result_t
+parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+
+ CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "auto") == 0)
+ return (cfg_create_obj(pctx, &cfg_type_auto, ret));
+ cfg_ungettoken(pctx);
+ return (cfg_parse_boolean(pctx, type, ret));
+ cleanup:
+ return (result);
+}
+
+static void
+print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ if (obj->type->rep == &cfg_rep_void)
+ cfg_print_cstr(pctx, "auto");
+ else if (obj->value.boolean)
+ cfg_print_cstr(pctx, "yes");
+ else
+ cfg_print_cstr(pctx, "no");
+}
+
+static void
+doc_boolorauto(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "( yes | no | auto )");
+}
+
+static cfg_type_t cfg_type_boolorauto = {
+ "boolorauto", parse_boolorauto, print_boolorauto,
+ doc_boolorauto, NULL, NULL
+};
+
+/*%
+ * keyword hostname
+ */
+static void
+print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ UNUSED(obj);
+ cfg_print_cstr(pctx, "hostname");
+}
+
+static cfg_type_t cfg_type_hostname = {
+ "hostname", NULL, print_hostname, NULL, &cfg_rep_boolean, NULL
+};
+
+/*%
+ * "server-id" argument.
+ */
+
+static isc_result_t
+parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "none") == 0)
+ return (cfg_create_obj(pctx, &cfg_type_none, ret));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "hostname") == 0) {
+ result = cfg_create_obj(pctx, &cfg_type_hostname, ret);
+ if (result == ISC_R_SUCCESS)
+ (*ret)->value.boolean = true;
+ return (result);
+ }
+ cfg_ungettoken(pctx);
+ return (cfg_parse_qstring(pctx, type, ret));
+ cleanup:
+ return (result);
+}
+
+static void
+doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "( <quoted_string> | none | hostname )");
+}
+
+static cfg_type_t cfg_type_serverid = {
+ "serverid", parse_serverid, NULL, doc_serverid, NULL, NULL };
+
+/*%
+ * Port list.
+ */
+static void
+print_porttuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_cstr(pctx, "range ");
+ cfg_print_tuple(pctx, obj);
+}
+static cfg_tuplefielddef_t porttuple_fields[] = {
+ { "loport", &cfg_type_uint32, 0 },
+ { "hiport", &cfg_type_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_porttuple = {
+ "porttuple", cfg_parse_tuple, print_porttuple, cfg_doc_tuple,
+ &cfg_rep_tuple, porttuple_fields
+};
+
+static isc_result_t
+parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) {
+ isc_result_t result;
+
+ CHECK(cfg_parse_uint32(pctx, NULL, ret));
+ if ((*ret)->value.uint32 > 0xffff) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port");
+ cfg_obj_destroy(pctx, ret);
+ result = ISC_R_RANGE;
+ }
+
+ cleanup:
+ return (result);
+}
+
+static isc_result_t
+parse_portrange(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
+ if (pctx->token.type == isc_tokentype_number)
+ CHECK(parse_port(pctx, ret));
+ else {
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type != isc_tokentype_string ||
+ strcasecmp(TOKEN_STRING(pctx), "range") != 0) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected integer or 'range'");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ CHECK(cfg_create_tuple(pctx, &cfg_type_porttuple, &obj));
+ CHECK(parse_port(pctx, &obj->value.tuple[0]));
+ CHECK(parse_port(pctx, &obj->value.tuple[1]));
+ if (obj->value.tuple[0]->value.uint32 >
+ obj->value.tuple[1]->value.uint32) {
+ cfg_parser_error(pctx, CFG_LOG_NOPREP,
+ "low port '%u' must not be larger "
+ "than high port",
+ obj->value.tuple[0]->value.uint32);
+ result = ISC_R_RANGE;
+ goto cleanup;
+ }
+ *ret = obj;
+ obj = NULL;
+ }
+
+ cleanup:
+ if (obj != NULL)
+ cfg_obj_destroy(pctx, &obj);
+ return (result);
+}
+
+static cfg_type_t cfg_type_portrange = {
+ "portrange", parse_portrange, NULL, cfg_doc_terminal,
+ NULL, NULL
+};
+
+static cfg_type_t cfg_type_bracketed_portlist = {
+ "bracketed_sockaddrlist", cfg_parse_bracketed_list,
+ cfg_print_bracketed_list, cfg_doc_bracketed_list,
+ &cfg_rep_list, &cfg_type_portrange
+};
+
+static const char *cookiealg_enums[] = { "aes", "sha1", "sha256", NULL };
+static cfg_type_t cfg_type_cookiealg = {
+ "cookiealg", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &cookiealg_enums
+};
+
+/*%
+ * fetch-quota-params
+ */
+
+static cfg_tuplefielddef_t fetchquota_fields[] = {
+ { "frequency", &cfg_type_uint32, 0 },
+ { "low", &cfg_type_fixedpoint, 0 },
+ { "high", &cfg_type_fixedpoint, 0 },
+ { "discount", &cfg_type_fixedpoint, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_fetchquota = {
+ "fetchquota", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, fetchquota_fields
+};
+
+/*%
+ * fetches-per-server or fetches-per-zone
+ */
+
+static const char *response_enums[] = { "drop", "fail", NULL };
+
+static isc_result_t
+parse_optional_enum(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ return (parse_enum_or_other(pctx, type, &cfg_type_void, ret));
+}
+
+static void
+doc_optional_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "[ ");
+ cfg_doc_enum(pctx, type);
+ cfg_print_cstr(pctx, " ]");
+}
+
+static cfg_type_t cfg_type_responsetype = {
+ "responsetype", parse_optional_enum, cfg_print_ustring,
+ doc_optional_enum, &cfg_rep_string, response_enums
+};
+
+static cfg_tuplefielddef_t fetchesper_fields[] = {
+ { "fetches", &cfg_type_uint32, 0 },
+ { "response", &cfg_type_responsetype, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_fetchesper = {
+ "fetchesper", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, fetchesper_fields
+};
+
+/*%
+ * Clauses that can be found within the top level of the named.conf
+ * file only.
+ */
+static cfg_clausedef_t
+namedconf_clauses[] = {
+ { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
+ { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
+ { "logging", &cfg_type_logging, 0 },
+ { "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI },
+ { "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI },
+ { "options", &cfg_type_options, 0 },
+ { "statistics-channels", &cfg_type_statschannels,
+ CFG_CLAUSEFLAG_MULTI },
+ { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+
+/*%
+ * Clauses that can occur at the top level or in the view
+ * statement, but not in the options block.
+ */
+static cfg_clausedef_t
+namedconf_or_view_clauses[] = {
+ { "dlz", &cfg_type_dlz, CFG_CLAUSEFLAG_MULTI },
+ { "dyndb", &cfg_type_dyndb, CFG_CLAUSEFLAG_MULTI },
+ { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
+ { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
+ { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
+ { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
+ { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+
+/*%
+ * Clauses that can occur in the bind.keys file.
+ */
+static cfg_clausedef_t
+bindkeys_clauses[] = {
+ { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
+ { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+
+static const char *fstrm_model_enums[] = { "mpsc", "spsc", NULL };
+static cfg_type_t cfg_type_fstrm_model = {
+ "model", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &fstrm_model_enums
+};
+
+/*%
+ * Clauses that can be found within the 'options' statement.
+ */
+static cfg_clausedef_t
+options_clauses[] = {
+ { "answer-cookie", &cfg_type_boolean, 0 },
+ { "automatic-interface-scan", &cfg_type_boolean, 0 },
+ { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
+ { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
+ { "bindkeys-file", &cfg_type_qstring, 0 },
+ { "blackhole", &cfg_type_bracketed_aml, 0 },
+ { "cookie-algorithm", &cfg_type_cookiealg, 0 },
+ { "cookie-secret", &cfg_type_sstring, CFG_CLAUSEFLAG_MULTI },
+ { "coresize", &cfg_type_size, 0 },
+ { "datasize", &cfg_type_size, 0 },
+ { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK },
+#ifdef HAVE_DNSTAP
+ { "dnstap-output", &cfg_type_dnstapoutput, 0 },
+ { "dnstap-identity", &cfg_type_serverid, 0 },
+ { "dnstap-version", &cfg_type_qstringornone, 0 },
+#else
+ { "dnstap-output", &cfg_type_dnstapoutput,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "dnstap-identity", &cfg_type_serverid,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "dnstap-version", &cfg_type_qstringornone,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+#endif
+ { "dscp", &cfg_type_uint32, 0 },
+ { "dump-file", &cfg_type_qstring, 0 },
+ { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "files", &cfg_type_size, 0 },
+ { "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
+#ifdef HAVE_DNSTAP
+ { "fstrm-set-buffer-hint", &cfg_type_uint32, 0 },
+ { "fstrm-set-flush-timeout", &cfg_type_uint32, 0 },
+ { "fstrm-set-input-queue-size", &cfg_type_uint32, 0 },
+ { "fstrm-set-output-notify-threshold", &cfg_type_uint32, 0 },
+ { "fstrm-set-output-queue-model", &cfg_type_fstrm_model, 0 },
+ { "fstrm-set-output-queue-size", &cfg_type_uint32, 0 },
+ { "fstrm-set-reopen-interval", &cfg_type_uint32, 0 },
+#else
+ { "fstrm-set-buffer-hint", &cfg_type_uint32,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "fstrm-set-flush-timeout", &cfg_type_uint32,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "fstrm-set-input-queue-size", &cfg_type_uint32,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "fstrm-set-output-notify-threshold", &cfg_type_uint32,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "fstrm-set-output-queue-model", &cfg_type_fstrm_model,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "fstrm-set-output-queue-size", &cfg_type_uint32,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "fstrm-set-reopen-interval", &cfg_type_uint32,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+#endif /* HAVE_DNSTAP */
+#ifdef HAVE_GEOIP
+ { "geoip-directory", &cfg_type_qstringornone, 0 },
+ { "geoip-use-ecs", &cfg_type_boolean, 0 },
+#else
+ { "geoip-directory", &cfg_type_qstringornone,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "geoip-use-ecs", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED },
+#endif /* HAVE_GEOIP */
+ { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "heartbeat-interval", &cfg_type_uint32, 0 },
+ { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP },
+ { "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
+ { "hostname", &cfg_type_qstringornone, 0 },
+ { "interface-interval", &cfg_type_uint32, 0 },
+ { "keep-response-order", &cfg_type_bracketed_aml, 0 },
+ { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
+ { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
+ { "lock-file", &cfg_type_qstringornone, 0 },
+ { "managed-keys-directory", &cfg_type_qstring, 0 },
+ { "match-mapped-addresses", &cfg_type_boolean, 0 },
+ { "max-rsa-exponent-size", &cfg_type_uint32, 0 },
+ { "memstatistics", &cfg_type_boolean, 0 },
+ { "memstatistics-file", &cfg_type_qstring, 0 },
+ { "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
+ { "notify-rate", &cfg_type_uint32, 0 },
+ { "pid-file", &cfg_type_qstringornone, 0 },
+ { "port", &cfg_type_uint32, 0 },
+ { "querylog", &cfg_type_boolean, 0 },
+ { "random-device", &cfg_type_qstring, 0 },
+ { "recursing-file", &cfg_type_qstring, 0 },
+ { "recursive-clients", &cfg_type_uint32, 0 },
+ { "reserved-sockets", &cfg_type_uint32, 0 },
+ { "secroots-file", &cfg_type_qstring, 0 },
+ { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
+ { "serial-query-rate", &cfg_type_uint32, 0 },
+ { "server-id", &cfg_type_serverid, 0 },
+ { "session-keyalg", &cfg_type_astring, 0 },
+ { "session-keyfile", &cfg_type_qstringornone, 0 },
+ { "session-keyname", &cfg_type_astring, 0 },
+ { "sit-secret", &cfg_type_sstring, CFG_CLAUSEFLAG_OBSOLETE },
+ { "stacksize", &cfg_type_size, 0 },
+ { "startup-notify-rate", &cfg_type_uint32, 0 },
+ { "statistics-file", &cfg_type_qstring, 0 },
+ { "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI },
+ { "tcp-clients", &cfg_type_uint32, 0 },
+ { "tcp-listen-queue", &cfg_type_uint32, 0 },
+ { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 },
+ { "tkey-domain", &cfg_type_qstring, 0 },
+ { "tkey-gssapi-credential", &cfg_type_qstring, 0 },
+ { "tkey-gssapi-keytab", &cfg_type_qstring, 0 },
+ { "transfer-message-size", &cfg_type_uint32, 0 },
+ { "transfers-in", &cfg_type_uint32, 0 },
+ { "transfers-out", &cfg_type_uint32, 0 },
+ { "transfers-per-ns", &cfg_type_uint32, 0 },
+ { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "use-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
+ { "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
+ { "version", &cfg_type_qstringornone, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_namelist = {
+ "namelist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_qstring
+};
+
+static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist };
+
+static cfg_type_t cfg_type_optional_exclude = {
+ "optional_exclude", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_list, &exclude_kw
+};
+
+static keyword_type_t exceptionnames_kw = {
+ "except-from", &cfg_type_namelist
+};
+
+static cfg_type_t cfg_type_optional_exceptionnames = {
+ "optional_allow", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw
+};
+
+static cfg_tuplefielddef_t denyaddresses_fields[] = {
+ { "acl", &cfg_type_bracketed_aml, 0 },
+ { "except-from", &cfg_type_optional_exceptionnames, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_denyaddresses = {
+ "denyaddresses", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, denyaddresses_fields
+};
+
+static cfg_tuplefielddef_t denyaliases_fields[] = {
+ { "name", &cfg_type_namelist, 0 },
+ { "except-from", &cfg_type_optional_exceptionnames, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_denyaliases = {
+ "denyaliases", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, denyaliases_fields
+};
+
+static cfg_type_t cfg_type_algorithmlist = {
+ "algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
+};
+
+static cfg_tuplefielddef_t disablealgorithm_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "algorithms", &cfg_type_algorithmlist, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_disablealgorithm = {
+ "disablealgorithm", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, disablealgorithm_fields
+};
+
+static cfg_type_t cfg_type_dsdigestlist = {
+ "dsdigestlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
+};
+
+static cfg_tuplefielddef_t disabledsdigest_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "digests", &cfg_type_dsdigestlist, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_disabledsdigest = {
+ "disabledsdigest", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, disabledsdigest_fields
+};
+
+static cfg_tuplefielddef_t mustbesecure_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "value", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_mustbesecure = {
+ "mustbesecure", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, mustbesecure_fields
+};
+
+static const char *masterformat_enums[] = { "map", "raw", "text", NULL };
+static cfg_type_t cfg_type_masterformat = {
+ "masterformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &masterformat_enums
+};
+
+static const char *masterstyle_enums[] = { "full", "relative", NULL };
+static cfg_type_t cfg_type_masterstyle = {
+ "masterstyle", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &masterstyle_enums
+};
+
+/*%
+ * dnstap {
+ * &lt;message type&gt; [query | response] ;
+ * ...
+ * }
+ *
+ * ... where message type is one of: client, resolver, auth, forwarder, all
+ */
+static const char *dnstap_types[] = {
+ "all", "auth", "client", "forwarder", "resolver", NULL
+};
+
+static const char *dnstap_modes[] = { "query", "response", NULL };
+
+static cfg_type_t cfg_type_dnstap_type = {
+ "dnstap_type", cfg_parse_enum, cfg_print_ustring,
+ cfg_doc_enum, &cfg_rep_string, dnstap_types
+};
+
+static cfg_type_t cfg_type_dnstap_mode = {
+ "dnstap_mode", parse_optional_enum, cfg_print_ustring,
+ doc_optional_enum, &cfg_rep_string, dnstap_modes
+};
+
+static cfg_tuplefielddef_t dnstap_fields[] = {
+ { "type", &cfg_type_dnstap_type, 0 },
+ { "mode", &cfg_type_dnstap_mode, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_dnstap_entry = {
+ "dnstap_value", cfg_parse_tuple, cfg_print_tuple,
+ cfg_doc_tuple, &cfg_rep_tuple, dnstap_fields
+};
+
+static cfg_type_t cfg_type_dnstap = {
+ "dnstap", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_dnstap_entry
+};
+
+/*%
+ * dnstap-output
+ */
+static const char *dtoutmode_enums[] = { "file", "unix", NULL };
+static cfg_type_t cfg_type_dtmode = {
+ "dtmode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &dtoutmode_enums
+};
+
+static cfg_tuplefielddef_t dtout_fields[] = {
+ { "mode", &cfg_type_dtmode, 0 },
+ { "path", &cfg_type_qstring, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_dnstapoutput = {
+ "dnstapoutput", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, dtout_fields
+};
+
+/*%
+ * response-policy {
+ * zone &lt;string&gt; [ policy (given|disabled|passthru|drop|tcp-only|
+ * nxdomain|nodata|cname &lt;domain&gt; ) ]
+ * [ recursive-only yes|no ] [ log yes|no ]
+ * [ max-policy-ttl number ] ;
+ * } [ recursive-only yes|no ] [ max-policy-ttl number ]
+ * [ break-dnssec yes|no ] [ min-ns-dots number ]
+ * [ qname-wait-recurse yes|no ] ;
+ */
+
+static void
+doc_rpz_policy(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const char * const *p;
+ /*
+ * This is cfg_doc_enum() without the trailing " )".
+ */
+ cfg_print_cstr(pctx, "( ");
+ for (p = type->of; *p != NULL; p++) {
+ cfg_print_cstr(pctx, *p);
+ if (p[1] != NULL)
+ cfg_print_cstr(pctx, " | ");
+ }
+}
+
+static void
+doc_rpz_cname(cfg_printer_t *pctx, const cfg_type_t *type) {
+ cfg_doc_terminal(pctx, type);
+ cfg_print_cstr(pctx, " )");
+}
+
+/*
+ * Parse
+ * given|disabled|passthru|drop|tcp-only|nxdomain|nodata|cname <domain>
+ */
+static isc_result_t
+cfg_parse_rpz_policy(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ const cfg_tuplefielddef_t *fields;
+
+ CHECK(cfg_create_tuple(pctx, type, &obj));
+
+ fields = type->of;
+ CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
+ /*
+ * parse cname domain only after "policy cname"
+ */
+ if (strcasecmp("cname", cfg_obj_asstring(obj->value.tuple[0])) != 0) {
+ CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
+ } else {
+ CHECK(cfg_parse_obj(pctx, fields[1].type,
+ &obj->value.tuple[1]));
+ }
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+/*
+ * Parse a tuple consisting of any kind of required field followed
+ * by 2 or more optional keyvalues that can be in any order.
+ */
+static isc_result_t
+cfg_parse_kv_tuple(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ const cfg_tuplefielddef_t *fields, *f;
+ cfg_obj_t *obj = NULL;
+ int fn;
+ isc_result_t result;
+
+ CHECK(cfg_create_tuple(pctx, type, &obj));
+
+ /*
+ * The zone first field is required and always first.
+ */
+ fields = type->of;
+ CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
+
+ for (;;) {
+ CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type != isc_tokentype_string)
+ break;
+
+ for (fn = 1, f = &fields[1]; ; ++fn, ++f) {
+ if (f->name == NULL) {
+ cfg_parser_error(pctx, 0, "unexpected '%s'",
+ TOKEN_STRING(pctx));
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+ if (obj->value.tuple[fn] == NULL &&
+ strcasecmp(f->name, TOKEN_STRING(pctx)) == 0)
+ break;
+ }
+
+ CHECK(cfg_gettoken(pctx, 0));
+ CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[fn]));
+ }
+
+ for (fn = 1, f = &fields[1]; f->name != NULL; ++fn, ++f) {
+ if (obj->value.tuple[fn] == NULL)
+ CHECK(cfg_parse_void(pctx, NULL,
+ &obj->value.tuple[fn]));
+ }
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static void
+cfg_print_kv_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ unsigned int i;
+ const cfg_tuplefielddef_t *fields, *f;
+ const cfg_obj_t *fieldobj;
+
+ fields = obj->type->of;
+ for (f = fields, i = 0; f->name != NULL; f++, i++) {
+ fieldobj = obj->value.tuple[i];
+ if (fieldobj->type->print == cfg_print_void)
+ continue;
+ if (i != 0) {
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, f->name);
+ cfg_print_cstr(pctx, " ");
+ }
+ cfg_print_obj(pctx, fieldobj);
+ }
+}
+
+static void
+cfg_doc_kv_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const cfg_tuplefielddef_t *fields, *f;
+
+ fields = type->of;
+ for (f = fields; f->name != NULL; f++) {
+ if (f != fields) {
+ cfg_print_cstr(pctx, " [ ");
+ cfg_print_cstr(pctx, f->name);
+ if (f->type->doc != cfg_doc_void)
+ cfg_print_cstr(pctx, " ");
+ }
+ cfg_doc_obj(pctx, f->type);
+ if (f != fields)
+ cfg_print_cstr(pctx, " ]");
+ }
+}
+
+static keyword_type_t zone_kw = {"zone", &cfg_type_qstring};
+static cfg_type_t cfg_type_rpz_zone = {
+ "zone", parse_keyvalue, print_keyvalue,
+ doc_keyvalue, &cfg_rep_string,
+ &zone_kw
+};
+/*
+ * "no-op" is an obsolete equivalent of "passthru".
+ */
+static const char *rpz_policies[] = {
+ "cname", "disabled", "drop", "given", "no-op", "nodata",
+ "nxdomain", "passthru", "tcp-only", NULL
+};
+static cfg_type_t cfg_type_rpz_policy_name = {
+ "policy name", cfg_parse_enum, cfg_print_ustring,
+ doc_rpz_policy, &cfg_rep_string,
+ &rpz_policies
+};
+static cfg_type_t cfg_type_rpz_cname = {
+ "quoted_string", cfg_parse_astring, NULL,
+ doc_rpz_cname, &cfg_rep_string,
+ NULL
+};
+static cfg_tuplefielddef_t rpz_policy_fields[] = {
+ { "policy name", &cfg_type_rpz_policy_name, 0 },
+ { "cname", &cfg_type_rpz_cname, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_rpz_policy = {
+ "policy tuple", cfg_parse_rpz_policy,
+ cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ rpz_policy_fields
+};
+static cfg_tuplefielddef_t rpz_zone_fields[] = {
+ { "zone name", &cfg_type_rpz_zone, 0 },
+ { "log", &cfg_type_boolean, 0 },
+ { "max-policy-ttl", &cfg_type_uint32, 0 },
+ { "policy", &cfg_type_rpz_policy, 0 },
+ { "recursive-only", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_rpz_tuple = {
+ "rpz tuple", cfg_parse_kv_tuple,
+ cfg_print_kv_tuple, cfg_doc_kv_tuple, &cfg_rep_tuple,
+ rpz_zone_fields
+};
+static cfg_type_t cfg_type_rpz_list = {
+ "zone list", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list,
+ &cfg_type_rpz_tuple
+};
+static cfg_tuplefielddef_t rpz_fields[] = {
+ { "zone list", &cfg_type_rpz_list, 0 },
+ { "break-dnssec", &cfg_type_boolean, 0 },
+ { "max-policy-ttl", &cfg_type_uint32, 0 },
+ { "min-ns-dots", &cfg_type_uint32, 0 },
+ { "nsip-wait-recurse", &cfg_type_boolean, 0 },
+ { "qname-wait-recurse", &cfg_type_boolean, 0 },
+ { "recursive-only", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_rpz = {
+ "rpz", cfg_parse_kv_tuple,
+ cfg_print_kv_tuple, cfg_doc_kv_tuple, &cfg_rep_tuple,
+ rpz_fields
+};
+
+/*
+ * Catalog zones
+ */
+static cfg_type_t cfg_type_catz_zone = {
+ "zone", parse_keyvalue, print_keyvalue,
+ doc_keyvalue, &cfg_rep_string,
+ &zone_kw
+};
+
+static cfg_tuplefielddef_t catz_zone_fields[] = {
+ { "zone name", &cfg_type_catz_zone, 0 },
+ { "default-masters", &cfg_type_namesockaddrkeylist, 0 },
+ { "zone-directory", &cfg_type_qstring, 0 },
+ { "in-memory", &cfg_type_boolean, 0 },
+ { "min-update-interval", &cfg_type_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_catz_tuple = {
+ "catz tuple", cfg_parse_kv_tuple,
+ cfg_print_kv_tuple, cfg_doc_kv_tuple, &cfg_rep_tuple,
+ catz_zone_fields
+};
+static cfg_type_t cfg_type_catz_list = {
+ "zone list", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list,
+ &cfg_type_catz_tuple
+};
+static cfg_tuplefielddef_t catz_fields[] = {
+ { "zone list", &cfg_type_catz_list, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_catz = {
+ "catz", cfg_parse_kv_tuple, cfg_print_kv_tuple,
+ cfg_doc_kv_tuple, &cfg_rep_tuple, catz_fields
+};
+
+/*
+ * rate-limit
+ */
+static cfg_clausedef_t rrl_clauses[] = {
+ { "all-per-second", &cfg_type_uint32, 0 },
+ { "errors-per-second", &cfg_type_uint32, 0 },
+ { "exempt-clients", &cfg_type_bracketed_aml, 0 },
+ { "ipv4-prefix-length", &cfg_type_uint32, 0 },
+ { "ipv6-prefix-length", &cfg_type_uint32, 0 },
+ { "log-only", &cfg_type_boolean, 0 },
+ { "max-table-size", &cfg_type_uint32, 0 },
+ { "min-table-size", &cfg_type_uint32, 0 },
+ { "nodata-per-second", &cfg_type_uint32, 0 },
+ { "nxdomains-per-second", &cfg_type_uint32, 0 },
+ { "qps-scale", &cfg_type_uint32, 0 },
+ { "referrals-per-second", &cfg_type_uint32, 0 },
+ { "responses-per-second", &cfg_type_uint32, 0 },
+ { "slip", &cfg_type_uint32, 0 },
+ { "window", &cfg_type_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *rrl_clausesets[] = {
+ rrl_clauses, NULL
+};
+
+static cfg_type_t cfg_type_rrl = {
+ "rate-limit", cfg_parse_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, rrl_clausesets
+};
+
+/*%
+ * dnssec-lookaside
+ */
+
+static void
+print_lookaside(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ const cfg_obj_t *domain = obj->value.tuple[0];
+
+ if (domain->value.string.length == 4 &&
+ strncmp(domain->value.string.base, "auto", 4) == 0)
+ cfg_print_cstr(pctx, "auto");
+ else
+ cfg_print_tuple(pctx, obj);
+}
+
+static void
+doc_lookaside(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "( <string> trust-anchor <string> | auto | no )");
+}
+
+static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring };
+
+static cfg_type_t cfg_type_optional_trustanchor = {
+ "optional_trustanchor", parse_optional_keyvalue, print_keyvalue,
+ doc_keyvalue, &cfg_rep_string, &trustanchor_kw
+};
+
+static cfg_tuplefielddef_t lookaside_fields[] = {
+ { "domain", &cfg_type_astring, 0 },
+ { "trust-anchor", &cfg_type_optional_trustanchor, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_lookaside = {
+ "lookaside", cfg_parse_tuple, print_lookaside, doc_lookaside,
+ &cfg_rep_tuple, lookaside_fields
+};
+
+static isc_result_t
+parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
+ if (pctx->token.type == isc_tokentype_number) {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret));
+ } else {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
+ }
+ cleanup:
+ return (result);
+}
+
+static void
+doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "[ <integer> ]");
+}
+
+static cfg_type_t cfg_type_optional_uint32 = {
+ "optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32,
+ NULL, NULL
+};
+
+static cfg_tuplefielddef_t prefetch_fields[] = {
+ { "trigger", &cfg_type_uint32, 0 },
+ { "eligible", &cfg_type_optional_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_prefetch = {
+ "prefetch", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, prefetch_fields
+};
+/*
+ * DNS64.
+ */
+static cfg_clausedef_t
+dns64_clauses[] = {
+ { "break-dnssec", &cfg_type_boolean, 0 },
+ { "clients", &cfg_type_bracketed_aml, 0 },
+ { "exclude", &cfg_type_bracketed_aml, 0 },
+ { "mapped", &cfg_type_bracketed_aml, 0 },
+ { "recursive-only", &cfg_type_boolean, 0 },
+ { "suffix", &cfg_type_netaddr6, 0 },
+ { NULL, NULL, 0 },
+};
+
+static cfg_clausedef_t *
+dns64_clausesets[] = {
+ dns64_clauses,
+ NULL
+};
+
+static cfg_type_t cfg_type_dns64 = {
+ "dns64", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, dns64_clausesets
+};
+
+/*%
+ * Clauses that can be found within the 'view' statement,
+ * with defaults in the 'options' statement.
+ */
+
+static cfg_clausedef_t
+view_clauses[] = {
+ { "acache-cleaning-interval", &cfg_type_uint32, 0 },
+ { "acache-enable", &cfg_type_boolean, 0 },
+ { "additional-from-auth", &cfg_type_boolean, 0 },
+ { "additional-from-cache", &cfg_type_boolean, 0 },
+ { "allow-new-zones", &cfg_type_boolean, 0 },
+ { "allow-query-cache", &cfg_type_bracketed_aml, 0 },
+ { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 },
+ { "allow-recursion", &cfg_type_bracketed_aml, 0 },
+ { "allow-recursion-on", &cfg_type_bracketed_aml, 0 },
+ { "allow-v6-synthesis", &cfg_type_bracketed_aml,
+ CFG_CLAUSEFLAG_OBSOLETE },
+ { "attach-cache", &cfg_type_astring, 0 },
+ { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
+ { "cache-file", &cfg_type_qstring, 0 },
+ { "catalog-zones", &cfg_type_catz, 0 },
+ { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
+ { "cleaning-interval", &cfg_type_uint32, 0 },
+ { "clients-per-query", &cfg_type_uint32, 0 },
+ { "deny-answer-addresses", &cfg_type_denyaddresses, 0 },
+ { "deny-answer-aliases", &cfg_type_denyaliases, 0 },
+ { "disable-algorithms", &cfg_type_disablealgorithm,
+ CFG_CLAUSEFLAG_MULTI },
+ { "disable-ds-digests", &cfg_type_disabledsdigest,
+ CFG_CLAUSEFLAG_MULTI },
+ { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
+ { "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI },
+ { "dns64-contact", &cfg_type_astring, 0 },
+ { "dns64-server", &cfg_type_astring, 0 },
+ { "dnssec-accept-expired", &cfg_type_boolean, 0 },
+ { "dnssec-enable", &cfg_type_boolean, 0 },
+ { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI },
+ { "dnssec-must-be-secure", &cfg_type_mustbesecure,
+ CFG_CLAUSEFLAG_MULTI },
+ { "dnssec-validation", &cfg_type_boolorauto, 0 },
+#ifdef HAVE_DNSTAP
+ { "dnstap", &cfg_type_dnstap, 0 },
+#else
+ { "dnstap", &cfg_type_dnstap, CFG_CLAUSEFLAG_NOTCONFIGURED },
+#endif /* HAVE_DNSTAP */
+ { "dual-stack-servers", &cfg_type_nameportiplist, 0 },
+ { "edns-udp-size", &cfg_type_uint32, 0 },
+ { "empty-contact", &cfg_type_astring, 0 },
+ { "empty-server", &cfg_type_astring, 0 },
+ { "empty-zones-enable", &cfg_type_boolean, 0 },
+ { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "fetch-quota-params", &cfg_type_fetchquota, 0 },
+ { "fetches-per-server", &cfg_type_fetchesper, 0 },
+ { "fetches-per-zone", &cfg_type_fetchesper, 0 },
+#ifdef ALLOW_FILTER_AAAA
+ { "filter-aaaa", &cfg_type_bracketed_aml, 0 },
+ { "filter-aaaa-on-v4", &cfg_type_filter_aaaa, 0 },
+ { "filter-aaaa-on-v6", &cfg_type_filter_aaaa, 0 },
+#else
+ { "filter-aaaa", &cfg_type_bracketed_aml,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "filter-aaaa-on-v4", &cfg_type_filter_aaaa,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+ { "filter-aaaa-on-v6", &cfg_type_filter_aaaa,
+ CFG_CLAUSEFLAG_NOTCONFIGURED },
+#endif
+ { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
+ { "lame-ttl", &cfg_type_ttlval, 0 },
+#ifdef HAVE_LMDB
+ { "lmdb-mapsize", &cfg_type_sizeval, 0 },
+#else
+ { "lmdb-mapsize", &cfg_type_sizeval, CFG_CLAUSEFLAG_NOOP },
+#endif
+ { "max-acache-size", &cfg_type_sizenodefault, 0 },
+ { "max-cache-size", &cfg_type_sizeorpercent, 0 },
+ { "max-cache-ttl", &cfg_type_uint32, 0 },
+ { "max-clients-per-query", &cfg_type_uint32, 0 },
+ { "max-ncache-ttl", &cfg_type_uint32, 0 },
+ { "max-recursion-depth", &cfg_type_uint32, 0 },
+ { "max-recursion-queries", &cfg_type_uint32, 0 },
+ { "max-udp-size", &cfg_type_uint32, 0 },
+ { "message-compression", &cfg_type_boolean, 0 },
+ { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
+ { "minimal-any", &cfg_type_boolean, 0 },
+ { "minimal-responses", &cfg_type_minimal, 0 },
+ { "no-case-compress", &cfg_type_bracketed_aml, 0 },
+ { "nocookie-udp-size", &cfg_type_uint32, 0 },
+ { "nosit-udp-size", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
+ { "nta-lifetime", &cfg_type_ttlval, 0 },
+ { "nta-recheck", &cfg_type_ttlval, 0 },
+ { "nxdomain-redirect", &cfg_type_astring, 0 },
+ { "preferred-glue", &cfg_type_astring, 0 },
+ { "prefetch", &cfg_type_prefetch, 0 },
+ { "provide-ixfr", &cfg_type_boolean, 0 },
+ /*
+ * Note that the query-source option syntax is different
+ * from the other -source options.
+ */
+ { "query-source", &cfg_type_querysource4, 0 },
+ { "query-source-v6", &cfg_type_querysource6, 0 },
+ { "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
+ { "queryport-pool-updateinterval", &cfg_type_uint32,
+ CFG_CLAUSEFLAG_OBSOLETE },
+ { "rate-limit", &cfg_type_rrl, 0 },
+ { "recursion", &cfg_type_boolean, 0 },
+ { "request-nsid", &cfg_type_boolean, 0 },
+ { "request-sit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "require-server-cookie", &cfg_type_boolean, 0 },
+ { "resolver-query-timeout", &cfg_type_uint32, 0 },
+ { "response-policy", &cfg_type_rpz, 0 },
+ { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
+ { "root-delegation-only", &cfg_type_optional_exclude, 0 },
+ { "root-key-sentinel", &cfg_type_boolean, 0 },
+ { "rrset-order", &cfg_type_rrsetorder, 0 },
+ { "send-cookie", &cfg_type_boolean, 0 },
+ { "servfail-ttl", &cfg_type_ttlval, 0 },
+ { "sortlist", &cfg_type_bracketed_aml, 0 },
+ { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
+ { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
+ { "transfer-format", &cfg_type_transferformat, 0 },
+ { "trust-anchor-telemetry", &cfg_type_boolean,
+ CFG_CLAUSEFLAG_EXPERIMENTAL },
+ { "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "v6-bias", &cfg_type_uint32, 0 },
+ { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+
+/*%
+ * Clauses that can be found within the 'view' statement only.
+ */
+static cfg_clausedef_t
+view_only_clauses[] = {
+ { "match-clients", &cfg_type_bracketed_aml, 0 },
+ { "match-destinations", &cfg_type_bracketed_aml, 0 },
+ { "match-recursive-only", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+
+/*%
+ * Sig-validity-interval.
+ */
+
+static cfg_tuplefielddef_t validityinterval_fields[] = {
+ { "validity", &cfg_type_uint32, 0 },
+ { "re-sign", &cfg_type_optional_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_validityinterval = {
+ "validityinterval", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, validityinterval_fields
+};
+
+/*%
+ * Clauses that can be found in a 'zone' statement,
+ * with defaults in the 'view' or 'options' statement.
+ *
+ * Note: CFG_ZONE_* options indicate in which zone types this clause is
+ * legal.
+ */
+static cfg_clausedef_t
+zone_clauses[] = {
+ { "allow-notify", &cfg_type_bracketed_aml,
+ CFG_ZONE_SLAVE
+ },
+ { "allow-query", &cfg_type_bracketed_aml,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB |
+ CFG_ZONE_REDIRECT | CFG_ZONE_STATICSTUB
+ },
+ { "allow-query-on", &cfg_type_bracketed_aml,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB |
+ CFG_ZONE_REDIRECT | CFG_ZONE_STATICSTUB
+ },
+ { "allow-transfer", &cfg_type_bracketed_aml,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "allow-update", &cfg_type_bracketed_aml,
+ CFG_ZONE_MASTER
+ },
+ { "allow-update-forwarding", &cfg_type_bracketed_aml,
+ CFG_ZONE_SLAVE
+ },
+ { "also-notify", &cfg_type_namesockaddrkeylist,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "alt-transfer-source", &cfg_type_sockaddr4wild,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "alt-transfer-source-v6", &cfg_type_sockaddr6wild,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "auto-dnssec", &cfg_type_autodnssec,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "check-dup-records", &cfg_type_checkmode,
+ CFG_ZONE_MASTER
+ },
+ { "check-integrity", &cfg_type_boolean,
+ CFG_ZONE_MASTER
+ },
+ { "check-mx", &cfg_type_checkmode,
+ CFG_ZONE_MASTER
+ },
+ { "check-mx-cname", &cfg_type_checkmode,
+ CFG_ZONE_MASTER
+ },
+ { "check-sibling", &cfg_type_boolean,
+ CFG_ZONE_MASTER
+ },
+ { "check-spf", &cfg_type_warn,
+ CFG_ZONE_MASTER
+ },
+ { "check-srv-cname", &cfg_type_checkmode,
+ CFG_ZONE_MASTER
+ },
+ { "check-wildcard", &cfg_type_boolean,
+ CFG_ZONE_MASTER
+ },
+ { "dialup", &cfg_type_dialuptype,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "dnssec-dnskey-kskonly", &cfg_type_boolean,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "dnssec-loadkeys-interval", &cfg_type_uint32,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "dnssec-secure-to-insecure", &cfg_type_boolean,
+ CFG_ZONE_MASTER
+ },
+ { "dnssec-update-mode", &cfg_type_dnssecupdatemode,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "forward", &cfg_type_forwardtype,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB |
+ CFG_ZONE_STATICSTUB | CFG_ZONE_FORWARD
+ },
+ { "forwarders", &cfg_type_portiplist,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB |
+ CFG_ZONE_STATICSTUB | CFG_ZONE_FORWARD
+ },
+ { "inline-signing", &cfg_type_boolean,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "key-directory", &cfg_type_qstring,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "maintain-ixfr-base", &cfg_type_boolean,
+ CFG_CLAUSEFLAG_OBSOLETE
+ },
+ { "masterfile-format", &cfg_type_masterformat,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE |
+ CFG_ZONE_STUB | CFG_ZONE_REDIRECT
+ },
+ { "masterfile-style", &cfg_type_masterstyle,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE |
+ CFG_ZONE_STUB | CFG_ZONE_REDIRECT
+ },
+ { "max-ixfr-log-size", &cfg_type_size,
+ CFG_CLAUSEFLAG_OBSOLETE
+ },
+ { "max-journal-size", &cfg_type_sizenodefault,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "max-records", &cfg_type_uint32,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB |
+ CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT
+ },
+ { "max-refresh-time", &cfg_type_uint32,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "max-retry-time", &cfg_type_uint32,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "max-transfer-idle-in", &cfg_type_uint32,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "max-transfer-idle-out", &cfg_type_uint32,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "max-transfer-time-in", &cfg_type_uint32,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "max-transfer-time-out", &cfg_type_uint32,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "max-zone-ttl", &cfg_type_maxttl,
+ CFG_ZONE_MASTER | CFG_ZONE_REDIRECT
+ },
+ { "min-refresh-time", &cfg_type_uint32,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "min-retry-time", &cfg_type_uint32,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "multi-master", &cfg_type_boolean,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "notify", &cfg_type_notifytype,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "notify-delay", &cfg_type_uint32,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "notify-source", &cfg_type_sockaddr4wild,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "notify-source-v6", &cfg_type_sockaddr6wild,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "notify-to-soa", &cfg_type_boolean,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "nsec3-test-zone", &cfg_type_boolean,
+ CFG_CLAUSEFLAG_TESTONLY |
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "request-expire", &cfg_type_boolean,
+ CFG_ZONE_SLAVE
+ },
+ { "request-ixfr", &cfg_type_boolean,
+ CFG_ZONE_SLAVE
+ },
+ { "serial-update-method", &cfg_type_updatemethod,
+ CFG_ZONE_MASTER
+ },
+ { "sig-signing-nodes", &cfg_type_uint32,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "sig-signing-signatures", &cfg_type_uint32,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "sig-signing-type", &cfg_type_uint32,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "sig-validity-interval", &cfg_type_validityinterval,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "transfer-source", &cfg_type_sockaddr4wild,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "transfer-source-v6", &cfg_type_sockaddr6wild,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "try-tcp-refresh", &cfg_type_boolean,
+ CFG_ZONE_SLAVE
+ },
+ { "update-check-ksk", &cfg_type_boolean,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "use-alt-transfer-source", &cfg_type_boolean,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "zero-no-soa-ttl", &cfg_type_boolean,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "zone-statistics", &cfg_type_zonestat,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB |
+ CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT
+ },
+ { NULL, NULL, 0 }
+};
+
+/*%
+ * Clauses that can be found in a 'zone' statement only.
+ *
+ * Note: CFG_ZONE_* options indicate in which zone types this clause is
+ * legal.
+ */
+static cfg_clausedef_t
+zone_only_clauses[] = {
+ /*
+ * Note that the format of the check-names option is different between
+ * the zone options and the global/view options. Ugh.
+ */
+ { "type", &cfg_type_zonetype,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB |
+ CFG_ZONE_STATICSTUB | CFG_ZONE_DELEGATION | CFG_ZONE_HINT |
+ CFG_ZONE_REDIRECT | CFG_ZONE_FORWARD
+ },
+ { "check-names", &cfg_type_checkmode,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE |
+ CFG_ZONE_HINT | CFG_ZONE_STUB
+ },
+ { "database", &cfg_type_astring,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB
+ },
+ { "delegation-only", &cfg_type_boolean,
+ CFG_ZONE_HINT | CFG_ZONE_STUB | CFG_ZONE_FORWARD
+ },
+ { "dlz", &cfg_type_astring,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_REDIRECT
+ },
+ { "file", &cfg_type_qstring,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB |
+ CFG_ZONE_HINT | CFG_ZONE_REDIRECT
+ },
+ { "in-view", &cfg_type_astring,
+ CFG_ZONE_INVIEW
+ },
+ { "ixfr-base", &cfg_type_qstring,
+ CFG_CLAUSEFLAG_OBSOLETE
+ },
+ { "ixfr-from-differences", &cfg_type_boolean,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "ixfr-tmp-file", &cfg_type_qstring,
+ CFG_CLAUSEFLAG_OBSOLETE
+ },
+ { "journal", &cfg_type_qstring,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
+ { "masters", &cfg_type_namesockaddrkeylist,
+ CFG_ZONE_SLAVE | CFG_ZONE_STUB | CFG_ZONE_REDIRECT
+ },
+ { "pubkey", &cfg_type_pubkey,
+ CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE
+ },
+ { "server-addresses", &cfg_type_bracketed_sockaddrlist,
+ CFG_ZONE_STATICSTUB
+ },
+ { "server-names", &cfg_type_namelist,
+ CFG_ZONE_STATICSTUB
+ },
+ { "update-policy", &cfg_type_updatepolicy,
+ CFG_ZONE_MASTER
+ },
+ { NULL, NULL, 0 }
+};
+
+/*% The top-level named.conf syntax. */
+
+static cfg_clausedef_t *
+namedconf_clausesets[] = {
+ namedconf_clauses,
+ namedconf_or_view_clauses,
+ NULL
+};
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = {
+ "namedconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
+ &cfg_rep_map, namedconf_clausesets
+};
+
+/*% The bind.keys syntax (trusted-keys/managed-keys only). */
+static cfg_clausedef_t *
+bindkeys_clausesets[] = {
+ bindkeys_clauses,
+ NULL
+};
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bindkeys = {
+ "bindkeys", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
+ &cfg_rep_map, bindkeys_clausesets
+};
+
+/*% The "options" statement syntax. */
+
+static cfg_clausedef_t *
+options_clausesets[] = {
+ options_clauses,
+ view_clauses,
+ zone_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_options = {
+ "options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
+ options_clausesets
+};
+
+/*% The "view" statement syntax. */
+
+static cfg_clausedef_t *
+view_clausesets[] = {
+ view_only_clauses,
+ namedconf_or_view_clauses,
+ view_clauses,
+ zone_clauses,
+ NULL
+};
+
+static cfg_type_t cfg_type_viewopts = {
+ "view", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
+ view_clausesets
+};
+
+/*% The "zone" statement syntax. */
+
+static cfg_clausedef_t *
+zone_clausesets[] = {
+ zone_only_clauses,
+ zone_clauses,
+ NULL
+};
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_zoneopts = {
+ "zoneopts", cfg_parse_map, cfg_print_map,
+ cfg_doc_map, &cfg_rep_map, zone_clausesets };
+
+/*% The "dynamically loadable zones" statement syntax. */
+
+static cfg_clausedef_t
+dlz_clauses[] = {
+ { "database", &cfg_type_astring, 0 },
+ { "search", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_clausedef_t *
+dlz_clausesets[] = {
+ dlz_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_dlz = {
+ "dlz", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, dlz_clausesets
+};
+
+/*%
+ * The "dyndb" statement syntax.
+ */
+
+static cfg_tuplefielddef_t dyndb_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "library", &cfg_type_qstring, 0 },
+ { "parameters", &cfg_type_bracketed_text, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_dyndb = {
+ "dyndb", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, dyndb_fields
+};
+
+/*%
+ * Clauses that can be found within the 'key' statement.
+ */
+static cfg_clausedef_t
+key_clauses[] = {
+ { "algorithm", &cfg_type_astring, 0 },
+ { "secret", &cfg_type_sstring, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+key_clausesets[] = {
+ key_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_key = {
+ "key", cfg_parse_named_map, cfg_print_map,
+ cfg_doc_map, &cfg_rep_map, key_clausesets
+};
+
+
+/*%
+ * Clauses that can be found in a 'server' statement.
+ */
+static cfg_clausedef_t
+server_clauses[] = {
+ { "bogus", &cfg_type_boolean, 0 },
+ { "edns", &cfg_type_boolean, 0 },
+ { "edns-udp-size", &cfg_type_uint32, 0 },
+ { "edns-version", &cfg_type_uint32, 0 },
+ { "keys", &cfg_type_server_key_kludge, 0 },
+ { "max-udp-size", &cfg_type_uint32, 0 },
+ { "notify-source", &cfg_type_sockaddr4wild, 0 },
+ { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
+ { "provide-ixfr", &cfg_type_boolean, 0 },
+ { "query-source", &cfg_type_querysource4, 0 },
+ { "query-source-v6", &cfg_type_querysource6, 0 },
+ { "request-expire", &cfg_type_boolean, 0 },
+ { "request-ixfr", &cfg_type_boolean, 0 },
+ { "request-nsid", &cfg_type_boolean, 0 },
+ { "request-sit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "send-cookie", &cfg_type_boolean, 0 },
+ { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "tcp-only", &cfg_type_boolean, 0 },
+ { "transfer-format", &cfg_type_transferformat, 0 },
+ { "transfer-source", &cfg_type_sockaddr4wild, 0 },
+ { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
+ { "transfers", &cfg_type_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_clausedef_t *
+server_clausesets[] = {
+ server_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_server = {
+ "server", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, server_clausesets
+};
+
+
+/*%
+ * Clauses that can be found in a 'channel' clause in the
+ * 'logging' statement.
+ *
+ * These have some additional constraints that need to be
+ * checked after parsing:
+ * - There must exactly one of file/syslog/null/stderr
+ *
+ */
+static cfg_clausedef_t
+channel_clauses[] = {
+ /* Destinations. We no longer require these to be first. */
+ { "file", &cfg_type_logfile, 0 },
+ { "syslog", &cfg_type_optional_facility, 0 },
+ { "null", &cfg_type_void, 0 },
+ { "stderr", &cfg_type_void, 0 },
+ /* Options. We now accept these for the null channel, too. */
+ { "severity", &cfg_type_logseverity, 0 },
+ { "print-time", &cfg_type_boolean, 0 },
+ { "print-severity", &cfg_type_boolean, 0 },
+ { "print-category", &cfg_type_boolean, 0 },
+ { "buffered", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_clausedef_t *
+channel_clausesets[] = {
+ channel_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_channel = {
+ "channel", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, channel_clausesets
+};
+
+/*% A list of log destination, used in the "category" clause. */
+static cfg_type_t cfg_type_destinationlist = {
+ "destinationlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
+};
+
+/*%
+ * Clauses that can be found in a 'logging' statement.
+ */
+static cfg_clausedef_t logging_clauses[] = {
+ { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI },
+ { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+static cfg_clausedef_t * logging_clausesets[] = {
+ logging_clauses, NULL
+};
+static cfg_type_t cfg_type_logging = {
+ "logging", cfg_parse_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, logging_clausesets
+};
+
+/*%
+ * For parsing an 'addzone' statement
+ */
+static cfg_tuplefielddef_t addzone_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "class", &cfg_type_optional_class, 0 },
+ { "view", &cfg_type_optional_class, 0 },
+ { "options", &cfg_type_zoneopts, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_addzone = {
+ "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, addzone_fields
+};
+
+static cfg_clausedef_t
+addzoneconf_clauses[] = {
+ { "zone", &cfg_type_addzone, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+addzoneconf_clausesets[] = {
+ addzoneconf_clauses,
+ NULL
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_addzoneconf = {
+ "addzoneconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
+ &cfg_rep_map, addzoneconf_clausesets
+};
+
+static isc_result_t
+parse_unitstring(char *str, isc_resourcevalue_t *valuep) {
+ char *endp;
+ unsigned int len;
+ uint64_t value;
+ uint64_t unit;
+
+ value = isc_string_touint64(str, &endp, 10);
+ if (*endp == 0) {
+ *valuep = value;
+ return (ISC_R_SUCCESS);
+ }
+
+ len = strlen(str);
+ if (len < 2 || endp[1] != '\0')
+ return (ISC_R_FAILURE);
+
+ switch (str[len - 1]) {
+ case 'k':
+ case 'K':
+ unit = 1024;
+ break;
+ case 'm':
+ case 'M':
+ unit = 1024 * 1024;
+ break;
+ case 'g':
+ case 'G':
+ unit = 1024 * 1024 * 1024;
+ break;
+ default:
+ return (ISC_R_FAILURE);
+ }
+ if (value > UINT64_MAX / unit)
+ return (ISC_R_FAILURE);
+ *valuep = value * unit;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ uint64_t val;
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type != isc_tokentype_string) {
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+ CHECK(parse_unitstring(TOKEN_STRING(pctx), &val));
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj));
+ obj->value.uint64 = val;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected integer and optional unit");
+ return (result);
+}
+
+static isc_result_t
+parse_sizeval_percent(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ char *endp;
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ uint64_t val;
+ uint64_t percent;
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type != isc_tokentype_string) {
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+
+ percent = isc_string_touint64(TOKEN_STRING(pctx), &endp, 10);
+
+ if (*endp == '%' && *(endp+1) == 0) {
+ CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj));
+ obj->value.uint32 = (uint32_t)percent;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+ } else {
+ CHECK(parse_unitstring(TOKEN_STRING(pctx), &val));
+ CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj));
+ obj->value.uint64 = val;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+ }
+
+ cleanup:
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected integer and optional unit or percent");
+ return (result);
+}
+
+static void
+doc_sizeval_percent(cfg_printer_t *pctx, const cfg_type_t *type) {
+
+ UNUSED(type);
+
+ cfg_print_cstr(pctx, "( ");
+ cfg_doc_terminal(pctx, &cfg_type_size);
+ cfg_print_cstr(pctx, " | ");
+ cfg_doc_terminal(pctx, &cfg_type_percentage);
+ cfg_print_cstr(pctx, " )");
+}
+
+/*%
+ * A size value (number + optional unit).
+ */
+static cfg_type_t cfg_type_sizeval = {
+ "sizeval", parse_sizeval, cfg_print_uint64, cfg_doc_terminal,
+ &cfg_rep_uint64, NULL
+};
+
+/*%
+ * A size, "unlimited", or "default".
+ */
+
+static isc_result_t
+parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret));
+}
+
+static void
+doc_size(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_sizeval);
+}
+
+static const char *size_enums[] = { "default", "unlimited", NULL };
+static cfg_type_t cfg_type_size = {
+ "size", parse_size, cfg_print_ustring, doc_size,
+ &cfg_rep_string, size_enums
+};
+
+/*%
+ * A size or "unlimited", but not "default".
+ */
+static const char *sizenodefault_enums[] = { "unlimited", NULL };
+static cfg_type_t cfg_type_sizenodefault = {
+ "size_no_default", parse_size, cfg_print_ustring, doc_size,
+ &cfg_rep_string, sizenodefault_enums
+};
+
+/*%
+ * A size in absolute values or percents.
+ */
+
+static cfg_type_t cfg_type_sizeval_percent = {
+ "sizeval_percent", parse_sizeval_percent, cfg_print_ustring,
+ doc_sizeval_percent, &cfg_rep_string, NULL
+};
+
+/*%
+ * A size in absolute values or percents, or "unlimited", or "default"
+ */
+
+static isc_result_t
+parse_size_or_percent(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ return (parse_enum_or_other(pctx, type, &cfg_type_sizeval_percent,
+ ret));
+}
+
+static void
+doc_parse_size_or_percent(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_sizeval_percent);
+}
+
+static const char *sizeorpercent_enums[] = { "default", "unlimited", NULL };
+static cfg_type_t cfg_type_sizeorpercent = {
+ "size_or_percent", parse_size_or_percent, cfg_print_ustring,
+ doc_parse_size_or_percent, &cfg_rep_string, sizeorpercent_enums
+};
+
+/*%
+ * optional_keyvalue
+ */
+static isc_result_t
+parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
+ bool optional, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ const keyword_type_t *kw = type->of;
+
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), kw->name) == 0) {
+ CHECK(cfg_gettoken(pctx, 0));
+ CHECK(kw->type->parse(pctx, kw->type, &obj));
+ obj->type = type; /* XXX kludge */
+ } else {
+ if (optional) {
+ CHECK(cfg_parse_void(pctx, NULL, &obj));
+ } else {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected '%s'",
+ kw->name);
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+ }
+ *ret = obj;
+ cleanup:
+ return (result);
+}
+
+static isc_result_t
+parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
+ const cfg_type_t *othertype, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string &&
+ cfg_is_enum(TOKEN_STRING(pctx), enumtype->of)) {
+ CHECK(cfg_parse_enum(pctx, enumtype, ret));
+ } else {
+ CHECK(cfg_parse_obj(pctx, othertype, ret));
+ }
+ cleanup:
+ return (result);
+}
+
+static void
+doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype,
+ const cfg_type_t *othertype)
+{
+ const char * const *p;
+ bool first = true;
+
+ /*
+ * If othertype is cfg_type_void, it means that enumtype is
+ * optional.
+ */
+
+ if (othertype == &cfg_type_void)
+ cfg_print_cstr(pctx, "[ ");
+ cfg_print_cstr(pctx, "( ");
+ for (p = enumtype->of; *p != NULL; p++) {
+ if (!first)
+ cfg_print_cstr(pctx, " | ");
+ first = false;
+ cfg_print_cstr(pctx, *p);
+ }
+ if (othertype == &cfg_type_sizeval_percent) {
+ if (!first)
+ cfg_print_cstr(pctx, " | ");
+ cfg_doc_terminal(pctx, &cfg_type_sizeval);
+ cfg_print_cstr(pctx, " | ");
+ cfg_doc_terminal(pctx, &cfg_type_percentage);
+ } else if (othertype != &cfg_type_void) {
+ if (!first)
+ cfg_print_cstr(pctx, " | ");
+ cfg_doc_terminal(pctx, othertype);
+ }
+ cfg_print_cstr(pctx, " )");
+ if (othertype == &cfg_type_void)
+ cfg_print_cstr(pctx, " ]");
+}
+
+static isc_result_t
+parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_maybe_optional_keyvalue(pctx, type, false, ret));
+}
+
+static isc_result_t
+parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ return (parse_maybe_optional_keyvalue(pctx, type, true, ret));
+}
+
+static void
+print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ const keyword_type_t *kw = obj->type->of;
+ cfg_print_cstr(pctx, kw->name);
+ cfg_print_cstr(pctx, " ");
+ kw->type->print(pctx, obj);
+}
+
+static void
+doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const keyword_type_t *kw = type->of;
+ cfg_print_cstr(pctx, kw->name);
+ cfg_print_cstr(pctx, " ");
+ cfg_doc_obj(pctx, kw->type);
+}
+
+static void
+doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const keyword_type_t *kw = type->of;
+ cfg_print_cstr(pctx, "[ ");
+ cfg_print_cstr(pctx, kw->name);
+ cfg_print_cstr(pctx, " ");
+ cfg_doc_obj(pctx, kw->type);
+ cfg_print_cstr(pctx, " ]");
+}
+
+static const char *dialup_enums[] = {
+ "notify", "notify-passive", "passive", "refresh", NULL
+};
+static isc_result_t
+parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static void
+doc_dialup_type(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_boolean);
+}
+static cfg_type_t cfg_type_dialuptype = {
+ "dialuptype", parse_dialup_type, cfg_print_ustring, doc_dialup_type,
+ &cfg_rep_string, dialup_enums
+};
+
+static const char *notify_enums[] = { "explicit", "master-only", NULL };
+static isc_result_t
+parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static void
+doc_notify_type(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_boolean);
+}
+static cfg_type_t cfg_type_notifytype = {
+ "notifytype", parse_notify_type, cfg_print_ustring, doc_notify_type,
+ &cfg_rep_string, notify_enums,
+};
+
+static const char *minimal_enums[] = { "no-auth", "no-auth-recursive", NULL };
+static isc_result_t
+parse_minimal(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static void
+doc_minimal(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_boolean);
+}
+static cfg_type_t cfg_type_minimal = {
+ "mimimal", parse_minimal, cfg_print_ustring, doc_minimal,
+ &cfg_rep_string, minimal_enums,
+};
+
+static const char *ixfrdiff_enums[] = { "master", "slave", NULL };
+static isc_result_t
+parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static void
+doc_ixfrdiff_type(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_boolean);
+}
+static cfg_type_t cfg_type_ixfrdifftype = {
+ "ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring, doc_ixfrdiff_type,
+ &cfg_rep_string, ixfrdiff_enums,
+};
+
+static const char *filter_aaaa_enums[] = { "break-dnssec", NULL };
+static isc_result_t
+parse_filter_aaaa(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static void
+doc_filter_aaaa(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_boolean);
+}
+static cfg_type_t cfg_type_filter_aaaa = {
+ "filter_aaaa", parse_filter_aaaa, cfg_print_ustring,
+ doc_filter_aaaa, &cfg_rep_string, filter_aaaa_enums,
+};
+
+static keyword_type_t key_kw = { "key", &cfg_type_astring };
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = {
+ "keyref", parse_keyvalue, print_keyvalue, doc_keyvalue,
+ &cfg_rep_string, &key_kw
+};
+
+static cfg_type_t cfg_type_optional_keyref = {
+ "optional_keyref", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_string, &key_kw
+};
+
+#ifdef HAVE_GEOIP
+/*
+ * "geoip" ACL element:
+ * geoip [ db <database> ] search-type <string>
+ */
+static const char *geoiptype_enums[] = {
+ "area", "areacode", "asnum", "city", "continent", "country",
+ "country3", "countryname", "domain", "isp", "metro", "metrocode",
+ "netspeed", "org", "postal", "postalcode", "region", "regionname",
+ "timezone", "tz", NULL
+};
+static cfg_type_t cfg_type_geoiptype = {
+ "geoiptype", cfg_parse_enum, cfg_print_ustring,
+ cfg_doc_enum, &cfg_rep_string, &geoiptype_enums
+};
+
+static const char *geoipdb_enums[] = {
+ "asnum", "city", "country", "domain", "isp", "netspeed",
+ "org", "region", NULL
+};
+static cfg_type_t cfg_type_geoipdb = {
+ "geoipdb", cfg_parse_enum, cfg_print_ustring,
+ cfg_doc_enum, &cfg_rep_string, &geoipdb_enums
+};
+
+static cfg_tuplefielddef_t geoip_fields[] = {
+ { "negated", &cfg_type_void, 0 },
+ { "db", &cfg_type_geoipdb, 0 },
+ { "subtype", &cfg_type_geoiptype, 0 },
+ { "search", &cfg_type_astring, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_geoip = {
+ "geoip", parse_geoip, print_geoip, doc_geoip,
+ &cfg_rep_tuple, geoip_fields
+};
+
+static isc_result_t
+parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ const cfg_tuplefielddef_t *fields = type->of;
+
+ CHECK(cfg_create_tuple(pctx, type, &obj));
+ CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[0]));
+
+ /* Parse the optional "db" field. */
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string) {
+ CHECK(cfg_gettoken(pctx, 0));
+ if (strcasecmp(TOKEN_STRING(pctx), "db") == 0 &&
+ obj->value.tuple[1] == NULL) {
+ CHECK(cfg_parse_obj(pctx, fields[1].type,
+ &obj->value.tuple[1]));
+ } else {
+ CHECK(cfg_parse_void(pctx, NULL,
+ &obj->value.tuple[1]));
+ cfg_ungettoken(pctx);
+ }
+ }
+
+ CHECK(cfg_parse_obj(pctx, fields[2].type, &obj->value.tuple[2]));
+ CHECK(cfg_parse_obj(pctx, fields[3].type, &obj->value.tuple[3]));
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static void
+print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ if (obj->value.tuple[1]->type->print != cfg_print_void) {
+ cfg_print_cstr(pctx, " db ");
+ cfg_print_obj(pctx, obj->value.tuple[1]);
+ }
+ cfg_print_obj(pctx, obj->value.tuple[2]);
+ cfg_print_obj(pctx, obj->value.tuple[3]);
+}
+
+static void
+doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "[ db ");
+ cfg_doc_enum(pctx, &cfg_type_geoipdb);
+ cfg_print_cstr(pctx, " ]");
+ cfg_print_cstr(pctx, " ");
+ cfg_doc_enum(pctx, &cfg_type_geoiptype);
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "<quoted_string>");
+}
+#endif /* HAVE_GEOIP */
+
+/*%
+ * An EDNS client subnet address
+ */
+
+static keyword_type_t ecs_kw = { "ecs", &cfg_type_netprefix };
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_ecsprefix = {
+ "edns_client_subnet", parse_keyvalue, print_keyvalue, doc_keyvalue,
+ &cfg_rep_netprefix, &ecs_kw
+};
+
+/*%
+ * A "controls" statement is represented as a map with the multivalued
+ * "inet" and "unix" clauses.
+ */
+
+static keyword_type_t controls_allow_kw = {
+ "allow", &cfg_type_bracketed_aml };
+
+static cfg_type_t cfg_type_controls_allow = {
+ "controls_allow", parse_keyvalue,
+ print_keyvalue, doc_keyvalue,
+ &cfg_rep_list, &controls_allow_kw
+};
+
+static keyword_type_t controls_keys_kw = {
+ "keys", &cfg_type_keylist
+};
+
+static cfg_type_t cfg_type_controls_keys = {
+ "controls_keys", parse_optional_keyvalue,
+ print_keyvalue, doc_optional_keyvalue,
+ &cfg_rep_list, &controls_keys_kw
+};
+
+static keyword_type_t controls_readonly_kw = {
+ "read-only", &cfg_type_boolean
+};
+
+static cfg_type_t cfg_type_controls_readonly = {
+ "controls_readonly", parse_optional_keyvalue,
+ print_keyvalue, doc_optional_keyvalue,
+ &cfg_rep_boolean, &controls_readonly_kw
+};
+
+static cfg_tuplefielddef_t inetcontrol_fields[] = {
+ { "address", &cfg_type_controls_sockaddr, 0 },
+ { "allow", &cfg_type_controls_allow, 0 },
+ { "keys", &cfg_type_controls_keys, 0 },
+ { "read-only", &cfg_type_controls_readonly, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_inetcontrol = {
+ "inetcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, inetcontrol_fields
+};
+
+static keyword_type_t controls_perm_kw = {
+ "perm", &cfg_type_uint32
+};
+
+static cfg_type_t cfg_type_controls_perm = {
+ "controls_perm", parse_keyvalue,
+ print_keyvalue, doc_keyvalue,
+ &cfg_rep_uint32, &controls_perm_kw
+};
+
+static keyword_type_t controls_owner_kw = {
+ "owner", &cfg_type_uint32
+};
+
+static cfg_type_t cfg_type_controls_owner = {
+ "controls_owner", parse_keyvalue,
+ print_keyvalue, doc_keyvalue,
+ &cfg_rep_uint32, &controls_owner_kw
+};
+
+static keyword_type_t controls_group_kw = {
+ "group", &cfg_type_uint32
+};
+
+static cfg_type_t cfg_type_controls_group = {
+ "controls_allow", parse_keyvalue,
+ print_keyvalue, doc_keyvalue,
+ &cfg_rep_uint32, &controls_group_kw
+};
+
+static cfg_tuplefielddef_t unixcontrol_fields[] = {
+ { "path", &cfg_type_qstring, 0 },
+ { "perm", &cfg_type_controls_perm, 0 },
+ { "owner", &cfg_type_controls_owner, 0 },
+ { "group", &cfg_type_controls_group, 0 },
+ { "keys", &cfg_type_controls_keys, 0 },
+ { "read-only", &cfg_type_controls_readonly, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_unixcontrol = {
+ "unixcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, unixcontrol_fields
+};
+
+static cfg_clausedef_t
+controls_clauses[] = {
+ { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI },
+ { "unix", &cfg_type_unixcontrol, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+controls_clausesets[] = {
+ controls_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_controls = {
+ "controls", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
+ &controls_clausesets
+};
+
+/*%
+ * A "statistics-channels" statement is represented as a map with the
+ * multivalued "inet" clauses.
+ */
+static void
+doc_optional_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const keyword_type_t *kw = type->of;
+ cfg_print_cstr(pctx, "[ ");
+ cfg_print_cstr(pctx, kw->name);
+ cfg_print_cstr(pctx, " ");
+ cfg_doc_obj(pctx, kw->type);
+ cfg_print_cstr(pctx, " ]");
+}
+
+static cfg_type_t cfg_type_optional_allow = {
+ "optional_allow", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_bracketed_list, &cfg_rep_list, &controls_allow_kw
+};
+
+static cfg_tuplefielddef_t statserver_fields[] = {
+ { "address", &cfg_type_controls_sockaddr, 0 }, /* reuse controls def */
+ { "allow", &cfg_type_optional_allow, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_statschannel = {
+ "statschannel", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, statserver_fields
+};
+
+static cfg_clausedef_t
+statservers_clauses[] = {
+ { "inet", &cfg_type_statschannel, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+statservers_clausesets[] = {
+ statservers_clauses,
+ NULL
+};
+
+static cfg_type_t cfg_type_statschannels = {
+ "statistics-channels", cfg_parse_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, &statservers_clausesets
+};
+
+/*%
+ * An optional class, as used in view and zone statements.
+ */
+static isc_result_t
+parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ UNUSED(type);
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string)
+ CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, ret));
+ else
+ CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
+ cleanup:
+ return (result);
+}
+
+static void
+doc_optional_class(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "[ <class> ]");
+}
+
+static cfg_type_t cfg_type_optional_class = {
+ "optional_class", parse_optional_class, NULL, doc_optional_class,
+ NULL, NULL
+};
+
+static isc_result_t
+parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ isc_netaddr_t netaddr;
+ in_port_t port = 0;
+ isc_dscp_t dscp = -1;
+ unsigned int have_address = 0;
+ unsigned int have_port = 0;
+ unsigned int have_dscp = 0;
+ const unsigned int *flagp = type->of;
+
+ if ((*flagp & CFG_ADDR_V4OK) != 0)
+ isc_netaddr_any(&netaddr);
+ else if ((*flagp & CFG_ADDR_V6OK) != 0)
+ isc_netaddr_any6(&netaddr);
+ else
+ INSIST(0);
+
+ for (;;) {
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string) {
+ if (strcasecmp(TOKEN_STRING(pctx),
+ "address") == 0)
+ {
+ /* read "address" */
+ CHECK(cfg_gettoken(pctx, 0));
+ CHECK(cfg_parse_rawaddr(pctx, *flagp,
+ &netaddr));
+ have_address++;
+ } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0)
+ {
+ /* read "port" */
+ CHECK(cfg_gettoken(pctx, 0));
+ CHECK(cfg_parse_rawport(pctx,
+ CFG_ADDR_WILDOK,
+ &port));
+ have_port++;
+ } else if (strcasecmp(TOKEN_STRING(pctx), "dscp") == 0)
+ {
+ /* read "dscp" */
+ CHECK(cfg_gettoken(pctx, 0));
+ CHECK(cfg_parse_dscp(pctx, &dscp));
+ have_dscp++;
+ } else if (have_port == 0 && have_dscp == 0 &&
+ have_address == 0)
+ {
+ return (cfg_parse_sockaddr(pctx, type, ret));
+ } else {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected 'address', 'port', "
+ "or 'dscp'");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ } else
+ break;
+ }
+ if (have_address > 1 || have_port > 1 ||
+ have_address + have_port == 0) {
+ cfg_parser_error(pctx, 0, "expected one address and/or port");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+
+ if (have_dscp > 1) {
+ cfg_parser_error(pctx, 0, "expected at most one dscp");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj));
+ isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
+ obj->value.sockaddrdscp.dscp = dscp;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source");
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static void
+print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ isc_netaddr_t na;
+ isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr);
+ cfg_print_cstr(pctx, "address ");
+ cfg_print_rawaddr(pctx, &na);
+ cfg_print_cstr(pctx, " port ");
+ cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr));
+ if (obj->value.sockaddrdscp.dscp != -1) {
+ cfg_print_cstr(pctx, " dscp ");
+ cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp);
+ }
+}
+
+static void
+doc_querysource(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const unsigned int *flagp = type->of;
+
+ cfg_print_cstr(pctx, "( ( [ address ] ( ");
+ if (*flagp & CFG_ADDR_V4OK)
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ else if (*flagp & CFG_ADDR_V6OK)
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ else
+ INSIST(0);
+ cfg_print_cstr(pctx, " | * ) [ port ( <integer> | * ) ] ) | "
+ "( [ [ address ] ( ");
+ if (*flagp & CFG_ADDR_V4OK)
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ else if (*flagp & CFG_ADDR_V6OK)
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ else
+ INSIST(0);
+ cfg_print_cstr(pctx, " | * ) ] port ( <integer> | * ) ) )"
+ " [ dscp <integer> ]");
+}
+
+static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK |
+ CFG_ADDR_DSCPOK;
+static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK |
+ CFG_ADDR_DSCPOK;
+
+static cfg_type_t cfg_type_querysource4 = {
+ "querysource4", parse_querysource, NULL, doc_querysource,
+ NULL, &sockaddr4wild_flags
+};
+
+static cfg_type_t cfg_type_querysource6 = {
+ "querysource6", parse_querysource, NULL, doc_querysource,
+ NULL, &sockaddr6wild_flags
+};
+
+static cfg_type_t cfg_type_querysource = {
+ "querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL
+};
+
+/*% addrmatchelt */
+
+static isc_result_t
+parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
+
+ if (pctx->token.type == isc_tokentype_string ||
+ pctx->token.type == isc_tokentype_qstring) {
+ if (pctx->token.type == isc_tokentype_string &&
+ (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
+ } else if (pctx->token.type == isc_tokentype_string &&
+ (strcasecmp(TOKEN_STRING(pctx), "ecs") == 0)) {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_ecsprefix, ret));
+ } else if (pctx->token.type == isc_tokentype_string &&
+ (strcasecmp(TOKEN_STRING(pctx), "geoip") == 0)) {
+#ifdef HAVE_GEOIP
+ CHECK(cfg_gettoken(pctx, 0));
+ CHECK(cfg_parse_obj(pctx, &cfg_type_geoip, ret));
+#else
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "'geoip' "
+ "not supported in this build");
+ return (ISC_R_UNEXPECTEDTOKEN);
+#endif
+ } else {
+ if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK |
+ CFG_ADDR_V4PREFIXOK |
+ CFG_ADDR_V6OK))
+ {
+ CHECK(cfg_parse_netprefix(pctx, NULL, ret));
+ } else {
+ CHECK(cfg_parse_astring(pctx, NULL, ret));
+ }
+ }
+ } else if (pctx->token.type == isc_tokentype_special) {
+ if (pctx->token.value.as_char == '{') {
+ /* Nested match list. */
+ CHECK(cfg_parse_obj(pctx,
+ &cfg_type_bracketed_aml, ret));
+ } else if (pctx->token.value.as_char == '!') {
+ CHECK(cfg_gettoken(pctx, 0)); /* read "!" */
+ CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret));
+ } else {
+ goto bad;
+ }
+ } else {
+ bad:
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IP match list element");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ cleanup:
+ return (result);
+}
+
+/*%
+ * A negated address match list element (like "! 10.0.0.1").
+ * Somewhat sneakily, the caller is expected to parse the
+ * "!", but not to print it.
+ */
+
+static cfg_tuplefielddef_t negated_fields[] = {
+ { "negated", &cfg_type_addrmatchelt, 0 },
+ { NULL, NULL, 0 }
+};
+
+static void
+print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_cstr(pctx, "!");
+ cfg_print_tuple(pctx, obj);
+}
+
+static cfg_type_t cfg_type_negated = {
+ "negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple,
+ &negated_fields
+};
+
+/*% An address match list element */
+
+static cfg_type_t cfg_type_addrmatchelt = {
+ "address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal,
+ NULL, NULL
+};
+
+/*% A bracketed address match list */
+
+static cfg_type_t cfg_type_bracketed_aml = {
+ "bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt
+};
+
+/*%
+ * The socket address syntax in the "controls" statement is silly.
+ * It allows both socket address families, but also allows "*",
+ * whis is gratuitously interpreted as the IPv4 wildcard address.
+ */
+static unsigned int controls_sockaddr_flags =
+ CFG_ADDR_V4OK | CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
+static cfg_type_t cfg_type_controls_sockaddr = {
+ "controls_sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr,
+ cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags
+};
+
+/*%
+ * Handle the special kludge syntax of the "keys" clause in the "server"
+ * statement, which takes a single key with or without braces and semicolon.
+ */
+static isc_result_t
+parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ bool braces = false;
+ UNUSED(type);
+
+ /* Allow opening brace. */
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == '{') {
+ CHECK(cfg_gettoken(pctx, 0));
+ braces = true;
+ }
+
+ CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
+
+ if (braces) {
+ /* Skip semicolon if present. */
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == ';')
+ CHECK(cfg_gettoken(pctx, 0));
+
+ CHECK(cfg_parse_special(pctx, '}'));
+ }
+ cleanup:
+ return (result);
+}
+static cfg_type_t cfg_type_server_key_kludge = {
+ "server_key", parse_server_key_kludge, NULL, cfg_doc_terminal,
+ NULL, NULL
+};
+
+
+/*%
+ * An optional logging facility.
+ */
+
+static isc_result_t
+parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string ||
+ pctx->token.type == isc_tokentype_qstring) {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
+ } else {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
+ }
+ cleanup:
+ return (result);
+}
+
+static void
+doc_optional_facility(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "[ <syslog_facility> ]");
+}
+
+static cfg_type_t cfg_type_optional_facility = {
+ "optional_facility", parse_optional_facility, NULL,
+ doc_optional_facility, NULL, NULL
+};
+
+
+/*%
+ * A log severity. Return as a string, except "debug N",
+ * which is returned as a keyword object.
+ */
+
+static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 };
+static cfg_type_t cfg_type_debuglevel = {
+ "debuglevel", parse_keyvalue,
+ print_keyvalue, doc_keyvalue,
+ &cfg_rep_uint32, &debug_kw
+};
+
+static isc_result_t
+parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "debug") == 0) {
+ CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */
+ CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER));
+ if (pctx->token.type == isc_tokentype_number) {
+ CHECK(cfg_parse_uint32(pctx, NULL, ret));
+ } else {
+ /*
+ * The debug level is optional and defaults to 1.
+ * This makes little sense, but we support it for
+ * compatibility with BIND 8.
+ */
+ CHECK(cfg_create_obj(pctx, &cfg_type_uint32, ret));
+ (*ret)->value.uint32 = 1;
+ }
+ (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */
+ } else {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_loglevel, ret));
+ }
+ cleanup:
+ return (result);
+}
+
+static cfg_type_t cfg_type_logseverity = {
+ "log_severity", parse_logseverity, NULL, cfg_doc_terminal,
+ NULL, NULL
+};
+
+/*%
+ * The "file" clause of the "channel" statement.
+ * This is yet another special case.
+ */
+
+static const char *logversions_enums[] = { "unlimited", NULL };
+static isc_result_t
+parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ return (parse_enum_or_other(pctx, type, &cfg_type_uint32, ret));
+}
+
+static void
+doc_logversions(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_uint32);
+}
+
+static cfg_type_t cfg_type_logversions = {
+ "logversions", parse_logversions, cfg_print_ustring, doc_logversions,
+ &cfg_rep_string, logversions_enums
+};
+
+static cfg_tuplefielddef_t logfile_fields[] = {
+ { "file", &cfg_type_qstring, 0 },
+ { "versions", &cfg_type_logversions, 0 },
+ { "size", &cfg_type_size, 0 },
+ { NULL, NULL, 0 }
+};
+
+static isc_result_t
+parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ const cfg_tuplefielddef_t *fields = type->of;
+
+ CHECK(cfg_create_tuple(pctx, type, &obj));
+
+ /* Parse the mandatory "file" field */
+ CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
+
+ /* Parse "versions" and "size" fields in any order. */
+ for (;;) {
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string) {
+ CHECK(cfg_gettoken(pctx, 0));
+ if (strcasecmp(TOKEN_STRING(pctx),
+ "versions") == 0 &&
+ obj->value.tuple[1] == NULL) {
+ CHECK(cfg_parse_obj(pctx, fields[1].type,
+ &obj->value.tuple[1]));
+ } else if (strcasecmp(TOKEN_STRING(pctx),
+ "size") == 0 &&
+ obj->value.tuple[2] == NULL) {
+ CHECK(cfg_parse_obj(pctx, fields[2].type,
+ &obj->value.tuple[2]));
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* Create void objects for missing optional values. */
+ if (obj->value.tuple[1] == NULL)
+ CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
+ if (obj->value.tuple[2] == NULL)
+ CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2]));
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static void
+print_logfile(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_obj(pctx, obj->value.tuple[0]); /* file */
+ if (obj->value.tuple[1]->type->print != cfg_print_void) {
+ cfg_print_cstr(pctx, " versions ");
+ cfg_print_obj(pctx, obj->value.tuple[1]);
+ }
+ if (obj->value.tuple[2]->type->print != cfg_print_void) {
+ cfg_print_cstr(pctx, " size ");
+ cfg_print_obj(pctx, obj->value.tuple[2]);
+ }
+}
+
+
+static void
+doc_logfile(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "<quoted_string>");
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "[ versions ( \"unlimited\" | <integer> ) ]");
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "[ size <size> ]");
+}
+
+static cfg_type_t cfg_type_logfile = {
+ "log_file", parse_logfile, print_logfile, doc_logfile,
+ &cfg_rep_tuple, logfile_fields
+};
+
+/*% An IPv4 address with optional dscp and port, "*" accepted as wildcard. */
+static cfg_type_t cfg_type_sockaddr4wild = {
+ "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr,
+ cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags
+};
+
+/*% An IPv6 address with optional port, "*" accepted as wildcard. */
+static cfg_type_t cfg_type_sockaddr6wild = {
+ "v6addrportwild", cfg_parse_sockaddr, cfg_print_sockaddr,
+ cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr6wild_flags
+};
+
+/*%
+ * lwres
+ */
+
+static cfg_tuplefielddef_t lwres_view_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "class", &cfg_type_optional_class, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_lwres_view = {
+ "lwres_view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, lwres_view_fields
+};
+
+static cfg_type_t cfg_type_lwres_searchlist = {
+ "lwres_searchlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
+};
+
+static cfg_clausedef_t
+lwres_clauses[] = {
+ { "listen-on", &cfg_type_portiplist, 0 },
+ { "view", &cfg_type_lwres_view, 0 },
+ { "search", &cfg_type_lwres_searchlist, 0 },
+ { "ndots", &cfg_type_uint32, 0 },
+ { "lwres-tasks", &cfg_type_uint32, 0},
+ { "lwres-clients", &cfg_type_uint32, 0},
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+lwres_clausesets[] = {
+ lwres_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_lwres = {
+ "lwres", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
+ lwres_clausesets
+};
+
+/*%
+ * rndc
+ */
+
+static cfg_clausedef_t
+rndcconf_options_clauses[] = {
+ { "default-key", &cfg_type_astring, 0 },
+ { "default-port", &cfg_type_uint32, 0 },
+ { "default-server", &cfg_type_astring, 0 },
+ { "default-source-address", &cfg_type_netaddr4wild, 0 },
+ { "default-source-address-v6", &cfg_type_netaddr6wild, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+rndcconf_options_clausesets[] = {
+ rndcconf_options_clauses,
+ NULL
+};
+
+static cfg_type_t cfg_type_rndcconf_options = {
+ "rndcconf_options", cfg_parse_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, rndcconf_options_clausesets
+};
+
+static cfg_clausedef_t
+rndcconf_server_clauses[] = {
+ { "key", &cfg_type_astring, 0 },
+ { "port", &cfg_type_uint32, 0 },
+ { "source-address", &cfg_type_netaddr4wild, 0 },
+ { "source-address-v6", &cfg_type_netaddr6wild, 0 },
+ { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+rndcconf_server_clausesets[] = {
+ rndcconf_server_clauses,
+ NULL
+};
+
+static cfg_type_t cfg_type_rndcconf_server = {
+ "rndcconf_server", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, rndcconf_server_clausesets
+};
+
+static cfg_clausedef_t
+rndcconf_clauses[] = {
+ { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
+ { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI },
+ { "options", &cfg_type_rndcconf_options, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+rndcconf_clausesets[] = {
+ rndcconf_clauses,
+ NULL
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = {
+ "rndcconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
+ &cfg_rep_map, rndcconf_clausesets
+};
+
+static cfg_clausedef_t
+rndckey_clauses[] = {
+ { "key", &cfg_type_key, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+rndckey_clausesets[] = {
+ rndckey_clauses,
+ NULL
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = {
+ "rndckey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
+ &cfg_rep_map, rndckey_clausesets
+};
+
+/*
+ * session.key has exactly the same syntax as rndc.key, but it's defined
+ * separately for clarity (and so we can extend it someday, if needed).
+ */
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sessionkey = {
+ "sessionkey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
+ &cfg_rep_map, rndckey_clausesets
+};
+
+static cfg_tuplefielddef_t nameport_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "port", &cfg_type_optional_port, 0 },
+ { "dscp", &cfg_type_optional_dscp, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_nameport = {
+ "nameport", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, nameport_fields
+};
+
+static void
+doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "( ");
+ cfg_print_cstr(pctx, "<quoted_string>");
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "[ port <integer> ]");
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "[ dscp <integer> ]");
+ cfg_print_cstr(pctx, " | ");
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "[ port <integer> ]");
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "[ dscp <integer> ]");
+ cfg_print_cstr(pctx, " | ");
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "[ port <integer> ]");
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "[ dscp <integer> ]");
+ cfg_print_cstr(pctx, " )");
+}
+
+static isc_result_t
+parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string ||
+ pctx->token.type == isc_tokentype_qstring) {
+ if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
+ CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr,
+ ret));
+ else {
+ const cfg_tuplefielddef_t *fields =
+ cfg_type_nameport.of;
+ CHECK(cfg_create_tuple(pctx, &cfg_type_nameport,
+ &obj));
+ CHECK(cfg_parse_obj(pctx, fields[0].type,
+ &obj->value.tuple[0]));
+ CHECK(cfg_parse_obj(pctx, fields[1].type,
+ &obj->value.tuple[1]));
+ CHECK(cfg_parse_obj(pctx, fields[2].type,
+ &obj->value.tuple[2]));
+ *ret = obj;
+ obj = NULL;
+ }
+ } else {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IP address or hostname");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static cfg_type_t cfg_type_sockaddrnameport = {
+ "sockaddrnameport_element", parse_sockaddrnameport, NULL,
+ doc_sockaddrnameport, NULL, NULL
+};
+
+static cfg_type_t cfg_type_bracketed_sockaddrnameportlist = {
+ "bracketed_sockaddrnameportlist", cfg_parse_bracketed_list,
+ cfg_print_bracketed_list, cfg_doc_bracketed_list,
+ &cfg_rep_list, &cfg_type_sockaddrnameport
+};
+
+/*%
+ * A list of socket addresses or name with an optional default port,
+ * as used in the dual-stack-servers option. E.g.,
+ * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }"
+ */
+static cfg_tuplefielddef_t nameportiplist_fields[] = {
+ { "port", &cfg_type_optional_port, 0 },
+ { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_nameportiplist = {
+ "nameportiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, nameportiplist_fields
+};
+
+/*%
+ * masters element.
+ */
+
+static void
+doc_masterselement(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_cstr(pctx, "( ");
+ cfg_print_cstr(pctx, "<masters>");
+ cfg_print_cstr(pctx, " | ");
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "[ port <integer> ]");
+ cfg_print_cstr(pctx, " | ");
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ cfg_print_cstr(pctx, " ");
+ cfg_print_cstr(pctx, "[ port <integer> ]");
+ cfg_print_cstr(pctx, " )");
+}
+
+static isc_result_t
+parse_masterselement(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string ||
+ pctx->token.type == isc_tokentype_qstring) {
+ if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
+ CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr,
+ ret));
+ else
+ CHECK(cfg_parse_astring(pctx, &cfg_type_astring, ret));
+ } else {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IP address or masters name");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static cfg_type_t cfg_type_masterselement = {
+ "masters_element", parse_masterselement, NULL,
+ doc_masterselement, NULL, NULL
+};
+
+static isc_result_t
+parse_ttlval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ uint32_t ttl;
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type != isc_tokentype_string) {
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+
+ result = dns_ttl_fromtext(&pctx->token.value.as_textregion, &ttl);
+ if (result == ISC_R_RANGE ) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "TTL out of range ");
+ return (result);
+ } else if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
+ obj->value.uint32 = ttl;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected integer and optional unit");
+ return (result);
+}
+
+/*%
+ * A TTL value (number + optional unit).
+ */
+static cfg_type_t cfg_type_ttlval = {
+ "ttlval", parse_ttlval, cfg_print_uint64, cfg_doc_terminal,
+ &cfg_rep_uint64, NULL
+};
+
+static isc_result_t
+parse_maxttl(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_ttlval, ret));
+}
+
+static void
+doc_maxttl(cfg_printer_t *pctx, const cfg_type_t *type) {
+ doc_enum_or_other(pctx, type, &cfg_type_ttlval);
+}
+
+/*%
+ * A size or "unlimited", but not "default".
+ */
+static const char *maxttl_enums[] = { "unlimited", NULL };
+static cfg_type_t cfg_type_maxttl = {
+ "maxttl_no_default", parse_maxttl, cfg_print_ustring, doc_maxttl,
+ &cfg_rep_string, maxttl_enums
+};
+
+static int cmp_clause(const void *ap, const void *bp) {
+ const cfg_clausedef_t *a = (const cfg_clausedef_t *)ap;
+ const cfg_clausedef_t *b = (const cfg_clausedef_t *)bp;
+ return (strcmp(a->name, b->name));
+}
+
+bool
+cfg_clause_validforzone(const char *name, unsigned int ztype) {
+ const cfg_clausedef_t *clause;
+ bool valid = false;
+
+ for (clause = zone_clauses; clause->name != NULL; clause++) {
+ if ((clause->flags & ztype) == 0 ||
+ strcmp(clause->name, name) != 0)
+ {
+ continue;
+ }
+ valid = true;
+ }
+ for (clause = zone_only_clauses; clause->name != NULL; clause++) {
+ if ((clause->flags & ztype) == 0 ||
+ strcmp(clause->name, name) != 0)
+ {
+ continue;
+ }
+ valid = true;
+ }
+
+ return (valid);
+}
+
+void
+cfg_print_zonegrammar(const unsigned int zonetype,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure)
+{
+#define NCLAUSES \
+ (((sizeof(zone_clauses) + sizeof(zone_only_clauses)) / \
+ sizeof(clause[0])) - 1)
+
+ cfg_printer_t pctx;
+ cfg_clausedef_t *clause = NULL;
+ cfg_clausedef_t clauses[NCLAUSES];
+
+ pctx.f = f;
+ pctx.closure = closure;
+ pctx.indent = 0;
+ pctx.flags = 0;
+
+ memmove(clauses, zone_clauses, sizeof(zone_clauses));
+ memmove(clauses + sizeof(zone_clauses)/sizeof(zone_clauses[0]) - 1,
+ zone_only_clauses, sizeof(zone_only_clauses));
+ qsort(clauses, NCLAUSES - 1, sizeof(clause[0]), cmp_clause);
+
+ cfg_print_cstr(&pctx, "zone <string> [ <class> ] {\n");
+ pctx.indent++;
+
+ switch (zonetype) {
+ case CFG_ZONE_MASTER:
+ cfg_print_indent(&pctx);
+ cfg_print_cstr(&pctx, "type ( master | primary );\n");
+ break;
+ case CFG_ZONE_SLAVE:
+ cfg_print_indent(&pctx);
+ cfg_print_cstr(&pctx, "type ( slave | secondary );\n");
+ break;
+ case CFG_ZONE_STUB:
+ cfg_print_indent(&pctx);
+ cfg_print_cstr(&pctx, "type stub;\n");
+ break;
+ case CFG_ZONE_HINT:
+ cfg_print_indent(&pctx);
+ cfg_print_cstr(&pctx, "type hint;\n");
+ break;
+ case CFG_ZONE_FORWARD:
+ cfg_print_indent(&pctx);
+ cfg_print_cstr(&pctx, "type forward;\n");
+ break;
+ case CFG_ZONE_STATICSTUB:
+ cfg_print_indent(&pctx);
+ cfg_print_cstr(&pctx, "type static-stub;\n");
+ break;
+ case CFG_ZONE_REDIRECT:
+ cfg_print_indent(&pctx);
+ cfg_print_cstr(&pctx, "type redirect;\n");
+ break;
+ case CFG_ZONE_DELEGATION:
+ cfg_print_indent(&pctx);
+ cfg_print_cstr(&pctx, "type delegation-only;\n");
+ break;
+ case CFG_ZONE_INVIEW:
+ /* no zone type is specified for these */
+ break;
+ default:
+ INSIST(0);
+ }
+
+ for (clause = clauses; clause->name != NULL; clause++) {
+ if ((clause->flags & zonetype) == 0 ||
+ strcasecmp(clause->name, "type") == 0) {
+ continue;
+ }
+ cfg_print_indent(&pctx);
+ cfg_print_cstr(&pctx, clause->name);
+ cfg_print_cstr(&pctx, " ");
+ cfg_doc_obj(&pctx, clause->type);
+ cfg_print_cstr(&pctx, ";");
+ cfg_print_clauseflags(&pctx, clause->flags);
+ cfg_print_cstr(&pctx, "\n");
+ }
+
+ pctx.indent--;
+ cfg_print_cstr(&pctx, "};\n");
+}
diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c
new file mode 100644
index 0000000..e08e257
--- /dev/null
+++ b/lib/isccfg/parser.c
@@ -0,0 +1,3282 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/dir.h>
+#include <isc/formatcheck.h>
+#include <isc/lex.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/net.h>
+#include <isc/netaddr.h>
+#include <isc/netscope.h>
+#include <isc/print.h>
+#include <isc/refcount.h>
+#include <isc/string.h>
+#include <isc/sockaddr.h>
+#include <isc/symtab.h>
+#include <isc/util.h>
+
+#include <isccfg/cfg.h>
+#include <isccfg/grammar.h>
+#include <isccfg/log.h>
+
+/* Shorthand */
+#define CAT CFG_LOGCATEGORY_CONFIG
+#define MOD CFG_LOGMODULE_PARSER
+
+#define MAP_SYM 1 /* Unique type for isc_symtab */
+
+#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
+
+/* Check a return value. */
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto cleanup; \
+ } while (0)
+
+/* Clean up a configuration object if non-NULL. */
+#define CLEANUP_OBJ(obj) \
+ do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
+
+
+/*
+ * Forward declarations of static functions.
+ */
+
+static void
+free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj);
+
+static isc_result_t
+parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+static void
+print_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+static void
+free_list(cfg_parser_t *pctx, cfg_obj_t *obj);
+
+static isc_result_t
+create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp);
+
+static isc_result_t
+create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
+ cfg_obj_t **ret);
+
+static void
+free_string(cfg_parser_t *pctx, cfg_obj_t *obj);
+
+static isc_result_t
+create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
+
+static void
+free_map(cfg_parser_t *pctx, cfg_obj_t *obj);
+
+static isc_result_t
+parse_symtab_elt(cfg_parser_t *pctx, const char *name,
+ cfg_type_t *elttype, isc_symtab_t *symtab,
+ bool callback);
+
+static void
+free_noop(cfg_parser_t *pctx, cfg_obj_t *obj);
+
+static isc_result_t
+cfg_getstringtoken(cfg_parser_t *pctx);
+
+static void
+parser_complain(cfg_parser_t *pctx, bool is_warning,
+ unsigned int flags, const char *format, va_list args);
+
+/*
+ * Data representations. These correspond to members of the
+ * "value" union in struct cfg_obj (except "void", which does
+ * not need a union member).
+ */
+
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_string = { "string", free_string };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_boolean = { "boolean", free_noop };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_map = { "map", free_map };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_list = { "list", free_list };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_netprefix =
+ { "netprefix", free_noop };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_void = { "void", free_noop };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_fixedpoint =
+ { "fixedpoint", free_noop };
+LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_percentage =
+ { "percentage", free_noop };
+
+/*
+ * Configuration type definitions.
+ */
+
+/*%
+ * An implicit list. These are formed by clauses that occur multiple times.
+ */
+static cfg_type_t cfg_type_implicitlist = {
+ "implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL };
+
+/* Functions. */
+
+void
+cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ obj->type->print(pctx, obj);
+}
+
+void
+cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(text != NULL);
+
+ pctx->f(pctx->closure, text, len);
+}
+
+static void
+print_open(cfg_printer_t *pctx) {
+ if ((pctx->flags & CFG_PRINTER_ONELINE) != 0)
+ cfg_print_cstr(pctx, "{ ");
+ else {
+ cfg_print_cstr(pctx, "{\n");
+ pctx->indent++;
+ }
+}
+
+void
+cfg_print_indent(cfg_printer_t *pctx) {
+ int indent = pctx->indent;
+ if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) {
+ cfg_print_cstr(pctx, " ");
+ return;
+ }
+ while (indent > 0) {
+ cfg_print_cstr(pctx, "\t");
+ indent--;
+ }
+}
+
+static void
+print_close(cfg_printer_t *pctx) {
+ if ((pctx->flags & CFG_PRINTER_ONELINE) == 0) {
+ pctx->indent--;
+ cfg_print_indent(pctx);
+ }
+ cfg_print_cstr(pctx, "}");
+}
+
+isc_result_t
+cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ result = type->parse(pctx, type, ret);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ ENSURE(*ret != NULL);
+ return (ISC_R_SUCCESS);
+}
+
+void
+cfg_print(const cfg_obj_t *obj,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure)
+{
+ REQUIRE(obj != NULL);
+ REQUIRE(f != NULL);
+
+ cfg_printx(obj, 0, f, closure);
+}
+
+void
+cfg_printx(const cfg_obj_t *obj, unsigned int flags,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure)
+{
+ cfg_printer_t pctx;
+
+ REQUIRE(obj != NULL);
+ REQUIRE(f != NULL);
+
+ pctx.f = f;
+ pctx.closure = closure;
+ pctx.indent = 0;
+ pctx.flags = flags;
+ obj->type->print(&pctx, obj);
+}
+
+/* Tuples. */
+
+isc_result_t
+cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ const cfg_tuplefielddef_t *fields = type->of;
+ const cfg_tuplefielddef_t *f;
+ cfg_obj_t *obj = NULL;
+ unsigned int nfields = 0;
+ int i;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ for (f = fields; f->name != NULL; f++)
+ nfields++;
+
+ CHECK(cfg_create_obj(pctx, type, &obj));
+ obj->value.tuple = isc_mem_get(pctx->mctx,
+ nfields * sizeof(cfg_obj_t *));
+ if (obj->value.tuple == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ for (f = fields, i = 0; f->name != NULL; f++, i++)
+ obj->value.tuple[i] = NULL;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (obj != NULL)
+ isc_mem_put(pctx->mctx, obj, sizeof(*obj));
+ return (result);
+}
+
+isc_result_t
+cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ const cfg_tuplefielddef_t *fields = type->of;
+ const cfg_tuplefielddef_t *f;
+ cfg_obj_t *obj = NULL;
+ unsigned int i;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ CHECK(cfg_create_tuple(pctx, type, &obj));
+ for (f = fields, i = 0; f->name != NULL; f++, i++)
+ CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i]));
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+void
+cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ unsigned int i;
+ const cfg_tuplefielddef_t *fields;
+ const cfg_tuplefielddef_t *f;
+ bool need_space = false;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ fields = obj->type->of;
+
+ for (f = fields, i = 0; f->name != NULL; f++, i++) {
+ const cfg_obj_t *fieldobj = obj->value.tuple[i];
+ if (need_space && fieldobj->type->rep != &cfg_rep_void)
+ cfg_print_cstr(pctx, " ");
+ cfg_print_obj(pctx, fieldobj);
+ need_space = (need_space ||
+ fieldobj->type->print != cfg_print_void);
+ }
+}
+
+void
+cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const cfg_tuplefielddef_t *fields;
+ const cfg_tuplefielddef_t *f;
+ bool need_space = false;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+
+ fields = type->of;
+
+ for (f = fields; f->name != NULL; f++) {
+ if (need_space)
+ cfg_print_cstr(pctx, " ");
+ cfg_doc_obj(pctx, f->type);
+ need_space = (f->type->print != cfg_print_void);
+ }
+}
+
+static void
+free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
+ unsigned int i;
+ const cfg_tuplefielddef_t *fields = obj->type->of;
+ const cfg_tuplefielddef_t *f;
+ unsigned int nfields = 0;
+
+ if (obj->value.tuple == NULL)
+ return;
+
+ for (f = fields, i = 0; f->name != NULL; f++, i++) {
+ CLEANUP_OBJ(obj->value.tuple[i]);
+ nfields++;
+ }
+ isc_mem_put(pctx->mctx, obj->value.tuple,
+ nfields * sizeof(cfg_obj_t *));
+}
+
+bool
+cfg_obj_istuple(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_tuple);
+}
+
+const cfg_obj_t *
+cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) {
+ unsigned int i;
+ const cfg_tuplefielddef_t *fields;
+ const cfg_tuplefielddef_t *f;
+
+ REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple);
+ REQUIRE(name != NULL);
+
+ fields = tupleobj->type->of;
+ for (f = fields, i = 0; f->name != NULL; f++, i++) {
+ if (strcmp(f->name, name) == 0)
+ return (tupleobj->value.tuple[i]);
+ }
+ INSIST(0);
+ return (NULL);
+}
+
+isc_result_t
+cfg_parse_special(cfg_parser_t *pctx, int special) {
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == special)
+ return (ISC_R_SUCCESS);
+
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special);
+ return (ISC_R_UNEXPECTEDTOKEN);
+ cleanup:
+ return (result);
+}
+
+/*
+ * Parse a required semicolon. If it is not there, log
+ * an error and increment the error count but continue
+ * parsing. Since the next token is pushed back,
+ * care must be taken to make sure it is eventually
+ * consumed or an infinite loop may result.
+ */
+static isc_result_t
+parse_semicolon(cfg_parser_t *pctx) {
+ isc_result_t result;
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == ';')
+ return (ISC_R_SUCCESS);
+
+ cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'");
+ cfg_ungettoken(pctx);
+ cleanup:
+ return (result);
+}
+
+/*
+ * Parse EOF, logging and returning an error if not there.
+ */
+static isc_result_t
+parse_eof(cfg_parser_t *pctx) {
+ isc_result_t result;
+
+ CHECK(cfg_gettoken(pctx, 0));
+
+ if (pctx->token.type == isc_tokentype_eof)
+ return (ISC_R_SUCCESS);
+
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ cleanup:
+ return (result);
+}
+
+/* A list of files, used internally for pctx->files. */
+
+static cfg_type_t cfg_type_filelist = {
+ "filelist", NULL, print_list, NULL, &cfg_rep_list,
+ &cfg_type_qstring
+};
+
+isc_result_t
+cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) {
+ isc_result_t result;
+ cfg_parser_t *pctx;
+ isc_lexspecials_t specials;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ pctx = isc_mem_get(mctx, sizeof(*pctx));
+ if (pctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ pctx->mctx = NULL;
+ isc_mem_attach(mctx, &pctx->mctx);
+
+ result = isc_refcount_init(&pctx->references, 1);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
+ return (result);
+ }
+
+ pctx->lctx = lctx;
+ pctx->lexer = NULL;
+ pctx->seen_eof = false;
+ pctx->ungotten = false;
+ pctx->errors = 0;
+ pctx->warnings = 0;
+ pctx->open_files = NULL;
+ pctx->closed_files = NULL;
+ pctx->line = 0;
+ pctx->callback = NULL;
+ pctx->callbackarg = NULL;
+ pctx->token.type = isc_tokentype_unknown;
+ pctx->flags = 0;
+ pctx->buf_name = NULL;
+
+ memset(specials, 0, sizeof(specials));
+ specials['{'] = 1;
+ specials['}'] = 1;
+ specials[';'] = 1;
+ specials['/'] = 1;
+ specials['"'] = 1;
+ specials['!'] = 1;
+
+ CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer));
+
+ isc_lex_setspecials(pctx->lexer, specials);
+ isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C |
+ ISC_LEXCOMMENT_CPLUSPLUS |
+ ISC_LEXCOMMENT_SHELL));
+
+ CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files));
+ CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files));
+
+ *ret = pctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (pctx->lexer != NULL)
+ isc_lex_destroy(&pctx->lexer);
+ CLEANUP_OBJ(pctx->open_files);
+ CLEANUP_OBJ(pctx->closed_files);
+ isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
+ return (result);
+}
+
+static isc_result_t
+parser_openfile(cfg_parser_t *pctx, const char *filename) {
+ isc_result_t result;
+ cfg_listelt_t *elt = NULL;
+ cfg_obj_t *stringobj = NULL;
+
+ result = isc_lex_openfile(pctx->lexer, filename);
+ if (result != ISC_R_SUCCESS) {
+ cfg_parser_error(pctx, 0, "open: %s: %s",
+ filename, isc_result_totext(result));
+ goto cleanup;
+ }
+
+ CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj));
+ CHECK(create_listelt(pctx, &elt));
+ elt->obj = stringobj;
+ ISC_LIST_APPEND(pctx->open_files->value.list, elt, link);
+
+ return (ISC_R_SUCCESS);
+ cleanup:
+ CLEANUP_OBJ(stringobj);
+ return (result);
+}
+
+void
+cfg_parser_setcallback(cfg_parser_t *pctx,
+ cfg_parsecallback_t callback,
+ void *arg)
+{
+ REQUIRE(pctx != NULL);
+
+ pctx->callback = callback;
+ pctx->callbackarg = arg;
+}
+
+void
+cfg_parser_reset(cfg_parser_t *pctx) {
+ REQUIRE(pctx != NULL);
+
+ if (pctx->lexer != NULL)
+ isc_lex_close(pctx->lexer);
+
+ pctx->seen_eof = false;
+ pctx->ungotten = false;
+ pctx->errors = 0;
+ pctx->warnings = 0;
+ pctx->line = 0;
+}
+
+/*
+ * Parse a configuration using a pctx where a lexer has already
+ * been set up with a source.
+ */
+static isc_result_t
+parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+
+ result = cfg_parse_obj(pctx, type, &obj);
+
+ if (pctx->errors != 0) {
+ /* Errors have been logged. */
+ if (result == ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ /* Parsing failed but no errors have been logged. */
+ cfg_parser_error(pctx, 0, "parsing failed: %s",
+ isc_result_totext(result));
+ goto cleanup;
+ }
+
+ CHECK(parse_eof(pctx));
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+isc_result_t
+cfg_parse_file(cfg_parser_t *pctx, const char *filename,
+ const cfg_type_t *type, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_listelt_t *elt;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(filename != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ CHECK(parser_openfile(pctx, filename));
+
+ result = parse2(pctx, type, ret);
+
+ /* Clean up the opened file */
+ elt = ISC_LIST_TAIL(pctx->open_files->value.list);
+ INSIST(elt != NULL);
+ ISC_LIST_UNLINK(pctx->open_files->value.list, elt, link);
+ ISC_LIST_APPEND(pctx->closed_files->value.list, elt, link);
+
+ cleanup:
+ return (result);
+}
+
+
+isc_result_t
+cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer,
+ const cfg_type_t *type, cfg_obj_t **ret)
+{
+ return (cfg_parse_buffer4(pctx, buffer, NULL, 0, type, 0, ret));
+}
+
+isc_result_t
+cfg_parse_buffer2(cfg_parser_t *pctx, isc_buffer_t *buffer,
+ const char *file, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ return (cfg_parse_buffer4(pctx, buffer, file, 0, type, 0, ret));
+}
+
+isc_result_t
+cfg_parse_buffer3(cfg_parser_t *pctx, isc_buffer_t *buffer,
+ const char *file, unsigned int line,
+ const cfg_type_t *type, cfg_obj_t **ret)
+{
+ return (cfg_parse_buffer4(pctx, buffer, file, line, type, 0, ret));
+}
+
+isc_result_t
+cfg_parse_buffer4(cfg_parser_t *pctx, isc_buffer_t *buffer,
+ const char *file, unsigned int line,
+ const cfg_type_t *type, unsigned int flags,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(buffer != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+ REQUIRE((flags & ~(CFG_PCTX_NODEPRECATED)) == 0);
+
+ CHECK(isc_lex_openbuffer(pctx->lexer, buffer));
+
+ pctx->buf_name = file;
+ pctx->flags = flags;
+
+ if (line != 0U)
+ CHECK(isc_lex_setsourceline(pctx->lexer, line));
+
+ CHECK(parse2(pctx, type, ret));
+ pctx->buf_name = NULL;
+
+ cleanup:
+ return (result);
+}
+
+void
+cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) {
+ REQUIRE(src != NULL);
+ REQUIRE(dest != NULL && *dest == NULL);
+
+ isc_refcount_increment(&src->references, NULL);
+ *dest = src;
+}
+
+void
+cfg_parser_destroy(cfg_parser_t **pctxp) {
+ cfg_parser_t *pctx;
+ unsigned int refs;
+
+ REQUIRE(pctxp != NULL && *pctxp != NULL);
+
+ pctx = *pctxp;
+ *pctxp = NULL;
+
+ isc_refcount_decrement(&pctx->references, &refs);
+ if (refs == 0) {
+ isc_lex_destroy(&pctx->lexer);
+ /*
+ * Cleaning up open_files does not
+ * close the files; that was already done
+ * by closing the lexer.
+ */
+ CLEANUP_OBJ(pctx->open_files);
+ CLEANUP_OBJ(pctx->closed_files);
+ isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
+ }
+}
+
+/*
+ * void
+ */
+isc_result_t
+cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ UNUSED(type);
+
+ return (cfg_create_obj(pctx, &cfg_type_void, ret));
+}
+
+void
+cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ UNUSED(pctx);
+ UNUSED(obj);
+}
+
+void
+cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) {
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+
+ UNUSED(pctx);
+ UNUSED(type);
+}
+
+bool
+cfg_obj_isvoid(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_void);
+}
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_void = {
+ "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void,
+ NULL };
+
+/*
+ * percentage
+ */
+isc_result_t
+cfg_parse_percentage(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ char *endp;
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ uint64_t percent;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type != isc_tokentype_string) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected percentage");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+
+ percent = isc_string_touint64(TOKEN_STRING(pctx), &endp, 10);
+ if (*endp != '%' || *(endp+1) != 0) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected percentage");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj));
+ obj->value.uint32 = (uint32_t)percent;
+ *ret = obj;
+
+ cleanup:
+ return (result);
+}
+
+void
+cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ char buf[64];
+ int n;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ n = snprintf(buf, sizeof(buf), "%u%%", obj->value.uint32);
+ INSIST(n > 0 && (size_t)n < sizeof(buf));
+ cfg_print_chars(pctx, buf, strlen(buf));
+}
+
+uint32_t
+cfg_obj_aspercentage(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_percentage);
+ return (obj->value.uint32);
+}
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_percentage = {
+ "percentage", cfg_parse_percentage, cfg_print_percentage,
+ cfg_doc_terminal, &cfg_rep_percentage, NULL
+};
+
+bool
+cfg_obj_ispercentage(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_percentage);
+}
+
+/*
+ * Fixed point
+ */
+isc_result_t
+cfg_parse_fixedpoint(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ size_t n1, n2, n3, l;
+ const char *p;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type != isc_tokentype_string) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected fixed point number");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+
+
+ p = TOKEN_STRING(pctx);
+ l = strlen(p);
+ n1 = strspn(p, "0123456789");
+ n2 = strspn(p + n1, ".");
+ n3 = strspn(p + n1 + n2, "0123456789");
+
+ if ((n1 + n2 + n3 != l) || (n1 + n3 == 0) ||
+ n1 > 5 || n2 > 1 || n3 > 2) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected fixed point number");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_fixedpoint, &obj));
+
+ obj->value.uint32 = strtoul(p, NULL, 10) * 100;
+ switch (n3) {
+ case 2:
+ obj->value.uint32 += strtoul(p + n1 + n2, NULL, 10);
+ break;
+ case 1:
+ obj->value.uint32 += strtoul(p + n1 + n2, NULL, 10) * 10;
+ break;
+ }
+ *ret = obj;
+
+ cleanup:
+ return (result);
+}
+
+void
+cfg_print_fixedpoint(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ char buf[64];
+ int n;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ n = snprintf(buf, sizeof(buf), "%u.%02u",
+ obj->value.uint32/100, obj->value.uint32%100);
+ INSIST(n > 0 && (size_t)n < sizeof(buf));
+ cfg_print_chars(pctx, buf, strlen(buf));
+}
+
+uint32_t
+cfg_obj_asfixedpoint(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_fixedpoint);
+ return (obj->value.uint32);
+}
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_fixedpoint = {
+ "fixedpoint", cfg_parse_fixedpoint, cfg_print_fixedpoint,
+ cfg_doc_terminal, &cfg_rep_fixedpoint, NULL
+};
+
+bool
+cfg_obj_isfixedpoint(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_fixedpoint);
+}
+
+/*
+ * uint32
+ */
+isc_result_t
+cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
+ if (pctx->token.type != isc_tokentype_number) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
+
+ obj->value.uint32 = pctx->token.value.as_ulong;
+ *ret = obj;
+ cleanup:
+ return (result);
+}
+
+void
+cfg_print_cstr(cfg_printer_t *pctx, const char *s) {
+ cfg_print_chars(pctx, s, strlen(s));
+}
+
+void
+cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) {
+ char buf[32];
+
+ snprintf(buf, sizeof(buf), "%u", u);
+ cfg_print_cstr(pctx, buf);
+}
+
+void
+cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_rawuint(pctx, obj->value.uint32);
+}
+
+bool
+cfg_obj_isuint32(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_uint32);
+}
+
+uint32_t
+cfg_obj_asuint32(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
+ return (obj->value.uint32);
+}
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_uint32 = {
+ "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal,
+ &cfg_rep_uint32, NULL
+};
+
+
+/*
+ * uint64
+ */
+bool
+cfg_obj_isuint64(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_uint64);
+}
+
+uint64_t
+cfg_obj_asuint64(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64);
+ return (obj->value.uint64);
+}
+
+void
+cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ char buf[32];
+
+ snprintf(buf, sizeof(buf), "%" PRIu64,
+ obj->value.uint64);
+ cfg_print_cstr(pctx, buf);
+}
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_uint64 = {
+ "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal,
+ &cfg_rep_uint64, NULL
+};
+
+/*
+ * qstring (quoted string), ustring (unquoted string), astring
+ * (any string)
+ */
+
+/* Create a string object from a null-terminated C string. */
+static isc_result_t
+create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ int len;
+
+ CHECK(cfg_create_obj(pctx, type, &obj));
+ len = strlen(contents);
+ obj->value.string.length = len;
+ obj->value.string.base = isc_mem_get(pctx->mctx, len + 1);
+ if (obj->value.string.base == 0) {
+ isc_mem_put(pctx->mctx, obj, sizeof(*obj));
+ return (ISC_R_NOMEMORY);
+ }
+ memmove(obj->value.string.base, contents, len);
+ obj->value.string.base[len] = '\0';
+
+ *ret = obj;
+ cleanup:
+ return (result);
+}
+
+isc_result_t
+cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type != isc_tokentype_qstring) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ return (create_string(pctx, TOKEN_STRING(pctx),
+ &cfg_type_qstring, ret));
+ cleanup:
+ return (result);
+}
+
+static isc_result_t
+parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type != isc_tokentype_string) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ return (create_string(pctx,
+ TOKEN_STRING(pctx),
+ &cfg_type_ustring,
+ ret));
+ cleanup:
+ return (result);
+}
+
+isc_result_t
+cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ UNUSED(type);
+
+ CHECK(cfg_getstringtoken(pctx));
+ return (create_string(pctx,
+ TOKEN_STRING(pctx),
+ &cfg_type_qstring,
+ ret));
+ cleanup:
+ return (result);
+}
+
+isc_result_t
+cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ UNUSED(type);
+
+ CHECK(cfg_getstringtoken(pctx));
+ return (create_string(pctx,
+ TOKEN_STRING(pctx),
+ &cfg_type_sstring,
+ ret));
+ cleanup:
+ return (result);
+}
+
+static isc_result_t
+parse_btext(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_BTEXT));
+ if (pctx->token.type != isc_tokentype_btext) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected bracketed text");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ return (create_string(pctx,
+ TOKEN_STRING(pctx),
+ &cfg_type_bracketed_text,
+ ret));
+ cleanup:
+ return (result);
+}
+
+static void
+print_btext(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ /*
+ * We need to print "{" instead of running print_open()
+ * in order to preserve the exact original formatting
+ * of the bracketed text. But we increment the indent value
+ * so that print_close() will leave us back in our original
+ * state.
+ */
+ pctx->indent++;
+ cfg_print_cstr(pctx, "{");
+ cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
+ print_close(pctx);
+}
+
+static void
+doc_btext(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+
+ cfg_print_cstr(pctx, "{ <unspecified-text> }");
+}
+
+
+bool
+cfg_is_enum(const char *s, const char *const *enums) {
+ const char * const *p;
+
+ REQUIRE(s != NULL);
+ REQUIRE(enums != NULL);
+
+ for (p = enums; *p != NULL; p++) {
+ if (strcasecmp(*p, s) == 0)
+ return (true);
+ }
+ return (false);
+}
+
+static isc_result_t
+check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) {
+ const char *s = obj->value.string.base;
+
+ if (cfg_is_enum(s, enums))
+ return (ISC_R_SUCCESS);
+ cfg_parser_error(pctx, 0, "'%s' unexpected", s);
+ return (ISC_R_UNEXPECTEDTOKEN);
+}
+
+isc_result_t
+cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ CHECK(parse_ustring(pctx, NULL, &obj));
+ CHECK(check_enum(pctx, obj, type->of));
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+void
+cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const char * const *p;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+
+ cfg_print_cstr(pctx, "( ");
+ for (p = type->of; *p != NULL; p++) {
+ cfg_print_cstr(pctx, *p);
+ if (p[1] != NULL)
+ cfg_print_cstr(pctx, " | ");
+ }
+ cfg_print_cstr(pctx, " )");
+}
+
+void
+cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
+}
+
+static void
+print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_cstr(pctx, "\"");
+ cfg_print_ustring(pctx, obj);
+ cfg_print_cstr(pctx, "\"");
+}
+
+static void
+print_sstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_cstr(pctx, "\"");
+ if ((pctx->flags & CFG_PRINTER_XKEY) != 0) {
+ unsigned int len = obj->value.string.length;
+ while (len-- > 0)
+ cfg_print_cstr(pctx, "?");
+ } else
+ cfg_print_ustring(pctx, obj);
+ cfg_print_cstr(pctx, "\"");
+}
+
+static void
+free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
+ isc_mem_put(pctx->mctx, obj->value.string.base,
+ obj->value.string.length + 1);
+}
+
+bool
+cfg_obj_isstring(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_string);
+}
+
+const char *
+cfg_obj_asstring(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
+ return (obj->value.string.base);
+}
+
+/* Quoted string only */
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_qstring = {
+ "quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal,
+ &cfg_rep_string, NULL
+};
+
+/* Unquoted string only */
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_ustring = {
+ "string", parse_ustring, cfg_print_ustring, cfg_doc_terminal,
+ &cfg_rep_string, NULL
+};
+
+/* Any string (quoted or unquoted); printed with quotes */
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_astring = {
+ "string", cfg_parse_astring, print_qstring, cfg_doc_terminal,
+ &cfg_rep_string, NULL
+};
+
+/*
+ * Any string (quoted or unquoted); printed with quotes.
+ * If CFG_PRINTER_XKEY is set when printing the string will be '?' out.
+ */
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sstring = {
+ "string", cfg_parse_sstring, print_sstring, cfg_doc_terminal,
+ &cfg_rep_string, NULL
+};
+
+/*
+ * Text enclosed in brackets. Used to pass a block of configuration
+ * text to dynamic library or external application. Checked for
+ * bracket balance, but not otherwise parsed.
+ */
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_text = {
+ "bracketed_text", parse_btext, print_btext, doc_btext,
+ &cfg_rep_string, NULL
+};
+
+/*
+ * Booleans
+ */
+
+bool
+cfg_obj_isboolean(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_boolean);
+}
+
+bool
+cfg_obj_asboolean(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
+ return (obj->value.boolean);
+}
+
+isc_result_t
+cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ bool value;
+ cfg_obj_t *obj = NULL;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ UNUSED(type);
+
+ result = cfg_gettoken(pctx, 0);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (pctx->token.type != isc_tokentype_string)
+ goto bad_boolean;
+
+ if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) ||
+ (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) ||
+ (strcmp(TOKEN_STRING(pctx), "1") == 0)) {
+ value = true;
+ } else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) ||
+ (strcasecmp(TOKEN_STRING(pctx), "no") == 0) ||
+ (strcmp(TOKEN_STRING(pctx), "0") == 0)) {
+ value = false;
+ } else {
+ goto bad_boolean;
+ }
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj));
+ obj->value.boolean = value;
+ *ret = obj;
+ return (result);
+
+ bad_boolean:
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected");
+ return (ISC_R_UNEXPECTEDTOKEN);
+
+ cleanup:
+ return (result);
+}
+
+void
+cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ if (obj->value.boolean)
+ cfg_print_cstr(pctx, "yes");
+ else
+ cfg_print_cstr(pctx, "no");
+}
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_boolean = {
+ "boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal,
+ &cfg_rep_boolean, NULL
+};
+
+/*
+ * Lists.
+ */
+
+isc_result_t
+cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) {
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(obj != NULL && *obj == NULL);
+
+ CHECK(cfg_create_obj(pctx, type, obj));
+ ISC_LIST_INIT((*obj)->value.list);
+ cleanup:
+ return (result);
+}
+
+static isc_result_t
+create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) {
+ cfg_listelt_t *elt;
+
+ elt = isc_mem_get(pctx->mctx, sizeof(*elt));
+ if (elt == NULL)
+ return (ISC_R_NOMEMORY);
+ elt->obj = NULL;
+ ISC_LINK_INIT(elt, link);
+ *eltp = elt;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+free_listelt(cfg_parser_t *pctx, cfg_listelt_t *elt) {
+ if (elt->obj != NULL)
+ cfg_obj_destroy(pctx, &elt->obj);
+ isc_mem_put(pctx->mctx, elt, sizeof(*elt));
+}
+
+static void
+free_list(cfg_parser_t *pctx, cfg_obj_t *obj) {
+ cfg_listelt_t *elt, *next;
+ for (elt = ISC_LIST_HEAD(obj->value.list);
+ elt != NULL;
+ elt = next)
+ {
+ next = ISC_LIST_NEXT(elt, link);
+ free_listelt(pctx, elt);
+ }
+}
+
+isc_result_t
+cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
+ cfg_listelt_t **ret)
+{
+ isc_result_t result;
+ cfg_listelt_t *elt = NULL;
+ cfg_obj_t *value = NULL;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(elttype != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ CHECK(create_listelt(pctx, &elt));
+
+ result = cfg_parse_obj(pctx, elttype, &value);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ elt->obj = value;
+
+ *ret = elt;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ isc_mem_put(pctx->mctx, elt, sizeof(*elt));
+ return (result);
+}
+
+/*
+ * Parse a homogeneous list whose elements are of type 'elttype'
+ * and where each element is terminated by a semicolon.
+ */
+static isc_result_t
+parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret)
+{
+ cfg_obj_t *listobj = NULL;
+ const cfg_type_t *listof = listtype->of;
+ isc_result_t result;
+ cfg_listelt_t *elt = NULL;
+
+ CHECK(cfg_create_list(pctx, listtype, &listobj));
+
+ for (;;) {
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == /*{*/ '}')
+ break;
+ CHECK(cfg_parse_listelt(pctx, listof, &elt));
+ CHECK(parse_semicolon(pctx));
+ ISC_LIST_APPEND(listobj->value.list, elt, link);
+ elt = NULL;
+ }
+ *ret = listobj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (elt != NULL)
+ free_listelt(pctx, elt);
+ CLEANUP_OBJ(listobj);
+ return (result);
+}
+
+static void
+print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ const cfg_list_t *list = &obj->value.list;
+ const cfg_listelt_t *elt;
+
+ for (elt = ISC_LIST_HEAD(*list);
+ elt != NULL;
+ elt = ISC_LIST_NEXT(elt, link))
+ {
+ if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) {
+ cfg_print_obj(pctx, elt->obj);
+ cfg_print_cstr(pctx, "; ");
+ } else {
+ cfg_print_indent(pctx);
+ cfg_print_obj(pctx, elt->obj);
+ cfg_print_cstr(pctx, ";\n");
+ }
+ }
+}
+
+isc_result_t
+cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ CHECK(cfg_parse_special(pctx, '{'));
+ CHECK(parse_list(pctx, type, ret));
+ CHECK(cfg_parse_special(pctx, '}'));
+ cleanup:
+ return (result);
+}
+
+void
+cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ print_open(pctx);
+ print_list(pctx, obj);
+ print_close(pctx);
+}
+
+void
+cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+
+ cfg_print_cstr(pctx, "{ ");
+ cfg_doc_obj(pctx, type->of);
+ cfg_print_cstr(pctx, "; ... }");
+}
+
+/*
+ * Parse a homogeneous list whose elements are of type 'elttype'
+ * and where elements are separated by space. The list ends
+ * before the first semicolon.
+ */
+isc_result_t
+cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype,
+ cfg_obj_t **ret)
+{
+ cfg_obj_t *listobj = NULL;
+ const cfg_type_t *listof = listtype->of;
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(listtype != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ CHECK(cfg_create_list(pctx, listtype, &listobj));
+
+ for (;;) {
+ cfg_listelt_t *elt = NULL;
+
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == ';')
+ break;
+ CHECK(cfg_parse_listelt(pctx, listof, &elt));
+ ISC_LIST_APPEND(listobj->value.list, elt, link);
+ }
+ *ret = listobj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(listobj);
+ return (result);
+}
+
+void
+cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ const cfg_list_t *list = &obj->value.list;
+ const cfg_listelt_t *elt;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ for (elt = ISC_LIST_HEAD(*list);
+ elt != NULL;
+ elt = ISC_LIST_NEXT(elt, link)) {
+ cfg_print_obj(pctx, elt->obj);
+ if (ISC_LIST_NEXT(elt, link) != NULL)
+ cfg_print_cstr(pctx, " ");
+ }
+}
+
+bool
+cfg_obj_islist(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_list);
+}
+
+const cfg_listelt_t *
+cfg_list_first(const cfg_obj_t *obj) {
+ REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list);
+ if (obj == NULL)
+ return (NULL);
+ return (ISC_LIST_HEAD(obj->value.list));
+}
+
+const cfg_listelt_t *
+cfg_list_next(const cfg_listelt_t *elt) {
+ REQUIRE(elt != NULL);
+ return (ISC_LIST_NEXT(elt, link));
+}
+
+/*
+ * Return the length of a list object. If obj is NULL or is not
+ * a list, return 0.
+ */
+unsigned int
+cfg_list_length(const cfg_obj_t *obj, bool recurse) {
+ const cfg_listelt_t *elt;
+ unsigned int count = 0;
+
+ if (obj == NULL || !cfg_obj_islist(obj))
+ return (0U);
+ for (elt = cfg_list_first(obj);
+ elt != NULL;
+ elt = cfg_list_next(elt)) {
+ if (recurse && cfg_obj_islist(elt->obj)) {
+ count += cfg_list_length(elt->obj, recurse);
+ } else {
+ count++;
+ }
+ }
+ return (count);
+}
+
+cfg_obj_t *
+cfg_listelt_value(const cfg_listelt_t *elt) {
+ REQUIRE(elt != NULL);
+ return (elt->obj);
+}
+
+/*
+ * Maps.
+ */
+
+/*
+ * Parse a map body. That's something like
+ *
+ * "foo 1; bar { glub; }; zap true; zap false;"
+ *
+ * i.e., a sequence of option names followed by values and
+ * terminated by semicolons. Used for the top level of
+ * the named.conf syntax, as well as for the body of the
+ * options, view, zone, and other statements.
+ */
+isc_result_t
+cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+{
+ const cfg_clausedef_t * const *clausesets = type->of;
+ isc_result_t result;
+ const cfg_clausedef_t * const *clauseset;
+ const cfg_clausedef_t *clause;
+ cfg_obj_t *value = NULL;
+ cfg_obj_t *obj = NULL;
+ cfg_obj_t *eltobj = NULL;
+ cfg_obj_t *includename = NULL;
+ isc_symvalue_t symval;
+ cfg_list_t *list = NULL;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ CHECK(create_map(pctx, type, &obj));
+
+ obj->value.map.clausesets = clausesets;
+
+ for (;;) {
+ cfg_listelt_t *elt;
+
+ redo:
+ /*
+ * Parse the option name and see if it is known.
+ */
+ CHECK(cfg_gettoken(pctx, 0));
+
+ if (pctx->token.type != isc_tokentype_string) {
+ cfg_ungettoken(pctx);
+ break;
+ }
+
+ /*
+ * We accept "include" statements wherever a map body
+ * clause can occur.
+ */
+ if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) {
+ /*
+ * Turn the file name into a temporary configuration
+ * object just so that it is not overwritten by the
+ * semicolon token.
+ */
+ CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename));
+ CHECK(parse_semicolon(pctx));
+ CHECK(parser_openfile(pctx, includename->
+ value.string.base));
+ cfg_obj_destroy(pctx, &includename);
+ goto redo;
+ }
+
+ clause = NULL;
+ for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
+ for (clause = *clauseset;
+ clause->name != NULL;
+ clause++) {
+ if (strcasecmp(TOKEN_STRING(pctx),
+ clause->name) == 0)
+ goto done;
+ }
+ }
+ done:
+ if (clause == NULL || clause->name == NULL) {
+ cfg_parser_error(pctx, CFG_LOG_NOPREP,
+ "unknown option");
+ /*
+ * Try to recover by parsing this option as an unknown
+ * option and discarding it.
+ */
+ CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported,
+ &eltobj));
+ cfg_obj_destroy(pctx, &eltobj);
+ CHECK(parse_semicolon(pctx));
+ continue;
+ }
+
+ /* Clause is known. */
+
+ /* Issue warnings if appropriate */
+ if ((pctx->flags & CFG_PCTX_NODEPRECATED) == 0 &&
+ (clause->flags & CFG_CLAUSEFLAG_DEPRECATED) != 0)
+ {
+ cfg_parser_warning(pctx, 0, "option '%s' is deprecated",
+ clause->name);
+ }
+ if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) {
+ cfg_parser_warning(pctx, 0, "option '%s' is obsolete",
+ clause->name);
+ }
+ if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0) {
+ cfg_parser_warning(pctx, 0, "option '%s' is "
+ "not implemented", clause->name);
+ }
+ if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) {
+ cfg_parser_warning(pctx, 0, "option '%s' is "
+ "not implemented", clause->name);
+ }
+ if ((clause->flags & CFG_CLAUSEFLAG_NOOP) != 0) {
+ cfg_parser_warning(pctx, 0, "option '%s' was not "
+ "enabled at compile time "
+ "(ignored)", clause->name);
+ }
+
+ if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) {
+ cfg_parser_warning(pctx, 0, "option '%s' was not "
+ "enabled at compile time",
+ clause->name);
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ /*
+ * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
+ * set here - we need to log the *lack* of such an option,
+ * not its presence.
+ */
+
+ /* See if the clause already has a value; if not create one. */
+ result = isc_symtab_lookup(obj->value.map.symtab,
+ clause->name, 0, &symval);
+
+ if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
+ /* Multivalued clause */
+ cfg_obj_t *listobj = NULL;
+ if (result == ISC_R_NOTFOUND) {
+ CHECK(cfg_create_list(pctx,
+ &cfg_type_implicitlist,
+ &listobj));
+ symval.as_pointer = listobj;
+ result = isc_symtab_define(obj->value.
+ map.symtab,
+ clause->name,
+ 1, symval,
+ isc_symexists_reject);
+ if (result != ISC_R_SUCCESS) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "isc_symtab_define(%s) "
+ "failed", clause->name);
+ isc_mem_put(pctx->mctx, list,
+ sizeof(cfg_list_t));
+ goto cleanup;
+ }
+ } else {
+ INSIST(result == ISC_R_SUCCESS);
+ listobj = symval.as_pointer;
+ }
+
+ elt = NULL;
+ CHECK(cfg_parse_listelt(pctx, clause->type, &elt));
+ CHECK(parse_semicolon(pctx));
+
+ ISC_LIST_APPEND(listobj->value.list, elt, link);
+ } else {
+ /* Single-valued clause */
+ if (result == ISC_R_NOTFOUND) {
+ bool callback =
+ (clause->flags & CFG_CLAUSEFLAG_CALLBACK);
+ CHECK(parse_symtab_elt(pctx, clause->name,
+ clause->type,
+ obj->value.map.symtab,
+ callback));
+ CHECK(parse_semicolon(pctx));
+ } else if (result == ISC_R_SUCCESS) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined",
+ clause->name);
+ result = ISC_R_EXISTS;
+ goto cleanup;
+ } else {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "isc_symtab_define() failed");
+ goto cleanup;
+ }
+ }
+ }
+
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(value);
+ CLEANUP_OBJ(obj);
+ CLEANUP_OBJ(eltobj);
+ CLEANUP_OBJ(includename);
+ return (result);
+}
+
+static isc_result_t
+parse_symtab_elt(cfg_parser_t *pctx, const char *name,
+ cfg_type_t *elttype, isc_symtab_t *symtab,
+ bool callback)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ isc_symvalue_t symval;
+
+ CHECK(cfg_parse_obj(pctx, elttype, &obj));
+
+ if (callback && pctx->callback != NULL)
+ CHECK(pctx->callback(name, obj, pctx->callbackarg));
+
+ symval.as_pointer = obj;
+ CHECK(isc_symtab_define(symtab, name,
+ 1, symval,
+ isc_symexists_reject));
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+/*
+ * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
+ */
+isc_result_t
+cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ CHECK(cfg_parse_special(pctx, '{'));
+ CHECK(cfg_parse_mapbody(pctx, type, ret));
+ CHECK(cfg_parse_special(pctx, '}'));
+ cleanup:
+ return (result);
+}
+
+/*
+ * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map().
+ */
+static isc_result_t
+parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype,
+ const cfg_type_t *type, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *idobj = NULL;
+ cfg_obj_t *mapobj = NULL;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(nametype != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ CHECK(cfg_parse_obj(pctx, nametype, &idobj));
+ CHECK(cfg_parse_map(pctx, type, &mapobj));
+ mapobj->value.map.id = idobj;
+ *ret = mapobj;
+ return (result);
+ cleanup:
+ CLEANUP_OBJ(idobj);
+ CLEANUP_OBJ(mapobj);
+ return (result);
+}
+
+/*
+ * Parse a map identified by a string name. E.g., "name { foo 1; }".
+ * Used for the "key" and "channel" statements.
+ */
+isc_result_t
+cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_any_named_map(pctx, &cfg_type_astring, type, ret));
+}
+
+/*
+ * Parse a map identified by a network address.
+ * Used to be used for the "server" statement.
+ */
+isc_result_t
+cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret));
+}
+
+/*
+ * Parse a map identified by a network prefix.
+ * Used for the "server" statement.
+ */
+isc_result_t
+cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret));
+}
+
+static void
+print_symval(cfg_printer_t *pctx, const char *name, cfg_obj_t *obj) {
+ if ((pctx->flags & CFG_PRINTER_ONELINE) == 0)
+ cfg_print_indent(pctx);
+
+ cfg_print_cstr(pctx, name);
+ cfg_print_cstr(pctx, " ");
+ cfg_print_obj(pctx, obj);
+
+ if ((pctx->flags & CFG_PRINTER_ONELINE) == 0)
+ cfg_print_cstr(pctx, ";\n");
+ else
+ cfg_print_cstr(pctx, "; ");
+}
+
+void
+cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ isc_result_t result = ISC_R_SUCCESS;
+ const cfg_clausedef_t * const *clauseset;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ for (clauseset = obj->value.map.clausesets;
+ *clauseset != NULL;
+ clauseset++)
+ {
+ isc_symvalue_t symval;
+ const cfg_clausedef_t *clause;
+
+ for (clause = *clauseset;
+ clause->name != NULL;
+ clause++) {
+ result = isc_symtab_lookup(obj->value.map.symtab,
+ clause->name, 0, &symval);
+ if (result == ISC_R_SUCCESS) {
+ cfg_obj_t *symobj = symval.as_pointer;
+ if (symobj->type == &cfg_type_implicitlist) {
+ /* Multivalued. */
+ cfg_list_t *list = &symobj->value.list;
+ cfg_listelt_t *elt;
+ for (elt = ISC_LIST_HEAD(*list);
+ elt != NULL;
+ elt = ISC_LIST_NEXT(elt, link)) {
+ print_symval(pctx,
+ clause->name,
+ elt->obj);
+ }
+ } else {
+ /* Single-valued. */
+ print_symval(pctx, clause->name,
+ symobj);
+ }
+ } else if (result == ISC_R_NOTFOUND) {
+ ; /* do nothing */
+ } else {
+ INSIST(0);
+ }
+ }
+ }
+}
+
+static struct flagtext {
+ unsigned int flag;
+ const char *text;
+} flagtexts[] = {
+ { CFG_CLAUSEFLAG_NOTIMP, "not implemented" },
+ { CFG_CLAUSEFLAG_NYI, "not yet implemented" },
+ { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
+ { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" },
+ { CFG_CLAUSEFLAG_TESTONLY, "test only" },
+ { CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" },
+ { CFG_CLAUSEFLAG_MULTI, "may occur multiple times" },
+ { CFG_CLAUSEFLAG_EXPERIMENTAL, "experimental" },
+ { CFG_CLAUSEFLAG_NOOP, "non-operational" },
+ { 0, NULL }
+};
+
+void
+cfg_print_clauseflags(cfg_printer_t *pctx, unsigned int flags) {
+ struct flagtext *p;
+ bool first = true;
+ for (p = flagtexts; p->flag != 0; p++) {
+ if ((flags & p->flag) != 0) {
+ if (first)
+ cfg_print_cstr(pctx, " // ");
+ else
+ cfg_print_cstr(pctx, ", ");
+ cfg_print_cstr(pctx, p->text);
+ first = false;
+ }
+ }
+}
+
+void
+cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const cfg_clausedef_t * const *clauseset;
+ const cfg_clausedef_t *clause;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+
+ for (clauseset = type->of; *clauseset != NULL; clauseset++) {
+ for (clause = *clauseset; clause->name != NULL; clause++) {
+ cfg_print_cstr(pctx, clause->name);
+ cfg_print_cstr(pctx, " ");
+ cfg_doc_obj(pctx, clause->type);
+ cfg_print_cstr(pctx, ";");
+ cfg_print_clauseflags(pctx, clause->flags);
+ cfg_print_cstr(pctx, "\n\n");
+ }
+ }
+}
+
+void
+cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ if (obj->value.map.id != NULL) {
+ cfg_print_obj(pctx, obj->value.map.id);
+ cfg_print_cstr(pctx, " ");
+ }
+ print_open(pctx);
+ cfg_print_mapbody(pctx, obj);
+ print_close(pctx);
+}
+
+void
+cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const cfg_clausedef_t * const *clauseset;
+ const cfg_clausedef_t *clause;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+
+ if (type->parse == cfg_parse_named_map) {
+ cfg_doc_obj(pctx, &cfg_type_astring);
+ cfg_print_cstr(pctx, " ");
+ } else if (type->parse == cfg_parse_addressed_map) {
+ cfg_doc_obj(pctx, &cfg_type_netaddr);
+ cfg_print_cstr(pctx, " ");
+ } else if (type->parse == cfg_parse_netprefix_map) {
+ cfg_doc_obj(pctx, &cfg_type_netprefix);
+ cfg_print_cstr(pctx, " ");
+ }
+
+ print_open(pctx);
+
+ for (clauseset = type->of; *clauseset != NULL; clauseset++) {
+ for (clause = *clauseset; clause->name != NULL; clause++) {
+ cfg_print_indent(pctx);
+ cfg_print_cstr(pctx, clause->name);
+ if (clause->type->print != cfg_print_void)
+ cfg_print_cstr(pctx, " ");
+ cfg_doc_obj(pctx, clause->type);
+ cfg_print_cstr(pctx, ";");
+ cfg_print_clauseflags(pctx, clause->flags);
+ cfg_print_cstr(pctx, "\n");
+ }
+ }
+ print_close(pctx);
+}
+
+bool
+cfg_obj_ismap(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_map);
+}
+
+isc_result_t
+cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) {
+ isc_result_t result;
+ isc_symvalue_t val;
+ const cfg_map_t *map;
+
+ REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
+ REQUIRE(name != NULL);
+ REQUIRE(obj != NULL && *obj == NULL);
+
+ map = &mapobj->value.map;
+
+ result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ *obj = val.as_pointer;
+ return (ISC_R_SUCCESS);
+}
+
+const cfg_obj_t *
+cfg_map_getname(const cfg_obj_t *mapobj) {
+ REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
+ return (mapobj->value.map.id);
+}
+
+unsigned int
+cfg_map_count(const cfg_obj_t *mapobj) {
+ const cfg_map_t *map;
+
+ REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
+
+ map = &mapobj->value.map;
+ return (isc_symtab_count(map->symtab));
+}
+
+const char *
+cfg_map_firstclause(const cfg_type_t *map, const void **clauses,
+ unsigned int *idx)
+{
+ cfg_clausedef_t * const * clauseset;
+
+ REQUIRE(map != NULL && map->rep == &cfg_rep_map);
+ REQUIRE(idx != NULL);
+ REQUIRE(clauses != NULL && *clauses == NULL);
+
+ clauseset = map->of;
+ if (*clauseset == NULL) {
+ return (NULL);
+ }
+ *clauses = *clauseset;
+ *idx = 0;
+ while ((*clauseset)[*idx].name == NULL) {
+ *clauses = (*++clauseset);
+ if (*clauses == NULL)
+ return (NULL);
+ }
+ return ((*clauseset)[*idx].name);
+}
+
+const char *
+cfg_map_nextclause(const cfg_type_t *map, const void **clauses,
+ unsigned int *idx)
+{
+ cfg_clausedef_t * const * clauseset;
+
+ REQUIRE(map != NULL && map->rep == &cfg_rep_map);
+ REQUIRE(idx != NULL);
+ REQUIRE(clauses != NULL && *clauses != NULL);
+
+ clauseset = map->of;
+ while (*clauseset != NULL && *clauseset != *clauses) {
+ clauseset++;
+ }
+ INSIST(*clauseset == *clauses);
+ (*idx)++;
+ while ((*clauseset)[*idx].name == NULL) {
+ *idx = 0;
+ *clauses = (*++clauseset);
+ if (*clauses == NULL)
+ return (NULL);
+ }
+ return ((*clauseset)[*idx].name);
+}
+
+/* Parse an arbitrary token, storing its raw text representation. */
+static isc_result_t
+parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ cfg_obj_t *obj = NULL;
+ isc_result_t result;
+ isc_region_t r;
+
+ UNUSED(type);
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj));
+ CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_eof) {
+ cfg_ungettoken(pctx);
+ result = ISC_R_EOF;
+ goto cleanup;
+ }
+
+ isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r);
+
+ obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1);
+ if (obj->value.string.base == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ obj->value.string.length = r.length;
+ memmove(obj->value.string.base, r.base, r.length);
+ obj->value.string.base[r.length] = '\0';
+ *ret = obj;
+ return (result);
+
+ cleanup:
+ if (obj != NULL)
+ isc_mem_put(pctx->mctx, obj, sizeof(*obj));
+ return (result);
+}
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_token = {
+ "token", parse_token, cfg_print_ustring, cfg_doc_terminal,
+ &cfg_rep_string, NULL
+};
+
+/*
+ * An unsupported option. This is just a list of tokens with balanced braces
+ * ending in a semicolon.
+ */
+
+static isc_result_t
+parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ cfg_obj_t *listobj = NULL;
+ isc_result_t result;
+ int braces = 0;
+
+ CHECK(cfg_create_list(pctx, type, &listobj));
+
+ for (;;) {
+ cfg_listelt_t *elt = NULL;
+
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special) {
+ if (pctx->token.value.as_char == '{')
+ braces++;
+ else if (pctx->token.value.as_char == '}')
+ braces--;
+ else if (pctx->token.value.as_char == ';')
+ if (braces == 0)
+ break;
+ }
+ if (pctx->token.type == isc_tokentype_eof || braces < 0) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token");
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+
+ CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt));
+ ISC_LIST_APPEND(listobj->value.list, elt, link);
+ }
+ INSIST(braces == 0);
+ *ret = listobj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(listobj);
+ return (result);
+}
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_unsupported = {
+ "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal,
+ &cfg_rep_list, NULL
+};
+
+/*
+ * Try interpreting the current token as a network address.
+ *
+ * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard
+ * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The
+ * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is
+ * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set),
+ * and the IPv6 wildcard address otherwise.
+ */
+static isc_result_t
+token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
+ char *s;
+ struct in_addr in4a;
+ struct in6_addr in6a;
+
+ if (pctx->token.type != isc_tokentype_string)
+ return (ISC_R_UNEXPECTEDTOKEN);
+
+ s = TOKEN_STRING(pctx);
+ if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) {
+ if ((flags & CFG_ADDR_V4OK) != 0) {
+ isc_netaddr_any(na);
+ return (ISC_R_SUCCESS);
+ } else if ((flags & CFG_ADDR_V6OK) != 0) {
+ isc_netaddr_any6(na);
+ return (ISC_R_SUCCESS);
+ } else {
+ INSIST(0);
+ }
+ } else {
+ if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) {
+ if (inet_pton(AF_INET, s, &in4a) == 1) {
+ isc_netaddr_fromin(na, &in4a);
+ return (ISC_R_SUCCESS);
+ }
+ }
+ if ((flags & CFG_ADDR_V4PREFIXOK) != 0 && strlen(s) <= 15U) {
+ char buf[64];
+ int i;
+
+ strlcpy(buf, s, sizeof(buf));
+ for (i = 0; i < 3; i++) {
+ strlcat(buf, ".0", sizeof(buf));
+ if (inet_pton(AF_INET, buf, &in4a) == 1) {
+ isc_netaddr_fromin(na, &in4a);
+ return (ISC_R_SUCCESS);
+ }
+ }
+ }
+ if ((flags & CFG_ADDR_V6OK) != 0 && strlen(s) <= 127U) {
+ char buf[128]; /* see lib/bind9/getaddresses.c */
+ char *d; /* zone delimiter */
+ uint32_t zone = 0; /* scope zone ID */
+
+ strlcpy(buf, s, sizeof(buf));
+ d = strchr(buf, '%');
+ if (d != NULL)
+ *d = '\0';
+
+ if (inet_pton(AF_INET6, buf, &in6a) == 1) {
+ if (d != NULL) {
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ isc_result_t result;
+
+ result = isc_netscope_pton(AF_INET6,
+ d + 1,
+ &in6a,
+ &zone);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#else
+ return (ISC_R_BADADDRESSFORM);
+#endif
+ }
+
+ isc_netaddr_fromin6(na, &in6a);
+ isc_netaddr_setzone(na, zone);
+ return (ISC_R_SUCCESS);
+ }
+ }
+ }
+ return (ISC_R_UNEXPECTEDTOKEN);
+}
+
+isc_result_t
+cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
+ isc_result_t result;
+ const char *wild = "";
+ const char *prefix = "";
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(na != NULL);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ result = token_addr(pctx, flags, na);
+ if (result == ISC_R_UNEXPECTEDTOKEN) {
+ if ((flags & CFG_ADDR_WILDOK) != 0)
+ wild = " or '*'";
+ if ((flags & CFG_ADDR_V4PREFIXOK) != 0)
+ wild = " or IPv4 prefix";
+ if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK)
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IPv4 address%s%s",
+ prefix, wild);
+ else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK)
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IPv6 address%s%s",
+ prefix, wild);
+ else
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IP address%s%s",
+ prefix, wild);
+ }
+ cleanup:
+ return (result);
+}
+
+bool
+cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) {
+ isc_result_t result;
+ isc_netaddr_t na_dummy;
+
+ REQUIRE(pctx != NULL);
+
+ result = token_addr(pctx, flags, &na_dummy);
+ return (result == ISC_R_SUCCESS);
+}
+
+isc_result_t
+cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) {
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(port != NULL);
+
+ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
+
+ if ((flags & CFG_ADDR_WILDOK) != 0 &&
+ pctx->token.type == isc_tokentype_string &&
+ strcmp(TOKEN_STRING(pctx), "*") == 0) {
+ *port = 0;
+ return (ISC_R_SUCCESS);
+ }
+ if (pctx->token.type != isc_tokentype_number) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected port number or '*'");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ if (pctx->token.value.as_ulong >= 65536U) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "port number out of range");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ *port = (in_port_t)(pctx->token.value.as_ulong);
+ return (ISC_R_SUCCESS);
+ cleanup:
+ return (result);
+}
+
+void
+cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) {
+ isc_result_t result;
+ char text[128];
+ isc_buffer_t buf;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(na != NULL);
+
+ isc_buffer_init(&buf, text, sizeof(text));
+ result = isc_netaddr_totext(na, &buf);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ cfg_print_chars(pctx, isc_buffer_base(&buf),
+ isc_buffer_usedlength(&buf));
+}
+
+isc_result_t
+cfg_parse_dscp(cfg_parser_t *pctx, isc_dscp_t *dscp) {
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(dscp != NULL);
+
+ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
+
+ if (pctx->token.type != isc_tokentype_number) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected number");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ if (pctx->token.value.as_ulong > 63U) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "dscp out of range");
+ return (ISC_R_RANGE);
+ }
+ *dscp = (isc_dscp_t)(pctx->token.value.as_ulong);
+ return (ISC_R_SUCCESS);
+ cleanup:
+ return (result);
+}
+
+/* netaddr */
+
+static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
+static unsigned int netaddr4_flags = CFG_ADDR_V4OK;
+static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK;
+static unsigned int netaddr6_flags = CFG_ADDR_V6OK;
+static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
+
+static isc_result_t
+parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ isc_netaddr_t netaddr;
+ unsigned int flags = *(const unsigned int *)type->of;
+
+ CHECK(cfg_create_obj(pctx, type, &obj));
+ CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
+ isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0);
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static void
+cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const unsigned int *flagp = type->of;
+ int n = 0;
+ if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
+ cfg_print_cstr(pctx, "( ");
+ if (*flagp & CFG_ADDR_V4OK) {
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ n++;
+ }
+ if (*flagp & CFG_ADDR_V6OK) {
+ if (n != 0)
+ cfg_print_cstr(pctx, " | ");
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ n++;
+ }
+ if (*flagp & CFG_ADDR_WILDOK) {
+ if (n != 0)
+ cfg_print_cstr(pctx, " | ");
+ cfg_print_cstr(pctx, "*");
+ n++;
+ POST(n);
+ }
+ if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
+ cfg_print_cstr(pctx, " )");
+}
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr = {
+ "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
+ &cfg_rep_sockaddr, &netaddr_flags
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr4 = {
+ "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
+ &cfg_rep_sockaddr, &netaddr4_flags
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr4wild = {
+ "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
+ &cfg_rep_sockaddr, &netaddr4wild_flags
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr6 = {
+ "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
+ &cfg_rep_sockaddr, &netaddr6_flags
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr6wild = {
+ "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
+ &cfg_rep_sockaddr, &netaddr6wild_flags
+};
+
+/* netprefix */
+
+isc_result_t
+cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ cfg_obj_t *obj = NULL;
+ isc_result_t result;
+ isc_netaddr_t netaddr;
+ unsigned int addrlen = 0, prefixlen;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ UNUSED(type);
+
+ CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK |
+ CFG_ADDR_V6OK, &netaddr));
+ switch (netaddr.family) {
+ case AF_INET:
+ addrlen = 32;
+ break;
+ case AF_INET6:
+ addrlen = 128;
+ break;
+ default:
+ INSIST(0);
+ break;
+ }
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == '/') {
+ CHECK(cfg_gettoken(pctx, 0)); /* read "/" */
+ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
+ if (pctx->token.type != isc_tokentype_number) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected prefix length");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ prefixlen = pctx->token.value.as_ulong;
+ if (prefixlen > addrlen) {
+ cfg_parser_error(pctx, CFG_LOG_NOPREP,
+ "invalid prefix length");
+ return (ISC_R_RANGE);
+ }
+ } else {
+ prefixlen = addrlen;
+ }
+ CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj));
+ obj->value.netprefix.address = netaddr;
+ obj->value.netprefix.prefixlen = prefixlen;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+ cleanup:
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix");
+ return (result);
+}
+
+static void
+print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ const cfg_netprefix_t *p = &obj->value.netprefix;
+
+ cfg_print_rawaddr(pctx, &p->address);
+ cfg_print_cstr(pctx, "/");
+ cfg_print_rawuint(pctx, p->prefixlen);
+}
+
+bool
+cfg_obj_isnetprefix(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_netprefix);
+}
+
+void
+cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
+ unsigned int *prefixlen)
+{
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix);
+ REQUIRE(netaddr != NULL);
+ REQUIRE(prefixlen != NULL);
+
+ *netaddr = obj->value.netprefix.address;
+ *prefixlen = obj->value.netprefix.prefixlen;
+}
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netprefix = {
+ "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal,
+ &cfg_rep_netprefix, NULL
+};
+
+static isc_result_t
+parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type,
+ int flags, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ isc_netaddr_t netaddr;
+ in_port_t port = 0;
+ isc_dscp_t dscp = -1;
+ cfg_obj_t *obj = NULL;
+ int have_port = 0, have_dscp = 0;
+
+ CHECK(cfg_create_obj(pctx, type, &obj));
+ CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
+ for (;;) {
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string) {
+ if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) {
+ CHECK(cfg_gettoken(pctx, 0)); /* read "port" */
+ CHECK(cfg_parse_rawport(pctx, flags, &port));
+ ++have_port;
+ } else if ((flags & CFG_ADDR_DSCPOK) != 0 &&
+ strcasecmp(TOKEN_STRING(pctx), "dscp") == 0)
+ {
+ CHECK(cfg_gettoken(pctx, 0)); /* read "dscp" */
+ CHECK(cfg_parse_dscp(pctx, &dscp));
+ ++have_dscp;
+ } else
+ break;
+ } else
+ break;
+ }
+ if (have_port > 1) {
+ cfg_parser_error(pctx, 0, "expected at most one port");
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+
+ if (have_dscp > 1) {
+ cfg_parser_error(pctx, 0, "expected at most one dscp");
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+ isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
+ obj->value.sockaddrdscp.dscp = dscp;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sockaddr = {
+ "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
+ &cfg_rep_sockaddr, &sockaddr_flags
+};
+
+static unsigned int sockaddrdscp_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK |
+ CFG_ADDR_DSCPOK;
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sockaddrdscp = {
+ "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
+ &cfg_rep_sockaddr, &sockaddrdscp_flags
+};
+
+isc_result_t
+cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ const unsigned int *flagp;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ flagp = type->of;
+
+ return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret));
+}
+
+void
+cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ isc_netaddr_t netaddr;
+ in_port_t port;
+ char buf[ISC_NETADDR_FORMATSIZE];
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(obj != NULL);
+
+ isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr);
+ isc_netaddr_format(&netaddr, buf, sizeof(buf));
+ cfg_print_cstr(pctx, buf);
+ port = isc_sockaddr_getport(&obj->value.sockaddr);
+ if (port != 0) {
+ cfg_print_cstr(pctx, " port ");
+ cfg_print_rawuint(pctx, port);
+ }
+ if (obj->value.sockaddrdscp.dscp != -1) {
+ cfg_print_cstr(pctx, " dscp ");
+ cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp);
+ }
+}
+
+void
+cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const unsigned int *flagp = type->of;
+ int n = 0;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+
+ cfg_print_cstr(pctx, "( ");
+ if (*flagp & CFG_ADDR_V4OK) {
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ n++;
+ }
+ if (*flagp & CFG_ADDR_V6OK) {
+ if (n != 0)
+ cfg_print_cstr(pctx, " | ");
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ n++;
+ }
+ if (*flagp & CFG_ADDR_WILDOK) {
+ if (n != 0)
+ cfg_print_cstr(pctx, " | ");
+ cfg_print_cstr(pctx, "*");
+ n++;
+ POST(n);
+ }
+ cfg_print_cstr(pctx, " ) ");
+ if (*flagp & CFG_ADDR_WILDOK) {
+ cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]");
+ } else {
+ cfg_print_cstr(pctx, "[ port <integer> ]");
+ }
+ if ((*flagp & CFG_ADDR_DSCPOK) != 0) {
+ cfg_print_cstr(pctx, " [ dscp <integer> ]");
+ }
+}
+
+bool
+cfg_obj_issockaddr(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (obj->type->rep == &cfg_rep_sockaddr);
+}
+
+const isc_sockaddr_t *
+cfg_obj_assockaddr(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
+ return (&obj->value.sockaddr);
+}
+
+isc_dscp_t
+cfg_obj_getdscp(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
+ return (obj->value.sockaddrdscp.dscp);
+}
+
+isc_result_t
+cfg_gettoken(cfg_parser_t *pctx, int options) {
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+
+ if (pctx->seen_eof)
+ return (ISC_R_SUCCESS);
+
+ options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE);
+
+ redo:
+ pctx->token.type = isc_tokentype_unknown;
+ result = isc_lex_gettoken(pctx->lexer, options, &pctx->token);
+ pctx->ungotten = false;
+ pctx->line = isc_lex_getsourceline(pctx->lexer);
+
+ switch (result) {
+ case ISC_R_SUCCESS:
+ if (pctx->token.type == isc_tokentype_eof) {
+ result = isc_lex_close(pctx->lexer);
+ INSIST(result == ISC_R_NOMORE ||
+ result == ISC_R_SUCCESS);
+
+ if (isc_lex_getsourcename(pctx->lexer) != NULL) {
+ /*
+ * Closed an included file, not the main file.
+ */
+ cfg_listelt_t *elt;
+ elt = ISC_LIST_TAIL(pctx->open_files->
+ value.list);
+ INSIST(elt != NULL);
+ ISC_LIST_UNLINK(pctx->open_files->
+ value.list, elt, link);
+ ISC_LIST_APPEND(pctx->closed_files->
+ value.list, elt, link);
+ goto redo;
+ }
+ pctx->seen_eof = true;
+ }
+ break;
+
+ case ISC_R_NOSPACE:
+ /* More understandable than "ran out of space". */
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big");
+ break;
+
+ case ISC_R_IOERROR:
+ cfg_parser_error(pctx, 0, "%s",
+ isc_result_totext(result));
+ break;
+
+ default:
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "%s",
+ isc_result_totext(result));
+ break;
+ }
+ return (result);
+}
+
+void
+cfg_ungettoken(cfg_parser_t *pctx) {
+ REQUIRE(pctx != NULL);
+
+ if (pctx->seen_eof)
+ return;
+ isc_lex_ungettoken(pctx->lexer, &pctx->token);
+ pctx->ungotten = true;
+}
+
+isc_result_t
+cfg_peektoken(cfg_parser_t *pctx, int options) {
+ isc_result_t result;
+
+ REQUIRE(pctx != NULL);
+
+ CHECK(cfg_gettoken(pctx, options));
+ cfg_ungettoken(pctx);
+ cleanup:
+ return (result);
+}
+
+/*
+ * Get a string token, accepting both the quoted and the unquoted form.
+ * Log an error if the next token is not a string.
+ */
+static isc_result_t
+cfg_getstringtoken(cfg_parser_t *pctx) {
+ isc_result_t result;
+
+ result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (pctx->token.type != isc_tokentype_string &&
+ pctx->token.type != isc_tokentype_qstring) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+void
+cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
+ va_list args;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(fmt != NULL);
+
+ va_start(args, fmt);
+ parser_complain(pctx, false, flags, fmt, args);
+ va_end(args);
+ pctx->errors++;
+}
+
+void
+cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
+ va_list args;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(fmt != NULL);
+
+ va_start(args, fmt);
+ parser_complain(pctx, true, flags, fmt, args);
+ va_end(args);
+ pctx->warnings++;
+}
+
+#define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */
+
+static bool
+have_current_file(cfg_parser_t *pctx) {
+ cfg_listelt_t *elt;
+ if (pctx->open_files == NULL)
+ return (false);
+
+ elt = ISC_LIST_TAIL(pctx->open_files->value.list);
+ if (elt == NULL)
+ return (false);
+
+ return (true);
+}
+
+static char *
+current_file(cfg_parser_t *pctx) {
+ static char none[] = "none";
+ cfg_listelt_t *elt;
+ cfg_obj_t *fileobj;
+
+ if (!have_current_file(pctx))
+ return (none);
+
+ elt = ISC_LIST_TAIL(pctx->open_files->value.list);
+ if (elt == NULL) /* shouldn't be possible, but... */
+ return (none);
+
+ fileobj = elt->obj;
+ INSIST(fileobj->type == &cfg_type_qstring);
+ return (fileobj->value.string.base);
+}
+
+static void
+parser_complain(cfg_parser_t *pctx, bool is_warning,
+ unsigned int flags, const char *format,
+ va_list args)
+{
+ char tokenbuf[MAX_LOG_TOKEN + 10];
+ static char where[ISC_DIR_PATHMAX + 100];
+ static char message[2048];
+ int level = ISC_LOG_ERROR;
+ const char *prep = "";
+ size_t len;
+
+ if (is_warning)
+ level = ISC_LOG_WARNING;
+
+ where[0] = '\0';
+ if (have_current_file(pctx))
+ snprintf(where, sizeof(where), "%s:%u: ",
+ current_file(pctx), pctx->line);
+ else if (pctx->buf_name != NULL)
+ snprintf(where, sizeof(where), "%s: ", pctx->buf_name);
+
+ len = vsnprintf(message, sizeof(message), format, args);
+#define ELIPSIS " ... "
+ if (len >= sizeof(message)) {
+ message[sizeof(message) - sizeof(ELIPSIS)] = 0;
+ strlcat(message, ELIPSIS, sizeof(message));
+ }
+
+ if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) {
+ isc_region_t r;
+
+ if (pctx->ungotten)
+ (void)cfg_gettoken(pctx, 0);
+
+ if (pctx->token.type == isc_tokentype_eof) {
+ snprintf(tokenbuf, sizeof(tokenbuf), "end of file");
+ } else if (pctx->token.type == isc_tokentype_unknown) {
+ flags = 0;
+ tokenbuf[0] = '\0';
+ } else {
+ isc_lex_getlasttokentext(pctx->lexer,
+ &pctx->token, &r);
+ if (r.length > MAX_LOG_TOKEN)
+ snprintf(tokenbuf, sizeof(tokenbuf),
+ "'%.*s...'", MAX_LOG_TOKEN, r.base);
+ else
+ snprintf(tokenbuf, sizeof(tokenbuf),
+ "'%.*s'", (int)r.length, r.base);
+ }
+
+ /* Choose a preposition. */
+ if (flags & CFG_LOG_NEAR)
+ prep = " near ";
+ else if (flags & CFG_LOG_BEFORE)
+ prep = " before ";
+ else
+ prep = " ";
+ } else {
+ tokenbuf[0] = '\0';
+ }
+ isc_log_write(pctx->lctx, CAT, MOD, level,
+ "%s%s%s%s", where, message, prep, tokenbuf);
+}
+
+void
+cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level,
+ const char *fmt, ...) {
+ va_list ap;
+ char msgbuf[2048];
+
+ REQUIRE(obj != NULL);
+ REQUIRE(fmt != NULL);
+
+ if (! isc_log_wouldlog(lctx, level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ if (obj->file != NULL) {
+ isc_log_write(lctx, CAT, MOD, level,
+ "%s:%u: %s", obj->file, obj->line, msgbuf);
+ } else {
+ isc_log_write(lctx, CAT, MOD, level, "%s", msgbuf);
+ }
+}
+
+const char *
+cfg_obj_file(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+
+ return (obj->file);
+}
+
+unsigned int
+cfg_obj_line(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+
+ return (obj->line);
+}
+
+isc_result_t
+cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t));
+ if (obj == NULL)
+ return (ISC_R_NOMEMORY);
+
+ obj->type = type;
+ obj->file = current_file(pctx);
+ obj->line = pctx->line;
+ obj->pctx = pctx;
+
+ result = isc_refcount_init(&obj->references, 1);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
+ return (result);
+ }
+ *ret = obj;
+
+ return (ISC_R_SUCCESS);
+}
+
+
+static void
+map_symtabitem_destroy(char *key, unsigned int type,
+ isc_symvalue_t symval, void *userarg)
+{
+ cfg_obj_t *obj = symval.as_pointer;
+ cfg_parser_t *pctx = (cfg_parser_t *)userarg;
+
+ UNUSED(key);
+ UNUSED(type);
+
+ cfg_obj_destroy(pctx, &obj);
+}
+
+static isc_result_t
+create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ isc_symtab_t *symtab = NULL;
+ cfg_obj_t *obj = NULL;
+
+ CHECK(cfg_create_obj(pctx, type, &obj));
+ CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */
+ map_symtabitem_destroy,
+ pctx, false, &symtab));
+ obj->value.map.symtab = symtab;
+ obj->value.map.id = NULL;
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (obj != NULL)
+ isc_mem_put(pctx->mctx, obj, sizeof(*obj));
+ return (result);
+}
+
+static void
+free_map(cfg_parser_t *pctx, cfg_obj_t *obj) {
+ CLEANUP_OBJ(obj->value.map.id);
+ isc_symtab_destroy(&obj->value.map.symtab);
+}
+
+bool
+cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) {
+
+ REQUIRE(obj != NULL);
+ REQUIRE(type != NULL);
+
+ return (obj->type == type);
+}
+
+/*
+ * Destroy 'obj', a configuration object created in 'pctx'.
+ */
+void
+cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) {
+ cfg_obj_t *obj;
+ unsigned int refs;
+
+ REQUIRE(objp != NULL && *objp != NULL);
+ REQUIRE(pctx != NULL);
+
+ obj = *objp;
+
+ isc_refcount_decrement(&obj->references, &refs);
+ if (refs == 0) {
+ obj->type->rep->free(pctx, obj);
+ isc_refcount_destroy(&obj->references);
+ isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
+ }
+ *objp = NULL;
+}
+
+void
+cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) {
+ REQUIRE(src != NULL);
+ REQUIRE(dest != NULL && *dest == NULL);
+
+ isc_refcount_increment(&src->references, NULL);
+ *dest = src;
+}
+
+static void
+free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) {
+ UNUSED(pctx);
+ UNUSED(obj);
+}
+
+void
+cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+
+ type->doc(pctx, type);
+}
+
+void
+cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+
+ cfg_print_cstr(pctx, "<");
+ cfg_print_cstr(pctx, type->name);
+ cfg_print_cstr(pctx, ">");
+}
+
+void
+cfg_print_grammar(const cfg_type_t *type,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure)
+{
+ cfg_printer_t pctx;
+
+ pctx.f = f;
+ pctx.closure = closure;
+ pctx.indent = 0;
+ pctx.flags = 0;
+ cfg_doc_obj(&pctx, type);
+}
+
+isc_result_t
+cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj,
+ cfg_obj_t *obj, const char *clausename)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ const cfg_map_t *map;
+ isc_symvalue_t symval;
+ cfg_obj_t *destobj = NULL;
+ cfg_listelt_t *elt = NULL;
+ const cfg_clausedef_t * const *clauseset;
+ const cfg_clausedef_t *clause;
+
+ REQUIRE(pctx != NULL);
+ REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
+ REQUIRE(obj != NULL);
+ REQUIRE(clausename != NULL);
+
+ map = &mapobj->value.map;
+
+ clause = NULL;
+ for (clauseset = map->clausesets; *clauseset != NULL; clauseset++) {
+ for (clause = *clauseset; clause->name != NULL; clause++) {
+ if (strcasecmp(clause->name, clausename) == 0) {
+ goto breakout;
+ }
+ }
+ }
+
+ breakout:
+ if (clause == NULL || clause->name == NULL)
+ return (ISC_R_FAILURE);
+
+ result = isc_symtab_lookup(map->symtab, clausename, 0, &symval);
+ if (result == ISC_R_NOTFOUND) {
+ if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
+ CHECK(cfg_create_list(pctx, &cfg_type_implicitlist,
+ &destobj));
+ CHECK(create_listelt(pctx, &elt));
+ cfg_obj_attach(obj, &elt->obj);
+ ISC_LIST_APPEND(destobj->value.list, elt, link);
+ symval.as_pointer = destobj;
+ } else
+ symval.as_pointer = obj;
+
+ CHECK(isc_symtab_define(map->symtab, clausename, 1, symval,
+ isc_symexists_reject));
+ } else {
+ cfg_obj_t *destobj2 = symval.as_pointer;
+
+ INSIST(result == ISC_R_SUCCESS);
+
+ if (destobj2->type == &cfg_type_implicitlist) {
+ CHECK(create_listelt(pctx, &elt));
+ cfg_obj_attach(obj, &elt->obj);
+ ISC_LIST_APPEND(destobj2->value.list, elt, link);
+ } else
+ result = ISC_R_EXISTS;
+ }
+
+ destobj = NULL;
+ elt = NULL;
+
+ cleanup:
+ if (elt != NULL)
+ free_listelt(pctx, elt);
+ CLEANUP_OBJ(destobj);
+
+ return (result);
+}
diff --git a/lib/isccfg/tests/Atffile b/lib/isccfg/tests/Atffile
new file mode 100644
index 0000000..f399e12
--- /dev/null
+++ b/lib/isccfg/tests/Atffile
@@ -0,0 +1,5 @@
+Content-Type: application/X-atf-atffile; version="1"
+
+prop: test-suite = bind9
+
+tp: parser_test
diff --git a/lib/isccfg/tests/Kyuafile b/lib/isccfg/tests/Kyuafile
new file mode 100644
index 0000000..342d25f
--- /dev/null
+++ b/lib/isccfg/tests/Kyuafile
@@ -0,0 +1,4 @@
+syntax(2)
+test_suite('bind9')
+
+atf_test_program{name='parser_test'}
diff --git a/lib/isccfg/tests/Makefile.in b/lib/isccfg/tests/Makefile.in
new file mode 100644
index 0000000..327226b
--- /dev/null
+++ b/lib/isccfg/tests/Makefile.in
@@ -0,0 +1,54 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+# Attempt to disable parallel processing.
+.NOTPARALLEL:
+.NO_PARALLEL:
+
+VERSION=@BIND9_VERSION@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = -I. -Iinclude \
+ ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \
+ @DST_OPENSSL_INC@
+CDEFINES = @CRYPTO@ -DTESTS="\"${top_builddir}/lib/dns/tests/\""
+
+ISCLIBS = ../../isc/libisc.@A@
+ISCDEPLIBS = ../../isc/libisc.@A@
+DNSLIBS = ../../dns/libdns.@A@ @DNS_CRYPTO_LIBS@
+DNSDEPLIBS = ../../dns/libdns.@A@
+ISCCFGLIBS = ../libisccfg.@A@
+ISCCFGDEPLIBS = ../libisccfg.@A@
+
+LIBS = @LIBS@ @ATFLIBS@
+
+OBJS =
+SRCS = parser_test.c
+
+SUBDIRS =
+TARGETS = parser_test@EXEEXT@
+
+@BIND9_MAKE_RULES@
+
+parser_test@EXEEXT@: parser_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ${ISCCFGDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ parser_test.@O@ ${ISCCFGLIBS} ${DNSLIBS} \
+ ${ISCLIBS} ${LIBS}
+
+unit::
+ sh ${top_builddir}/unit/unittest.sh
+
+clean distclean::
+ rm -f ${TARGETS}
+ rm -f atf.out
diff --git a/lib/isccfg/tests/parser_test.c b/lib/isccfg/tests/parser_test.c
new file mode 100644
index 0000000..606bbeb
--- /dev/null
+++ b/lib/isccfg/tests/parser_test.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <isccfg/cfg.h>
+#include <isccfg/grammar.h>
+#include <isccfg/namedconf.h>
+
+#define CHECK(r) \
+ do { \
+ result = (r); \
+ if (result != ISC_R_SUCCESS) \
+ goto cleanup; \
+ } while (0)
+
+isc_mem_t *mctx = NULL;
+isc_log_t *lctx = NULL;
+static isc_logcategory_t categories[] = {
+ { "", 0 },
+ { "client", 0 },
+ { "network", 0 },
+ { "update", 0 },
+ { "queries", 0 },
+ { "unmatched", 0 },
+ { "update-security", 0 },
+ { "query-errors", 0 },
+ { NULL, 0 }
+};
+
+static void
+cleanup() {
+ if (lctx != NULL)
+ isc_log_destroy(&lctx);
+ if (mctx != NULL)
+ isc_mem_destroy(&mctx);
+}
+
+static isc_result_t
+setup() {
+ isc_result_t result;
+
+ isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
+ CHECK(isc_mem_create(0, 0, &mctx));
+
+ isc_logdestination_t destination;
+ isc_logconfig_t *logconfig = NULL;
+
+ CHECK(isc_log_create(mctx, &lctx, &logconfig));
+ isc_log_registercategories(lctx, categories);
+ isc_log_setcontext(lctx);
+
+ destination.file.stream = stderr;
+ destination.file.name = NULL;
+ destination.file.versions = ISC_LOG_ROLLNEVER;
+ destination.file.maximum_size = 0;
+ CHECK(isc_log_createchannel(logconfig, "stderr",
+ ISC_LOG_TOFILEDESC,
+ ISC_LOG_DYNAMIC,
+ &destination, 0));
+ CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL));
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ cleanup();
+ return (result);
+}
+
+ATF_TC(parse_buffer);
+ATF_TC_HEAD(parse_buffer, tc) {
+ atf_tc_set_md_var(tc, "descr", "cfg_parse_buffer");
+}
+ATF_TC_BODY(parse_buffer, tc) {
+ isc_result_t result;
+ unsigned char text[] = "options\n{\nrecursion yes;\n};\n";
+ isc_buffer_t buf1, buf2;
+ cfg_parser_t *p1 = NULL, *p2 = NULL;
+ cfg_obj_t *c1 = NULL, *c2 = NULL;
+
+ UNUSED(tc);
+
+ setup();
+
+ isc_buffer_init(&buf1, &text[0], sizeof(text) - 1);
+ isc_buffer_add(&buf1, sizeof(text) - 1);
+
+ /* Parse with default line numbering */
+ result = cfg_parser_create(mctx, lctx, &p1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = cfg_parse_buffer3(p1, &buf1, "text1", 0,
+ &cfg_type_namedconf, &c1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(p1->line, 5);
+
+ isc_buffer_init(&buf2, &text[0], sizeof(text) - 1);
+ isc_buffer_add(&buf2, sizeof(text) - 1);
+
+ /* Parse with changed line number */
+ result = cfg_parser_create(mctx, lctx, &p2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = cfg_parse_buffer3(p2, &buf2, "text2", 100,
+ &cfg_type_namedconf, &c2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(p2->line, 104);
+
+ cfg_obj_destroy(p1, &c1);
+ cfg_obj_destroy(p2, &c2);
+
+ cfg_parser_destroy(&p1);
+ cfg_parser_destroy(&p2);
+
+ cleanup();
+}
+
+ATF_TC(cfg_map_firstclause);
+ATF_TC_HEAD(cfg_map_firstclause, tc) {
+ atf_tc_set_md_var(tc, "descr", "cfg_map_firstclause");
+}
+ATF_TC_BODY(cfg_map_firstclause, tc) {
+ const char *name = NULL;
+ const void *clauses = NULL;
+ unsigned int idx;
+
+ UNUSED(tc);
+
+ name = cfg_map_firstclause(&cfg_type_zoneopts, &clauses, &idx);
+ ATF_CHECK(name != NULL);
+ ATF_CHECK(clauses != NULL);
+ ATF_CHECK_EQ(idx, 0);
+}
+
+ATF_TC(cfg_map_nextclause);
+ATF_TC_HEAD(cfg_map_nextclause, tc) {
+ atf_tc_set_md_var(tc, "descr", "cfg_map_firstclause");
+}
+ATF_TC_BODY(cfg_map_nextclause, tc) {
+ const char *name = NULL;
+ const void *clauses = NULL;
+ unsigned int idx;
+
+ UNUSED(tc);
+
+ name = cfg_map_firstclause(&cfg_type_zoneopts, &clauses, &idx);
+ ATF_REQUIRE(name != NULL);
+ ATF_REQUIRE(clauses != NULL);
+ ATF_REQUIRE_EQ(idx, ISC_R_SUCCESS);
+
+ do {
+ name = cfg_map_nextclause(&cfg_type_zoneopts, &clauses, &idx);
+ if (name != NULL) {
+ ATF_CHECK(clauses != NULL);
+ } else {
+ ATF_CHECK_EQ(clauses, NULL);
+ ATF_CHECK_EQ(idx, 0);
+ }
+ } while (name != NULL);
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, parse_buffer);
+ ATF_TP_ADD_TC(tp, cfg_map_firstclause);
+ ATF_TP_ADD_TC(tp, cfg_map_nextclause);
+ return (atf_no_error());
+}
diff --git a/lib/isccfg/version.c b/lib/isccfg/version.c
new file mode 100644
index 0000000..51ed4b5
--- /dev/null
+++ b/lib/isccfg/version.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/*! \file */
+
+#include <isccfg/version.h>
+
+const char cfg_version[] = VERSION;
+
+const unsigned int cfg_libinterface = LIBINTERFACE;
+const unsigned int cfg_librevision = LIBREVISION;
+const unsigned int cfg_libage = LIBAGE;
+
diff --git a/lib/isccfg/win32/DLLMain.c b/lib/isccfg/win32/DLLMain.c
new file mode 100644
index 0000000..93c2893
--- /dev/null
+++ b/lib/isccfg/win32/DLLMain.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <windows.h>
+#include <signal.h>
+
+/*
+ * Called when we enter the DLL
+ */
+__declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL,
+ DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ /*
+ * The DLL is loading due to process
+ * initialization or a call to LoadLibrary.
+ */
+ case DLL_PROCESS_ATTACH:
+ break;
+
+ /*
+ * The attached process creates a new thread.
+ */
+ case DLL_THREAD_ATTACH:
+ break;
+
+ /* The thread of the attached process terminates. */
+ case DLL_THREAD_DETACH:
+ break;
+
+ /*
+ * The DLL is unloading from a process due to
+ * process termination or a call to FreeLibrary.
+ */
+ case DLL_PROCESS_DETACH:
+ break;
+
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
diff --git a/lib/isccfg/win32/libisccfg.def b/lib/isccfg/win32/libisccfg.def
new file mode 100644
index 0000000..c5e9be7
--- /dev/null
+++ b/lib/isccfg/win32/libisccfg.def
@@ -0,0 +1,165 @@
+LIBRARY libisccfg
+
+; Exported Functions
+EXPORTS
+
+cfg_acl_fromconfig
+cfg_acl_fromconfig2
+cfg_aclconfctx_attach
+cfg_aclconfctx_create
+cfg_aclconfctx_detach
+cfg_clause_validforzone
+cfg_create_list
+cfg_create_obj
+cfg_create_tuple
+cfg_doc_bracketed_list
+cfg_doc_enum
+cfg_doc_map
+cfg_doc_mapbody
+cfg_doc_obj
+cfg_doc_sockaddr
+cfg_doc_terminal
+cfg_doc_tuple
+cfg_doc_void
+cfg_gettoken
+cfg_is_enum
+cfg_list_first
+cfg_list_length
+cfg_list_next
+cfg_listelt_value
+cfg_log_init
+cfg_lookingat_netaddr
+cfg_map_count
+cfg_map_firstclause
+cfg_map_get
+cfg_map_getname
+cfg_map_nextclause
+cfg_obj_asboolean
+cfg_obj_asfixedpoint
+cfg_obj_asnetprefix
+cfg_obj_aspercentage
+cfg_obj_assockaddr
+cfg_obj_asstring
+cfg_obj_asuint32
+cfg_obj_asuint64
+cfg_obj_attach
+cfg_obj_destroy
+cfg_obj_file
+cfg_obj_getdscp
+cfg_obj_isboolean
+cfg_obj_isfixedpoint
+cfg_obj_islist
+cfg_obj_ismap
+cfg_obj_isnetprefix
+cfg_obj_ispercentage
+cfg_obj_issockaddr
+cfg_obj_isstring
+cfg_obj_istuple
+cfg_obj_istype
+cfg_obj_isuint32
+cfg_obj_isuint64
+cfg_obj_isvoid
+cfg_obj_line
+cfg_obj_log
+cfg_parse_addressed_map
+cfg_parse_astring
+cfg_parse_boolean
+cfg_parse_bracketed_list
+cfg_parse_buffer
+cfg_parse_buffer2
+cfg_parse_buffer3
+cfg_parse_buffer4
+cfg_parse_dscp
+cfg_parse_enum
+cfg_parse_file
+cfg_parse_fixedpoint
+cfg_parse_listelt
+cfg_parse_map
+cfg_parse_mapbody
+cfg_parse_named_map
+cfg_parse_netprefix
+cfg_parse_netprefix_map
+cfg_parse_obj
+cfg_parse_percentage
+cfg_parse_qstring
+cfg_parse_rawaddr
+cfg_parse_rawport
+cfg_parse_sockaddr
+cfg_parse_spacelist
+cfg_parse_special
+cfg_parse_sstring
+cfg_parse_tuple
+cfg_parse_uint32
+cfg_parse_void
+cfg_parser_attach
+cfg_parser_create
+cfg_parser_destroy
+cfg_parser_error
+cfg_parser_mapadd
+cfg_parser_reset
+cfg_parser_setcallback
+cfg_parser_warning
+cfg_peektoken
+cfg_print
+cfg_print_boolean
+cfg_print_bracketed_list
+cfg_print_chars
+cfg_print_clauseflags
+cfg_print_cstr
+cfg_print_fixedpoint
+cfg_print_grammar
+cfg_print_indent
+cfg_print_map
+cfg_print_mapbody
+cfg_print_obj
+cfg_print_percentage
+cfg_print_rawaddr
+cfg_print_rawuint
+cfg_print_sockaddr
+cfg_print_spacelist
+cfg_print_tuple
+cfg_print_uint32
+cfg_print_uint64
+cfg_print_ustring
+cfg_print_void
+cfg_print_zonegrammar
+cfg_printx
+cfg_tuple_get
+cfg_ungettoken
+
+; Exported Data
+
+;cfg_rep_boolean
+;cfg_rep_fixedpoint
+;cfg_rep_list
+;cfg_rep_map
+;cfg_rep_netprefix
+;cfg_rep_percentage
+;cfg_rep_sockaddr
+;cfg_rep_string
+;cfg_rep_tuple
+;cfg_rep_uint32
+;cfg_rep_uint64
+;cfg_rep_void
+;cfg_type_astring
+;cfg_type_boolean
+;cfg_type_bracketed_text
+;cfg_type_fixedpoint
+;cfg_type_netaddr
+;cfg_type_netaddr4
+;cfg_type_netaddr4wild
+;cfg_type_netaddr6
+;cfg_type_netaddr6wild
+;cfg_type_netprefix
+;cfg_type_percentage
+;cfg_type_qstring
+;cfg_type_rndcconf
+;cfg_type_sockaddr
+;cfg_type_sockaddrdscp
+;cfg_type_sstring
+;cfg_type_token
+;cfg_type_uint32
+;cfg_type_uint64
+;cfg_type_unsupported
+;cfg_type_ustring
+;cfg_type_void
diff --git a/lib/isccfg/win32/libisccfg.dsp.in b/lib/isccfg/win32/libisccfg.dsp.in
new file mode 100644
index 0000000..425af5a
--- /dev/null
+++ b/lib/isccfg/win32/libisccfg.dsp.in
@@ -0,0 +1,169 @@
+# Microsoft Developer Studio Project File - Name="libisccfg" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "@PLATFORM@ (x86) Dynamic-Link Library" 0x0102
+
+CFG=libisccfg - @PLATFORM@ Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libisccfg.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libisccfg.mak" CFG="libisccfg - @PLATFORM@ Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libisccfg - @PLATFORM@ Release" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE "libisccfg - @PLATFORM@ Debug" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 @COPTX@ @COPTI@ /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "libisccfg_EXPORTS" @COPTY@ /FD /c
+# ADD CPP /nologo /MD /W3 @COPTX@ @COPTI@ /O2 /I "./" /I "../../../" /I "include" /I "../include" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/dns/win32/include" /I "../../../lib/dns/include" @LIBXML2_INC@ @GEOIP_INC@ /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "USE_MD5" @CRYPTO@ /D "LIBISCCFG_EXPORTS" @COPTY@ /FD /c
+# SUBTRACT CPP /X
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll @MACHINE@
+# ADD LINK32 user32.lib advapi32.lib ws2_32.lib ../../dns/win32/Release/libdns.lib ../../isc/win32/Release/libisc.lib /nologo /dll @MACHINE@ /out:"../../../Build/Release/libisccfg.dll"
+
+!ELSEIF "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "libisccfg_EXPORTS" @COPTY@ /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /I "./" /I "../../../" /I "include" /I "../include" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/dns/win32/include" /I "../../../lib/dns/include" @LIBXML2_INC@ @GEOIP_INC@ /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISCCFG_EXPORTS" /FR @COPTY@ /FD /GZ /c
+# SUBTRACT CPP /X
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug @MACHINE@ /pdbtype:sept
+# ADD LINK32 user32.lib advapi32.lib ws2_32.lib ../../dns/win32/debug/libdns.lib ../../isc/win32/debug/libisc.lib /nologo /dll /debug @MACHINE@ /out:"../../../Build/Debug/libisccfg.dll" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "libisccfg - @PLATFORM@ Release"
+# Name "libisccfg - @PLATFORM@ Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\DLLMain.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\aclconf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\dnsconf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\log.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\namedconf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\parser.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\version.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\include\isccfg\cfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccfg\check.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccfg\grammar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccfg\aclconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccfg\dnsconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccfg\log.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccfg\namedconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isccfg\version.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=.\libisccfg.def
+# End Source File
+# End Target
+# End Project
diff --git a/lib/isccfg/win32/libisccfg.dsw b/lib/isccfg/win32/libisccfg.dsw
new file mode 100644
index 0000000..2851ea8
--- /dev/null
+++ b/lib/isccfg/win32/libisccfg.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "libisccfg"=".\libisccfg.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lib/isccfg/win32/libisccfg.mak.in b/lib/isccfg/win32/libisccfg.mak.in
new file mode 100644
index 0000000..aa24b27
--- /dev/null
+++ b/lib/isccfg/win32/libisccfg.mak.in
@@ -0,0 +1,490 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on libisccfg.dsp
+!IF "$(CFG)" == ""
+CFG=libisccfg - @PLATFORM@ Debug
+!MESSAGE No configuration specified. Defaulting to libisccfg - @PLATFORM@ Debug.
+!ENDIF
+
+!IF "$(CFG)" != "libisccfg - @PLATFORM@ Release" && "$(CFG)" != "libisccfg - @PLATFORM@ Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libisccfg.mak" CFG="libisccfg - @PLATFORM@ Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libisccfg - @PLATFORM@ Release" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE "libisccfg - @PLATFORM@ Debug" (based on "@PLATFORM@ (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+_VC_MANIFEST_INC=0
+_VC_MANIFEST_BASENAME=__VC80
+!ELSE
+_VC_MANIFEST_INC=1
+_VC_MANIFEST_BASENAME=__VC80.Debug
+!ENDIF
+
+####################################################
+# Specifying name of temporary resource file used only in incremental builds:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res
+!else
+_VC_MANIFEST_AUTO_RES=
+!endif
+
+####################################################
+# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+#MT_SPECIAL_RETURN=1090650113
+#MT_SPECIAL_SWITCH=-notify_resource_update
+MT_SPECIAL_RETURN=0
+MT_SPECIAL_SWITCH=
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
+if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
+rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
+link $** /out:$@ $(LFLAGS)
+
+!else
+
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1
+
+!endif
+
+####################################################
+# _VC_MANIFEST_EMBED_DLL - command to embed manifest in DLL:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+#MT_SPECIAL_RETURN=1090650113
+#MT_SPECIAL_SWITCH=-notify_resource_update
+MT_SPECIAL_RETURN=0
+MT_SPECIAL_SWITCH=
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
+if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
+rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
+link $** /out:$@ $(LFLAGS)
+
+!else
+
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;2
+
+!endif
+####################################################
+# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \
+ $(_VC_MANIFEST_BASENAME).auto.rc \
+ $(_VC_MANIFEST_BASENAME).auto.manifest
+
+!else
+
+_VC_MANIFEST_CLEAN=
+
+!endif
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\..\..\Build\Release\libisccfg.dll"
+
+!ELSE
+
+ALL : "libdns - @PLATFORM@ Release" "libisc - @PLATFORM@ Release" "..\..\..\Build\Release\libisccfg.dll"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libdns - @PLATFORM@ ReleaseCLEAN" "libisc - @PLATFORM@ ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\DLLMain.obj"
+ -@erase "$(INTDIR)\aclconf.obj"
+ -@erase "$(INTDIR)\dnsconf.obj"
+ -@erase "$(INTDIR)\log.obj"
+ -@erase "$(INTDIR)\namedconf.obj"
+ -@erase "$(INTDIR)\parser.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\version.obj"
+ -@erase "$(OUTDIR)\libisccfg.exp"
+ -@erase "$(OUTDIR)\libisccfg.lib"
+ -@erase "..\..\..\Build\Release\libisccfg.dll"
+ -@$(_VC_MANIFEST_CLEAN)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MD /W3 @COPTX@ @COPTI@ /O2 /I "./" /I "../../../" /I "include" /I "../include" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/dns/win32/include" /I "../../../lib/dns/include" @LIBXML2_INC@ @GEOIP_INC@ /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "USE_MD5" @CRYPTO@ /D "LIBISCCFG_EXPORTS" /Fp"$(INTDIR)\libisccfg.pch" @COPTY@ /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libisccfg.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=user32.lib advapi32.lib ws2_32.lib ../../dns/win32/Release/libdns.lib ../../isc/win32/Release/libisc.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\libisccfg.pdb" @MACHINE@ /def:".\libisccfg.def" /out:"../../../Build/Release/libisccfg.dll" /implib:"$(OUTDIR)\libisccfg.lib"
+DEF_FILE= \
+ ".\libisccfg.def"
+LINK32_OBJS= \
+ "$(INTDIR)\DLLMain.obj" \
+ "$(INTDIR)\aclconf.obj" \
+ "$(INTDIR)\dnsconf.obj" \
+ "$(INTDIR)\log.obj" \
+ "$(INTDIR)\parser.obj" \
+ "$(INTDIR)\version.obj" \
+ "$(INTDIR)\namedconf.obj" \
+ "..\..\dns\win32\Release\libdns.lib" \
+ "..\..\isc\win32\Release\libisc.lib"
+
+"..\..\..\Build\Release\libisccfg.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+ $(_VC_MANIFEST_EMBED_DLL)
+
+!ELSEIF "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\..\..\Build\Debug\libisccfg.dll" "$(OUTDIR)\libisccfg.bsc"
+
+!ELSE
+
+ALL : "libisc - @PLATFORM@ Debug" "..\..\..\Build\Debug\libisccfg.dll" "$(OUTDIR)\libisccfg.bsc"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libisc - @PLATFORM@ DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\DLLMain.obj"
+ -@erase "$(INTDIR)\DLLMain.sbr"
+ -@erase "$(INTDIR)\aclconf.obj"
+ -@erase "$(INTDIR)\aclconf.sbr"
+ -@erase "$(INTDIR)\dnsconf.obj"
+ -@erase "$(INTDIR)\dnsconf.sbr"
+ -@erase "$(INTDIR)\log.obj"
+ -@erase "$(INTDIR)\log.sbr"
+ -@erase "$(INTDIR)\namedconf.obj"
+ -@erase "$(INTDIR)\namedconf.sbr"
+ -@erase "$(INTDIR)\parser.obj"
+ -@erase "$(INTDIR)\parser.sbr"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\version.obj"
+ -@erase "$(INTDIR)\version.sbr"
+ -@erase "$(OUTDIR)\libisccfg.bsc"
+ -@erase "$(OUTDIR)\libisccfg.exp"
+ -@erase "$(OUTDIR)\libisccfg.lib"
+ -@erase "$(OUTDIR)\libisccfg.pdb"
+ -@erase "..\..\..\Build\Debug\libisccfg.dll"
+ -@erase "..\..\..\Build\Debug\libisccfg.ilk"
+ -@$(_VC_MANIFEST_CLEAN)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MDd /W3 /Gm @COPTX@ @COPTI@ /ZI /Od /I "./" /I "../../../" /I "include" /I "../include" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/dns/win32/include" /I "../../../lib/dns/include" @LIBXML2_INC@ @GEOIP_INC@ /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISCCFG_EXPORTS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\libisccfg.pch" @COPTY@ /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libisccfg.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\DLLMain.sbr" \
+ "$(INTDIR)\aclconf.sbr" \
+ "$(INTDIR)\dnsconf.sbr" \
+ "$(INTDIR)\log.sbr" \
+ "$(INTDIR)\parser.sbr" \
+ "$(INTDIR)\version.sbr" \
+ "$(INTDIR)\namedconf.sbr"
+
+"$(OUTDIR)\libisccfg.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=user32.lib advapi32.lib ws2_32.lib ../../dns/win32/debug/libdns.lib ../../isc/win32/debug/libisc.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\libisccfg.pdb" /debug @MACHINE@ /def:".\libisccfg.def" /out:"../../../Build/Debug/libisccfg.dll" /implib:"$(OUTDIR)\libisccfg.lib" /pdbtype:sept
+DEF_FILE= \
+ ".\libisccfg.def"
+LINK32_OBJS= \
+ "$(INTDIR)\DLLMain.obj" \
+ "$(INTDIR)\aclconf.obj" \
+ "$(INTDIR)\dnsconf.obj" \
+ "$(INTDIR)\log.obj" \
+ "$(INTDIR)\parser.obj" \
+ "$(INTDIR)\version.obj" \
+ "$(INTDIR)\namedconf.obj" \
+ "..\..\dns\win32\Debug\libdns.lib" \
+ "..\..\isc\win32\Debug\libisc.lib"
+
+"..\..\..\Build\Debug\libisccfg.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+ $(_VC_MANIFEST_EMBED_DLL)
+
+!ENDIF
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("libisccfg.dep")
+!INCLUDE "libisccfg.dep"
+!ELSE
+!MESSAGE Warning: cannot find "libisccfg.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release" || "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+SOURCE=.\DLLMain.c
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+
+
+"$(INTDIR)\DLLMain.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\DLLMain.obj" "$(INTDIR)\DLLMain.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=..\aclconf.c
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+
+
+"$(INTDIR)\aclconf.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\aclconf.obj" "$(INTDIR)\aclconf.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\dnsconf.c
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+
+
+"$(INTDIR)\dnsconf.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\dnsconf.obj" "$(INTDIR)\dnsconf.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\log.c
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+
+
+"$(INTDIR)\log.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\log.obj" "$(INTDIR)\log.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\namedconf.c
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+
+
+"$(INTDIR)\namedconf.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\namedconf.obj" "$(INTDIR)\namedconf.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\parser.c
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+
+
+"$(INTDIR)\parser.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\parser.obj" "$(INTDIR)\parser.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\version.c
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+
+
+"$(INTDIR)\version.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\version.obj" "$(INTDIR)\version.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF
+
+!IF "$(CFG)" == "libisccfg - @PLATFORM@ Release"
+
+"libdns - @PLATFORM@ Release" :
+ cd "..\..\dns\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdns.mak" CFG="libdns - @PLATFORM@ Release"
+ cd "..\..\isccfg\win32"
+
+"libdns - @PLATFORM@ ReleaseCLEAN" :
+ cd "..\..\dns\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdns.mak" CFG="libdns - @PLATFORM@ Release" RECURSE=1 CLEAN
+ cd "..\..\isccfg\win32"
+
+"libisc - @PLATFORM@ Release" :
+ cd "..\..\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - @PLATFORM@ Release"
+ cd "..\..\isccfg\win32"
+
+"libisc - @PLATFORM@ ReleaseCLEAN" :
+ cd "..\..\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - @PLATFORM@ Release" RECURSE=1 CLEAN
+ cd "..\..\isccfg\win32"
+
+!ELSEIF "$(CFG)" == "libisccfg - @PLATFORM@ Debug"
+
+"libdns - @PLATFORM@ Debug" :
+ cd "..\..\dns\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdns.mak" CFG="libdns - @PLATFORM@ Debug"
+ cd "..\..\isccfg\win32"
+
+"libdns - @PLATFORM@ DebugCLEAN" :
+ cd "..\..\dns\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdns.mak" CFG="libdns - @PLATFORM@ Debug" RECURSE=1 CLEAN
+ cd "..\..\isccfg\win32"
+
+"libisc - @PLATFORM@ Debug" :
+ cd "..\..\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - @PLATFORM@ Debug"
+ cd "..\..\isccfg\win32"
+
+"libisc - @PLATFORM@ DebugCLEAN" :
+ cd "..\..\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - @PLATFORM@ Debug" RECURSE=1 CLEAN
+ cd "..\..\isccfg\win32"
+
+!ENDIF
+
+
+!ENDIF
+
+####################################################
+# Commands to generate initial empty manifest file and the RC file
+# that references it, and for generating the .res file:
+
+$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc
+
+$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest
+ type <<$@
+#include <winuser.h>
+1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest"
+<< KEEP
+
+$(_VC_MANIFEST_BASENAME).auto.manifest :
+ type <<$@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+</assembly>
+<< KEEP
diff --git a/lib/isccfg/win32/libisccfg.vcxproj.filters.in b/lib/isccfg/win32/libisccfg.vcxproj.filters.in
new file mode 100644
index 0000000..46b4e54
--- /dev/null
+++ b/lib/isccfg/win32/libisccfg.vcxproj.filters.in
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="libisccfg.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="DLLMain.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="version.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\aclconf.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\dnsconf.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\log.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\namedconf.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\parser.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\include\isccfg\aclconf.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccfg\dnsconf.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccfg\cfg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccfg\grammar.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccfg\log.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccfg\namedconf.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isccfg\version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/lib/isccfg/win32/libisccfg.vcxproj.in b/lib/isccfg/win32/libisccfg.vcxproj.in
new file mode 100644
index 0000000..74a445f
--- /dev/null
+++ b/lib/isccfg/win32/libisccfg.vcxproj.in
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|@PLATFORM@">
+ <Configuration>Debug</Configuration>
+ <Platform>@PLATFORM@</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|@PLATFORM@">
+ <Configuration>Release</Configuration>
+ <Platform>@PLATFORM@</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{B2DFA58C-6347-478E-81E8-01E06999D4F1}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>libisccfg</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>..\..\..\Build\$(Configuration)\</OutDir>
+ <IntDir>.\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>..\..\..\Build\$(Configuration)\</OutDir>
+ <IntDir>.\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;USE_MD5;@CRYPTO@_DEBUG;_WINDOWS;_USRDLL;LIBISCCFG_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>.\;..\..\..\;include;..\include;..\..\isc\win32;..\..\isc\win32\include;..\..\isc\include;..\..\dns\include;@LIBXML2_INC@@GEOIP_INC@%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeaderOutputFile>.\$(Configuration)\$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\$(Configuration)\</AssemblerListingLocation>
+ <ObjectFileName>.\$(Configuration)\</ObjectFileName>
+ <ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <BrowseInformation>true</BrowseInformation>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>..\..\dns\win32\$(Configuration);..\..\isc\win32\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libdns.lib;libisc.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
+ <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
+ <ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>@INTRINSIC@</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;USE_MD5;@CRYPTO@NDEBUG;_WINDOWS;_USRDLL;LIBISCCFG_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>.\;..\..\..\;include;..\include;..\..\isc\win32;..\..\isc\win32\include;..\..\isc\include;..\..\dns\include;@LIBXML2_INC@@GEOIP_INC@%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <StringPooling>true</StringPooling>
+ <PrecompiledHeaderOutputFile>.\$(Configuration)\$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\$(Configuration)\</AssemblerListingLocation>
+ <ObjectFileName>.\$(Configuration)\</ObjectFileName>
+ <ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalLibraryDirectories>..\..\dns\win32\$(Configuration);..\..\isc\win32\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libdns.lib;libisc.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
+ <OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
+ <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
+ <ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <None Include="libisccfg.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\aclconf.c" />
+ <ClCompile Include="..\dnsconf.c" />
+ <ClCompile Include="..\log.c" />
+ <ClCompile Include="..\namedconf.c" />
+ <ClCompile Include="..\parser.c" />
+ <ClCompile Include="DLLMain.c" />
+ <ClCompile Include="version.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\include\isccfg\aclconf.h" />
+ <ClInclude Include="..\include\isccfg\dnsconf.h" />
+ <ClInclude Include="..\include\isccfg\cfg.h" />
+ <ClInclude Include="..\include\isccfg\grammar.h" />
+ <ClInclude Include="..\include\isccfg\log.h" />
+ <ClInclude Include="..\include\isccfg\namedconf.h" />
+ <ClInclude Include="..\include\isccfg\version.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/lib/isccfg/win32/libisccfg.vcxproj.user b/lib/isccfg/win32/libisccfg.vcxproj.user
new file mode 100644
index 0000000..695b5c7
--- /dev/null
+++ b/lib/isccfg/win32/libisccfg.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project> \ No newline at end of file
diff --git a/lib/isccfg/win32/version.c b/lib/isccfg/win32/version.c
new file mode 100644
index 0000000..4a69e87
--- /dev/null
+++ b/lib/isccfg/win32/version.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+#include <versions.h>
+
+#include <isccfg/version.h>
+
+LIBISCCFG_EXTERNAL_DATA const char cfg_version[] = VERSION;
+
+LIBISCCFG_EXTERNAL_DATA const unsigned int cfg_libinterface = LIBINTERFACE;
+LIBISCCFG_EXTERNAL_DATA const unsigned int cfg_librevision = LIBREVISION;
+LIBISCCFG_EXTERNAL_DATA const unsigned int cfg_libage = LIBAGE;
+