Merge master to cloud-interface branch
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / arduino / caipserver_eth.cpp
1 /******************************************************************
2 *
3 * Copyright 2014 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 "caipinterface.h"
22
23 #include <Arduino.h>
24 #include <Ethernet.h>
25 #include <socket.h>
26 #include <w5100.h>
27 #include <EthernetUdp.h>
28 #include <IPAddress.h>
29
30 #include "logger.h"
31 #include "cacommon.h"
32 #include "cainterface.h"
33 #include "caadapterinterface.h"
34 #include "caipadapter.h"
35 #include "caipadapterutils_eth.h"
36 #include "caadapterutils.h"
37 #include "oic_malloc.h"
38 #include "oic_string.h"
39
40 #define TAG "IPS"
41
42 // Length of the IP address decimal notation string
43 #define IPNAMESIZE (16)
44
45 CAResult_t CAIPStartUnicastServer(const char *localAddress, uint16_t *port,
46                                         const bool forceStart, int32_t *serverFD);
47 static CAResult_t CAArduinoRecvData(int32_t sockFd);
48 static void CAArduinoCheckData();
49 static void CAPacketReceivedCallback(const char *ipAddress, const uint16_t port,
50                               const void *data, const uint32_t dataLength);
51
52 static CAIPPacketReceivedCallback g_packetReceivedCallback = NULL;
53 static int g_unicastSocket = 0;
54 static int g_multicastSocket = 0;
55
56 /**
57  * @var g_isMulticastServerStarted
58  * @brief Flag to check if multicast server is started
59  */
60 static bool g_isMulticastServerStarted = false;
61
62 /**
63  * @var g_unicastPort
64  * @brief Unicast Port
65  */
66 static uint16_t g_unicastPort = 0;
67
68 CAResult_t CAIPInitializeServer(const ca_thread_pool_t threadPool)
69 {
70     return CA_STATUS_OK;
71 }
72
73 void CAIPTerminateServer(void)
74 {
75     return;
76 }
77
78 uint16_t CAGetServerPortNum(const char *ipAddress, bool isSecured)
79 {
80     return g_unicastPort;
81 }
82
83 CAResult_t CAIPStartUnicastServer(const char *localAddress, uint16_t *port,
84                                   bool secured)
85 {
86     OIC_LOG(DEBUG, TAG, "IN");
87     VERIFY_NON_NULL(port, TAG, "port");
88
89     uint8_t rawIPAddr[4];
90     char address[16];
91     W5100.getIPAddress(rawIPAddr);
92     sprintf(address, "%d.%d.%d.%d", rawIPAddr[0], rawIPAddr[1], rawIPAddr[2], rawIPAddr[3]);
93     OIC_LOG_V(DEBUG, TAG, "address:%s", address);
94     int serverFD = 1;
95     if (CAArduinoInitUdpSocket(port, &serverFD) != CA_STATUS_OK)
96     {
97         OIC_LOG(DEBUG, TAG, "failed");
98         return CA_STATUS_FAILED;
99     }
100
101     g_unicastPort = *port;
102     g_unicastSocket = serverFD;
103     CAIPSetUnicastSocket(g_unicastSocket);
104     CAIPSetUnicastPort(g_unicastPort);
105     OIC_LOG_V(DEBUG, TAG, "g_unicastPort: %u", g_unicastPort);
106     OIC_LOG_V(DEBUG, TAG, "g_unicastSocket: %d", g_unicastSocket);
107     OIC_LOG(DEBUG, TAG, "OUT");
108     return CA_STATUS_OK;
109 }
110
111 CAResult_t CAIPStartMulticastServer(const char *localAddress, const char *multicastAddress,
112                                     uint16_t multicastPort)
113 {
114     OIC_LOG(DEBUG, TAG, "IN");
115     if (g_isMulticastServerStarted == true)
116     {
117         OIC_LOG(ERROR, TAG, "Already Started!");
118         return CA_SERVER_STARTED_ALREADY;
119     }
120     int serverFD = 1;
121     if (CAArduinoInitMulticastUdpSocket(multicastAddress, multicastPort, multicastPort,
122                                         &serverFD) != CA_STATUS_OK)
123     {
124         OIC_LOG(DEBUG, TAG, "failed");
125         return CA_STATUS_FAILED;
126     }
127
128     g_multicastSocket = serverFD;
129     g_isMulticastServerStarted = true;
130     OIC_LOG_V(DEBUG, TAG, "gMulticastPort: %d", multicastPort);
131     OIC_LOG_V(DEBUG, TAG, "g_multicastSocket: %d", g_multicastSocket);
132     OIC_LOG(DEBUG, TAG, "OUT");
133     return CA_STATUS_OK;
134 }
135
136 CAResult_t CAIPStartServer()
137 {
138     uint16_t unicastPort = 55555;
139
140     CAResult_t ret = CAIPStartUnicastServer("0.0.0.0", &unicastPort, false);
141     if (CA_STATUS_OK != ret)
142     {
143         OIC_LOG_V(DEBUG, TAG, "Start unicast serv failed[%d]", ret);
144     }
145     ret = CAIPStartMulticastServer("0.0.0.0", "224.0.1.187", 5683);
146     if (CA_STATUS_OK != ret)
147     {
148         OIC_LOG_V(ERROR, TAG, "Start multicast failed[%d]", ret);
149     }
150     return ret;
151 }
152
153 CAResult_t CAIPStopUnicastServer()
154 {
155     OIC_LOG(DEBUG, TAG, "IN");
156     close(g_unicastSocket);
157     g_unicastSocket = 0;
158     OIC_LOG(DEBUG, TAG, "OUT");
159     return CA_STATUS_OK;
160 }
161
162 CAResult_t CAIPStopMulticastServer()
163 {
164     OIC_LOG(DEBUG, TAG, "IN");
165     close(g_multicastSocket);
166     g_multicastSocket = 0;
167     OIC_LOG(DEBUG, TAG, "OUT");
168     return CA_STATUS_OK;
169 }
170
171 void CAIPStopServer()
172 {
173     OIC_LOG(DEBUG, TAG, "IN");
174     CAResult_t result = CAIPStopUnicastServer();
175     if (CA_STATUS_OK != result)
176     {
177         OIC_LOG_V(ERROR, TAG, "stop ucast srv fail:%d", result);
178         return;
179     }
180     CAIPSetUnicastSocket(-1);
181     CAIPSetUnicastPort(0);
182
183     result = CAIPStopMulticastServer();
184     if (CA_STATUS_OK != result)
185     {
186         OIC_LOG_V(ERROR, TAG, "stop mcast srv fail:%d", result);
187     }
188     OIC_LOG(DEBUG, TAG, "OUT");
189 }
190
191 void CAPacketReceivedCallback(const char *ipAddress, const uint16_t port,
192                               const void *data, const uint32_t dataLength)
193 {
194     OIC_LOG(DEBUG, TAG, "IN");
195     if (g_packetReceivedCallback)
196     {
197         CASecureEndpoint_t sep =
198         {.endpoint = {.adapter = CA_ADAPTER_IP, .flags = CA_IPV4, .port = port}};
199         OICStrcpy(sep.endpoint.addr, sizeof(sep.endpoint.addr), ipAddress);
200         g_packetReceivedCallback(&sep, data, dataLength);
201     }
202     OIC_LOG(DEBUG, TAG, "OUT");
203 }
204
205 void CAArduinoCheckData()
206 {
207     if (g_unicastSocket)
208     {
209         if (CAArduinoRecvData(g_unicastSocket) != CA_STATUS_OK)
210         {
211             OIC_LOG(ERROR, TAG, "rcv fail");
212             CAIPStopUnicastServer();
213         }
214     }
215
216     if (g_multicastSocket)
217     {
218         if (CAArduinoRecvData(g_multicastSocket) != CA_STATUS_OK)
219         {
220             OIC_LOG(ERROR, TAG, "rcv fail");
221             CAIPStopMulticastServer();
222         }
223     }
224 }
225
226 /** Retrieve any available data from UDP socket and call callback.
227  *  This is a non-blocking call.
228  */
229 CAResult_t CAArduinoRecvData(int32_t sockFd)
230 {
231     /**Bug : When there are multiple UDP packets in Wiznet buffer, W5100.getRXReceivedSize
232      * will not return correct length of the first packet.
233      * Fix : Use the patch provided for arduino/libraries/Ethernet/utility/socket.cpp
234      */
235
236     void *data = NULL;
237     uint8_t senderAddr[4] = { 0 };
238     char addr[IPNAMESIZE] = {0};
239     uint16_t senderPort = 0;
240
241     uint16_t recvLen = W5100.getRXReceivedSize(sockFd);
242     if (recvLen == 0)
243     {
244         // No data available on socket
245         return CA_STATUS_OK;
246     }
247
248     OIC_LOG_V(DEBUG, TAG, "rcvd %d", recvLen);
249     recvLen = recvLen > COAP_MAX_PDU_SIZE ? COAP_MAX_PDU_SIZE:recvLen;
250
251     data = OICCalloc(recvLen + 1, 1);
252     if (NULL == data)
253     {
254         OIC_LOG(DEBUG, TAG, "Out of memory!");
255         return CA_MEMORY_ALLOC_FAILED;
256     }
257
258     // Read available data.
259     int32_t ret = recvfrom(sockFd, (uint8_t *)data, recvLen + 1, senderAddr, &senderPort);
260     if (ret < 0)
261     {
262         OIC_LOG(ERROR, TAG, "rcv fail");
263         OICFree(data);
264         return CA_STATUS_FAILED;
265     }
266     else if (ret > 0)
267     {
268         OIC_LOG(DEBUG, TAG, "data recvd");
269         snprintf(addr, sizeof(addr), "%d.%d.%d.%d", senderAddr[0], senderAddr[1], senderAddr[2],
270                  senderAddr[3]);
271         CAPacketReceivedCallback(addr, senderPort, data, ret);
272     }
273
274     OICFree(data);
275
276     OIC_LOG(DEBUG, TAG, "OUT");
277     return CA_STATUS_OK;
278 }
279
280 void CAIPSetPacketReceiveCallback(CAIPPacketReceivedCallback callback)
281 {
282     OIC_LOG(DEBUG, TAG, "IN");
283     g_packetReceivedCallback = callback;
284     OIC_LOG(DEBUG, TAG, "OUT");
285 }
286
287 void CAIPSetExceptionCallback(CAIPExceptionCallback callback)
288 {
289     // TODO
290 }
291
292 void CAIPSetErrorHandleCallback(CAIPErrorHandleCallback ipErrorCallback)
293 {
294     OIC_LOG(DEBUG, TAG, "IN");
295     OIC_LOG(DEBUG, TAG, "OUT");
296 }
297
298 void CAIPPullData()
299 {
300     CAArduinoCheckData();
301 }
302
303 CAResult_t CAGetIPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
304 {
305     OIC_LOG(DEBUG, TAG, "IN");
306
307     VERIFY_NON_NULL(info, TAG, "info is NULL");
308     VERIFY_NON_NULL(size, TAG, "size is NULL");
309
310     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
311     if (!iflist)
312     {
313         OIC_LOG(ERROR, TAG, "get interface info failed");
314         return CA_STATUS_FAILED;
315     }
316
317     uint32_t len = u_arraylist_length(iflist);
318
319     CAEndpoint_t *eps = (CAEndpoint_t *)OICCalloc(len, sizeof (CAEndpoint_t));
320     if (!eps)
321     {
322         OIC_LOG(ERROR, TAG, "Malloc Failed");
323         u_arraylist_destroy(iflist);
324         return CA_MEMORY_ALLOC_FAILED;
325     }
326
327     for (uint32_t i = 0, j = 0; i < len; i++)
328     {
329         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
330
331         OICStrcpy(eps[j].addr, CA_INTERFACE_NAME_SIZE, ifitem->name);
332         eps[j].flags = CA_IPV4;
333         eps[j].adapter = CA_ADAPTER_IP;
334         eps[j].interface = 0;
335         eps[j].port = 0;
336         j++;
337     }
338
339     *info = eps;
340     *size = len;
341
342     u_arraylist_destroy(iflist);
343
344     OIC_LOG(DEBUG, TAG, "OUT");
345     return CA_STATUS_OK;
346 }
347