~ubuntu-branches/ubuntu/natty/freeradius/natty-updates

« back to all changes in this revision

Viewing changes to src/main/detail.c

  • Committer: Bazaar Package Importer
  • Author(s): Josip Rodin
  • Date: 2009-11-23 03:57:37 UTC
  • mfrom: (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: james.westby@ubuntu.com-20091123035737-zsgtzhfych8hir68
Tags: 2.1.7+dfsg-1
* Adopting the package, closes: #536623.
* New upstream version, closes: #513484.
  + Fixes the blooper in unlang evaluation logic, closes: #526175.
* Used quilt (and added README.source), and moved upstream file patching
  into debian/patches/. The source is no longer in collab-maint git
  (to make it simpler for me to finally get this out the door), but
  kept the .gitignore should we need that again.
* Dropped the dialup_admin/bin/backup_radacct patch (integrated upstream).
* Dropped the raddb/Makefile patch (problem no longer exists upstream).
* Dropped the lib/packet.c lib/radius.c main/listen.c patches (was from
  upstream 2.0.5 anyway).
* Dropped references to otp.conf, it no longer exists upstream.
  Keep removing the conffile statoverride in prerm.
* Dropped references to snmp.conf, it no longer exists upstream.
  Keep removing the conffile statoverride in prerm.
* Ship /etc/freeradius/modules/* in the freeradius package.
* Stop shipping sites-enabled symlinks in the package and instead create
  them only on initial install, thanks to Matej Vela, closes: #533396.
* Add export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" to the init script
  at the request of John Morrissey, closes: #550143.
* Stop installing /var/run/freeradius in the package to silence Lintian.
  The init script already recreates it at will.
* Remove executable bit from example.pl to silence Lintian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * detail.c     Process the detail file
3
3
 *
4
 
 * Version:     $Id: detail.c,v 1.14 2008/04/26 15:07:43 aland Exp $
 
4
 * Version:     $Id$
5
5
 *
6
6
 *   This program is free software; you can redistribute it and/or modify
7
7
 *   it under the terms of the GNU General Public License as published by
22
22
 */
23
23
 
24
24
#include <freeradius-devel/ident.h>
25
 
RCSID("$Id: detail.c,v 1.14 2008/04/26 15:07:43 aland Exp $")
 
25
RCSID("$Id$")
26
26
 
27
27
#include <freeradius-devel/radiusd.h>
28
28
#include <freeradius-devel/modules.h>
39
39
 
40
40
#include <fcntl.h>
41
41
 
 
42
#ifdef WITH_DETAIL
 
43
 
42
44
#define USEC (1000000)
43
45
 
 
46
typedef enum detail_state_t {
 
47
  STATE_UNOPENED = 0,
 
48
  STATE_UNLOCKED,
 
49
  STATE_HEADER,
 
50
  STATE_READING,
 
51
  STATE_QUEUED,
 
52
  STATE_RUNNING,
 
53
  STATE_NO_REPLY,
 
54
  STATE_REPLIED
 
55
} detail_state_t;
 
56
 
44
57
typedef struct listen_detail_t {
45
 
        int             delay_time; /* should be first entry */
 
58
        fr_event_t      *ev;    /* has to be first entry (ugh) */
 
59
        int             delay_time;
46
60
        char            *filename;
47
61
        char            *filename_work;
48
62
        VALUE_PAIR      *vps;
49
63
        FILE            *fp;
50
 
        int             state;
 
64
        detail_state_t  state;
51
65
        time_t          timestamp;
52
66
        fr_ipaddr_t     client_ip;
53
67
        int             load_factor; /* 1..100 */
54
68
        int             signal;
 
69
        int             poll_interval;
 
70
        int             retry_interval;
55
71
 
56
72
        int             has_rtt;
57
73
        int             srtt;
61
77
} listen_detail_t;
62
78
 
63
79
 
64
 
#define STATE_UNOPENED  (0)
65
 
#define STATE_UNLOCKED  (1)
66
 
#define STATE_HEADER    (2)
67
 
#define STATE_READING   (3)
68
 
#define STATE_QUEUED    (4)
69
 
#define STATE_RUNNING   (5)
70
 
#define STATE_NO_REPLY  (6)
71
 
#define STATE_REPLIED   (7)
72
 
 
73
80
/*
74
81
 *      If we're limiting outstanding packets, then mark the response
75
82
 *      as being sent.
88
95
         *      caller it's OK to read more "detail" file stuff.
89
96
         */
90
97
        if (request->reply->code == 0) {
91
 
                data->delay_time = USEC;
 
98
                data->delay_time = data->retry_interval * USEC;
92
99
                data->signal = 1;
93
100
                data->state = STATE_NO_REPLY;
 
101
 
 
102
                RDEBUG("No response configured for request %d.  Will retry in %d seconds",
 
103
                       request->number, data->retry_interval);
 
104
 
94
105
                radius_signal_self(RADIUS_SIGNAL_SELF_DETAIL);
95
106
                return 0;
96
107
        }
97
108
 
98
109
        /*
99
 
         *      We call gettimeofday a lot.  But here it should be OK,
 
110
         *      We call gettimeofday a lot.  But it should be OK,
100
111
         *      because there's nothing else to do.
101
112
         */
102
113
        gettimeofday(&now, NULL);
154
165
         *      rtt / (rtt + delay) = load_factor / 100
155
166
         */
156
167
        data->delay_time = (data->srtt * (100 - data->load_factor)) / (data->load_factor);
157
 
        if (data->delay_time == 0) data->delay_time = USEC / 10;
158
168
 
159
169
        /*
160
170
         *      Cap delay at 4 packets/s.  If the end system can't
161
171
         *      handle this, then it's very broken.
162
172
         */
163
173
        if (data->delay_time > (USEC / 4)) data->delay_time= USEC / 4;
164
 
 
165
 
#if 0
166
 
        DEBUG2("RTT %d\tdelay %d", data->srtt, data->delay_time);
167
 
#endif
168
 
 
 
174
        
 
175
next:
 
176
        RDEBUG3("Received response for request %d.  Will read the next packet in %d seconds",
 
177
                request->number, data->delay_time / USEC);
 
178
        
169
179
        data->last_packet = now;
170
180
        data->signal = 1;
171
181
        data->state = STATE_REPLIED;
174
184
        return 0;
175
185
}
176
186
 
