xref: /haiku/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPReportManager.cpp (revision 9eb55bc1d104b8fda80898f8b25c94d8000c8255)
1 //-----------------------------------------------------------------------
2 //  This software is part of the OpenBeOS distribution and is covered
3 //  by the OpenBeOS license.
4 //
5 //  Copyright (c) 2003-2004 Waldemar Kornewald, Waldemar.Kornewald@web.de
6 //-----------------------------------------------------------------------
7 
8 #include <KPPPReportManager.h>
9 #include <LockerHelper.h>
10 
11 #include <KPPPUtils.h>
12 
13 
14 KPPPReportManager::KPPPReportManager(BLocker& lock)
15 	: fLock(lock)
16 {
17 }
18 
19 
20 KPPPReportManager::~KPPPReportManager()
21 {
22 	for(int32 index = 0; index < fReportRequests.CountItems(); index++)
23 		delete fReportRequests.ItemAt(index);
24 }
25 
26 
27 void
28 KPPPReportManager::EnableReports(ppp_report_type type, thread_id thread,
29 	int32 flags = PPP_NO_FLAGS)
30 {
31 	LockerHelper locker(fLock);
32 
33 	ppp_report_request *request = new ppp_report_request;
34 	request->type = type;
35 	request->thread = thread;
36 	request->flags = flags;
37 
38 	fReportRequests.AddItem(request);
39 }
40 
41 
42 void
43 KPPPReportManager::DisableReports(ppp_report_type type, thread_id thread)
44 {
45 	LockerHelper locker(fLock);
46 
47 	ppp_report_request *request;
48 
49 	for(int32 i = 0; i < fReportRequests.CountItems(); i++) {
50 		request = fReportRequests.ItemAt(i);
51 
52 		if(request->thread != thread)
53 			continue;
54 
55 		if(request->type == type || request->type == PPP_ALL_REPORTS)
56 			fReportRequests.RemoveItem(request);
57 	}
58 }
59 
60 
61 bool
62 KPPPReportManager::DoesReport(ppp_report_type type, thread_id thread)
63 {
64 	LockerHelper locker(fLock);
65 
66 	ppp_report_request *request;
67 
68 	for(int32 i = 0; i < fReportRequests.CountItems(); i++) {
69 		request = fReportRequests.ItemAt(i);
70 
71 		if(request->thread == thread && request->type == type)
72 			return true;
73 	}
74 
75 	return false;
76 }
77 
78 
79 bool
80 KPPPReportManager::Report(ppp_report_type type, int32 code, void *data, int32 length)
81 {
82 #if DEBUG
83 	dprintf("KPPPReportManager: Report(type=%d code=%ld length=%ld) to %ld receivers\n",
84 		type, code, length, fReportRequests.CountItems());
85 #endif
86 
87 	if(length > PPP_REPORT_DATA_LIMIT)
88 		return false;
89 
90 	if(fReportRequests.CountItems() == 0)
91 		return true;
92 
93 	if(!data)
94 		length = 0;
95 
96 	LockerHelper locker(fLock);
97 
98 	status_t result;
99 	thread_id sender, me = find_thread(NULL);
100 	bool acceptable = true;
101 
102 	ppp_report_packet report;
103 	report.type = type;
104 	report.code = code;
105 	report.length = length;
106 	memcpy(report.data, data, length);
107 
108 	ppp_report_request *request;
109 
110 	for(int32 index = 0; index < fReportRequests.CountItems(); index++) {
111 		request = fReportRequests.ItemAt(index);
112 
113 		// do not send to yourself
114 		if(request->thread == me)
115 			continue;
116 
117 		result = send_data_with_timeout(request->thread, PPP_REPORT_CODE, &report,
118 			sizeof(report), PPP_REPORT_TIMEOUT);
119 
120 #if DEBUG
121 	if(result == B_TIMED_OUT)
122 		dprintf("KPPPReportManager::Report(): timed out sending\n");
123 #endif
124 
125 		if(result == B_BAD_THREAD_ID || result == B_NO_MEMORY) {
126 			fReportRequests.RemoveItem(request);
127 			--index;
128 			continue;
129 		} else if(result == B_OK) {
130 			if(request->flags & PPP_WAIT_FOR_REPLY) {
131 				thread_info info;
132 
133 				if(request->flags & PPP_NO_REPLY_TIMEOUT) {
134 					sender = -1;
135 					result = B_ERROR;
136 					// always check if the thread still exists
137 					while(sender != request->thread
138 							&& get_thread_info(request->thread, &info)
139 								!= B_BAD_THREAD_ID) {
140 						result = receive_data_with_timeout(&sender, &code, NULL, 0,
141 							PPP_REPORT_TIMEOUT);
142 
143 						if(request->flags & PPP_ALLOW_ANY_REPLY_THREAD)
144 							sender = request->thread;
145 					}
146 				} else {
147 					sender = -1;
148 					result = B_OK;
149 					while(sender != request->thread && result == B_OK) {
150 						result = receive_data_with_timeout(&sender, &code, NULL, 0,
151 							PPP_REPORT_TIMEOUT);
152 
153 						if(request->flags & PPP_ALLOW_ANY_REPLY_THREAD)
154 							sender = request->thread;
155 					}
156 				}
157 
158 				if(result == B_OK && code != B_OK)
159 					acceptable = false;
160 #if DEBUG
161 				if(result == B_TIMED_OUT)
162 					dprintf("KPPPReportManager::Report(): reply timed out\n");
163 #endif
164 			}
165 		}
166 
167 		if(request->flags & PPP_REMOVE_AFTER_REPORT) {
168 			fReportRequests.RemoveItem(request);
169 			--index;
170 		}
171 	}
172 
173 #if DEBUG
174 	dprintf("KPPPReportManager::Report(): returning: %s\n", acceptable?"true":"false");
175 #endif
176 
177 	return acceptable;
178 }
179