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"
26 #include "caremotehandler.h"
27 #include "caprotocolmessage.h"
28 #include "oic_malloc.h"
39 /** last sent time. microseconds **/
42 /** retransmission count **/
45 /** coap PDU message id **/
48 /** remote endpoint **/
49 CARemoteEndpoint_t *endpoint;
57 } CARetransmissionData_t;
59 static CARetransmission_t *g_retransmissionPtr = NULL;
62 * getCurrent monotonic time.
64 * @return current time in microseconds.
66 uint64_t getCurrentTimeInMicroSeconds();
69 * @brief check timeout routine
70 * @param currentTime [IN]microseconds
71 * @param timeStamp [IN]microseconds
72 * @param triedCount [IN]Number of retransmission tried.
73 * @return true if the timeout period has elapsed, false otherwise.
75 static bool CACheckTimeout(uint64_t currentTime, uint64_t timeStamp, uint8_t triedCount)
77 OIC_LOG(DEBUG, TAG, "IN");
78 // #1. calculate timeout
79 uint64_t timeOut = (2 << triedCount) * 1000000;
81 if (currentTime >= timeStamp + timeOut)
83 OIC_LOG_V(DEBUG, TAG, "timeout=%d, tried cnt=%d", (2 << triedCount), triedCount);
87 OIC_LOG(DEBUG, TAG, "OUT");
91 void CACheckRetransmissionList()
93 uint32_t len = u_arraylist_length(g_retransmissionPtr->dataList);
95 OIC_LOG_V(DEBUG, TAG, "len=%d", len);
96 for (uint32_t i = 0; i < len; i++)
98 CARetransmissionData_t *retData =
99 (CARetransmissionData_t *) u_arraylist_get(g_retransmissionPtr->dataList, i);
106 uint64_t currentTime = getCurrentTimeInMicroSeconds();
108 OIC_LOG_V(DEBUG, TAG, "currtime=%lu", currentTime);
109 if (CACheckTimeout(currentTime, retData->timeStamp, retData->triedCount))
112 OIC_LOG(DEBUG, TAG, "RTdata-Success");
113 // #2. if time's up, send the data.
114 if (NULL != g_retransmissionPtr->dataSendMethod)
116 OIC_LOG_V(DEBUG, TAG, "retry CON data-msgid=%d", retData->messageId);
117 g_retransmissionPtr->dataSendMethod(retData->endpoint, retData->pdu, retData->size);
120 // #3. increase the retransmission count and update timestamp.
121 retData->timeStamp = currentTime;
122 retData->triedCount++;
125 // #4. if tried count is max, remove the retransmission data from list.
126 if (retData->triedCount >= g_retransmissionPtr->config.tryingCount)
128 CARetransmissionData_t *removedData = (CARetransmissionData_t *) u_arraylist_remove(
129 g_retransmissionPtr->dataList, i);
130 if (NULL == removedData)
132 OIC_LOG(ERROR, TAG, "Removed data is NULL");
136 OIC_LOG(DEBUG, TAG, "max trycount rchd");
138 OIC_LOG_V(DEBUG, TAG, "max trycount, remove retransmission CON data!!, messageid=%d",
139 removedData->messageId);
141 // callback for retransmit timeout
142 if (NULL != g_retransmissionPtr->timeoutCallback)
144 g_retransmissionPtr->timeoutCallback(removedData->endpoint, removedData->pdu,
148 CADestroyRemoteEndpointInternal(removedData->endpoint);
149 OICFree(removedData->pdu);
151 OICFree(removedData);
153 // modify loop value.
154 len = u_arraylist_length(g_retransmissionPtr->dataList);
160 void CARetransmissionBaseRoutine(void *threadValue)
162 CARetransmission_t *context = (CARetransmission_t *) threadValue;
166 OIC_LOG(ERROR, TAG, "cnxt null");
170 if (true == context->isStop)
172 OIC_LOG(DEBUG, TAG, "thread stopped");
175 g_retransmissionPtr = context;
176 CACheckRetransmissionList();
179 CAResult_t CARetransmissionInitialize(CARetransmission_t *context,
180 CADataSendMethod_t retransmissionSendMethod,
181 CATimeoutCallback_t timeoutCallback,
182 CARetransmissionConfig_t *config)
184 OIC_LOG(DEBUG, TAG, "IN");
187 OIC_LOG(ERROR, TAG, "cnxt null");
188 return CA_STATUS_INVALID_PARAM;
191 memset(context, 0, sizeof(CARetransmission_t));
193 CARetransmissionConfig_t cfg;
194 memset(&cfg, 0, sizeof(CARetransmissionConfig_t));
199 cfg.supportType = (CATransportType_t) DEFAULT_RETRANSMISSION_TYPE;
200 cfg.tryingCount = DEFAULT_RETRANSMISSION_COUNT;
207 // set send thread data
208 context->dataSendMethod = retransmissionSendMethod;
209 context->timeoutCallback = timeoutCallback;
210 context->config = cfg;
211 context->isStop = false;
212 context->dataList = u_arraylist_create();
214 // Enable TimedAction for CACheckRetransmissionList API
215 g_retransmissionPtr = context;
216 OIC_LOG(DEBUG, TAG, "OUT");
220 CAResult_t CARetransmissionSentData(CARetransmission_t *context, const CARemoteEndpoint_t *endpoint,
221 const void *pdu, uint32_t size)
223 OIC_LOG(DEBUG, TAG, "IN");
224 if (NULL == context || NULL == endpoint || NULL == pdu)
226 OIC_LOG(ERROR, TAG, "error");
227 return CA_STATUS_INVALID_PARAM;
230 // #0. check support connectivity type
231 if (!(context->config.supportType & endpoint->transportType))
233 OIC_LOG(ERROR, TAG, "error");
234 OIC_LOG_V(ERROR, TAG, "not supported conntype=%d", endpoint->transportType);
235 return CA_NOT_SUPPORTED;
238 // #1. check PDU method type and get message id.
239 CAMessageType_t type = CAGetMessageTypeFromPduBinaryData(pdu, size);
240 uint16_t messageId = CAGetMessageIdFromPduBinaryData(pdu, size);
242 OIC_LOG_V(DEBUG, TAG, "sent pdu, msgtype=%d,msgid=%d", type, messageId);
244 if (CA_MSG_CONFIRM != type)
246 OIC_LOG(DEBUG, TAG, "not supported message type");
247 return CA_NOT_SUPPORTED;
250 // create retransmission data
251 CARetransmissionData_t *retData = (CARetransmissionData_t *) OICCalloc(
252 1, sizeof(CARetransmissionData_t));
256 OIC_LOG(ERROR, TAG, "error");
257 return CA_MEMORY_ALLOC_FAILED;
261 void *pduData = (void *) OICMalloc(size);
265 OIC_LOG(ERROR, TAG, "error");
266 return CA_MEMORY_ALLOC_FAILED;
268 memcpy(pduData, pdu, size);
270 // clone remote endpoint
271 CARemoteEndpoint_t *remoteEndpoint = CACloneRemoteEndpoint(endpoint);
272 if (NULL == remoteEndpoint)
276 OIC_LOG(ERROR, TAG, "error");
277 return CA_MEMORY_ALLOC_FAILED;
280 // #2. add additional information. (time stamp, retransmission count...)
281 retData->timeStamp = getCurrentTimeInMicroSeconds();
282 retData->triedCount = 0;
283 retData->messageId = messageId;
284 retData->endpoint = remoteEndpoint;
285 retData->pdu = pduData;
286 retData->size = size;
288 // #3. add data into list
289 u_arraylist_add(context->dataList, (void *) retData);
291 // #4. Initiate Re-transmission for added entry
292 g_retransmissionPtr = context;
293 CACheckRetransmissionList();
294 OIC_LOG(DEBUG, TAG, "OUT");
298 CAResult_t CARetransmissionReceivedData(CARetransmission_t *context,
299 const CARemoteEndpoint_t *endpoint, const void *pdu,
300 uint32_t size, void **retransmissionPdu)
302 OIC_LOG(DEBUG, TAG, "IN");
303 if (NULL == context || NULL == endpoint || NULL == pdu || NULL == retransmissionPdu)
305 OIC_LOG(ERROR, TAG, "error");
306 return CA_STATUS_INVALID_PARAM;
309 // #0. check support connectivity type
310 if (!(context->config.supportType & endpoint->transportType))
312 OIC_LOG_V(DEBUG, TAG, "not supp conntype=%d", endpoint->transportType);
316 // #1. check PDU method type and get message id.
317 // ACK, RST --> remove the CON data
318 CAMessageType_t type = CAGetMessageTypeFromPduBinaryData(pdu, size);
319 uint16_t messageId = CAGetMessageIdFromPduBinaryData(pdu, size);
321 OIC_LOG_V(DEBUG, TAG, "recv pdu, msgtype=%d,msgid=%d", type, messageId);
323 if (CA_MSG_ACKNOWLEDGE != type && CA_MSG_RESET != type)
328 uint32_t len = u_arraylist_length(context->dataList);
331 for (uint32_t i = 0; i < len; i++)
333 CARetransmissionData_t *retData = (CARetransmissionData_t *) u_arraylist_get(
334 context->dataList, i);
342 if (NULL != retData->endpoint && retData->messageId == messageId
343 && (retData->endpoint->transportType == endpoint->transportType))
345 // get pdu data for getting token when CA_EMPTY(RST/ACK) is received from remote device
346 // if retransmission was finish..token will be unavailable.
347 if (CA_EMPTY == CAGetCodeFromPduBinaryData(pdu, size))
349 OIC_LOG(DEBUG, TAG, "CA_EMPTY");
351 if (NULL == retData->pdu)
353 OIC_LOG(ERROR, TAG, "retData->pdu is null");
355 return CA_STATUS_FAILED;
359 (*retransmissionPdu) = (void *) OICCalloc(1, retData->size);
360 if (NULL == (*retransmissionPdu))
363 OIC_LOG(ERROR, TAG, "error");
364 return CA_MEMORY_ALLOC_FAILED;
366 memcpy((*retransmissionPdu), retData->pdu, retData->size);
369 // #2. remove data from list
370 CARetransmissionData_t *removedData = (CARetransmissionData_t *) u_arraylist_remove(
371 context->dataList, i);
372 if (NULL == removedData)
374 OIC_LOG(ERROR, TAG, "Removed data is NULL");
375 return CA_STATUS_FAILED;
378 OIC_LOG_V(DEBUG, TAG, "remove RTCON data, msgid=%d", messageId);
380 CADestroyRemoteEndpointInternal(removedData->endpoint);
381 OICFree(removedData->pdu);
383 OICFree(removedData);
389 OIC_LOG(DEBUG, TAG, "OUT");
393 CAResult_t CARetransmissionStop(CARetransmission_t *context)
395 OIC_LOG(DEBUG, TAG, "IN");
398 OIC_LOG(ERROR, TAG, "error");
399 return CA_STATUS_INVALID_PARAM;
403 context->isStop = true;
404 OIC_LOG(DEBUG, TAG, "OUT");
408 CAResult_t CARetransmissionDestroy(CARetransmission_t *context)
410 OIC_LOG(DEBUG, TAG, "IN");
413 OIC_LOG(ERROR, TAG, "error");
414 return CA_STATUS_INVALID_PARAM;
417 u_arraylist_free(&context->dataList);
418 OIC_LOG(DEBUG, TAG, "OUT");
422 uint64_t getCurrentTimeInMicroSeconds()
424 OIC_LOG(DEBUG, TAG, "IN");
425 uint64_t currentTime = 0;
428 currentTime = millis() * 1000;
430 OIC_LOG_V(DEBUG, TAG, "currtime=%lu", currentTime);
433 gettimeofday(&tv, NULL);
434 currentTime = tv.tv_sec * USECS_PER_SEC + tv.tv_usec;
437 OIC_LOG(DEBUG, TAG, "OUT");