Merge branch 'master' into simulator.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / tcp_adapter / catcpserver.c
1 /* ****************************************************************j
2  *
3  * Copyright 2015 Samsung Electronics 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
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/ioctl.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #include <sys/select.h>
29 #include <arpa/inet.h>
30 #include <netinet/in.h>
31 #include <net/if.h>
32 #include <errno.h>
33 #include <sys/poll.h>
34
35 #ifndef WITH_ARDUINO
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <netdb.h>
39 #endif
40
41 #include "catcpinterface.h"
42 #include "pdu.h"
43 #include "caadapterutils.h"
44 #include "camutex.h"
45 #include "oic_malloc.h"
46 #include "oic_string.h"
47
48 /**
49  * Logging tag for module name.
50  */
51 #define TAG "TCP_SERVER"
52
53 /**
54  * Server port number for local test.
55  */
56 #define SERVER_PORT 8000
57
58 /**
59  * Maximum CoAP over TCP header length
60  * to know the total data length.
61  */
62 #define TCP_MAX_HEADER_LEN  6
63
64 /**
65  * Default Thread Counts in TCP adapter
66  */
67 #define CA_TCP_DEFAULT_THREAD_COUNTS    2
68
69 /**
70  * Accept server file descriptor.
71  */
72 static int g_acceptServerFD = -1;
73
74 /**
75  * Mutex to synchronize device object list.
76  */
77 static ca_mutex g_mutexObjectList = NULL;
78
79 /**
80  * Conditional mutex to synchronize.
81  */
82 static ca_cond g_condObjectList = NULL;
83
84 /**
85  * Maintains the current running thread counts.
86  */
87 static uint32_t g_threadCounts = CA_TCP_DEFAULT_THREAD_COUNTS;
88
89 /**
90  * Maintains the callback to be notified when data received from remote device.
91  */
92 static CATCPPacketReceivedCallback g_packetReceivedCallback;
93
94 /**
95  * Error callback to update error in TCP.
96  */
97 static CATCPErrorHandleCallback g_TCPErrorHandler = NULL;
98
99 static CAResult_t CATCPCreateMutex();
100 static void CATCPDestroyMutex();
101 static CAResult_t CATCPCreateCond();
102 static void CATCPDestroyCond();
103 static void CAAcceptHandler(void *data);
104 static void CAReceiveHandler(void *data);
105 static CAResult_t CAReceiveMessage();
106 static int CASetNonblocking(int fd);
107 static int CATCPCreateSocket(int family, CATCPServerInfo_t *TCPServerInfo);
108 static size_t CAGetTotalLengthFromHeader(const unsigned char *recvBuffer);
109 static void CATCPDisconnectAll();
110
111 static void CATCPDestroyMutex()
112 {
113     if (g_mutexObjectList)
114     {
115         ca_mutex_free(g_mutexObjectList);
116         g_mutexObjectList = NULL;
117     }
118 }
119
120 static CAResult_t CATCPCreateMutex()
121 {
122     if (!g_mutexObjectList)
123     {
124         g_mutexObjectList = ca_mutex_new();
125         if (!g_mutexObjectList)
126         {
127             OIC_LOG(ERROR, TAG, "Failed to created mutex!");
128             return CA_STATUS_FAILED;
129         }
130     }
131
132     return CA_STATUS_OK;
133 }
134
135 static void CATCPDestroyCond()
136 {
137     if (g_condObjectList)
138     {
139         ca_cond_free(g_condObjectList);
140         g_condObjectList = NULL;
141     }
142 }
143
144 static CAResult_t CATCPCreateCond()
145 {
146     if (!g_condObjectList)
147     {
148         g_condObjectList = ca_cond_new();
149         if (!g_condObjectList)
150         {
151             OIC_LOG(ERROR, TAG, "Failed to created cond!");
152             return CA_STATUS_FAILED;
153         }
154     }
155     return CA_STATUS_OK;
156 }
157
158 static void CATCPDisconnectAll()
159 {
160     OIC_LOG(DEBUG, TAG, "IN");
161
162     ca_mutex_lock(g_mutexObjectList);
163     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
164
165     CATCPServerInfo_t *svritem = NULL;
166     for (size_t i = 0; i < length; i++)
167     {
168         svritem = (CATCPServerInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
169         if (svritem && svritem->u4tcp.fd >= 0)
170         {
171             shutdown(svritem->u4tcp.fd, SHUT_RDWR);
172             close(svritem->u4tcp.fd);
173         }
174     }
175     u_arraylist_destroy(caglobals.tcp.svrlist);
176     caglobals.tcp.svrlist = NULL;
177     ca_mutex_unlock(g_mutexObjectList);
178
179     OIC_LOG(DEBUG, TAG, "OUT");
180 }
181
182 static void CAReceiveHandler(void *data)
183 {
184     (void)data;
185     OIC_LOG(DEBUG, TAG, "IN - CAReceiveHandler");
186
187     while (!caglobals.tcp.terminate)
188     {
189         CAReceiveMessage();
190     }
191
192     ca_mutex_lock(g_mutexObjectList);
193     // notify the thread
194     g_threadCounts--;
195     if (!g_threadCounts)
196     {
197         ca_cond_signal(g_condObjectList);
198     }
199     ca_mutex_unlock(g_mutexObjectList);
200
201     OIC_LOG(DEBUG, TAG, "OUT - CAReceiveHandler");
202 }
203
204 static size_t CAGetTotalLengthFromHeader(const unsigned char *recvBuffer)
205 {
206     OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
207
208     coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(
209             ((unsigned char *)recvBuffer)[0] >> 4);
210     size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
211                                                         transport);
212     size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
213
214     OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%zu]", optPaylaodLen);
215     OIC_LOG_V(DEBUG, TAG, "header length [%zu]", headerLen);
216     OIC_LOG_V(DEBUG, TAG, "total data length [%zu]", headerLen + optPaylaodLen);
217
218     OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
219     return headerLen + optPaylaodLen;
220 }
221
222 static CAResult_t CAReceiveMessage()
223 {
224     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
225
226     size_t i = 0;
227     unsigned char *recvBuffer = NULL;
228     CATCPServerInfo_t *svritem = NULL;
229     for (i = 0; i < length; i++)
230     {
231         svritem = (CATCPServerInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
232         if (svritem->u4tcp.fd < 0)
233         {
234             continue;
235         }
236
237         size_t bufSize = TCP_MAX_HEADER_LEN;
238         recvBuffer = (unsigned char *) OICCalloc(1, bufSize);
239         if (!recvBuffer)
240         {
241             OIC_LOG(ERROR, TAG, "out of memory");
242             goto exit;
243         }
244
245         bool isHeaderChecked = false;
246         size_t totalLen = 0;
247         size_t totalReceivedLen = 0;
248         do
249         {
250             ssize_t recvLen = recv(svritem->u4tcp.fd, recvBuffer + totalReceivedLen,
251                                    bufSize - totalReceivedLen, 0);
252             if (recvLen <= 0)
253             {
254                 if(EWOULDBLOCK != errno)
255                 {
256                     OIC_LOG_V(ERROR, TAG, "Recvfrom failed %s", strerror(errno));
257                     goto exit;
258                 }
259                 // if received data length is zero, we are breaking loop.
260                 // because we use non-blocking socket to receive data from remote device.
261                 if (!totalReceivedLen)
262                 {
263                     break;
264                 }
265                 continue;
266             }
267
268             totalReceivedLen += recvLen;
269             if (!isHeaderChecked && totalReceivedLen)
270             {
271                 coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(
272                         ((unsigned char *)recvBuffer)[0] >> 4);
273                 size_t headerLen = coap_get_tcp_header_length_for_transport(transport);
274                 if (totalReceivedLen >= headerLen)
275                 {
276                     // get actual data length from coap over tcp header
277                     totalLen = CAGetTotalLengthFromHeader((unsigned char *) recvBuffer);
278                     bufSize = totalLen;
279                     unsigned char *newBuf = OICRealloc(recvBuffer, bufSize);
280                     if (NULL == newBuf)
281                     {
282                         OIC_LOG(ERROR, TAG, "out of memory");
283                         goto exit;
284                     }
285                     recvBuffer = newBuf;
286                     isHeaderChecked = true;
287                 }
288             }
289             if (totalLen == totalReceivedLen)
290             {
291                 CAEndpoint_t ep = { .adapter = CA_ADAPTER_TCP,
292                                     .port = svritem->u4tcp.port };
293                 strncpy(ep.addr, svritem->addr, sizeof(ep.addr));
294
295                 if (g_packetReceivedCallback)
296                 {
297                     g_packetReceivedCallback(&ep, recvBuffer, totalLen);
298                 }
299                 OIC_LOG_V(DEBUG, TAG, "received data len:%zu", totalLen);
300                 break;
301             }
302         } while (!totalLen || totalLen > totalReceivedLen);
303
304         OICFree(recvBuffer);
305     }
306
307     return CA_STATUS_OK;
308
309 exit:
310     ca_mutex_lock(g_mutexObjectList);
311     close(svritem->u4tcp.fd);
312     u_arraylist_remove(caglobals.tcp.svrlist, i);
313     ca_mutex_unlock(g_mutexObjectList);
314     OICFree(recvBuffer);
315     return CA_STATUS_FAILED;
316 }
317
318 // TODO: resolving duplication.
319 static int CASetNonblocking(int fd)
320 {
321     int fl = fcntl(fd, F_GETFL);
322     if (fl == -1)
323     {
324         OIC_LOG_V(ERROR, TAG, "Failed to get existing flags, Error code: %s",
325                   strerror(errno));
326     }
327     else if ((fl & O_NONBLOCK) != O_NONBLOCK)
328     {
329         fl = fcntl(fd, F_SETFL, fl | O_NONBLOCK);
330         if (fl == -1)
331         {
332             OIC_LOG_V(ERROR, TAG, "Failed to set non-blocking mode, Error code: %s",
333                       strerror(errno));
334         }
335     }
336
337     return fl;
338 }
339
340 static int CATCPCreateSocket(int family, CATCPServerInfo_t *TCPServerInfo)
341 {
342     // create tcp socket
343     int fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
344     if (-1 == fd)
345     {
346         OIC_LOG_V(ERROR, TAG, "create socket failed: %s", strerror(errno));
347         goto exit;
348     }
349
350     // set non-blocking socket
351     if (-1 == CASetNonblocking(fd))
352     {
353         goto exit;
354     }
355
356     struct sockaddr_storage sa = { .ss_family = family };
357     CAConvertNameToAddr(TCPServerInfo->addr, TCPServerInfo->u4tcp.port, &sa);
358     socklen_t socklen = sizeof (struct sockaddr_in);
359
360     // connect to TCP server
361     int ret = connect(fd, (struct sockaddr *)&sa, socklen);
362     if (0 == ret)
363     {
364         OIC_LOG(DEBUG, TAG, "connect socket success");
365     }
366     else if (EINPROGRESS == errno)
367     {
368         int error = 0;
369         socklen_t len = sizeof(error);
370         if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
371         {
372             OIC_LOG(ERROR, TAG, "getsockopt() error");
373             goto exit;
374         }
375
376         if (error)
377         {
378             if (ECONNREFUSED == error)
379             {
380                 OIC_LOG(ERROR, TAG, "connection refused");
381                 goto exit;
382             }
383             OIC_LOG(ERROR, TAG, "failed to connect socket");
384             goto exit;
385         }
386         OIC_LOG(DEBUG, TAG, "connect socket success");
387     }
388     else
389     {
390         OIC_LOG(ERROR, TAG, "failed to connect socket");
391         goto exit;
392     }
393
394     return fd;
395
396 exit:
397     if (fd >= 0)
398     {
399         close(fd);
400     }
401     return -1;
402 }
403
404 static void CAAcceptHandler(void *data)
405 {
406     (void)data;
407     OIC_LOG(DEBUG, TAG, "IN - CAAcceptHandler");
408
409     int reuse = 1;
410     struct sockaddr_in server = { .sin_addr.s_addr = INADDR_ANY,
411                                   .sin_family = AF_INET,
412                                   .sin_port = htons(SERVER_PORT) };
413
414     g_acceptServerFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
415     if (g_acceptServerFD < 0)
416     {
417         OIC_LOG(ERROR, TAG, "Failed to create socket");
418         goto exit;
419     }
420
421     if (-1 == setsockopt(g_acceptServerFD, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)))
422     {
423         OIC_LOG(ERROR, TAG, "setsockopt SO_REUSEADDR");
424         goto exit;
425     }
426
427     int serverlen = sizeof(server);
428     if (-1 == bind(g_acceptServerFD, (struct sockaddr *)&server, serverlen))
429     {
430         OIC_LOG(ERROR, TAG, "bind() error");
431         goto exit;
432     }
433
434     if (listen(g_acceptServerFD, caglobals.tcp.listenBacklog) != 0)
435     {
436         OIC_LOG(ERROR, TAG, "listen() error");
437         goto exit;
438     }
439
440     struct pollfd acceptServerFD = { .fd = g_acceptServerFD,
441                                      .events = POLLIN };
442
443     while (!caglobals.tcp.terminate)
444     {
445         int pollState = poll(&acceptServerFD, 1, caglobals.tcp.selectTimeout);
446         if (pollState < 0)
447         {
448             OIC_LOG_V(FATAL, TAG, "polling error %s", strerror(errno));
449             goto exit;
450         }
451         else if (!pollState)
452         {
453             continue;
454         }
455
456         if (acceptServerFD.revents & POLLIN)
457         {
458             struct sockaddr_storage clientaddr;
459             socklen_t clientlen = sizeof (struct sockaddr_in);
460
461             int sockfd = accept(g_acceptServerFD, (struct sockaddr *)&clientaddr, &clientlen);
462             if (sockfd != -1)
463             {
464                 CATCPServerInfo_t *svritem = (CATCPServerInfo_t *) OICMalloc(sizeof (*svritem));
465                 if (!svritem)
466                 {
467                     OIC_LOG(ERROR, TAG, "Out of memory");
468                     close(sockfd);
469                     return;
470                 }
471
472                 // set non-blocking socket
473                 if (-1 == CASetNonblocking(sockfd))
474                 {
475                     close(sockfd);
476                     OICFree(svritem);
477                     continue;
478                 }
479                 svritem->u4tcp.fd = sockfd;
480
481                 CAConvertAddrToName((struct sockaddr_storage *)&clientaddr, clientlen,
482                                     (char *) &svritem->addr, &svritem->u4tcp.port);
483
484                 ca_mutex_lock(g_mutexObjectList);
485                 bool res = u_arraylist_add(caglobals.tcp.svrlist, svritem);
486                 if (!res)
487                 {
488                     OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
489                     close(sockfd);
490                     OICFree(svritem);
491                     ca_mutex_unlock(g_mutexObjectList);
492                     continue;
493                 }
494                 ca_mutex_unlock(g_mutexObjectList);
495             }
496         }
497     }
498
499     ca_mutex_lock(g_mutexObjectList);
500     // notify the thread
501     g_threadCounts--;
502     if (!g_threadCounts)
503     {
504         ca_cond_signal(g_condObjectList);
505     }
506     ca_mutex_unlock(g_mutexObjectList);
507
508     OIC_LOG(DEBUG, TAG, "OUT - CAAcceptHandler");
509
510 exit:
511     if (g_acceptServerFD >= 0)
512     {
513         close(g_acceptServerFD);
514     }
515     ca_mutex_lock(g_mutexObjectList);
516     g_threadCounts--;
517     if (!g_threadCounts)
518     {
519         ca_cond_signal(g_condObjectList);
520     }
521     ca_mutex_unlock(g_mutexObjectList);
522     return;
523 }
524
525 CAResult_t CATCPStartServer(const ca_thread_pool_t threadPool)
526 {
527     if (caglobals.tcp.started)
528     {
529         return CA_STATUS_OK;
530     }
531
532     if (!caglobals.tcp.ipv4tcpenabled)
533     {
534         caglobals.tcp.ipv4tcpenabled = true;    // only needed to run CA tests
535     }
536
537     CAResult_t res = CATCPCreateMutex();
538     if (CA_STATUS_OK != res)
539     {
540         OIC_LOG(ERROR, TAG, "failed to create mutex");
541         return res;
542     }
543
544     res = CATCPCreateCond();
545     if (CA_STATUS_OK != res)
546     {
547         OIC_LOG(ERROR, TAG, "failed to create cond");
548         return res;
549     }
550
551     ca_mutex_lock(g_mutexObjectList);
552     if (!caglobals.tcp.svrlist)
553     {
554         caglobals.tcp.svrlist = u_arraylist_create();
555     }
556     ca_mutex_unlock(g_mutexObjectList);
557
558     caglobals.tcp.terminate = false;
559
560     res = ca_thread_pool_add_task(threadPool, CAAcceptHandler, NULL);
561     if (CA_STATUS_OK != res)
562     {
563         OIC_LOG(ERROR, TAG, "thread_pool_add_task failed");
564         return res;
565     }
566     OIC_LOG(DEBUG, TAG, "CAAcceptHandler thread started successfully.");
567
568     res = ca_thread_pool_add_task(threadPool, CAReceiveHandler, NULL);
569     if (CA_STATUS_OK != res)
570     {
571         OIC_LOG(ERROR, TAG, "thread_pool_add_task failed");
572         return res;
573     }
574     OIC_LOG(DEBUG, TAG, "CAReceiveHandler thread started successfully.");
575
576     caglobals.tcp.started = true;
577
578     g_threadCounts = CA_TCP_DEFAULT_THREAD_COUNTS;
579
580     return CA_STATUS_OK;
581 }
582
583 void CATCPStopServer()
584 {
585     OIC_LOG(DEBUG, TAG, "IN");
586
587     // mutex lock
588     ca_mutex_lock(g_mutexObjectList);
589
590     // set terminate flag
591     caglobals.tcp.terminate = true;
592     caglobals.tcp.started = false;
593
594     ca_cond_wait(g_condObjectList, g_mutexObjectList);
595
596     // mutex unlock
597     ca_mutex_unlock(g_mutexObjectList);
598
599     if (-1 != g_acceptServerFD)
600     {
601         close(g_acceptServerFD);
602         g_acceptServerFD = -1;
603     }
604
605     CATCPDisconnectAll();
606     CATCPDestroyMutex();
607     CATCPDestroyCond();
608
609     OIC_LOG(DEBUG, TAG, "OUT");
610 }
611
612 void CATCPSetPacketReceiveCallback(CATCPPacketReceivedCallback callback)
613 {
614     OIC_LOG(DEBUG, TAG, "IN");
615
616     g_packetReceivedCallback = callback;
617
618     OIC_LOG(DEBUG, TAG, "OUT");
619 }
620
621 static size_t CACheckPayloadLength(const void *data, size_t dlen)
622 {
623     coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(
624             ((unsigned char *)data)[0] >> 4);
625
626     coap_pdu_t *pdu = coap_new_pdu(transport, dlen);
627     if (!pdu)
628     {
629         OIC_LOG(ERROR, TAG, "outpdu is null");
630         return 0;
631     }
632
633     int ret = coap_pdu_parse((unsigned char *) data, dlen, pdu, transport);
634     if (0 >= ret)
635     {
636         OIC_LOG(ERROR, TAG, "pdu parse failed");
637         coap_delete_pdu(pdu);
638         return 0;
639     }
640
641     size_t payloadLen = 0;
642     size_t headerSize = coap_get_tcp_header_length_for_transport(transport);
643     OIC_LOG_V(DEBUG, TAG, "headerSize : %d, pdu length : %d",
644               headerSize, pdu->length);
645     if (pdu->length > headerSize)
646     {
647         payloadLen = (unsigned char *) pdu->hdr + pdu->length - pdu->data;
648     }
649
650     OICFree(pdu);
651
652     return payloadLen;
653 }
654
655 static void sendData(const CAEndpoint_t *endpoint,
656                      const void *data, size_t dlen)
657 {
658     // #1. get TCP Server object from list
659     uint32_t index = 0;
660     CATCPServerInfo_t *svritem = CAGetTCPServerInfoFromList(endpoint->addr, endpoint->port,
661                                                             &index);
662     if (!svritem)
663     {
664         // if there is no connection info, connect to TCP Server
665         svritem = CAConnectToTCPServer(endpoint);
666         if (!svritem)
667         {
668             OIC_LOG(ERROR, TAG, "Failed to create TCP server object");
669             g_TCPErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
670             return;
671         }
672     }
673
674     // #2. check payload length
675     size_t payloadLen = CACheckPayloadLength(data, dlen);
676     // if payload length is zero, disconnect from TCP server
677     if (!payloadLen)
678     {
679         OIC_LOG(DEBUG, TAG, "payload length is zero, disconnect from remote device");
680         CADisconnectFromTCPServer(endpoint);
681         return;
682     }
683
684     // #3. check connection state
685     if (svritem->u4tcp.fd < 0)
686     {
687         // if file descriptor value is wrong, remove TCP Server info from list
688         OIC_LOG(ERROR, TAG, "Failed to connect to TCP server");
689         CADisconnectFromTCPServer(endpoint);
690         g_TCPErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
691         return;
692     }
693
694     // #4. send data to TCP Server
695     ssize_t remainLen = dlen;
696     do
697     {
698         ssize_t len = send(svritem->u4tcp.fd, data, remainLen, 0);
699         if (-1 == len)
700         {
701             if (EWOULDBLOCK != errno)
702             {
703                 OIC_LOG_V(ERROR, TAG, "unicast ipv4tcp sendTo failed: %s", strerror(errno));
704                 g_TCPErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
705                 return;
706             }
707             continue;
708         }
709         data += len;
710         remainLen -= len;
711     } while (remainLen > 0);
712
713     OIC_LOG_V(INFO, TAG, "unicast ipv4tcp sendTo is successful: %zu bytes", dlen);
714 }
715
716 void CATCPSendData(CAEndpoint_t *endpoint, const void *data, uint32_t datalen,
717                    bool isMulticast)
718 {
719     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
720     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
721
722     if (!isMulticast)
723     {
724         if (caglobals.tcp.ipv4tcpenabled && (endpoint->adapter & CA_ADAPTER_TCP))
725         {
726             sendData(endpoint, data, datalen);
727         }
728     }
729 }
730
731 CAResult_t CAGetTCPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
732 {
733     OIC_LOG(DEBUG, TAG, "IN");
734
735     VERIFY_NON_NULL(info, TAG, "info is NULL");
736     VERIFY_NON_NULL(size, TAG, "size is NULL");
737
738     return CA_NOT_SUPPORTED;
739 }
740
741 CATCPServerInfo_t *CAConnectToTCPServer(const CAEndpoint_t *TCPServerInfo)
742 {
743     VERIFY_NON_NULL_RET(TCPServerInfo, TAG, "TCPServerInfo is NULL", NULL);
744
745     // #1. create TCP server object
746     CATCPServerInfo_t *svritem = (CATCPServerInfo_t *) OICMalloc(sizeof (*svritem));
747     if (!svritem)
748     {
749         OIC_LOG(ERROR, TAG, "Out of memory");
750         return NULL;
751     }
752     memcpy(svritem->addr, TCPServerInfo->addr, sizeof(svritem->addr));
753     svritem->u4tcp.port = TCPServerInfo->port;
754
755     // #2. create the socket and connect to TCP server
756     if (caglobals.tcp.ipv4tcpenabled)
757     {
758         svritem->u4tcp.fd = CATCPCreateSocket(AF_INET, svritem);
759         if (-1 == svritem->u4tcp.fd)
760         {
761             OICFree(svritem);
762             return NULL;
763         }
764     }
765
766     // #3. add TCP connection info to list
767     ca_mutex_lock(g_mutexObjectList);
768     if (caglobals.tcp.svrlist)
769     {
770         bool res = u_arraylist_add(caglobals.tcp.svrlist, svritem);
771         if (!res)
772         {
773             OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
774             close(svritem->u4tcp.fd);
775             OICFree(svritem);
776             ca_mutex_unlock(g_mutexObjectList);
777             return NULL;
778         }
779     }
780     ca_mutex_unlock(g_mutexObjectList);
781
782     return svritem;
783 }
784
785 CAResult_t CADisconnectFromTCPServer(const CAEndpoint_t *TCPServerInfo)
786 {
787     VERIFY_NON_NULL(TCPServerInfo, TAG, "TCP server info is NULL");
788
789     // #1. get server info
790     uint32_t index = 0;
791     ca_mutex_lock(g_mutexObjectList);
792     CATCPServerInfo_t *svritem = CAGetTCPServerInfoFromList(TCPServerInfo->addr,
793                                                             TCPServerInfo->port,
794                                                             &index);
795     if (!svritem)
796     {
797         OIC_LOG(ERROR, TAG, "there is no connection info");
798         ca_mutex_unlock(g_mutexObjectList);
799         return CA_STATUS_FAILED;
800     }
801
802     // #2. close the socket and remove TCP connection info in list
803     if (svritem->u4tcp.fd >= 0)
804     {
805         close(svritem->u4tcp.fd);
806     }
807     u_arraylist_remove(caglobals.tcp.svrlist, index);
808     ca_mutex_unlock(g_mutexObjectList);
809
810     return CA_STATUS_OK;
811 }
812
813 CATCPServerInfo_t *CAGetTCPServerInfoFromList(const char *addr, const uint16_t port,
814                                               uint32_t *index)
815 {
816     VERIFY_NON_NULL_RET(addr, TAG, "addr is NULL", NULL);
817     VERIFY_NON_NULL_RET(index, TAG, "index is NULL", NULL);
818
819     // get connection info from list
820     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
821
822     for (size_t i = 0; i < length; i++)
823     {
824         CATCPServerInfo_t *svritem = (CATCPServerInfo_t *) u_arraylist_get(
825                 caglobals.tcp.svrlist, i);
826         if (!svritem)
827         {
828             continue;
829         }
830
831         if (!strncmp(svritem->addr, addr, sizeof(svritem->addr))
832                 && (svritem->u4tcp.port == port))
833         {
834             *index = i;
835             return svritem;
836         }
837     }
838
839     return NULL;
840 }
841
842 void CATCPSetErrorHandler(CATCPErrorHandleCallback errorHandleCallback)
843 {
844     g_TCPErrorHandler = errorHandleCallback;
845 }