1 /*
2  * Copyright (c) 2022 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 <stdbool.h>
17 
18 #include "softbus_conn_br_pending_packet.h"
19 
20 #include "common_list.h"
21 #include "conn_log.h"
22 #include "softbus_adapter_mem.h"
23 #include "softbus_conn_br_connection.h"
24 #include "softbus_conn_br_trans.h"
25 #include "softbus_def.h"
26 
27 typedef struct {
28     ListNode node;
29     uint32_t id;
30     int64_t seq;
31     void *data;
32     bool finded;
33     SoftBusCond cond;
34     SoftBusMutex lock;
35 } PendingPacket;
36 
37 static SoftBusMutex g_pendingLock;
38 static LIST_HEAD(g_pendingList);
39 
ConnBrInitBrPendingPacket(void)40 int32_t ConnBrInitBrPendingPacket(void)
41 {
42     if (SoftBusMutexInit(&g_pendingLock, NULL) != 0) {
43         return SOFTBUS_LOCK_ERR;
44     }
45     return SOFTBUS_OK;
46 }
47 
ConnBrCreateBrPendingPacket(uint32_t id,int64_t seq)48 int32_t ConnBrCreateBrPendingPacket(uint32_t id, int64_t seq)
49 {
50     if (SoftBusMutexLock(&g_pendingLock) != SOFTBUS_OK) {
51         return SOFTBUS_LOCK_ERR;
52     }
53     PendingPacket *pending = NULL;
54     LIST_FOR_EACH_ENTRY(pending, &g_pendingList, PendingPacket, node) {
55         if (pending->id == id && pending->seq == seq) {
56             CONN_LOGW(CONN_BR, "PendingPacket exist, id=%{public}u, seq=%{public}" PRId64, id, seq);
57             (void)SoftBusMutexUnlock(&g_pendingLock);
58             return SOFTBUS_ALREADY_EXISTED;
59         }
60     }
61     pending = (PendingPacket *)SoftBusCalloc(sizeof(PendingPacket));
62     if (pending == NULL) {
63         CONN_LOGE(CONN_BR, "calloc failed, id=%{public}u, seq=%{public}" PRId64, id, seq);
64         (void)SoftBusMutexUnlock(&g_pendingLock);
65         return SOFTBUS_MALLOC_ERR;
66     }
67     ListInit(&pending->node);
68     pending->id = id;
69     pending->seq = seq;
70     pending->data = NULL;
71     pending->finded = false;
72     if (SoftBusMutexInit(&pending->lock, NULL) != SOFTBUS_OK) {
73         SoftBusFree(pending);
74         (void)SoftBusMutexUnlock(&g_pendingLock);
75         return SOFTBUS_LOCK_ERR;
76     }
77     if (SoftBusCondInit(&pending->cond) != SOFTBUS_OK) {
78         SoftBusMutexDestroy(&pending->lock);
79         SoftBusFree(pending);
80         (void)SoftBusMutexUnlock(&g_pendingLock);
81         return SOFTBUS_NO_INIT;
82     }
83     ListTailInsert(&g_pendingList, &(pending->node));
84     (void)SoftBusMutexUnlock(&g_pendingLock);
85     return SOFTBUS_OK;
86 }
87 
ConnBrDelBrPendingPacket(uint32_t id,int64_t seq)88 void ConnBrDelBrPendingPacket(uint32_t id, int64_t seq)
89 {
90     if (SoftBusMutexLock(&g_pendingLock) != SOFTBUS_OK) {
91         return;
92     }
93     PendingPacket *pending = NULL;
94     LIST_FOR_EACH_ENTRY(pending, &g_pendingList, PendingPacket, node) {
95         if (pending->id == id && pending->seq == seq) {
96             ListDelete(&pending->node);
97             SoftBusCondSignal(&pending->cond);
98             SoftBusMutexDestroy(&pending->lock);
99             SoftBusCondDestroy(&pending->cond);
100             SoftBusFree(pending);
101             break;
102         }
103     }
104     (void)SoftBusMutexUnlock(&g_pendingLock);
105 }
106 
ConnBrGetBrPendingPacket(uint32_t id,int64_t seq,uint32_t waitMillis,void ** data)107 int32_t ConnBrGetBrPendingPacket(uint32_t id, int64_t seq, uint32_t waitMillis, void **data)
108 {
109 #define USECTONSEC 1000LL
110     CONN_CHECK_AND_RETURN_RET_LOGW(data != NULL, SOFTBUS_INVALID_PARAM, CONN_BR, "invalid param");
111     CONN_CHECK_AND_RETURN_RET_LOGW(SoftBusMutexLock(&g_pendingLock) == SOFTBUS_OK, SOFTBUS_LOCK_ERR,
112         CONN_BR, "lock failed");
113     PendingPacket *pending = NULL;
114     PendingPacket *item = NULL;
115     LIST_FOR_EACH_ENTRY(item, &g_pendingList, PendingPacket, node) {
116         if (item->id == id && item->seq == seq) {
117             pending = item;
118         }
119     }
120     if (pending == NULL) {
121         (void)SoftBusMutexUnlock(&g_pendingLock);
122         return SOFTBUS_NOT_FIND;
123     }
124     (void)SoftBusMutexUnlock(&g_pendingLock);
125 
126     int32_t ret = SOFTBUS_OK;
127     if (SoftBusMutexLock(&pending->lock) != SOFTBUS_OK) {
128         ret = SOFTBUS_LOCK_ERR;
129         goto EXIT;
130     }
131     if (pending->finded) {
132         *data = pending->data;
133         ret = SOFTBUS_ALREADY_TRIGGERED;
134     } else {
135         SoftBusSysTime outtime;
136         SoftBusSysTime now;
137         (void)SoftBusGetTime(&now);
138         int64_t time = (now.sec * USECTONSEC * USECTONSEC + now.usec + (int64_t)(waitMillis * USECTONSEC));
139         outtime.sec = time / USECTONSEC / USECTONSEC;
140         outtime.usec = time % (USECTONSEC * USECTONSEC);
141         (void)SoftBusCondWait(&pending->cond, &pending->lock, &outtime);
142         if (pending->finded) {
143             *data = pending->data;
144         } else {
145             ret = SOFTBUS_TIMOUT;
146         }
147     }
148     (void)SoftBusMutexUnlock(&pending->lock);
149 EXIT:
150     (void)SoftBusMutexLock(&g_pendingLock);
151     ListDelete(&pending->node);
152     SoftBusMutexDestroy(&pending->lock);
153     SoftBusCondDestroy(&pending->cond);
154     SoftBusFree(pending);
155     (void)SoftBusMutexUnlock(&g_pendingLock);
156     return ret;
157 }
158 
ConnBrSetBrPendingPacket(uint32_t id,int64_t seq,void * data)159 int32_t ConnBrSetBrPendingPacket(uint32_t id, int64_t seq, void *data)
160 {
161     PendingPacket *item = NULL;
162     if (SoftBusMutexLock(&g_pendingLock) != SOFTBUS_OK) {
163         CONN_LOGE(CONN_BR, "lock failed");
164         return SOFTBUS_LOCK_ERR;
165     }
166     LIST_FOR_EACH_ENTRY(item, &g_pendingList, PendingPacket, node) {
167         if (item->seq == seq && item->id == id) {
168             if (SoftBusMutexLock(&item->lock) != SOFTBUS_OK) {
169                 SoftBusMutexUnlock(&g_pendingLock);
170                 return SOFTBUS_LOCK_ERR;
171             }
172             item->finded = true;
173             item->data = data;
174             SoftBusCondSignal(&item->cond);
175             SoftBusMutexUnlock(&item->lock);
176             SoftBusMutexUnlock(&g_pendingLock);
177             return SOFTBUS_OK;
178         }
179     }
180     SoftBusMutexUnlock(&g_pendingLock);
181     return SOFTBUS_CONN_BR_SET_PENDING_PACKET_ERR;
182 }
183 
ConnBrOnAckRequest(ConnBrConnection * connection,const cJSON * json)184 int32_t ConnBrOnAckRequest(ConnBrConnection *connection, const cJSON *json)
185 {
186     CONN_CHECK_AND_RETURN_RET_LOGW(connection != NULL, SOFTBUS_INVALID_PARAM, CONN_BR, "invalid param");
187     int32_t peerWindows = 0;
188     int64_t peerSeq = 0;
189     if (!GetJsonObjectSignedNumberItem(json, KEY_WINDOWS, &peerWindows) ||
190         !GetJsonObjectNumber64Item(json, KEY_ACK_SEQ_NUM, &peerSeq)) {
191         CONN_LOGE(CONN_BR, "parse window or seq failed, connId=%{public}u", connection->connectionId);
192         return SOFTBUS_PARSE_JSON_ERR;
193     }
194 
195     int32_t status = SoftBusMutexLock(&connection->lock);
196     if (status != SOFTBUS_OK) {
197         CONN_LOGE(CONN_BR, "lock failed, connId=%{public}u, error=%{public}d", connection->connectionId, status);
198         return SOFTBUS_LOCK_ERR;
199     }
200 
201     int32_t localWindows = connection->window;
202     (void)SoftBusMutexUnlock(&connection->lock);
203 
204     CONN_LOGD(CONN_BR,
205         "ack request message: connId=%{public}u, localWindow=%{public}d, peerWindow=%{public}d, "
206         "peerSeq=%{public}" PRId64,
207         connection->connectionId, localWindows, peerWindows, peerSeq);
208 
209     int32_t flag = CONN_HIGH;
210     BrCtlMessageSerializationContext ctx = {
211         .connectionId = connection->connectionId,
212         .flag = flag,
213         .method = BR_METHOD_ACK_RESPONSE,
214         .ackRequestResponse = {
215             .window = localWindows,
216             .seq = peerSeq,
217         },
218     };
219     uint8_t *data = NULL;
220     uint32_t dataLen = 0;
221     int64_t seq = ConnBrPackCtlMessage(ctx, &data, &dataLen);
222     if (seq < 0) {
223         CONN_LOGE(CONN_BR,
224             "pack msg failed: connId=%{public}u, localWindow=%{public}d, peeWindow=%{public}d, "
225             "peerSeq=%{public}" PRId64 ", error=%{public}d",
226             connection->connectionId, localWindows, peerWindows, peerSeq, (int32_t)seq);
227         return (int32_t)seq;
228     }
229     return ConnBrPostBytes(connection->connectionId, data, dataLen, 0, flag, MODULE_CONNECTION, seq);
230 }
231 
ConnBrOnAckResponse(ConnBrConnection * connection,const cJSON * json)232 int32_t ConnBrOnAckResponse(ConnBrConnection *connection, const cJSON *json)
233 {
234     int32_t peerWindows = 0;
235     uint64_t seq = 0;
236     if (!GetJsonObjectSignedNumberItem(json, KEY_WINDOWS, &peerWindows) ||
237         !GetJsonObjectNumber64Item(json, KEY_ACK_SEQ_NUM, (int64_t *)&seq)) {
238         CONN_LOGE(CONN_BR, "parse window or seq fields failed, connId=%{public}u", connection->connectionId);
239         return SOFTBUS_PARSE_JSON_ERR;
240     }
241     CONN_LOGD(CONN_BR, "connId=%{public}u, peerWindow=%{public}d, seq=%{public}" PRId64, connection->connectionId,
242         peerWindows, seq);
243     int32_t status = ConnBrSetBrPendingPacket(connection->connectionId, (int64_t)seq, NULL);
244     if (status != SOFTBUS_OK) {
245         CONN_LOGE(CONN_BR,
246             "set br pending packet failed, connId=%{public}u, error=%{public}d", connection->connectionId, status);
247     }
248     return status;
249 }
250