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_singlethread.h"
28 #include "oic_malloc.h"
35 /** last sent time. microseconds **/
37 /** retransmission count **/
39 /** coap PDU message id **/
41 /** remote endpoint **/
42 CARemoteEndpoint_t *endpoint;
47 } CARetransmissionData_t;
49 static CARetransmission_t *gRetransmissionPtr = NULL;
52 * getCurrent monotonic time
56 uint64_t getCurrentTimeInMicroSeconds();
60 * 2sec -> 4sec -> 8sec -> 16sec
64 static CABool_t CACheckTimeout(uint64_t currentTime, uint64_t timeStamp, uint8_t triedCount)
66 OIC_LOG(DEBUG, TAG, "IN");
67 // #1. calculate timeout
68 uint64_t timeOut = (2 << triedCount) * 1000000;
70 if (currentTime >= timeStamp + timeOut)
72 OIC_LOG_V(DEBUG, TAG, "timeout=%d, tried cnt=%d", (2 << triedCount), triedCount);
76 OIC_LOG(DEBUG, TAG, "OUT");
80 void CACheckRetransmissionList()
82 uint64_t currentTime = 0;
85 uint32_t len = u_arraylist_length(gRetransmissionPtr->dataList);
87 OIC_LOG_V(DEBUG, TAG, "len=%d", len);
88 for (i = 0; i < len; i++)
90 CARetransmissionData_t *retData =
91 (CARetransmissionData_t *)u_arraylist_get(gRetransmissionPtr->dataList, i);
96 currentTime = getCurrentTimeInMicroSeconds();
98 OIC_LOG_V(DEBUG, TAG, "currtime=%lu", currentTime);
99 if (CACheckTimeout(currentTime, retData->timeStamp, retData->triedCount))
102 OIC_LOG(DEBUG, TAG, "RTdata-Success");
103 // #2. if time's up, send the data.
104 if (gRetransmissionPtr->dataSendMethod != NULL)
106 OIC_LOG_V(DEBUG, TAG, "retry CON data-msgid=%d", retData->messageId);
107 gRetransmissionPtr->dataSendMethod(retData->endpoint, retData->pdu, retData->size);
110 // #3. increase the retransmission count and update timestamp.
111 retData->timeStamp = currentTime;
112 retData->triedCount++;
115 // #4. if tried count is max, remove the retransmission data from list.
116 if (retData->triedCount >= gRetransmissionPtr->config.tryingCount)
118 CARetransmissionData_t *removedData =
119 (CARetransmissionData_t *)u_arraylist_remove(gRetransmissionPtr->dataList, i);
120 if (NULL == removedData)
122 OIC_LOG(DEBUG, TAG, "Removed data is NULL");
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);
129 // callback for retransmit timeout
130 if (gRetransmissionPtr->timeoutCallback != NULL)
132 gRetransmissionPtr->timeoutCallback(removedData->endpoint, removedData->pdu,
136 CADestroyRemoteEndpointInternal(removedData->endpoint);
137 OICFree(removedData->pdu);
139 OICFree(removedData);
141 // modify loop value.
142 len = u_arraylist_length(gRetransmissionPtr->dataList);
148 void CARetransmissionBaseRoutine(void *threadValue)
150 CARetransmission_t *context = (CARetransmission_t *) threadValue;
154 OIC_LOG(DEBUG, TAG, "error");
158 if (CA_TRUE == context->isStop)
160 OIC_LOG(DEBUG, TAG, "Not reqd");
163 gRetransmissionPtr = context;
164 CACheckRetransmissionList();
167 CAResult_t CARetransmissionInitialize(CARetransmission_t *context,
168 CADataSendMethod_t retransmissionSendMethod,
169 CATimeoutCallback_t timeoutCallback,
170 CARetransmissionConfig_t *config)
172 OIC_LOG(DEBUG, TAG, "IN");
175 OIC_LOG(DEBUG, TAG, "error");
176 return CA_STATUS_FAILED;
179 memset(context, 0, sizeof(CARetransmission_t));
181 CARetransmissionConfig_t cfg;
182 memset(&cfg, 0, sizeof(CARetransmissionConfig_t));
187 cfg.supportType = (CAConnectivityType_t)DEFAULT_RETRANSMISSION_TYPE;
188 cfg.tryingCount = DEFAULT_RETRANSMISSION_COUNT;
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();
202 // Enable TimedAction for CACheckRetransmissionList API
203 gRetransmissionPtr = context;
204 OIC_LOG(DEBUG, TAG, "OUT");
208 CAResult_t CARetransmissionSentData(CARetransmission_t *context,
209 const CARemoteEndpoint_t *endpoint,
210 const void *pdu, uint32_t size)
212 OIC_LOG(DEBUG, TAG, "IN");
213 if (context == NULL || endpoint == NULL || pdu == NULL)
215 OIC_LOG(DEBUG, TAG, "error");
216 return CA_STATUS_INVALID_PARAM;
219 // #0. check support connectivity type
220 if (!(context->config.supportType & endpoint->connectivityType))
222 OIC_LOG(DEBUG, TAG, "error");
223 OIC_LOG_V(DEBUG, TAG, "not supported conntype=%d", endpoint->connectivityType);
227 // #1. check PDU method type and get message id.
228 CAMessageType_t type = CAGetMessageTypeFromPduBinaryData(pdu, size);
229 uint16_t messageId = CAGetMessageIdFromPduBinaryData(pdu, size);
231 OIC_LOG_V(DEBUG, TAG, "sent pdu, msgtype=%d,msgid=%d", type, messageId);
233 if (type != CA_MSG_CONFIRM)
235 OIC_LOG(DEBUG, TAG, "error");
239 // create retransmission data
240 CARetransmissionData_t *retData = (CARetransmissionData_t *) OICMalloc(
241 sizeof(CARetransmissionData_t));
245 OIC_LOG(DEBUG, TAG, "error");
246 return CA_MEMORY_ALLOC_FAILED;
248 memset(retData, 0, sizeof(CARetransmissionData_t));
251 void *pduData = (void *) OICMalloc(sizeof(int8_t) * size);
255 OIC_LOG(DEBUG, TAG, "error");
256 return CA_MEMORY_ALLOC_FAILED;
258 memset(pduData, 0, sizeof(int8_t) * size);
259 memcpy(pduData, pdu, sizeof(int8_t) * size);
261 // clone remote endpoint
262 CARemoteEndpoint_t *remoteEndpoint = CACloneRemoteEndpoint(endpoint);
263 if (remoteEndpoint == NULL)
267 OIC_LOG(DEBUG, TAG, "error");
268 return CA_MEMORY_ALLOC_FAILED;
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;
279 // #3. add data into list
280 u_arraylist_add(context->dataList, (void *) retData);
282 // #4. Initiate Re-transmission for added entry
283 gRetransmissionPtr = context;
284 CACheckRetransmissionList();
285 OIC_LOG(DEBUG, TAG, "OUT");
289 CAResult_t CARetransmissionReceivedData(CARetransmission_t *context,
290 const CARemoteEndpoint_t *endpoint,
291 const void *pdu, uint32_t size,
292 void **retransmissionPdu)
294 OIC_LOG(DEBUG, TAG, "IN");
295 if (context == NULL || endpoint == NULL || pdu == NULL)
297 OIC_LOG(DEBUG, TAG, "error");
298 return CA_STATUS_INVALID_PARAM;
301 // #0. check support connectivity type
302 if (!(context->config.supportType & endpoint->connectivityType))
304 OIC_LOG_V(DEBUG, TAG, "not supp conntype=%d", endpoint->connectivityType);
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);
313 OIC_LOG_V(DEBUG, TAG, "recv pdu, msgtype=%d,msgid=%d", type, messageId);
315 if (type != CA_MSG_ACKNOWLEDGE && type != CA_MSG_RESET)
321 uint32_t len = u_arraylist_length(context->dataList);
324 for (i = 0; i < len; i++)
326 CARetransmissionData_t *retData =
327 (CARetransmissionData_t *)u_arraylist_get(context->dataList, i);
333 if ((retData->endpoint->connectivityType == endpoint->connectivityType)
334 && retData->messageId == messageId)
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))
340 OIC_LOG(DEBUG, TAG, "CA_EMPTY");
342 if(NULL == retData->pdu)
344 OIC_LOG(DEBUG, TAG, "retData->pdu is null");
348 (*retransmissionPdu) = (void *) OICMalloc(sizeof(int8_t) * retData->size);
349 if (NULL == (*retransmissionPdu))
352 OIC_LOG(DEBUG, TAG, "error");
353 return CA_MEMORY_ALLOC_FAILED;
355 memset((*retransmissionPdu), 0, sizeof(int8_t) * retData->size);
356 memcpy((*retransmissionPdu), retData->pdu, sizeof(int8_t) * retData->size);
363 // #2. remove data from list
366 CARetransmissionData_t *removedData =
367 (CARetransmissionData_t *)u_arraylist_remove(context->dataList, i);
368 if (NULL == removedData)
370 OIC_LOG(DEBUG, TAG, "Removed data is NULL");
371 return CA_STATUS_FAILED;
374 OIC_LOG_V(DEBUG, TAG, "remove RTCON data, msgid=%d", messageId);
376 CADestroyRemoteEndpointInternal(removedData->endpoint);
377 OICFree(removedData->pdu);
379 OICFree(removedData);
381 OIC_LOG(DEBUG, TAG, "OUT");
385 CAResult_t CARetransmissionStop(CARetransmission_t *context)
387 OIC_LOG(DEBUG, TAG, "IN");
390 OIC_LOG(DEBUG, TAG, "error");
391 return CA_STATUS_FAILED;
395 context->isStop = CA_TRUE;
396 OIC_LOG(DEBUG, TAG, "OUT");
400 CAResult_t CARetransmissionDestroy(CARetransmission_t *context)
402 OIC_LOG(DEBUG, TAG, "IN");
405 OIC_LOG(DEBUG, TAG, "error");
406 return CA_STATUS_FAILED;
409 u_arraylist_free(&context->dataList);
410 OIC_LOG(DEBUG, TAG, "OUT");
414 uint64_t getCurrentTimeInMicroSeconds()
416 OIC_LOG(DEBUG, TAG, "IN");
417 uint64_t currentTime = 0;
421 struct timespec getTs;
423 memset(&getTs, 0, sizeof(getTs));
424 clock_gettime(CLOCK_MONOTONIC, &getTs);
426 currentTime = (getTs.tv_sec * 1000000000 + getTs.tv_nsec)/1000;
427 OIC_LOG_V(DEBUG, TAG, "current time = %d", currentTime);
429 currentTime = micros();
431 currentTime = g_get_monotonic_time();
434 currentTime = micros();
436 OIC_LOG_V(DEBUG, TAG, "currtime=%lu", currentTime);
438 currentTime = g_get_monotonic_time();
441 OIC_LOG(DEBUG, TAG, "OUT");