Revert "Make WITH_DETAIL_THREAD the default."
[freeradius.git] / src / main / detail.c
1 /*
2  * detail.c     Process the detail file
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2007  The FreeRADIUS server project
21  * Copyright 2007  Alan DeKok <aland@deployingradius.com>
22  */
23
24 RCSID("$Id$")
25
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/detail.h>
29 #include <freeradius-devel/process.h>
30 #include <freeradius-devel/rad_assert.h>
31
32 #ifdef HAVE_SYS_STAT_H
33 #include <sys/stat.h>
34 #endif
35
36 #ifdef HAVE_GLOB_H
37 #include <glob.h>
38 #endif
39
40 #include <fcntl.h>
41
42 #ifdef WITH_DETAIL
43
44 #define USEC (1000000)
45
46 static FR_NAME_NUMBER state_names[] = {
47         { "unopened", STATE_UNOPENED },
48         { "unlocked", STATE_UNLOCKED },
49         { "header", STATE_HEADER },
50         { "reading", STATE_READING },
51         { "queued", STATE_QUEUED },
52         { "running", STATE_RUNNING },
53         { "no-reply", STATE_NO_REPLY },
54         { "replied", STATE_REPLIED },
55
56         { NULL, 0 }
57 };
58
59
60 /*
61  *      If we're limiting outstanding packets, then mark the response
62  *      as being sent.
63  */
64 int detail_send(rad_listen_t *listener, REQUEST *request)
65 {
66 #ifdef WITH_DETAIL_THREAD
67         char c = 0;
68 #endif
69         listen_detail_t *data = listener->data;
70
71         rad_assert(request->listener == listener);
72         rad_assert(listener->send == detail_send);
73
74         /*
75          *      This request timed out.  Remember that, and tell the
76          *      caller it's OK to read more "detail" file stuff.
77          */
78         if (request->reply->code == 0) {
79                 data->delay_time = data->retry_interval * USEC;
80                 data->signal = 1;
81                 data->state = STATE_NO_REPLY;
82
83                 RDEBUG("detail (%s): No response to request.  Will retry in %d seconds",
84                        data->name, data->retry_interval);
85         } else {
86                 int rtt;
87                 struct timeval now;
88                 /*
89                  *      We call gettimeofday a lot.  But it should be OK,
90                  *      because there's nothing else to do.
91                  */
92                 gettimeofday(&now, NULL);
93
94                 /*
95                  *      If we haven't sent a packet in the last second, reset
96                  *      the RTT.
97                  */
98                 now.tv_sec -= 1;
99                 if (timercmp(&data->last_packet, &now, <)) {
100                         data->has_rtt = false;
101                 }
102                 now.tv_sec += 1;
103
104                 /*
105                  *      Only one detail packet may be outstanding at a time,
106                  *      so it's safe to update some entries in the detail
107                  *      structure.
108                  *
109                  *      We keep smoothed round trip time (SRTT), but not round
110                  *      trip timeout (RTO).  We use SRTT to calculate a rough
111                  *      load factor.
112                  */
113                 rtt = now.tv_sec - request->packet->timestamp.tv_sec;
114                 rtt *= USEC;
115                 rtt += now.tv_usec;
116                 rtt -= request->packet->timestamp.tv_usec;
117
118                 /*
119                  *      If we're proxying, the RTT is our processing time,
120                  *      plus the network delay there and back, plus the time
121                  *      on the other end to process the packet.  Ideally, we
122                  *      should remove the network delays from the RTT, but we
123                  *      don't know what they are.
124                  *
125                  *      So, to be safe, we over-estimate the total cost of
126                  *      processing the packet.
127                  */
128                 if (!data->has_rtt) {
129                         data->has_rtt = true;
130                         data->srtt = rtt;
131                         data->rttvar = rtt / 2;
132
133                 } else {
134                         data->rttvar -= data->rttvar >> 2;
135                         data->rttvar += (data->srtt - rtt);
136                         data->srtt -= data->srtt >> 3;
137                         data->srtt += rtt >> 3;
138                 }
139
140                 /*
141                  *      Calculate the time we wait before sending the next
142                  *      packet.
143                  *
144                  *      rtt / (rtt + delay) = load_factor / 100
145                  */
146                 data->delay_time = (data->srtt * (100 - data->load_factor)) / (data->load_factor);
147
148                 /*
149                  *      Cap delay at no less than 4 packets/s.  If the
150                  *      end system can't handle this, then it's very
151                  *      broken.
152                  */
153                 if (data->delay_time > (USEC / 4)) data->delay_time= USEC / 4;
154
155                 RDEBUG3("detail (%s): Received response for request %d.  Will read the next packet in %d seconds",
156                         data->name, request->number, data->delay_time / USEC);
157
158                 data->last_packet = now;
159                 data->signal = 1;
160                 data->state = STATE_REPLIED;
161                 data->counter++;
162         }
163
164 #ifdef WITH_DETAIL_THREAD
165         if (write(data->child_pipe[1], &c, 1) < 0) {
166                 RERROR("detail (%s): Failed writing ack to reader thread: %s", data->name, fr_syserror(errno));
167         }
168 #else
169         radius_signal_self(RADIUS_SIGNAL_SELF_DETAIL);
170 #endif
171
172         return 0;
173 }
174
175
176 /*
177  *      Open the detail file, if we can.
178  *
179  *      FIXME: create it, if it's not already there, so that the main
180  *      server select() will wake us up if there's anything to read.
181  */
182 static int detail_open(rad_listen_t *this)
183 {
184         struct stat st;
185         listen_detail_t *data = this->data;
186
187         rad_assert(data->state == STATE_UNOPENED);
188         data->delay_time = USEC;
189
190         /*
191          *      Open detail.work first, so we don't lose
192          *      accounting packets.  It's probably better to
193          *      duplicate them than to lose them.
194          *
195          *      Note that we're not writing to the file, but
196          *      we've got to open it for writing in order to
197          *      establish the lock, to prevent rlm_detail from
198          *      writing to it.
199          *
200          *      This also means that if we're doing globbing,
201          *      this file will be read && processed before the
202          *      file globbing is done.
203          */
204         data->fp = NULL;
205         data->work_fd = open(data->filename_work, O_RDWR);
206         if (data->work_fd < 0) {
207 #ifndef HAVE_GLOB_H
208                 return 0;
209 #else
210                 unsigned int    i;
211                 int             found;
212                 time_t          chtime;
213                 char const      *filename;
214                 glob_t          files;
215
216                 DEBUG2("detail (%s): Polling for detail file", data->name);
217
218                 memset(&files, 0, sizeof(files));
219                 if (glob(data->filename, 0, NULL, &files) != 0) {
220                 noop:
221                         globfree(&files);
222                         return 0;
223                 }
224
225                 /*
226                  *      Loop over the glob'd files, looking for the
227                  *      oldest one.
228                  */
229                 chtime = 0;
230                 found = -1;
231                 for (i = 0; i < files.gl_pathc; i++) {
232                         if (stat(files.gl_pathv[i], &st) < 0) continue;
233
234                         if ((i == 0) || (st.st_ctime < chtime)) {
235                                 chtime = st.st_ctime;
236                                 found = i;
237                         }
238                 }
239
240                 if (found < 0) goto noop;
241
242                 /*
243                  *      Rename detail to detail.work
244                  */
245                 filename = files.gl_pathv[found];
246
247                 DEBUG("detail (%s): Renaming %s -> %s", data->name, filename, data->filename_work);
248                 if (rename(filename, data->filename_work) < 0) {
249                         ERROR("detail (%s): Failed renaming %s to %s: %s",
250                               data->name, filename, data->filename_work, fr_syserror(errno));
251                         goto noop;
252                 }
253
254                 globfree(&files);       /* Shouldn't be using anything in files now */
255
256                 /*
257                  *      And try to open the filename.
258                  */
259                 data->work_fd = open(data->filename_work, O_RDWR);
260                 if (data->work_fd < 0) return 0;
261 #endif
262         } /* else detail.work existed, and we opened it */
263
264         rad_assert(data->vps == NULL);
265         rad_assert(data->fp == NULL);
266
267         data->state = STATE_UNLOCKED;
268
269         data->client_ip.af = AF_UNSPEC;
270         data->timestamp = 0;
271         data->offset = data->last_offset = data->timestamp_offset = 0;
272         data->packets = 0;
273         data->tries = 0;
274         data->done_entry = false;
275
276         return 1;
277 }
278
279
280 /*
281  *      FIXME: add a configuration "exit when done" so that the detail
282  *      file reader can be used as a one-off tool to update stuff.
283  *
284  *      The time sequence for reading from the detail file is:
285  *
286  *      t_0             signalled that the server is idle, and we
287  *                      can read from the detail file.
288  *
289  *      t_rtt           the packet has been processed successfully,
290  *                      wait for t_delay to enforce load factor.
291  *
292  *      t_rtt + t_delay wait for signal that the server is idle.
293  *
294  */
295 #ifndef WITH_DETAIL_THREAD
296 static RADIUS_PACKET *detail_poll(rad_listen_t *listener);
297
298 int detail_recv(rad_listen_t *listener)
299 {
300         RADIUS_PACKET *packet;
301         listen_detail_t *data = listener->data;
302         RAD_REQUEST_FUNP fun = NULL;
303
304         /*
305          *      We may be in the main thread.  It needs to update the
306          *      timers before we try to read from the file again.
307          */
308         if (data->signal) return 0;
309
310         packet = detail_poll(listener);
311         if (!packet) return -1;
312
313         if (DEBUG_ENABLED2) {
314                 VALUE_PAIR *vp;
315                 vp_cursor_t cursor;
316
317                 DEBUG2("detail (%s): Read packet from %s", data->name, data->filename_work);
318
319                 for (vp = fr_cursor_init(&cursor, &packet->vps);
320                      vp;
321                      vp = fr_cursor_next(&cursor)) {
322                         debug_pair(vp);
323                 }
324         }
325
326         switch (packet->code) {
327         case PW_CODE_ACCOUNTING_REQUEST:
328                 fun = rad_accounting;
329                 break;
330
331         case PW_CODE_COA_REQUEST:
332         case PW_CODE_DISCONNECT_REQUEST:
333                 fun = rad_coa_recv;
334                 break;
335
336         default:
337                 rad_free(&packet);
338                 data->state = STATE_REPLIED;
339                 return 0;
340         }
341
342         /*
343          *      Don't bother doing limit checks, etc.
344          */
345         if (!request_receive(NULL, listener, packet, &data->detail_client, fun)) {
346                 rad_free(&packet);
347                 data->state = STATE_NO_REPLY;   /* try again later */
348                 return 0;
349         }
350
351         return 1;
352 }
353 #else
354 int detail_recv(rad_listen_t *listener)
355 {
356         char c = 0;
357         ssize_t rcode;
358         RADIUS_PACKET *packet;
359         listen_detail_t *data = listener->data;
360         RAD_REQUEST_FUNP fun = NULL;
361
362         /*
363          *      Block until there's a packet ready.
364          */
365         rcode = read(data->master_pipe[0], &packet, sizeof(packet));
366         if (rcode <= 0) return rcode;
367
368         if (DEBUG_ENABLED2) {
369                 VALUE_PAIR *vp;
370                 vp_cursor_t cursor;
371
372                 DEBUG2("detail (%s): Read packet from %s", data->name, data->filename_work);
373                 for (vp = fr_cursor_init(&cursor, &packet->vps);
374                      vp;
375                      vp = fr_cursor_next(&cursor)) {
376                         debug_pair(vp);
377                 }
378         }
379         rad_assert(packet != NULL);
380
381         switch (packet->code) {
382         case PW_CODE_ACCOUNTING_REQUEST:
383                 fun = rad_accounting;
384                 break;
385
386         case PW_CODE_COA_REQUEST:
387         case PW_CODE_DISCONNECT_REQUEST:
388                 fun = rad_coa_recv;
389                 break;
390
391         default:
392                 data->state = STATE_REPLIED;
393                 goto signal_thread;
394         }
395
396         if (!request_receive(NULL, listener, packet, &data->detail_client, fun)) {
397                 data->state = STATE_NO_REPLY;   /* try again later */
398
399         signal_thread:
400                 rad_free(&packet);
401                 if (write(data->child_pipe[1], &c, 1) < 0) {
402                         ERROR("detail (%s): Failed writing ack to reader thread: %s", data->name,
403                               fr_syserror(errno));
404                 }
405         }
406
407         /*
408          *      Wait for the child thread to write an answer to the pipe
409          */
410         return 0;
411 }
412 #endif
413
414 static RADIUS_PACKET *detail_poll(rad_listen_t *listener)
415 {
416         char            key[256], op[8], value[1024];
417         vp_cursor_t     cursor;
418         VALUE_PAIR      *vp;
419         RADIUS_PACKET   *packet;
420         char            buffer[2048];
421         listen_detail_t *data = listener->data;
422
423         switch (data->state) {
424         case STATE_UNOPENED:
425 open_file:
426                 rad_assert(data->work_fd < 0);
427
428                 if (!detail_open(listener)) return NULL;
429
430                 rad_assert(data->state == STATE_UNLOCKED);
431                 rad_assert(data->work_fd >= 0);
432
433                 /* FALL-THROUGH */
434
435         /*
436          *      Try to lock fd.  If we can't, return.
437          *      If we can, continue.  This means that
438          *      the server doesn't block while waiting
439          *      for the lock to open...
440          */
441         case STATE_UNLOCKED:
442                 /*
443                  *      Note that we do NOT block waiting for
444                  *      the lock.  We've re-named the file
445                  *      above, so we've already guaranteed
446                  *      that any *new* detail writer will not
447                  *      be opening this file.  The only
448                  *      purpose of the lock is to catch a race
449                  *      condition where the execution
450                  *      "ping-pongs" between radiusd &
451                  *      radrelay.
452                  */
453                 if (rad_lockfd_nonblock(data->work_fd, 0) < 0) {
454                         /*
455                          *      Close the FD.  The main loop
456                          *      will wake up in a second and
457                          *      try again.
458                          */
459                         close(data->work_fd);
460                         data->fp = NULL;
461                         data->work_fd = -1;
462                         data->state = STATE_UNOPENED;
463                         return NULL;
464                 }
465
466                 /*
467                  *      Only open for writing if we're
468                  *      marking requests as completed.
469                  */
470                 data->fp = fdopen(data->work_fd, data->track ? "r+" : "r");
471                 if (!data->fp) {
472                         ERROR("detail (%s): FATAL: Failed to re-open detail file: %s",
473                               data->name, fr_syserror(errno));
474                         fr_exit(1);
475                 }
476
477                 /*
478                  *      Look for the header
479                  */
480                 data->state = STATE_HEADER;
481                 data->delay_time = USEC;
482                 data->vps = NULL;
483
484                 /* FALL-THROUGH */
485
486         case STATE_HEADER:
487         do_header:
488                 data->done_entry = false;
489                 data->timestamp_offset = 0;
490
491                 data->tries = 0;
492                 if (!data->fp) {
493                         data->state = STATE_UNOPENED;
494                         goto open_file;
495                 }
496
497                 {
498                         struct stat buf;
499
500                         if (fstat(data->work_fd, &buf) < 0) {
501                                 ERROR("detail (%s): Failed to stat detail file: %s",
502                                       data->name, fr_syserror(errno));
503
504                                 goto cleanup;
505                         }
506                         if (((off_t) ftell(data->fp)) == buf.st_size) {
507                                 goto cleanup;
508                         }
509                 }
510
511                 /*
512                  *      End of file.  Delete it, and re-set
513                  *      everything.
514                  */
515                 if (feof(data->fp)) {
516                 cleanup:
517                         DEBUG("detail (%s): Unlinking %s", data->name, data->filename_work);
518                         unlink(data->filename_work);
519                         if (data->fp) fclose(data->fp);
520                         data->fp = NULL;
521                         data->work_fd = -1;
522                         data->state = STATE_UNOPENED;
523                         rad_assert(data->vps == NULL);
524
525                         if (data->one_shot) {
526                                 INFO("detail (%s): Finished reading \"one shot\" detail file - Exiting", data->name);
527                                 radius_signal_self(RADIUS_SIGNAL_SELF_EXIT);
528                         }
529
530                         return NULL;
531                 }
532
533                 /*
534                  *      Else go read something.
535                  */
536                 break;
537
538         /*
539          *      Read more value-pair's, unless we're
540          *      at EOF.  In that case, queue whatever
541          *      we have.
542          */
543         case STATE_READING:
544                 if (data->fp && !feof(data->fp)) break;
545                 data->state = STATE_QUEUED;
546
547                 /* FALL-THROUGH */
548
549         case STATE_QUEUED:
550                 goto alloc_packet;
551
552         /*
553          *      Periodically check what's going on.
554          *      If the request is taking too long,
555          *      retry it.
556          */
557         case STATE_RUNNING:
558                 if (time(NULL) < (data->running + (int)data->retry_interval)) {
559                         return NULL;
560                 }
561
562                 DEBUG("detail (%s): No response to detail request.  Retrying", data->name);
563                 /* FALL-THROUGH */
564
565         /*
566          *      If there's no reply, keep
567          *      retransmitting the current packet
568          *      forever.
569          */
570         case STATE_NO_REPLY:
571                 data->state = STATE_QUEUED;
572                 goto alloc_packet;
573
574         /*
575          *      We have a reply.  Clean up the old
576          *      request, and go read another one.
577          */
578         case STATE_REPLIED:
579                 if (data->track) {
580                         rad_assert(data->fp != NULL);
581
582                         if (fseek(data->fp, data->timestamp_offset, SEEK_SET) < 0) {
583                                 WARN("detail (%s): Failed seeking to timestamp offset: %s",
584                                      data->name, fr_syserror(errno));
585                         } else if (fwrite("\tDone", 1, 5, data->fp) < 5) {
586                                 WARN("detail (%s): Failed marking request as done: %s",
587                                      data->name, fr_syserror(errno));
588                         } else if (fflush(data->fp) != 0) {
589                                 WARN("detail (%s): Failed flushing marked detail file to disk: %s",
590                                      data->name, fr_syserror(errno));
591                         }
592
593                         if (fseek(data->fp, data->offset, SEEK_SET) < 0) {
594                                 WARN("detail (%s): Failed seeking to next detail request: %s",
595                                      data->name, fr_syserror(errno));
596                         }
597                 }
598
599                 pairfree(&data->vps);
600                 data->state = STATE_HEADER;
601                 goto do_header;
602         }
603
604         fr_cursor_init(&cursor, &data->vps);
605
606         /*
607          *      Read a header, OR a value-pair.
608          */
609         while (fgets(buffer, sizeof(buffer), data->fp)) {
610                 data->last_offset = data->offset;
611                 data->offset = ftell(data->fp); /* for statistics */
612
613                 /*
614                  *      Badly formatted file: delete it.
615                  *
616                  *      FIXME: Maybe flag an error?
617                  */
618                 if (!strchr(buffer, '\n')) {
619                         pairfree(&data->vps);
620                         goto cleanup;
621                 }
622
623                 /*
624                  *      We're reading VP's, and got a blank line.
625                  *      Queue the packet.
626                  */
627                 if ((data->state == STATE_READING) &&
628                     (buffer[0] == '\n')) {
629                         data->state = STATE_QUEUED;
630                         break;
631                 }
632
633                 /*
634                  *      Look for date/time header, and read VP's if
635                  *      found.  If not, keep reading lines until we
636                  *      find one.
637                  */
638                 if (data->state == STATE_HEADER) {
639                         int y;
640
641                         if (sscanf(buffer, "%*s %*s %*d %*d:%*d:%*d %d", &y)) {
642                                 data->state = STATE_READING;
643                         }
644                         continue;
645                 }
646
647                 /*
648                  *      We have a full "attribute = value" line.
649                  *      If it doesn't look reasonable, skip it.
650                  *
651                  *      FIXME: print an error for badly formatted attributes?
652                  */
653                 if (sscanf(buffer, "%255s %7s %1023s", key, op, value) != 3) {
654                         WARN("detail (%s): Skipping badly formatted line %s", data->name, buffer);
655                         continue;
656                 }
657
658                 /*
659                  *      Should be =, :=, +=, ...
660                  */
661                 if (!strchr(op, '=')) continue;
662
663                 /*
664                  *      Skip non-protocol attributes.
665                  */
666                 if (!strcasecmp(key, "Request-Authenticator")) continue;
667
668                 /*
669                  *      Set the original client IP address, based on
670                  *      what's in the detail file.
671                  *
672                  *      Hmm... we don't set the server IP address.
673                  *      or port.  Oh well.
674                  */
675                 if (!strcasecmp(key, "Client-IP-Address")) {
676                         data->client_ip.af = AF_INET;
677                         if (ip_hton(&data->client_ip, AF_INET, value, false) < 0) {
678                                 ERROR("detail (%s): Failed parsing Client-IP-Address", data->name);
679
680                                 pairfree(&data->vps);
681                                 goto cleanup;
682                         }
683                         continue;
684                 }
685
686                 /*
687                  *      The original time at which we received the
688                  *      packet.  We need this to properly calculate
689                  *      Acct-Delay-Time.
690                  */
691                 if (!strcasecmp(key, "Timestamp")) {
692                         data->timestamp = atoi(value);
693                         data->timestamp_offset = data->last_offset;
694
695                         vp = paircreate(data, PW_PACKET_ORIGINAL_TIMESTAMP, 0);
696                         if (vp) {
697                                 vp->vp_date = (uint32_t) data->timestamp;
698                                 vp->type = VT_DATA;
699                                 fr_cursor_insert(&cursor, vp);
700                         }
701                         continue;
702                 }
703
704                 if (!strcasecmp(key, "Donestamp")) {
705                         data->timestamp = atoi(value);
706                         data->done_entry = true;
707                         continue;
708                 }
709
710                 /*
711                  *      Read one VP.
712                  *
713                  *      FIXME: do we want to check for non-protocol
714                  *      attributes like radsqlrelay does?
715                  */
716                 vp = NULL;
717                 if ((userparse(data, buffer, &vp) > 0) &&
718                     (vp != NULL)) {
719                         fr_cursor_merge(&cursor, vp);
720                 }
721         }
722
723         /*
724          *      Some kind of error.
725          *
726          *      FIXME: Leave the file in-place, and warn the
727          *      administrator?
728          */
729         if (ferror(data->fp)) goto cleanup;
730
731         data->tries = 0;
732         data->packets++;
733
734         /*
735          *      Process the packet.
736          */
737  alloc_packet:
738         if (data->done_entry) {
739                 DEBUG2("detail (%s): Skipping record for timestamp %lu", data->name, data->timestamp);
740                 pairfree(&data->vps);
741                 data->state = STATE_HEADER;
742                 goto do_header;
743         }
744
745         data->tries++;
746
747         /*
748          *      The writer doesn't check that the record was
749          *      completely written.  If the disk is full, this can
750          *      result in a truncated record.  When that happens,
751          *      treat it as EOF.
752          */
753         if (data->state != STATE_QUEUED) {
754                 ERROR("detail (%s): Truncated record: treating it as EOF for detail file %s",
755                       data->name, data->filename_work);
756                 pairfree(&data->vps);
757                 goto cleanup;
758         }
759
760         /*
761          *      We're done reading the file, but we didn't read
762          *      anything.  Clean up, and don't return anything.
763          */
764         if (!data->vps) {
765                 data->state = STATE_HEADER;
766                 if (!data->fp || feof(data->fp)) goto cleanup;
767                 return NULL;
768         }
769
770         /*
771          *      Allocate the packet.  If we fail, it's a serious
772          *      problem.
773          */
774         packet = rad_alloc(NULL, true);
775         if (!packet) {
776                 ERROR("detail (%s): FATAL: Failed allocating memory for detail", data->name);
777                 fr_exit(1);
778         }
779
780         memset(packet, 0, sizeof(*packet));
781         packet->sockfd = -1;
782         packet->src_ipaddr.af = AF_INET;
783         packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
784
785         /*
786          *      If everything's OK, this is a waste of memory.
787          *      Otherwise, it lets us re-send the original packet
788          *      contents, unmolested.
789          */
790         packet->vps = paircopy(packet, data->vps);
791
792         packet->code = PW_CODE_ACCOUNTING_REQUEST;
793         vp = pairfind(packet->vps, PW_PACKET_TYPE, 0, TAG_ANY);
794         if (vp) packet->code = vp->vp_integer;
795
796         gettimeofday(&packet->timestamp, NULL);
797
798         /*
799          *      Remember where it came from, so that we don't
800          *      proxy it to the place it came from...
801          */
802         if (data->client_ip.af != AF_UNSPEC) {
803                 packet->src_ipaddr = data->client_ip;
804         }
805
806         vp = pairfind(packet->vps, PW_PACKET_SRC_IP_ADDRESS, 0, TAG_ANY);
807         if (vp) {
808                 packet->src_ipaddr.af = AF_INET;
809                 packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
810                 packet->src_ipaddr.prefix = 32;
811         } else {
812                 vp = pairfind(packet->vps, PW_PACKET_SRC_IPV6_ADDRESS, 0, TAG_ANY);
813                 if (vp) {
814                         packet->src_ipaddr.af = AF_INET6;
815                         memcpy(&packet->src_ipaddr.ipaddr.ip6addr,
816                                &vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
817                         packet->src_ipaddr.prefix = 128;
818                 }
819         }
820
821         vp = pairfind(packet->vps, PW_PACKET_DST_IP_ADDRESS, 0, TAG_ANY);
822         if (vp) {
823                 packet->dst_ipaddr.af = AF_INET;
824                 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
825                 packet->dst_ipaddr.prefix = 32;
826         } else {
827                 vp = pairfind(packet->vps, PW_PACKET_DST_IPV6_ADDRESS, 0, TAG_ANY);
828                 if (vp) {
829                         packet->dst_ipaddr.af = AF_INET6;
830                         memcpy(&packet->dst_ipaddr.ipaddr.ip6addr,
831                                &vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
832                         packet->dst_ipaddr.prefix = 128;
833                 }
834         }
835
836         /*
837          *      Generate packet ID, ports, IP via a counter.
838          */
839         packet->id = data->counter & 0xff;
840         packet->src_port = 1024 + ((data->counter >> 8) & 0xff);
841         packet->dst_port = 1024 + ((data->counter >> 16) & 0xff);
842
843         packet->dst_ipaddr.af = AF_INET;
844         packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl((INADDR_LOOPBACK & ~0xffffff) | ((data->counter >> 24) & 0xff));
845
846         /*
847          *      Create / update accounting attributes.
848          */
849         if (packet->code == PW_CODE_ACCOUNTING_REQUEST) {
850                 /*
851                  *      Prefer the Event-Timestamp in the packet, if it
852                  *      exists.  That is when the event occurred, whereas the
853                  *      "Timestamp" field is when we wrote the packet to the
854                  *      detail file, which could have been much later.
855                  */
856                 vp = pairfind(packet->vps, PW_EVENT_TIMESTAMP, 0, TAG_ANY);
857                 if (vp) {
858                         data->timestamp = vp->vp_integer;
859                 }
860
861                 /*
862                  *      Look for Acct-Delay-Time, and update
863                  *      based on Acct-Delay-Time += (time(NULL) - timestamp)
864                  */
865                 vp = pairfind(packet->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
866                 if (!vp) {
867                         vp = paircreate(packet, PW_ACCT_DELAY_TIME, 0);
868                         rad_assert(vp != NULL);
869                         pairadd(&packet->vps, vp);
870                 }
871                 if (data->timestamp != 0) {
872                         vp->vp_integer += time(NULL) - data->timestamp;
873                 }
874         }
875
876         /*
877          *      Set the transmission count.
878          */
879         vp = pairfind(packet->vps, PW_PACKET_TRANSMIT_COUNTER, 0, TAG_ANY);
880         if (!vp) {
881                 vp = paircreate(packet, PW_PACKET_TRANSMIT_COUNTER, 0);
882                 rad_assert(vp != NULL);
883                 pairadd(&packet->vps, vp);
884         }
885         vp->vp_integer = data->tries;
886
887         data->state = STATE_RUNNING;
888         data->running = packet->timestamp.tv_sec;
889
890         return packet;
891 }
892
893 /*
894  *      Free detail-specific stuff.
895  */
896 void detail_free(rad_listen_t *this)
897 {
898         listen_detail_t *data = this->data;
899
900 #ifdef WITH_DETAIL_THREAD
901         if (!check_config) {
902                 ssize_t ret;
903                 void *arg = NULL;
904
905                 /*
906                  *      Mark the child pipes as unusable
907                  */
908                 close(data->child_pipe[0]);
909                 close(data->child_pipe[1]);
910                 data->child_pipe[0] = -1;
911
912                 /*
913                  *      Tell it to stop (interrupting its sleep)
914                  */
915                 pthread_kill(data->pthread_id, SIGTERM);
916
917                 /*
918                  *      Wait for it to acknowledge that it's stopped.
919                  */
920                 ret = read(data->master_pipe[0], &arg, sizeof(arg));
921                 if (ret < 0) {
922                         ERROR("detail (%s): Reader thread exited without informing the master: %s",
923                               data->name, fr_syserror(errno));
924                 } else if (ret != sizeof(arg)) {
925                         ERROR("detail (%s): Invalid thread pointer received from reader thread during exit",
926                               data->name);
927                         ERROR("detail (%s): Expected %zu bytes, got %zi bytes", data->name, sizeof(arg), ret);
928                 }
929
930                 close(data->master_pipe[0]);
931                 close(data->master_pipe[1]);
932
933                 if (arg) pthread_join(data->pthread_id, &arg);
934         }
935 #endif
936
937         if (data->fp != NULL) {
938                 fclose(data->fp);
939                 data->fp = NULL;
940         }
941 }
942
943
944 int detail_print(rad_listen_t const *this, char *buffer, size_t bufsize)
945 {
946         if (!this->server) {
947                 return snprintf(buffer, bufsize, "%s",
948                                 ((listen_detail_t *)(this->data))->filename);
949         }
950
951         return snprintf(buffer, bufsize, "detail file %s as server %s",
952                         ((listen_detail_t *)(this->data))->filename,
953                         this->server);
954 }
955
956
957 /*
958  *      Delay while waiting for a file to be ready
959  */
960 static int detail_delay(listen_detail_t *data)
961 {
962         int delay = (data->poll_interval - 1) * USEC;
963
964         /*
965          *      Add +/- 0.25s of jitter
966          */
967         delay += (USEC * 3) / 4;
968         delay += fr_rand() % (USEC / 2);
969
970         DEBUG2("detail (%s): Detail listener state %s waiting %d.%06d sec",
971                data->name,
972                fr_int2str(state_names, data->state, "?"),
973                (delay / USEC), delay % USEC);
974
975         return delay;
976 }
977
978 /*
979  *      Overloaded to return delay times.
980  */
981 int detail_encode(UNUSED rad_listen_t *this, UNUSED REQUEST *request)
982 {
983 #ifdef WITH_DETAIL_THREAD
984         return 0;
985 #else
986         listen_detail_t *data = this->data;
987
988         /*
989          *      We haven't sent a packet... delay things a bit.
990          */
991         if (!data->signal) return detail_delay(data);
992
993         data->signal = 0;
994
995         DEBUG2("detail (%s): Detail listener state %s signalled %d waiting %d.%06d sec",
996                data->name,
997                fr_int2str(state_names, data->state, "?"),
998                data->signal,
999                data->delay_time / USEC,
1000                data->delay_time % USEC);
1001
1002         return data->delay_time;
1003 #endif
1004 }
1005
1006 /*
1007  *      Overloaded to return "should we fix delay times"
1008  */
1009 int detail_decode(UNUSED rad_listen_t *this, UNUSED REQUEST *request)
1010 {
1011 #ifdef WITH_DETAIL_THREAD
1012         return 0;
1013 #else
1014         listen_detail_t *data = this->data;
1015
1016         return data->signal;
1017 #endif
1018 }
1019
1020
1021 #ifdef WITH_DETAIL_THREAD
1022 static void *detail_handler_thread(void *arg)
1023 {
1024         char c;
1025         rad_listen_t *this = arg;
1026         listen_detail_t *data = this->data;
1027
1028         while (true) {
1029                 RADIUS_PACKET *packet;
1030
1031                 while ((packet = detail_poll(this)) == NULL) {
1032                         usleep(detail_delay(data));
1033
1034                         /*
1035                          *      If we're supposed to exit then tell
1036                          *      the master thread we've exited.
1037                          */
1038                         if (data->child_pipe[0] < 0) {
1039                                 packet = NULL;
1040                                 if (write(data->master_pipe[1], &packet, sizeof(packet)) < 0) {
1041                                         ERROR("detail (%s): Failed writing exit status to master: %s",
1042                                               data->name, fr_syserror(errno));
1043                                 }
1044                                 return NULL;
1045                         }
1046                 }
1047
1048                 /*
1049                  *      Keep retrying forever.
1050                  *
1051                  *      FIXME: cap the retries.
1052                  */
1053                 do {
1054                         if (write(data->master_pipe[1], &packet, sizeof(packet)) < 0) {
1055                                 ERROR("detail (%s): Failed passing detail packet pointer to master: %s",
1056                                       data->name, fr_syserror(errno));
1057                         }
1058
1059                         if (read(data->child_pipe[0], &c, 1) < 0) {
1060                                 ERROR("detail (%s): Failed getting detail packet ack from master: %s",
1061                                       data->name, fr_syserror(errno));
1062                                 break;
1063                         }
1064
1065                         if (data->delay_time > 0) usleep(data->delay_time);
1066
1067                         packet = detail_poll(this);
1068                         if (!packet) break;
1069                 } while (data->state != STATE_REPLIED);
1070         }
1071
1072         return NULL;
1073 }
1074 #endif
1075
1076
1077 static const CONF_PARSER detail_config[] = {
1078         { "detail", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_DEPRECATED, listen_detail_t, filename), NULL },
1079         { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, listen_detail_t, filename), NULL },
1080         { "load_factor", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_detail_t, load_factor), STRINGIFY(10) },
1081         { "poll_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_detail_t, poll_interval), STRINGIFY(1) },
1082         { "retry_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_detail_t, retry_interval), STRINGIFY(30) },
1083         { "one_shot", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, listen_detail_t, one_shot), "no" },
1084         { "track", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, listen_detail_t, track), "no" },
1085
1086         { NULL, -1, 0, NULL, NULL }             /* end the list */
1087 };
1088
1089 /*
1090  *      Parse a detail section.
1091  */
1092 int detail_parse(CONF_SECTION *cs, rad_listen_t *this)
1093 {
1094         int             rcode;
1095         listen_detail_t *data;
1096         RADCLIENT       *client;
1097         char            buffer[2048];
1098
1099         data = this->data;
1100
1101         rcode = cf_section_parse(cs, data, detail_config);
1102         if (rcode < 0) {
1103                 cf_log_err_cs(cs, "Failed parsing listen section");
1104                 return -1;
1105         }
1106
1107         data->name = cf_section_name2(cs);
1108         if (!data->name) data->name = data->filename;
1109
1110         /*
1111          *      We don't do duplicate detection for "detail" sockets.
1112          */
1113         this->nodup = true;
1114         this->synchronous = false;
1115
1116         if (!data->filename) {
1117                 cf_log_err_cs(cs, "No detail file specified in listen section");
1118                 return -1;
1119         }
1120
1121         FR_INTEGER_BOUND_CHECK("load_factor", data->load_factor, >=, 1);
1122         FR_INTEGER_BOUND_CHECK("load_factor", data->load_factor, <=, 100);
1123
1124         FR_INTEGER_BOUND_CHECK("poll_interval", data->poll_interval, >=, 1);
1125         FR_INTEGER_BOUND_CHECK("poll_interval", data->poll_interval, <=, 60);
1126
1127         FR_INTEGER_BOUND_CHECK("retry_interval", data->retry_interval, >=, 4);
1128         FR_INTEGER_BOUND_CHECK("retry_interval", data->retry_interval, <=, 3600);
1129
1130         /*
1131          *      Only checking the config.  Don't start threads or anything else.
1132          */
1133         if (check_config) return 0;
1134
1135         /*
1136          *      If the filename is a glob, use "detail.work" as the
1137          *      work file name.
1138          */
1139         if ((strchr(data->filename, '*') != NULL) ||
1140             (strchr(data->filename, '[') != NULL)) {
1141                 char *p;
1142
1143 #ifndef HAVE_GLOB_H
1144                 WARN("detail (%s): File \"%s\" appears to use file globbing, but it is not supported on this system",
1145                      data->name, data->filename);
1146 #endif
1147                 strlcpy(buffer, data->filename, sizeof(buffer));
1148                 p = strrchr(buffer, FR_DIR_SEP);
1149                 if (p) {
1150                         p[1] = '\0';
1151                 } else {
1152                         buffer[0] = '\0';
1153                 }
1154                 strlcat(buffer, "detail.work",
1155                         sizeof(buffer) - strlen(buffer));
1156
1157         } else {
1158                 snprintf(buffer, sizeof(buffer), "%s.work", data->filename);
1159         }
1160
1161         data->filename_work = talloc_strdup(data, buffer);
1162
1163         data->work_fd = -1;
1164         data->vps = NULL;
1165         data->fp = NULL;
1166         data->state = STATE_UNOPENED;
1167         data->delay_time = data->poll_interval * USEC;
1168         data->signal = 1;
1169
1170         /*
1171          *      Initialize the fake client.
1172          */
1173         client = &data->detail_client;
1174         memset(client, 0, sizeof(*client));
1175         client->ipaddr.af = AF_INET;
1176         client->ipaddr.ipaddr.ip4addr.s_addr = INADDR_NONE;
1177         client->ipaddr.prefix = 0;
1178         client->longname = client->shortname = data->filename;
1179         client->secret = client->shortname;
1180         client->nas_type = talloc_strdup(data, "none"); /* Part of 'data' not dynamically allocated */
1181
1182 #ifdef WITH_DETAIL_THREAD
1183         /*
1184          *      Create the communication pipes.
1185          */
1186         if (pipe(data->master_pipe) < 0) {
1187                 ERROR("detail (%s): Error opening internal pipe: %s", data->name, fr_syserror(errno));
1188                 fr_exit(1);
1189         }
1190
1191         if (pipe(data->child_pipe) < 0) {
1192                 ERROR("detail (%s): Error opening internal pipe: %s", data->name, fr_syserror(errno));
1193                 fr_exit(1);
1194         }
1195
1196         pthread_create(&data->pthread_id, NULL, detail_handler_thread, this);
1197
1198         this->fd = data->master_pipe[0];
1199 #endif
1200
1201         return 0;
1202 }
1203 #endif