1 /*****************************************************************************
2 * mrtg-cnt.c Handle dvb TS packets and count them for MRTG
3 *****************************************************************************
4 * Copyright Tripleplay service 2004,2005,2011
6 * Author: Andy Lindsay <a.lindsay@tripleplay-services.com>
8 * This program 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 2 of the License, or
11 * (at your option) any later version.
13 * This program 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.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /* vim: set shiftwidth=4 tabstop=4 expandtab autoindent : */
30 #include <sys/types.h>
39 static FILE *mrtg_fh
= NULL
;
42 static long long l_mrtg_packets
= 0; // Packets received
43 static long long l_mrtg_seq_err_packets
= 0; // Out of sequence packets received
44 static long long l_mrtg_error_packets
= 0; // Packets received with the error flag set
45 static long long l_mrtg_scram_packets
= 0; // Scrambled Packets received
49 static LARGE_INTEGER mrtg_time
;
50 static LARGE_INTEGER mrtg_inc
;
52 static struct timeval mrtg_time
= { 0, 0 };
55 // Define the dump period in seconds
56 #define MRTG_INTERVAL 10
58 // Pid sequence numbers
60 static signed char i_pid_seq
[PIDS
];
62 // Report the mrtg counters: bytes received, error packets & sequence errors
63 static void dumpCounts()
65 unsigned int multiplier
= 1; //MRTG_INTERVAL;
68 fprintf(mrtg_fh
, "%lld %lld %lld %lld\n",
69 l_mrtg_packets
* 188 * multiplier
,
70 l_mrtg_error_packets
* multiplier
,
71 l_mrtg_seq_err_packets
* multiplier
,
72 l_mrtg_scram_packets
* multiplier
);
77 // analyse the input block counting packets and errors
78 // The input is a pointer to a block_t structure, which might be a linked list
79 // of blocks. Each block has one TS packet.
80 void mrtgAnalyse(block_t
* p_ts
)
83 block_t
*p_block
= p_ts
;
85 if (mrtg_fh
== NULL
) return;
87 while (p_block
!= NULL
) {
88 uint8_t *ts_packet
= p_block
->p_ts
;
90 char i_seq
, i_last_seq
;
93 if (ts_packet
[0] != 0x47) {
94 l_mrtg_error_packets
++;
95 p_block
= p_block
->p_next
;
99 if (ts_packet
[1] & 0x80) {
100 l_mrtg_error_packets
++;
101 p_block
= p_block
->p_next
;
105 i_pid
= (ts_packet
[1] & 0x1f) << 8 | ts_packet
[2];
107 // Just count null packets - don't check the sequence numbering
108 if (i_pid
== 0x1fff) {
109 p_block
= p_block
->p_next
;
113 if (ts_packet
[3] & 0xc0) {
114 l_mrtg_scram_packets
++;
116 // Check the sequence numbering
117 i_seq
= ts_packet
[3] & 0xf;
118 i_last_seq
= i_pid_seq
[i_pid
];
120 if (i_last_seq
== -1) {
121 // First packet - ignore the sequence
122 } else if (ts_packet
[3] & 0x10) {
123 // Packet contains payload - sequence should be up by one
124 if (i_seq
!= ((i_last_seq
+ 1) & 0x0f)) {
125 l_mrtg_seq_err_packets
++;
128 // Packet contains no payload - sequence should be unchanged
129 if (i_seq
!= i_last_seq
) {
130 l_mrtg_seq_err_packets
++;
133 i_pid_seq
[i_pid
] = i_seq
;
135 // Look at next block
136 p_block
= p_block
->p_next
;
139 // All blocks processed. See if we need to dump the stats
141 gettimeofday(&now
, NULL
);
142 if (timercmp(&now
, &mrtg_time
, >)) {
143 // Time to report the mrtg counters
146 // Set the timer for next time
148 // Normally we add the interval to the previous time so that if one
149 // dump is a bit late, the next one still occurs at the correct time.
150 // However, if there is a long gap (e.g. because the channel has
151 // stopped for some time), then just rebase the timing to the current
152 // time. I've chosen MRTG_INTERVAL as the long gap - this is arbitary
153 if ((now
.tv_sec
- mrtg_time
.tv_sec
) > MRTG_INTERVAL
) {
154 msg_Dbg(NULL
, "Dump is %d seconds late - reset timing\n",
155 (int) (now
.tv_sec
- mrtg_time
.tv_sec
));
158 mrtg_time
.tv_sec
+= MRTG_INTERVAL
;
162 int mrtgInit(char *mrtg_file
)
168 msg_Dbg(NULL
, "Opening mrtg file %s.\n", mrtg_file
);
169 if ((mrtg_fh
= fopen(mrtg_file
, "wb")) == NULL
) {
170 msg_Err(NULL
, "unable to open mrtg file");
173 // Initialise the file
174 fprintf(mrtg_fh
, "0 0 0 0\n");
177 // Initialise the sequence numbering
178 memset(&i_pid_seq
[0], -1, sizeof(signed char) * PIDS
);
180 // Set the reporting timer
181 gettimeofday(&mrtg_time
, NULL
);
182 mrtg_time
.tv_sec
+= MRTG_INTERVAL
;
189 // This is only for testing when using filetest.