1 /*
2  * Copyright (c) 2022-2023 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 <inttypes.h>
17 #include <stdbool.h>
18 
19 #include "client_trans_pending.h"
20 
21 #include "common_list.h"
22 #include "softbus_adapter_mem.h"
23 #include "softbus_def.h"
24 #include "softbus_errcode.h"
25 #include "trans_log.h"
26 
27 typedef struct {
28     ListNode node;
29     uint32_t id;
30     uint64_t seq;
31     bool finded;
32     SoftBusCond cond;
33     SoftBusMutex lock;
34     TransPendData data;
35 } PendingPacket;
36 
37 static SoftBusMutex g_pendingLock;
38 static LIST_HEAD(g_pendingList);
39 
40 #define USECTONSEC 1000LL
41 
InitPendingPacket(void)42 int32_t InitPendingPacket(void)
43 {
44     if (SoftBusMutexInit(&g_pendingLock, NULL) != SOFTBUS_OK) {
45         return SOFTBUS_LOCK_ERR;
46     }
47     return SOFTBUS_OK;
48 }
49 
DestroyPendingPacket(void)50 void DestroyPendingPacket(void)
51 {
52     (void)SoftBusMutexDestroy(&g_pendingLock);
53 }
54 
CheckPendingPacketExisted(uint32_t id,uint64_t seq)55 static int32_t CheckPendingPacketExisted(uint32_t id, uint64_t seq)
56 {
57     if (SoftBusMutexLock(&g_pendingLock) != SOFTBUS_OK) {
58         TRANS_LOGE(TRANS_SDK, "Check pending packet is exist, lock error.");
59         return SOFTBUS_LOCK_ERR;
60     }
61     PendingPacket *pending = NULL;
62     LIST_FOR_EACH_ENTRY(pending, &g_pendingList, PendingPacket, node) {
63         if (pending->id == id && pending->seq == seq) {
64             TRANS_LOGE(TRANS_SDK, "PendingPacket existed. pendingId=%{public}u, pendingSeq=%{public}" PRIu64, id, seq);
65             (void)SoftBusMutexUnlock(&g_pendingLock);
66             return SOFTBUS_ALREADY_EXISTED;
67         }
68     }
69     (void)SoftBusMutexUnlock(&g_pendingLock);
70     return SOFTBUS_OK;
71 }
72 
CreatePendingPacket(uint32_t id,uint64_t seq)73 int32_t CreatePendingPacket(uint32_t id, uint64_t seq)
74 {
75     int32_t ret = CheckPendingPacketExisted(id, seq);
76     if (ret != SOFTBUS_OK) {
77         TRANS_LOGE(TRANS_SDK, "Check pending packet is exist, ret=%{public}d.", ret);
78         return ret;
79     }
80 
81     PendingPacket *pending = (PendingPacket *)SoftBusCalloc(sizeof(PendingPacket));
82     if (pending == NULL) {
83         TRANS_LOGE(TRANS_SDK, "SoftBusCalloc fail");
84         return SOFTBUS_MALLOC_ERR;
85     }
86     ListInit(&pending->node);
87     pending->id = id;
88     pending->seq = seq;
89     pending->data.data = NULL;
90     pending->data.len = 0;
91     pending->finded = false;
92     if (SoftBusMutexInit(&pending->lock, NULL) != SOFTBUS_OK) {
93         SoftBusFree(pending);
94         TRANS_LOGE(TRANS_SDK, "init lock fail");
95         return SOFTBUS_LOCK_ERR;
96     }
97     if (SoftBusCondInit(&pending->cond) != SOFTBUS_OK) {
98         TRANS_LOGE(TRANS_SDK, "condInit fail");
99         goto EXIT;
100     }
101     if (SoftBusMutexLock(&g_pendingLock) != SOFTBUS_OK) {
102         TRANS_LOGE(TRANS_SDK, "lock fail");
103         goto EXIT;
104     }
105     ListTailInsert(&g_pendingList, &(pending->node));
106     (void)SoftBusMutexUnlock(&g_pendingLock);
107     return SOFTBUS_OK;
108 EXIT:
109     SoftBusMutexDestroy(&pending->lock);
110     SoftBusFree(pending);
111     return SOFTBUS_NO_INIT;
112 }
113 
DeletePendingPacket(uint32_t id,uint64_t seq)114 void DeletePendingPacket(uint32_t id, uint64_t seq)
115 {
116     if (SoftBusMutexLock(&g_pendingLock) != SOFTBUS_OK) {
117         TRANS_LOGE(TRANS_SDK, "mutex lock fail");
118         return;
119     }
120     PendingPacket *pending = NULL;
121     LIST_FOR_EACH_ENTRY(pending, &g_pendingList, PendingPacket, node) {
122         if (pending->id == id && pending->seq == seq) {
123             ListDelete(&pending->node);
124             SoftBusCondSignal(&pending->cond);
125             SoftBusMutexDestroy(&pending->lock);
126             SoftBusCondDestroy(&pending->cond);
127             SoftBusFree(pending);
128             break;
129         }
130     }
131     (void)SoftBusMutexUnlock(&g_pendingLock);
132 }
133 
ComputeWaitPendTime(uint32_t waitMillis,SoftBusSysTime * outtime)134 static void ComputeWaitPendTime(uint32_t waitMillis, SoftBusSysTime *outtime)
135 {
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 }
142 
TransPendWaitTime(const PendingPacket * pending,TransPendData * data,uint32_t waitMillis)143 static int32_t TransPendWaitTime(const PendingPacket *pending, TransPendData *data, uint32_t waitMillis)
144 {
145     if (pending->finded) {
146         data->data = pending->data.data;
147         data->len = pending->data.len;
148         return SOFTBUS_ALREADY_TRIGGERED;
149     }
150     SoftBusSysTime outtime;
151     ComputeWaitPendTime(waitMillis, &outtime);
152     while (1) {
153         (void)SoftBusCondWait((SoftBusCond *)(&pending->cond), (SoftBusMutex *)(&pending->lock), &outtime);
154         if (pending->finded) {
155             data->data = pending->data.data;
156             data->len = pending->data.len;
157             return SOFTBUS_OK;
158         }
159         SoftBusSysTime now;
160         ComputeWaitPendTime(0, &now);
161         if (now.sec > outtime.sec || (now.sec == outtime.sec && now.usec >= outtime.usec)) {
162             break;
163         }
164     }
165     return SOFTBUS_TIMOUT;
166 }
167 
GetPendingPacketData(uint32_t id,uint64_t seq,uint32_t waitMillis,bool isDelete,TransPendData * data)168 int32_t GetPendingPacketData(uint32_t id, uint64_t seq, uint32_t waitMillis, bool isDelete, TransPendData *data)
169 {
170     if (data == NULL) {
171         TRANS_LOGE(TRANS_SDK, "invalid param");
172         return SOFTBUS_INVALID_PARAM;
173     }
174     if (SoftBusMutexLock(&g_pendingLock) != SOFTBUS_OK) {
175         TRANS_LOGE(TRANS_SDK, "mutex lock fail");
176         return SOFTBUS_LOCK_ERR;
177     }
178     PendingPacket *pending = NULL;
179     PendingPacket *item = NULL;
180     LIST_FOR_EACH_ENTRY(item, &g_pendingList, PendingPacket, node) {
181         if (item->id == id && item->seq == seq) {
182             pending = item;
183         }
184     }
185     if (pending == NULL) {
186         (void)SoftBusMutexUnlock(&g_pendingLock);
187         return SOFTBUS_NOT_FIND;
188     }
189     (void)SoftBusMutexUnlock(&g_pendingLock);
190 
191     int32_t ret;
192     if (SoftBusMutexLock(&pending->lock) != SOFTBUS_OK) {
193         ret = SOFTBUS_LOCK_ERR;
194         goto EXIT;
195     }
196     ret = TransPendWaitTime(pending, data, waitMillis);
197     (void)SoftBusMutexUnlock(&pending->lock);
198 EXIT:
199     (void)SoftBusMutexLock(&g_pendingLock);
200     if (isDelete || ret != SOFTBUS_TIMOUT) {
201         ListDelete(&pending->node);
202         SoftBusMutexDestroy(&pending->lock);
203         SoftBusCondDestroy(&pending->cond);
204         SoftBusFree(pending);
205     }
206     (void)SoftBusMutexUnlock(&g_pendingLock);
207     return ret;
208 }
209 
SetPendingPacketData(uint32_t id,uint64_t seq,const TransPendData * data)210 int32_t SetPendingPacketData(uint32_t id, uint64_t seq, const TransPendData *data)
211 {
212     if (SoftBusMutexLock(&g_pendingLock) != SOFTBUS_OK) {
213         TRANS_LOGE(TRANS_SDK, "mutex lock fail");
214         return SOFTBUS_LOCK_ERR;
215     }
216     PendingPacket *item = NULL;
217     LIST_FOR_EACH_ENTRY(item, &g_pendingList, PendingPacket, node) {
218         if (item->seq == seq && item->id == id) {
219             if (SoftBusMutexLock(&item->lock) != SOFTBUS_OK) {
220                 TRANS_LOGE(TRANS_SDK, "mutex lock fail");
221                 (void)SoftBusMutexUnlock(&g_pendingLock);
222                 return SOFTBUS_LOCK_ERR;
223             }
224             item->finded = true;
225             if (data != NULL) {
226                 item->data.data = data->data;
227                 item->data.len = data->len;
228             }
229             SoftBusCondSignal(&item->cond);
230             (void)SoftBusMutexUnlock(&item->lock);
231             (void)SoftBusMutexUnlock(&g_pendingLock);
232             return SOFTBUS_OK;
233         }
234     }
235     (void)SoftBusMutexUnlock(&g_pendingLock);
236     return SOFTBUS_NOT_FIND;
237 }