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