1/* 2 * Copyright 2003-2007, Waldemar Kornewald <wkornew@gmx.net> 3 * Distributed under the terms of the MIT License. 4 */ 5 6/*! \class PPPInterfaceListener 7 \brief This class simplifies the process of monitoring PPP interfaces. 8 9 PPPInterfaceListener converts all kernel report messages from the PPP stack 10 into BMessage objects and forwards them to the target BHandler.\n 11 The following values are added to each BMessage as int32 values: 12 - "interface" [\c int32] (optional): the interface ID of the affected interface 13 - "type" [\c int32]: the report type 14 - "code" [\c int32]: the report code 15*/ 16 17#include "PPPInterfaceListener.h" 18 19#include "PPPInterface.h" 20 21#include <Messenger.h> 22#include <Handler.h> 23#include <LockerHelper.h> 24#include <KPPPUtils.h> 25 26 27static const int32 kCodeQuitReportThread = 'QUIT'; 28 29 30// Creates a BMessage for each report and send it to the target BHandler. 31static 32status_t 33report_thread(void *data) 34{ 35 PPPInterfaceListener *listener = static_cast<PPPInterfaceListener*>(data); 36 37 ppp_report_packet report; 38 ppp_interface_id *interfaceID; 39 int32 code; 40 thread_id sender; 41 BMessage message; 42 43 while (true) { 44 code = receive_data(&sender, &report, sizeof(report)); 45 46 if (code == kCodeQuitReportThread) 47 break; 48 else if (code != PPP_REPORT_CODE) 49 continue; 50 51 BMessenger messenger(listener->Target()); 52 if (messenger.IsValid()) { 53 message.MakeEmpty(); 54 message.what = PPP_REPORT_MESSAGE; 55 message.AddInt32("type", report.type); 56 message.AddInt32("code", report.code); 57 58 if (report.length >= sizeof(ppp_interface_id) 59 && ((report.type == PPP_MANAGER_REPORT 60 && report.code == PPP_REPORT_INTERFACE_CREATED) 61 || report.type >= PPP_INTERFACE_REPORT_TYPE_MIN)) { 62 interfaceID = reinterpret_cast<ppp_interface_id*>(report.data); 63 message.AddInt32("interface", static_cast<int32>(*interfaceID)); 64 } 65 66 // We might cause a dead-lock. Thus, abort if we cannot send. 67 messenger.SendMessage(&message, (BHandler*) NULL, 100000); 68 } 69 } 70 71 return B_OK; 72} 73 74 75/*! \brief Constructs a new listener that sends report messages to \a target. 76 77 \param target The target BHandler which should receive report messages. 78*/ 79PPPInterfaceListener::PPPInterfaceListener(BHandler *target) 80 : fTarget(target), 81 fIsWatching(false), 82 fInterface(PPP_UNDEFINED_INTERFACE_ID) 83{ 84 Construct(); 85} 86 87 88//! Copy constructor. 89PPPInterfaceListener::PPPInterfaceListener(const PPPInterfaceListener& copy) 90 : fTarget(copy.Target()), 91 fIsWatching(false), 92 fInterface(PPP_UNDEFINED_INTERFACE_ID) 93{ 94 Construct(); 95} 96 97 98//! Removes all report message requests. 99PPPInterfaceListener::~PPPInterfaceListener() 100{ 101 // disable all report messages 102 StopWatchingInterface(); 103 StopWatchingManager(); 104 105 // tell thread to quit 106 send_data(fReportThread, kCodeQuitReportThread, NULL, 0); 107 int32 tmp; 108 wait_for_thread(fReportThread, &tmp); 109} 110 111 112/*! \brief Returns whether the listener was constructed correctly. 113 114 \return 115 - \c B_OK: No errors. 116 - \c B_ERROR: Some not defined error occured (like missing PPP stack). 117 - any other value: see \c PPPManager::InitCheck() 118 119 \sa PPPManager::InitCheck() 120*/ 121status_t 122PPPInterfaceListener::InitCheck() const 123{ 124 if (fReportThread < 0) 125 return B_ERROR; 126 127 return Manager().InitCheck(); 128} 129 130 131//! Changes the target BHandler for the report messages (may be \c NULL). 132void 133PPPInterfaceListener::SetTarget(BHandler *target) 134{ 135 fTarget = target; 136} 137 138 139/*! \brief Changes the interface being monitored. 140 141 This unregisters the old interface from the watch-list. 142 143 \param ID The ID of the interface you want to watch. 144 145 \return \c true on sucess, \c false on failure. 146*/ 147bool 148PPPInterfaceListener::WatchInterface(ppp_interface_id ID) 149{ 150 if (ID == fInterface) 151 return true; 152 153 StopWatchingInterface(); 154 155 if (ID == PPP_UNDEFINED_INTERFACE_ID) 156 return true; 157 158 // enable reports 159 PPPInterface interface(ID); 160 if (interface.InitCheck() != B_OK) 161 return false; 162 163 if (!interface.EnableReports(PPP_CONNECTION_REPORT, fReportThread, PPP_NO_FLAGS)) 164 return false; 165 166 fIsWatching = true; 167 fInterface = ID; 168 169 return true; 170} 171 172 173//! Enables interface creation messages from the PPP manager. 174void 175PPPInterfaceListener::WatchManager() 176{ 177 Manager().EnableReports(PPP_MANAGER_REPORT, fReportThread, PPP_NO_FLAGS); 178} 179 180 181/*! \brief Stops watching the interface. 182 183 Beware that this does not disable the PPP manager's report messages. 184*/ 185void 186PPPInterfaceListener::StopWatchingInterface() 187{ 188 if (!fIsWatching) 189 return; 190 191 PPPInterface interface(fInterface); 192 interface.DisableReports(PPP_ALL_REPORTS, fReportThread); 193 194 fIsWatching = false; 195 fInterface = PPP_UNDEFINED_INTERFACE_ID; 196} 197 198 199//! Disables interface creation messages from the PPP manager. 200void 201PPPInterfaceListener::StopWatchingManager() 202{ 203 Manager().DisableReports(PPP_ALL_REPORTS, fReportThread); 204} 205 206 207void 208PPPInterfaceListener::Construct() 209{ 210 fReportThread = spawn_thread(report_thread, "report_thread", B_NORMAL_PRIORITY, 211 this); 212 resume_thread(fReportThread); 213} 214