~ubuntu-branches/ubuntu/edgy/syslog-ng/edgy

« back to all changes in this revision

Viewing changes to src/nscache.c

  • Committer: Bazaar Package Importer
  • Author(s): SZALAY Attila
  • Date: 2002-03-04 21:29:11 UTC
  • Revision ID: james.westby@ubuntu.com-20020304212911-zmhvv15v8dmigez1
Tags: upstream-1.5.15
Import upstream version 1.5.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *
 
3
 * Copyright (c) 2001 BalaBit IT Ltd.
 
4
 * 
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
18
 *
 
19
 * Inspired by nsyslog, originally written by Darren Reed.
 
20
 *
 
21
 * $Id: nscache.c,v 1.4 2001/05/14 09:07:25 bazsi Exp $
 
22
 *
 
23
 ***************************************************************************/
 
24
 
 
25
/*
 
26
 * Copyright (c) 2001 Ga�l Roualland <gael.roualland@iname.com>
 
27
 * All rights reserved.
 
28
 *
 
29
 * Redistribution and use in source and binary forms, with or without
 
30
 * modification, are permitted provided that the following conditions
 
31
 * are met:
 
32
 * 1. Redistributions of source code must retain the above copyright
 
33
 *    notice, this list of conditions and the following disclaimer.
 
34
 * 2. Redistributions in binary form must reproduce the above copyright
 
35
 *    notice, this list of conditions and the following disclaimer in the
 
36
 *    documentation and/or other materials provided with the distribution.
 
37
 * 3. Neither the name of the author nor the names of its contributors
 
38
 *    may be used to endorse or promote products derived from this software
 
39
 *    without specific prior written permission.
 
40
 *
 
41
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS'' AND
 
42
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
44
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 
45
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
46
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
47
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
49
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
50
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
51
 * SUCH DAMAGE.
 
52
 */
 
53
 
 
54
#include <netdb.h>
 
55
#include <netinet/in.h>
 
56
#include <arpa/inet.h>
 
57
#include <stdio.h>
 
58
#include <stdlib.h>
 
59
#include <string.h>
 
60
#include <time.h>
 
61
#include <sys/socket.h>
 
62
#include "nscache.h"
 
63
 
 
64
/* Simple NS cache, using a flat hash table (NOT thread safe).
 
65
 * This is designed to be used with a fixed set of ip adresses.
 
66
 * Inspired from similar caches in ippl, iplog...
 
67
 *
 
68
 * The size of the cache must be a primary number for good
 
69
 * performance and somewhat larger than the maximum number
 
70
 * of estimated entries. If more entries than available in the
 
71
 * cache are used at the same time it will perform very poorly.
 
72
 */
 
73
 
 
74
struct nsentry {
 
75
        struct in_addr addr;
 
76
        char * name;
 
77
        time_t used;
 
78
        time_t expire;
 
79
};
 
80
 
 
81
struct nscache {
 
82
        int size;
 
83
        int expire;
 
84
        int expire_failed;
 
85
        struct nsentry * entries;
 
86
#ifdef NSCACHE_DEBUG
 
87
        int hits, misses;
 
88
#endif  
 
89
};
 
90
 
 
91
struct nscache *nscache_new(int size, int expire, int expire_failed) 
 
92
{
 
93
        struct nscache * cache;
 
94
        int i;
 
95
 
 
96
        if ((cache = malloc(sizeof(struct nscache))) == NULL)
 
97
                return NULL;
 
98
        
 
99
        /* check args for reasonnable values
 
100
           0 for expire_failed means not to cache failures */
 
101
        cache->size = (size < 10) ? 10 : size;
 
102
        cache->expire = (expire < 10) ? 10 : expire;
 
103
        cache->expire_failed = (expire_failed < 0) ? 0 : expire_failed;
 
104
 
 
105
        if ((cache->entries =
 
106
             malloc(cache->size * sizeof(struct nsentry))) == NULL) {
 
107
                free(cache);
 
108
                return NULL;
 
109
        }
 
110
 
 
111
        for (i = 0; i < cache->size; i++) {
 
112
                cache->entries[i].addr.s_addr = 0;
 
113
                cache->entries[i].name = NULL;
 
114
                cache->entries[i].expire = 0;
 
115
                cache->entries[i].used = 0;
 
116
        }
 
117
 
 
118
#ifdef NSCACHE_DEBUG
 
119
        fprintf(stderr, "initialising nscache: %d entries, %d/%d expiration.\n",
 
120
                cache->size, cache->expire, cache->expire_failed);
 
121
        cache->hits = cache->misses = 0;
 
122
#endif
 
123
 
 
124
        return cache;
 
125
}
 
126
 
 
127
void nscache_free(struct nscache * cache) 
 
128
{
 
129
        int i;
 
130
 
 
131
        if (cache == NULL)
 
132
                return;
 
133
 
 
134
        if (cache->entries == NULL) {
 
135
                free(cache);
 
136
                return;
 
137
        }
 
138
 
 
139
#ifdef NSCACHE_DEBUG
 
140
        fprintf(stderr, "destroying nscache: %d entries, %d hits, %d misses.\n",
 
141
                cache->size, cache->hits, cache->misses);
 
142
#endif
 
143
        
 
144
        for (i = 0; i < cache->size; i++) {
 
145
                if (cache->entries[i].name != NULL)
 
146
                        free(cache->entries[i].name);
 
147
        }
 
148
 
 
149
        free(cache->entries);
 
150
        free(cache);
 
151
}
 
