Clean up the stack code of csdk to check NULL
[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         uint8_t * payload,
342         size_t payloadSize,
343         uint8_t numVendorOptions,
344         OCHeaderOption * vendorOptions,
345         OCObserveAction observeAction,
346         OCObservationId observeID)
347 {
348     if (entityHandlerRequest)
349     {
350         entityHandlerRequest->resource = (OCResourceHandle) resource;
351         entityHandlerRequest->requestHandle = request;
352         entityHandlerRequest->method = method;
353         entityHandlerRequest->devAddr = *endpoint;
354         entityHandlerRequest->query = queryBuf;
355         entityHandlerRequest->obsInfo.action = observeAction;
356         entityHandlerRequest->obsInfo.obsId = observeID;
357
358         if(payload && payloadSize)
359         {
360             if(OCParsePayload(&entityHandlerRequest->payload, PAYLOAD_TYPE_REPRESENTATION,
361                         payload, payloadSize) != OC_STACK_OK)
362             {
363                 return OC_STACK_ERROR;
364             }
365         }
366         else
367         {
368             entityHandlerRequest->payload = NULL;
369         }
370
371         entityHandlerRequest->numRcvdVendorSpecificHeaderOptions = numVendorOptions;
372         entityHandlerRequest->rcvdVendorSpecificHeaderOptions = vendorOptions;
373
374         return OC_STACK_OK;
375     }
376
377     return OC_STACK_INVALID_PARAM;
378 }
379
380 /**
381  * Find a server request in the server request list and delete
382  *
383  * @param serverRequest - server request to find and delete
384  */
385 void FindAndDeleteServerRequest(OCServerRequest * serverRequest)
386 {
387     OCServerRequest* tmp;
388     if(serverRequest)
389     {
390         LL_FOREACH(serverRequestList, tmp)
391         {
392             if (serverRequest == tmp)
393             {
394                 DeleteServerRequest(tmp);
395                 return;
396             }
397         }
398     }
399 }
400
401 CAResponseResult_t ConvertEHResultToCAResult (OCEntityHandlerResult result, OCMethod method)
402 {
403     CAResponseResult_t caResult;
404
405     switch (result)
406     {
407         case OC_EH_OK:
408            switch (method)
409            {
410                case OC_REST_PUT: 
411                case OC_REST_POST:
412                    // This Response Code is like HTTP 204 "No Content" but only used in
413                    // response to POST and PUT requests.
414                    caResult = CA_CHANGED;
415                    break;
416                case OC_REST_GET:
417                    // This Response Code is like HTTP 200 "OK" but only used in response to
418                    // GET requests.
419                    caResult = CA_CONTENT;
420                    break;
421                default:
422                    // This should not happen but,
423                    // give it a value just in case but output an error
424                    caResult = CA_CONTENT;
425                    OC_LOG_V(ERROR, TAG, "Unexpected OC_EH_OK return code for method [d].", method);
426            }
427             break;
428         case OC_EH_ERROR:
429             caResult = CA_BAD_REQ;
430             break;
431         case OC_EH_RESOURCE_CREATED:
432             caResult = CA_CREATED;
433             break;
434         case OC_EH_RESOURCE_DELETED:
435             caResult = CA_DELETED;
436             break;
437         case OC_EH_SLOW:
438             caResult = CA_CONTENT;
439             break;
440         case OC_EH_FORBIDDEN:
441             caResult = CA_UNAUTHORIZED_REQ;
442             break;
443         case OC_EH_RESOURCE_NOT_FOUND:
444             caResult = CA_NOT_FOUND;
445             break;
446         default:
447             caResult = CA_BAD_REQ;
448             break;
449     }
450     return caResult;
451 }
452
453
454 /**
455  * Handler function for sending a response from a single resource
456  *
457  * @param ehResponse - pointer to the response from the resource
458  *
459  * @return
460  *     OCStackResult
461  */
462
463 OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
464 {
465     OCStackResult result = OC_STACK_ERROR;
466     CAEndpoint_t responseEndpoint = {.adapter = CA_DEFAULT_ADAPTER};
467     CAResponseInfo_t responseInfo = {.result = CA_EMPTY};
468     CAHeaderOption_t* optionsPointer = NULL;
469
470     if(!ehResponse || !ehResponse->requestHandle)
471     {
472         return OC_STACK_ERROR;
473     }
474
475     OCServerRequest *serverRequest = (OCServerRequest *)ehResponse->requestHandle;
476
477     CopyDevAddrToEndpoint(&serverRequest->devAddr, &responseEndpoint);
478
479     responseInfo.info.resourceUri = serverRequest->resourceUrl;
480     responseInfo.result = ConvertEHResultToCAResult(ehResponse->ehResult, serverRequest->method);
481
482     if(serverRequest->notificationFlag && serverRequest->qos == OC_HIGH_QOS)
483     {
484         responseInfo.info.type = CA_MSG_CONFIRM;
485     }
486     else if(serverRequest->notificationFlag && serverRequest->qos != OC_HIGH_QOS)
487     {
488         responseInfo.info.type = CA_MSG_NONCONFIRM;
489     }
490     else if(!serverRequest->notificationFlag && !serverRequest->slowFlag &&
491             serverRequest->qos == OC_HIGH_QOS)
492     {
493         responseInfo.info.type = CA_MSG_ACKNOWLEDGE;
494     }
495     else if(!serverRequest->notificationFlag && serverRequest->slowFlag &&
496             serverRequest->qos == OC_HIGH_QOS)
497     {
498         responseInfo.info.type = CA_MSG_CONFIRM;
499     }
500     else if(!serverRequest->notificationFlag)
501     {
502         responseInfo.info.type = CA_MSG_NONCONFIRM;
503     }
504     else
505     {
506         OC_LOG(ERROR, TAG, "default responseInfo type is NON");
507         responseInfo.info.type = CA_MSG_NONCONFIRM;
508     }
509
510     char rspToken[CA_MAX_TOKEN_LEN + 1] = {};
511     responseInfo.info.messageId = serverRequest->coapID;
512     responseInfo.info.token = (CAToken_t)rspToken;
513
514     memcpy(responseInfo.info.token, serverRequest->requestToken, serverRequest->tokenLength);
515     responseInfo.info.tokenLength = serverRequest->tokenLength;
516
517     if(serverRequest->observeResult == OC_STACK_OK)
518     {
519         responseInfo.info.numOptions = ehResponse->numSendVendorSpecificHeaderOptions + 1;
520     }
521     else
522     {
523         responseInfo.info.numOptions = ehResponse->numSendVendorSpecificHeaderOptions;
524     }
525
526     if(responseInfo.info.numOptions > 0)
527     {
528         responseInfo.info.options = (CAHeaderOption_t *)
529                                       OICCalloc(responseInfo.info.numOptions,
530                                               sizeof(CAHeaderOption_t));
531
532         if(!responseInfo.info.options)
533         {
534             OC_LOG(FATAL, TAG, "Memory alloc for options failed");
535             return OC_STACK_NO_MEMORY;
536         }
537
538         optionsPointer = responseInfo.info.options;
539
540         // TODO: This exposes CoAP specific details.  At some point, this should be
541         // re-factored and handled in the CA layer.
542         if(serverRequest->observeResult == OC_STACK_OK)
543         {
544             responseInfo.info.options[0].protocolID = CA_COAP_ID;
545             responseInfo.info.options[0].optionID = COAP_OPTION_OBSERVE;
546             responseInfo.info.options[0].optionLength = sizeof(uint32_t);
547             uint8_t* observationData = (uint8_t*)responseInfo.info.options[0].optionData;
548             uint32_t observationOption= serverRequest->observationOption;
549
550             for (size_t i=sizeof(uint32_t); i; --i)
551             {
552                 observationData[i-1] = observationOption & 0xFF;
553                 observationOption >>=8;
554             }
555
556             // Point to the next header option before copying vender specific header options
557             optionsPointer += 1;
558         }
559
560         if (ehResponse->numSendVendorSpecificHeaderOptions)
561         {
562             memcpy(optionsPointer, ehResponse->sendVendorSpecificHeaderOptions,
563                             sizeof(OCHeaderOption) *
564                             ehResponse->numSendVendorSpecificHeaderOptions);
565         }
566     }
567     else
568     {
569         responseInfo.info.options = NULL;
570     }
571
572     responseInfo.isMulticast = false;
573     responseInfo.info.payload = NULL;
574     responseInfo.info.payloadSize = 0;
575     responseInfo.info.payloadFormat = CA_FORMAT_UNDEFINED;
576
577     // Put the JSON prefix and suffix around the payload
578     if(ehResponse->payload)
579     {
580         if (ehResponse->payload->type == PAYLOAD_TYPE_PRESENCE)
581         {
582             responseInfo.isMulticast = true;
583         }
584         else
585         {
586             responseInfo.isMulticast = false;
587         }
588
589         switch(serverRequest->acceptFormat)
590         {
591             case OC_FORMAT_UNDEFINED:
592                 // No preference set by the client, so default to CBOR then
593             case OC_FORMAT_CBOR:
594                 if((result = OCConvertPayload(ehResponse->payload, &responseInfo.info.payload,
595                                 &responseInfo.info.payloadSize))
596                         != OC_STACK_OK)
597                 {
598                     OC_LOG(ERROR, TAG, "Error converting payload");
599                     OICFree(responseInfo.info.options);
600                     return result;
601                 }
602                 responseInfo.info.payloadFormat = CA_FORMAT_APPLICATION_CBOR;
603                 break;
604             default:
605                 responseInfo.result = CA_NOT_ACCEPTABLE;
606         }
607     }
608
609 #ifdef WITH_PRESENCE
610     CATransportAdapter_t CAConnTypes[] = {
611                             CA_ADAPTER_IP,
612                             CA_ADAPTER_GATT_BTLE,
613                             CA_ADAPTER_RFCOMM_BTEDR
614
615 #ifdef RA_ADAPTER
616                             , CA_ADAPTER_REMOTE_ACCESS
617 #endif
618
619 #ifdef TCP_ADAPTER
620                             , CA_ADAPTER_TCP
621 #endif
622                         };
623
624     size_t size = sizeof(CAConnTypes)/ sizeof(CATransportAdapter_t);
625
626     CATransportAdapter_t adapter = responseEndpoint.adapter;
627     // Default adapter, try to send response out on all adapters.
628     if (adapter == CA_DEFAULT_ADAPTER)
629     {
630         adapter =
631             (CATransportAdapter_t)(
632                 CA_ADAPTER_IP           |
633                 CA_ADAPTER_GATT_BTLE    |
634                 CA_ADAPTER_RFCOMM_BTEDR
635
636 #ifdef RA_ADAP
637                 | CA_ADAPTER_REMOTE_ACCESS
638 #endif
639
640 #ifdef TCP_ADAPTER
641                 | CA_ADAPTER_TCP
642 #endif
643             );
644     }
645
646     result = OC_STACK_OK;
647     OCStackResult tempResult = OC_STACK_OK;
648
649     for(size_t i = 0; i < size; i++ )
650     {
651         responseEndpoint.adapter = (CATransportAdapter_t)(adapter & CAConnTypes[i]);
652         if(responseEndpoint.adapter)
653         {
654             //The result is set to OC_STACK_OK only if OCSendResponse succeeds in sending the
655             //response on all the n/w interfaces else it is set to OC_STACK_ERROR
656             tempResult = OCSendResponse(&responseEndpoint, &responseInfo);
657         }
658         if(OC_STACK_OK != tempResult)
659         {
660             result = tempResult;
661         }
662     }
663 #else
664
665     OC_LOG(INFO, TAG, "Calling OCSendResponse with:");
666     OC_LOG_V(INFO, TAG, "\tEndpoint address: %s", responseEndpoint.addr);
667     OC_LOG_V(INFO, TAG, "\tEndpoint adapter: %s", responseEndpoint.adapter);
668     OC_LOG_V(INFO, TAG, "\tResponse result : %s", responseInfo.result);
669     OC_LOG_V(INFO, TAG, "\tResponse for uri: %s", responseInfo.info.resourceUri);
670
671     result = OCSendResponse(&responseEndpoint, &responseInfo);
672 #endif
673
674     OICFree(responseInfo.info.payload);
675     OICFree(responseInfo.info.options);
676     //Delete the request
677     FindAndDeleteServerRequest(serverRequest);
678     return result;
679 }
680
681 /**
682  * Handler function for sending a response from multiple resources, such as a collection.
683  * Aggregates responses from multiple resource until all responses are received then sends the
684  * concatenated response
685  *
686  * TODO: Need to add a timeout in case a (remote?) resource does not respond
687  *
688  * @param ehResponse - pointer to the response from the resource
689  *
690  * @return
691  *     OCStackResult
692  */
693 OCStackResult HandleAggregateResponse(OCEntityHandlerResponse * ehResponse)
694 {
695     if(!ehResponse || !ehResponse->payload)
696     {
697         OC_LOG(ERROR, TAG, "HandleAggregateResponse invalid parameters");
698         return OC_STACK_INVALID_PARAM;
699     }
700
701     OC_LOG(INFO, TAG, "Inside HandleAggregateResponse");
702
703     OCServerRequest *serverRequest = GetServerRequestUsingHandle((OCServerRequest *)
704                                                                  ehResponse->requestHandle);
705     OCServerResponse *serverResponse = GetServerResponseUsingHandle((OCServerRequest *)
706                                                                     ehResponse->requestHandle);
707
708     OCStackResult stackRet = OC_STACK_ERROR;
709     if(serverRequest)
710     {
711         if(!serverResponse)
712         {
713             OC_LOG(INFO, TAG, "This is the first response fragment");
714             stackRet = AddServerResponse(&serverResponse, ehResponse->requestHandle);
715             if (OC_STACK_OK != stackRet)
716             {
717                 OC_LOG(ERROR, TAG, "Error adding server response");
718                 return stackRet;
719             }
720             VERIFY_NON_NULL(serverResponse);
721         }
722
723         if(ehResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION)
724         {
725             stackRet = OC_STACK_ERROR;
726             OC_LOG(ERROR, TAG, "Error adding payload, as it was the incorrect type");
727             goto exit;
728         }
729
730         if(!serverResponse->payload)
731         {
732             serverResponse->payload = ehResponse->payload;
733         }
734         else
735         {
736             OCRepPayloadAppend((OCRepPayload*)serverResponse->payload,
737                     (OCRepPayload*)ehResponse->payload);
738         }
739
740
741         (serverRequest->numResponses)--;
742
743         if(serverRequest->numResponses == 0)
744         {
745             OC_LOG(INFO, TAG, "This is the last response fragment");
746             ehResponse->payload = serverResponse->payload;
747             stackRet = HandleSingleResponse(ehResponse);
748             //Delete the request and response
749             FindAndDeleteServerRequest(serverRequest);
750             FindAndDeleteServerResponse(serverResponse);
751         }
752         else
753         {
754             OC_LOG(INFO, TAG, "More response fragments to come");
755             stackRet = OC_STACK_OK;
756         }
757     }
758 exit:
759     return stackRet;
760 }
761