xref: /haiku/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPReportManager.cpp (revision 5d9e40fe9252c8f9c5e5e41594545bfa4419fcc7)
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 	if(thread < 0 || type == PPP_ALL_REPORTS)
32 		return;
33 
34 	LockerHelper locker(fLock);
35 
36 	ppp_report_request *request = new ppp_report_request;
37 	request->type = type;
38 	request->thread = thread;
39 	request->flags = flags;
40 
41 	fReportRequests.AddItem(request);
42 }
43 
44 
45 void
46 KPPPReportManager::DisableReports(ppp_report_type type, thread_id thread)
47 {
48 	if(thread < 0)
49 		return;
50 
51 	LockerHelper locker(fLock);
52 
53 	ppp_report_request *request;
54 
55 	for(int32 i = 0; i < fReportRequests.CountItems(); i++) {
56 		request = fReportRequests.ItemAt(i);
57 
58 		if(request->thread != thread)
59 			continue;
60 
61 		if(request->type == type || type == PPP_ALL_REPORTS)
62 			fReportRequests.RemoveItem(request);
63 	}
64 }
65 
66 
67 bool
68 KPPPReportManager::DoesReport(ppp_report_type type, thread_id thread)
69 {
70 	if(thread < 0)
71 		return false;
72 
73 	LockerHelper locker(fLock);
74 
75 	ppp_report_request *request;
76 
77 	for(int32 i = 0; i < fReportRequests.CountItems(); i++) {
78 		request = fReportRequests.ItemAt(i);
79 
80 		if(request->thread == thread && request->type == type)
81 			return true;
82 	}
83 
84 	return false;
85 }
86 
87 
88 bool
89 KPPPReportManager::Report(ppp_report_type type, int32 code, void *data, int32 length)
90 {
91 #if DEBUG
92 	dprintf("KPPPReportManager: Report(type=%d code=%ld length=%ld) to %ld receivers\n",
93 		type, code, length, fReportRequests.CountItems());
94 #endif
95 
96 	if(length > PPP_REPORT_DATA_LIMIT)
97 		return false;
98 
99 	if(fReportRequests.CountItems() == 0)
100 		return true;
101 
102 	if(!data)
103 		length = 0;
104 
105 	LockerHelper locker(fLock);
106 
107 	status_t result;
108 	thread_id sender, me = find_thread(NULL);
109 	bool acceptable = true;
110 
111 	ppp_report_packet report;
112 	report.type = type;
113 	report.code = code;
114 	report.length = length;
115 	memcpy(report.data, data, length);
116 
117 	ppp_report_request *request;
118 
119 	for(int32 index = 0; index < fReportRequests.CountItems(); index++) {
120 		request = fReportRequests.ItemAt(index);
121 
122 		// do not send to yourself
123 		if(request->thread == me)
124 			continue;
125 
126 		result = send_data_with_timeout(request->thread, PPP_REPORT_CODE, &report,
127 			sizeof(report), PPP_REPORT_TIMEOUT);
128 
129 #if DEBUG
130 		if(result == B_TIMED_OUT)
131 			dprintf("KPPPReportManager::Report(): timed out sending\n");
132 #endif
133 
134 		thread_info info;
135 
136 		if(result == B_BAD_THREAD_ID || result == B_NO_MEMORY) {
137 			fReportRequests.RemoveItem(request);
138 			--index;
139 			continue;
140 		} else if(result == B_OK && request->flags & PPP_WAIT_FOR_REPLY) {
141 			if(request->flags & PPP_NO_REPLY_TIMEOUT) {
142 				sender = -1;
143 				result = B_ERROR;
144 				// always check if the thread still exists
145 				while(sender != request->thread
146 						&& get_thread_info(request->thread, &info) == B_OK) {
147 					result = receive_data_with_timeout(&sender, &code, NULL, 0,
148 						PPP_REPORT_TIMEOUT);
149 
150 					if(request->flags & PPP_ALLOW_ANY_REPLY_THREAD
151 							&& result == B_OK)
152 						sender = request->thread;
153 				}
154 			} else {
155 				sender = -1;
156 				result = B_OK;
157 				while(sender != request->thread && result == B_OK
158 						&& get_thread_info(request->thread, &info) == B_OK) {
159 					result = receive_data_with_timeout(&sender, &code, NULL, 0,
160 						PPP_REPORT_TIMEOUT);
161 
162 					if(request->flags & PPP_ALLOW_ANY_REPLY_THREAD)
163 						sender = request->thread;
164 				}
165 			}
166 
167 			if(sender != request->thread) {
168 #if DEBUG
169 				dprintf("KPPPReportManager::Report(): sender != requested\n");
170 #endif
171 				continue;
172 			}
173 
174 			if(result == B_OK && code != B_OK)
175 				acceptable = false;
176 #if DEBUG
177 			if(result == B_TIMED_OUT)
178 				dprintf("KPPPReportManager::Report(): reply timed out\n");
179 #endif
180 		}
181 
182 		// remove thread if it is not existant or if remove-flag is set
183 		if(request->flags & PPP_REMOVE_AFTER_REPORT
184 				|| get_thread_info(request->thread, &info) != B_OK) {
185 			fReportRequests.RemoveItem(request);
186 			--index;
187 		}
188 	}
189 
190 #if DEBUG
191 	dprintf("KPPPReportManager::Report(): returning: %s\n", acceptable?"true":"false");
192 #endif
193 
194 	return acceptable;
195 }
196