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
report_sender_thread(void * data)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 */
KPPPReportManager(mutex & lock)38 KPPPReportManager::KPPPReportManager(mutex& lock)
39 : fLock(lock)
40 {
41 }
42
43
44 //! Deletes all report requests.
~KPPPReportManager()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
SendReport(thread_id thread,const ppp_report_packet * report)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
EnableReports(ppp_report_type type,thread_id thread,int32 flags)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
DisableReports(ppp_report_type type,thread_id thread)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
DoesReport(ppp_report_type type,thread_id thread)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
Report(ppp_report_type type,int32 code,void * data,int32 length)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