152
 
 
153
static char *nsresolve(struct in_addr addr) 
 
154
{
 
155
        struct hostent *host;
 
156
 
 
157
        if ((host = gethostbyaddr((char *) &addr,
 
158
                                  sizeof(struct in_addr),
 
159
                                  AF_INET)) != NULL &&
 
160
            host->h_name != NULL)
 
161
                return host->h_name;
 
162
        return NULL;
 
163
}
 
164
 
 
165
char *nscache_lookup(struct nscache * cache, struct in_addr in) 
 
166
{
 
167
        int h, k, old, new;
 
168
#ifdef NSCACHE_DEBUG
 
169
        int iter = 1;
 
170
#endif  
 
171
        time_t now = time(NULL);
 
172
        time_t oldest = now + 1;
 
173
        char *host;
 
174
 
 
175
        if (cache == NULL || cache->entries == NULL) /* be safe.. */
 
176
                return nsresolve(in);
 
177
 
 
178
        k = h = ntohl(in.s_addr) % (cache->size - 1) + 1;
 
179
        old = new = -1;
 
180
  
 
181
        do {
 
182
                if (cache->entries[k].expire > 0 &&
 
183
                    cache->entries[k].addr.s_addr == in.s_addr) { /* found it! */
 
184
                        if (now > cache->entries[k].expire) {
 
185
                                /* entry has expired, update it */
 
186
#ifdef NSCACHE_DEBUG
 
187
                                fprintf(stderr, "%s... updating entry %d (%d > %d).\n",
 
188
                                        inet_ntoa(in), k, (int) now,
 
189
                                        (int) cache->entries[k].expire);
 
190
#endif
 
191
                                new = k;
 
192
                                break;
 
193
                        }
 
194
#ifdef NSCACHE_DEBUG
 
195
                        fprintf(stderr, "%s... found on %d: %s (%d iters, %d/%d)\n",
 
196
                                inet_ntoa(in), k, cache->entries[k].name,
 
197
                                iter, (int) now, (int) cache->entries[k].expire);
 
198
                        cache->hits++;
 
199
#endif  
 
200
                        cache->entries[k].used = now;
 
201
                        return cache->entries[k].name;
 
202
                }
 
203
                if (new < 0) { /* no empty entries found yet */
 
204
                        if (cache->entries[k].expire < now) {
 
205
                                new = k; /* use this to save new entry if not found */
 
206
                                if (cache->entries[k].expire < 1)
 
207
                                        break; /* never used */
 
208
                        } else 
 
209
                                if (cache->entries[k].used < oldest) {
 
210
                                        old = k;
 
211
                                        oldest = cache->entries[k].used;
 
212
                                }
 
213
                }
 
214
                k = (h + k) % cache->size;
 
215
#ifdef NSCACHE_DEBUG
 
216
                iter++;
 
217
#endif  
 
218
        } while (k > 0);
 
219
        
 
220
        if (new < 0) { /* no place to save ? use oldest. */
 
221
                if (old < 0)
 
222
                        old = 0; /* shouldn't happen.. */
 
223
#ifdef NSCACHE_DEBUG
 
224
                fprintf(stderr, "%s... old entry %d will be replaced.\n",
 
225
                        inet_ntoa(cache->entries[old].addr), old);
 
226
#endif  
 
227
                new = old;
 
228
        }
 
229
#ifdef NSCACHE_DEBUG
 
230
        fprintf(stderr, "%s... adding as %d (%d iters).\n",
 
231
                inet_ntoa(in), new, iter);
 
232
        cache->misses++;
 
233
#endif  
 
234
        if (cache->entries[new].name != NULL)
 
235
                free (cache->entries[new].name);
 
236
        if ((host = nsresolve(in)) != NULL) {
 
237
                cache->entries[new].name = strdup(host);
 
238
                cache->entries[new].expire =
 
239
                        now + cache->expire;
 
240
        } else {
 
241
                cache->entries[new].name = NULL;
 
242
                cache->entries[new].expire =
 
243
                        now + cache->expire_failed;
 
244
        }
 
245
        cache->entries[new].addr.s_addr = in.s_addr;
 
246
        return cache->entries[new].name;
 
247
}
 
248
 
 
249
#ifdef NSCACHE_DEBUG
 
250
void nscache_dump(struct nscache * cache) 
 
251
{
 
252
        int i;
 
253
        
 
254
        fprintf(stderr, "nscache contents:\n");
 
255
        for (i = 0; i < cache->size; i++) {
 
256
                if (cache->entries[i].used > 0)
 
257
                        fprintf(stderr, "  %5d  %-16s %09d/%09d  %s\n",
 
258
                                i, inet_ntoa(cache->entries[i].addr),
 
259
                                (int) cache->entries[i].used,
 
260
                                (int) cache->entries[i].expire,
 
261
                                cache->entries[i].name);
 
262
        }
 
263
}
 
264
#endif