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