t_db_hash_seq.c revision 313498
1/* $NetBSD: t_db_hash_seq.c,v 1.2 2015/06/22 22:35:51 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31#include <sys/cdefs.h> 32__RCSID("$NetBSD: t_db_hash_seq.c,v 1.2 2015/06/22 22:35:51 christos Exp $"); 33 34#include <sys/types.h> 35#include <sys/socket.h> 36#include <db.h> 37#include <stdio.h> 38#include <string.h> 39#include <errno.h> 40#include <stdlib.h> 41#include <fcntl.h> 42#include <syslog.h> 43#include <netinet/in.h> 44 45#define ATF 46 47struct conf { 48 struct sockaddr_storage c_ss; 49 int c_lmask; 50 int c_port; 51 int c_proto; 52 int c_family; 53 int c_uid; 54 int c_nfail; 55 char c_name[128]; 56 int c_rmask; 57 int c_duration; 58}; 59 60struct dbinfo { 61 int count; 62 time_t last; 63 char id[64]; 64}; 65 66#ifdef ATF 67#include <atf-c.h> 68 69#define DO_ERR(msg, ...) ATF_REQUIRE_MSG(0, msg, __VA_ARGS__) 70#define DO_WARNX(msg, ...) ATF_REQUIRE_MSG(0, msg, __VA_ARGS__) 71#else 72#include <err.h> 73 74#define DO_ERR(fmt, ...) err(EXIT_FAILURE, fmt, __VA_ARGS__) 75#define DO_WARNX(fmt, ...) warnx(fmt, __VA_ARGS__) 76#endif 77 78#define DO_DEBUG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) 79 80static HASHINFO openinfo = { 81 4096, /* bsize */ 82 32, /* ffactor */ 83 256, /* nelem */ 84 8 * 1024 * 1024,/* cachesize */ 85 NULL, /* hash() */ 86 0 /* lorder */ 87}; 88 89static int debug = 0; 90 91static int 92state_close(DB *db) 93{ 94 if (db == NULL) 95 return -1; 96 if ((*db->close)(db) == -1) 97 DO_ERR("%s: can't close db", __func__); 98 return 0; 99} 100 101static DB * 102state_open(const char *dbname, int flags, mode_t perm) 103{ 104 DB *db; 105 106 db = dbopen(dbname, flags, perm, DB_HASH, &openinfo); 107 if (db == NULL) { 108 if (errno == ENOENT && (flags & O_CREAT) == 0) 109 return NULL; 110 DO_ERR("%s: can't open `%s'", __func__, dbname); 111 } 112 return db; 113} 114 115static int 116state_sizecheck(const DBT *t) 117{ 118 if (sizeof(struct conf) == t->size) 119 return 0; 120 DO_WARNX("Key size mismatch %zu != %zu", sizeof(struct conf), t->size); 121 return 0; 122} 123 124static int 125state_del(DB *db, const struct conf *c) 126{ 127 int rv; 128 DBT k; 129 130 if (db == NULL) 131 return -1; 132 133 k.data = __UNCONST(c); 134 k.size = sizeof(*c); 135 136 switch (rv = (*db->del)(db, &k, 1)) { 137 case 0: 138 case 1: 139 if (debug > 1) { 140 DO_DEBUG("%s: returns %d", __func__, rv); 141 (*db->sync)(db, 0); 142 } 143 return 0; 144 default: 145 DO_ERR("%s: failed", __func__); 146 return -1; 147 } 148} 149 150#if 0 151static int 152state_get(DB *db, const struct conf *c, struct dbinfo *dbi) 153{ 154 int rv; 155 DBT k, v; 156 157 if (db == NULL) 158 return -1; 159 160 k.data = __UNCONST(c); 161 k.size = sizeof(*c); 162 163 switch (rv = (*db->get)(db, &k, &v, 0)) { 164 case 0: 165 case 1: 166 if (rv) 167 memset(dbi, 0, sizeof(*dbi)); 168 else 169 memcpy(dbi, v.data, sizeof(*dbi)); 170 if (debug > 1) 171 DO_DEBUG("%s: returns %d", __func__, rv); 172 return 0; 173 default: 174 DO_ERR("%s: failed", __func__); 175 return -1; 176 } 177} 178#endif 179 180static int 181state_put(DB *db, const struct conf *c, const struct dbinfo *dbi) 182{ 183 int rv; 184 DBT k, v; 185 186 if (db == NULL) 187 return -1; 188 189 k.data = __UNCONST(c); 190 k.size = sizeof(*c); 191 v.data = __UNCONST(dbi); 192 v.size = sizeof(*dbi); 193 194 switch (rv = (*db->put)(db, &k, &v, 0)) { 195 case 0: 196 if (debug > 1) { 197 DO_DEBUG("%s: returns %d", __func__, rv); 198 (*db->sync)(db, 0); 199 } 200 return 0; 201 case 1: 202 errno = EEXIST; 203 /*FALLTHROUGH*/ 204 default: 205 DO_ERR("%s: failed", __func__); 206 } 207} 208 209static int 210state_iterate(DB *db, struct conf *c, struct dbinfo *dbi, unsigned int first) 211{ 212 int rv; 213 DBT k, v; 214 215 if (db == NULL) 216 return -1; 217 218 first = first ? R_FIRST : R_NEXT; 219 220 switch (rv = (*db->seq)(db, &k, &v, first)) { 221 case 0: 222 if (state_sizecheck(&k) == -1) 223 return -1; 224 memcpy(c, k.data, sizeof(*c)); 225 memcpy(dbi, v.data, sizeof(*dbi)); 226 if (debug > 1) 227 DO_DEBUG("%s: returns %d", __func__, rv); 228 return 1; 229 case 1: 230 if (debug > 1) 231 DO_DEBUG("%s: returns %d", __func__, rv); 232 return 0; 233 default: 234 DO_ERR("%s: failed", __func__); 235 return -1; 236 } 237} 238 239#define MAXB 100 240 241static int 242testdb(int skip) 243{ 244 size_t i; 245 int f; 246 char flag[MAXB]; 247 DB *db; 248 struct conf c; 249 struct dbinfo d; 250 251 db = state_open(NULL, O_RDWR|O_CREAT|O_TRUNC, 0600); 252 if (db == NULL) 253 DO_ERR("%s: cannot open `%s'", __func__, "foo"); 254 255 memset(&c, 0, sizeof(c)); 256 memset(&d, 0, sizeof(d)); 257 memset(flag, 0, sizeof(flag)); 258 259 for (i = 0; i < __arraycount(flag); i++) { 260 c.c_port = i; 261 state_put(db, &c, &d); 262 } 263 264 for (f = 1, i = 0; state_iterate(db, &c, &d, f) == 1; f = 0, i++) { 265 if (debug > 1) 266 DO_DEBUG("%zu %d\n", i, c.c_port); 267 if (flag[c.c_port]) 268 DO_WARNX("Already visited %d", c.c_port); 269 flag[c.c_port] = 1; 270 if (skip == 0 || c.c_port % skip != 0) 271 continue; 272 state_del(db, &c); 273 } 274 state_close(db); 275 for (i = 0; i < __arraycount(flag); i++) { 276 if (flag[i] == 0) 277 DO_WARNX("Not visited %zu", i); 278 } 279 return 0; 280} 281 282#ifndef ATF 283int 284main(int argc, char *argv[]) 285{ 286 return testdb(6); 287} 288#else 289 290ATF_TC(test_hash_del_none); 291ATF_TC_HEAD(test_hash_del_none, tc) 292{ 293 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables deleting none"); 294} 295 296ATF_TC_BODY(test_hash_del_none, tc) 297{ 298 testdb(0); 299} 300 301ATF_TC(test_hash_del_all); 302ATF_TC_HEAD(test_hash_del_all, tc) 303{ 304 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables deleting all"); 305} 306 307ATF_TC_BODY(test_hash_del_all, tc) 308{ 309 testdb(1); 310} 311 312ATF_TC(test_hash_del_alt); 313ATF_TC_HEAD(test_hash_del_alt, tc) 314{ 315 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables alternating deletets"); 316} 317 318ATF_TC_BODY(test_hash_del_alt, tc) 319{ 320 testdb(2); 321} 322 323ATF_TC(test_hash_del_every_7); 324ATF_TC_HEAD(test_hash_del_every_7, tc) 325{ 326 atf_tc_set_md_var(tc, "descr", "Check sequential scan of hash tables deleting every 7 elements"); 327} 328 329ATF_TC_BODY(test_hash_del_every_7, tc) 330{ 331 testdb(7); 332} 333 334ATF_TP_ADD_TCS(tp) 335{ 336 ATF_TP_ADD_TC(tp, test_hash_del_none); 337 ATF_TP_ADD_TC(tp, test_hash_del_all); 338 ATF_TP_ADD_TC(tp, test_hash_del_alt); 339 ATF_TP_ADD_TC(tp, test_hash_del_every_7); 340 341 return 0; 342} 343#endif 344