File: pcaptxttagstats.cpp

package info (click to toggle)
ostinato 1.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 4,840 kB
  • sloc: cpp: 46,226; makefile: 8
file content (190 lines) | stat: -rw-r--r-- 5,516 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
Copyright (C) 2023 Srivats P.

This file is part of "Ostinato"

This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

#include "pcaptxttagstats.h"

#include "pcapextra.h"
#include "../common/debugdefs.h"
#include "../common/sign.h"
#include "streamtiming.h"

#define Xnotify qWarning // FIXME

PcapTxTtagStats::PcapTxTtagStats(const char *device, int id)
    : portId_(id)
{
    setObjectName(QString("TxT$:%1").arg(device));
    device_ = QString::fromLatin1(device);

    timing_ = StreamTiming::instance();
}

void PcapTxTtagStats::run()
{
    int flags = PCAP_OPENFLAG_PROMISCUOUS;
    char errbuf[PCAP_ERRBUF_SIZE] = "";
    struct bpf_program bpf;
    const int optimize = 1;
    QString capture_filter = QString(
            "(ether[len - 4:4] == 0x%1) and (ether[len - 5:1] == 0x%2)")
            .arg(SignProtocol::magic(), 0, BASE_HEX)
            .arg(SignProtocol::kTypeLenTtag, 0, BASE_HEX);

    qDebug("In %s", __PRETTY_FUNCTION__);
    qDebug("pcap-filter: %s", qPrintable(capture_filter));

    handle_ = pcap_open_live(qPrintable(device_), 65535,
                    flags, 100 /* ms */, errbuf);
    if (!handle_) {
        if (flags && QString(errbuf).contains("promiscuous")) {
            Xnotify("Unable to set promiscuous mode on <%s> - "
                    "stream stats time tracking will not work", qPrintable(device_));
            goto _exit;
        }
        else {
            Xnotify("Unable to open <%s> [%s] - stream stats rx will not work",
                    qPrintable(device_), errbuf);
            goto _exit;
        }
    }

#ifdef Q_OS_WIN32
    // pcap_setdirection() API is not supported in Windows.
    // NOTE: WinPcap 4.1.1 and above exports a dummy API that returns -1
    // but since we would like to work with previous versions of WinPcap
    // also, we assume the API does not exist
    isDirectional_ = false;
#else
    if (pcap_setdirection(handle_, PCAP_D_OUT) < 0) {
        qDebug("TxTtagStats: Error setting OUT direction %s: %s\n",
                qPrintable(device_), pcap_geterr(handle_));
        isDirectional_ = false;
    }
#endif

    if (pcap_compile(handle_, &bpf, qPrintable(capture_filter),
                     optimize, 0) < 0) {
        qWarning("%s: error compiling filter: %s", qPrintable(device_),
                pcap_geterr(handle_));
        goto _skip_filter;
    }

    if (pcap_setfilter(handle_, &bpf) < 0) {
        qWarning("%s: error setting filter: %s", qPrintable(device_),
                pcap_geterr(handle_));
        goto _skip_filter;
    }

_skip_filter:
    clearDebugStats();
    PcapSession::preRun();
    state_ = kRunning;
    while (1) {
        int ret;
        struct pcap_pkthdr *hdr;
        const uchar *data;

        ret = pcap_next_ex(handle_, &hdr, &data);
        switch (ret) {
            case 1: {
                uint ttagId;
                uint guid;
                if (SignProtocol::packetTtagId(data, hdr->caplen,
                        &ttagId, &guid)) {
#ifdef Q_OS_WIN32
                    // TxPort is NOT us ==> Rx Packet, so skip
                    // See similar check in PcapRxStats for details
                    if (ttagId >> 8 != uint(portId_))
                        break;
                    ttagId &= 0xFF;
#endif
                    timing_->recordTxTime(portId_, guid, ttagId, hdr->ts);
                }
                break;
            }
            case 0:
                // timeout: just go back to the loop
                break;
            case -1:
                qWarning("%s: error reading packet (%d): %s",
                        __PRETTY_FUNCTION__, ret, pcap_geterr(handle_));
                break;
            case -2:
                qDebug("%s: Loop/signal break or some other error",
                        __PRETTY_FUNCTION__);
                break;
            default:
                qWarning("%s: Unexpected return value %d",
                        __PRETTY_FUNCTION__, ret);
                stop_ = true;
        }

        if (stop_) {
            qDebug("user requested txTtagStats stop");
            break;
        }
    }
    PcapSession::postRun();
    pcap_close(handle_);
    handle_ = NULL;
    stop_ = false;

_exit:
    state_ = kFinished;
}

bool PcapTxTtagStats::start()
{
    if (state_ == kRunning) {
        qWarning("TxTtagStats start requested but is already running!");
        goto _exit;
    }

    state_ = kNotStarted;
    PcapSession::start();

    while (state_ == kNotStarted)
        QThread::msleep(10);
_exit:
    return true;
}

bool PcapTxTtagStats::stop()
{
    if (state_ == kRunning) {
        stop_ = true;
        PcapSession::stop();
        while (state_ == kRunning)
            QThread::msleep(10);
    }
    else
        qWarning("TxTtagStats stop requested but is not running!");

    return true;
}

bool PcapTxTtagStats::isRunning()
{
    return (state_ == kRunning);
}

bool PcapTxTtagStats::isDirectional()
{
    return isDirectional_;
}