~ubuntu-branches/ubuntu/precise/pdnsd/precise

« back to all changes in this revision

Viewing changes to .pc/05_fix_spelling.patch/src/servers.c

  • Committer: Bazaar Package Importer
  • Author(s): Mahyuddin Susanto
  • Date: 2011-03-09 18:54:22 UTC
  • mfrom: (1.3.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20110309185422-33hwmg565m18dpu4
Tags: 1.2.8-par-1
* New Maintainer. (Closes: #596302)
* New Upstream Releases. (Closes: #596302, LP: #712938)
* debian/patches/05_fix_spelling.patch: Fix spelling errors.
* debian/patches/04_ipv6_localhost.patch. Adding ipv6 in localhost.
  (Closes: #466332, #504211)
* debian/init.d:
  - Add init status. (Closes: #476538)
  - Don't says starting pdnsd if already started. (Closes: #487467)
* deban/changelog: Fix incorrect date in 1.2.7-par-1 (Closes: #527352)
* debian/control:
  - Add Vcs-Browser and Vcs-Git to alioth.
  - Bump Standards-Version to 3.9.1.
* debian/copyright: Updated as per DEP-5 specification.
* debian/pdnsd-recurse.conf:
  - Adding recurse mode. (Closes: #602262)
  - Fixing recursive neg section. (Closes: #519656)
* doc/pdnsd.conf.in: Separate ip address by new line. Thanks to
  Raphael Geissert. (Closes: #597734)
* perm_cache size set to default. (Closes: #602329)
  - doc/pdnsd.conf.in
  - debian/pdnsd.conf
  - debian/pdnsd-recurse.conf
  - debian/pdnsd-resolvconf.conf
* debian/002_NetMan_pdnsd: add compabilty with WiFi. 
  (Closes: #617373, LP: #452351)
* Ack'd NMU upload. (Closes: #548173)
* Update debconf Indonesian translations. (Closes: #610148)
* Switch to quilt system.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* servers.c - manage a set of dns servers
 
2
 
 
3
   Copyright (C) 2000, 2001 Thomas Moestl
 
4
   Copyright (C) 2002, 2003, 2005, 2007, 2009 Paul A. Rombouts
 
5
 
 
6
  This file is part of the pdnsd package.
 
7
 
 
8
  pdnsd is free software; you can redistribute it and/or modify
 
9
  it under the terms of the GNU General Public License as published by
 
10
  the Free Software Foundation; either version 3 of the License, or
 
11
  (at your option) any later version.
 
12
 
 
13
  pdnsd is distributed in the hope that it will be useful,
 
14
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
  GNU General Public License for more details.
 
17
 
 
18
  You should have received a copy of the GNU General Public License
 
19
  along with pdnsd; see the file COPYING. If not, see
 
20
  <http://www.gnu.org/licenses/>.
 
21
*/
 
22
 
 
23
#include <config.h>
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <time.h>
 
27
#include <pthread.h>
 
28
#include <unistd.h>
 
29
#include <sys/types.h>
 
30
#include <sys/time.h>
 
31
#include <sys/resource.h>
 
32
#include <sys/wait.h>
 
33
#include <string.h>
 
34
#include <errno.h>
 
35
#include <signal.h>
 
36
#include <sys/stat.h>
 
37
#include <fcntl.h>
 
38
#include <fnmatch.h>
 
39
#include <string.h>
 
40
#include "thread.h"
 
41
#include "error.h"
 
42
#include "servers.h"
 
43
#include "conff.h"
 
44
#include "consts.h"
 
45
#include "icmp.h"
 
46
#include "netdev.h"
 
47
#include "helpers.h"
 
48
#include "dns_query.h"
 
49
 
 
50
#if !defined(lint) && !defined(NO_RCSIDS)
 
51
static char rcsid[]="$Id: servers.c,v 1.19 2002/07/19 21:14:19 tmm Exp $";
 
52
#endif
 
53
 
 
54
/*
 
55
 * We may be a little over-strict with locks here. Never mind...
 
56
 * Also, there may be some code-redundancy regarding uptests. It saves some locks, though.
 
57
 */
 
58
 
 
59
static pthread_mutex_t servers_lock = PTHREAD_MUTEX_INITIALIZER;
 
60
static pthread_cond_t server_data_cond = PTHREAD_COND_INITIALIZER;
 
61
static pthread_cond_t server_test_cond = PTHREAD_COND_INITIALIZER;
 
62
static int server_data_users = 0, server_status_ping = 0;
 
63
/* Used to notify the server status thread that it should discontinue uptests. */
 
64
volatile int signal_interrupt=0;
 
65
#define statusintsig SIGHUP
 
66
 
 
67
static short retest_flag=0;
 
68
 
 
69
static char schm[32];
 
70
 
 
71
static void sigint_handler(int signum);
 
72
 
 
73
/*
 
74
 * Execute an individual uptest. Call with locks applied 
 
75
 */
 
76
static int uptest (servparm_t *serv, int j)
 
77
{
 
78
        int ret=0, count_running_ping=0;
 
79
        pdnsd_a *s_addr= PDNSD_A2_TO_A(&DA_INDEX(serv->atup_a,j).a);
 
80
 
 
81
        DEBUG_PDNSDA_MSG("performing uptest (type=%s) for %s\n",const_name(serv->uptest),PDNSDA2STR(s_addr));
 
82
 
 
83
        /* Unlock the mutex because some of the tests may take a while. */
 
84
        ++server_data_users;
 
85
        if((serv->uptest==C_PING || serv->uptest==C_QUERY) && pthread_equal(pthread_self(),servstat_thrid)) {
 
86
                /* Inform other threads that a ping is in progress. */
 
87
                count_running_ping=1;
 
88
                ++server_status_ping;
 
89
        }
 
90
        pthread_mutex_unlock(&servers_lock);
 
91
 
 
92
        switch (serv->uptest) {
 
93
        case C_NONE:
 
94
                /* Don't change */
 
95
                ret=DA_INDEX(serv->atup_a,j).is_up;
 
96
                break;
 
97
        case C_PING:
 
98
                ret=ping(is_inaddr_any(&serv->ping_a) ? s_addr : &serv->ping_a, serv->ping_timeout,PINGREPEAT)!=-1;
 
99
                break;
 
100
        case C_IF:
 
101
        case C_DEV:
 
102
        case C_DIALD:
 
103
                ret=if_up(serv->interface);
 
104
#if (TARGET==TARGET_LINUX)
 
105
                if (ret!=0) {
 
106
                        if(serv->uptest==C_DEV)
 
107
                                ret=dev_up(serv->interface,serv->device);
 
108
                        else if (serv->uptest==C_DIALD)
 
109
                                ret=dev_up("diald",serv->device);
 
110
                }
 
111
#endif
 
112
                break;
 
113
        case C_EXEC: {
 
114
                pid_t pid;
 
115
 
 
116
                if ((pid=fork())==-1) {
 
117
                        DEBUG_MSG("Could not fork to perform exec uptest: %s\n",strerror(errno));
 
118
                        break;
 
119
                } else if (pid==0) { /* child */
 
120
                        /*
 
121
                         * If we ran as setuid or setgid, do not inherit this to the
 
122
                         * command. This is just a last guard. Running pdnsd as setuid()
 
123
                         * or setgid() is a no-no.
 
124
                         */
 
125
                        if (setgid(getgid()) == -1 || setuid(getuid()) == -1) {
 
126
                                log_error("Could not reset uid or gid: %s",strerror(errno));
 
127
                                _exit(1);
 
128
                        }
 
129
                        /* Try to setuid() to a different user as specified. Good when you
 
130
                           don't want the test command to run as root */
 
131
                        if (!run_as(serv->uptest_usr)) {
 
132
                                _exit(1);
 
133
                        }
 
134
                        {
 
135
                            struct rlimit rl; int i;
 
136
                            /*
 
137
                             * Mark all open fd's FD_CLOEXEC for paranoia reasons.
 
138
                             */
 
139
                            if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
 
140
                                    log_error("getrlimit() failed: %s",strerror(errno));
 
141
                                    _exit(1);
 
142
                            }
 
143
                            for (i = 0; i < rl.rlim_max; i++) {
 
144
                                    if (fcntl(i, F_SETFD, FD_CLOEXEC) == -1 && errno != EBADF) {
 
145
                                            log_error("fcntl(F_SETFD) failed: %s",strerror(errno));
 
146
                                            _exit(1);
 
147
                                    }
 
148
                            }
 
149
                        }
 
150
                        execl("/bin/sh", "uptest_sh","-c",serv->uptest_cmd,(char *)NULL);
 
151
                        _exit(1); /* failed execl */
 
152
                } else { /* parent */
 
153
                        int status;
 
154
                        pid_t wpid = waitpid(pid,&status,0);
 
155
                        if (wpid==pid) {
 
156
                                if(WIFEXITED(status)) {
 
157
                                        int exitstatus=WEXITSTATUS(status);
 
158
                                        DEBUG_MSG("uptest command \"%s\" exited with status %d\n",
 
159
                                                  serv->uptest_cmd, exitstatus);
 
160
                                        ret=(exitstatus==0);
 
161
                                }
 
162
#if DEBUG>0
 
163
                                else if(WIFSIGNALED(status)) {
 
164
                                        DEBUG_MSG("uptest command \"%s\" was terminated by signal %d\n",
 
165
                                                  serv->uptest_cmd, WTERMSIG(status));
 
166
                                }
 
167
                                else {
 
168
                                        DEBUG_MSG("status of uptest command \"%s\" is of unkown type (0x%x)\n",
 
169
                                                  serv->uptest_cmd, status);
 
170
                                }
 
171
#endif
 
172
                        }
 
173
#if DEBUG>0
 
174
                        else if (wpid==-1) {
 
175
                                DEBUG_MSG("Error while waiting for uptest command \"%s\" to terminate: "
 
176
                                          "waitpid for pid %d failed: %s\n",
 
177
                                          serv->uptest_cmd, pid, strerror(errno));
 
178
                        }
 
179
                        else {
 
180
                                DEBUG_MSG("Error while waiting for uptest command \"%s\" to terminate: "
 
181
                                          "waitpid returned %d, expected pid %d\n",
 
182
                                          serv->uptest_cmd, wpid, pid);
 
183
                        }
 
184
#endif
 
185
                }
 
186
        }
 
187
                break;
 
188
        case C_QUERY:
 
189
                ret=query_uptest(s_addr, serv->port,
 
190
                                 serv->timeout>=global.timeout?serv->timeout:global.timeout,
 
191
                                 PINGREPEAT);
 
192
        } /* end of switch */
 
193
 
 
194
        pthread_mutex_lock(&servers_lock);
 
195
        if(count_running_ping)
 
196
                --server_status_ping;
 
197
        PDNSD_ASSERT(server_data_users>0, "server_data_users non-positive before attempt to decrement it");
 
198
        if (--server_data_users==0) pthread_cond_broadcast(&server_data_cond);
 
199
 
 
200
        DEBUG_PDNSDA_MSG("result of uptest for %s: %s\n",
 
201
                         PDNSDA2STR(s_addr),
 
202
                         ret?"OK":"failed");
 
203
        return ret;
 
204
}
 
205
 
 
206
static int scheme_ok(servparm_t *serv)
 
207
{
 
208
        if (serv->scheme[0]) {
 
209
                if (!schm[0]) {
 
210
                        ssize_t nschm;
 
211
                        int sc = open(global.scheme_file, O_RDONLY);
 
212
                        char *s;
 
213
                        if (sc<0) 
 
214
                                return 0;
 
215
                        nschm = read(sc, schm, sizeof(schm)-1);
 
216
                        close(sc);
 
217
                        if (nschm < 0) 
 
218
                                return 0;
 
219
                        schm[nschm] = '\0';
 
220
                        s = strchr(schm, '\n');
 
221
                        if (s) 
 
222
                                *s='\0';
 
223
                }
 
224
                if (fnmatch(serv->scheme, schm, 0))
 
225
                        return 0;
 
226
        }
 
227
        return 1;
 
228
}
 
229
 
 
230
/* Internal server test. Call with locks applied.
 
231
   May test a single server ip or several collectively.
 
232
 */
 
233
static void retest(int i, int j)
 
234
{
 
235
  time_t s_ts;
 
236
  servparm_t *srv=&DA_INDEX(servers,i);
 
237
  int nsrvs=DA_NEL(srv->atup_a);
 
238
 
 
239
  if(!nsrvs) return;
 
240
  if(j>=0) {
 
241
    if(j<nsrvs) nsrvs=j+1;  /* test just one */
 
242
  }
 
243
  else {
 
244
    j=0;        /* test a range of servers */
 
245
  }
 
246
 
 
247
  if(!scheme_ok(srv)) {
 
248
    s_ts=time(NULL);
 
249
 
 
250
    for(;j<nsrvs;++j) {
 
251
      atup_t *at=&DA_INDEX(srv->atup_a,j);
 
252
      at->is_up=0;
 
253
      at->i_ts=s_ts;
 
254
    }
 
255
  }
 
256
  else if(srv->uptest==C_NONE) {
 
257
    s_ts=time(NULL);
 
258
 
 
259
    for(;j<nsrvs;++j) {
 
260
        DA_INDEX(srv->atup_a,j).i_ts=s_ts;
 
261
    }
 
262
  }
 
263
  else if(srv->uptest==C_QUERY || (srv->uptest==C_PING && is_inaddr_any(&srv->ping_a))) {  /* test each ip address separately */
 
264
    for(;j<nsrvs;++j) {
 
265
        atup_t *at=&DA_INDEX(srv->atup_a,j);
 
266
        s_ts=time(NULL);
 
267
        at->is_up=uptest(srv,j);
 
268
        if(signal_interrupt)
 
269
          break;
 
270
        at->i_ts=s_ts;
 
271
    }
 
272
  }
 
273
  else {  /* test ip addresses collectively */
 
274
    int res;
 
275
 
 
276
    s_ts=time(NULL);
 
277
    res=uptest(srv,j);
 
278
    for(;j<nsrvs;++j) {
 
279
      atup_t *at=&DA_INDEX(srv->atup_a,j);
 
280
      at->is_up=res;
 
281
      if(signal_interrupt && srv->uptest==C_PING)
 
282
        continue;
 
283
      at->i_ts=s_ts;
 
284
    }
 
285
  }
 
286
}
 
287
 
 
288
 
 
289
/* This is called by the server status thread to discover the addresses of root servers.
 
290
   Call with server_lock applied.
 
291
*/
 
292
static addr2_array resolv_rootserver_addrs(atup_array a, int port, time_t timeout)
 
293
{
 
294
        addr2_array retval=NULL;
 
295
 
 
296
        /* Unlock the mutex because this may take a while. */
 
297
        ++server_data_users;
 
298
        pthread_mutex_unlock(&servers_lock);
 
299
 
 
300
        retval= dns_rootserver_resolv(a,port,timeout);
 
301
 
 
302
        pthread_mutex_lock(&servers_lock);
 
303
        PDNSD_ASSERT(server_data_users>0, "server_data_users non-positive before attempt to decrement it");
 
304
        if (--server_data_users==0) pthread_cond_broadcast(&server_data_cond);
 
305
 
 
306
        return retval;  
 
307
}
 
308
 
 
309
/*
 
310
 * Refresh the server status by pinging or testing the interface in the given interval.
 
311
 * Note that you may get inaccuracies in the dimension of the ping timeout or the runtime
 
312
 * of your uptest command if you have uptest=ping or uptest=exec for at least one server.
 
313
 * This happens when all the uptests for the first n servers take more time than the inteval
 
314
 * of n+1 (or 0 when n+1>servnum). I do not think that these delays are critical, so I did
 
315
 * not to anything about that (because that may also be costly).
 
316
 */
 
317
void *servstat_thread(void *p)
 
318
{
 
319
        struct sigaction action;
 
320
        int keep_testing;
 
321
 
 
322
        /* (void)p; */  /* To inhibit "unused variable" warning */
 
323
 
 
324
        THREAD_SIGINIT;
 
325
 
 
326
        pthread_mutex_lock(&servers_lock);
 
327
        /* servstat_thrid=pthread_self(); */
 
328
 
 
329
        signal_interrupt=0;
 
330
        action.sa_handler = sigint_handler;
 
331
        sigemptyset(&action.sa_mask);
 
332
        action.sa_flags = 0;
 
333
        if(sigaction(statusintsig, &action, NULL) == 0) {
 
334
                sigset_t smask;
 
335
                sigemptyset(&smask);
 
336
                sigaddset(&smask, statusintsig); 
 
337
                pthread_sigmask(SIG_UNBLOCK,&smask,NULL);
 
338
        }
 
339
        else {
 
340
                log_warn("Cannot install signal handler for server status thread: %s\n",strerror(errno));
 
341
        }
 
342
 
 
343
        for(;;) {
 
344
                do {
 
345
                        int i,n;
 
346
                        keep_testing=0;
 
347
                        retest_flag=0;
 
348
                        schm[0] = '\0';
 
349
                        n=DA_NEL(servers);
 
350
                        for (i=0;i<n;++i) {
 
351
                                servparm_t *sp=&DA_INDEX(servers,i);
 
352
                                int j,m;
 
353
                                if(sp->rootserver==2) {
 
354
                                        /* First get addresses of root servers. */
 
355
                                        addr2_array adrs;
 
356
                                        int l, one_up=0;
 
357
 
 
358
                                        if(!scheme_ok(sp)) {
 
359
                                                time_t now=time(NULL);
 
360
                                                m=DA_NEL(sp->atup_a);
 
361
                                                for(j=0;j<m;++j)
 
362
                                                        DA_INDEX(sp->atup_a,j).i_ts=now;
 
363
                                        } else if(sp->uptest==C_PING || sp->uptest==C_QUERY) {
 
364
                                                /* Skip ping or query tests until after discovery. */
 
365
                                                if(sp->interval>0)
 
366
                                                        one_up= DA_NEL(sp->atup_a);
 
367
                                                else {
 
368
                                                        time_t now=time(NULL);
 
369
                                                        m=DA_NEL(sp->atup_a);
 
370
                                                        for(j=0;j<m;++j) {
 
371
                                                                atup_t *at=&DA_INDEX(sp->atup_a,j);
 
372
                                                                if(at->is_up || at->i_ts==0)
 
373
                                                                        one_up=1;
 
374
                                                                at->i_ts=now;
 
375
                                                        }
 
376
                                                }
 
377
                                        }
 
378
                                        else {
 
379
                                                retest(i,-1);
 
380
 
 
381
                                                m=DA_NEL(sp->atup_a);
 
382
                                                for(j=0;j<m;++j) {
 
383
                                                        if(DA_INDEX(sp->atup_a,j).is_up) {
 
384
                                                                one_up=1;
 
385
                                                                break;
 
386
                                                        }
 
387
                                                }
 
388
                                        }
 
389
 
 
390
                                        if(!one_up) {
 
391
                                                if (needs_intermittent_testing(sp)) keep_testing=1;
 
392
                                                continue;
 
393
                                        }
 
394
 
 
395
                                        DEBUG_MSG("Attempting to discover root servers for server section #%d.\n",i);
 
396
                                        adrs=resolv_rootserver_addrs(sp->atup_a,sp->port,sp->timeout);
 
397
                                        l= DA_NEL(adrs);
 
398
                                        if(l>0) {
 
399
                                                struct timeval now;
 
400
                                                struct timespec timeout;
 
401
                                                atup_array ata;
 
402
                                                DEBUG_MSG("Filling server section #%d with %d root server addresses.\n",i,l);
 
403
                                                gettimeofday(&now,NULL);
 
404
                                                timeout.tv_sec = now.tv_sec + 60;     /* time out after 60 seconds */
 
405
                                                timeout.tv_nsec = now.tv_usec * 1000;
 
406
                                                while (server_data_users>0) {
 
407
                                                        if(pthread_cond_timedwait(&server_data_cond, &servers_lock, &timeout) == ETIMEDOUT) {
 
408
                                                                DEBUG_MSG("Timed out while waiting for exclusive access to server data"
 
409
                                                                          " to set root server addresses of server section #%d\n",i);
 
410
                                                                da_free(adrs);
 
411
                                                                keep_testing=1;
 
412
                                                                continue;
 
413
                                                        }
 
414
                                                }
 
415
                                                ata = DA_CREATE(atup_array, l);
 
416
                                                if(!ata) {
 
417
                                                        log_warn("Out of memory in servstat_thread() while discovering root servers.");
 
418
                                                        da_free(adrs);
 
419
                                                        keep_testing=1;
 
420
                                                        continue;
 
421
                                                }
 
422
                                                for(j=0; j<l; ++j) {
 
423
                                                        atup_t *at = &DA_INDEX(ata,j);
 
424
                                                        at->a = DA_INDEX(adrs,j);
 
425
                                                        at->is_up=sp->preset;
 
426
                                                        at->i_ts= sp->interval<0 ? time(NULL): 0;
 
427
                                                }
 
428
                                                da_free(sp->atup_a);
 
429
                                                sp->atup_a=ata;
 
430
                                                da_free(adrs);
 
431
                                                /* Successfully set IP addresses for this server section. */
 
432
                                                sp->rootserver=1;
 
433
                                        }
 
434
                                        else {
 
435
                                                DEBUG_MSG("Failed to discover root servers in servstat_thread() (server section #%d).\n",i);
 
436
                                                if(adrs) da_free(adrs);
 
437
                                                if(DA_NEL(sp->atup_a)) keep_testing=1;
 
438
                                                continue;
 
439
                                        }
 
440
                                }
 
441
 
 
442
                                if (needs_testing(sp)) keep_testing=1;
 
443
                                m=DA_NEL(sp->atup_a);
 
444
                                for(j=0;j<m;++j)
 
445
                                        if(DA_INDEX(sp->atup_a,j).i_ts)
 
446
                                                goto individual_tests;
 
447
                                /* Test collectively */
 
448
                                if(!signal_interrupt) retest(i,-1);
 
449
                                continue;
 
450
 
 
451
                        individual_tests:
 
452
                                for(j=0; !signal_interrupt && j<m; ++j) {
 
453
                                        time_t ts=DA_INDEX(sp->atup_a,j).i_ts, now;
 
454
 
 
455
                                        if (ts==0 /* Always test servers with timestamp 0 */ ||
 
456
                                            (needs_intermittent_testing(sp) &&
 
457
                                             ((now=time(NULL))-ts>sp->interval ||
 
458
                                              ts>now /* kluge for clock skew */)))
 
459
                                        { 
 
460
                                                retest(i,j);
 
461
                                        }
 
462
                                }
 
463
                        }
 
464
                } while(!signal_interrupt && retest_flag);
 
465
 
 
466
                signal_interrupt=0;
 
467
 
 
468
                /* Break the loop and exit the thread if it is no longer needed. */
 
469
                if(!keep_testing) break;
 
470
 
 
471
                {
 
472
                        struct timeval now;
 
473
                        struct timespec timeout;
 
474
                        time_t minwait;
 
475
                        int i,n,retval;
 
476
 
 
477
                        gettimeofday(&now,NULL);
 
478
                        minwait=3600; /* Check at least once every hour. */
 
479
                        n=DA_NEL(servers);
 
480
                        for (i=0;i<n;++i) {
 
481
                                servparm_t *sp=&DA_INDEX(servers,i);
 
482
                                int j,m=DA_NEL(sp->atup_a);
 
483
                                for(j=0;j<m;++j) {
 
484
                                        time_t ts= DA_INDEX(sp->atup_a,j).i_ts;
 
485
                                        if(ts==0) {
 
486
                                                /* Test servers with timestamp 0 without delay */
 
487
                                                if(minwait > 0) minwait=0;
 
488
                                        }
 
489
                                        else if(needs_intermittent_testing(sp)) {
 
490
                                                time_t wait= ts + sp->interval - now.tv_sec;
 
491
                                                if(wait < minwait) minwait=wait;
 
492
                                        }
 
493
                                }
 
494
                        }
 
495
                        timeout.tv_sec = now.tv_sec;
 
496
                        if(minwait>0)
 
497
                                timeout.tv_sec += minwait;
 
498
                        timeout.tv_nsec = now.tv_usec * 1000 + 500000000;  /* wait at least half a second. */
 
499
                        if(timeout.tv_nsec>=1000000000) {
 
500
                                timeout.tv_nsec -= 1000000000;
 
501
                                ++timeout.tv_sec;
 
502
                        }
 
503
                        /* While we wait for a server_test_cond condition or a timeout
 
504
                           the servers_lock mutex is unlocked, so other threads can access
 
505
                           server data
 
506
                        */
 
507
                        retval=pthread_cond_timedwait(&server_test_cond, &servers_lock, &timeout);
 
508
                        DEBUG_MSG("Server status thread woke up (%s signal).\n",
 
509
                                  retval==0?"test condition":retval==ETIMEDOUT?"timer":retval==EINTR?"interrupt":"error");
 
510
                }
 
511
        }
 
512
 
 
513
        /* server status thread no longer needed. */
 
514
        servstat_thrid=main_thrid;
 
515
        pthread_mutex_unlock(&servers_lock);
 
516
        DEBUG_MSG("Server status thread exiting.\n");
 
517
        return NULL;
 
518
}
 
519
 
 
520
/*
 
521
 * Start the server status thread.
 
522
 */
 
523
int start_servstat_thread()
 
524
{
 
525
        pthread_t stt;
 
526
 
 
527
        int rv=pthread_create(&stt,&attr_detached,servstat_thread,NULL);
 
528
        if (rv)
 
529
                log_warn("Failed to start server status thread: %s",strerror(rv));
 
530
        else {
 
531
                servstat_thrid=stt;
 
532
                log_info(2,"Server status thread started.");
 
533
        }
 
534
        return rv;
 
535
}
 
536
 
 
537
/*
 
538
 * This can be used to mark a server (or a list of nadr servers) up (up=1) or down (up=0),
 
539
 * or to schedule an immediate retest (up=-1).
 
540
 * We can't always use indices to identify a server, because we allow run-time
 
541
 * configuration of server addresses, so the servers are identified by their IP addresses.
 
542
 */ 
 
543
void sched_server_test(pdnsd_a *sa, int nadr, int up)
 
544
{
 
545
        int k,signal_test;
 
546
        
 
547
        pthread_mutex_lock(&servers_lock);
 
548
 
 
549
        signal_test=0;
 
550
        /* This obviously isn't very efficient, but nadr should be small
 
551
           and anything else would introduce considerable overhead */
 
552
        for(k=0;k<nadr;++k) {
 
553
                pdnsd_a *sak= &sa[k];
 
554
                int i,n=DA_NEL(servers);
 
555
                for(i=0;i<n;++i) {
 
556
                        servparm_t *sp=&DA_INDEX(servers,i);
 
557
                        int j,m=DA_NEL(sp->atup_a);
 
558
                        for(j=0;j<m;++j) {
 
559
                                atup_t *at=&DA_INDEX(sp->atup_a,j);
 
560
                                if(equiv_inaddr2(sak,&at->a)) {
 
561
                                        if(up>=0) {
 
562
                                                at->is_up=up;
 
563
                                                at->i_ts=time(NULL);
 
564
                                                DEBUG_PDNSDA_MSG("Marked server %s %s.\n",PDNSDA2STR(sak),up?"up":"down");
 
565
                                        } 
 
566
                                        else if(at->i_ts) {
 
567
                                                /* A test may take a while, and we don't want to hold
 
568
                                                   up the calling thread.
 
569
                                                   Instead we set the timestamp to zero and signal
 
570
                                                   a condition which should wake up the server test thread.
 
571
                                                */
 
572
                                                at->i_ts=0;
 
573
                                                signal_test=1;
 
574
                                        }
 
575
                                }
 
576
                        }
 
577
                }
 
578
        }
 
579
        if(signal_test) pthread_cond_signal(&server_test_cond);
 
580
 
 
581
        pthread_mutex_unlock(&servers_lock);
 
582
}
 
583
 
 
584
/* Mark a set of servers up or down or schedule uptests.
 
585
 * If i>=0 only the server section with index i is scanned,
 
586
 * if i<0 all sections are scanned.
 
587
 * Only sections matching label are actually set. A NULL label matches
 
588
 * any section.
 
589
 * up=1 or up=0 means mark server up or down, up=-1 means retest.
 
590
 *
 
591
 * A non-zero return value indicates an error.
 
592
 */
 
593
int mark_servers(int i, char *label, int up)
 
594
{
 
595
        int retval=0,n,signal_test;
 
596
 
 
597
        pthread_mutex_lock(&servers_lock);
 
598
 
 
599
        signal_test=0;
 
600
        n=DA_NEL(servers);
 
601
        if(i>=0) {
 
602
                /* just one section */
 
603
                if(i<n) n=i+1;
 
604
        }
 
605
        else {
 
606
                i=0; /* scan all sections */
 
607
        }
 
608
        for(;i<n;++i) {
 
609
                servparm_t *sp=&DA_INDEX(servers,i);
 
610
                if(!label || (sp->label && !strcmp(sp->label,label))) {
 
611
                        int j,m=DA_NEL(sp->atup_a);
 
612
 
 
613
                        /* If a section with undiscovered root servers is marked up, signal a test. */
 
614
                        if(m && sp->rootserver>1 && up>0) signal_test=1;
 
615
 
 
616
                        for(j=0;j<m;++j) {
 
617
                                atup_t *at=&DA_INDEX(sp->atup_a,j);
 
618
                                if(up>=0) {
 
619
                                        at->is_up=up;
 
620
                                        at->i_ts=time(NULL);
 
621
                                }
 
622
                                else if(at->i_ts) {
 
623
                                        /* A test may take a while, and we don't want to hold
 
624
                                           up the calling thread.
 
625
                                           Instead we set the timestamp to zero and signal
 
626
                                           a condition which should wake up the server test thread.
 
627
                                        */
 
628
                                        at->i_ts=0;
 
629
                                        signal_test=1;
 
630
                                }
 
631
                        }
 
632
                }
 
633
        }
 
634
        if(signal_test) {
 
635
                if(pthread_equal(servstat_thrid,main_thrid))
 
636
                        retval=start_servstat_thread();
 
637
                else {
 
638
                        retest_flag=1;
 
639
                        retval=pthread_cond_signal(&server_test_cond);
 
640
                }
 
641
        }
 
642
 
 
643
        pthread_mutex_unlock(&servers_lock);
 
644
        return retval;
 
645
}
 
646
 
 
647
/*
 
648
 * Test called by the dns query handlers to handle interval=onquery cases.
 
649
 */
 
650
void test_onquery()
 
651
{
 
652
        int i,n,signal_test;
 
653
        
 
654
        pthread_mutex_lock(&servers_lock);
 
655
        schm[0] = '\0';
 
656
        signal_test=0;
 
657
        n=DA_NEL(servers);
 
658
        for (i=0;i<n;++i) {
 
659
                servparm_t *sp=&DA_INDEX(servers,i);
 
660
                if (sp->interval==-1) {
 
661
                        if(sp->rootserver<=1)
 
662
                                retest(i,-1);
 
663
                        else {
 
664
                                /* We leave root-server discovery to the server status thread */
 
665
                                int j,m=DA_NEL(sp->atup_a);
 
666
                                for(j=0;j<m;++j)
 
667
                                        DA_INDEX(sp->atup_a,j).i_ts=0;
 
668
                                signal_test=1;
 
669
                        }
 
670
                }
 
671
        }
 
672
 
 
673
        if(signal_test) {
 
674
                int rv;
 
675
                if(pthread_equal(servstat_thrid,main_thrid))
 
676
                        start_servstat_thread();
 
677
                else {
 
678
                        retest_flag=1;
 
679
                        if((rv=pthread_cond_signal(&server_test_cond))) {
 
680
                                DEBUG_MSG("test_onquery(): couldn't signal server status thread: %s\n",strerror(rv));
 
681
                        }
 
682
                }
 
683
        }
 
684
 
 
685
        pthread_mutex_unlock(&servers_lock);
 
686
}
 
687
 
 
688
/* non-exclusive lock, for read only access to server data. */
 
689
void lock_server_data()
 
690
{
 
691
        pthread_mutex_lock(&servers_lock);
 
692
        ++server_data_users;
 
693
        pthread_mutex_unlock(&servers_lock);
 
694
}
 
695
 
 
696
void unlock_server_data()
 
697
{
 
698
        pthread_mutex_lock(&servers_lock);
 
699
        PDNSD_ASSERT(server_data_users>0, "server_data_users non-positive before attempt to decrement it");
 
700
        if (--server_data_users==0) pthread_cond_broadcast(&server_data_cond);
 
701
        pthread_mutex_unlock(&servers_lock);
 
702
}
 
703
 
 
704
/* Try to obtain an exclusive lock, needed for modifying server data.
 
705
   Return 1 on success, 0 on failure (time out after tm seconds).
 
706
*/
 
707
int exclusive_lock_server_data(int tm)
 
708
{
 
709
        struct timeval now;
 
710
        struct timespec timeout;
 
711
 
 
712
        pthread_mutex_lock(&servers_lock);
 
713
        if(server_status_ping>0 && !pthread_equal(servstat_thrid,main_thrid)) {
 
714
                int err;
 
715
                /* Try to interrupt server status thread to prevent delays. */
 
716
                DEBUG_MSG("Sending server status thread an interrupt signal.\n");
 
717
                if((err=pthread_kill(servstat_thrid,statusintsig))) {
 
718
                        DEBUG_MSG("pthread_kill failed: %s\n",strerror(err));
 
719
                }
 
720
        }
 
721
        gettimeofday(&now,NULL);
 
722
        timeout.tv_sec = now.tv_sec + tm;     /* time out after tm seconds */
 
723
        timeout.tv_nsec = now.tv_usec * 1000;
 
724
        while (server_data_users>0) {
 
725
                if(pthread_cond_timedwait(&server_data_cond, &servers_lock, &timeout) == ETIMEDOUT) {
 
726
                        pthread_mutex_unlock(&servers_lock);
 
727
                        return 0;
 
728
                }
 
729
        }
 
730
        return 1;
 
731
}
 
732
/* Call this to free the lock obtained with exclusive_lock_server_data().
 
733
   If retest is nonzero, the server-status thread is reactivated to check
 
734
   which servers are up. This is useful in case the configuration has changed.
 
735
*/
 
736
void exclusive_unlock_server_data(int retest)
 
737
{
 
738
        if(retest) {
 
739
                if(pthread_equal(servstat_thrid,main_thrid))
 
740
                        start_servstat_thread();
 
741
                else
 
742
                        pthread_cond_signal(&server_test_cond);
 
743
        }
 
744
        pthread_mutex_unlock(&servers_lock);
 
745
}
 
746
 
 
747
/*
 
748
  Change addresses of servers during runtime.
 
749
  i is the number of the server section to change.
 
750
  ar should point to an array of IP addresses (may be NULL).
 
751
  up=1 or up=0 means mark server up or down afterwards,
 
752
  up=-1 means retest.
 
753
 
 
754
  A non-zero return value indicates an error.
 
755
*/
 
756
int change_servers(int i, addr_array ar, int up)
 
757
{
 
758
        int retval=0,j,change,signal_test;
 
759
        int n;
 
760
        servparm_t *sp;
 
761
 
 
762
        pthread_mutex_lock(&servers_lock);
 
763
 
 
764
        signal_test=0;
 
765
        change=0;
 
766
        n=DA_NEL(ar);
 
767
        sp=&DA_INDEX(servers,i);
 
768
        if(n != DA_NEL(sp->atup_a) || sp->rootserver>1)
 
769
                change=1;
 
770
        else {
 
771
                int j;
 
772
                for(j=0;j<n;++j)
 
773
                        if(!same_inaddr2(&DA_INDEX(ar,j),&DA_INDEX(sp->atup_a,j).a)) {
 
774
                                change=1;
 
775
                                break;
 
776
                        }
 
777
        }
 
778
        if(change) {
 
779
                /* we need exclusive access to the server data to make the changes */
 
780
                struct timeval now;
 
781
                struct timespec timeout;
 
782
                atup_array ata;
 
783
 
 
784
                if(server_status_ping>0 && !pthread_equal(servstat_thrid,main_thrid)) {
 
785
                        int err;
 
786
                        /* Try to interrupt server status thread to prevent delays. */
 
787
                        DEBUG_MSG("Sending server status thread an interrupt signal.\n");
 
788
                        if((err=pthread_kill(servstat_thrid,statusintsig))) {
 
789
                                DEBUG_MSG("pthread_kill failed: %s\n",strerror(err));
 
790
                        }
 
791
                }
 
792
 
 
793
                DEBUG_MSG("Changing IPs of server section #%d\n",i);
 
794
                gettimeofday(&now,NULL);
 
795
                timeout.tv_sec = now.tv_sec + 60;     /* time out after 60 seconds */
 
796
                timeout.tv_nsec = now.tv_usec * 1000;
 
797
                while (server_data_users>0) {
 
798
                        if(pthread_cond_timedwait(&server_data_cond, &servers_lock, &timeout) == ETIMEDOUT) {
 
799
                                retval=ETIMEDOUT;
 
800
                                goto unlock_mutex;
 
801
                        }
 
802
                }
 
803
 
 
804
                ata= DA_CREATE(atup_array, n);
 
805
                if(!ata) {
 
806
                        log_warn("Out of memory in change_servers().");
 
807
                        retval=ENOMEM;
 
808
                        goto unlock_mutex;
 
809
                }
 
810
                da_free(sp->atup_a);
 
811
                sp->atup_a=ata;
 
812
                /* Stop trying to discover rootservers
 
813
                   if we set the addresses using this routine. */
 
814
                if(sp->rootserver>1) sp->rootserver=1;
 
815
        }
 
816
 
 
817
        for(j=0; j<n; ++j) {
 
818
                atup_t *at = &DA_INDEX(sp->atup_a,j);
 
819
                if(change) {
 
820
                        SET_PDNSD_A2(&at->a, &DA_INDEX(ar,j));
 
821
                        at->is_up=sp->preset;
 
822
                }
 
823
                if(up>=0) {
 
824
                        at->is_up=up;
 
825
                        at->i_ts=time(NULL);
 
826
                }
 
827
                else if(change || at->i_ts) {
 
828
                        /* A test may take a while, and we don't want to hold
 
829
                           up the calling thread.
 
830
                           Instead we set the timestamp to zero and signal
 
831
                           a condition which should wake up the server test thread.
 
832
                        */
 
833
                        at->i_ts=0;
 
834
                        signal_test=1;
 
835
                }
 
836
        }
 
837
 
 
838
        if(signal_test) {
 
839
                if(pthread_equal(servstat_thrid,main_thrid))
 
840
                        retval=start_servstat_thread();
 
841
                else {
 
842
                        retest_flag=1;
 
843
                        retval=pthread_cond_signal(&server_test_cond);
 
844
                }
 
845
        }
 
846
 
 
847
 unlock_mutex:
 
848
        pthread_mutex_unlock(&servers_lock);
 
849
        return retval;
 
850
}
 
851
 
 
852
 
 
853
/*
 
854
  The signal handler for the signal to tell the server status thread to discontinue testing.
 
855
*/
 
856
static void sigint_handler(int signum)
 
857
{
 
858
        signal_interrupt=1;
 
859
}