1/* Copyright (c) 2014, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#if !defined(_POSIX_C_SOURCE)
16#define _POSIX_C_SOURCE 201410L
17#endif
18
19#include <openssl/crypto.h>
20#include <openssl/lhash.h>
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26struct dummy_lhash_node {
27  char *s;
28  struct dummy_lhash_node *next;
29};
30
31struct dummy_lhash {
32  struct dummy_lhash_node *head;
33};
34
35static void dummy_lh_free(struct dummy_lhash *lh) {
36  struct dummy_lhash_node *cur, *next;
37
38  for (cur = lh->head; cur != NULL; cur = next) {
39    next = cur->next;
40    free(cur->s);
41    free(cur);
42  }
43}
44
45static size_t dummy_lh_num_items(const struct dummy_lhash *lh) {
46  size_t count = 0;
47  struct dummy_lhash_node *cur;
48
49  for (cur = lh->head; cur != NULL; cur = cur->next) {
50    count++;
51  }
52
53  return count;
54}
55
56static char *dummy_lh_retrieve(struct dummy_lhash *lh, const char *s) {
57  struct dummy_lhash_node *cur;
58
59  for (cur = lh->head; cur != NULL; cur = cur->next) {
60    if (strcmp(cur->s, s) == 0) {
61      return cur->s;
62    }
63  }
64
65  return NULL;
66}
67
68static int dummy_lh_insert(struct dummy_lhash *lh, char **old_data, char *s) {
69  struct dummy_lhash_node *node, *cur;
70
71  for (cur = lh->head; cur != NULL; cur = cur->next) {
72    if (strcmp(cur->s, s) == 0) {
73      *old_data = cur->s;
74      cur->s = s;
75      return 1;
76    }
77  }
78
79  node = malloc(sizeof(struct dummy_lhash_node));
80  *old_data = NULL;
81  node->s = s;
82  node->next = lh->head;
83  lh->head = node;
84  return 1;
85}
86
87static char *dummy_lh_delete(struct dummy_lhash *lh, const void *s) {
88  struct dummy_lhash_node *cur, **next_ptr;
89  char *ret;
90
91  next_ptr = &lh->head;
92  for (cur = lh->head; cur != NULL; cur = cur->next) {
93    if (strcmp(cur->s, s) == 0) {
94      ret = cur->s;
95      *next_ptr = cur->next;
96      free(cur);
97      return ret;
98    }
99    next_ptr = &cur->next;
100  }
101
102  return NULL;
103}
104
105static char *rand_string(void) {
106  unsigned len = 1 + (rand() % 3);
107  char *ret = malloc(len + 1);
108  unsigned i;
109
110  for (i = 0; i < len; i++) {
111    ret[i] = '0' + (rand() & 7);
112  }
113  ret[i] = 0;
114
115  return ret;
116}
117
118int main(int argc, char **argv) {
119  _LHASH *lh;
120  struct dummy_lhash dummy_lh = {NULL};
121  unsigned i;
122
123  CRYPTO_library_init();
124
125  lh = lh_new(NULL, NULL);
126  if (lh == NULL) {
127    return 1;
128  }
129
130  for (i = 0; i < 100000; i++) {
131    unsigned action;
132    char *s, *s1, *s2;
133
134    if (dummy_lh_num_items(&dummy_lh) != lh_num_items(lh)) {
135      fprintf(stderr, "Length mismatch\n");
136      return 1;
137    }
138
139    action = rand() % 3;
140    switch (action) {
141      case 0:
142        s = rand_string();
143        s1 = (char *)lh_retrieve(lh, s);
144        s2 = dummy_lh_retrieve(&dummy_lh, s);
145        if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) {
146          fprintf(stderr, "lh_retrieve failure\n");
147          abort();
148        }
149        free(s);
150        break;
151
152      case 1:
153        s = rand_string();
154        lh_insert(lh, (void **)&s1, s);
155        dummy_lh_insert(&dummy_lh, &s2, strdup(s));
156
157        if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) {
158          fprintf(stderr, "lh_insert failure\n");
159          abort();
160        }
161
162        if (s1) {
163          free(s1);
164        }
165        if (s2) {
166          free(s2);
167        }
168        break;
169
170      case 2:
171        s = rand_string();
172        s1 = lh_delete(lh, s);
173        s2 = dummy_lh_delete(&dummy_lh, s);
174
175        if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) {
176          fprintf(stderr, "lh_insert failure\n");
177          abort();
178        }
179
180        if (s1) {
181          free(s1);
182        }
183        if (s2) {
184          free(s2);
185        }
186        free(s);
187        break;
188
189      default:
190        abort();
191    }
192  }
193
194  lh_doall(lh, free);
195  lh_free(lh);
196  dummy_lh_free(&dummy_lh);
197  printf("PASS\n");
198  return 0;
199}
200