2 * Copyright (c) 2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <utilities/SecCFWrappers.h>
27 #include "secd_regressions.h"
28 #include "SOSTestDataSource.h"
30 #include "SOSRegressionUtilities.h"
32 static int kTestTestCount
= 10;
33 static int MAX_PENALTY_TIME
= 32;
35 struct monitor_traffic
{
38 int total_consecutive_attempts
;
39 int last_write_timestamp
;
42 static void clear_penalty(struct monitor_traffic
*monitor
){
43 monitor
->penalty_box
= 0;
44 monitor
->total_consecutive_attempts
= 0;
45 monitor
->last_write_timestamp
= 0;
47 static int increase_penalty(int time
){
56 static int decrease_penalty(int time
){
65 //calculate new penalty time based off time passed
66 static void calculate_new_penalty(struct monitor_traffic
*monitor
, int current_time
){
67 int difference
= current_time
- monitor
->last_write_timestamp
;
70 if(difference
>= monitor
->penalty_box
* 2){
71 monitor
->penalty_box
= decrease_penalty(monitor
->penalty_box
);
72 difference
=- monitor
->penalty_box
*2;
79 static void keychain_changed_notification(struct monitor_traffic
*monitor
){
80 clear_penalty(monitor
);
83 static void initialize_monitor(struct monitor_traffic
*monitor
){
84 monitor
->key
= CFSTR("ak|alskdfj:a;lskdjf");
85 monitor
->penalty_box
= 0;
86 monitor
->total_consecutive_attempts
= 0;
87 monitor
->last_write_timestamp
= 0;
90 static int backoff_algorithm(CFArrayRef timestamps
, struct monitor_traffic
*monitor
)
92 __block
int successful_writes
= 0;
93 CFNumberRef timestamp
;
95 CFArrayForEachC(timestamps
, timestamp
) {
97 if(!CFNumberGetValue(timestamp
, kCFNumberSInt32Type
, ¤t_time
))
98 return successful_writes
;
100 if(monitor
->last_write_timestamp
== 0){ //successful default case, initially sending to another peer
103 else if(current_time
== 0){ //keychain changed notification fired
104 keychain_changed_notification(monitor
);
108 if(monitor
->last_write_timestamp
== (current_time
-1) && monitor
->total_consecutive_attempts
>= 4){
109 monitor
->penalty_box
= increase_penalty(monitor
->penalty_box
);
110 monitor
->total_consecutive_attempts
++;
112 else if(monitor
->last_write_timestamp
== (current_time
-1) && monitor
->total_consecutive_attempts
< 4 ){
113 monitor
->total_consecutive_attempts
++;
114 if(monitor
->penalty_box
== 0)
117 else if((current_time
- monitor
->last_write_timestamp
) >= (2*monitor
->penalty_box
)){ //we haven't written consecutively for 2* the penalty time
118 monitor
->total_consecutive_attempts
= 0;
119 calculate_new_penalty(monitor
, current_time
);
122 else if((current_time
- monitor
->last_write_timestamp
) <= (2*monitor
->penalty_box
)){ //nonconsecutive write came in within the penalty time
123 monitor
->penalty_box
= increase_penalty(monitor
->penalty_box
);
124 if(monitor
->last_write_timestamp
!= (current_time
-1))
125 monitor
->total_consecutive_attempts
= 0;
127 monitor
->total_consecutive_attempts
++;
130 if(current_time
!= 0)
131 monitor
->last_write_timestamp
= current_time
;
134 return successful_writes
;
137 static void tests(void)
139 struct monitor_traffic
*monitor
= (struct monitor_traffic
*)malloc(sizeof(struct monitor_traffic
));
140 initialize_monitor(monitor
);
141 CFMutableArrayRef write_attempts
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
142 CFNumberRef timestamp
= NULL
;
146 * first test: peer continuously writes for 12 minutes
148 for(int i
= 1; i
< 13; i
++){
149 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &i
);
150 CFArrayAppendValue(write_attempts
, timestamp
);
151 CFReleaseNull(timestamp
);
153 int successful_writes
= backoff_algorithm(write_attempts
, monitor
);
154 ok(successful_writes
== 5, "successfull writes should have only reached 5 minutes");
155 ok(monitor
->penalty_box
== MAX_PENALTY_TIME
, "penalty box should have maxed out to 32 minutes");
158 initialize_monitor(monitor
);
159 CFArrayRemoveAllValues(write_attempts
);
162 * first test: peer continuously writes for 12 minutes, then backs off 2*(max penalty timeout)
164 for(int i
= 1; i
< 13; i
++){
165 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &i
);
166 CFArrayAppendValue(write_attempts
, timestamp
);
167 CFReleaseNull(timestamp
);
170 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
171 CFArrayAppendValue(write_attempts
, timestamp
);
173 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
174 CFArrayAppendValue(write_attempts
, timestamp
);
175 successful_writes
= backoff_algorithm(write_attempts
, monitor
);
176 ok(successful_writes
== 7, "successfull writes should have only reached 6"); //5 initial writes, then 1 write after enough time passes
177 ok(monitor
->penalty_box
== (MAX_PENALTY_TIME
/4), "penalty box should have maxed out to 16 minutes");
180 initialize_monitor(monitor
);
181 CFArrayRemoveAllValues(write_attempts
);
184 * first test: peer continuously writes for 12 minutes, then backs off exponentially until everything effectively resets
187 for(int i
= 1; i
< 13; i
++){
188 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &i
);
189 CFArrayAppendValue(write_attempts
, timestamp
);
190 CFReleaseNull(timestamp
);
193 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
194 CFArrayAppendValue(write_attempts
, timestamp
);
196 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
197 CFArrayAppendValue(write_attempts
, timestamp
);
199 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
200 CFArrayAppendValue(write_attempts
, timestamp
);
202 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
203 CFArrayAppendValue(write_attempts
, timestamp
);
205 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
206 CFArrayAppendValue(write_attempts
, timestamp
);
208 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
209 CFArrayAppendValue(write_attempts
, timestamp
);
211 successful_writes
= backoff_algorithm(write_attempts
, monitor
);
212 ok(successful_writes
== 11, "successfull writes should have only reached 11");
213 ok(monitor
->penalty_box
== 0, "penalty box should reset back to 0");
216 initialize_monitor(monitor
);
217 CFArrayRemoveAllValues(write_attempts
);
220 * first test: peer continuously writes for 12 minutes, then backs off exponentially until everything effectively resets
223 for(int i
= 1; i
< 13; i
++){
224 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &i
);
225 CFArrayAppendValue(write_attempts
, timestamp
);
226 CFReleaseNull(timestamp
);
228 time
= 0; //flag that keychain changed notification fired
229 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
230 CFArrayAppendValue(write_attempts
, timestamp
);
232 for(int i
= 1; i
< 13; i
++){
233 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &i
);
234 CFArrayAppendValue(write_attempts
, timestamp
);
235 CFReleaseNull(timestamp
);
238 successful_writes
= backoff_algorithm(write_attempts
, monitor
);
239 ok(successful_writes
== 10, "successfull writes should have only reached 10");
240 ok(monitor
->penalty_box
== MAX_PENALTY_TIME
, "penalty box should reset back to 0");
243 initialize_monitor(monitor
);
244 CFArrayRemoveAllValues(write_attempts
);
247 * first test: peer continuously writes for 5 minutes, then attempts to write again for another 5 minutes, the once much later
249 for(int i
= 1; i
< 6; i
++){
250 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &i
);
251 CFArrayAppendValue(write_attempts
, timestamp
);
252 CFReleaseNull(timestamp
);
255 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
256 CFArrayAppendValue(write_attempts
, timestamp
);
258 for(int i
= 100; i
< 106; i
++){
259 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &i
);
260 CFArrayAppendValue(write_attempts
, timestamp
);
261 CFReleaseNull(timestamp
);
264 timestamp
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &time
);
265 CFArrayAppendValue(write_attempts
, timestamp
);
267 successful_writes
= backoff_algorithm(write_attempts
, monitor
);
268 ok(successful_writes
== 12, "successfull writes should have only reached 10");
269 ok(monitor
->penalty_box
== 0, "penalty box should reset back to 0");
272 int secd_154_engine_backoff(int argc
, char *const *argv
)
274 plan_tests(kTestTestCount
);