* Copyright 2003-2007, Waldemar Kornewald <wkornew@gmx.net>
* Distributed under the terms of the MIT License.
*/
\brief Manager for PPP reports and report requests.
*/
#include <KPPPReportManager.h>
#include <lock.h>
#include <util/AutoLock.h>
#include <KPPPUtils.h>
typedef struct report_sender_info {
thread_id thread;
ppp_report_packet report;
} report_sender_info;
static status_t
report_sender_thread(void *data)
{
report_sender_info *info = static_cast<report_sender_info*>(data);
KPPPReportManager::SendReport(info->thread, &info->report);
delete info;
return B_OK;
}
\param lock The BLocker that should be used by this report manager.
*/
KPPPReportManager::KPPPReportManager(mutex& lock)
: fLock(lock)
{
}
KPPPReportManager::~KPPPReportManager()
{
for (int32 index = 0; index < fReportRequests.CountItems(); index++)
delete fReportRequests.ItemAt(index);
}
\param thread The report receiver.
\param report The report message.
\return \c false on error.
*/
bool
KPPPReportManager::SendReport(thread_id thread, const ppp_report_packet *report)
{
if (!report)
return false;
if (thread == find_thread(NULL)) {
report_sender_info *info = new report_sender_info;
info->thread = thread;
memcpy(&info->report, report, sizeof(ppp_report_packet));
resume_thread(spawn_kernel_thread(report_sender_thread, "PPP: ReportSender",
B_NORMAL_PRIORITY, info));
return true;
}
send_data_with_timeout(thread, PPP_REPORT_CODE, &report, sizeof(report),
PPP_REPORT_TIMEOUT);
return true;
}
\param type The type of report.
\param thread The receiver thread.
\param flags Optional report flags. See \c ppp_report_flags for more information.
*/
void
KPPPReportManager::EnableReports(ppp_report_type type, thread_id thread,
int32 flags)
{
if (thread < 0 || type == PPP_ALL_REPORTS)
return;
MutexLocker locker(fLock);
ppp_report_request *request = new ppp_report_request;
request->type = type;
request->thread = thread;
request->flags = flags;
fReportRequests.AddItem(request);
}
void
KPPPReportManager::DisableReports(ppp_report_type type, thread_id thread)
{
if (thread < 0)
return;
MutexLocker locker(fLock);
ppp_report_request *request;
for (int32 i = 0; i < fReportRequests.CountItems(); i++) {
request = fReportRequests.ItemAt(i);
if (request->thread != thread)
continue;
if (request->type == type || type == PPP_ALL_REPORTS)
fReportRequests.RemoveItem(request);
}
while (has_data(thread)) {
thread_id sender;
receive_data(&sender, NULL, 0);
}
}
bool
KPPPReportManager::DoesReport(ppp_report_type type, thread_id thread)
{
if (thread < 0)
return false;
MutexLocker locker(fLock);
ppp_report_request *request;
for (int32 i = 0; i < fReportRequests.CountItems(); i++) {
request = fReportRequests.ItemAt(i);
if (request->thread == thread && request->type == type)
return true;
}
return false;
}
You may append additional data to the report messages. The data length may not be
greater than \c PPP_REPORT_DATA_LIMIT.
\param type The report type.
\param code The report code belonging to the report type.
\param data Additional data.
\param length Length of the data.
\return \c false on error.
*/
bool
KPPPReportManager::Report(ppp_report_type type, int32 code, void *data, int32 length)
{
TRACE("KPPPReportManager: Report(type=%d code=%ld length=%ld) to %ld receivers\n",
type, code, length, fReportRequests.CountItems());
if (length > PPP_REPORT_DATA_LIMIT)
return false;
if (fReportRequests.CountItems() == 0)
return true;
if (!data)
length = 0;
MutexLocker locker(fLock);
status_t result;
thread_id me = find_thread(NULL);
ppp_report_packet report;
report.type = type;
report.code = code;
report.length = length;
memcpy(report.data, data, length);
ppp_report_request *request;
for (int32 index = 0; index < fReportRequests.CountItems(); index++) {
request = fReportRequests.ItemAt(index);
if (request->thread == me)
continue;
result = send_data_with_timeout(request->thread, PPP_REPORT_CODE, &report,
sizeof(report), PPP_REPORT_TIMEOUT);
#if DEBUG
if (result == B_TIMED_OUT)
TRACE("KPPPReportManager::Report(): timed out sending\n");
#endif
if (result == B_BAD_THREAD_ID || result == B_NO_MEMORY
|| request->flags & PPP_REMOVE_AFTER_REPORT) {
fReportRequests.RemoveItem(request);
--index;
continue;
}
}
return true;
}