5a6c4980212312666ecf0e7d943c151e0c5cb5ce
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocserverrequest.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH 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 <string.h>
21
22 #include "ocstack.h"
23 #include "ocserverrequest.h"
24 #include "ocresourcehandler.h"
25 #include "oic_malloc.h"
26 #include "oic_string.h"
27 #include "ocpayload.h"
28 #include "ocpayloadcbor.h"
29
30 #include "cacommon.h"
31 #include "cainterface.h"
32
33 #include "utlist.h"
34 #include "pdu.h"
35
36 // Module Name
37 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
38
39 #define TAG  "ocserverrequest"
40
41 static struct OCServerRequest * serverRequestList = NULL;
42 static struct OCServerResponse * serverResponseList = NULL;
43
44 //-------------------------------------------------------------------------------------------------
45 // Local functions
46 //-------------------------------------------------------------------------------------------------
47
48 /**
49  * Add a server response to the server response list
50  *
51  * @param response initialized server response that is created by this function
52  * @param requestHandle - handle of the response
53  *
54  * @return
55  *     OCStackResult
56  */
57 static OCStackResult AddServerResponse (OCServerResponse ** response, OCRequestHandle requestHandle)
58 {
59     if (!response)
60     {
61         return OC_STACK_INVALID_PARAM;
62     }
63
64     OCServerResponse * serverResponse = NULL;
65
66     serverResponse = (OCServerResponse *) OICCalloc(1, sizeof(OCServerResponse));
67     VERIFY_NON_NULL(serverResponse);
68
69     serverResponse->payload = NULL;
70
71     serverResponse->requestHandle = requestHandle;
72
73     *response = serverResponse;
74     OC_LOG(INFO, TAG, "Server Response Added!!");
75     LL_APPEND (serverResponseList, serverResponse);
76     return OC_STACK_OK;
77
78 exit:
79     if (serverResponse)
80     {
81         OICFree(serverResponse);
82         serverResponse = NULL;
83     }
84     *response = NULL;
85     return OC_STACK_NO_MEMORY;
86 }
87
88 /**
89  * Delete a server request from the server request list
90  *
91  * @param serverRequest - server request to delete
92  */
93 static void DeleteServerRequest(OCServerRequest * serverRequest)
94 {
95     if(serverRequest)
96     {
97         LL_DELETE(serverRequestList, serverRequest);
98         OICFree(serverRequest->requestToken);
99         OICFree(serverRequest);
100         serverRequest = NULL;
101         OC_LOG(INFO, TAG, "Server Request Removed!!");
102     }
103 }
104
105 /**
106  * Delete a server response from the server response list
107  *
108  * @param serverResponse - server response to delete
109  */
110 static void DeleteServerResponse(OCServerResponse * serverResponse)
111 {
112     if(serverResponse)
113     {
114         LL_DELETE(serverResponseList, serverResponse);
115         OICFree(serverResponse->payload);
116         OICFree(serverResponse);
117         OC_LOG(INFO, TAG, "Server Response Removed!!");
118     }
119 }
120
121 /**
122  * Find a server response and delete it from the server response list
123  *
124  * @param serverResponse - server response to find and delete
125  */
126 static void FindAndDeleteServerResponse(OCServerResponse * serverResponse)
127 {
128     OCServerResponse* tmp;
129     if(serverResponse)
130     {
131         LL_FOREACH(serverResponseList, tmp)
132         {
133             if (serverResponse == tmp)
134             {
135                 DeleteServerResponse(tmp);
136                 return;
137             }
138         }
139     }
140 }
141
142 /**
143  * Ensure no accept header option is included when sending responses
144  *
145  * @param object CA remote endpoint.
146  * @param requestInfo CA request info.
147  *
148  * @return ::OC_STACK_OK on success, some other value upon failure.
149  */
150 static OCStackResult OCSendResponse(const CAEndpoint_t *object, CAResponseInfo_t *responseInfo)
151 {
152     // Do not include the accept header option
153     responseInfo->info.acceptFormat = CA_FORMAT_UNDEFINED;
154     CAResult_t result = CASendResponse(object, responseInfo);
155     if(CA_STATUS_OK != result)
156     {
157         OC_LOG_V(ERROR, TAG, "CASendResponse failed with CA error %u", result);
158         return CAResultToOCResult(result);
159     }
160     return OC_STACK_OK;
161 }
162
163 //-------------------------------------------------------------------------------------------------
164 // Internal APIs
165 //-------------------------------------------------------------------------------------------------
166
167 /**
168  * Get a server request from the server request list using the specified token.
169  *
170  * @param token - token of server request
171  * @param tokenLength - length of token
172  *
173  * @return
174  *     OCServerRequest*
175  */
176 OCServerRequest * GetServerRequestUsingToken (const CAToken_t token, uint8_t tokenLength)
177 {
178     if(!token)
179     {
180         OC_LOG(ERROR, TAG, "Invalid Parameter Token");
181         return NULL;
182     }
183
184     OCServerRequest * out = NULL;
185     OC_LOG(INFO, TAG,"Get server request with token");
186     OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
187
188     OC_LOG(INFO, TAG,"Found token");
189     LL_FOREACH (serverRequestList, out)
190     {
191         OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->requestToken, tokenLength);
192         if(memcmp(out->requestToken, token, tokenLength) == 0)
193         {
194             return out;
195         }
196     }
197     OC_LOG(ERROR, TAG, "Server Request not found!!");
198     return NULL;
199 }
200
201 /**
202  * Get a server request from the server request list using the specified handle
203  *
204  * @param handle - handle of server request
205  * @return
206  *     OCServerRequest*
207  */
208 OCServerRequest * GetServerRequestUsingHandle (const OCServerRequest * handle)
209 {
210     OCServerRequest * out = NULL;
211     LL_FOREACH (serverRequestList, out)
212     {
213         if(out == handle)
214         {
215             return out;
216         }
217     }
218     OC_LOG(ERROR, TAG, "Server Request not found!!");
219     return NULL;
220 }
221
222 /**
223  * Get a server response from the server response list using the specified handle
224  *
225  * @param handle - handle of server response
226  *
227  * @return
228  *     OCServerResponse*
229  */
230 OCServerResponse * GetServerResponseUsingHandle (const OCServerRequest * handle)
231 {
232     OCServerResponse * out = NULL;
233     LL_FOREACH (serverResponseList, out)
234     {
235         if(out->requestHandle == handle)
236         {
237             return out;
238         }
239     }
240     OC_LOG(ERROR, TAG, "Server Response not found!!");
241     return NULL;
242 }
243
244 OCStackResult AddServerRequest (OCServerRequest ** request, uint16_t coapID,
245         uint8_t delayedResNeeded, uint8_t notificationFlag, OCMethod method,
246         uint8_t numRcvdVendorSpecificHeaderOptions, uint32_t observationOption,
247         OCQualityOfService qos, char * query,
248         OCHeaderOption * rcvdVendorSpecificHeaderOptions,
249         uint8_t * payload, CAToken_t requestToken, uint8_t tokenLength,
250         char * resourceUrl, size_t reqTotalSize, OCPayloadFormat acceptFormat,
251         const OCDevAddr *devAddr)
252 {
253     if (!request)
254     {
255         return OC_STACK_INVALID_PARAM;
256     }
257
258     OCServerRequest * serverRequest = NULL;
259
260     serverRequest = (OCServerRequest *) OICCalloc(1, sizeof(OCServerRequest) +
261         (reqTotalSize ? reqTotalSize : 1) - 1);
262     VERIFY_NON_NULL(devAddr);
263     VERIFY_NON_NULL(serverRequest);
264
265     serverRequest->coapID = coapID;
266     serverRequest->delayedResNeeded = delayedResNeeded;
267     serverRequest->notificationFlag = notificationFlag;
268
269     serverRequest->method = method;
270     serverRequest->numRcvdVendorSpecificHeaderOptions = numRcvdVendorSpecificHeaderOptions;
271     serverRequest->observationOption = observationOption;
272     serverRequest->observeResult = OC_STACK_ERROR;
273     serverRequest->qos = qos;
274     serverRequest->acceptFormat = acceptFormat;
275     serverRequest->ehResponseHandler = HandleSingleResponse;
276     serverRequest->numResponses = 1;
277
278     if(query)
279     {
280         OICStrcpy(serverRequest->query, sizeof(serverRequest->query), query);
281     }
282
283     if(rcvdVendorSpecificHeaderOptions)
284     {
285         memcpy(serverRequest->rcvdVendorSpecificHeaderOptions, rcvdVendorSpecificHeaderOptions,
286             MAX_HEADER_OPTIONS * sizeof(OCHeaderOption));
287     }
288     if(payload && reqTotalSize)
289     {
290        // destination is at least 1 greater than the source, so a NULL always exists in the
291         // last character
292         memcpy(serverRequest->payload, payload, reqTotalSize);
293         serverRequest->payloadSize = reqTotalSize;
294     }
295
296     serverRequest->requestComplete = 0;
297     if(requestToken)
298     {
299         // If tokenLength is zero, the return value depends on the
300         // particular library implementation (it may or may not be a null pointer).
301         if (tokenLength)
302         {
303             serverRequest->requestToken = (CAToken_t) OICMalloc(tokenLength);
304             VERIFY_NON_NULL(serverRequest->requestToken);
305             memcpy(serverRequest->requestToken, requestToken, tokenLength);
306         }
307
308     }
309     serverRequest->tokenLength = tokenLength;
310
311     if(resourceUrl)
312     {
313         OICStrcpy(serverRequest->resourceUrl, sizeof(serverRequest->resourceUrl),
314             resourceUrl);
315     }
316
317     serverRequest->devAddr = *devAddr;
318
319     *request = serverRequest;
320     OC_LOG(INFO, TAG, "Server Request Added!!");
321     LL_APPEND (serverRequestList, serverRequest);
322     return OC_STACK_OK;
323
324 exit:
325     if (serverRequest)
326     {
327         OICFree(serverRequest);
328         serverRequest = NULL;
329     }
330     *request = NULL;
331     return OC_STACK_NO_MEMORY;
332 }
333
334 OCStackResult FormOCEntityHandlerRequest(
335         OCEntityHandlerRequest * entityHandlerRequest,
336         OCRequestHandle request,
337         OCMethod method,
338         OCDevAddr *endpoint,
339         OCResourceHandle resource,
340         char * queryBuf,
341         OCPayloadType payloadType,
342         uint8_t * payload,
343         size_t payloadSize,
344         uint8_t numVendorOptions,
345         OCHeaderOption * vendorOptions,
346         OCObserveAction observeAction,
347         OCObservationId observeID)
348 {
349     if (entityHandlerRequest)
350     {
351         entityHandlerRequest->resource = (OCResourceHandle) resource;
352         entityHandlerRequest->requestHandle = request;
353         entityHandlerRequest->method = method;
354         entityHandlerRequest->devAddr = *endpoint;
355         entityHandlerRequest->query = queryBuf;
356         entityHandlerRequest->obsInfo.action = observeAction;
357         entityHandlerRequest->obsInfo.obsId = observeID;
358
359         if(payload && payloadSize)
360         {
361             if(OCParsePayload(&entityHandlerRequest->payload, payloadType,
362                         payload, payloadSize) != OC_STACK_OK)
363             {
364                 return OC_STACK_ERROR;
365             }
366         }
367         else
368         {
369             entityHandlerRequest->payload = NULL;
370         }
371
372         entityHandlerRequest->numRcvdVendorSpecificHeaderOptions = numVendorOptions;
373         entityHandlerRequest->rcvdVendorSpecificHeaderOptions = vendorOptions;
374
375         return OC_STACK_OK;
376     }
377
378     return OC_STACK_INVALID_PARAM;
379 }
380
381 /**
382  * Find a server request in the server request list and delete
383  *
384  * @param serverRequest - server request to find and delete
385  */
386 void FindAndDeleteServerRequest(OCServerRequest * serverRequest)
387 {
388     OCServerRequest* tmp;
389     if(serverRequest)
390     {
391         LL_FOREACH(serverRequestList, tmp)
392         {
393             if (serverRequest == tmp)
394             {
395                 DeleteServerRequest(tmp);
396                 return;
397             }
398         }
399     }
400 }
401
402 CAResponseResult_t ConvertEHResultToCAResult (OCEntityHandlerResult result, OCMethod method)
403 {
404     CAResponseResult_t caResult;
405
406     switch (result)
407     {
408         case OC_EH_OK:
409            switch (method)
410            {
411                case OC_REST_PUT: 
412                case OC_REST_POST:
413                    // This Response Code is like HTTP 204 "No Content" but only used in
414                    // response to POST and PUT requests.
415                    caResult = CA_CHANGED;
416                    break;
417                case OC_REST_GET:
418                    // This Response Code is like HTTP 200 "OK" but only used in response to
419                    // GET requests.
420                    caResult = CA_CONTENT;
421                    break;
422                default:
423                    // This should not happen but,
424                    // give it a value just in case but output an error
425                    caResult = CA_CONTENT;
426                    OC_LOG_V(ERROR, TAG, "Unexpected OC_EH_OK return code for method [d].", method);
427            }
428             break;
429         case OC_EH_ERROR:
430             caResult = CA_BAD_REQ;
431             break;
432         case OC_EH_RESOURCE_CREATED:
433             caResult = CA_CREATED;
434             break;
435         case OC_EH_RESOURCE_DELETED:
436             caResult = CA_DELETED;
437             break;
438         case OC_EH_SLOW:
439             caResult = CA_CONTENT;
440             break;
441         case OC_EH_FORBIDDEN:
442             caResult = CA_UNAUTHORIZED_REQ;
443             break;
444         case OC_EH_RESOURCE_NOT_FOUND:
445             caResult = CA_NOT_FOUND;
446             break;
447         default:
448             caResult = CA_BAD_REQ;
449             break;
450     }
451     return caResult;
452 }
453
454
455 /**
456  * Handler function for sending a response from a single resource
457  *
458  * @param ehResponse - pointer to the response from the resource
459  *
460  * @return
461  *     OCStackResult
462  */
463
464 OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
465 {
466     OCStackResult result = OC_STACK_ERROR;
467     CAEndpoint_t responseEndpoint = {.adapter = CA_DEFAULT_ADAPTER};
468     CAResponseInfo_t responseInfo = {.result = CA_EMPTY};
469     CAHeaderOption_t* optionsPointer = NULL;
470
471     if(!ehResponse || !ehResponse->requestHandle)
472     {
473         return OC_STACK_ERROR;
474     }
475
476     OCServerRequest *serverRequest = (OCServerRequest *)ehResponse->requestHandle;
477
478     CopyDevAddrToEndpoint(&serverRequest->devAddr, &responseEndpoint);
479
480     responseInfo.info.resourceUri = serverRequest->resourceUrl;
481     responseInfo.result = ConvertEHResultToCAResult(ehResponse->ehResult, serverRequest->method);
482
483     if(serverRequest->notificationFlag && serverRequest->qos == OC_HIGH_QOS)
484     {
485         responseInfo.info.type = CA_MSG_CONFIRM;
486     }
487     else if(serverRequest->notificationFlag && serverRequest->qos != OC_HIGH_QOS)
488     {
489         responseInfo.info.type = CA_MSG_NONCONFIRM;
490     }
491     else if(!serverRequest->notificationFlag && !serverRequest->slowFlag &&
492             serverRequest->qos == OC_HIGH_QOS)
493     {
494         responseInfo.info.type = CA_MSG_ACKNOWLEDGE;
495     }
496     else if(!serverRequest->notificationFlag && serverRequest->slowFlag &&
497             serverRequest->qos == OC_HIGH_QOS)
498     {
499         responseInfo.info.type = CA_MSG_CONFIRM;
500     }
501     else if(!serverRequest->notificationFlag)
502     {
503         responseInfo.info.type = CA_MSG_NONCONFIRM;
504     }
505     else
506     {
507         OC_LOG(ERROR, TAG, "default responseInfo type is NON");
508         responseInfo.info.type = CA_MSG_NONCONFIRM;
509     }
510
511     char rspToken[CA_MAX_TOKEN_LEN + 1] = {};
512     responseInfo.info.messageId = serverRequest->coapID;
513     responseInfo.info.token = (CAToken_t)rspToken;
514
515     memcpy(responseInfo.info.token, serverRequest->requestToken, serverRequest->tokenLength);
516     responseInfo.info.tokenLength = serverRequest->tokenLength;
517
518     if(serverRequest->observeResult == OC_STACK_OK)
519     {
520         responseInfo.info.numOptions = ehResponse->numSendVendorSpecificHeaderOptions + 1;
521     }
522     else
523     {
524         responseInfo.info.numOptions = ehResponse->numSendVendorSpecificHeaderOptions;
525     }
526
527     if(responseInfo.info.numOptions > 0)
528     {
529         responseInfo.info.options = (CAHeaderOption_t *)
530                                       OICCalloc(responseInfo.info.numOptions,
531                                               sizeof(CAHeaderOption_t));
532
533         if(!responseInfo.info.options)
534         {
535             OC_LOG(FATAL, TAG, "Memory alloc for options failed");
536             return OC_STACK_NO_MEMORY;
537         }
538
539         optionsPointer = responseInfo.info.options;
540
541         // TODO: This exposes CoAP specific details.  At some point, this should be
542         // re-factored and handled in the CA layer.
543         if(serverRequest->observeResult == OC_STACK_OK)
544         {
545             responseInfo.info.options[0].protocolID = CA_COAP_ID;
546             responseInfo.info.options[0].optionID = COAP_OPTION_OBSERVE;
547             responseInfo.info.options[0].optionLength = sizeof(uint32_t);
548             uint8_t* observationData = (uint8_t*)responseInfo.info.options[0].optionData;
549             uint32_t observationOption= serverRequest->observationOption;
550
551             for (size_t i=sizeof(uint32_t); i; --i)
552             {
553                 observationData[i-1] = observationOption & 0xFF;
554                 observationOption >>=8;
555             }
556
557             // Point to the next header option before copying vender specific header options
558             optionsPointer += 1;
559         }
560
561         if (ehResponse->numSendVendorSpecificHeaderOptions)
562         {
563             memcpy(optionsPointer, ehResponse->sendVendorSpecificHeaderOptions,
564                             sizeof(OCHeaderOption) *
565                             ehResponse->numSendVendorSpecificHeaderOptions);
566         }
567     }
568     else
569     {
570         responseInfo.info.options = NULL;
571     }
572
573     responseInfo.isMulticast = false;
574     responseInfo.info.payload = NULL;
575     responseInfo.info.payloadSize = 0;
576     responseInfo.info.payloadFormat = CA_FORMAT_UNDEFINED;
577
578     // Put the JSON prefix and suffix around the payload
579     if(ehResponse->payload)
580     {
581         if (ehResponse->payload->type == PAYLOAD_TYPE_PRESENCE)
582         {
583             responseInfo.isMulticast = true;
584         }
585         else
586         {
587             responseInfo.isMulticast = false;
588         }
589
590         switch(serverRequest->acceptFormat)
591         {
592             case OC_FORMAT_UNDEFINED:
593                 // No preference set by the client, so default to CBOR then
594             case OC_FORMAT_CBOR:
595                 if((result = OCConvertPayload(ehResponse->payload, &responseInfo.info.payload,
596                                 &responseInfo.info.payloadSize))
597                         != OC_STACK_OK)
598                 {
599                     OC_LOG(ERROR, TAG, "Error converting payload");
600                     OICFree(responseInfo.info.options);
601                     return result;
602                 }
603                 responseInfo.info.payloadFormat = CA_FORMAT_APPLICATION_CBOR;
604                 break;
605             default:
606                 responseInfo.result = CA_NOT_ACCEPTABLE;
607         }
608     }
609
610 #ifdef WITH_PRESENCE
611     CATransportAdapter_t CAConnTypes[] = {
612                             CA_ADAPTER_IP,
613                             CA_ADAPTER_GATT_BTLE,
614                             CA_ADAPTER_RFCOMM_BTEDR
615
616 #ifdef RA_ADAPTER
617                             , CA_ADAPTER_REMOTE_ACCESS
618 #endif
619
620 #ifdef TCP_ADAPTER
621                             , CA_ADAPTER_TCP
622 #endif
623                         };
624
625     size_t size = sizeof(CAConnTypes)/ sizeof(CATransportAdapter_t);
626
627     CATransportAdapter_t adapter = responseEndpoint.adapter;
628     // Default adapter, try to send response out on all adapters.
629     if (adapter == CA_DEFAULT_ADAPTER)
630     {
631         adapter =
632             (CATransportAdapter_t)(
633                 CA_ADAPTER_IP           |
634                 CA_ADAPTER_GATT_BTLE    |
635                 CA_ADAPTER_RFCOMM_BTEDR
636
637 #ifdef RA_ADAP
638                 | CA_ADAPTER_REMOTE_ACCESS
639 #endif
640
641 #ifdef TCP_ADAPTER
642                 | CA_ADAPTER_TCP
643 #endif
644             );
645     }
646
647     result = OC_STACK_OK;
648     OCStackResult tempResult = OC_STACK_OK;
649
650     for(size_t i = 0; i < size; i++ )
651     {
652         responseEndpoint.adapter = (CATransportAdapter_t)(adapter & CAConnTypes[i]);
653         if(responseEndpoint.adapter)
654         {
655             //The result is set to OC_STACK_OK only if OCSendResponse succeeds in sending the
656             //response on all the n/w interfaces else it is set to OC_STACK_ERROR
657             tempResult = OCSendResponse(&responseEndpoint, &responseInfo);
658         }
659         if(OC_STACK_OK != tempResult)
660         {
661             result = tempResult;
662         }
663     }
664 #else
665
666     OC_LOG(INFO, TAG, "Calling OCSendResponse with:");
667     OC_LOG_V(INFO, TAG, "\tEndpoint address: %s", responseEndpoint.addr);
668     OC_LOG_V(INFO, TAG, "\tEndpoint adapter: %s", responseEndpoint.adapter);
669     OC_LOG_V(INFO, TAG, "\tResponse result : %s", responseInfo.result);
670     OC_LOG_V(INFO, TAG, "\tResponse for uri: %s", responseInfo.info.resourceUri);
671
672     result = OCSendResponse(&responseEndpoint, &responseInfo);
673 #endif
674
675     OICFree(responseInfo.info.payload);
676     OICFree(responseInfo.info.options);
677     //Delete the request
678     FindAndDeleteServerRequest(serverRequest);
679     return result;
680 }
681
682 /**
683  * Handler function for sending a response from multiple resources, such as a collection.
684  * Aggregates responses from multiple resource until all responses are received then sends the
685  * concatenated response
686  *
687  * TODO: Need to add a timeout in case a (remote?) resource does not respond
688  *
689  * @param ehResponse - pointer to the response from the resource
690  *
691  * @return
692  *     OCStackResult
693  */
694 OCStackResult HandleAggregateResponse(OCEntityHandlerResponse * ehResponse)
695 {
696     if(!ehResponse || !ehResponse->payload)
697     {
698         OC_LOG(ERROR, TAG, "HandleAggregateResponse invalid parameters");
699         return OC_STACK_INVALID_PARAM;
700     }
701
702     OC_LOG(INFO, TAG, "Inside HandleAggregateResponse");
703
704     OCServerRequest *serverRequest = GetServerRequestUsingHandle((OCServerRequest *)
705                                                                  ehResponse->requestHandle);
706     OCServerResponse *serverResponse = GetServerResponseUsingHandle((OCServerRequest *)
707                                                                     ehResponse->requestHandle);
708
709     OCStackResult stackRet = OC_STACK_ERROR;
710     if(serverRequest)
711     {
712         if(!serverResponse)
713         {
714             OC_LOG(INFO, TAG, "This is the first response fragment");
715             stackRet = AddServerResponse(&serverResponse, ehResponse->requestHandle);
716             if (OC_STACK_OK != stackRet)
717             {
718                 OC_LOG(ERROR, TAG, "Error adding server response");
719                 return stackRet;
720             }
721             VERIFY_NON_NULL(serverResponse);
722         }
723
724         if(ehResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION)
725         {
726             stackRet = OC_STACK_ERROR;
727             OC_LOG(ERROR, TAG, "Error adding payload, as it was the incorrect type");
728             goto exit;
729         }
730
731         if(!serverResponse->payload)
732         {
733             serverResponse->payload = ehResponse->payload;
734         }
735         else
736         {
737             OCRepPayloadAppend((OCRepPayload*)serverResponse->payload,
738                     (OCRepPayload*)ehResponse->payload);
739         }
740
741
742         (serverRequest->numResponses)--;
743
744         if(serverRequest->numResponses == 0)
745         {
746             OC_LOG(INFO, TAG, "This is the last response fragment");
747             ehResponse->payload = serverResponse->payload;
748             stackRet = HandleSingleResponse(ehResponse);
749             //Delete the request and response
750             FindAndDeleteServerRequest(serverRequest);
751             FindAndDeleteServerResponse(serverResponse);
752         }
753         else
754         {
755             OC_LOG(INFO, TAG, "More response fragments to come");
756             stackRet = OC_STACK_OK;
757         }
758     }
759 exit:
760     return stackRet;
761 }
762