1 /******************************************************************
3 * Copyright 2014 Samsung Electronics All Rights Reserved.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 ******************************************************************/
20 #include "caretransmission_singlethread.h"
25 #include <TimedAction.h>
27 #include "caremotehandler.h"
28 #include "caprotocolmessage.h"
29 #include "oic_malloc.h"
36 /** last sent time. microseconds **/
38 /** retransmission count **/
40 /** coap PDU message id **/
42 /** remote endpoint **/
43 CARemoteEndpoint_t* endpoint;
48 } CARetransmissionData_t;
50 static TimedAction gRcvAction = TimedAction(2000, CACheckRetransmissionList);
51 static CARetransmission_t *gRetransmissionPtr = NULL;
54 * getCurrent monotonic time
58 uint64_t getCurrentTimeInMicroSeconds();
62 * 2sec -> 4sec -> 8sec -> 16sec
66 static CABool_t CACheckTimeout(uint64_t currentTime, uint64_t timeStamp, uint8_t triedCount)
68 OIC_LOG(DEBUG, TAG, "IN");
69 // #1. calculate timeout
70 uint64_t timeOut = (2 << triedCount) * 1000000;
72 if (currentTime >= timeStamp + timeOut)
74 OIC_LOG_V(DEBUG, TAG, "%d sec time out!!, tried count(%d)", (2 << triedCount), triedCount);
78 OIC_LOG(DEBUG, TAG, "OUT");
82 void CACheckRetransmissionList()
84 OIC_LOG(DEBUG, TAG, "IN");
85 uint64_t currentTime = 0;
88 uint32_t len = u_arraylist_length(gRetransmissionPtr->dataList);
90 OIC_LOG_V(DEBUG, TAG, "len=%d", len);
91 for (i = 0; i < len; i++)
93 CARetransmissionData_t* retData =
94 (CARetransmissionData_t*)u_arraylist_get(gRetransmissionPtr->dataList, i);
99 currentTime = getCurrentTimeInMicroSeconds();
101 OIC_LOG_V(DEBUG, TAG, "currtime=%lu", currentTime);
102 if (CACheckTimeout(currentTime, retData->timeStamp, retData->triedCount))
105 OIC_LOG(DEBUG, TAG, "CCT-Success, retransmit data");
106 // #2. if time's up, send the data.
107 if (gRetransmissionPtr->dataSendMethod != NULL)
109 OIC_LOG_V(DEBUG, TAG, "retry CON data, msgid=%d", retData->messageId);
110 gRetransmissionPtr->dataSendMethod(retData->endpoint, retData->pdu, retData->size);
113 // #3. increase the retransmission count and update timestamp.
114 retData->timeStamp = currentTime;
115 retData->triedCount++;
118 // #4. if tried count is max, remove the retransmission data from list.
119 if (retData->triedCount >= gRetransmissionPtr->config.tryingCount)
121 CARetransmissionData_t* removedData =
122 (CARetransmissionData_t*)u_arraylist_remove(gRetransmissionPtr->dataList, i);
124 OIC_LOG_V(DEBUG, TAG, "max trycount, remove retransmission CON data!!, messageid=%d",
125 removedData->messageId);
127 CADestroyRemoteEndpointInternal(removedData->endpoint);
128 OICFree(removedData->pdu);
130 OICFree(removedData);
132 // modify loop value.
133 len = u_arraylist_length(gRetransmissionPtr->dataList);
137 OIC_LOG(DEBUG, TAG, "OUT");
140 void CARetransmissionBaseRoutine(void *threadValue)
142 CARetransmission_t *context = (CARetransmission_t *) threadValue;
146 OIC_LOG_V(DEBUG, TAG, "error");
150 if (CA_TRUE == context->isStop)
152 OIC_LOG(DEBUG, TAG, "Not reqd");
155 gRetransmissionPtr = context;
159 CAResult_t CARetransmissionInitialize(CARetransmission_t* context,
160 CADataSendMethod_t retransmissionSendMethod,
161 CARetransmissionConfig_t* config)
165 OIC_LOG_V(DEBUG, TAG, "thread instance is empty..");
166 return CA_STATUS_FAILED;
169 OIC_LOG_V(DEBUG, TAG, "thread initialize..");
171 memset(context, 0, sizeof(CARetransmission_t));
173 CARetransmissionConfig_t cfg;
174 memset(&cfg, 0, sizeof(CARetransmissionConfig_t));
179 cfg.supportType = (CAConnectivityType_t)DEFAULT_RETRANSMISSION_TYPE;
180 cfg.tryingCount = DEFAULT_RETRANSMISSION_COUNT;
187 // set send thread data
188 context->dataSendMethod = retransmissionSendMethod;
189 context->config = cfg;
190 context->isStop = CA_FALSE;
191 context->dataList = u_arraylist_create();
193 // Enable TimedAction for CACheckRetransmissionList API
194 gRetransmissionPtr = context;
200 CAResult_t CARetransmissionSentData(CARetransmission_t* context,
201 const CARemoteEndpoint_t* endpoint,
202 const void* pdu, uint32_t size)
204 if (context == NULL || endpoint == NULL || pdu == NULL)
206 OIC_LOG_V(DEBUG, TAG, "error");
207 return CA_STATUS_INVALID_PARAM;
210 // #0. check support connectivity type
211 if (!(context->config.supportType & endpoint->connectivityType))
213 OIC_LOG_V(DEBUG, TAG, "not supported conntype=%d", endpoint->connectivityType);
217 // #1. check PDU method type and get message id.
218 CAMessageType_t type = CAGetMessageTypeFromPduBinaryData(pdu, size);
219 uint16_t messageId = CAGetMessageIdFromPduBinaryData(pdu, size);
221 OIC_LOG_V(DEBUG, TAG, "sent pdu, msgtype=%d,msgid=%d", type, messageId);
223 if (type != CA_MSG_CONFIRM)
228 // create retransmission data
229 CARetransmissionData_t* retData = (CARetransmissionData_t*) OICMalloc(
230 sizeof(CARetransmissionData_t));
234 OIC_LOG_V(DEBUG, TAG, "memory error!!");
235 return CA_MEMORY_ALLOC_FAILED;
237 memset(retData, 0, sizeof(CARetransmissionData_t));
240 void* pduData = (void*) OICMalloc(sizeof(int8_t) * size);
244 OIC_LOG_V(DEBUG, TAG, "memory error!!");
245 return CA_MEMORY_ALLOC_FAILED;
247 memset(pduData, 0, sizeof(int8_t) * size);
248 memcpy(pduData, pdu, sizeof(int8_t) * size);
250 // clone remote endpoint
251 CARemoteEndpoint_t* remoteEndpoint = CACloneRemoteEndpoint(endpoint);
252 if (remoteEndpoint == NULL)
256 OIC_LOG_V(DEBUG, TAG, "memory error!!");
257 return CA_MEMORY_ALLOC_FAILED;
260 // #2. add additional information. (time stamp, retransmission count...)
261 retData->timeStamp = getCurrentTimeInMicroSeconds();
262 retData->triedCount = 0;
263 retData->messageId = messageId;
264 retData->endpoint = remoteEndpoint;
265 retData->pdu = pduData;
266 retData->size = size;
268 // #3. add data into list
269 u_arraylist_add(context->dataList, (void*) retData);
271 // #4. Initiate Re-transmission for added entry
272 gRetransmissionPtr = context;
273 CACheckRetransmissionList();
278 CAResult_t CARetransmissionReceivedData(CARetransmission_t* context,
279 const CARemoteEndpoint_t* endpoint, const void* pdu, uint32_t size)
281 if (context == NULL || endpoint == NULL || pdu == NULL)
283 OIC_LOG_V(DEBUG, TAG, "invalid parameter..");
284 return CA_STATUS_INVALID_PARAM;
287 // #0. check support connectivity type
288 if (!(context->config.supportType & endpoint->connectivityType))
290 OIC_LOG_V(DEBUG, TAG, "not supported conntype=%d", endpoint->connectivityType);
294 // #1. check PDU method type and get message id.
295 // ACK, RST --> remove the CON data
296 CAMessageType_t type = CAGetMessageTypeFromPduBinaryData(pdu, size);
297 uint16_t messageId = CAGetMessageIdFromPduBinaryData(pdu, size);
299 OIC_LOG_V(DEBUG, TAG, "recv pdu, msgtype=%d,msgid=%d", type, messageId);
301 if (type != CA_MSG_ACKNOWLEDGE && type != CA_MSG_RESET)
307 uint32_t len = u_arraylist_length(context->dataList);
310 for (i = 0; i < len; i++)
312 CARetransmissionData_t* retData =
313 (CARetransmissionData_t*)u_arraylist_get(context->dataList, i);
319 if ((retData->endpoint->connectivityType == endpoint->connectivityType)
320 && retData->messageId == messageId)
324 // #2. remove data from list
327 CARetransmissionData_t* removedData =
328 (CARetransmissionData_t*)u_arraylist_remove(context->dataList, i);
330 OIC_LOG_V(DEBUG, TAG, "remove retransmission CON data!!, message id(%d)", messageId);
332 CADestroyRemoteEndpointInternal(removedData->endpoint);
333 OICFree(removedData->pdu);
335 OICFree(removedData);
341 CAResult_t CARetransmissionStop(CARetransmission_t* context)
345 OIC_LOG_V(DEBUG, TAG, "context is empty..");
346 return CA_STATUS_FAILED;
349 OIC_LOG_V(DEBUG, TAG, "retransmission stop request!!");
351 // Disable TimedAction for CACheckRetransmissionList API
352 gRcvAction.disable();
355 context->isStop = CA_TRUE;
360 CAResult_t CARetransmissionDestroy(CARetransmission_t* context)
364 OIC_LOG_V(DEBUG, TAG, "context is empty..");
365 return CA_STATUS_FAILED;
368 OIC_LOG_V(DEBUG, TAG, "retransmission context destroy..");
370 u_arraylist_free(context->dataList);
375 uint64_t getCurrentTimeInMicroSeconds()
377 OIC_LOG(DEBUG, TAG, "IN");
378 uint64_t currentTime = 0;
382 struct timespec getTs;
384 memset(&getTs, 0, sizeof(getTs));
385 clock_gettime(CLOCK_MONOTONIC, &getTs);
387 currentTime = (getTs.tv_sec * 1000000000 + getTs.tv_nsec)/1000;
388 OIC_LOG_V(DEBUG, TAG, "current time = %d", currentTime);
390 currentTime = micros();
392 currentTime = g_get_monotonic_time();
395 currentTime = micros();
397 OIC_LOG_V(DEBUG, TAG, "currtime=%lu", currentTime);
399 currentTime = g_get_monotonic_time();
402 OIC_LOG(DEBUG, TAG, "OUT");