invalid packets since the packet will not be validated against it's protocol.
- \section packet_usage_fields Protocol fields
+ \section packet_usage_fields Field access
When working with concrete protocols, the packet library provides direct access to all the
protocol information.
This is a very abstract description of the parser structure. For a more concrete description, we
need to differentiate between the different parser types
- \subsection packet_usage_fields_value Value parsers
+ \subsection packet_usage_fields_value Simple fields (Value parsers)
We have already seen value parsers: These are the lowest level building blocks witch parse
numbers, addresses etc. They return some type of value and can be assigned such a value. More
Remember, that a parser does \e not contain any data: It only points into the raw data
container. This is also true for the collection parsers. VectorParser and ListParser provide an
- interface which looks like an STL container to access the elements.
+ interface which looks like an STL container to access a sequence of elements.
- We will use an MLDv2 Query as an example (see <a
- href="http://tools.ietf.org/html/rfc3810#section-5">RFC 3810</a>).
+ We will use an \c MLDv2QueryPacket as an example (see <a
+ href="http://tools.ietf.org/html/rfc3810#section-5">RFC 3810</a>). Here an excerpt of the
+ relevant fields:
+
+ <table class="fields">
+ <tr><td>nrOfSources</td><td>Integer</td><td>Number of multicast sources in this packet</td></tr>
+ <tr><td>sources</td><td>Vector of IPv6 Addresses</td><td>Multicast sources</td></tr>
+ </table>
+
+ To demonstrate nested collections, we use the \c MLDv2ReportPacket as an example. The relevant
+ fields of this packet are;
+
+ <table class="fields">
+ <tr><td>nrOfRecords</td><td>Integer</td><td>Number of multicast address records</td></tr>
+ <tr><td>records</td><td>List of Records</td><td>List of multicast groups and sources</td></tr>
+ </table>
+
+ Each Record is a composite with the following relevant fields:
+
+ <table class="fields">
+ <tr><td>nrSources</td><td>Integer</td><td>Number of sources in this record</td></tr>
+ <tr><td>sources</td><td>Vector of IPv6 Addresses</td><td>Multicast sources</td></tr>
+ </table>
+
+ The first example will iterate over the sources in a \c MLDv2QueryPacket:
\code
MLDv2QueryPacket mld = ...;
Beside other fields, the MLDv2Query consists of a list of source addresses. The \c sources()
member returns a VectorParser for these addresses. The collection parsers can only be accessed
- completely using a container wrapper. This is, what we do in above example.
+ completely using a container wrapper. The container wrapper type is available as the \c
+ container member of the collection parser, here it is \c
+ MLDv2QueryPacket::Parser::sources_t::container.
- The wrapper can also be used to manipulate that list. Here we copy a list of addresses from an
- \c std::vector into the packet:
+ Using this wrapper, we can not only read the data, we can also manipulate the source list. Here
+ we copy a list of addresses from an \c std::vector into the packet:
\code
std::vector<senf::INet6Address> addrs (...);
std::copy(addrs.begin(), addrs.end(), sources.begin())
\endcode
- Collection parsers may also be nested. To access a nested collection parser, such a container
- wrapper should be allocated for each level. An MLD Report (which is a composite parser) includes
- a list of multicast address records called \c records(). Each record is again a composite which
- contains a list of sources called \c sources():
+ Collection parsers may be nested. To access a nested collection parser, a container wrapper must
+ be allocated for each level. An MLD Report (which is a composite parser) includes a list of
+ multicast address records called \c records(). Each record is again a composite which contains a
+ list of sources called \c sources():
\code
MLDv2ReportPacket report = ...;
///////////////////////////////cc.p////////////////////////////////////////
prefix_ senf::scheduler::FIFORunner::FIFORunner()
- : tasks_ (), next_ (tasks_.end()), hangCount_ (0)
+ : tasks_ (), next_ (tasks_.end()), watchdogMs_ (1000), watchdogCount_(0), hangCount_ (0)
{
struct sigevent ev;
::memset(&ev, 0, sizeof(ev));
TaskList::iterator end (TaskList::current(null));
next_ = tasks_.begin();
struct itimerspec timer;
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_nsec = 0;
- timer.it_value.tv_sec = 1;
- timer.it_value.tv_nsec = 0;
+ timer.it_interval.tv_sec = watchdogMs_ / 1000;
+ timer.it_interval.tv_nsec = (watchdogMs_ % 1000) * 1000000ul;
+ timer.it_value.tv_sec = timer.it_interval.tv_sec;
+ timer.it_value.tv_nsec = timer.it_interval.tv_nsec;
+ if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
+ SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
while (next_ != end) {
TaskInfo & task (*next_);
if (task.runnable) {
task.runnable = false;
- if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
- SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
runningName_ = task.name;
# ifdef SENF_DEBUG
runningBacktrace_ = task.backtrace;
TaskList::iterator i (next_);
++ next_;
tasks_.splice(tasks_.end(), tasks_, i);
+ watchdogCount_ = 1;
task.run();
}
else
++ next_;
}
+ watchdogCount_ = 0;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_nsec = 0;
timer.it_value.tv_sec = 0;
+ timer.it_value.tv_nsec = 0;
if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
tasks_.erase(end);
prefix_ void senf::scheduler::FIFORunner::watchdog(int, siginfo_t * si, void *)
{
FIFORunner & runner (*static_cast<FIFORunner *>(si->si_value.sival_ptr));
- ++ runner.hangCount_;
- write(1, "\n\n*** Scheduler task hanging: ", 30);
- write(1, runner.runningName_.c_str(), runner.runningName_.size());
- write(1, "\n", 1);
+ if (runner.watchdogCount_ > 0) {
+ ++ runner.watchdogCount_;
+ if (runner.watchdogCount_ > 2) {
+ ++ runner.hangCount_;
+ write(1, "\n\n*** Scheduler task hanging: ", 30);
+ write(1, runner.runningName_.c_str(), runner.runningName_.size());
+ write(1, "\n", 1);
#ifdef SENF_DEBUG
- write(1, "Task was initialized at\n", 24);
- write(1, runner.runningBacktrace_.c_str(), runner.runningBacktrace_.size());
+ write(1, "Task was initialized at\n", 24);
+ write(1, runner.runningBacktrace_.c_str(), runner.runningBacktrace_.size());
#endif
- write(1, "\n", 1);
+ write(1, "\n", 1);
+ }
+ }
}
///////////////////////////////cc.e////////////////////////////////////////
#endif
}
+prefix_ void senf::scheduler::FIFORunner::taskTimeout(unsigned ms)
+{
+ watchdogMs_ = ms;
+}
+
+prefix_ unsigned senf::scheduler::FIFORunner::taskTimeout()
+ const
+{
+ return watchdogMs_;
+}
+
prefix_ unsigned senf::scheduler::FIFORunner::hangCount()
const
{
void run(); ///< Run queue
+ void taskTimeout(unsigned ms); ///< Set task timeout to \a ms milliseconds
+ unsigned taskTimeout() const; ///< Get task timeout in milliseconds
+
unsigned hangCount() const; ///< Number of task expirations
/**< The FIFORunner manages a watchdog which checks, that a
single task does not run continuously for a longer time
TaskList tasks_;
TaskList::iterator next_;
timer_t watchdogId_;
+ unsigned watchdogMs_;
std::string runningName_;
# ifdef SENF_DEBUG
std::string runningBacktrace_;
# endif
+ unsigned watchdogCount_;
unsigned hangCount_;
};
return manager_.eventTime();
}
+prefix_ void senf::Scheduler::taskTimeout(unsigned ms)
+{
+ runner_.taskTimeout(ms);
+}
+
+prefix_ unsigned senf::Scheduler::taskTimeout()
+ const
+{
+ return runner_.taskTimeout();
+}
+
prefix_ unsigned senf::Scheduler::hangCount()
const
{
delivered \e not the time it should have been delivered
(in the case of timers). */
+ void taskTimeout(unsigned ms);
+ unsigned taskTimeout() const;
unsigned hangCount() const;
protected:
void blockingHandler()
{
- delay(1200);
+ delay(2200);
Scheduler::instance().terminate();
}
font-weight: bold;
}
+table.fields {
+ width: 95%;
+ margin: 10pt auto;
+ border: 1px solid #AAAAAA;
+ padding: 2px;
+ border-spacing: 0;
+}
+
+table.fields td,th {
+ border: 2px solid white;
+ background-color: #EEEEEE;
+ padding: 2px 4px;
+ text-align: left;
+ vertical-align: top;
+}
+
+table.fields th {
+ background-color: #DDDDDD;
+ text-align: center;
+ font-weight: bold;
+}
+
+table.fields td:first-child {
+ width: 25%;
+ font-style: italic;
+}
+
table.fixedcolumn td:first-child {
width: 35%;
}