Merge branch '1.3-rel' (5cfded4d) into 'master'
[iotivity.git] / resource / csdk / stack / src / occonnectionmanager.c
1 /******************************************************************
2  *
3  * Copyright 2017 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 "iotivity_config.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <signal.h>
26 #include <ctype.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #include <getopt.h>
31 #include "octypes.h"
32 #include "ocstack.h"
33 #include "ocstackinternal.h"
34 #include "experimental/ocrandom.h"
35 #include "experimental/logger.h"
36 #include "occonnectionmanager.h"
37 #include "ocpayload.h"
38 #include "oic_string.h"
39 #include "oic_malloc.h"
40
41 #include "cacommon.h"
42 #include "cainterface.h"
43 #include "cautilinterface.h"
44
45 #define DEFAULT_CONTEXT_VALUE (0x99)
46 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OIC_LOG((logLevel), \
47              TAG, #arg " is NULL"); return (retVal); } }
48 #define VERIFY_NON_NULL_NR(arg, logLevel) { if (!(arg)) { OIC_LOG((logLevel), \
49              TAG, #arg " is NULL"); return; } }
50 #define CLOUD_PREFIX "/oic/route\0"
51 #define CLOUD_PREFIX_LENGTH 10
52
53 #define TAG "OIC_RI_CM"
54
55 /**
56  * Flag for first response message.
57  * Afer first discovery response, D2D endpoint info need to be updated.
58  */
59 static bool isFirstResponse = true;
60
61 /**
62  * Adapter state change callback method.
63  *
64  * @param[in] adapter   CA network adapter type.
65  * @param[in] enabled   current adapter state.
66  */
67 static void OCAdapterStateChangedHandler(CATransportAdapter_t adapter, bool enabled);
68
69 /**
70  *  Connection State change callback method.
71  *
72  *  @param[in] info         CAEndpoint which has address, port and etc.
73  *  @param[in] isConnected  current connection state.
74  */
75 static void OCConnectionStateChangedHandler(const CAEndpoint_t *info, bool isConnected);
76
77 /**
78  * Check uri has device id.
79  *
80  * @param[in]  uri  uri of resource.
81  * @return  true if uri has device id, or false.
82  */
83 static bool OCCMHasDeviceId(const char *uri);
84
85 /**
86  * This function is used to find resources when connection status is changed
87  * or first discovery response.
88  *
89  * @return ::OC_STACK_OK or ERROR CODES (::OCStackResult_t error codes in octypes.h).
90  */
91 static OCStackResult OCCMFindResource();
92
93 /**
94  * Callback function for OCCMFindResource.
95  *
96  * @return ::OC_STACK_KEEP_TRANSACTION
97  */
98 static OCStackApplicationResult OCCMFoundResource(void *ctx,
99                                 OCDoHandle handle, OCClientResponse *clientResponse);
100
101 OCStackResult OCCMInitialize()
102 {
103     OIC_LOG_V(INFO, TAG, "%s", __func__);
104
105     //Initialize the Connection Manager
106     CAResult_t ret = CAUtilCMInitailize();
107     if (CA_STATUS_OK != ret)
108     {
109         OIC_LOG(ERROR, TAG, "CAInitializeConnectionManager failed!");
110         return CAResultToOCResult(ret);
111     }
112
113     // Register NetworkMonitor
114     ret = CARegisterNetworkMonitorHandler(OCAdapterStateChangedHandler,
115                                           OCConnectionStateChangedHandler);
116     if (CA_STATUS_OK != ret)
117     {
118         OIC_LOG(ERROR, TAG, "CARegisterNetworkMonitorHandler failed!");
119         return CAResultToOCResult(ret);
120     }
121
122     return CAResultToOCResult(ret);
123 }
124
125 OCStackResult OCCMTerminate()
126 {
127     OIC_LOG_V(INFO, TAG, "%s", __func__);
128
129     //Unregister IP NetworkMonitor
130     CAResult_t ret = CAUnregisterNetworkMonitorHandler(OCAdapterStateChangedHandler,
131                                                        OCConnectionStateChangedHandler);
132     if (CA_STATUS_OK != ret)
133     {
134         OIC_LOG(ERROR, TAG, "CAUnregisterNetworkMonitorHandler has failed");
135     }
136
137     //Terminate the Connection Manager
138     ret = CAUtilCMTerminate();
139     if (CA_STATUS_OK != ret)
140     {
141         OIC_LOG(ERROR, TAG, "CAUtilCMTerminate has failed");
142     }
143
144     return CAResultToOCResult(ret);
145 }
146
147 OCStackResult OCCMDiscoveryResource(OCClientResponse *clientResponse)
148 {
149     OIC_LOG_V(INFO, TAG, "%s", __func__);
150
151     VERIFY_NON_NULL(clientResponse, ERROR, OC_STACK_INVALID_PARAM);
152
153     OCDiscoveryPayload *payload = (OCDiscoveryPayload*) clientResponse->payload;
154     if (!payload)
155     {
156         OIC_LOG(ERROR, TAG, "payload is empty!");
157         return OC_STACK_ERROR;
158     }
159
160     if (NULL == payload->sid)
161     {
162         OIC_LOG(ERROR, TAG, "Device ID is null");
163         return OC_STACK_ERROR;
164     }
165     OIC_LOG_V(INFO, TAG, "Device ID : %s", payload->sid);
166
167     OCResourcePayload *resource = (OCResourcePayload*) payload->resources;
168
169     if (NULL == resource)
170     {
171         OIC_LOG(ERROR, TAG, "payload resource is NULL");
172         return OC_STACK_ERROR;
173     }
174
175     if (NULL == resource->uri)
176     {
177         OIC_LOG(ERROR, TAG, "resource->uri is NULL");
178         return OC_STACK_ERROR;
179     }
180
181     // update di in CM managed table
182     bool isCloud = OCCMHasDeviceId(resource->uri);
183     CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER};
184     CopyDevAddrToEndpoint(&(clientResponse->devAddr), &endpoint);
185
186     CAResult_t ret = CAUtilCMUpdateRemoteDeviceInfo(&endpoint, isCloud);
187     if (CA_STATUS_OK != ret)
188     {
189         OIC_LOG(ERROR, TAG, "CAUtilCMUpdateRemoteDeviceInfo is failed.");
190         return CAResultToOCResult(ret);
191     }
192
193 #ifdef TCP_ADAPTER
194     if (!isCloud && resource->tcpPort != 0)
195     {
196         endpoint.adapter = CA_ADAPTER_TCP;
197         endpoint.port = resource->tcpPort;
198
199         ret = CAUtilCMUpdateRemoteDeviceInfo(&endpoint, isCloud);
200         if (CA_STATUS_OK != ret)
201         {
202             OIC_LOG(ERROR, TAG, "CAUtilCMUpdateRemoteDeviceInfo is failed!");
203             return CAResultToOCResult(ret);
204         }
205     }
206 #endif
207
208     //CM tries to find local resource when ocstack found a cloud resource.
209     if (isFirstResponse)
210     {
211         OCStackResult ret = OCCMFindResource();
212         if (OC_STACK_OK != ret)
213         {
214             OIC_LOG(ERROR, TAG, "OCCMFindResource is failed!");
215             return ret;
216         }
217         isFirstResponse = false;
218     }
219
220     return OC_STACK_OK;
221 }
222
223 static void OCAdapterStateChangedHandler(CATransportAdapter_t adapter, bool enabled)
224 {
225     OC_UNUSED(adapter);
226     // check user configuration
227     CAConnectUserPref_t connPrefer = CA_USER_PREF_CLOUD;
228     CAResult_t ret = CAUtilCMGetConnectionUserConfig(&connPrefer);
229     if (CA_STATUS_OK != ret)
230     {
231         OIC_LOG_V(ERROR, TAG, "CAUtilCMGetConnectionUserConfig failed with error %u", ret);
232     }
233
234     if (CA_USER_PREF_CLOUD != connPrefer)
235     {
236         //set connection callback
237         if (true == enabled)
238         {
239             OIC_LOG(DEBUG, TAG, "CM ConnectionStatusChangedHandler ENABLED");
240         }
241         else
242         {
243             OIC_LOG(DEBUG, TAG, "CM ConnectionStatusChangedHandler DISABLED");
244         }
245     }
246 }
247
248 static void OCConnectionStateChangedHandler(const CAEndpoint_t *info, bool isConnected)
249 {
250     OIC_LOG(DEBUG, TAG, "OCConnectionStateChangedHandler");
251     OC_UNUSED(info);
252
253     CAConnectUserPref_t connPrefer = CA_USER_PREF_CLOUD;
254     CAResult_t ret = CAUtilCMGetConnectionUserConfig(&connPrefer);
255     if (CA_STATUS_OK != ret)
256     {
257         OIC_LOG_V(ERROR, TAG, "CAUtilCMGetConnectionUserConfig failed with error %u", ret);
258     }
259     else
260     {
261         if (CA_USER_PREF_CLOUD != connPrefer)
262         {
263             if (!isConnected)
264             {
265                 OIC_LOG(DEBUG, TAG, "is disconnedted");
266
267                 //clean local ip up in CM managed table
268                 CAUtilCMResetRemoteDeviceInfo();
269             }
270             else
271             {
272                 OIC_LOG(DEBUG, TAG, "is connected");
273
274                 // Find Resource
275                 OCCMFindResource();
276             }
277         }
278     }
279 }
280
281 static OCStackResult OCCMFindResource()
282 {
283     OIC_LOG_V(INFO, TAG, "%s", __func__);
284
285     char szQueryUri[MAX_QUERY_LENGTH] = { 0 };
286     snprintf(szQueryUri, sizeof(szQueryUri) - 1, "%s%c", OC_RSRVD_WELL_KNOWN_URI, '\0');
287
288     OCCallbackData cbData = {0,};
289     cbData.cb = OCCMFoundResource;
290     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
291     cbData.cd = NULL;
292
293     OCStackResult ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri,
294                                      NULL, 0, CT_DEFAULT | CT_IP_USE_V4,
295                                      OC_LOW_QOS, &cbData, NULL, 0);
296     if (OC_STACK_OK != ret)
297     {
298         OIC_LOG(ERROR, TAG, "OCStack resource error");
299         return ret;
300     }
301
302     return OC_STACK_OK;
303 }
304
305 static OCStackApplicationResult OCCMFoundResource(void* ctx,
306                                            OCDoHandle handle,
307                                            OCClientResponse* clientResponse)
308 {
309     OC_UNUSED(ctx);
310     OC_UNUSED(handle);
311     OC_UNUSED(clientResponse);
312     return OC_STACK_KEEP_TRANSACTION;
313 }
314
315 static bool OCCMHasDeviceId(const char* uri)
316 {
317     bool ret = false;
318     char *copyUri = OICStrdup(uri);
319     bool hasCloudPrefix = strncmp(CLOUD_PREFIX, copyUri, CLOUD_PREFIX_LENGTH) == 0 ? true : false;
320
321     int tokSize = 0;
322     char *str = copyUri;
323
324     char *savePtr = NULL;
325     char *tok = strtok_r(str, "/", &savePtr);
326     while (hasCloudPrefix && tok != NULL && ret != true)
327     {
328         tokSize = strlen(tok);
329         if (tokSize == MAX_IDENTITY_SIZE - 1)
330         {
331             if (OCIsUUID(tok))
332             {
333                 OIC_LOG_V(DEBUG, TAG, "[%s] has uuid", uri);
334                 ret = true;
335             }
336         }
337         tok = strtok_r(NULL, "/", &savePtr);
338     }
339     OICFree(copyUri);
340     copyUri = NULL;
341
342     return ret;
343 }