Return correct error code when send fails in catcpserver
[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 <coap/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 CATCPSetConnectionChangedCallback(CATCPConnectionHandleCallback connHandler)
163 {
164     return;
165 }
166
167 void CATCPSetErrorHandler(CATCPErrorHandleCallback errorHandleCallback)
168 {
169     return;
170 }
171
172 void CATCPReadDataInternal()
173 {
174     OIC_LOG(DEBUG, TAG, "CATCPReadDataInternal IN");
175     if (false == caglobals.tcp.started)
176     {
177         OIC_LOG(ERROR, TAG, "Server is not running");
178         return;
179     }
180
181     EthernetClient client = server.available();
182
183     if (client && client.connected())
184     {
185         client.getTCPClientIP(tcpClientIP);
186         client.getTCPClientPort(&tcpClientPort);
187         OIC_LOG_V(DEBUG, TAG, "Client ip is %d.%d.%d.%d , Port is : %d", tcpClientIP[0],
188                 tcpClientIP[1], tcpClientIP[2], tcpClientIP[3], tcpClientPort);
189
190         OIC_LOG(DEBUG, TAG, "DATA Available");
191         unsigned char *recvBuffer = NULL;
192         size_t bufSize = TCP_MAX_HEADER_LEN;
193
194         recvBuffer = (unsigned char *) OICCalloc(1, bufSize);
195         if (!recvBuffer)
196         {
197             OIC_LOG(ERROR, TAG, "out of memory");
198         }
199
200         bool isHeaderChecked = false;
201         size_t totalLen = 0;
202         size_t totalReceivedLen = 0;
203
204         do
205         {
206             size_t bufferLen = 0;
207             if (client.available())
208             {
209                 bufferLen = client.read(recvBuffer, bufSize);
210                 totalReceivedLen += bufferLen;
211             }
212
213             if (!isHeaderChecked && totalReceivedLen)
214             {
215                 coap_transport_t transport;
216                 size_t headerLen;
217                 CAGetTCPHeaderDetails(recvBuffer, &transport, &headerLen);
218                 if (totalReceivedLen >= headerLen)
219                 {
220                     // get actual data length from coap over tcp header
221                     totalLen = CAGetTotalLengthFromPacketHeader((const unsigned char *) recvBuffer,
222                                                                  bufferLen);
223                     bufSize = totalLen;
224                     unsigned char *newBuf = (unsigned char *) OICRealloc(recvBuffer, bufSize);
225                     if (NULL == newBuf)
226                     {
227                         OIC_LOG(ERROR, TAG, "out of memory");
228                         OICFree(recvBuffer);
229                         return;
230                     }
231
232                     recvBuffer = newBuf;
233                     isHeaderChecked = true;
234                 }
235             }
236
237             if (totalLen == totalReceivedLen)
238             {
239                 CASecureEndpoint_t ep =
240                     {.endpoint = {.adapter = CA_ADAPTER_TCP,
241                                   .flags = CA_DEFAULT_FLAGS,
242                                   .port = tcpClientPort}};
243
244                 IPAddress clientIP = tcpClientIP;
245                 int ret = snprintf(ep.endpoint.addr, sizeof(ep.endpoint.addr), "%d.%d.%d.%d",
246                                    clientIP[0], clientIP[1], clientIP[2], clientIP[3]);
247                 if(0 > ret)
248                 {
249                     OIC_LOG(ERROR, TAG, "Error parsing client IP");
250                     OICFree(recvBuffer);
251                     return;
252                 }
253
254                 OIC_LOG_V(DEBUG, TAG, "Client ip is %d.%d.%d.%d", clientIP[0],
255                           clientIP[1], clientIP[2], clientIP[3]);
256                 if (g_packetReceivedCallback)
257                 {
258                     g_packetReceivedCallback(&ep, recvBuffer, totalLen);
259                 }
260
261                 OIC_LOG_V(DEBUG, TAG, "received data len:%d", totalLen);
262                 break;
263             }
264         } while (!totalLen || totalLen > totalReceivedLen);
265
266         OICFree(recvBuffer);
267
268         OIC_LOG(DEBUG, TAG, "OUT");
269     }
270     else
271     {
272         OIC_LOG(DEBUG, TAG, "NoData");
273     }
274     return;
275 }
276
277 CAResult_t CAGetTCPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
278 {
279     OIC_LOG(DEBUG, TAG, "IN");
280
281     VERIFY_NON_NULL(info, TAG, "info is NULL");
282     VERIFY_NON_NULL(size, TAG, "size is NULL");
283
284     return CA_NOT_SUPPORTED;
285 }
286
287 static ssize_t sendData(const CAEndpoint_t *endpoint,
288                         const void *data, size_t dlen)
289 {
290     uint16_t port = endpoint->port;
291     uint8_t ipAddr[4] = { 0 };
292     uint16_t parsedPort = 0;
293     if (CAParseIPv4AddressInternal(endpoint->addr, ipAddr, sizeof(ipAddr),
294                                    &parsedPort) != CA_STATUS_OK)
295     {
296         OIC_LOG(ERROR, TAG, "parse fail");
297         return -1;
298     }
299
300     if (dlen > 65535) // Max value for uint16_t
301     {
302         // This will never happen as max buffer size we are dealing with is COAP_MAX_PDU_SIZE
303         OIC_LOG(ERROR, TAG, "Size exceeded");
304         return -1;
305     }
306
307     uint32_t ret = send(g_unicastSocket, (const uint8_t *)data, (uint16_t)dlen);
308     if (ret <= 0)
309     {
310         OIC_LOG_V(ERROR, TAG, "SendData failed: %d", ret);
311     }
312
313     OIC_LOG(DEBUG, TAG, "OUT");
314     return ret;
315 }
316
317 ssize_t CATCPSendData(CAEndpoint_t *endpoint, const void *data, size_t datalen)
318 {
319     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
320     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
321
322     if (caglobals.tcp.ipv4tcpenabled && (endpoint->adapter & CA_ADAPTER_TCP))
323     {
324         return sendData(endpoint, data, datalen);
325     }
326     return -1;
327 }