1 /* ****************************************************************
3 * Copyright 2015 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 ******************************************************************/
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/select.h>
24 #include <sys/ioctl.h>
29 #include <arpa/inet.h>
30 #include <netinet/in.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
40 #include "catcpinterface.h"
42 #include "caadapterutils.h"
44 #include "oic_malloc.h"
47 #include "ca_adapter_net_tls.h"
51 * Logging tag for module name.
53 #define TAG "OIC_CA_TCP_SERVER"
56 * Maximum CoAP over TCP header length
57 * to know the total data length.
59 #define COAP_MAX_HEADER_SIZE 6
64 #define TLS_HEADER_SIZE 5
67 * Mutex to synchronize device object list.
69 static ca_mutex g_mutexObjectList = NULL;
72 * Conditional mutex to synchronize.
74 static ca_cond g_condObjectList = NULL;
77 * Maintains the callback to be notified when data received from remote device.
79 static CATCPPacketReceivedCallback g_packetReceivedCallback = NULL;
82 * Error callback to update error in TCP.
84 static CATCPErrorHandleCallback g_tcpErrorHandler = NULL;
87 * Connected Callback to pass the connection information to RI.
89 static CATCPConnectionHandleCallback g_connectionCallback = NULL;
91 static CAResult_t CATCPCreateMutex();
92 static void CATCPDestroyMutex();
93 static CAResult_t CATCPCreateCond();
94 static void CATCPDestroyCond();
95 static int CACreateAcceptSocket(int family, CASocket_t *sock);
96 static void CAAcceptConnection(CATransportFlags_t flag, CASocket_t *sock);
97 static void CAFindReadyMessage();
98 static void CASelectReturned(fd_set *readFds);
99 static void CAReceiveMessage(int fd);
100 static void CAReceiveHandler(void *data);
101 static int CATCPCreateSocket(int family, CATCPSessionInfo_t *tcpServerInfo);
103 #define CHECKFD(FD) \
104 if (FD > caglobals.tcp.maxfd) \
105 caglobals.tcp.maxfd = FD;
107 #define REALLOC(buffer, length) \
109 unsigned char *tmpBuf = OICRealloc(buffer, length); \
112 OIC_LOG(ERROR, TAG, "out of memory"); \
119 * Read length amount of data from socket fd
120 * Made a few recv calls if required
122 * @param[in] fd - socket
123 * @param[out] item - used to update received message length
124 * @param[out] data - buffer to store data
125 * @param[in] length - length of data required to read
126 * @param[in] flags - additional info about socket
128 #define RECV(fd, item, data, length, flags) \
130 int remain_len = length; \
132 while (remain_len > 0) \
134 len = recv(fd, data + item->len, remain_len, flags); \
135 OIC_LOG_V(DEBUG, TAG, "recv len = %d", len); \
136 OIC_LOG_BUFFER(DEBUG, TAG, data + item->len, len); \
137 if (2 == len && 0 == data[item->len] && 0 == data[item->len + 1]) \
139 OIC_LOG(DEBUG, TAG, "received RESET message. Skip it"); \
144 OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno)); \
149 OIC_LOG(INFO, TAG, "Received disconnect from peer. Close connection"); \
157 static void CATCPDestroyMutex()
159 if (g_mutexObjectList)
161 ca_mutex_free(g_mutexObjectList);
162 g_mutexObjectList = NULL;
166 static CAResult_t CATCPCreateMutex()
168 if (!g_mutexObjectList)
170 g_mutexObjectList = ca_mutex_new();
171 if (!g_mutexObjectList)
173 OIC_LOG(ERROR, TAG, "Failed to created mutex!");
174 return CA_STATUS_FAILED;
181 static void CATCPDestroyCond()
183 if (g_condObjectList)
185 ca_cond_free(g_condObjectList);
186 g_condObjectList = NULL;
190 static CAResult_t CATCPCreateCond()
192 if (!g_condObjectList)
194 g_condObjectList = ca_cond_new();
195 if (!g_condObjectList)
197 OIC_LOG(ERROR, TAG, "Failed to created cond!");
198 return CA_STATUS_FAILED;
204 static void CAReceiveHandler(void *data)
207 OIC_LOG(DEBUG, TAG, "IN - CAReceiveHandler");
209 while (!caglobals.tcp.terminate)
211 CAFindReadyMessage();
214 ca_mutex_lock(g_mutexObjectList);
215 ca_cond_signal(g_condObjectList);
216 ca_mutex_unlock(g_mutexObjectList);
218 OIC_LOG(DEBUG, TAG, "OUT - CAReceiveHandler");
221 static void CAFindReadyMessage()
224 struct timeval timeout = { .tv_sec = caglobals.tcp.selectTimeout };
228 if (-1 != caglobals.tcp.ipv4.fd)
230 FD_SET(caglobals.tcp.ipv4.fd, &readFds);
232 if (-1 != caglobals.tcp.ipv6.fd)
234 FD_SET(caglobals.tcp.ipv6.fd, &readFds);
236 if (-1 != caglobals.tcp.shutdownFds[0])
238 FD_SET(caglobals.tcp.shutdownFds[0], &readFds);
240 if (-1 != caglobals.tcp.connectionFds[0])
242 FD_SET(caglobals.tcp.connectionFds[0], &readFds);
245 uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
246 for (size_t i = 0; i < length; i++)
248 CATCPSessionInfo_t *svritem =
249 (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
250 if (svritem && 0 <= svritem->fd)
252 FD_SET(svritem->fd, &readFds);
256 int ret = select(caglobals.tcp.maxfd + 1, &readFds, NULL, NULL, &timeout);
258 if (caglobals.tcp.terminate)
260 OIC_LOG_V(DEBUG, TAG, "Packet receiver Stop request received.");
267 OIC_LOG_V(FATAL, TAG, "select error %s", strerror(errno));
272 CASelectReturned(&readFds);
275 static void CASelectReturned(fd_set *readFds)
277 VERIFY_NON_NULL_VOID(readFds, TAG, "readFds is NULL");
279 if (caglobals.tcp.ipv4.fd != -1 && FD_ISSET(caglobals.tcp.ipv4.fd, readFds))
281 CAAcceptConnection(CA_IPV4, &caglobals.tcp.ipv4);
284 else if (caglobals.tcp.ipv6.fd != -1 && FD_ISSET(caglobals.tcp.ipv6.fd, readFds))
286 CAAcceptConnection(CA_IPV6, &caglobals.tcp.ipv6);
289 else if (-1 != caglobals.tcp.connectionFds[0] &&
290 FD_ISSET(caglobals.tcp.connectionFds[0], readFds))
292 // new connection was created from remote device.
293 // exit the function to update read file descriptor.
294 char buf[MAX_ADDR_STR_SIZE_CA] = {0};
295 ssize_t len = read(caglobals.tcp.connectionFds[0], buf, sizeof (buf));
300 OIC_LOG_V(DEBUG, TAG, "Received new connection event with [%s]", buf);
301 FD_CLR(caglobals.tcp.connectionFds[0], readFds);
304 else if (-1 != caglobals.tcp.connectionFds[0] &&
305 FD_ISSET(caglobals.tcp.connectionFds[0], readFds))
307 // new connection was created from remote device.
308 // exit the function to update read file descriptor.
309 char buf[MAX_ADDR_STR_SIZE_CA] = {0};
310 ssize_t len = read(caglobals.tcp.connectionFds[0], buf, sizeof (buf));
315 OIC_LOG_V(DEBUG, TAG, "Received new connection event with [%s]", buf);
316 FD_CLR(caglobals.tcp.connectionFds[0], readFds);
321 uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
322 for (size_t i = 0; i < length; i++)
324 CATCPSessionInfo_t *svritem =
325 (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
326 if (svritem && svritem->fd >= 0)
328 if (FD_ISSET(svritem->fd, readFds))
330 CAReceiveMessage(svritem->fd);
331 FD_CLR(svritem->fd, readFds);
338 static void CAAcceptConnection(CATransportFlags_t flag, CASocket_t *sock)
340 VERIFY_NON_NULL_VOID(sock, TAG, "sock is NULL");
342 struct sockaddr_storage clientaddr;
343 socklen_t clientlen = sizeof (struct sockaddr_in);
346 clientlen = sizeof(struct sockaddr_in6);
349 int sockfd = accept(sock->fd, (struct sockaddr *)&clientaddr, &clientlen);
352 CATCPSessionInfo_t *svritem =
353 (CATCPSessionInfo_t *) OICCalloc(1, sizeof (*svritem));
356 OIC_LOG(ERROR, TAG, "Out of memory");
361 svritem->fd = sockfd;
362 svritem->sep.endpoint.flags = flag;
363 CAConvertAddrToName((struct sockaddr_storage *)&clientaddr, clientlen,
364 svritem->sep.endpoint.addr, &svritem->sep.endpoint.port);
366 ca_mutex_lock(g_mutexObjectList);
367 bool result = u_arraylist_add(caglobals.tcp.svrlist, svritem);
370 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
373 ca_mutex_unlock(g_mutexObjectList);
376 ca_mutex_unlock(g_mutexObjectList);
383 static bool CAIsTlsMessage(const CATCPSessionInfo_t * recvinfo)
385 if (recvinfo->data == NULL || recvinfo->len == 0)
387 OIC_LOG_V(ERROR, TAG, "%s: null input param", __func__);
391 unsigned char first_byte = recvinfo->data[0];
393 //TLS Plaintext has four types: change_cipher_spec = [14], alert = [15],
394 //handshake = [16], application_data = [17] in HEX
395 const uint8_t tls_head_type[] = {0x14, 0x15, 0x16, 0x17};
398 for (i = 0; i < sizeof(tls_head_type); i++)
400 if(tls_head_type[i] == first_byte)
410 static void CAReceiveMessage(int fd)
412 // #1. get remote device information from file descriptor.
414 CATCPSessionInfo_t *svritem = CAGetSessionInfoFromFD(fd, &index);
417 OIC_LOG(ERROR, TAG, "there is no connection information in list");
421 // #2. allocate memory for message header (CoAP header size because it is bigger)
422 svritem->data = (unsigned char *) OICCalloc(1, COAP_MAX_HEADER_SIZE);
425 OIC_LOG(ERROR, TAG, "out of memory");
429 // #3. read data (assume TLS header) from remote device.
430 RECV(fd, svritem, svritem->data, TLS_HEADER_SIZE, 0);
433 if (CAIsTlsMessage(svritem))
435 // #4.1 get tls body length from tls header. [3][4] bytes are length of tls body in header
436 unsigned int message_length = (unsigned int)((svritem->data[3] << 8) | svritem->data[4]);
437 OIC_LOG_V(DEBUG, TAG, "%s: message_length = %d", __func__, message_length);
439 REALLOC(svritem->data, message_length + TLS_HEADER_SIZE);
441 RECV(fd, svritem, svritem->data, message_length, 0);
443 int ret = CAdecryptTls(&svritem->sep, (uint8_t *)svritem->data, svritem->len);
445 OIC_LOG_V(DEBUG, TAG, "%s: CAdecryptTls returned %d", __func__, ret);
451 // #4.2 Seems CoAP data received. read full coap header.
452 coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(svritem->data[0] >> 4);
454 size_t headerLen = coap_get_tcp_header_length_for_transport(transport);
456 if (svritem->len < headerLen)
458 // read required bytes to have full CoAP header
459 // usually it is 1 bytes (COAP_MAX_HEADER_SIZE - TLS_HEADER_SIZE)
460 RECV(fd, svritem, svritem->data, headerLen - svritem->len, 0);
463 // #4.3 Calculate CoAP message length and read it
464 size_t total_length = CAGetTotalLengthFromHeader(svritem->data);
465 REALLOC(svritem->data, total_length);
467 RECV(fd, svritem, svritem->data, total_length - svritem->len, 0);
469 // #4.4. pass the received data information to upper layer.
470 if (g_packetReceivedCallback)
472 svritem->sep.endpoint.adapter = CA_ADAPTER_TCP;
473 g_packetReceivedCallback(&svritem->sep, svritem->data, svritem->len);
479 CADisconnectTCPSession(svritem, index);
482 // initialize data info to receive next message.
483 OICFree(svritem->data);
484 svritem->data = NULL;
490 static void CAWakeUpForReadFdsUpdate(const char *host)
492 if (caglobals.tcp.connectionFds[1] != -1)
497 len = write(caglobals.tcp.connectionFds[1], host, strlen(host));
498 } while ((len == -1) && (errno == EINTR));
500 if ((len == -1) && (errno != EINTR) && (errno != EPIPE))
502 OIC_LOG_V(DEBUG, TAG, "write failed: %s", strerror(errno));
507 static CAResult_t CATCPConvertNameToAddr(int family, const char *host, uint16_t port,
508 struct sockaddr_storage *sockaddr)
510 struct addrinfo *addrs = NULL;
511 struct addrinfo hints = { .ai_family = family,
512 .ai_protocol = IPPROTO_TCP,
513 .ai_socktype = SOCK_STREAM,
514 .ai_flags = AI_NUMERICHOST };
516 int r = getaddrinfo(host, NULL, &hints, &addrs);
521 OIC_LOG_V(ERROR, TAG, "getaddrinfo failed: errno %s", strerror(errno));
525 OIC_LOG_V(ERROR, TAG, "getaddrinfo failed: %s", gai_strerror(r));
528 return CA_STATUS_FAILED;
530 // assumption: in this case, getaddrinfo will only return one addrinfo
531 // or first is the one we want.
532 if (addrs[0].ai_family == AF_INET6)
534 memcpy(sockaddr, addrs[0].ai_addr, sizeof (struct sockaddr_in6));
535 ((struct sockaddr_in6 *)sockaddr)->sin6_port = htons(port);
539 memcpy(sockaddr, addrs[0].ai_addr, sizeof (struct sockaddr_in));
540 ((struct sockaddr_in *)sockaddr)->sin_port = htons(port);
546 static int CATCPCreateSocket(int family, CATCPSessionInfo_t *svritem)
548 // #1. create tcp socket.
549 int fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
552 OIC_LOG_V(ERROR, TAG, "create socket failed: %s", strerror(errno));
556 // #2. convert address from string to binary.
557 struct sockaddr_storage sa = { .ss_family = family };
558 CAResult_t res = CATCPConvertNameToAddr(family, svritem->sep.endpoint.addr,
559 svritem->sep.endpoint.port, &sa);
560 if (CA_STATUS_OK != res)
566 // #3. set socket length.
567 socklen_t socklen = 0;
568 if (sa.ss_family == AF_INET6)
570 struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)&sa;
571 if (!sock6->sin6_scope_id)
573 sock6->sin6_scope_id = svritem->sep.endpoint.ifindex;
575 socklen = sizeof(struct sockaddr_in6);
579 socklen = sizeof(struct sockaddr_in);
582 // #4. connect to remote server device.
583 if (connect(fd, (struct sockaddr *)&sa, socklen) < 0)
585 OIC_LOG_V(ERROR, TAG, "failed to connect socket, %s", strerror(errno));
590 OIC_LOG(DEBUG, TAG, "connect socket success");
591 CAWakeUpForReadFdsUpdate(svritem->sep.endpoint.addr);
595 static int CACreateAcceptSocket(int family, CASocket_t *sock)
597 VERIFY_NON_NULL_RET(sock, TAG, "sock", -1);
601 OIC_LOG(DEBUG, TAG, "accept socket created already");
605 socklen_t socklen = 0;
606 struct sockaddr_storage server = { .ss_family = family };
608 int fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
611 OIC_LOG(ERROR, TAG, "Failed to create socket");
615 if (family == AF_INET6)
617 // the socket is re‐stricted to sending and receiving IPv6 packets only.
619 if (-1 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)))
621 OIC_LOG_V(ERROR, TAG, "IPV6_V6ONLY failed: %s", strerror(errno));
624 ((struct sockaddr_in6 *)&server)->sin6_port = htons(sock->port);
625 socklen = sizeof (struct sockaddr_in6);
629 ((struct sockaddr_in *)&server)->sin_port = htons(sock->port);
630 socklen = sizeof (struct sockaddr_in);
634 if (-1 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)))
636 OIC_LOG(ERROR, TAG, "setsockopt SO_REUSEADDR");
640 if (-1 == bind(fd, (struct sockaddr *)&server, socklen))
642 OIC_LOG_V(ERROR, TAG, "bind socket failed: %s", strerror(errno));
646 if (listen(fd, caglobals.tcp.listenBacklog) != 0)
648 OIC_LOG(ERROR, TAG, "listen() error");
652 if (!sock->port) // return the assigned port
654 if (-1 == getsockname(fd, (struct sockaddr *)&server, &socklen))
656 OIC_LOG_V(ERROR, TAG, "getsockname failed: %s", strerror(errno));
659 sock->port = ntohs(family == AF_INET6 ?
660 ((struct sockaddr_in6 *)&server)->sin6_port :
661 ((struct sockaddr_in *)&server)->sin_port);
674 static void CAInitializePipe(int *fds)
679 ret = fcntl(fds[0], F_GETFD);
682 ret = fcntl(fds[0], F_SETFD, ret|FD_CLOEXEC);
686 ret = fcntl(fds[1], F_GETFD);
690 ret = fcntl(fds[1], F_SETFD, ret|FD_CLOEXEC);
700 OIC_LOG_V(ERROR, TAG, "pipe failed: %s", strerror(errno));
705 #define NEWSOCKET(FAMILY, NAME) \
706 caglobals.tcp.NAME.fd = CACreateAcceptSocket(FAMILY, &caglobals.tcp.NAME); \
707 if (caglobals.tcp.NAME.fd == -1) \
709 caglobals.tcp.NAME.port = 0; \
710 caglobals.tcp.NAME.fd = CACreateAcceptSocket(FAMILY, &caglobals.tcp.NAME); \
712 CHECKFD(caglobals.tcp.NAME.fd);
714 CAResult_t CATCPStartServer(const ca_thread_pool_t threadPool)
716 if (caglobals.tcp.started)
721 if (!caglobals.tcp.ipv4tcpenabled)
723 caglobals.tcp.ipv4tcpenabled = true; // only needed to run CA tests
725 if (!caglobals.tcp.ipv6tcpenabled)
727 caglobals.tcp.ipv6tcpenabled = true; // only needed to run CA tests
730 CAResult_t res = CATCPCreateMutex();
731 if (CA_STATUS_OK == res)
733 res = CATCPCreateCond();
735 if (CA_STATUS_OK != res)
737 OIC_LOG(ERROR, TAG, "failed to create mutex/cond");
741 ca_mutex_lock(g_mutexObjectList);
742 if (!caglobals.tcp.svrlist)
744 caglobals.tcp.svrlist = u_arraylist_create();
746 ca_mutex_unlock(g_mutexObjectList);
748 if (caglobals.server)
750 NEWSOCKET(AF_INET, ipv4);
751 NEWSOCKET(AF_INET6, ipv6);
752 OIC_LOG_V(DEBUG, TAG, "IPv4 socket fd=%d, port=%d",
753 caglobals.tcp.ipv4.fd, caglobals.tcp.ipv4.port);
754 OIC_LOG_V(DEBUG, TAG, "IPv6 socket fd=%d, port=%d",
755 caglobals.tcp.ipv6.fd, caglobals.tcp.ipv6.port);
758 // create pipe for fast shutdown
759 CAInitializePipe(caglobals.tcp.shutdownFds);
760 CHECKFD(caglobals.tcp.shutdownFds[0]);
761 CHECKFD(caglobals.tcp.shutdownFds[1]);
763 // create pipe for connection event
764 CAInitializePipe(caglobals.tcp.connectionFds);
765 CHECKFD(caglobals.tcp.connectionFds[0]);
766 CHECKFD(caglobals.tcp.connectionFds[1]);
768 caglobals.tcp.terminate = false;
769 res = ca_thread_pool_add_task(threadPool, CAReceiveHandler, NULL);
770 if (CA_STATUS_OK != res)
772 OIC_LOG(ERROR, TAG, "thread_pool_add_task failed");
775 OIC_LOG(DEBUG, TAG, "CAReceiveHandler thread started successfully.");
777 caglobals.tcp.started = true;
781 void CATCPStopServer()
784 ca_mutex_lock(g_mutexObjectList);
786 // set terminate flag
787 caglobals.tcp.terminate = true;
789 if (caglobals.tcp.shutdownFds[1] != -1)
791 close(caglobals.tcp.shutdownFds[1]);
792 // receive thread will stop immediately
795 if (caglobals.tcp.connectionFds[1] != -1)
797 close(caglobals.tcp.connectionFds[1]);
800 if (caglobals.tcp.started)
802 ca_cond_wait(g_condObjectList, g_mutexObjectList);
804 caglobals.tcp.started = false;
807 ca_mutex_unlock(g_mutexObjectList);
809 if (-1 != caglobals.tcp.ipv4.fd)
811 close(caglobals.tcp.ipv4.fd);
812 caglobals.tcp.ipv4.fd = -1;
815 if (-1 != caglobals.tcp.ipv6.fd)
817 close(caglobals.tcp.ipv6.fd);
818 caglobals.tcp.ipv6.fd = -1;
821 CATCPDisconnectAll();
826 void CATCPSetPacketReceiveCallback(CATCPPacketReceivedCallback callback)
828 g_packetReceivedCallback = callback;
831 void CATCPSetConnectionChangedCallback(CATCPConnectionHandleCallback connHandler)
833 g_connectionCallback = connHandler;
836 static void sendData(const CAEndpoint_t *endpoint, const void *data,
837 size_t dlen, const char *fam)
839 // #1. get TCP Server object from list
841 CATCPSessionInfo_t *svritem = CAGetTCPSessionInfoFromEndpoint(endpoint, &index);
844 // if there is no connection info, connect to TCP Server
845 svritem = CAConnectTCPSession(endpoint);
848 OIC_LOG(ERROR, TAG, "Failed to create TCP server object");
849 if (g_tcpErrorHandler)
851 g_tcpErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
857 // #2. check connection state
860 // if file descriptor value is wrong, remove TCP Server info from list
861 OIC_LOG(ERROR, TAG, "Failed to connect to TCP server");
862 CADisconnectTCPSession(svritem, index);
863 if (g_tcpErrorHandler)
865 g_tcpErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
870 // #4. send data to TCP Server
871 ssize_t remainLen = dlen;
874 ssize_t len = send(svritem->fd, data, remainLen, 0);
877 if (EWOULDBLOCK != errno)
879 OIC_LOG_V(ERROR, TAG, "unicast ipv4tcp sendTo failed: %s", strerror(errno));
880 if (g_tcpErrorHandler)
882 g_tcpErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
890 } while (remainLen > 0);
892 OIC_LOG_V(INFO, TAG, "unicast %stcp sendTo is successful: %zu bytes", fam, dlen);
895 void CATCPSendData(CAEndpoint_t *endpoint, const void *data, uint32_t datalen,
898 VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
899 VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
903 if (caglobals.tcp.ipv6tcpenabled && (endpoint->flags & CA_IPV6))
905 sendData(endpoint, data, datalen, "ipv6");
907 if (caglobals.tcp.ipv4tcpenabled && (endpoint->flags & CA_IPV4))
909 sendData(endpoint, data, datalen, "ipv4");
914 CAResult_t CAGetTCPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
916 VERIFY_NON_NULL(info, TAG, "info is NULL");
917 VERIFY_NON_NULL(size, TAG, "size is NULL");
919 return CA_NOT_SUPPORTED;
922 CATCPSessionInfo_t *CAConnectTCPSession(const CAEndpoint_t *endpoint)
924 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", NULL);
926 // #1. create TCP server object
927 CATCPSessionInfo_t *svritem = (CATCPSessionInfo_t *) OICCalloc(1, sizeof (*svritem));
930 OIC_LOG(ERROR, TAG, "Out of memory");
933 memcpy(svritem->sep.endpoint.addr, endpoint->addr, sizeof(svritem->sep.endpoint.addr));
934 svritem->sep.endpoint.adapter = endpoint->adapter;
935 svritem->sep.endpoint.port = endpoint->port;
936 svritem->sep.endpoint.flags = endpoint->flags;
937 svritem->sep.endpoint.ifindex = endpoint->ifindex;
939 // #2. create the socket and connect to TCP server
940 int family = (svritem->sep.endpoint.flags & CA_IPV6) ? AF_INET6 : AF_INET;
941 int fd = CATCPCreateSocket(family, svritem);
948 // #3. add TCP connection info to list
950 ca_mutex_lock(g_mutexObjectList);
951 if (caglobals.tcp.svrlist)
953 bool res = u_arraylist_add(caglobals.tcp.svrlist, svritem);
956 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
959 ca_mutex_unlock(g_mutexObjectList);
963 ca_mutex_unlock(g_mutexObjectList);
967 // pass the connection information to CA Common Layer.
968 if (g_connectionCallback)
970 g_connectionCallback(&(svritem->sep.endpoint), true);
976 CAResult_t CADisconnectTCPSession(CATCPSessionInfo_t *svritem, size_t index)
978 VERIFY_NON_NULL(svritem, TAG, "svritem is NULL");
980 ca_mutex_lock(g_mutexObjectList);
982 // close the socket and remove TCP connection info in list
983 if (svritem->fd >= 0)
987 u_arraylist_remove(caglobals.tcp.svrlist, index);
988 OICFree(svritem->data);
989 svritem->data = NULL;
991 // pass the connection information to CA Common Layer.
992 if (g_connectionCallback)
994 g_connectionCallback(&(svritem->sep.endpoint), false);
998 ca_mutex_unlock(g_mutexObjectList);
1000 return CA_STATUS_OK;
1003 void CATCPDisconnectAll()
1005 ca_mutex_lock(g_mutexObjectList);
1006 uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
1008 CATCPSessionInfo_t *svritem = NULL;
1009 for (size_t i = 0; i < length; i++)
1011 svritem = (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
1012 if (svritem && svritem->fd >= 0)
1014 shutdown(svritem->fd, SHUT_RDWR);
1017 OICFree(svritem->data);
1018 svritem->data = NULL;
1021 u_arraylist_destroy(caglobals.tcp.svrlist);
1022 ca_mutex_unlock(g_mutexObjectList);
1025 CATCPSessionInfo_t *CAGetTCPSessionInfoFromEndpoint(const CAEndpoint_t *endpoint, size_t *index)
1027 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", NULL);
1028 VERIFY_NON_NULL_RET(index, TAG, "index is NULL", NULL);
1030 // get connection info from list
1031 uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
1032 for (size_t i = 0; i < length; i++)
1034 CATCPSessionInfo_t *svritem = (CATCPSessionInfo_t *) u_arraylist_get(
1035 caglobals.tcp.svrlist, i);
1041 if (!strncmp(svritem->sep.endpoint.addr, endpoint->addr,
1042 sizeof(svritem->sep.endpoint.addr))
1043 && (svritem->sep.endpoint.port == endpoint->port)
1044 && (svritem->sep.endpoint.flags & endpoint->flags))
1054 CATCPSessionInfo_t *CAGetSessionInfoFromFD(int fd, size_t *index)
1056 ca_mutex_lock(g_mutexObjectList);
1058 // check from the last item.
1059 CATCPSessionInfo_t *svritem = NULL;
1060 uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
1061 for (size_t i = 0; i < length; i++)
1063 svritem = (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
1065 if (svritem && svritem->fd == fd)
1068 ca_mutex_unlock(g_mutexObjectList);
1073 ca_mutex_unlock(g_mutexObjectList);
1078 size_t CAGetTotalLengthFromHeader(const unsigned char *recvBuffer)
1080 OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
1082 coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(
1083 ((unsigned char *)recvBuffer)[0] >> 4);
1084 size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
1086 size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
1088 OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%zu]", optPaylaodLen);
1089 OIC_LOG_V(DEBUG, TAG, "header length [%zu]", headerLen);
1090 OIC_LOG_V(DEBUG, TAG, "total data length [%zu]", headerLen + optPaylaodLen);
1092 OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
1093 return headerLen + optPaylaodLen;
1096 void CATCPSetErrorHandler(CATCPErrorHandleCallback errorHandleCallback)
1098 g_tcpErrorHandler = errorHandleCallback;