1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "softbus_conn_flow_control.h"
17
18 #include "conn_log.h"
19 #include "softbus_adapter_mem.h"
20 #include "softbus_adapter_timer.h"
21
22 typedef uint64_t timestamp_t;
23 struct HistoryNode {
24 ListNode node;
25
26 timestamp_t timestamp;
27 int32_t amount;
28 };
29
Apply(struct ConnSlideWindowController * self,int32_t expect)30 static int32_t Apply(struct ConnSlideWindowController *self, int32_t expect)
31 {
32 CONN_CHECK_AND_RETURN_RET_LOGE(self, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid parameter, controller is null");
33
34 int32_t status = SoftBusMutexLock(&self->lock);
35 CONN_CHECK_AND_RETURN_RET_LOGE(status == SOFTBUS_OK, SOFTBUS_LOCK_ERR, CONN_COMMON, "lock failed");
36 if (!self->active) {
37 (void)SoftBusMutexUnlock(&self->lock);
38 return expect;
39 }
40 struct HistoryNode *it = NULL;
41 struct HistoryNode *next = NULL;
42 int32_t appliedTotal = 0;
43 timestamp_t now = SoftBusGetSysTimeMs();
44 timestamp_t expiredTimestamp = now - (timestamp_t)self->windowInMillis;
45 timestamp_t currentWindowStartTimestamp = 0;
46 LIST_FOR_EACH_ENTRY_SAFE(it, next, &self->histories, struct HistoryNode, node) {
47 if (it->timestamp > expiredTimestamp) {
48 appliedTotal += it->amount;
49 currentWindowStartTimestamp = it->timestamp;
50 } else {
51 ListDelete(&it->node);
52 SoftBusFree(it);
53 }
54 }
55
56 if (self->quotaInBytes <= appliedTotal) {
57 unsigned int sleepMs = (timestamp_t)self->windowInMillis - (now - currentWindowStartTimestamp);
58 (void)SoftBusMutexUnlock(&self->lock);
59 SoftBusSleepMs(sleepMs);
60 return Apply(self, expect);
61 }
62 int32_t remain = self->quotaInBytes - appliedTotal;
63 int32_t amount = remain > expect ? expect : remain;
64 struct HistoryNode *history = SoftBusCalloc(sizeof(*history));
65 if (history == NULL) {
66 (void)SoftBusMutexUnlock(&self->lock);
67 return expect;
68 }
69 ListInit(&history->node);
70 history->amount = amount;
71 history->timestamp = now;
72 ListAdd(&self->histories, &history->node);
73
74 (void)SoftBusMutexUnlock(&self->lock);
75 return amount;
76 }
77
CleanupHistoriesUnsafe(struct ConnSlideWindowController * self)78 static void CleanupHistoriesUnsafe(struct ConnSlideWindowController *self)
79 {
80 struct HistoryNode *it = NULL;
81 struct HistoryNode *next = NULL;
82 LIST_FOR_EACH_ENTRY_SAFE(it, next, &self->histories, struct HistoryNode, node) {
83 ListDelete(&it->node);
84 SoftBusFree(it);
85 }
86 }
87
ChangeConfiguration(struct ConnSlideWindowController * self,bool active,int32_t windowInMillis,int32_t quotaInBytes)88 static int32_t ChangeConfiguration(
89 struct ConnSlideWindowController *self, bool active, int32_t windowInMillis, int32_t quotaInBytes)
90 {
91 CONN_CHECK_AND_RETURN_RET_LOGE(self, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid parameter, controller is null");
92 if (active) {
93 CONN_CHECK_AND_RETURN_RET_LOGE(windowInMillis >= MIN_WINDOW_IN_MILLIS && windowInMillis <= MAX_WINDOW_IN_MILLIS,
94 SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid parameter, window=%u", windowInMillis);
95 CONN_CHECK_AND_RETURN_RET_LOGE(quotaInBytes >= MIN_QUOTA_IN_BYTES && quotaInBytes <= MAX_QUOTA_IN_BYTES,
96 SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid parameter, quota=%u", quotaInBytes);
97 }
98
99 int32_t status = SoftBusMutexLock(&self->lock);
100 CONN_CHECK_AND_RETURN_RET_LOGE(status == SOFTBUS_OK, SOFTBUS_LOCK_ERR, CONN_COMMON, "lock failed");
101
102 self->windowInMillis = windowInMillis;
103 self->quotaInBytes = quotaInBytes;
104 self->active = active;
105 // cleanup histories as configuration change
106 CleanupHistoriesUnsafe(self);
107 (void)SoftBusMutexUnlock(&self->lock);
108 return SOFTBUS_OK;
109 }
110
Enable(struct ConnSlideWindowController * self,int32_t windowInMillis,int32_t quotaInBytes)111 static int32_t Enable(struct ConnSlideWindowController *self, int32_t windowInMillis, int32_t quotaInBytes)
112 {
113 return ChangeConfiguration(self, true, windowInMillis, quotaInBytes);
114 }
115
Disable(struct ConnSlideWindowController * self)116 static int32_t Disable(struct ConnSlideWindowController *self)
117 {
118 return ChangeConfiguration(self, false, -1, -1);
119 }
120
ConnSlideWindowControllerConstructor(struct ConnSlideWindowController * self)121 int32_t ConnSlideWindowControllerConstructor(struct ConnSlideWindowController *self)
122 {
123 CONN_CHECK_AND_RETURN_RET_LOGE(self, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid parameter, controller is null");
124 int32_t ret = SoftBusMutexInit(&self->lock, NULL);
125 CONN_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, SOFTBUS_LOCK_ERR, CONN_COMMON, "init lock failed");
126
127 self->active = false;
128 self->windowInMillis = -1;
129 self->quotaInBytes = -1;
130 ListInit(&self->histories);
131
132 self->apply = Apply;
133 self->enable = Enable;
134 self->disable = Disable;
135 return SOFTBUS_OK;
136 }
137
ConnSlideWindowControllerDestructor(struct ConnSlideWindowController * self)138 void ConnSlideWindowControllerDestructor(struct ConnSlideWindowController *self)
139 {
140 CONN_CHECK_AND_RETURN_LOGE(self, CONN_COMMON, "invalid parameter, controller is null");
141 int32_t status = SoftBusMutexLock(&self->lock);
142 CONN_CHECK_AND_RETURN_LOGE(status == SOFTBUS_OK, CONN_COMMON, "lock failed");
143 CleanupHistoriesUnsafe(self);
144 SoftBusMutexDestroy(&self->lock);
145 }
146
ConnSlideWindowControllerNew(void)147 struct ConnSlideWindowController *ConnSlideWindowControllerNew(void)
148 {
149 struct ConnSlideWindowController *controller = SoftBusCalloc(sizeof(*controller));
150 CONN_CHECK_AND_RETURN_RET_LOGE(controller, NULL, CONN_COMMON, "alloc failed");
151
152 int32_t ret = ConnSlideWindowControllerConstructor(controller);
153 if (ret != SOFTBUS_OK) {
154 SoftBusFree(controller);
155 return NULL;
156 }
157 return controller;
158 }
159
ConnSlideWindowControllerDelete(struct ConnSlideWindowController * self)160 void ConnSlideWindowControllerDelete(struct ConnSlideWindowController *self)
161 {
162 ConnSlideWindowControllerDestructor(self);
163 SoftBusFree(self);
164 }
165