177
 
int detail_delay(rad_listen_t *listener)
178
 
{
179
 
        listen_detail_t *data = listener->data;
180
 
 
181
 
        if (!data->signal) return 0;
182
 
 
183
 
        data->signal = 0;
184
 
 
185
 
        return data->delay_time;
186
 
}
187
 
 
188
187
 
189
188
/*
190
189
 *      Open the detail file, if we can.
210
209
         *      we've got to open it for writing in order to
211
210
         *      establish the lock, to prevent rlm_detail from
212
211
         *      writing to it.
 
212
         *
 
213
         *      This also means that if we're doing globbing,
 
214
         *      this file will be read && processed before the
 
215
         *      file globbing is done.
213
216
         */
214
217
        this->fd = open(data->filename_work, O_RDWR);
215
218
        if (this->fd < 0) {
226
229
                if (stat(filename, &st) < 0) {
227
230
#ifdef HAVE_GLOB_H
228
231
                        int i, found;
229
 
                        time_t ctime;
 
232
                        time_t chtime;
230
233
                        glob_t files;
231
234
 
232
235
                        memset(&files, 0, sizeof(files));
234
237
                                return 0;
235
238
                        }
236
239
 
237
 
                        ctime = 0;
 
240
                        chtime = 0;
238
241
                        found = -1;
239
242
                        for (i = 0; i < files.gl_pathc; i++) {
240
243
                                if (stat(files.gl_pathv[i], &st) < 0) continue;
241
244
 
242
245
                                if ((i == 0) ||
243
 
                                    (st.st_ctime < ctime)) {
244
 
                                        ctime = st.st_ctime;
 
246
                                    (st.st_ctime < chtime)) {
 
247
                                        chtime = st.st_ctime;
245
248
                                        found = i;
246
249
                                }
247
250
                        }
253
256
 
254
257
                        filename = strdup(files.gl_pathv[found]);
255
258
                        globfree(&files);
256
 
 
257
 
 
258
259
#else
259
260
                        return 0;
260
261
#endif
321
322
        char            buffer[2048];
322
323
        listen_detail_t *data = listener->data;
323
324
 
 
325
        /*
 
326
         *      We may be in the main thread.  It needs to update the
 
327
         *      timers before we try to read from the file again.
 
328
         */
 
329
        if (data->signal) return 0;
 
330
 
324
331
        switch (data->state) {
325
332
                case STATE_UNOPENED:
326
333
        open_file:
374
381
                         *      Look for the header
375
382
                         */
376
383
                        data->state = STATE_HEADER;
 
384
                        data->delay_time = USEC;
377
385
                        data->vps = NULL;
378
386
 
379
387
                        /* FALL-THROUGH */
420
428
                         *      we have.
421
429
                         */
422
430
                case STATE_READING:
423
 
                        if (!feof(data->fp)) break;
 
431
                        if (data->fp && !feof(data->fp)) break;
424
432
                        data->state = STATE_QUEUED;
425
433
 
426
434
                        /* FALL-THROUGH */
575
583
         */
576
584
        if (!data->vps) {
577
585
                data->state = STATE_HEADER;
 
586
                if (feof(data->fp)) goto cleanup; 
578
587
                return 0;
579
588
        }
580
589
 
722
731
                        this->server);
723
732
}
724
733
 
