xref: /haiku/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPReportManager.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
1 /*
2  * Copyright 2003-2007, Waldemar Kornewald <wkornew@gmx.net>
3  * Distributed under the terms of the MIT License.
4  */
5 
6 /*!	\class KPPPReportManager
7 	\brief Manager for PPP reports and report requests.
8 */
9 
10 #include <KPPPReportManager.h>
11 
12 #include <lock.h>
13 #include <util/AutoLock.h>
14 
15 #include <KPPPUtils.h>
16 
17 
18 typedef struct report_sender_info {
19 	thread_id thread;
20 	ppp_report_packet report;
21 } report_sender_info;
22 
23 
24 static status_t
25 report_sender_thread(void *data)
26 {
27 	report_sender_info *info = static_cast<report_sender_info*>(data);
28 	KPPPReportManager::SendReport(info->thread, &info->report);
29 	delete info;
30 	return B_OK;
31 }
32 
33 
34 /*!	\brief Constructor.
35 
36 	\param lock The BLocker that should be used by this report manager.
37 */
38 KPPPReportManager::KPPPReportManager(mutex& lock)
39 	: fLock(lock)
40 {
41 }
42 
43 
44 //!	Deletes all report requests.
45 KPPPReportManager::~KPPPReportManager()
46 {
47 	for (int32 index = 0; index < fReportRequests.CountItems(); index++)
48 		delete fReportRequests.ItemAt(index);
49 }
50 
51 
52 /*!	\brief Send the given report message to the given thread.
53 
54 	\param thread The report receiver.
55 	\param report The report message.
56 
57 	\return \c false on error.
58 */
59 bool
60 KPPPReportManager::SendReport(thread_id thread, const ppp_report_packet *report)
61 {
62 	if (!report)
63 		return false;
64 
65 	if (thread == find_thread(NULL)) {
66 		report_sender_info *info = new report_sender_info;
67 		info->thread = thread;
68 		memcpy(&info->report, report, sizeof(ppp_report_packet));
69 		resume_thread(spawn_kernel_thread(report_sender_thread, "PPP: ReportSender",
70 			B_NORMAL_PRIORITY, info));
71 		return true;
72 	}
73 
74 	send_data_with_timeout(thread, PPP_REPORT_CODE, &report, sizeof(report),
75 		PPP_REPORT_TIMEOUT);
76 	return true;
77 }
78 
79 
80 /*!	\brief Requests report messages of a given \a type.
81 
82 	\param type The type of report.
83 	\param thread The receiver thread.
84 	\param flags Optional report flags. See \c ppp_report_flags for more information.
85 */
86 void
87 KPPPReportManager::EnableReports(ppp_report_type type, thread_id thread,
88 	int32 flags)
89 {
90 	if (thread < 0 || type == PPP_ALL_REPORTS)
91 		return;
92 
93 	MutexLocker locker(fLock);
94 
95 	ppp_report_request *request = new ppp_report_request;
96 	request->type = type;
97 	request->thread = thread;
98 	request->flags = flags;
99 
100 	fReportRequests.AddItem(request);
101 }
102 
103 
104 //!	Removes a report request.
105 void
106 KPPPReportManager::DisableReports(ppp_report_type type, thread_id thread)
107 {
108 	if (thread < 0)
109 		return;
110 
111 	MutexLocker locker(fLock);
112 
113 	ppp_report_request *request;
114 
115 	for (int32 i = 0; i < fReportRequests.CountItems(); i++) {
116 		request = fReportRequests.ItemAt(i);
117 
118 		if (request->thread != thread)
119 			continue;
120 
121 		if (request->type == type || type == PPP_ALL_REPORTS)
122 			fReportRequests.RemoveItem(request);
123 	}
124 
125 	// empty message queue
126 	while (has_data(thread)) {
127 		thread_id sender;
128 		receive_data(&sender, NULL, 0);
129 	}
130 }
131 
132 
133 //!	Returns if we report messages of a given \a type to the given \a thread.
134 bool
135 KPPPReportManager::DoesReport(ppp_report_type type, thread_id thread)
136 {
137 	if (thread < 0)
138 		return false;
139 
140 	MutexLocker locker(fLock);
141 
142 	ppp_report_request *request;
143 
144 	for (int32 i = 0; i < fReportRequests.CountItems(); i++) {
145 		request = fReportRequests.ItemAt(i);
146 
147 		if (request->thread == thread && request->type == type)
148 			return true;
149 	}
150 
151 	return false;
152 }
153 
154 
155 /*!	\brief Send out report messages to all requestors.
156 
157 	You may append additional data to the report messages. The data length may not be
158 	greater than \c PPP_REPORT_DATA_LIMIT.
159 
160 	\param type The report type.
161 	\param code The report code belonging to the report type.
162 	\param data Additional data.
163 	\param length Length of the data.
164 
165 	\return \c false on error.
166 */
167 bool
168 KPPPReportManager::Report(ppp_report_type type, int32 code, void *data, int32 length)
169 {
170 	TRACE("KPPPReportManager: Report(type=%d code=%ld length=%ld) to %ld receivers\n",
171 		type, code, length, fReportRequests.CountItems());
172 
173 	if (length > PPP_REPORT_DATA_LIMIT)
174 		return false;
175 
176 	if (fReportRequests.CountItems() == 0)
177 		return true;
178 
179 	if (!data)
180 		length = 0;
181 
182 	MutexLocker locker(fLock);
183 
184 	status_t result;
185 	thread_id me = find_thread(NULL);
186 
187 	ppp_report_packet report;
188 	report.type = type;
189 	report.code = code;
190 	report.length = length;
191 	memcpy(report.data, data, length);
192 
193 	ppp_report_request *request;
194 
195 	for (int32 index = 0; index < fReportRequests.CountItems(); index++) {
196 		request = fReportRequests.ItemAt(index);
197 
198 		// do not send to yourself
199 		if (request->thread == me)
200 			continue;
201 
202 		result = send_data_with_timeout(request->thread, PPP_REPORT_CODE, &report,
203 			sizeof(report), PPP_REPORT_TIMEOUT);
204 
205 #if DEBUG
206 		if (result == B_TIMED_OUT)
207 			TRACE("KPPPReportManager::Report(): timed out sending\n");
208 #endif
209 
210 		if (result == B_BAD_THREAD_ID || result == B_NO_MEMORY
211 				|| request->flags & PPP_REMOVE_AFTER_REPORT) {
212 			fReportRequests.RemoveItem(request);
213 			--index;
214 			continue;
215 		}
216 	}
217 
218 	return true;
219 }
220