Imported Upstream version 0.9.1
[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_singlethread.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_singlethread.h"
35 #include "caipadapterutils_eth.h"
36 #include "caadapterutils.h"
37 #include "oic_malloc.h"
38
39 #define TAG "IPS"
40
41 // Length of the IP address decimal notation string
42 #define IPNAMESIZE (16)
43
44 CAResult_t CAIPStartUnicastServer(const char *localAddress, uint16_t *port,
45                                         const bool forceStart, int32_t *serverFD);
46 static CAResult_t CAArduinoRecvData(int32_t sockFd);
47 static CAResult_t CAArduinoGetInterfaceAddress(char *address, int32_t addrLen);
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_unicastPort
58  * @brief Unicast Port
59  */
60 static uint16_t g_unicastPort = 0;
61
62 CAResult_t CAIPInitializeServer(void)
63 {
64     return CA_STATUS_OK;
65 }
66
67 void CAIPTerminateServer(void)
68 {
69     return;
70 }
71
72 CAResult_t CAIPGetUnicastServerInfo(char **ipAddress, uint16_t *port,
73                                           int *serverID)
74 {
75     return CA_STATUS_OK;
76 }
77
78 CAResult_t CAIPStartUnicastServer(const char *localAddress, uint16_t *port,
79                                         const bool forceStart, int *serverFD)
80 {
81     OIC_LOG(DEBUG, TAG, "IN");
82     VERIFY_NON_NULL(port, TAG, "port");
83
84     uint8_t rawIPAddr[4];
85     char address[16];
86     W5100.getIPAddress(rawIPAddr);
87     sprintf(address, "%d.%d.%d.%d", rawIPAddr[0], rawIPAddr[1], rawIPAddr[2], rawIPAddr[3]);
88     OIC_LOG_V(DEBUG, TAG, "address:%s", address);
89
90     if (CAArduinoInitUdpSocket(port, serverFD) != CA_STATUS_OK)
91     {
92         OIC_LOG(DEBUG, TAG, "failed");
93         return CA_STATUS_FAILED;
94     }
95
96     g_unicastPort = *port;
97     g_unicastSocket = *serverFD;
98     OIC_LOG_V(DEBUG, TAG, "g_unicastPort: %d", g_unicastPort);
99     OIC_LOG_V(DEBUG, TAG, "g_unicastSocket: %d", g_unicastSocket);
100     OIC_LOG(DEBUG, TAG, "OUT");
101     return CA_STATUS_OK;
102 }
103
104 CAResult_t CAIPStartMulticastServer(const char *localAddress, const char *multicastAddress,
105                                     uint16_t multicastPort, int *serverFD)
106 {
107     OIC_LOG(DEBUG, TAG, "IN");
108     if (CAArduinoInitMulticastUdpSocket(multicastAddress, multicastPort, multicastPort,
109                                         serverFD) != CA_STATUS_OK)
110     {
111         OIC_LOG(DEBUG, TAG, "failed");
112         return CA_STATUS_FAILED;
113     }
114
115     g_multicastSocket = *serverFD;
116     OIC_LOG_V(DEBUG, TAG, "gMulticastPort: %d", multicastPort);
117     OIC_LOG_V(DEBUG, TAG, "g_multicastSocket: %d", g_multicastSocket);
118     OIC_LOG(DEBUG, TAG, "OUT");
119     return CA_STATUS_OK;
120 }
121
122 CAResult_t CAIPStopUnicastServer()
123 {
124     OIC_LOG(DEBUG, TAG, "IN");
125     close(g_unicastSocket);
126     g_unicastSocket = 0;
127     OIC_LOG(DEBUG, TAG, "OUT");
128     return CA_STATUS_OK;
129 }
130
131 CAResult_t CAIPStopMulticastServer()
132 {
133     OIC_LOG(DEBUG, TAG, "IN");
134     close(g_multicastSocket);
135     g_multicastSocket = 0;
136     OIC_LOG(DEBUG, TAG, "OUT");
137     return CA_STATUS_OK;
138 }
139
140 void CAPacketReceivedCallback(const char *ipAddress, const uint16_t port,
141                               const void *data, const uint32_t dataLength)
142 {
143     OIC_LOG(DEBUG, TAG, "IN");
144     if (g_packetReceivedCallback)
145     {
146         g_packetReceivedCallback(ipAddress, port, data, dataLength);
147     }
148     OIC_LOG(DEBUG, TAG, "OUT");
149 }
150
151 void CAArduinoCheckData()
152 {
153     if (g_unicastSocket)
154     {
155         if (CAArduinoRecvData(g_unicastSocket) != CA_STATUS_OK)
156         {
157             OIC_LOG(ERROR, TAG, "rcv fail");
158             CAIPStopUnicastServer();
159         }
160     }
161
162     if (g_multicastSocket)
163     {
164         if (CAArduinoRecvData(g_multicastSocket) != CA_STATUS_OK)
165         {
166             OIC_LOG(ERROR, TAG, "rcv fail");
167             CAIPStopMulticastServer();
168         }
169     }
170 }
171
172 /** Retrieve any available data from UDP socket and call callback.
173  *  This is a non-blocking call.
174  */
175 CAResult_t CAArduinoRecvData(int32_t sockFd)
176 {
177     /**Bug : When there are multiple UDP packets in Wiznet buffer, W5100.getRXReceivedSize
178      * will not return correct length of the first packet.
179      * Fix : Use the patch provided for arduino/libraries/Ethernet/utility/socket.cpp
180      */
181
182     void *data = NULL;
183     uint8_t senderAddr[4] = { 0 };
184     char addr[IPNAMESIZE] = {0};
185     uint16_t senderPort = 0;
186
187     uint16_t recvLen = W5100.getRXReceivedSize(sockFd);
188     if (recvLen == 0)
189     {
190         // No data available on socket
191         return CA_STATUS_OK;
192     }
193
194     OIC_LOG_V(DEBUG, TAG, "rcvd %d", recvLen);
195     recvLen = recvLen > COAP_MAX_PDU_SIZE ? COAP_MAX_PDU_SIZE:recvLen;
196
197     data = OICCalloc(recvLen + 1, 1);
198     if (NULL == data)
199     {
200         OIC_LOG(DEBUG, TAG, "Out of memory!");
201         return CA_MEMORY_ALLOC_FAILED;
202     }
203
204     // Read available data.
205     int32_t ret = recvfrom(sockFd, (uint8_t *)data, recvLen + 1, senderAddr, &senderPort);
206     if (ret < 0)
207     {
208         OIC_LOG(ERROR, TAG, "rcv fail");
209         OICFree(data);
210         return CA_STATUS_FAILED;
211     }
212     else if (ret > 0)
213     {
214         OIC_LOG(DEBUG, TAG, "data recvd");
215         snprintf(addr, sizeof(addr), "%d.%d.%d.%d", senderAddr[0], senderAddr[1], senderAddr[2],
216                  senderAddr[3]);
217         CAPacketReceivedCallback(addr, senderPort, data, ret);
218     }
219
220     OICFree(data);
221
222     OIC_LOG(DEBUG, TAG, "OUT");
223     return CA_STATUS_OK;
224 }
225
226 void CAIPSetPacketReceiveCallback(CAIPPacketReceivedCallback callback)
227 {
228     OIC_LOG(DEBUG, TAG, "IN");
229     g_packetReceivedCallback = callback;
230     OIC_LOG(DEBUG, TAG, "OUT");
231 }
232
233 void CAIPSetExceptionCallback(CAIPExceptionCallback callback)
234 {
235     // TODO
236 }
237
238 void CAIPPullData()
239 {
240     CAArduinoCheckData();
241 }
242
243 /// Retrieves the IP address assigned to Arduino Ethernet shield
244 CAResult_t CAArduinoGetInterfaceAddress(char *address, int32_t addrLen)
245 {
246     OIC_LOG(DEBUG, TAG, "IN");
247     VERIFY_NON_NULL(address, TAG, "address");
248
249     //TODO : Fix this for scenarios when this API is invoked when device is not connected
250     uint8_t rawIPAddr[4];
251     if (addrLen < IPNAMESIZE)
252     {
253         OIC_LOG(ERROR, TAG, "Invalid addrLen");
254         return CA_STATUS_FAILED;
255     }
256
257     W5100.getIPAddress(rawIPAddr);
258     snprintf(address, sizeof(address), "%d.%d.%d.%d", rawIPAddr[0], rawIPAddr[1], rawIPAddr[2],
259              rawIPAddr[3]);
260
261     OIC_LOG_V(DEBUG, TAG, "address:%s", address);
262     OIC_LOG(DEBUG, TAG, "OUT");
263     return CA_STATUS_OK;
264 }
265