725
 
int detail_encode(UNUSED rad_listen_t *this, UNUSED REQUEST *request)
 
734
/*
 
735
 *      Overloaded to return delay times.
 
736
 */
 
737
int detail_encode(rad_listen_t *this, UNUSED REQUEST *request)
726
738
{
 
739
        listen_detail_t *data = this->data;
 
740
 
727
741
        /*
728
 
         *      We never encode responses "sent to" the detail file.
 
742
         *      We haven't sent a packet... delay things a bit.
729
743
         */
730
 
        return 0;
 
744
        if (!data->signal) {
 
745
                int delay = (data->poll_interval - 1) * USEC;
 
746
 
 
747
                /*
 
748
                 *      Add +/- 0.25s of jitter
 
749
                 */
 
750
                delay += (USEC * 3) / 4;
 
751
                delay += fr_rand() % (USEC / 2);
 
752
                return delay;
 
753
        }
 
754
 
 
755
        data->signal = 0;
 
756
 
 
757
        return data->delay_time;
731
758
}
732
759
 
733
 
int detail_decode(UNUSED rad_listen_t *this, UNUSED REQUEST *request)
 
760
 
 
761
/*
 
762
 *      Overloaded to return "should we fix delay times"
 
763
 */
 
764
int detail_decode(rad_listen_t *this, UNUSED REQUEST *request)
734
765
{
735
 
        /*
736
 
         *      We never decode responses read from the detail file.
737
 
         */
738
 
        return 0;
 
766
        listen_detail_t *data = this->data;
 
767
 
 
768
        return data->signal;
739
769
}
740
770
 
741
771
 
744
774
          offsetof(listen_detail_t, filename), NULL,  NULL },
745
775
        { "load_factor",   PW_TYPE_INTEGER,
746
776
          offsetof(listen_detail_t, load_factor), NULL, Stringify(10)},
 
777
        { "poll_interval",   PW_TYPE_INTEGER,
 
778
          offsetof(listen_detail_t, poll_interval), NULL, Stringify(1)},
 
779
        { "retry_interval",   PW_TYPE_INTEGER,
 
780
          offsetof(listen_detail_t, retry_interval), NULL, Stringify(30)},
747
781
 
748
782
        { NULL, -1, 0, NULL, NULL }             /* end the list */
749
783
};
765
799
        }
766
800
 
767
801
        data = this->data;
768
 
        data->delay_time = USEC;
769
802
 
770
803
        rcode = cf_section_parse(cs, data, detail_config);
771
804
        if (rcode < 0) {
783
816
                return -1;
784
817
        }
785
818
 
786
 
        snprintf(buffer, sizeof(buffer), "%s.work", data->filename);
 
819
        if ((data->poll_interval < 1) || (data->poll_interval > 20)) {
 
820
                cf_log_err(cf_sectiontoitem(cs), "poll_interval must be between 1 and 20");
 
821
                return -1;
 
822
        }
 
823
 
 
824
        /*
 
825
         *      If the filename is a glob, use "detail.work" as the
 
826
         *      work file name.
 
827
         */
 
828
        if ((strchr(data->filename, '*') != NULL) ||
 
829
            (strchr(data->filename, '[') != NULL)) {
 
830
                char *p;
 
831
 
 
832
#ifndef HAVE_GLOB_H
 
833
                radlog(L_INFO, "WARNING: Detail file \"%s\" appears to use file globbing, but it is not supported on this system.", data->filename);
 
834
#endif
 
835
                strlcpy(buffer, data->filename, sizeof(buffer));
 
836
                p = strrchr(buffer, FR_DIR_SEP);
 
837
                if (p) {
 
838
                        p[1] = '\0';
 
839
                } else {
 
840
                        buffer[0] = '\0';
 
841
                }
 
842
                strlcat(buffer, "detail.work",
 
843
                        sizeof(buffer) - strlen(buffer));
 
844
                        
 
845
        } else {
 
846
                snprintf(buffer, sizeof(buffer), "%s.work", data->filename);
 
847
        }
 
848
 
787
849
        free(data->filename_work);
788
850
        data->filename_work = strdup(buffer); /* FIXME: leaked */
789
851
 
790
852
        data->vps = NULL;
791
853
        data->fp = NULL;
792
854
        data->state = STATE_UNOPENED;
 
855
        data->delay_time = data->poll_interval * USEC;
 
856
        data->signal = 1;
793
857
 
794
858
        /*
795
859
         *      Initialize the fake client.
805
869
 
806
870
        return 0;
807
871
}
 
872
#endif