Merge branch 'master' into windows-port
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / tcp_adapter / arduino / catcpserver_eth.cpp
1 /* ****************************************************************
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 <stdio.h>
22 #include <errno.h>
23
24 #include <Arduino.h>
25 #include <Ethernet.h>
26 #include <SPI.h>
27 #include <w5100.h>
28 #include <IPAddress.h>
29
30 #include "catcpadapterutils_eth.h"
31 #include "catcpinterface.h"
32 #include "pdu.h"
33 #include "caadapterutils.h"
34 #include "camutex.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37
38 /**
39  * Logging tag for module name.
40  */
41 #define TAG "TCP_SERVER"
42
43 /**
44  * Maximum CoAP over TCP header length
45  * to know the total data length.
46  */
47 #define TCP_MAX_HEADER_LEN  6
48
49 #define TCP_UNICAST_PORT  55556
50
51 uint16_t tcpClientPort = 0;
52 uint8_t tcpClientIP[4] = {0};
53
54 /**
55  * Maintains the callback to be notified when data received from remote device.
56  */
57 static CATCPPacketReceivedCallback g_packetReceivedCallback = NULL;
58
59 /**
60  * Error callback to update error in TCP.
61  */
62 static CATCPErrorHandleCallback g_TCPErrorHandler = NULL;
63
64 static uint16_t g_unicastPort = 0;
65
66 static int g_unicastSocket = -1;
67
68 static EthernetServer server(TCP_UNICAST_PORT);
69
70 /**
71  * @var g_receivedDataLen
72  * @brief Actual length of data received.
73  */
74 static uint32_t g_receivedDataLen = 0;
75
76 static void CATCPReadDataInternal();
77
78 uint16_t CAGetTcpServerPortNum(const char *ipAddress, bool isSecured)
79 {
80     return g_unicastPort;
81 }
82
83 void CATCPPullData()
84 {
85     CATCPReadDataInternal();
86 }
87
88 CAResult_t CATCPStartServer()
89 {
90     OIC_LOG(DEBUG, TAG, "IN");
91
92     if (caglobals.tcp.started)
93     {
94         return CA_STATUS_OK;
95     }
96
97     if (!caglobals.tcp.ipv4tcpenabled)
98     {
99         caglobals.tcp.ipv4tcpenabled = true;    // only needed to run CA tests
100     }
101
102     uint8_t rawIPAddr[4] = {0};
103     char address[16] = {0};
104     W5100.getIPAddress(rawIPAddr);
105     int ret = snprintf(address, sizeof(address), "%d.%d.%d.%d", rawIPAddr[0], rawIPAddr[1], rawIPAddr[2],
106                        rawIPAddr[3]);
107     if(0 > ret)
108     {
109         OIC_LOG(ERROR, TAG, "Error getting IP");
110         return CA_STATUS_FAILED;
111     }
112
113     OIC_LOG_V(DEBUG, TAG, "address:%s", address);
114     int serverFD = 1;
115     g_unicastPort = TCP_UNICAST_PORT;
116
117     if (CAArduinoInitTCPSocket(&g_unicastPort, &serverFD) != CA_STATUS_OK)
118     {
119         OIC_LOG(DEBUG, TAG, "Init TCP Socket failed");
120         return CA_STATUS_FAILED;
121     }
122
123     listen(serverFD);
124     EthernetClass::_server_port[serverFD] = g_unicastPort;
125     g_unicastSocket = serverFD;
126     caglobals.ip.u4.port =  TCP_UNICAST_PORT;
127
128     caglobals.tcp.terminate = false;
129     caglobals.tcp.started = true;
130
131     OIC_LOG_V(DEBUG, TAG, "g_unicastPort: %u", g_unicastPort);
132     OIC_LOG_V(DEBUG, TAG, "g_unicastSocket: %d", g_unicastSocket);
133     OIC_LOG(DEBUG, TAG, "OUT");
134     return CA_STATUS_OK;
135 }
136
137 void CATCPStopServer()
138 {
139     OIC_LOG(DEBUG, TAG, "IN");
140     caglobals.tcp.terminate = true;
141     caglobals.tcp.started = false;
142
143     if (-1 != g_unicastSocket)
144     {
145         close(g_unicastSocket);
146         g_unicastSocket = -1;
147     }
148
149     caglobals.ip.u4.port = 0;
150     OIC_LOG(DEBUG, TAG, "OUT");
151 }
152
153 void CATCPSetPacketReceiveCallback(CATCPPacketReceivedCallback callback)
154 {
155     OIC_LOG(DEBUG, TAG, "IN");
156
157     g_packetReceivedCallback = callback;
158
159     OIC_LOG(DEBUG, TAG, "OUT");
160 }
161
162 void CATCPSetErrorHandler(CATCPErrorHandleCallback errorHandleCallback)
163 {
164     return;
165 }
166
167 void CATCPReadDataInternal()
168 {
169     OIC_LOG(DEBUG, TAG, "CATCPReadDataInternal IN");
170     if (false == caglobals.tcp.started)
171     {
172         OIC_LOG(ERROR, TAG, "Server is not running");
173         return;
174     }
175
176     EthernetClient client = server.available();
177
178     if (client && client.connected())
179     {
180         client.getTCPClientIP(tcpClientIP);
181         client.getTCPClientPort(&tcpClientPort);
182         OIC_LOG_V(DEBUG, TAG, "Client ip is %d.%d.%d.%d , Port is : %d", tcpClientIP[0],
183                 tcpClientIP[1], tcpClientIP[2], tcpClientIP[3], tcpClientPort);
184
185         OIC_LOG(DEBUG, TAG, "DATA Available");
186         unsigned char *recvBuffer = NULL;
187         size_t bufSize = TCP_MAX_HEADER_LEN;
188
189         recvBuffer = (unsigned char *) OICCalloc(1, bufSize);
190         if (!recvBuffer)
191         {
192             OIC_LOG(ERROR, TAG, "out of memory");
193         }
194
195         bool isHeaderChecked = false;
196         size_t totalLen = 0;
197         size_t totalReceivedLen = 0;
198
199         do
200         {
201             size_t bufferLen = 0;
202             if (client.available())
203             {
204                 bufferLen = client.read(recvBuffer, bufSize);
205                 totalReceivedLen += bufferLen;
206             }
207
208             if (!isHeaderChecked && totalReceivedLen)
209             {
210                 coap_transport_type transport;
211                 size_t headerLen;
212                 CAGetTCPHeaderDetails(recvBuffer, &transport, &headerLen);
213                 if (totalReceivedLen >= headerLen)
214                 {
215                     // get actual data length from coap over tcp header
216                     totalLen = CAGetTotalLengthFromPacketHeader((const unsigned char *) recvBuffer,
217                                                                  bufferLen);
218                     bufSize = totalLen;
219                     unsigned char *newBuf = (unsigned char *) OICRealloc(recvBuffer, bufSize);
220                     if (NULL == newBuf)
221                     {
222                         OIC_LOG(ERROR, TAG, "out of memory");
223                         OICFree(recvBuffer);
224                         return;
225                     }
226
227                     recvBuffer = newBuf;
228                     isHeaderChecked = true;
229                 }
230             }
231
232             if (totalLen == totalReceivedLen)
233             {
234                 CASecureEndpoint_t ep =
235                     {.endpoint = {.adapter = CA_ADAPTER_TCP, .port = tcpClientPort}};
236
237                 IPAddress clientIP = tcpClientIP;
238                 int ret = snprintf(ep.endpoint.addr, sizeof(ep.endpoint.addr), "%d.%d.%d.%d",
239                                    clientIP[0], clientIP[1], clientIP[2], clientIP[3]);
240                 if(0 > ret)
241                 {
242                     OIC_LOG(ERROR, TAG, "Error parsing client IP");
243                     OICFree(recvBuffer);
244                     return;
245                 }
246
247                 OIC_LOG_V(DEBUG, TAG, "Client ip is %d.%d.%d.%d", clientIP[0],
248                           clientIP[1], clientIP[2], clientIP[3]);
249                 if (g_packetReceivedCallback)
250                 {
251                     g_packetReceivedCallback(&ep, recvBuffer, totalLen);
252                 }
253
254                 OIC_LOG_V(DEBUG, TAG, "received data len:%d", totalLen);
255                 break;
256             }
257         } while (!totalLen || totalLen > totalReceivedLen);
258
259         OICFree(recvBuffer);
260
261         OIC_LOG(DEBUG, TAG, "OUT");
262     }
263     else
264     {
265         OIC_LOG(DEBUG, TAG, "NoData");
266     }
267     return;
268 }
269
270 CAResult_t CAGetTCPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
271 {
272     OIC_LOG(DEBUG, TAG, "IN");
273
274     VERIFY_NON_NULL(info, TAG, "info is NULL");
275     VERIFY_NON_NULL(size, TAG, "size is NULL");
276
277     return CA_NOT_SUPPORTED;
278 }
279
280 static void sendData(const CAEndpoint_t *endpoint,
281                      const void *data, size_t dlen)
282 {
283     uint16_t port = endpoint->port;
284     uint8_t ipAddr[4] = { 0 };
285     uint16_t parsedPort = 0;
286     if (CAParseIPv4AddressInternal(endpoint->addr, ipAddr, sizeof(ipAddr),
287                                    &parsedPort) != CA_STATUS_OK)
288     {
289         OIC_LOG(ERROR, TAG, "parse fail");
290         return;
291     }
292
293     if (dlen > 65535) // Max value for uint16_t
294     {
295         // This will never happen as max buffer size we are dealing with is COAP_MAX_PDU_SIZE
296         OIC_LOG(ERROR, TAG, "Size exceeded");
297         return;
298     }
299
300     uint32_t ret = send(g_unicastSocket, (const uint8_t *)data, (uint16_t)dlen);
301     if (ret <= 0)
302     {
303         OIC_LOG_V(ERROR, TAG, "SendData failed: %d", ret);
304     }
305
306     OIC_LOG(DEBUG, TAG, "OUT");
307 }
308
309 void CATCPSendData(CAEndpoint_t *endpoint, const void *data, uint32_t datalen,
310                    bool isMulticast)
311 {
312     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
313     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
314
315     if (!isMulticast)
316     {
317         if (caglobals.tcp.ipv4tcpenabled && (endpoint->adapter & CA_ADAPTER_TCP))
318         {
319             sendData(endpoint, data, datalen);
320         }
321     }
322 }