Applied fixes to enable Unicast discovery in the RI Layer's sample apps.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / caretransmission_singlethread.cpp
1 /******************************************************************
2  *
3  * Copyright 2014 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************/
20 #include "caretransmission_singlethread.h"
21 #include "coap.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "caremotehandler.h"
27 #include "caprotocolmessage_singlethread.h"
28 #include "oic_malloc.h"
29 #include "logger.h"
30
31 #define TAG "RT"
32
33 typedef struct
34 {
35     /** last sent time. microseconds **/
36     uint64_t timeStamp;
37     /** retransmission count **/
38     uint8_t triedCount;
39     /** coap PDU message id **/
40     uint16_t messageId;
41     /** remote endpoint **/
42     CARemoteEndpoint_t *endpoint;
43     /** coap PDU **/
44     void *pdu;
45     /** coap PDU size**/
46     uint32_t size;
47 } CARetransmissionData_t;
48
49 static CARetransmission_t *gRetransmissionPtr = NULL;
50
51 /**
52  * getCurrent monotonic time
53  *
54  * microseconds
55  */
56 uint64_t getCurrentTimeInMicroSeconds();
57
58 /**
59  * timeout routine
60  * 2sec -> 4sec -> 8sec -> 16sec
61  *
62  * microseconds
63  */
64 static CABool_t CACheckTimeout(uint64_t currentTime, uint64_t timeStamp, uint8_t triedCount)
65 {
66     OIC_LOG(DEBUG, TAG, "IN");
67     // #1. calculate timeout
68     uint64_t timeOut = (2 << triedCount) * 1000000;
69
70     if (currentTime >= timeStamp + timeOut)
71     {
72         OIC_LOG_V(DEBUG, TAG, "timeout=%d, tried cnt=%d", (2 << triedCount), triedCount);
73         return CA_TRUE;
74     }
75
76     OIC_LOG(DEBUG, TAG, "OUT");
77     return CA_FALSE;
78 }
79
80 void CACheckRetransmissionList()
81 {
82     uint64_t currentTime = 0;
83
84     uint32_t i = 0;
85     uint32_t len = u_arraylist_length(gRetransmissionPtr->dataList);
86
87     OIC_LOG_V(DEBUG, TAG, "len=%d", len);
88     for (i = 0; i < len; i++)
89     {
90         CARetransmissionData_t *retData =
91             (CARetransmissionData_t *)u_arraylist_get(gRetransmissionPtr->dataList, i);
92
93         if (retData == NULL)
94             continue;
95
96         currentTime = getCurrentTimeInMicroSeconds();
97
98         OIC_LOG_V(DEBUG, TAG, "currtime=%lu", currentTime);
99         if (CACheckTimeout(currentTime, retData->timeStamp, retData->triedCount))
100         {
101
102             OIC_LOG(DEBUG, TAG, "RTdata-Success");
103             // #2. if time's up, send the data.
104             if (gRetransmissionPtr->dataSendMethod != NULL)
105             {
106                 OIC_LOG_V(DEBUG, TAG, "retry CON data-msgid=%d", retData->messageId);
107                 gRetransmissionPtr->dataSendMethod(retData->endpoint, retData->pdu, retData->size);
108             }
109
110             // #3. increase the retransmission count and update timestamp.
111             retData->timeStamp = currentTime;
112             retData->triedCount++;
113         }
114
115         // #4. if tried count is max, remove the retransmission data from list.
116         if (retData->triedCount >= gRetransmissionPtr->config.tryingCount)
117         {
118             CARetransmissionData_t *removedData =
119                 (CARetransmissionData_t *)u_arraylist_remove(gRetransmissionPtr->dataList, i);
120             if (NULL == removedData)
121             {
122                 OIC_LOG(DEBUG, TAG, "Removed data is NULL");
123                 return;
124             }
125             OIC_LOG(DEBUG, TAG, "max trycount rchd");
126             OIC_LOG_V(DEBUG, TAG, "max trycount, remove retransmission CON data!!, messageid=%d",
127                       removedData->messageId);
128
129             // callback for retransmit timeout
130             if (gRetransmissionPtr->timeoutCallback != NULL)
131             {
132                 gRetransmissionPtr->timeoutCallback(removedData->endpoint, removedData->pdu,
133                         removedData->size);
134             }
135
136             CADestroyRemoteEndpointInternal(removedData->endpoint);
137             OICFree(removedData->pdu);
138
139             OICFree(removedData);
140
141             // modify loop value.
142             len = u_arraylist_length(gRetransmissionPtr->dataList);
143             --i;
144         }
145     }
146 }
147
148 void CARetransmissionBaseRoutine(void *threadValue)
149 {
150     CARetransmission_t *context = (CARetransmission_t *) threadValue;
151
152     if (context == NULL)
153     {
154         OIC_LOG(DEBUG, TAG, "error");
155         return;
156     }
157
158     if (CA_TRUE == context->isStop)
159     {
160         OIC_LOG(DEBUG, TAG, "Not reqd");
161         return;
162     }
163     gRetransmissionPtr = context;
164     CACheckRetransmissionList();
165 }
166
167 CAResult_t CARetransmissionInitialize(CARetransmission_t *context,
168                                       CADataSendMethod_t retransmissionSendMethod,
169                                       CATimeoutCallback_t timeoutCallback,
170                                       CARetransmissionConfig_t *config)
171 {
172     OIC_LOG(DEBUG, TAG, "IN");
173     if (context == NULL)
174     {
175         OIC_LOG(DEBUG, TAG, "error");
176         return CA_STATUS_FAILED;
177     }
178
179     memset(context, 0, sizeof(CARetransmission_t));
180
181     CARetransmissionConfig_t cfg;
182     memset(&cfg, 0, sizeof(CARetransmissionConfig_t));
183
184     if (config == NULL)
185     {
186         // setDefault
187         cfg.supportType = (CAConnectivityType_t)DEFAULT_RETRANSMISSION_TYPE;
188         cfg.tryingCount = DEFAULT_RETRANSMISSION_COUNT;
189     }
190     else
191     {
192         cfg = *config;
193     }
194
195     // set send thread data
196     context->dataSendMethod = retransmissionSendMethod;
197     context->timeoutCallback = timeoutCallback;
198     context->config = cfg;
199     context->isStop = CA_FALSE;
200     context->dataList = u_arraylist_create();
201
202     // Enable TimedAction for CACheckRetransmissionList API
203     gRetransmissionPtr = context;
204     OIC_LOG(DEBUG, TAG, "OUT");
205     return CA_STATUS_OK;
206 }
207
208 CAResult_t CARetransmissionSentData(CARetransmission_t *context,
209                                     const CARemoteEndpoint_t *endpoint,
210                                     const void *pdu, uint32_t size)
211 {
212     OIC_LOG(DEBUG, TAG, "IN");
213     if (context == NULL || endpoint == NULL || pdu == NULL)
214     {
215         OIC_LOG(DEBUG, TAG, "error");
216         return CA_STATUS_INVALID_PARAM;
217     }
218
219     // #0. check support connectivity type
220     if (!(context->config.supportType & endpoint->connectivityType))
221     {
222         OIC_LOG(DEBUG, TAG, "error");
223         OIC_LOG_V(DEBUG, TAG, "not supported conntype=%d", endpoint->connectivityType);
224         return CA_STATUS_OK;
225     }
226
227     // #1. check PDU method type and get message id.
228     CAMessageType_t type = CAGetMessageTypeFromPduBinaryData(pdu, size);
229     uint16_t messageId = CAGetMessageIdFromPduBinaryData(pdu, size);
230
231     OIC_LOG_V(DEBUG, TAG, "sent pdu, msgtype=%d,msgid=%d", type, messageId);
232
233     if (type != CA_MSG_CONFIRM)
234     {
235         OIC_LOG(DEBUG, TAG, "error");
236         return CA_STATUS_OK;
237     }
238
239     // create retransmission data
240     CARetransmissionData_t *retData = (CARetransmissionData_t *) OICMalloc(
241                                           sizeof(CARetransmissionData_t));
242
243     if (retData == NULL)
244     {
245         OIC_LOG(DEBUG, TAG, "error");
246         return CA_MEMORY_ALLOC_FAILED;
247     }
248     memset(retData, 0, sizeof(CARetransmissionData_t));
249
250     // copy PDU data
251     void *pduData = (void *) OICMalloc(sizeof(int8_t) * size);
252     if (pduData == NULL)
253     {
254         OICFree(retData);
255         OIC_LOG(DEBUG, TAG, "error");
256         return CA_MEMORY_ALLOC_FAILED;
257     }
258     memset(pduData, 0, sizeof(int8_t) * size);
259     memcpy(pduData, pdu, sizeof(int8_t) * size);
260
261     // clone remote endpoint
262     CARemoteEndpoint_t *remoteEndpoint = CACloneRemoteEndpoint(endpoint);
263     if (remoteEndpoint == NULL)
264     {
265         OICFree(retData);
266         OICFree(pduData);
267         OIC_LOG(DEBUG, TAG, "error");
268         return CA_MEMORY_ALLOC_FAILED;
269     }
270
271     // #2. add additional information. (time stamp, retransmission count...)
272     retData->timeStamp = getCurrentTimeInMicroSeconds();
273     retData->triedCount = 0;
274     retData->messageId = messageId;
275     retData->endpoint = remoteEndpoint;
276     retData->pdu = pduData;
277     retData->size = size;
278
279     // #3. add data into list
280     u_arraylist_add(context->dataList, (void *) retData);
281
282     // #4. Initiate Re-transmission for added entry
283     gRetransmissionPtr = context;
284     CACheckRetransmissionList();
285     OIC_LOG(DEBUG, TAG, "OUT");
286     return CA_STATUS_OK;
287 }
288
289 CAResult_t CARetransmissionReceivedData(CARetransmission_t *context,
290                                         const CARemoteEndpoint_t *endpoint,
291                                         const void *pdu, uint32_t size,
292                                         void **retransmissionPdu)
293 {
294     OIC_LOG(DEBUG, TAG, "IN");
295     if (context == NULL || endpoint == NULL || pdu == NULL)
296     {
297         OIC_LOG(DEBUG, TAG, "error");
298         return CA_STATUS_INVALID_PARAM;
299     }
300
301     // #0. check support connectivity type
302     if (!(context->config.supportType & endpoint->connectivityType))
303     {
304         OIC_LOG_V(DEBUG, TAG, "not supp conntype=%d", endpoint->connectivityType);
305         return CA_STATUS_OK;
306     }
307
308     // #1. check PDU method type and get message id.
309     // ACK, RST --> remove the CON data
310     CAMessageType_t type = CAGetMessageTypeFromPduBinaryData(pdu, size);
311     uint16_t messageId = CAGetMessageIdFromPduBinaryData(pdu, size);
312
313     OIC_LOG_V(DEBUG, TAG, "recv pdu, msgtype=%d,msgid=%d", type, messageId);
314
315     if (type != CA_MSG_ACKNOWLEDGE && type != CA_MSG_RESET)
316     {
317         return CA_STATUS_OK;
318     }
319
320     uint32_t i = 0;
321     uint32_t len = u_arraylist_length(context->dataList);
322
323     // find index
324     for (i = 0; i < len; i++)
325     {
326         CARetransmissionData_t *retData =
327             (CARetransmissionData_t *)u_arraylist_get(context->dataList, i);
328
329         if (retData == NULL)
330             continue;
331
332         // found index
333         if ((retData->endpoint->connectivityType == endpoint->connectivityType)
334             && retData->messageId == messageId)
335         {
336             // get pdu data for getting token when CA_EMPTY(RST/ACK) is received from remote device
337             // if retransmission was finish..token will be unavailable.
338             if(CA_EMPTY == CAGetCodeFromPduBinaryData(pdu, size))
339             {
340                 OIC_LOG(DEBUG, TAG, "CA_EMPTY");
341
342                 if(NULL == retData->pdu)
343                 {
344                     OIC_LOG(DEBUG, TAG, "retData->pdu is null");
345                 }
346
347                 // copy PDU data
348                 (*retransmissionPdu) = (void *) OICMalloc(sizeof(int8_t) * retData->size);
349                 if (NULL == (*retransmissionPdu))
350                 {
351                     OICFree(retData);
352                     OIC_LOG(DEBUG, TAG, "error");
353                     return CA_MEMORY_ALLOC_FAILED;
354                 }
355                 memset((*retransmissionPdu), 0, sizeof(int8_t) * retData->size);
356                 memcpy((*retransmissionPdu), retData->pdu, sizeof(int8_t) * retData->size);
357             }
358
359             break;
360         }
361     }
362
363     // #2. remove data from list
364     if (i < len)
365     {
366         CARetransmissionData_t *removedData =
367             (CARetransmissionData_t *)u_arraylist_remove(context->dataList, i);
368         if (NULL == removedData)
369         {
370             OIC_LOG(DEBUG, TAG, "Removed data is NULL");
371             return CA_STATUS_FAILED;
372         }
373
374         OIC_LOG_V(DEBUG, TAG, "remove RTCON data, msgid=%d", messageId);
375
376         CADestroyRemoteEndpointInternal(removedData->endpoint);
377         OICFree(removedData->pdu);
378
379         OICFree(removedData);
380     }
381     OIC_LOG(DEBUG, TAG, "OUT");
382     return CA_STATUS_OK;
383 }
384
385 CAResult_t CARetransmissionStop(CARetransmission_t *context)
386 {
387     OIC_LOG(DEBUG, TAG, "IN");
388     if (context == NULL)
389     {
390         OIC_LOG(DEBUG, TAG, "error");
391         return CA_STATUS_FAILED;
392     }
393
394     // set stop flag
395     context->isStop = CA_TRUE;
396     OIC_LOG(DEBUG, TAG, "OUT");
397     return CA_STATUS_OK;
398 }
399
400 CAResult_t CARetransmissionDestroy(CARetransmission_t *context)
401 {
402     OIC_LOG(DEBUG, TAG, "IN");
403     if (context == NULL)
404     {
405         OIC_LOG(DEBUG, TAG, "error");
406         return CA_STATUS_FAILED;
407     }
408
409     u_arraylist_free(&context->dataList);
410     OIC_LOG(DEBUG, TAG, "OUT");
411     return CA_STATUS_OK;
412 }
413
414 uint64_t getCurrentTimeInMicroSeconds()
415 {
416     OIC_LOG(DEBUG, TAG, "IN");
417     uint64_t currentTime = 0;
418
419     /*
420     #ifdef __ANDROID__
421         struct timespec getTs;
422
423         memset(&getTs, 0, sizeof(getTs));
424         clock_gettime(CLOCK_MONOTONIC, &getTs);
425
426         currentTime = (getTs.tv_sec * 1000000000 + getTs.tv_nsec)/1000;
427         OIC_LOG_V(DEBUG, TAG, "current time = %d",  currentTime);
428     #else if __ARDUINO__
429         currentTime = micros();
430     #else
431         currentTime = g_get_monotonic_time();
432     */
433 #ifdef __ARDUINO__
434     currentTime = micros();
435
436     OIC_LOG_V(DEBUG, TAG, "currtime=%lu", currentTime);
437 #else
438     currentTime = g_get_monotonic_time();
439 #endif
440
441     OIC_LOG(DEBUG, TAG, "OUT");
442     return currentTime;
443 }