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